From 281f4d65306707944b83178cb479ee757246f0d3 Mon Sep 17 00:00:00 2001 From: Eric Koegel Date: Tue, 8 Oct 2013 14:56:35 +0300 Subject: [PATCH] Right click issues persist (Bug 9323) This patch uses the gtk_grab_add/remove functions to handle grabs prior to a menu popup. Additionally, the menu will pop up on the button press event if there's no conflict (i.e. right click DND). --- common/xfdesktop-common.c | 81 ---------------------------------- common/xfdesktop-common.h | 3 -- src/xfce-desktop.c | 108 ++++++++++++++++++---------------------------- src/xfdesktop-icon-view.c | 59 ++++++++++++++++++++----- 4 files changed, 90 insertions(+), 161 deletions(-) diff --git a/common/xfdesktop-common.c b/common/xfdesktop-common.c index 65f0214..d0f4c65 100644 --- a/common/xfdesktop-common.c +++ b/common/xfdesktop-common.c @@ -300,84 +300,3 @@ 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. - */ -gboolean -xfdesktop_popup_grab_available (GdkWindow *win, guint32 timestamp) -{ - GdkEventMask mask = - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | - GDK_POINTER_MOTION_MASK; - GdkGrabStatus g1; - GdkGrabStatus g2; - gboolean grab_failed = FALSE; - gint i = 0; - - TRACE ("entering grab_available"); - - g1 = gdk_pointer_grab (win, TRUE, mask, NULL, NULL, timestamp); - g2 = gdk_keyboard_grab (win, TRUE, timestamp); - - while ((i++ < 2500) && (grab_failed = ((g1 != GDK_GRAB_SUCCESS) - || (g2 != GDK_GRAB_SUCCESS)))) - { - TRACE ("grab not available yet, mouse reason: %d, keyboard reason: %d, waiting... (%i)", g1, g2, i); - if(g1 == GDK_GRAB_INVALID_TIME || g2 == GDK_GRAB_INVALID_TIME) - break; - - g_usleep (100); - if (g1 != GDK_GRAB_SUCCESS) - { - g1 = gdk_pointer_grab (win, TRUE, mask, NULL, NULL, timestamp); - } - if (g2 != GDK_GRAB_SUCCESS) - { - g2 = gdk_keyboard_grab (win, TRUE, timestamp); - } - } - - if (g1 == GDK_GRAB_SUCCESS) - { - gdk_pointer_ungrab (timestamp); - } - if (g2 == GDK_GRAB_SUCCESS) - { - gdk_keyboard_ungrab (timestamp); - } - - return (!grab_failed); -} diff --git a/common/xfdesktop-common.h b/common/xfdesktop-common.h index 1d6db85..e462c77 100644 --- a/common/xfdesktop-common.h +++ b/common/xfdesktop-common.h @@ -86,9 +86,6 @@ 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 #endif diff --git a/src/xfce-desktop.c b/src/xfce-desktop.c index aeebd57..82bb60d 100644 --- a/src/xfce-desktop.c +++ b/src/xfce-desktop.c @@ -849,6 +849,7 @@ xfce_desktop_init(XfceDesktop *desktop) gtk_window_set_type_hint(GTK_WINDOW(desktop), GDK_WINDOW_TYPE_HINT_DESKTOP); gtk_window_set_accept_focus(GTK_WINDOW(desktop), FALSE); + gtk_widget_set_can_focus(GTK_WIDGET(desktop), TRUE); gtk_window_set_resizable(GTK_WINDOW(desktop), FALSE); } @@ -1111,21 +1112,6 @@ 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; - - 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) @@ -1134,37 +1120,32 @@ xfce_desktop_button_press_event(GtkWidget *w, 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 + /* Let the icon view handle these menu pop ups */ if(desktop->priv->icons_style != XFCE_DESKTOP_ICON_STYLE_NONE) return FALSE; #endif - if(desktop->priv->grab_time == 0) - desktop->priv->grab_time = xfce_grab_cursor(w, evt); - else - return FALSE; + /* no icons on the desktop, grab the focus and pop up the menu */ + if(!gtk_widget_has_grab(w)) + gtk_grab_add(w); - if(desktop->priv->grab_time != 0) { - xfce_desktop_popup_root_menu(desktop, button, - desktop->priv->grab_time); + xfce_desktop_popup_root_menu(desktop, button, evt->time); return TRUE; - } } else if(button == 2 || (button == 1 && (state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))) { - if(desktop->priv->grab_time == 0) - desktop->priv->grab_time = xfce_grab_cursor(w, evt); - else - return FALSE; + /* always grab the focus and pop up the menu */ + if(!gtk_widget_has_grab(w)) + gtk_grab_add(w); - if(desktop->priv->grab_time != 0) { - xfce_desktop_popup_secondary_root_menu(desktop, button, - desktop->priv->grab_time); - return TRUE; - } + xfce_desktop_popup_secondary_root_menu(desktop, button, evt->time); + return TRUE; } } @@ -1175,17 +1156,23 @@ static gboolean xfce_desktop_button_release_event(GtkWidget *w, GdkEventButton *evt) { - xfce_desktop_release_grab(w); + TRACE("entering"); - return TRUE; + gtk_grab_remove(w); + + return FALSE; } +/* This function gets called when the user presses the menu key on the keyboard. + * Or Shift+F10 or whatever key binding the user has chosen. */ 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; @@ -1586,11 +1573,14 @@ xfce_desktop_do_menu_popup(XfceDesktop *desktop, gtk_menu_attach_to_widget(GTK_MENU(menu), GTK_WIDGET(desktop), NULL); + /* Per gtk_menu_popup's documentation "for conflict-resolve initiation of + * concurrent requests for mouse/keyboard grab requests." */ + if(activate_time == 0) + activate_time = gtk_get_current_event_time(); + /* 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 @@ -1598,24 +1588,16 @@ 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; - } - } + /* If it's launched by xfdesktop --menu we won't have an event time. + * Just grab the focus so the menu can pop up */ + if(activate_time == 0) + gtk_grab_add(GTK_WIDGET(desktop)); xfce_desktop_do_menu_popup(desktop, button, activate_time, signals[SIG_POPULATE_ROOT_MENU]); + + if(activate_time == 0) + gtk_grab_remove(GTK_WIDGET(desktop)); } void @@ -1623,24 +1605,16 @@ 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; - } - } + /* If it's launched by xfdesktop --windowlist we won't have an event time. + * Just grab the focus so the menu can pop up */ + if(activate_time == 0) + gtk_grab_add(GTK_WIDGET(desktop)); xfce_desktop_do_menu_popup(desktop, button, activate_time, signals[SIG_POPULATE_SECONDARY_ROOT_MENU]); + + if(activate_time == 0) + gtk_grab_remove(GTK_WIDGET(desktop)); } void xfce_desktop_refresh(XfceDesktop *desktop) diff --git a/src/xfdesktop-icon-view.c b/src/xfdesktop-icon-view.c index 2290884..817db45 100644 --- a/src/xfdesktop-icon-view.c +++ b/src/xfdesktop-icon-view.c @@ -686,6 +686,7 @@ xfdesktop_icon_view_init(XfdesktopIconView *icon_view) G_CALLBACK(xfdesktop_icon_view_show_tooltip), NULL); gtk_widget_set_has_window(GTK_WIDGET(icon_view), FALSE); + gtk_widget_set_can_focus(GTK_WIDGET(icon_view), TRUE); } static void @@ -789,10 +790,25 @@ xfdesktop_icon_view_button_press(GtkWidget *widget, { XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data); XfdesktopIcon *icon; - + + TRACE("entering"); + if(evt->type == GDK_BUTTON_PRESS) { GList *icon_l; - + + /* Let xfce-desktop handle button 2 */ + if(evt->button == 2) { + /* If we had the grab release it so the desktop gets the event */ + if(gtk_widget_has_grab(widget)) + gtk_grab_remove(widget); + + return FALSE; + } + + /* Grab the focus, release on button release */ + if(!gtk_widget_has_grab(widget)) + gtk_grab_add(widget); + icon_l = g_list_find_custom(icon_view->priv->icons, evt, (GCompareFunc)xfdesktop_check_icon_clicked); if(icon_l && (icon = icon_l->data)) { @@ -848,6 +864,7 @@ xfdesktop_icon_view_button_press(GtkWidget *widget, return TRUE; } else { + /* Button press wasn't over any icons */ /* unselect previously selected icons if we didn't click one */ if(icon_view->priv->sel_mode != GTK_SELECTION_MULTIPLE || !(evt->state & GDK_CONTROL_MASK)) @@ -864,6 +881,13 @@ xfdesktop_icon_view_button_press(GtkWidget *widget, icon_view->priv->press_start_x = evt->x; icon_view->priv->press_start_y = evt->y; } + + /* Since we're not over any icons this won't be the start of a + * drag so we can pop up menu */ + if(evt->button == 3 || (evt->button == 1 && (evt->state & GDK_SHIFT_MASK))) { + xfce_desktop_popup_root_menu(XFCE_DESKTOP(widget), evt->button, evt->time); + return TRUE; + } } } else if(evt->type == GDK_2BUTTON_PRESS) { /* be sure to cancel any pending drags that might have snuck through. @@ -904,7 +928,9 @@ xfdesktop_icon_view_button_release(GtkWidget *widget, gpointer user_data) { XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data); - + XfdesktopIcon *icon; + GList *icon_l = NULL; + TRACE("entering btn=%d", evt->button); /* single-click */ @@ -914,10 +940,11 @@ xfdesktop_icon_view_button_release(GtkWidget *widget, && !(evt->state & GDK_CONTROL_MASK) && !icon_view->priv->definitely_dragging && !icon_view->priv->definitely_rubber_banding) { - XfdesktopIcon *icon; - GList *icon_l = g_list_find_custom(icon_view->priv->icons, evt, - (GCompareFunc)xfdesktop_check_icon_clicked); + /* Find out if we clicked on an icon */ + icon_l = g_list_find_custom(icon_view->priv->icons, evt, + (GCompareFunc)xfdesktop_check_icon_clicked); if(icon_l && (icon = icon_l->data)) { + /* We did, activate it */ icon_view->priv->cursor = icon; g_signal_emit(G_OBJECT(icon_view), __signals[SIG_ICON_ACTIVATED], 0, NULL); @@ -930,7 +957,18 @@ 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); + /* If we're in single click mode we may already have the icon, don't + * find it again. */ + if(icon_l == NULL) { + icon_l = g_list_find_custom(icon_view->priv->icons, evt, + (GCompareFunc)xfdesktop_check_icon_clicked); + } + + /* If we clicked an icon then we didn't pop up the menu during the + * button press in order to support right click DND, pop up the menu + * now */ + if(icon_l && (icon = icon_l->data)) + xfce_desktop_popup_root_menu(XFCE_DESKTOP(widget), evt->button, evt->time); } if(evt->button == 1 || evt->button == 3) { @@ -938,15 +976,17 @@ xfdesktop_icon_view_button_release(GtkWidget *widget, icon_view->priv->definitely_dragging = FALSE; icon_view->priv->maybe_begin_drag = FALSE; if(icon_view->priv->definitely_rubber_banding) { + /* Remove the rubber band selection box */ icon_view->priv->definitely_rubber_banding = FALSE; - gtk_grab_remove(widget); gtk_widget_queue_draw_area(widget, icon_view->priv->band_rect.x, icon_view->priv->band_rect.y, icon_view->priv->band_rect.width, icon_view->priv->band_rect.height); } } - + + gtk_grab_remove(widget); + return FALSE; } @@ -1114,7 +1154,6 @@ xfdesktop_icon_view_motion_notify(GtkWidget *widget, old_rect.x = icon_view->priv->press_start_x; old_rect.y = icon_view->priv->press_start_y; old_rect.width = old_rect.height = 1; - gtk_grab_add(widget); } else memcpy(&old_rect, new_rect, sizeof(old_rect)); -- 1.8.3.2