diff options
Diffstat (limited to 'gdk/gdkwindow.c')
-rw-r--r-- | gdk/gdkwindow.c | 1116 |
1 files changed, 863 insertions, 253 deletions
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 10b27d3037..17d6e20a3c 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -37,6 +37,8 @@ #include "gdk.h" /* For gdk_rectangle_union() */ #include "gdkinternals.h" #include "gdkintl.h" +#include "gdkscreen.h" +#include "gdkdeviceprivate.h" #include "gdkdrawable.h" #include "gdkmarshalers.h" #include "gdkpixmap.h" @@ -224,7 +226,6 @@ typedef struct { int dx, dy; /* The amount that the source was moved to reach dest_region */ } GdkWindowRegionMove; - /* Global info */ static GdkGC *gdk_window_create_gc (GdkDrawable *drawable, @@ -402,7 +403,8 @@ static void do_move_region_bits_on_impl (GdkWindowObject *private, int dx, int dy); static void gdk_window_invalidate_in_parent (GdkWindowObject *private); static void move_native_children (GdkWindowObject *private); -static void update_cursor (GdkDisplay *display); +static void update_cursor (GdkDisplay *display, + GdkDevice *device); static void impl_window_add_update_area (GdkWindowObject *impl_window, GdkRegion *region); static void gdk_window_region_move_free (GdkWindowRegionMove *move); @@ -650,10 +652,30 @@ gdk_window_class_init (GdkWindowObjectClass *klass) } static void +device_removed_cb (GdkDeviceManager *device_manager, + GdkDevice *device, + GdkWindow *window) +{ + GdkWindowObject *private; + + private = (GdkWindowObject *) window; + + private->devices_inside = g_list_remove (private->devices_inside, device); + g_hash_table_remove (private->device_cursor, device); + + if (private->device_events) + g_hash_table_remove (private->device_events, device); +} + +static void gdk_window_finalize (GObject *object) { GdkWindow *window = GDK_WINDOW (object); GdkWindowObject *obj = (GdkWindowObject *) object; + GdkDeviceManager *device_manager; + + device_manager = gdk_display_get_device_manager (gdk_drawable_get_display (GDK_DRAWABLE (window))); + g_signal_handlers_disconnect_by_func (device_manager, device_removed_cb, window); if (!GDK_WINDOW_DESTROYED (window)) { @@ -690,6 +712,15 @@ gdk_window_finalize (GObject *object) if (obj->cursor) gdk_cursor_unref (obj->cursor); + if (obj->device_cursor) + g_hash_table_destroy (obj->device_cursor); + + if (obj->device_events) + g_hash_table_destroy (obj->device_events); + + if (obj->devices_inside) + g_list_free (obj->devices_inside); + G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -1246,12 +1277,20 @@ find_native_sibling_above (GdkWindowObject *parent, } static GdkEventMask -get_native_event_mask (GdkWindowObject *private) +get_native_device_event_mask (GdkWindowObject *private, + GdkDevice *device) { + GdkEventMask event_mask; + + if (device) + event_mask = GPOINTER_TO_INT (g_hash_table_lookup (private->device_events, device)); + else + event_mask = private->event_mask; + if (_gdk_native_windows || private->window_type == GDK_WINDOW_ROOT || private->window_type == GDK_WINDOW_FOREIGN) - return private->event_mask; + return event_mask; else { GdkEventMask mask; @@ -1313,6 +1352,12 @@ get_native_grab_event_mask (GdkEventMask grab_mask) ~GDK_POINTER_MOTION_HINT_MASK); } +static GdkEventMask +get_native_event_mask (GdkWindowObject *private) +{ + return get_native_device_event_mask (private, NULL); +} + /* Puts the native window in the right order wrt the other native windows * in the hierarchy, given the position it has in the client side data. * This is useful if some operation changed the stacking order. @@ -1365,6 +1410,7 @@ gdk_window_new (GdkWindow *parent, gboolean native; GdkEventMask event_mask; GdkWindow *real_parent; + GdkDeviceManager *device_manager; g_return_val_if_fail (attributes != NULL, NULL); @@ -1541,6 +1587,13 @@ gdk_window_new (GdkWindow *parent, (attributes->cursor) : NULL)); + private->device_cursor = g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) gdk_cursor_unref); + + device_manager = gdk_display_get_device_manager (gdk_drawable_get_display (GDK_DRAWABLE (parent))); + g_signal_connect (device_manager, "device-removed", + G_CALLBACK (device_removed_cb), window); + return window; } @@ -2003,6 +2056,30 @@ window_remove_filters (GdkWindow *window) } } +static void +update_pointer_info_foreach (GdkDisplay *display, + GdkDevice *device, + GdkPointerWindowInfo *pointer_info, + gpointer user_data) +{ + GdkWindow *window = user_data; + + if (pointer_info->toplevel_under_pointer == window) + { + g_object_unref (pointer_info->toplevel_under_pointer); + pointer_info->toplevel_under_pointer = NULL; + } +} + +static void +window_remove_from_pointer_info (GdkWindow *window, + GdkDisplay *display) +{ + _gdk_display_pointer_info_foreach (display, + update_pointer_info_foreach, + window); +} + /** * _gdk_window_destroy_hierarchy: * @window: a #GdkWindow @@ -2139,9 +2216,6 @@ _gdk_window_destroy_hierarchy (GdkWindow *window, impl_iface = GDK_WINDOW_IMPL_GET_IFACE (private->impl); - if (private->extension_events) - impl_iface->input_window_destroy (window); - if (gdk_window_has_impl (private)) impl_iface->destroy (window, recursing_native, foreign_destroy); @@ -2165,11 +2239,7 @@ _gdk_window_destroy_hierarchy (GdkWindow *window, private->redirect = NULL; - if (display->pointer_info.toplevel_under_pointer == window) - { - g_object_unref (display->pointer_info.toplevel_under_pointer); - display->pointer_info.toplevel_under_pointer = NULL; - } + window_remove_from_pointer_info (window, display); if (private->clip_region) { @@ -6377,6 +6447,8 @@ gdk_window_constrain_size (GdkGeometry *geometry, * Return value: (transfer none): the window containing the pointer (as with * gdk_window_at_pointer()), or %NULL if the window containing the * pointer isn't known to GDK + * + * Deprecated: 3.0. Use gdk_window_get_device_position() instead. **/ GdkWindow* gdk_window_get_pointer (GdkWindow *window, @@ -6385,29 +6457,50 @@ gdk_window_get_pointer (GdkWindow *window, GdkModifierType *mask) { GdkDisplay *display; - gint tmp_x, tmp_y; - GdkModifierType tmp_mask; - GdkWindow *child; - g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL); + g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); - if (window) - { - display = gdk_drawable_get_display (window); - } - else - { - GdkScreen *screen = gdk_screen_get_default (); + display = gdk_drawable_get_display (window); - display = gdk_screen_get_display (screen); - window = gdk_screen_get_root_window (screen); + return gdk_window_get_device_position (window, display->core_pointer, x, y, mask); +} - GDK_NOTE (MULTIHEAD, - g_message ("Passing NULL for window to gdk_window_get_pointer()\n" - "is not multihead safe")); - } +/** + * gdk_window_get_device_position: + * @window: a #GdkWindow. + * @device: #GdkDevice to query to. + * @x: return location for the X coordinate of @device, or %NULL. + * @y: return location for the Y coordinate of @device, or %NULL. + * @mask: return location for the modifier mask, or %NULL. + * + * Obtains the current device position and modifier state. + * The position is given in coordinates relative to the upper left + * corner of @window. + * + * Returns: The window underneath @device (as with + * gdk_display_get_window_at_device_position()), or %NULL if the + * window is not known to GDK. + * + * Since: 3.0 + **/ +GdkWindow * +gdk_window_get_device_position (GdkWindow *window, + GdkDevice *device, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkDisplay *display; + gint tmp_x, tmp_y; + GdkModifierType tmp_mask; + GdkWindow *child; - child = display->pointer_hooks->window_get_pointer (display, window, &tmp_x, &tmp_y, &tmp_mask); + g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); + g_return_val_if_fail (GDK_IS_DEVICE (device), NULL); + + display = gdk_drawable_get_display (window); + child = display->device_hooks->window_get_device_position (display, device, window, + &tmp_x, &tmp_y, &tmp_mask); if (x) *x = tmp_x; @@ -6416,7 +6509,7 @@ gdk_window_get_pointer (GdkWindow *window, if (mask) *mask = tmp_mask; - _gdk_display_enable_motion_hints (display); + _gdk_display_enable_motion_hints (display, device); return child; } @@ -6436,6 +6529,8 @@ gdk_window_get_pointer (GdkWindow *window, * gdk_display_get_window_at_pointer() instead. * * Return value: (transfer none): window under the mouse pointer + * + * Deprecated: 3.0. Use gdk_display_get_window_at_device_position() instead. **/ GdkWindow* gdk_window_at_pointer (gint *win_x, @@ -7086,30 +7181,31 @@ gdk_window_hide (GdkWindow *window) else if (was_mapped) { GdkDisplay *display; + GdkDeviceManager *device_manager; + GList *devices, *d; /* May need to break grabs on children */ display = gdk_drawable_get_display (window); + device_manager = gdk_display_get_device_manager (display); - if (_gdk_display_end_pointer_grab (display, - _gdk_windowing_window_get_next_serial (display), - window, - TRUE)) - gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME); + /* Get all devices */ + devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER); + devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE)); + devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING)); - if (display->keyboard_grab.window != NULL) - { - if (is_parent_of (window, display->keyboard_grab.window)) - { - /* Call this ourselves, even though gdk_display_keyboard_ungrab - does so too, since we want to pass implicit == TRUE so the - broken grab event is generated */ - _gdk_display_unset_has_keyboard_grab (display, - TRUE); - gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME); - } - } + for (d = devices; d; d = d->next) + { + GdkDevice *device = d->data; + + if (_gdk_display_end_device_grab (display, device, + _gdk_windowing_window_get_next_serial (display), + window, + TRUE)) + gdk_device_ungrab (device, GDK_CURRENT_TIME); + } private->state = GDK_WINDOW_STATE_WITHDRAWN; + g_list_free (devices); } did_hide = _gdk_window_update_viewable (window); @@ -7191,9 +7287,10 @@ gdk_window_withdraw (GdkWindow *window) * @event_mask: event mask for @window * * The event mask for a window determines which events will be reported - * for that window. For example, an event mask including #GDK_BUTTON_PRESS_MASK - * means the window should report button press events. The event mask - * is the bitwise OR of values from the #GdkEventMask enumeration. + * for that window from all master input devices. For example, an event mask + * including #GDK_BUTTON_PRESS_MASK means the window should report button + * press events. The event mask is the bitwise OR of values from the + * #GdkEventMask enumeration. **/ void gdk_window_set_events (GdkWindow *window, @@ -7213,7 +7310,15 @@ gdk_window_set_events (GdkWindow *window, display = gdk_drawable_get_display (window); if ((private->event_mask & GDK_POINTER_MOTION_HINT_MASK) && !(event_mask & GDK_POINTER_MOTION_HINT_MASK)) - _gdk_display_enable_motion_hints (display); + { + GList *devices = private->devices_inside; + + while (devices) + { + _gdk_display_enable_motion_hints (display, (GdkDevice *) devices->data); + devices = devices->next; + } + } private->event_mask = event_mask; @@ -7230,7 +7335,8 @@ gdk_window_set_events (GdkWindow *window, * gdk_window_get_events: * @window: a #GdkWindow * - * Gets the event mask for @window. See gdk_window_set_events(). + * Gets the event mask for @window for all master input devices. See + * gdk_window_set_events(). * * Return value: event mask for @window **/ @@ -7248,6 +7354,115 @@ gdk_window_get_events (GdkWindow *window) return private->event_mask; } +/** + * gdk_window_set_device_events: + * @window: a #GdkWindow + * @device: #GdkDevice to enable events for. + * @event_mask: event mask for @window + * + * Sets the event mask for a given device (Normally a floating device, not + * attached to any visible pointer) to @window. For example, an event mask + * including #GDK_BUTTON_PRESS_MASK means the window should report button + * press events. The event mask is the bitwise OR of values from the + * #GdkEventMask enumeration. + * + * Since: 3.0 + **/ +void +gdk_window_set_device_events (GdkWindow *window, + GdkDevice *device, + GdkEventMask event_mask) +{ + GdkEventMask device_mask; + GdkWindowObject *private; + GdkDisplay *display; + GdkWindow *native; + + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_DEVICE (device)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + private = (GdkWindowObject *) window; + + /* If motion hint is disabled, enable motion events again */ + display = gdk_drawable_get_display (window); + if ((private->event_mask & GDK_POINTER_MOTION_HINT_MASK) && + !(event_mask & GDK_POINTER_MOTION_HINT_MASK)) + _gdk_display_enable_motion_hints (display, device); + + if (G_UNLIKELY (!private->device_events)) + private->device_events = g_hash_table_new (NULL, NULL); + + if (event_mask == 0) + { + /* FIXME: unsetting events on a master device + * would restore private->event_mask + */ + g_hash_table_remove (private->device_events, device); + } + else + g_hash_table_insert (private->device_events, device, + GINT_TO_POINTER (event_mask)); + + if (_gdk_native_windows) + native = window; + else + native = gdk_window_get_toplevel (window); + + while (gdk_window_is_offscreen ((GdkWindowObject *)native)) + { + native = gdk_offscreen_window_get_embedder (native); + + if (native == NULL || + (!_gdk_window_has_impl (native) && + !gdk_window_is_viewable (native))) + return; + + native = gdk_window_get_toplevel (native); + } + + device_mask = get_native_device_event_mask (private, device); + GDK_DEVICE_GET_CLASS (device)->select_window_events (device, native, device_mask); +} + +/** + * gdk_window_get_device_events: + * @window: a #GdkWindow. + * @device: a #GdkDevice. + * + * Returns the event mask for @window corresponding to an specific device. + * + * Returns: device event mask for @window + * + * Since: 3.0 + **/ +GdkEventMask +gdk_window_get_device_events (GdkWindow *window, + GdkDevice *device) +{ + GdkWindowObject *private; + GdkEventMask mask; + + g_return_val_if_fail (GDK_IS_WINDOW (window), 0); + g_return_val_if_fail (GDK_IS_DEVICE (device), 0); + + if (GDK_WINDOW_DESTROYED (window)) + return 0; + + private = (GdkWindowObject *) window; + + if (!private->device_events) + return 0; + + mask = GPOINTER_TO_INT (g_hash_table_lookup (private->device_events, device)); + + /* FIXME: device could be controlled by private->event_mask */ + + return mask; +} + static void gdk_window_move_resize_toplevel (GdkWindow *window, gboolean with_move, @@ -8023,6 +8238,23 @@ gdk_window_set_back_pixmap (GdkWindow *window, } } +static void +update_cursor_foreach (GdkDisplay *display, + GdkDevice *device, + GdkPointerWindowInfo *pointer_info, + gpointer user_data) +{ + GdkWindow *window = user_data; + GdkWindowObject *private = (GdkWindowObject *) window; + + if (_gdk_native_windows || + private->window_type == GDK_WINDOW_ROOT || + private->window_type == GDK_WINDOW_FOREIGN) + GDK_WINDOW_IMPL_GET_IFACE (private->impl)->set_device_cursor (window, device, private->cursor); + else if (_gdk_window_event_parent_of (window, pointer_info->window_under_pointer)) + update_cursor (display, device); +} + /** * gdk_window_get_cursor: * @window: a #GdkWindow @@ -8055,7 +8287,7 @@ gdk_window_get_cursor (GdkWindow *window) * @window: a #GdkWindow * @cursor: a cursor * - * Sets the mouse pointer for a #GdkWindow. Use gdk_cursor_new_for_display() + * Sets the default mouse pointer for a #GdkWindow. Use gdk_cursor_new_for_display() * or gdk_cursor_new_from_pixmap() to create the cursor. To make the cursor * invisible, use %GDK_BLANK_CURSOR. Passing %NULL for the @cursor argument * to gdk_window_set_cursor() means that @window will use the cursor of its @@ -8066,7 +8298,6 @@ gdk_window_set_cursor (GdkWindow *window, GdkCursor *cursor) { GdkWindowObject *private; - GdkWindowImplIface *impl_iface; GdkDisplay *display; g_return_if_fail (GDK_IS_WINDOW (window)); @@ -8085,21 +8316,90 @@ gdk_window_set_cursor (GdkWindow *window, if (cursor) private->cursor = gdk_cursor_ref (cursor); - if (_gdk_native_windows || - private->window_type == GDK_WINDOW_ROOT || - private->window_type == GDK_WINDOW_FOREIGN) - { - impl_iface = GDK_WINDOW_IMPL_GET_IFACE (private->impl); - impl_iface->set_cursor (window, cursor); - } - else if (_gdk_window_event_parent_of (window, display->pointer_info.window_under_pointer)) - update_cursor (display); + _gdk_display_pointer_info_foreach (display, + update_cursor_foreach, + window); g_object_notify (G_OBJECT (window), "cursor"); } } /** + * gdk_window_get_device_cursor: + * @window: a #GdkWindow. + * @device: a #GdkDevice. + * + * Retrieves a #GdkCursor pointer for the @device currently set on the + * specified #GdkWindow, or %NULL. If the return value is %NULL then + * there is no custom cursor set on the specified window, and it is + * using the cursor for its parent window. + * + * Returns: a #GdkCursor, or %NULL. The returned object is owned + * by the #GdkWindow and should not be unreferenced directly. Use + * gdk_window_set_cursor() to unset the cursor of the window + * + * Since: 3.0 + **/ +GdkCursor * +gdk_window_get_device_cursor (GdkWindow *window, + GdkDevice *device) +{ + GdkWindowObject *private; + + g_return_val_if_fail (GDK_IS_WINDOW (window), NULL); + g_return_val_if_fail (GDK_IS_DEVICE (device), NULL); + + private = (GdkWindowObject *) window; + + return g_hash_table_lookup (private->device_cursor, device); +} + +/** + * gdk_window_set_device_cursor: + * @window: a #Gdkwindow + * @device: a #GdkDevice + * @cursor: a #GdkCursor + * + * Sets a specific #GdkCursor for a given device when it gets inside @window. + * Use gdk_cursor_new_for_display() or gdk_cursor_new_from_pixmap() to create + * the cursor. To make the cursor invisible, use %GDK_BLANK_CURSOR. Passing + * %NULL for the @cursor argument to gdk_window_set_cursor() means that + * @window will use the cursor of its parent window. Most windows should + * use this default. + * + * Since: 3.0 + **/ +void +gdk_window_set_device_cursor (GdkWindow *window, + GdkDevice *device, + GdkCursor *cursor) +{ + GdkWindowObject *private; + GdkDisplay *display; + + g_return_if_fail (GDK_IS_WINDOW (window)); + g_return_if_fail (GDK_IS_DEVICE (window)); + + private = (GdkWindowObject *) window; + display = gdk_drawable_get_display (window); + + if (!cursor) + g_hash_table_remove (private->device_cursor, device); + else + g_hash_table_replace (private->device_cursor, device, cursor); + + if (!GDK_WINDOW_DESTROYED (window)) + { + GdkPointerWindowInfo *pointer_info; + + pointer_info = _gdk_display_get_pointer_info (display, device); + + if (_gdk_window_event_parent_of (window, pointer_info->window_under_pointer)) + update_cursor (display, device); + } +} + +/** * gdk_window_get_geometry: * @window: a #GdkWindow * @x: return location for X coordinate of window (relative to its parent) @@ -9394,27 +9694,34 @@ _gdk_window_event_parent_of (GdkWindow *parent, } static void -update_cursor (GdkDisplay *display) +update_cursor (GdkDisplay *display, + GdkDevice *device) { GdkWindowObject *cursor_window, *parent, *toplevel; GdkWindow *pointer_window; GdkWindowImplIface *impl_iface; - GdkPointerGrabInfo *grab; + GdkPointerWindowInfo *pointer_info; + GdkDeviceGrabInfo *grab; - pointer_window = display->pointer_info.window_under_pointer; + pointer_info = _gdk_display_get_pointer_info (display, device); + pointer_window = pointer_info->window_under_pointer; /* We ignore the serials here and just pick the last grab we've sent, as that would shortly be used anyway. */ - grab = _gdk_display_get_last_pointer_grab (display); + grab = _gdk_display_get_last_device_grab (display, device); if (/* have grab */ grab != NULL && /* the pointer is not in a descendant of the grab window */ !_gdk_window_event_parent_of (grab->window, pointer_window)) - /* use the cursor from the grab window */ - cursor_window = (GdkWindowObject *)grab->window; + { + /* use the cursor from the grab window */ + cursor_window = (GdkWindowObject *) grab->window; + } else - /* otherwise use the cursor from the pointer window */ - cursor_window = (GdkWindowObject *)pointer_window; + { + /* otherwise use the cursor from the pointer window */ + cursor_window = (GdkWindowObject *) pointer_window; + } /* Find the first window with the cursor actually set, as the cursor is inherited from the parent */ @@ -9425,9 +9732,10 @@ update_cursor (GdkDisplay *display) /* Set all cursors on toplevel, otherwise its tricky to keep track of * which native window has what cursor set. */ - toplevel = (GdkWindowObject *)get_event_toplevel (pointer_window); + toplevel = (GdkWindowObject *) get_event_toplevel (pointer_window); impl_iface = GDK_WINDOW_IMPL_GET_IFACE (toplevel->impl); - impl_iface->set_cursor ((GdkWindow *)toplevel, cursor_window->cursor); + impl_iface->set_device_cursor ((GdkWindow *) toplevel, device, + cursor_window->cursor); } static gboolean @@ -9659,6 +9967,61 @@ gdk_window_beep (GdkWindow *window) gdk_display_beep (display); } +/** + * gdk_window_set_support_multidevice: + * @window: a #GdkWindow. + * @support_multidevice: %TRUE to enable multidevice support in @window. + * + * This function will enable multidevice features in @window. + * + * Multidevice aware windows will need to handle properly multiple, + * per device enter/leave events, device grabs and grab ownerships. + * + * Since: 3.0 + **/ +void +gdk_window_set_support_multidevice (GdkWindow *window, + gboolean support_multidevice) +{ + GdkWindowObject *private = (GdkWindowObject *) window; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + if (private->support_multidevice == support_multidevice) + return; + + private->support_multidevice = support_multidevice; + + /* FIXME: What to do if called when some pointers are inside the window ? */ +} + +/** + * gdk_window_get_support_multidevice: + * @window: a #GdkWindow. + * + * Returns %TRUE if the window is aware of the existence of multiple + * devices. + * + * Returns: %TRUE if the window handles multidevice features. + * + * Since: 3.0 + **/ +gboolean +gdk_window_get_support_multidevice (GdkWindow *window) +{ + GdkWindowObject *private = (GdkWindowObject *) window; + + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + if (GDK_WINDOW_DESTROYED (window)) + return FALSE; + + return private->support_multidevice; +} + static const guint type_masks[] = { GDK_SUBSTRUCTURE_MASK, /* GDK_DELETE = 0 */ GDK_STRUCTURE_MASK, /* GDK_DESTROY = 1 */ @@ -9888,6 +10251,7 @@ send_crossing_event (GdkDisplay *display, GdkCrossingMode mode, GdkNotifyType notify_type, GdkWindow *subwindow, + GdkDevice *device, gint toplevel_x, gint toplevel_y, GdkModifierType mask, @@ -9897,10 +10261,10 @@ send_crossing_event (GdkDisplay *display, { GdkEvent *event; guint32 window_event_mask, type_event_mask; - GdkPointerGrabInfo *grab; - GdkWindowImplIface *impl_iface; + GdkDeviceGrabInfo *grab; + gboolean block_event = FALSE; - grab = _gdk_display_has_pointer_grab (display, serial); + grab = _gdk_display_has_device_grab (display, device, serial); if (grab != NULL && !grab->owner_events) @@ -9914,20 +10278,39 @@ send_crossing_event (GdkDisplay *display, window_event_mask = window->event_mask; if (type == GDK_LEAVE_NOTIFY) - type_event_mask = GDK_LEAVE_NOTIFY_MASK; - else - type_event_mask = GDK_ENTER_NOTIFY_MASK; + { + type_event_mask = GDK_LEAVE_NOTIFY_MASK; + window->devices_inside = g_list_remove (window->devices_inside, device); - if (window->extension_events != 0) + if (!window->support_multidevice && window->devices_inside) + { + /* Block leave events unless it's the last pointer */ + block_event = TRUE; + } + } + else { - impl_iface = GDK_WINDOW_IMPL_GET_IFACE (window->impl); - impl_iface->input_window_crossing ((GdkWindow *)window, - type == GDK_ENTER_NOTIFY); + type_event_mask = GDK_ENTER_NOTIFY_MASK; + + if (!window->support_multidevice && window->devices_inside) + { + /* Only emit enter events for the first device */ + block_event = TRUE; + } + + if (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER && + device->mode != GDK_MODE_DISABLED && + !g_list_find (window->devices_inside, device)) + window->devices_inside = g_list_prepend (window->devices_inside, device); } + if (block_event) + return; + if (window_event_mask & type_event_mask) { event = _gdk_make_event ((GdkWindow *)window, type, event_in_queue, TRUE); + gdk_event_set_device (event, device); event->crossing.time = time_; event->crossing.subwindow = subwindow; if (subwindow) @@ -9954,6 +10337,7 @@ void _gdk_synthesize_crossing_events (GdkDisplay *display, GdkWindow *src, GdkWindow *dest, + GdkDevice *device, GdkCrossingMode mode, gint toplevel_x, gint toplevel_y, @@ -9978,6 +10362,18 @@ _gdk_synthesize_crossing_events (GdkDisplay *display, if (a == b) return; /* No crossings generated between src and dest */ + if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER) + { + if (a && gdk_window_get_device_events (src, device) == 0) + a = NULL; + + if (b && gdk_window_get_device_events (dest, device) == 0) + b = NULL; + } + + if (!a && !b) + return; + c = find_common_ancestor (a, b); non_linear |= (c != a) && (c != b); @@ -9997,7 +10393,7 @@ _gdk_synthesize_crossing_events (GdkDisplay *display, a, GDK_LEAVE_NOTIFY, mode, notify_type, - NULL, + NULL, device, toplevel_x, toplevel_y, mask, time_, event_in_queue, @@ -10019,6 +10415,7 @@ _gdk_synthesize_crossing_events (GdkDisplay *display, mode, notify_type, (GdkWindow *)last, + device, toplevel_x, toplevel_y, mask, time_, event_in_queue, @@ -10065,6 +10462,7 @@ _gdk_synthesize_crossing_events (GdkDisplay *display, mode, notify_type, (GdkWindow *)next, + device, toplevel_x, toplevel_y, mask, time_, event_in_queue, @@ -10086,6 +10484,7 @@ _gdk_synthesize_crossing_events (GdkDisplay *display, mode, notify_type, NULL, + device, toplevel_x, toplevel_y, mask, time_, event_in_queue, @@ -10100,14 +10499,18 @@ _gdk_synthesize_crossing_events (GdkDisplay *display, static GdkWindow * get_pointer_window (GdkDisplay *display, GdkWindow *event_window, + GdkDevice *device, gdouble toplevel_x, gdouble toplevel_y, gulong serial) { GdkWindow *pointer_window; - GdkPointerGrabInfo *grab; + GdkDeviceGrabInfo *grab; + GdkPointerWindowInfo *pointer_info; + + pointer_info = _gdk_display_get_pointer_info (display, device); - if (event_window == display->pointer_info.toplevel_under_pointer) + if (event_window == pointer_info->toplevel_under_pointer) pointer_window = _gdk_window_find_descendant_at (event_window, toplevel_x, toplevel_y, @@ -10115,7 +10518,7 @@ get_pointer_window (GdkDisplay *display, else pointer_window = NULL; - grab = _gdk_display_has_pointer_grab (display, serial); + grab = _gdk_display_has_device_grab (display, device, serial); if (grab != NULL && !grab->owner_events && pointer_window != grab->window) @@ -10126,47 +10529,80 @@ get_pointer_window (GdkDisplay *display, void _gdk_display_set_window_under_pointer (GdkDisplay *display, - GdkWindow *window) + GdkDevice *device, + GdkWindow *window) { + GdkPointerWindowInfo *device_info; + /* We don't track this if all native, and it can cause issues with the update_cursor call below */ if (_gdk_native_windows) return; - if (display->pointer_info.window_under_pointer) - g_object_unref (display->pointer_info.window_under_pointer); - display->pointer_info.window_under_pointer = window; - if (window) - g_object_ref (window); + device_info = _gdk_display_get_pointer_info (display, device); + + if (device_info->window_under_pointer) + g_object_unref (device_info->window_under_pointer); + device_info->window_under_pointer = window; if (window) - update_cursor (display); + { + g_object_ref (window); + update_cursor (display, device); + } - _gdk_display_enable_motion_hints (display); + _gdk_display_enable_motion_hints (display, device); } -/* - *-------------------------------------------------------------- - * gdk_pointer_grab - * - * Grabs the pointer to a specific window - * - * Arguments: - * "window" is the window which will receive the grab - * "owner_events" specifies whether events will be reported as is, - * or relative to "window" - * "event_mask" masks only interesting events - * "confine_to" limits the cursor movement to the specified window - * "cursor" changes the cursor for the duration of the grab - * "time" specifies the time - * - * Results: - * - * Side effects: - * requires a corresponding call to gdk_pointer_ungrab - * - *-------------------------------------------------------------- - */ +/** + * gdk_pointer_grab: + * @window: the #GdkWindow which will own the grab (the grab window). + * @owner_events: if %FALSE then all pointer events are reported with respect to + * @window and are only reported if selected by @event_mask. If %TRUE then pointer + * events for this application are reported as normal, but pointer events outside + * this application are reported with respect to @window and only if selected by + * @event_mask. In either mode, unreported events are discarded. + * @event_mask: specifies the event mask, which is used in accordance with + * @owner_events. Note that only pointer events (i.e. button and motion events) + * may be selected. + * @confine_to: If non-%NULL, the pointer will be confined to this + * window during the grab. If the pointer is outside @confine_to, it will + * automatically be moved to the closest edge of @confine_to and enter + * and leave events will be generated as necessary. + * @cursor: the cursor to display while the grab is active. If this is %NULL then + * the normal cursors are used for @window and its descendants, and the cursor + * for @window is used for all other windows. + * @time_: the timestamp of the event which led to this pointer grab. This usually + * comes from a #GdkEventButton struct, though %GDK_CURRENT_TIME can be used if + * the time isn't known. + * + * Grabs the pointer (usually a mouse) so that all events are passed to this + * application until the pointer is ungrabbed with gdk_pointer_ungrab(), or + * the grab window becomes unviewable. + * This overrides any previous pointer grab by this client. + * + * Pointer grabs are used for operations which need complete control over mouse + * events, even if the mouse leaves the application. + * For example in GTK+ it is used for Drag and Drop, for dragging the handle in + * the #GtkHPaned and #GtkVPaned widgets, and for resizing columns in #GtkCList + * widgets. + * + * Note that if the event mask of an X window has selected both button press and + * button release events, then a button press event will cause an automatic + * pointer grab until the button is released. + * X does this automatically since most applications expect to receive button + * press and release events in pairs. + * It is equivalent to a pointer grab on the window with @owner_events set to + * %TRUE. + * + * If you set up anything at the time you take the grab that needs to be cleaned + * up when the grab ends, you should handle the #GdkEventGrabBroken events that + * are emitted when the grab ends unvoluntarily. + * + * Returns: %GDK_GRAB_SUCCESS if the grab was successful. + * + * Deprecated: 3.0. Use gdk_device_grab() instead. + **/ GdkGrabStatus gdk_pointer_grab (GdkWindow * window, gboolean owner_events, @@ -10177,8 +10613,11 @@ gdk_pointer_grab (GdkWindow * window, { GdkWindow *native; GdkDisplay *display; - GdkGrabStatus res; + GdkDeviceManager *device_manager; + GdkDevice *device; + GdkGrabStatus res = 0; gulong serial; + GList *devices, *dev; g_return_val_if_fail (window != NULL, 0); g_return_val_if_fail (GDK_IS_WINDOW (window), 0); @@ -10218,24 +10657,147 @@ gdk_pointer_grab (GdkWindow * window, display = gdk_drawable_get_display (window); serial = _gdk_windowing_window_get_next_serial (display); + device_manager = gdk_display_get_device_manager (display); + devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER); + + /* FIXME: Should this be generic to all backends? */ + /* FIXME: What happens with extended devices? */ + for (dev = devices; dev; dev = dev->next) + { + device = dev->data; + + if (device->source != GDK_SOURCE_MOUSE) + continue; + + res = _gdk_windowing_device_grab (device, + window, + native, + owner_events, + get_native_grab_event_mask (event_mask), + confine_to, + cursor, + time); + + if (res == GDK_GRAB_SUCCESS) + _gdk_display_add_device_grab (display, + device, + window, + native, + GDK_OWNERSHIP_NONE, + owner_events, + event_mask, + serial, + time, + FALSE); + } + + /* FIXME: handle errors when grabbing */ + + g_list_free (devices); + + return res; +} + +/** + * gdk_keyboard_grab: + * @window: the #GdkWindow which will own the grab (the grab window). + * @owner_events: if %FALSE then all keyboard events are reported with respect to + * @window. If %TRUE then keyboard events for this application are + * reported as normal, but keyboard events outside this application + * are reported with respect to @window. Both key press and key + * release events are always reported, independant of the event mask + * set by the application. + * @time: a timestamp from a #GdkEvent, or %GDK_CURRENT_TIME if no timestamp is +available. + * + * Grabs the keyboard so that all events are passed to this + * application until the keyboard is ungrabbed with gdk_keyboard_ungrab(). + * This overrides any previous keyboard grab by this client. + * + * If you set up anything at the time you take the grab that needs to be cleaned + * up when the grab ends, you should handle the #GdkEventGrabBroken events that + * are emitted when the grab ends unvoluntarily. + * + * Returns: %GDK_GRAB_SUCCESS if the grab was successful. + * + * Deprecated: 3.0. Use gdk_device_grab() instead. + **/ +GdkGrabStatus +gdk_keyboard_grab (GdkWindow *window, + gboolean owner_events, + guint32 time) +{ + GdkWindow *native; + GdkDisplay *display; + GdkDeviceManager *device_manager; + GdkDevice *device; + GdkGrabStatus res = 0; + gulong serial; + GList *devices, *dev; + + g_return_val_if_fail (GDK_IS_WINDOW (window), 0); + + /* Non-viewable client side window => fail */ + if (!_gdk_window_has_impl (window) && + !gdk_window_is_viewable (window)) + return GDK_GRAB_NOT_VIEWABLE; + + if (_gdk_native_windows) + native = window; + else + native = gdk_window_get_toplevel (window); + + while (gdk_window_is_offscreen ((GdkWindowObject *)native)) + { + native = gdk_offscreen_window_get_embedder (native); + + if (native == NULL || + (!_gdk_window_has_impl (native) && + !gdk_window_is_viewable (native))) + return GDK_GRAB_NOT_VIEWABLE; + + native = gdk_window_get_toplevel (native); + } + + display = gdk_drawable_get_display (window); + + serial = _gdk_windowing_window_get_next_serial (display); + device_manager = gdk_display_get_device_manager (display); + devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER); + + /* FIXME: Should this be generic to all backends? */ + /* FIXME: What happens with extended devices? */ + for (dev = devices; dev; dev = dev->next) + { + device = dev->data; + + if (device->source != GDK_SOURCE_KEYBOARD) + continue; - res = _gdk_windowing_pointer_grab (window, - native, - owner_events, - get_native_grab_event_mask (event_mask), - confine_to, - cursor, - time); - - if (res == GDK_GRAB_SUCCESS) - _gdk_display_add_pointer_grab (display, - window, - native, - owner_events, - event_mask, - serial, - time, - FALSE); + res = _gdk_windowing_device_grab (device, + window, + native, + owner_events, + GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, + NULL, + NULL, + time); + + if (res == GDK_GRAB_SUCCESS) + _gdk_display_add_device_grab (display, + device, + window, + native, + GDK_OWNERSHIP_NONE, + owner_events, 0, + serial, + time, + FALSE); + } + + /* FIXME: handle errors when grabbing */ + + g_list_free (devices); return res; } @@ -10262,7 +10824,8 @@ do_synthesize_crossing_event (gpointer data) GdkDisplay *display; GdkWindow *changed_toplevel; GdkWindowObject *changed_toplevel_priv; - GdkWindow *new_window_under_pointer; + GHashTableIter iter; + gpointer key, value; gulong serial; changed_toplevel = data; @@ -10275,30 +10838,39 @@ do_synthesize_crossing_event (gpointer data) display = gdk_drawable_get_display (changed_toplevel); serial = _gdk_windowing_window_get_next_serial (display); + g_hash_table_iter_init (&iter, display->pointers_info); - if (changed_toplevel == display->pointer_info.toplevel_under_pointer) + while (g_hash_table_iter_next (&iter, &key, &value)) { - new_window_under_pointer = - get_pointer_window (display, changed_toplevel, - display->pointer_info.toplevel_x, - display->pointer_info.toplevel_y, - serial); - if (new_window_under_pointer != - display->pointer_info.window_under_pointer) - { - _gdk_synthesize_crossing_events (display, - display->pointer_info.window_under_pointer, - new_window_under_pointer, - GDK_CROSSING_NORMAL, - display->pointer_info.toplevel_x, - display->pointer_info.toplevel_y, - display->pointer_info.state, - GDK_CURRENT_TIME, - NULL, - serial, - FALSE); - _gdk_display_set_window_under_pointer (display, new_window_under_pointer); - } + GdkWindow *new_window_under_pointer; + GdkPointerWindowInfo *pointer_info = value; + GdkDevice *device = key; + + if (changed_toplevel == pointer_info->toplevel_under_pointer) + { + new_window_under_pointer = + get_pointer_window (display, changed_toplevel, + device, + pointer_info->toplevel_x, + pointer_info->toplevel_y, + serial); + if (new_window_under_pointer != pointer_info->window_under_pointer) + { + _gdk_synthesize_crossing_events (display, + pointer_info->window_under_pointer, + new_window_under_pointer, + device, + GDK_CROSSING_NORMAL, + pointer_info->toplevel_x, + pointer_info->toplevel_y, + pointer_info->state, + GDK_CURRENT_TIME, + NULL, + serial, + FALSE); + _gdk_display_set_window_under_pointer (display, device, new_window_under_pointer); + } + } } return FALSE; @@ -10317,12 +10889,12 @@ _gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window) display = gdk_drawable_get_display (changed_window); toplevel = get_event_toplevel (changed_window); - toplevel_priv = (GdkWindowObject *)toplevel; + toplevel_priv = (GdkWindowObject *) toplevel; - if (toplevel == display->pointer_info.toplevel_under_pointer && - !toplevel_priv->synthesize_crossing_event_queued) + if (!toplevel_priv->synthesize_crossing_event_queued) { toplevel_priv->synthesize_crossing_event_queued = TRUE; + g_idle_add_full (GDK_PRIORITY_EVENTS - 1, do_synthesize_crossing_event, g_object_ref (toplevel), @@ -10333,6 +10905,7 @@ _gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window) /* Don't use for crossing events */ static GdkWindow * get_event_window (GdkDisplay *display, + GdkDevice *device, GdkWindow *pointer_window, GdkEventType type, GdkModifierType mask, @@ -10342,9 +10915,9 @@ get_event_window (GdkDisplay *display, guint evmask; GdkWindow *grab_window; GdkWindowObject *w; - GdkPointerGrabInfo *grab; + GdkDeviceGrabInfo *grab; - grab = _gdk_display_has_pointer_grab (display, serial); + grab = _gdk_display_has_device_grab (display, device, serial); if (grab != NULL && !grab->owner_events) { @@ -10405,6 +10978,8 @@ proxy_pointer_event (GdkDisplay *display, { GdkWindow *toplevel_window, *event_window; GdkWindow *pointer_window; + GdkPointerWindowInfo *pointer_info; + GdkDevice *device; GdkEvent *event; guint state; gdouble toplevel_x, toplevel_y; @@ -10415,6 +10990,8 @@ proxy_pointer_event (GdkDisplay *display, gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y); gdk_event_get_state (source_event, &state); time_ = gdk_event_get_time (source_event); + device = gdk_event_get_device (source_event); + pointer_info = _gdk_display_get_pointer_info (display, device); toplevel_window = convert_native_coords_to_toplevel (event_window, toplevel_x, toplevel_y, &toplevel_x, &toplevel_y); @@ -10445,8 +11022,9 @@ proxy_pointer_event (GdkDisplay *display, /* Send leave events from window under pointer to event window that will get the subwindow == NULL window */ _gdk_synthesize_crossing_events (display, - display->pointer_info.window_under_pointer, + pointer_info->window_under_pointer, event_window, + device, source_event->crossing.mode, toplevel_x, toplevel_y, state, time_, @@ -10462,16 +11040,17 @@ proxy_pointer_event (GdkDisplay *display, source_event->crossing.mode, source_event->crossing.detail, NULL, - toplevel_x, toplevel_y, + device, + toplevel_x, toplevel_y, state, time_, source_event, serial); - _gdk_display_set_window_under_pointer (display, NULL); + _gdk_display_set_window_under_pointer (display, device, NULL); return TRUE; } - pointer_window = get_pointer_window (display, toplevel_window, + pointer_window = get_pointer_window (display, toplevel_window, device, toplevel_x, toplevel_y, serial); if (((source_event->type == GDK_ENTER_NOTIFY && @@ -10491,7 +11070,8 @@ proxy_pointer_event (GdkDisplay *display, source_event->crossing.mode, source_event->crossing.detail, NULL, - toplevel_x, toplevel_y, + device, + toplevel_x, toplevel_y, state, time_, source_event, serial); @@ -10500,30 +11080,32 @@ proxy_pointer_event (GdkDisplay *display, _gdk_synthesize_crossing_events (display, event_window, pointer_window, + device, source_event->crossing.mode, toplevel_x, toplevel_y, state, time_, source_event, serial, non_linear); - _gdk_display_set_window_under_pointer (display, pointer_window); + _gdk_display_set_window_under_pointer (display, device, pointer_window); return TRUE; } - if (display->pointer_info.window_under_pointer != pointer_window) + if (pointer_info->window_under_pointer != pointer_window) { /* Either a toplevel crossing notify that ended up inside a child window, or a motion notify that got into another child window */ /* Different than last time, send crossing events */ _gdk_synthesize_crossing_events (display, - display->pointer_info.window_under_pointer, + pointer_info->window_under_pointer, pointer_window, + device, GDK_CROSSING_NORMAL, toplevel_x, toplevel_y, state, time_, source_event, serial, non_linear); - _gdk_display_set_window_under_pointer (display, pointer_window); + _gdk_display_set_window_under_pointer (display, device, pointer_window); } else if (source_event->type == GDK_MOTION_NOTIFY) { @@ -10532,24 +11114,35 @@ proxy_pointer_event (GdkDisplay *display, gboolean is_hint; event_win = get_event_window (display, - pointer_window, - source_event->type, - state, - &evmask, - serial); + device, + pointer_window, + source_event->type, + state, + &evmask, + serial); + + if (event_win && + gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER && + gdk_window_get_device_events (event_win, device) == 0) + return TRUE; is_hint = FALSE; if (event_win && (evmask & GDK_POINTER_MOTION_HINT_MASK)) { - if (display->pointer_info.motion_hint_serial != 0 && - serial < display->pointer_info.motion_hint_serial) + gulong *device_serial; + + device_serial = g_hash_table_lookup (display->motion_hint_info, device); + + if (!device_serial || + (*device_serial != 0 && + serial < *device_serial)) event_win = NULL; /* Ignore event */ else { is_hint = TRUE; - display->pointer_info.motion_hint_serial = G_MAXULONG; + *device_serial = G_MAXULONG; } } @@ -10561,11 +11154,12 @@ proxy_pointer_event (GdkDisplay *display, toplevel_x, toplevel_y, &event->motion.x, &event->motion.y); event->motion.x_root = source_event->motion.x_root; - event->motion.y_root = source_event->motion.y_root;; + event->motion.y_root = source_event->motion.y_root; event->motion.state = state; event->motion.is_hint = is_hint; - event->motion.device = NULL; event->motion.device = source_event->motion.device; + event->motion.axes = g_memdup (source_event->motion.axes, + sizeof (gdouble) * source_event->motion.device->num_axes); } } @@ -10595,12 +11189,14 @@ proxy_button_event (GdkEvent *source_event, gdouble toplevel_x, toplevel_y; GdkDisplay *display; GdkWindowObject *w; + GdkDevice *device; type = source_event->any.type; event_window = source_event->any.window; gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y); gdk_event_get_state (source_event, &state); time_ = gdk_event_get_time (source_event); + device = gdk_event_get_device (source_event); display = gdk_drawable_get_display (source_event->any.window); toplevel_window = convert_native_coords_to_toplevel (event_window, toplevel_x, toplevel_y, @@ -10608,7 +11204,7 @@ proxy_button_event (GdkEvent *source_event, if (type == GDK_BUTTON_PRESS && !source_event->any.send_event && - _gdk_display_has_pointer_grab (display, serial) == NULL) + _gdk_display_has_device_grab (display, device, serial) == NULL) { pointer_window = _gdk_window_find_descendant_at (toplevel_window, @@ -10627,22 +11223,25 @@ proxy_button_event (GdkEvent *source_event, } pointer_window = (GdkWindow *)w; - _gdk_display_add_pointer_grab (display, - pointer_window, - toplevel_window, - FALSE, - gdk_window_get_events (pointer_window), - serial, + _gdk_display_add_device_grab (display, + device, + pointer_window, + toplevel_window, + GDK_OWNERSHIP_NONE, + FALSE, + gdk_window_get_events (pointer_window), + serial, time_, - TRUE); - _gdk_display_pointer_grab_update (display, serial); + TRUE); + _gdk_display_device_grab_update (display, device, serial); } - pointer_window = get_pointer_window (display, toplevel_window, + pointer_window = get_pointer_window (display, toplevel_window, device, toplevel_x, toplevel_y, serial); event_win = get_event_window (display, + device, pointer_window, type, state, NULL, serial); @@ -10650,6 +11249,10 @@ proxy_button_event (GdkEvent *source_event, if (event_win == NULL || display->ignore_core_events) return TRUE; + if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER && + gdk_window_get_device_events (event_win, device) == 0) + return TRUE; + event = _gdk_make_event (event_win, type, source_event, FALSE); switch (type) @@ -10664,6 +11267,8 @@ proxy_button_event (GdkEvent *source_event, event->button.y_root = source_event->button.y_root; event->button.state = state; event->button.device = source_event->button.device; + event->button.axes = g_memdup (source_event->button.axes, + sizeof (gdouble) * source_event->button.device->num_axes); if (type == GDK_BUTTON_PRESS) _gdk_event_button_generate (display, event); @@ -10762,22 +11367,6 @@ gdk_window_print_tree (GdkWindow *window, #endif /* DEBUG_WINDOW_PRINTING */ -static gboolean -is_input_event (GdkDisplay *display, - GdkEvent *event) -{ - GdkDevice *core_pointer; - - core_pointer = gdk_display_get_core_pointer (display); - if ((event->type == GDK_MOTION_NOTIFY && - event->motion.device != core_pointer) || - ((event->type == GDK_BUTTON_PRESS || - event->type == GDK_BUTTON_RELEASE) && - event->button.device != core_pointer)) - return TRUE; - return FALSE; -} - void _gdk_windowing_got_event (GdkDisplay *display, GList *event_link, @@ -10789,19 +11378,39 @@ _gdk_windowing_got_event (GdkDisplay *display, gdouble x, y; gboolean unlink_event; guint old_state, old_button; - GdkPointerGrabInfo *button_release_grab; + GdkDeviceGrabInfo *button_release_grab; + GdkPointerWindowInfo *pointer_info; + GdkDevice *device; gboolean is_toplevel; if (gdk_event_get_time (event) != GDK_CURRENT_TIME) display->last_event_time = gdk_event_get_time (event); - _gdk_display_pointer_grab_update (display, - serial); + device = gdk_event_get_device (event); + + if (device) + { + GdkInputMode mode; + + g_object_get (device, "input-mode", &mode, NULL); + _gdk_display_device_grab_update (display, device, serial); + + if (mode == GDK_MODE_DISABLED || + !_gdk_display_check_grab_ownership (display, device, serial)) + { + /* Device events are blocked by another + * device grab, or the device is disabled + */ + unlink_event = TRUE; + goto out; + } + } event_window = event->any.window; if (!event_window) return; + pointer_info = _gdk_display_get_pointer_info (display, device); event_private = GDK_WINDOW_OBJECT (event_window); #ifdef DEBUG_WINDOW_PRINTING @@ -10818,31 +11427,32 @@ _gdk_windowing_got_event (GdkDisplay *display, { if (event->type == GDK_BUTTON_PRESS && !event->any.send_event && - _gdk_display_has_pointer_grab (display, serial) == NULL) + _gdk_display_has_device_grab (display, device, serial) == NULL) { - _gdk_display_add_pointer_grab (display, - event_window, - event_window, - FALSE, - gdk_window_get_events (event_window), - serial, - gdk_event_get_time (event), - TRUE); - _gdk_display_pointer_grab_update (display, - serial); + _gdk_display_add_device_grab (display, + device, + event_window, + event_window, + GDK_OWNERSHIP_NONE, + FALSE, + gdk_window_get_events (event_window), + serial, + gdk_event_get_time (event), + TRUE); + _gdk_display_device_grab_update (display, device, serial); } if (event->type == GDK_BUTTON_RELEASE && !event->any.send_event) { button_release_grab = - _gdk_display_has_pointer_grab (display, serial); + _gdk_display_has_device_grab (display, device, serial); if (button_release_grab && button_release_grab->implicit && (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0) { button_release_grab->serial_end = serial; button_release_grab->implicit_ungrab = FALSE; - _gdk_display_pointer_grab_update (display, serial); + _gdk_display_device_grab_update (display, device, serial); } } @@ -10860,9 +11470,6 @@ _gdk_windowing_got_event (GdkDisplay *display, return; } - if (is_input_event (display, event)) - return; - if (!(is_button_type (event->type) || is_motion_type (event->type)) || event_private->window_type == GDK_WINDOW_ROOT) @@ -10874,7 +11481,7 @@ _gdk_windowing_got_event (GdkDisplay *display, event->type == GDK_LEAVE_NOTIFY) && (event->crossing.mode == GDK_CROSSING_GRAB || event->crossing.mode == GDK_CROSSING_UNGRAB) && - (_gdk_display_has_pointer_grab (display, serial) || + (_gdk_display_has_device_grab (display, device, serial) || event->crossing.detail == GDK_NOTIFY_INFERIOR)) { /* We synthesize all crossing events due to grabs ourselves, @@ -10900,9 +11507,9 @@ _gdk_windowing_got_event (GdkDisplay *display, event->type == GDK_ENTER_NOTIFY && event->crossing.mode == GDK_CROSSING_UNGRAB) { - if (display->pointer_info.toplevel_under_pointer) - g_object_unref (display->pointer_info.toplevel_under_pointer); - display->pointer_info.toplevel_under_pointer = g_object_ref (event_window); + if (pointer_info->toplevel_under_pointer) + g_object_unref (pointer_info->toplevel_under_pointer); + pointer_info->toplevel_under_pointer = g_object_ref (event_window); } unlink_event = TRUE; @@ -10915,36 +11522,37 @@ _gdk_windowing_got_event (GdkDisplay *display, if (event->type == GDK_ENTER_NOTIFY && event->crossing.detail != GDK_NOTIFY_INFERIOR) { - if (display->pointer_info.toplevel_under_pointer) - g_object_unref (display->pointer_info.toplevel_under_pointer); - display->pointer_info.toplevel_under_pointer = g_object_ref (event_window); + if (pointer_info->toplevel_under_pointer) + g_object_unref (pointer_info->toplevel_under_pointer); + pointer_info->toplevel_under_pointer = g_object_ref (event_window); } else if (event->type == GDK_LEAVE_NOTIFY && event->crossing.detail != GDK_NOTIFY_INFERIOR && - display->pointer_info.toplevel_under_pointer == event_window) + pointer_info->toplevel_under_pointer == event_window) { - if (display->pointer_info.toplevel_under_pointer) - g_object_unref (display->pointer_info.toplevel_under_pointer); - display->pointer_info.toplevel_under_pointer = NULL; + if (pointer_info->toplevel_under_pointer) + g_object_unref (pointer_info->toplevel_under_pointer); + pointer_info->toplevel_under_pointer = NULL; } } /* Store last pointer window and position/state */ - old_state = display->pointer_info.state; - old_button = display->pointer_info.button; + old_state = pointer_info->state; + old_button = pointer_info->button; gdk_event_get_coords (event, &x, &y); convert_native_coords_to_toplevel (event_window, x, y, &x, &y); - display->pointer_info.toplevel_x = x; - display->pointer_info.toplevel_y = y; - gdk_event_get_state (event, &display->pointer_info.state); + pointer_info->toplevel_x = x; + pointer_info->toplevel_y = y; + gdk_event_get_state (event, &pointer_info->state); if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) - display->pointer_info.button = event->button.button; + pointer_info->button = event->button.button; - if (display->pointer_info.state != old_state || - display->pointer_info.button != old_button) - _gdk_display_enable_motion_hints (display); + if (device && + (pointer_info->state != old_state || + pointer_info->button != old_button)) + _gdk_display_enable_motion_hints (display, device); unlink_event = FALSE; if (is_motion_type (event->type)) @@ -10959,14 +11567,14 @@ _gdk_windowing_got_event (GdkDisplay *display, !event->any.send_event) { button_release_grab = - _gdk_display_has_pointer_grab (display, serial); + _gdk_display_has_device_grab (display, device, serial); if (button_release_grab && button_release_grab->implicit && (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0) { button_release_grab->serial_end = serial; button_release_grab->implicit_ungrab = FALSE; - _gdk_display_pointer_grab_update (display, serial); + _gdk_display_device_grab_update (display, device, serial); } } @@ -10989,9 +11597,10 @@ get_extension_event_window (GdkDisplay *display, guint evmask; GdkWindow *grab_window; GdkWindowObject *w; - GdkPointerGrabInfo *grab; + GdkDeviceGrabInfo *grab; - grab = _gdk_display_has_pointer_grab (display, serial); + /* FIXME: which device? */ + grab = _gdk_display_has_device_grab (display, display->core_pointer, serial); if (grab != NULL && !grab->owner_events) { @@ -11050,7 +11659,8 @@ _gdk_window_get_input_window_for_event (GdkWindow *native_window, toplevel_window = convert_native_coords_to_toplevel (native_window, toplevel_x, toplevel_y, &toplevel_x, &toplevel_y); - pointer_window = get_pointer_window (display, toplevel_window, + /* FIXME: which device? */ + pointer_window = get_pointer_window (display, toplevel_window, NULL, toplevel_x, toplevel_y, serial); event_win = get_extension_event_window (display, pointer_window, |