[gtk+] gtkwindow: Use window-manager-side window menus
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] gtkwindow: Use window-manager-side window menus
- Date: Wed, 21 May 2014 22:53:31 +0000 (UTC)
commit 0ea1a526f93411f8a2aef60dcb5a429a7694ca99
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Thu Mar 13 17:28:01 2014 -0400
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.
gdk/gdkwindow.c | 33 ++++++++
gdk/gdkwindow.h | 3 +
gdk/gdkwindowimpl.h | 2 +
gdk/x11/gdkwindow-x11.c | 42 ++++++++++
gtk/gtkwindow.c | 200 +++--------------------------------------------
5 files changed, 91 insertions(+), 189 deletions(-)
---
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index e50601a..7f72dca 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -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;
+}
diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h
index d6c7205..09a4af3 100644
--- a/gdk/gdkwindow.h
+++ b/gdk/gdkwindow.h
@@ -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
diff --git a/gdk/gdkwindowimpl.h b/gdk/gdkwindowimpl.h
index bd1714d..b1e9290 100644
--- a/gdk/gdkwindowimpl.h
+++ b/gdk/gdkwindowimpl.h
@@ -301,6 +301,8 @@ struct _GdkWindowImplClass
gint right,
gint top,
gint bottom);
+ gboolean (* show_window_menu) (GdkWindow *window,
+ GdkEvent *event);
};
/* Interface Functions */
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index e5e0b23..d3120a6 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -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;
}
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 20f7251..537cdf1 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -8633,48 +8633,6 @@ popup_position_func (GtkMenu *menu,
}
static void
-ontop_window_clicked (GtkMenuItem *menuitem,
- gpointer user_data)
-{
- GtkWindow *window = (GtkWindow *)user_data;
-
- gtk_window_set_keep_above (window, !window->priv->above_initially);
-}
-
-#ifdef GDK_WINDOWING_X11
-static void
-stick_window_clicked (GtkMenuItem *menuitem,
- gpointer user_data)
-{
- GtkWindow *window = (GtkWindow *)user_data;
-
- gtk_window_stick (window);
-}
-
-static void
-unstick_window_clicked (GtkMenuItem *menuitem,
- gpointer user_data)
-{
- GtkWindow *window = (GtkWindow *)user_data;
-
- gtk_window_unstick (window);
-}
-
-static void
-workspace_change_clicked (GtkMenuItem *menuitem,
- gpointer user_data)
-{
- GtkWindow *window = (GtkWindow *)user_data;
- GdkWindow *gdk_window;
- guint32 desktop;
-
- gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
- desktop = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (menuitem), "workspace"));
- gdk_x11_window_move_to_desktop (gdk_window, desktop);
-}
-#endif
-
-static void
close_window_clicked (GtkMenuItem *menuitem,
gpointer user_data)
{
@@ -8685,30 +8643,8 @@ close_window_clicked (GtkMenuItem *menuitem,
}
static void
-move_window_clicked (GtkMenuItem *menuitem,
- gpointer user_data)
-{
- GtkWidget *widget = (GtkWidget *)user_data;
-
- gdk_window_begin_move_drag (gtk_widget_get_window (widget),
- 0, 0, 0,
- gtk_get_current_event_time ());
-}
-
-static void
-resize_window_clicked (GtkMenuItem *menuitem,
- gpointer user_data)
-{
- GtkWidget *widget = (GtkWidget *)user_data;
-
- gdk_window_begin_resize_drag (gtk_widget_get_window (widget),
- 0, 0, 0, 0,
- gtk_get_current_event_time ());
-}
-
-static void
-gtk_window_do_popup (GtkWindow *window,
- GdkEventButton *event)
+gtk_window_do_popup_fallback (GtkWindow *window,
+ GdkEventButton *event)
{
GtkWindowPrivate *priv = window->priv;
GtkWidget *menuitem;
@@ -8724,129 +8660,6 @@ gtk_window_do_popup (GtkWindow *window,
GTK_WIDGET (window),
popup_menu_detach);
- menuitem = gtk_menu_item_new_with_label (_("Minimize"));
- gtk_widget_show (menuitem);
- if (priv->gdk_type_hint != GDK_WINDOW_TYPE_HINT_NORMAL)
- gtk_widget_set_sensitive (menuitem, FALSE);
- g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
- G_CALLBACK (gtk_window_iconify), window);
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
-
- menuitem = gtk_menu_item_new_with_label (priv->maximized ? _("Unmaximize") : _("Maximize"));
- gtk_widget_show (menuitem);
- if (!priv->resizable ||
- priv->gdk_type_hint != GDK_WINDOW_TYPE_HINT_NORMAL)
- gtk_widget_set_sensitive (menuitem, FALSE);
- g_signal_connect_swapped (G_OBJECT (menuitem), "activate",
- G_CALLBACK (_gtk_window_toggle_maximized), window);
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
-
- menuitem = gtk_menu_item_new_with_label (_("Move"));
- gtk_widget_show (menuitem);
- g_signal_connect (G_OBJECT (menuitem), "activate",
- G_CALLBACK (move_window_clicked), window);
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
-
- menuitem = gtk_menu_item_new_with_label (_("Resize"));
- gtk_widget_show (menuitem);
- if (!priv->resizable || priv->maximized)
- gtk_widget_set_sensitive (menuitem, FALSE);
- g_signal_connect (G_OBJECT (menuitem), "activate",
- G_CALLBACK (resize_window_clicked), window);
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
-
- menuitem = gtk_separator_menu_item_new ();
- gtk_widget_show (menuitem);
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
-
- menuitem = gtk_check_menu_item_new_with_label (_("Always on Top"));
- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), priv->above_initially);
- if (priv->maximized)
- gtk_widget_set_sensitive (menuitem, FALSE);
- gtk_widget_show (menuitem);
- g_signal_connect (G_OBJECT (menuitem), "activate",
- G_CALLBACK (ontop_window_clicked), window);
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
-
-#ifdef GDK_WINDOWING_X11
- if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
- {
- menuitem = gtk_check_menu_item_new_with_label (_("Always on Visible Workspace"));
- gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (menuitem), TRUE);
- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), priv->stick_initially);
- gtk_widget_show (menuitem);
- g_signal_connect (G_OBJECT (menuitem), "activate",
- G_CALLBACK (stick_window_clicked), window);
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
-
- menuitem = gtk_check_menu_item_new_with_label (_("Only on This Workspace"));
- gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (menuitem), TRUE);
- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), !priv->stick_initially);
- gtk_widget_show (menuitem);
- g_signal_connect (G_OBJECT (menuitem), "activate",
- G_CALLBACK (unstick_window_clicked), window);
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
-
- if (!priv->stick_initially)
- {
- guint32 n_desktops, desktop;
-
- n_desktops = gdk_x11_screen_get_number_of_desktops (gtk_widget_get_screen (GTK_WIDGET (window)));
- desktop = gdk_x11_window_get_desktop (gtk_widget_get_window (GTK_WIDGET (window)));
-
- if (desktop > 0)
- {
- menuitem = gtk_menu_item_new_with_label (_("Move to Workspace Up"));
- g_object_set_data (G_OBJECT (menuitem), "workspace", GUINT_TO_POINTER (desktop - 1));
- gtk_widget_show (menuitem);
- g_signal_connect (G_OBJECT (menuitem), "activate",
- G_CALLBACK (workspace_change_clicked), window);
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
- }
- if (desktop + 1 < n_desktops)
- {
- menuitem = gtk_menu_item_new_with_label (_("Move to Workspace Down"));
- g_object_set_data (G_OBJECT (menuitem), "workspace", GUINT_TO_POINTER (desktop + 1));
- gtk_widget_show (menuitem);
- g_signal_connect (G_OBJECT (menuitem), "activate",
- G_CALLBACK (workspace_change_clicked), window);
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
- }
- if (n_desktops > 2)
- {
- GtkWidget *submenu;
- gint d;
- guint32 current;
-
- current = gdk_x11_screen_get_current_desktop (gtk_widget_get_screen (GTK_WIDGET (window)));
- menuitem = gtk_menu_item_new_with_label (_("Move to Another Workspace"));
- gtk_widget_show (menuitem);
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
- submenu = gtk_menu_new ();
- gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
- for (d = 0; d < n_desktops; d++)
- {
- gchar *label;
- label = g_strdup_printf (_("Workspace %d"), d + 1);
- menuitem = gtk_menu_item_new_with_label (label);
- g_free (label);
- g_object_set_data (G_OBJECT (menuitem), "workspace", GUINT_TO_POINTER (d));
- if (d == current)
- gtk_widget_set_sensitive (menuitem, FALSE);
- gtk_widget_show (menuitem);
- g_signal_connect (G_OBJECT (menuitem), "activate",
- G_CALLBACK (workspace_change_clicked), window);
- gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menuitem);
- }
- }
- }
- }
-#endif
-
- menuitem = gtk_separator_menu_item_new ();
- gtk_widget_show (menuitem);
- gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
-
menuitem = gtk_menu_item_new_with_label (_("Close"));
gtk_widget_show (menuitem);
if (!priv->deletable)
@@ -8867,6 +8680,15 @@ gtk_window_do_popup (GtkWindow *window,
0, gtk_get_current_event_time ());
}
+static void
+gtk_window_do_popup (GtkWindow *window,
+ GdkEventButton *event)
+{
+ if (!gdk_window_show_window_menu (gtk_widget_get_window (GTK_WIDGET (window)),
+ (GdkEvent *) event))
+ gtk_window_do_popup_fallback (window, event);
+}
+
/*********************************
* Functions related to resizing *
*********************************/
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]