From d5b5673118571b2b1ee04e21196667306793f602 Mon Sep 17 00:00:00 2001 From: Eric Koegel Date: Mon, 26 Aug 2013 11:19:23 +0300 Subject: [PATCH] Hold the cursor grab when presenting the menu (Bug 9105, 9323) Rewrite how key press and release events are handled so that the right-click menu appears more consistently and will disappear when any spawned dialogs are closed. --- common/xfdesktop-common.c | 30 ++++++++++ common/xfdesktop-common.h | 2 + src/main.c | 6 +- src/xfce-desktop.c | 148 +++++++++++++++++++++++++++++++++++----------- src/xfdesktop-icon-view.c | 4 +- 5 files changed, 148 insertions(+), 42 deletions(-) diff --git a/common/xfdesktop-common.c b/common/xfdesktop-common.c index 755e273..f36d9fa 100644 --- a/common/xfdesktop-common.c +++ b/common/xfdesktop-common.c @@ -301,6 +301,36 @@ xfdesktop_send_client_message(Window xid, const gchar *msg) gtk_widget_destroy(win); } +guint +xfce_grab_cursor(GtkWidget *w, + GdkEventButton *evt) +{ + GdkCursor *cursor; + GdkGrabStatus status; + GdkDisplay *display; + + TRACE("entering"); + + /* create a cursor */ + display = gdk_screen_get_display(gtk_widget_get_screen(w)); + cursor = gdk_cursor_new_for_display(display, GDK_FLEUR); + + /* grab the pointer for the desktop */ + status = gdk_pointer_grab(evt->window, FALSE, + GDK_BUTTON_MOTION_MASK + | GDK_BUTTON_RELEASE_MASK, + NULL, cursor, evt->time); + + gdk_cursor_unref(cursor); + + if(status != GDK_GRAB_SUCCESS) { + g_warning("mouse grab failed."); + return 0; + } + + return evt->time; +} + /* Code taken from xfwm4/src/menu.c:grab_available(). This should fix the case * where binding 'xfdesktop -menu' to a keyboard shortcut sometimes works and * sometimes doesn't. Credit for this one goes to Olivier. diff --git a/common/xfdesktop-common.h b/common/xfdesktop-common.h index b34d7b5..d95ec59 100644 --- a/common/xfdesktop-common.h +++ b/common/xfdesktop-common.h @@ -28,6 +28,7 @@ #include #include +#include #include @@ -84,6 +85,7 @@ gchar *xfdesktop_get_file_mimetype(const gchar *file); gboolean xfdesktop_check_is_running(Window *xid); void xfdesktop_send_client_message(Window xid, const gchar *msg); +guint xfce_grab_cursor(GtkWidget *w, GdkEventButton *evt); gboolean xfdesktop_popup_grab_available(GdkWindow *win, guint32 timestamp); G_END_DECLS diff --git a/src/main.c b/src/main.c index f8b7063..cdf5612 100644 --- a/src/main.c +++ b/src/main.c @@ -182,12 +182,10 @@ client_message_received(GtkWidget *w, GdkEventClient *evt, gpointer user_data) g_idle_add((GSourceFunc)reload_idle_cb, user_data); return TRUE; } else if(!strcmp(MENU_MESSAGE, evt->data.b)) { - xfce_desktop_popup_root_menu(XFCE_DESKTOP(w), 0, - GDK_CURRENT_TIME); + xfce_desktop_popup_root_menu(XFCE_DESKTOP(w), 0, 0); return TRUE; } else if(!strcmp(WINDOWLIST_MESSAGE, evt->data.b)) { - xfce_desktop_popup_secondary_root_menu(XFCE_DESKTOP(w), 0, - GDK_CURRENT_TIME); + xfce_desktop_popup_secondary_root_menu(XFCE_DESKTOP(w), 0, 0); return TRUE; #ifdef ENABLE_FILE_ICONS } else if(!strcmp(ARRANGE_MESSAGE, evt->data.b)) { diff --git a/src/xfce-desktop.c b/src/xfce-desktop.c index 149a833..6ba6686 100644 --- a/src/xfce-desktop.c +++ b/src/xfce-desktop.c @@ -106,7 +106,9 @@ struct _XfceDesktopPriv gint single_workspace_num; SessionLogoutFunc session_logout_func; - + + guint32 grab_time; + #ifdef ENABLE_DESKTOP_ICONS XfceDesktopIconStyle icons_style; gboolean icons_font_size_set; @@ -152,6 +154,8 @@ static void xfce_desktop_realize(GtkWidget *widget); static void xfce_desktop_unrealize(GtkWidget *widget); static gboolean xfce_desktop_button_press_event(GtkWidget *widget, GdkEventButton *evt); +static gboolean xfce_desktop_button_release_event(GtkWidget *widget, + GdkEventButton *evt); static gboolean xfce_desktop_popup_menu(GtkWidget *widget); static gboolean xfce_desktop_expose(GtkWidget *w, @@ -723,6 +727,7 @@ xfce_desktop_class_init(XfceDesktopClass *klass) widget_class->realize = xfce_desktop_realize; widget_class->unrealize = xfce_desktop_unrealize; widget_class->button_press_event = xfce_desktop_button_press_event; + widget_class->button_release_event = xfce_desktop_button_release_event; widget_class->expose_event = xfce_desktop_expose; widget_class->delete_event = xfce_desktop_delete_event; widget_class->popup_menu = xfce_desktop_popup_menu; @@ -1093,29 +1098,64 @@ xfce_desktop_unrealize(GtkWidget *widget) gtk_widget_set_realized(widget, FALSE); } +static void +xfce_desktop_release_grab(GtkWidget *w) +{ + XfceDesktop *desktop = XFCE_DESKTOP(w); + GdkDisplay *display; + + TRACE("entering"); + + g_return_if_fail(XFCE_IS_DESKTOP(w)); + + if(desktop->priv->grab_time != 0) { + display = gdk_screen_get_display(desktop->priv->gscreen); + gdk_display_pointer_ungrab(display, desktop->priv->grab_time); + desktop->priv->grab_time = 0; + } +} + static gboolean xfce_desktop_button_press_event(GtkWidget *w, GdkEventButton *evt) { guint button = evt->button; guint state = evt->state; + XfceDesktop *desktop = XFCE_DESKTOP(w); + + TRACE("entering"); + g_return_val_if_fail(XFCE_IS_DESKTOP(w), FALSE); if(evt->type == GDK_BUTTON_PRESS) { if(button == 3 || (button == 1 && (state & GDK_SHIFT_MASK))) { #ifdef ENABLE_DESKTOP_ICONS - if(XFCE_DESKTOP(w)->priv->icons_style != XFCE_DESKTOP_ICON_STYLE_NONE) + if(desktop->priv->icons_style != XFCE_DESKTOP_ICON_STYLE_NONE) return FALSE; #endif - xfce_desktop_popup_root_menu(XFCE_DESKTOP(w), - button, - evt->time); + if(desktop->priv->grab_time == 0) + desktop->priv->grab_time = xfce_grab_cursor(w, evt); + else + return FALSE; + + if(desktop->priv->grab_time != 0) { + xfce_desktop_popup_root_menu(desktop, button, + desktop->priv->grab_time); + return TRUE; + } } else if(button == 2 || (button == 1 && (state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))) { - xfce_desktop_popup_secondary_root_menu(XFCE_DESKTOP(w), - button, evt->time); - return TRUE; + if(desktop->priv->grab_time == 0) + desktop->priv->grab_time = xfce_grab_cursor(w, evt); + else + return FALSE; + + if(desktop->priv->grab_time != 0) { + xfce_desktop_popup_secondary_root_menu(desktop, button, + desktop->priv->grab_time); + return TRUE; + } } } @@ -1123,11 +1163,22 @@ xfce_desktop_button_press_event(GtkWidget *w, } static gboolean +xfce_desktop_button_release_event(GtkWidget *w, + GdkEventButton *evt) +{ + xfce_desktop_release_grab(w); + + return TRUE; +} + +static gboolean xfce_desktop_popup_menu(GtkWidget *w) { GdkEventButton *evt; guint button, etime; - + + TRACE("entering"); + evt = (GdkEventButton *)gtk_get_current_event(); if(evt && GDK_BUTTON_PRESS == evt->type) { button = evt->button; @@ -1510,34 +1561,30 @@ xfce_desktop_do_menu_popup(XfceDesktop *desktop, else screen = gdk_display_get_default_screen(gdk_display_get_default()); - if(xfdesktop_popup_grab_available(gdk_screen_get_root_window(screen), - activate_time)) - { - menu = gtk_menu_new(); - gtk_menu_set_screen(GTK_MENU(menu), screen); - g_signal_connect_swapped(G_OBJECT(menu), "deactivate", - G_CALLBACK(g_idle_add), - (gpointer)xfce_desktop_menu_destroy_idled); - - g_signal_emit(G_OBJECT(desktop), populate_signal, 0, menu); - - /* if nobody populated the menu, don't do anything */ - menu_children = gtk_container_get_children(GTK_CONTAINER(menu)); - if(!menu_children) { - gtk_widget_destroy(menu); - return; - } + menu = gtk_menu_new(); + gtk_menu_set_screen(GTK_MENU(menu), screen); + g_signal_connect_swapped(G_OBJECT(menu), "deactivate", + G_CALLBACK(g_idle_add), + (gpointer)xfce_desktop_menu_destroy_idled); + + g_signal_emit(G_OBJECT(desktop), populate_signal, 0, menu); + + /* if nobody populated the menu, don't do anything */ + menu_children = gtk_container_get_children(GTK_CONTAINER(menu)); + if(!menu_children) { + gtk_widget_destroy(menu); + return; + } - g_list_free(menu_children); + g_list_free(menu_children); - gtk_menu_attach_to_widget(GTK_MENU(menu), GTK_WIDGET(desktop), NULL); + gtk_menu_attach_to_widget(GTK_MENU(menu), GTK_WIDGET(desktop), NULL); - /* bug #3652: for some reason passing the correct button here breaks - * on some systems but not others. always pass 0 for now. */ - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, - activate_time); - } else - g_critical("Unable to get keyboard/mouse grab. Unable to pop up menu"); + /* bug #3652: for some reason passing the correct button here breaks + * on some systems but not others. always pass 0 for now. */ + gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, activate_time); + + xfce_desktop_release_grab(GTK_WIDGET(desktop)); } void @@ -1545,6 +1592,22 @@ xfce_desktop_popup_root_menu(XfceDesktop *desktop, guint button, guint activate_time) { + GdkScreen *screen; + + if(gtk_widget_has_screen(GTK_WIDGET(desktop))) + screen = gtk_widget_get_screen(GTK_WIDGET(desktop)); + else + screen = gdk_display_get_default_screen(gdk_display_get_default()); + + if(activate_time == 0) { + activate_time = GDK_CURRENT_TIME; + if(!xfdesktop_popup_grab_available(gdk_screen_get_root_window(screen), + activate_time)) { + g_critical("keyboard or mouse grab failed."); + return; + } + } + xfce_desktop_do_menu_popup(desktop, button, activate_time, signals[SIG_POPULATE_ROOT_MENU]); } @@ -1554,10 +1617,25 @@ xfce_desktop_popup_secondary_root_menu(XfceDesktop *desktop, guint button, guint activate_time) { + GdkScreen *screen; + + if(gtk_widget_has_screen(GTK_WIDGET(desktop))) + screen = gtk_widget_get_screen(GTK_WIDGET(desktop)); + else + screen = gdk_display_get_default_screen(gdk_display_get_default()); + + if(activate_time == 0) { + activate_time = GDK_CURRENT_TIME; + if(!xfdesktop_popup_grab_available(gdk_screen_get_root_window(screen), + activate_time)) { + g_critical("keyboard or mouse grab failed."); + return; + } + } + xfce_desktop_do_menu_popup(desktop, button, activate_time, signals[SIG_POPULATE_SECONDARY_ROOT_MENU]); } - void xfce_desktop_refresh(XfceDesktop *desktop) { diff --git a/src/xfdesktop-icon-view.c b/src/xfdesktop-icon-view.c index 6a8f223..0691570 100644 --- a/src/xfdesktop-icon-view.c +++ b/src/xfdesktop-icon-view.c @@ -922,9 +922,7 @@ xfdesktop_icon_view_button_release(GtkWidget *widget, icon_view->priv->definitely_dragging == FALSE && icon_view->priv->definitely_rubber_banding == FALSE) { - xfce_desktop_popup_root_menu(XFCE_DESKTOP(widget), - evt->button, - evt->time); + xfce_desktop_popup_root_menu(XFCE_DESKTOP(widget), evt->button, evt->time); } if(evt->button == 1 || evt->button == 3) { -- 1.8.1.2