Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Mail Systems
Eclipse Documentation

How To Guides
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Problem Solutions




Gtk+/Gnome Application Development
Prev Home Next

Mouse Movement Events

Events are emitted to let you track the mouse as it moves around the screen. Motion events are emitted as the pointer moves inside a window; crossing events are emitted when the pointer enters or leaves a GdkWindow. The type field for motion events is GDK_MOTION_NOTIFY. There are two kinds of crossing events: GDK_ENTER_NOTIFY and GDK_LEAVE_NOTIFY.

There are two ways to track motion events. If you specify GDK_POINTER_MOTION_MASK in the event mask for a window, you will receive as many motion events as the X server can generate. If the user moves the pointer rapidly, you will be deluged in motion events; you must handle them quickly, or your application may become unresponsive while it processes the backlog. If you also specify GDK_POINTER_MOTION_HINT_MASK, motion events are sent one at a time. At most one event will be sent until you call gdk_window_get_pointer(), the pointer leaves and re-enters the window, or a button or key event occurs. Thus, each time you receive a motion event, you must call gdk_window_get_pointer() to get the current pointer position and signal the server that you are ready for another event. See the section called The Mouse Pointer for details on gdk_window_get_pointer().

Which mode you choose depends on the application. If you need to trace the exact trajectory of the pointer, you will want to get all motion events. If you only care about the most recent pointer position, you will want to include GDK_POINTER_MOTION_HINT_MASK in your window's event mask to minimize network traffic and maximize responsiveness. One caveat: gdk_window_get_pointer() requires a server round-trip to obtain the pointer position; so it does place some maximum limit on your application's responsiveness. If you can handle motion events quickly enough to keep them from backlogging, your application will probably seem faster without GDK_POINTER_MOTION_HINT_MASK. Motion events are unlikely to come more often than a couple hundred per second --- so if you can handle them in less than 5 milliseconds, you should be OK.

You can ask to receive motion events only while one or more mouse buttons are held down. To receive motion events while any button is down, use GDK_BUTTON_MOTION_MASK in place of GDK_POINTER_MOTION_MASK. You can use GDK_POINTER_MOTION_HINT_MASK with GDK_BUTTON_MOTION_MASK to limit the number of events received, just as you can use it with GDK_POINTER_MOTION_MASK. If you are only interested in motion events while a certain button is pressed, you can use the more specific GDK_BUTTON1_MOTION_MASK, GDK_BUTTON2_MOTION_MASK, and GDK_BUTTON3_MOTION_MASK. Any combination of these three is allowed. They can also be combined with GDK_POINTER_MOTION_HINT_MASK to limit the number of events.

In sum, you can select which motion events to receive along the "button state" dimension using these five masks:

  • GDK_POINTER_MOTION_MASK: all motion events regardless of button state.

  • GDK_BUTTON_MOTION_MASK: all motion events while any button is held.

  • GDK_BUTTON1_MOTION_MASK: all motion events while button 1 is held.

  • GDK_BUTTON2_MOTION_MASK: all motion events while button 2 is held.

  • GDK_BUTTON3_MOTION_MASK: all motion events while button 3 is held.

By default, you are deluged with events as quickly as the X server can generate them; adding GDK_POINTER_MOTION_HINT_MASK to the event mask enables one-at-a-time behavior.

Motion events are represented by GdkEventMotion:

typedef struct _GdkEventMotion GdkEventMotion;

struct _GdkEventMotion
  GdkEventType type;
  GdkWindow *window;
  gint8 send_event;
  guint32 time;
  gdouble x;
  gdouble y;
  gdouble pressure;
  gdouble xtilt;
  gdouble ytilt;
  guint state;
  gint16 is_hint;
  GdkInputSource source;
  guint32 deviceid;
  gdouble x_root, y_root;

Most of these fields should be familiar to you from GdkEventButton; in fact, the only field unique to GdkEventMotion is the is_hint flag. If this field is TRUE, GDK_POINTER_MOTION_HINT_MASK was selected. You might use this flag if you are writing a widget for other people to use, and you want to let them choose how to receive motion events. In your motion event handler, you could do this:

  double x, y;

  x = event->motion.x;
  y = event->motion.y;

  if (event->motion.is_hint)
    gdk_window_get_pointer(event->window, &x, &y, NULL);

That is, you call gdk_window_get_pointer() only if necessary. If you are using GDK_POINTER_MOTION_HINT_MASK, you should prefer the results from gdk_window_get_pointer() to the coordinates given in the event, because they are more recent. (If you are receiving every event, it makes no sense to call gdk_window_get_pointer() because it is relatively slow and will worsen the backlog---you're getting every event eventually anyway.)

Crossing events occur when the mouse pointer enters or leaves a window. If you move the mouse pointer rapidly across your application, GDK generates these events for every window you pass through. However, GTK+ will try to remove the events "in the middle" and forward only the first leave event and the last enter event to widgets. If you feel you should be getting enter/leave events when you aren't, this optimization is a likely cause.

Here is GdkEventCrossing:

typedef struct _GdkEventCrossing GdkEventCrossing;

struct _GdkEventCrossing
  GdkEventType type;
  GdkWindow *window;
  gint8 send_event;
  GdkWindow *subwindow;
  guint32 time;
  gdouble x;
  gdouble y;
  gdouble x_root;
  gdouble y_root;
  GdkCrossingMode mode;
  GdkNotifyType detail;
  gboolean focus;
  guint state;

Again, many of the fields should be familiar; coordinates relative to the event window and the root window, a time stamp, a state bitfield indicating which buttons and modifiers are active, and the standard three fields from GdkEventAny. However, there are several new fields.

The standard window field contains a pointer to the window the pointer is entering or leaving; x and y are relative to this window. However, the pointer may have been in a child of the window receiving the event before a leave event occurred; the pointer may end up in a child window when an enter event occurs. In these cases, subwindow is set to the child window. Otherwise subwindow is NULL. Note that the child window will receive its own enter and leave events, if it GDK_ENTER_NOTIFY_MASK or GDK_LEAVE_NOTIFY_MASK are in its event mask.

The mode field indicates whether the event occurred normally, or as part of a pointer grab. When the pointer is grabbed or ungrabbed (see the section called The Mouse Pointer), the pointer may be moved; crossing events caused by a grab have the GDK_CROSSING_GRAB mode, those caused by an ungrab have GDK_CROSSING_UNGRAB, and all others have GDK_CROSSING_NORMAL. This field appears to be completely useless; some quick greps through GTK+ and Gnome reveal no examples of its use.

The detail field is rarely used. It gives information about the relative tree positions of the window being left and the window being entered. It has two simple and useful values:

  • GDK_NOTIFY_INFERIOR marks a crossing event received by a parent window when the pointer moves into or out of a child window.

  • GDK_NOTIFY_ANCESTOR marks a crossing event received by a child window when the pointer moves into or out of its parent window.

Several other values are also possible: GDK_NOTIFY_VIRTUAL, GDK_NOTIFY_INFERIOR, GDK_NOTIFY_NONLINEAR, GDK_NOTIFY_NONLINEAR_VIRTUAL, and GDK_NOTIFY_UNKNOWN. However, they are never used and are too complicated to explain here.

Gtk+/Gnome Application Development
Prev Home Next

  Published under free license. Design by Interspire