From 2782011ce8f79e4f4acbd8a4f4b64817bbca177b Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Wed, 19 Jan 2011 10:29:50 -0500 Subject: [PATCH] shell-global: try to resync the pointer state after grabs If the pointer moves on or off the stage while another process has a grab, we will lose track of it. One example of this is that if you use a popup menu from a message tray trayicon, the tray will stay up after the menu goes away, because the shell never saw the pointer leave it. Add a new method shell_global_sync_pointer() that causes clutter to recheck what actor is under the pointer and generate leave/enter events if appropriate. Of course, we can't actually tell for sure when another process has a grab, so we need a heuristic of when to call this. Currently we call it from Chrome._windowsRestacked(), which is not really the right thing at all, but does fix the menu-from-trayicon case... https://bugzilla.gnome.org/show_bug.cgi?id=630842 --- js/ui/chrome.js | 5 +++++ src/shell-global.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/shell-global.h | 9 +++++---- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/js/ui/chrome.js b/js/ui/chrome.js index 32b8f04f4..27779fcf3 100644 --- a/js/ui/chrome.js +++ b/js/ui/chrome.js @@ -335,6 +335,11 @@ Chrome.prototype = { this._updateVisibility(); this._queueUpdateRegions(); } + + // Figure out where the pointer is in case we lost track of + // it during a grab. (In particular, if a trayicon popup menu + // is dismissed, see if we need to close the message tray.) + global.sync_pointer(); }, _updateRegions: function() { diff --git a/src/shell-global.c b/src/shell-global.c index 32836cba5..44f4aff66 100644 --- a/src/shell-global.c +++ b/src/shell-global.c @@ -1490,6 +1490,48 @@ shell_global_get_pointer (ShellGlobal *global, *mods = raw_mods & GDK_MODIFIER_MASK; } +/** + * shell_global_sync_pointer: + * @global: the #ShellGlobal + * + * Ensures that clutter is aware of the current pointer position, + * causing enter and leave events to be emitted if the pointer moved + * behind our back (ie, during a pointer grab). + */ +void +shell_global_sync_pointer (ShellGlobal *global) +{ + int x, y; + GdkModifierType mods; + ClutterMotionEvent event; + + gdk_display_get_pointer (gdk_display_get_default (), NULL, &x, &y, &mods); + + event.type = CLUTTER_MOTION; + event.time = shell_global_get_current_time (global); + event.flags = 0; + /* This is wrong: we should be setting event.stage to NULL if the + * pointer is not inside the bounds of the stage given the current + * stage_input_mode. For our current purposes however, this works. + */ + event.stage = CLUTTER_STAGE (meta_plugin_get_stage (global->plugin)); + event.x = x; + event.y = y; + event.modifier_state = mods; + event.axes = NULL; + event.device = clutter_device_manager_get_core_device (clutter_device_manager_get_default (), + CLUTTER_POINTER_DEVICE); + + /* Leaving event.source NULL will force clutter to look it up, which + * will generate enter/leave events as a side effect, if they are + * needed. We need a better way to do this though... see + * http://bugzilla.clutter-project.org/show_bug.cgi?id=2615. + */ + event.source = NULL; + + clutter_event_put ((ClutterEvent *)&event); +} + /** * shell_get_event_state: * @event: a #ClutterEvent diff --git a/src/shell-global.h b/src/shell-global.h index 40f9a8f9b..cda10e455 100644 --- a/src/shell-global.h +++ b/src/shell-global.h @@ -103,10 +103,11 @@ MetaRectangle *shell_global_get_primary_monitor (ShellGlobal *global); int shell_global_get_primary_monitor_index (ShellGlobal *global); MetaRectangle *shell_global_get_focus_monitor (ShellGlobal *global); -void shell_global_get_pointer (ShellGlobal *global, - int *x, - int *y, - ClutterModifierType *mods); +void shell_global_get_pointer (ShellGlobal *global, + int *x, + int *y, + ClutterModifierType *mods); +void shell_global_sync_pointer (ShellGlobal *global); GSettings *shell_global_get_settings (ShellGlobal *global);