gtkwindow: Use window-manager-side window menus

This avoids a bunch of policy problems with deciding how to lay
out the window menu under different WMs.

For now, we use the special event _GTK_SHOW_WINDOW_MENU, but we
hope to have this standardized in wm-spec quite soon, as KDE wants
it as well.
This commit is contained in:
Jasper St. Pierre
2014-03-13 17:28:01 -04:00
parent 02d92ff831
commit 0ea1a526f9
5 changed files with 91 additions and 189 deletions

View File

@ -10921,3 +10921,36 @@ gdk_window_set_shadow_width (GdkWindow *window,
if (impl_class->set_shadow_width)
impl_class->set_shadow_width (window, left, right, top, bottom);
}
/**
* gdk_window_show_window_menu:
* @window: a #GdkWindow
* @event: a #GdkEvent to show the menu for
*
* Asks the window menu to show the window menu. The window menu is
* the menu shown when right-clicking the titlebar on traditional
* windows managed by the window manager. This is useful for windows
* using client-side decorations, activating it with a right-click
* on the window decorations.
*
* Returns: %TRUE if the window menu was shown by the window
* manager and %FALSE otherwise.
*
* Since: 3.14
*/
gboolean
gdk_window_show_window_menu (GdkWindow *window,
GdkEvent *event)
{
GdkWindowImplClass *impl_class;
g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
g_return_val_if_fail (!GDK_WINDOW_DESTROYED (window), FALSE);
impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
if (impl_class->show_window_menu)
return impl_class->show_window_menu (window, event);
else
return FALSE;
}

View File

@ -1100,6 +1100,9 @@ void gdk_window_set_shadow_width (GdkWindow *window,
gint right,
gint top,
gint bottom);
GDK_AVAILABLE_IN_3_14
gboolean gdk_window_show_window_menu (GdkWindow *window,
GdkEvent *event);
G_END_DECLS

View File

@ -301,6 +301,8 @@ struct _GdkWindowImplClass
gint right,
gint top,
gint bottom);
gboolean (* show_window_menu) (GdkWindow *window,
GdkEvent *event);
};
/* Interface Functions */

View File

@ -5702,6 +5702,47 @@ gdk_x11_window_set_opaque_region (GdkWindow *window,
g_free (data);
}
static gboolean
gdk_x11_window_show_window_menu (GdkWindow *window,
GdkEvent *event)
{
GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
GdkDevice *device;
int device_id;
XClientMessageEvent xclient = { 0 };
switch (event->type)
{
case GDK_BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
break;
default:
return FALSE;
}
if (!gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
gdk_atom_intern_static_string ("_GTK_SHOW_WINDOW_MENU")))
return FALSE;
device = gdk_event_get_device (event);
g_object_get (G_OBJECT (device),
"device-id", &device_id,
NULL);
xclient.type = ClientMessage;
xclient.window = GDK_WINDOW_XID (window);
xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_GTK_SHOW_WINDOW_MENU");
xclient.data.l[0] = device_id;
xclient.format = 32;
XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
SubstructureRedirectMask | SubstructureNotifyMask,
(XEvent *)&xclient);
return TRUE;
}
static void
gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
{
@ -5791,4 +5832,5 @@ gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
impl_class->get_scale_factor = gdk_x11_window_get_scale_factor;
impl_class->set_opaque_region = gdk_x11_window_set_opaque_region;
impl_class->set_shadow_width = gdk_x11_window_set_shadow_width;
impl_class->show_window_menu = gdk_x11_window_show_window_menu;
}