How to handle mousemovements in an GtkDrawingArea?

Hi

Here the relevant lines:

gtk_widget_set_events(drawingarea,GDK_MOTION_NOTIFY);

g_signal_connect((GtkWidget *)drawingarea, "motion-notify-event",G_CALLBACK(callback_mousemove),NULL);

If I set as event in the g_signal_connect-call “notify”, my callbackfunction is
called at programstart. But with “motion-notify-event” nothing happens.

How can I react to mousemovings ?

And if my callback is called correctly by the system, are this lines to get the
mouse-position ok ?

gboolean callback_mousemove(GtkWidget *widget,GdkEvent *event,gpointer user_data)
{
gdouble xpos,ypos;
    
    xpos = ((GdkEventMotion*)event)->x;
    ypos = ((GdkEventMotion*)event)->y;
}

You’re not returning anything from the signal handler, which leads me to think you’re not enabling any compiler warning in your build. You should do that, and you’ll get the compiler shouting at you because you declare a function that returns a gboolean and yet you don’t return anything.

By not returning anything from your handler, the signal machinery inside GLib will just read some data from the stack; and that data may have some random content that evaluates to a “true” value, which means “stop the signal emission”.

It also seems you’re not really reading the documentation, which explains that gtk_widget_set_events() will replace all event masks with what you’re passing. You haven’t specified whether or not the GdkDrawingArea you’re using has been set to have its own GdkWindow in order to handle events.

In practice, I would recommend you two things:

  • use GTK4, which removes a lot of the old bits of event handling and windowing system surfaces in favour of consistent use of event controllers
  • if you still wish to use GTK3, then install gtk3-demo, and you’ll see an example on how to draw in response to events
1 Like

This is just a small representation of my program, where I am severely limiting myself. Of course I return a value and because it does not work, I tried both true and false.

So there is no simple solution and my approach is wrong ?

The long answer is: you’re using the wrong event mask. It’s not GDK_MOTION_NOTIFY, it’s GDK_POINTER_MOTION_NOTIFY; you also need to accumulate the event mask if you use gtk_widget_set_events():

      gtk_widget_set_events (da,
                             gtk_widget_get_events (da) |
                             GDK_POINTER_MOTION_MASK);

If you’re planning to draw with motion events, though, you should also use GDK_POINTER_MOTION_HINT_MASK, and in your motion event handler you should use gdk_window_get_device_position() instead of using the event coordinates; additionally, you will need to use a separate Cairo surface to minimise the amount of time spent in the draw handler.

The short answer, as I said, is:

  • look at the drawing area demo in gtk-demo for a fully working code example
  • use GTK4, which uses event controllers instead of event masks
1 Like

Thank you for leading me to gtk3-demo. I installed it right now and I will work through it.

I have some questions though. Its not to “correct” you, but DevHelp says about
“GDK_POINTER_MOTION_HINT_MASK”:

GDK_POINTER_MOTION_HINT_MASK is deprecated. It is a special mask to reduce the number of GDK_MOTION_NOTIFY events received. When using GDK_POINTER_MOTION_HINT_MASK, fewer GDK_MOTION_NOTIFY events will be sent, some of which are marked as a hint (the is_hint member is TRUE). To receive more motion events after a motion hint event, the application needs to asks for more, by calling gdk_event_request_motions().

I honestly can’t do much with what devHelp is explaining there.

And the Flag “GDK_POINTER_MOTION_NOTIFY” is unknown for my compiler.

And this event-name doesnt appear in the event-list of glade and not in DevHelp. So it was unknown to me.

I then tried several spellings of that Flag (at g_signal_connect) and I always get at programstart in the console a message like this:

(… here the name of the event-name …) is invalid for instance ‘0x279d0f0’ of type ‘GtkDrawingArea’

I asked this questions because I want to know, whether I should stick with getting the Informations out of the Glade-UI and DevHelp or are there better sources of information where I can find what I need quickly and clearly, even as a beginner.

For those interested, who like me, are still a bit at the beginning:

It works now:

For “gtk_widget_set_events” I set these Flags:

gtk_widget_get_events((GtkWidget*)drawingarea)
| GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK);

And for “g_signal_connect” I set this event: “motion-notify-event”.

Another question:

I want to switch on/off the mouse-function during runtime.

Switch on works:

mask = gtk_widget_get_events(da);
        
mask |= (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);

gtk_widget_add_events(da,mask);

But I cannot find an “remove_event_function”.

So I tried:

...
mask &= ~(GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);

gtk_widget_add_events(da,mask);

But this does not remove the events. Is it possible at all, to remove events during runtime ?

Well, you cannot switch off something by using add_events()… Look into set_events() instead.

Or, simply have your handlers check a flag whether they care about events or not, and do nothing if you’re in the ‘mode’ where they don’t.

Yes. It was an experiment, since I could not find any “remove-function”. I thought, if there is an add-function, but no remove- or delete-function, and no mention in the docs, that you can add but no remove events DURING RUNTIME the developers handle that via the add-function.

It looks like gtk_widget_set_events is only working properly during the startup phase (where all widgets are created).

If I call that function during runtime, nothing happens,
except that I get an error “assertion”-message in the console…

This is, what I am doing at the moment. But I am not happy with that.
When I don’t need signals anymore, I want to be able to turn them off, instead of having to intercept pointless signal firing. (And, of course, I want to be able, to switch them on again, if needed again).

It looks like gtk_widget_set_events is only working properly during the startup phase (where all widgets are created).

See the doc:

This function must be called while a widget is unrealized.

Anyway, GTK4 removes the ability to change/add/remove events, so I would not use that stuff in new code.

When I don’t need signals anymore, I want to be able to turn them off, instead of having to intercept pointless signal firing. (And, of course, I want to be able, to switch them on again, if needed again).

OK, so do that, then? When the ‘off’ condition is entered, disconnect your event handlers, or remove your event controllers. Then when the ‘on’ state resumes, reconnect them. Personally I wouldn’t worry about it, since a handler that returns immediately won’t have noticeable overhead unless you have 100s-1000s of them, but you can do this.

1 Like

I think, you are talking about “g_signal_handler_disconnect”. After I read your Answer I searched for “disconnect” and found that function. Sometimes the mechanism in gtk is not really intuitive and so one searches in the “wrong” direction. Thank you, for this idea. It works !

1 Like

Yeah, that’s the one! Glad it works for you. :smiley:

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.