[gnome-terminal] Save the desktop when unrealizing/realizing



commit 6eb4c0d7de2ee9a3c27c7eb9905d186791f08626
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Thu Jun 18 16:52:18 2009 -0400

    Save the desktop when unrealizing/realizing
    
    Save the current desktop for a terminal window when unrealizing
    and realizing it to change the colormap.
    
    This is complicated because: a) GDK has no support for_NET_WM_DESKTOP
    b) GDK however clears _NET_WM_DESKTOP on map (as part of it's
    support for sticky windows.)
    
    http://bugzilla.gnome.org/show_bug.cgi?id=564648

 src/terminal-util.c   |  116 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/terminal-util.h   |    5 ++
 src/terminal-window.c |   11 +++++
 3 files changed, 132 insertions(+), 0 deletions(-)
---
diff --git a/src/terminal-util.c b/src/terminal-util.c
index a6bca92..587d1d7 100644
--- a/src/terminal-util.c
+++ b/src/terminal-util.c
@@ -32,6 +32,11 @@
 #include <gio/gio.h>
 #include <gtk/gtk.h>
 
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
+#endif
+
 #include "terminal-accels.h"
 #include "terminal-app.h"
 #include "terminal-intl.h"
@@ -869,3 +874,114 @@ terminal_util_bind_object_property_to_widget (GObject *object,
   change->object_notify_id = g_signal_connect_swapped (object, notify_signal, G_CALLBACK (object_change_notify_cb), change);
 }
 
+#ifdef GDK_WINDOWING_X11
+
+/* We don't want to hop desktops when we unrealize/realize.
+ * So we need to save and restore the value of NET_WM_DESKTOP. This isn't
+ * exposed through GDK.
+ */
+gboolean
+terminal_util_x11_get_net_wm_desktop (GdkWindow *window,
+				      guint32   *desktop)
+{
+  GdkDisplay *display = gdk_drawable_get_display (window);
+  Atom type;
+  int format;
+  guchar *data;
+  gulong n_items, bytes_after;
+  gboolean result = FALSE;
+
+  if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
+			  GDK_DRAWABLE_XID (window),
+			  gdk_x11_get_xatom_by_name_for_display (display,
+								 "_NET_WM_DESKTOP"),
+			  0, G_MAXLONG, False, AnyPropertyType,
+			  &type, &format, &n_items, &bytes_after, &data) == Success &&
+      type != None)
+    {
+      if (type == XA_CARDINAL && format == 32 && n_items == 1)
+	{
+	  *desktop = *(gulong *)data;
+	  result = TRUE;
+	}
+
+      XFree (data);
+    }
+
+  return result;
+}
+
+void
+terminal_util_x11_set_net_wm_desktop (GdkWindow *window,
+				      guint32    desktop)
+{
+  /* We can't change the current desktop before mapping our window,
+   * because GDK has the annoying habit of clearing _NET_WM_DESKTOP
+   * before mapping a GdkWindow, So we we have to do it after instead.
+   *
+   * However, doing it after is different whether or not we have a
+   * window manager (if we don't have a window manager, we have to
+   * set the _NET_WM_DESKTOP property so that it picks it up when
+   * it starts)
+   *
+   * http://bugzilla.gnome.org/show_bug.cgi?id=586311 asks for GTK+
+   * to just handle everything behind the scenes including the desktop.
+   */
+  GdkScreen *screen = gdk_drawable_get_screen (window);
+  GdkDisplay *display = gdk_screen_get_display (screen);
+  Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
+  char *wm_selection_name;
+  Atom wm_selection;
+  gboolean have_wm;
+
+  wm_selection_name = g_strdup_printf ("WM_S%d", gdk_screen_get_number (screen));
+  wm_selection = gdk_x11_get_xatom_by_name_for_display (display, wm_selection_name);
+  g_free(wm_selection_name);
+
+  XGrabServer (xdisplay);
+
+  have_wm = XGetSelectionOwner (xdisplay, wm_selection) != None;
+
+  if (have_wm)
+    {
+      /* code borrowed from GDK
+       */
+      XClientMessageEvent xclient;
+
+      memset (&xclient, 0, sizeof (xclient));
+      xclient.type = ClientMessage;
+      xclient.serial = 0;
+      xclient.send_event = True;
+      xclient.window = GDK_WINDOW_XWINDOW (window);
+      xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP");
+      xclient.format = 32;
+
+      xclient.data.l[0] = desktop;
+      xclient.data.l[1] = 0;
+      xclient.data.l[2] = 0;
+      xclient.data.l[3] = 0;
+      xclient.data.l[4] = 0;
+
+      XSendEvent (xdisplay,
+		  GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen)),
+		  False,
+		  SubstructureRedirectMask | SubstructureNotifyMask,
+		  (XEvent *)&xclient);
+    }
+  else
+    {
+      gulong long_desktop = desktop;
+
+      XChangeProperty (xdisplay,
+		       GDK_DRAWABLE_XID (window),
+		       gdk_x11_get_xatom_by_name_for_display (display,
+							      "_NET_WM_DESKTOP"),
+		       XA_CARDINAL, 32, PropModeReplace,
+		       (guchar *)&long_desktop, 1);
+    }
+
+  XUngrabServer (xdisplay);
+  XFlush (xdisplay);
+}
+
+#endif /* GDK_WINDOWING_X11 */
diff --git a/src/terminal-util.h b/src/terminal-util.h
index d72fba1..acfd437 100644
--- a/src/terminal-util.h
+++ b/src/terminal-util.h
@@ -100,4 +100,9 @@ void terminal_util_bind_object_property_to_widget (GObject *object,
                                                    GtkWidget *widget,
                                                    PropertyChangeFlags flags);
 
+gboolean terminal_util_x11_get_net_wm_desktop (GdkWindow *window,
+					       guint32   *desktop);
+void     terminal_util_x11_set_net_wm_desktop (GdkWindow *window,
+					       guint32    desktop);
+
 #endif /* TERMINAL_UTIL_H */
diff --git a/src/terminal-window.c b/src/terminal-window.c
index 470189b..95db45a 100644
--- a/src/terminal-window.c
+++ b/src/terminal-window.c
@@ -22,7 +22,9 @@
 #include <string.h>
 #include <stdlib.h>
 #include <gtk/gtk.h>
+#ifdef GDK_WINDOWING_X11
 #include <gdk/gdkx.h>
+#endif
 #include <gdk/gdkkeysyms.h>
 #include <libsn/sn-launchee.h>
 
@@ -1482,6 +1484,8 @@ terminal_window_composited_changed_cb (GdkScreen *screen,
     {
       GtkWidget *widget = GTK_WIDGET (window);
       guint32 user_time;
+      gboolean have_desktop;
+      guint32 desktop = 0; /* Quiet GCC */
       int x, y;
 
       user_time = gdk_x11_display_get_user_time (gtk_widget_get_display (widget));
@@ -1494,6 +1498,10 @@ terminal_window_composited_changed_cb (GdkScreen *screen,
        * framing our window, so we might see a funky intermediate state.
        * But at worst, we'll be off by a few pixels (the frame size). */
       gtk_window_get_position (GTK_WINDOW (window), &x, &y);
+
+      /* And the desktop */
+      have_desktop = terminal_util_x11_get_net_wm_desktop (widget->window, &desktop);
+
       gtk_widget_hide (widget);
       gtk_widget_unrealize (widget);
 
@@ -1501,7 +1509,10 @@ terminal_window_composited_changed_cb (GdkScreen *screen,
       gtk_window_move (GTK_WINDOW (window), x, y);
       gtk_widget_realize (widget);
       gdk_x11_window_set_user_time (widget->window, user_time);
+
       gtk_widget_show (widget);
+      if (have_desktop)
+        terminal_util_x11_set_net_wm_desktop (widget->window, desktop);
     }
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]