Skip to content

Commit

Permalink
eel-gtk-extensions.c: (Wayland) Fix menu popup positioning, popup
Browse files Browse the repository at this point in the history
closing issues when using the mouse to try and change focus.

When opening the menu without the mouse (shift-F10, keyboard
context  menu key) gtk_menu_popup complains about not having
a parent, and pops up in the wrong location.

Using gtk_menu_popup_at_rect() with a fabricated rectangle based
on the pointer location works instead.

A pleasant side effect of this is that it works around another
bug where clicking off the left side of a popup fails to close
the menu or change focus at all. The menu now closes fine,
regardless of where the user clicks.

In X11 sessions gtk_menu_popup_at_pointer() is still used.

Fixes linuxmint#3218
Fixes linuxmint#3280

ref: https://bugs.kde.org/show_bug.cgi?id=453532
  • Loading branch information
mtwebster committed Jul 26, 2023
1 parent 1ae5a6d commit 031d7ec
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 45 deletions.
89 changes: 54 additions & 35 deletions eel/eel-gtk-extensions.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <X11/Xatom.h>
#include <gdk/gdk.h>
#include <gdk/gdkprivate.h>
#include <gdk/gdkwayland.h>
#include <gtk/gtk.h>
#include <glib/gi18n-lib.h>
#include <math.h>
Expand Down Expand Up @@ -247,53 +248,71 @@ eel_gtk_window_set_initial_geometry_from_string (GtkWindow *window,
eel_gtk_window_set_initial_geometry (window, geometry_flags, left, top, width, height);
}

static void
create_popup_rect (GdkWindow *window, GdkRectangle *rect)
{
GdkSeat *seat;
GdkDevice *device;

seat = gdk_display_get_default_seat (gdk_display_get_default ());

if (seat != NULL) {
device = gdk_seat_get_pointer (seat);

if (device != NULL) {
gint x, y;

gdk_window_get_device_position (window, device, &x, &y, NULL);
rect->x = x;
rect->y = y;
rect->width = 2;
rect->height = 2;
}
}
}

/**
* eel_pop_up_context_menu:
*
* Pop up a context menu under the mouse.
* The menu is sunk after use, so it will be destroyed unless the
* caller first ref'ed it.
*
* This function is more of a helper function than a gtk extension,
* so perhaps it belongs in a different file.
*
* @menu: The menu to pop up under the mouse.
* @offset_x: Ignored.
* @offset_y: Ignored.
* @event: The event that invoked this popup menu, or #NULL if there
* is no event available. This is used to get the timestamp for the menu's popup.
* In case no event is provided, gtk_get_current_event_time() will be used automatically.
**/
void
eel_pop_up_context_menu (GtkMenu *menu,
GdkEventButton *event)
eel_pop_up_context_menu (GtkMenu *menu,
GdkEvent *event,
GtkWidget *widget)
{
int button;
g_return_if_fail (GTK_IS_MENU (menu));
static gboolean using_wayland = FALSE;
static gsize once_init = 0;

g_return_if_fail (GTK_IS_MENU (menu));
if (g_once_init_enter (&once_init)) {
using_wayland = GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ());

/* The event button needs to be 0 if we're popping up this menu from
* a button release, else a 2nd click outside the menu with any button
* other than the one that invoked the menu will be ignored (instead
* of dismissing the menu). This is a subtle fragility of the GTK menu code.
*/

if (event) {
button = event->type == GDK_BUTTON_RELEASE ? 0 : event->button;
} else {
button = 0;
}
g_once_init_leave (&once_init, 1);
}

if (button > 0) {
gtk_menu_popup_at_pointer (menu, (GdkEvent *) event);
} else {
gtk_menu_popup (menu, /* menu */
NULL, /* parent_menu_shell */
NULL, /* parent_menu_item */
NULL, /* popup_position_func */
NULL, /* popup_position_data */
button, /* button */
event ? event->time : gtk_get_current_event_time ()); /* activate_time */
// Using gtk_menu_popup_at_rect exclusively in wayland seems to avoid the problem
// of being unable to dismiss the menu when clicking to the left of it. See:
// https://github.com/linuxmint/nemo/issues/3218

#ifdef GDK_WINDOWING_X11
if (!using_wayland && event && event->type == GDK_BUTTON_PRESS) {
gtk_menu_popup_at_pointer (menu, event);
} else
#endif
{
GdkWindow *window = gtk_widget_get_window (gtk_widget_get_toplevel (widget));

GdkRectangle rect;
create_popup_rect (window, &rect);
gtk_menu_popup_at_rect (menu,
window,
&rect,
GDK_GRAVITY_NORTH_WEST,
GDK_GRAVITY_NORTH_WEST,
NULL);
}

g_object_ref_sink (menu);
Expand Down
3 changes: 2 additions & 1 deletion eel/eel-gtk-extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ char * eel_gtk_window_get_geometry_string (GtkWindow

/* GtkMenu and GtkMenuItem */
void eel_pop_up_context_menu (GtkMenu *menu,
GdkEventButton *event);
GdkEvent *event,
GtkWidget *widget);
GtkMenuItem * eel_gtk_menu_append_separator (GtkMenu *menu);
GtkMenuItem * eel_gtk_menu_insert_separator (GtkMenu *menu,
int index);
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ glib_version = '>=2.45.7'
math = cc.find_library('m', required: true)

gtk = dependency('gtk+-3.0', version: '>=3.10.0')
gtk_wl = dependency('gtk+-wayland-3.0', version: '>=3.10.0')
gio = dependency('gio-2.0', version: glib_version)
gio_unix= dependency('gio-unix-2.0', version: glib_version)
glib = dependency('glib-2.0', version: glib_version)
Expand Down
3 changes: 2 additions & 1 deletion src/nemo-blank-desktop-window.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ do_popup_menu (NemoBlankDesktopWindow *window, GdkEventButton *event)
}

eel_pop_up_context_menu (GTK_MENU(window->details->popup_menu),
event);
(GdkEvent *) event,
GTK_WIDGET (window));
}

static gboolean
Expand Down
7 changes: 4 additions & 3 deletions src/nemo-places-sidebar.c
Original file line number Diff line number Diff line change
Expand Up @@ -3689,9 +3689,10 @@ static void
bookmarks_popup_menu (NemoPlacesSidebar *sidebar,
GdkEventButton *event)
{
bookmarks_update_popup_menu (sidebar);
eel_pop_up_context_menu (GTK_MENU(sidebar->popup_menu),
event);
bookmarks_update_popup_menu (sidebar);
eel_pop_up_context_menu (GTK_MENU(sidebar->popup_menu),
(GdkEvent *) event,
GTK_WIDGET (sidebar));
}

/* Callback used for the GtkWidget::popup-menu signal of the shortcuts list */
Expand Down
12 changes: 7 additions & 5 deletions src/nemo-view.c
Original file line number Diff line number Diff line change
Expand Up @@ -10117,9 +10117,9 @@ nemo_view_pop_up_selection_context_menu (NemoView *view,
nemo_view_update_actions_and_extensions (view);
update_context_menu_position_from_event (view, event);

eel_pop_up_context_menu (create_popup_menu
(view, NEMO_VIEW_POPUP_PATH_SELECTION),
event);
eel_pop_up_context_menu (create_popup_menu (view, NEMO_VIEW_POPUP_PATH_SELECTION),
(GdkEvent *) event,
GTK_WIDGET (view));
}

/**
Expand All @@ -10145,7 +10145,8 @@ nemo_view_pop_up_background_context_menu (NemoView *view,

eel_pop_up_context_menu (create_popup_menu
(view, NEMO_VIEW_POPUP_PATH_BACKGROUND),
event);
(GdkEvent *) event,
GTK_WIDGET (view));
}

static void
Expand All @@ -10158,7 +10159,8 @@ real_pop_up_location_context_menu (NemoView *view)

eel_pop_up_context_menu (create_popup_menu
(view, NEMO_VIEW_POPUP_PATH_LOCATION),
view->details->location_popup_event);
(GdkEvent *) view->details->location_popup_event,
GTK_WIDGET (view));
}

static void
Expand Down

0 comments on commit 031d7ec

Please sign in to comment.