Skip to content

Commit 4a9b52e

Browse files
committed
Stop crashing when a context menu opens relative to a window on Linux
Window::GetNativeObject() returns the toplevel GtkWidget* on Linux, but Menu::Open cast it straight to GdkWindow* and handed it to gdk_window_get_frame_extents() — a segfault on every right click through ContextMenuRegion, which opens the menu with a window-relative strategy. The same pointer went on to gtk_menu_popup_at_rect(). Take the widget as a GtkWidget*, check it really is a GtkWindow, and get the GdkWindow from gtk_widget_get_window(). That also hands the Relative branch the GtkWindow it was searching gtk_window_list_toplevels() for, so the search goes. Verified on Ubuntu 24.04 (GNOME 46, Wayland): right click in menu_example segfaulted in gdk_window_get_frame_extents before, opens the menu after.
1 parent 522df16 commit 4a9b52e

1 file changed

Lines changed: 9 additions & 16 deletions

File tree

‎src/platform/linux/menu_linux.cpp‎

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -693,11 +693,15 @@ bool Menu::Open(const PositioningStrategy& strategy, Placement placement) {
693693

694694
// Get GdkWindow from relative window if available, otherwise use root window
695695
GdkWindow* gdk_window = nullptr;
696+
GtkWindow* relative_gtk_window = nullptr;
696697
const Window* relative_window = strategy.GetRelativeWindow();
697698
if (relative_window) {
698-
void* native_obj = relative_window->GetNativeObject();
699-
if (native_obj) {
700-
gdk_window = static_cast<GdkWindow*>(native_obj);
699+
// Window::GetNativeObject() hands out the toplevel GtkWidget*, not its GdkWindow:
700+
// passing it straight to a gdk_window_* call crashes.
701+
GtkWidget* widget = static_cast<GtkWidget*>(relative_window->GetNativeObject());
702+
if (widget && GTK_IS_WINDOW(widget)) {
703+
relative_gtk_window = GTK_WINDOW(widget);
704+
gdk_window = gtk_widget_get_window(widget); // null until the window is realized
701705
}
702706
}
703707
if (!gdk_window) {
@@ -756,22 +760,11 @@ bool Menu::Open(const PositioningStrategy& strategy, Placement placement) {
756760
Point position = Point{rect.x + offset.x, rect.y + offset.y};
757761

758762
// If we have a relative window, adjust for frame extents and title bar
759-
if (relative_window && relative_window->GetNativeObject()) {
763+
if (relative_gtk_window && gdk_window) {
760764
GdkRectangle frame_rectangle;
761765
gdk_window_get_frame_extents(gdk_window, &frame_rectangle);
762766

763-
// Get GtkWindow for window position and title bar
764-
GtkWindow* gtk_window = nullptr;
765-
GList* toplevels = gtk_window_list_toplevels();
766-
for (GList* l = toplevels; l != nullptr; l = l->next) {
767-
GtkWindow* candidate = GTK_WINDOW(l->data);
768-
GdkWindow* candidate_gdk = gtk_widget_get_window(GTK_WIDGET(candidate));
769-
if (candidate_gdk == gdk_window) {
770-
gtk_window = candidate;
771-
break;
772-
}
773-
}
774-
g_list_free(toplevels);
767+
GtkWindow* gtk_window = relative_gtk_window;
775768

776769
// Get window position using gtk_window_get_position (works better on Wayland)
777770
gint window_x = 0, window_y = 0;

0 commit comments

Comments
 (0)