[gnome-flashback] desktop-background: redo background window



commit bd5283e37b66b7a44cd4e29224fbf125ee73ecbc
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Fri Sep 18 19:40:16 2015 +0300

    desktop-background: redo background window
    
    Now background should be always under desktop window. Tested with
    metacity and compiz.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=754963

 .../libdesktop-background/gf-background-window.c   |  358 ++++++++++++++++++--
 .../libdesktop-background/gf-desktop-background.c  |  162 ---------
 2 files changed, 325 insertions(+), 195 deletions(-)
---
diff --git a/gnome-flashback/libdesktop-background/gf-background-window.c 
b/gnome-flashback/libdesktop-background/gf-background-window.c
index 4cab3e1..9ce8ee1 100644
--- a/gnome-flashback/libdesktop-background/gf-background-window.c
+++ b/gnome-flashback/libdesktop-background/gf-background-window.c
@@ -16,91 +16,383 @@
  */
 
 #include "config.h"
+
+#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
+
 #include "gf-background-window.h"
 
 struct _GfBackgroundWindow
 {
-  GtkWindow parent;
+  GtkWindow  parent;
+
+  Atom       desktop_manager_atom;
+  Atom       client_list_atom;
+  Atom       type_atom;
+  Atom       type_desktop_atom;
+
+  Window     xbackground;
+  GdkWindow *background;
+
+  Window     xdesktop;
+  GdkWindow *desktop;
 };
 
 G_DEFINE_TYPE (GfBackgroundWindow, gf_background_window, GTK_TYPE_WINDOW)
 
+static GdkWindow *
+create_window_from_xwindow (Window xwindow)
+{
+  GdkDisplay *display;
+  GdkWindow *window;
+  GdkEventMask mask;
+
+  display = gdk_display_get_default ();
+
+  gdk_error_trap_push ();
+  window = gdk_x11_window_foreign_new_for_display (display, xwindow);
+
+  if (gdk_error_trap_pop () != 0)
+    return NULL;
+
+  mask = gdk_window_get_events (window);
+  gdk_window_set_events (window, mask | GDK_STRUCTURE_MASK);
+
+  return window;
+}
+
+static gboolean
+is_desktop_window (GfBackgroundWindow *window,
+                   Display            *display,
+                   Window              xwindow)
+{
+  Atom type;
+  Atom *atoms;
+  int result;
+  int format;
+  unsigned long items;
+  unsigned long left;
+
+  if (window->type_atom == None)
+    window->type_atom = XInternAtom (display, "_NET_WM_WINDOW_TYPE", False);
+
+  if (window->type_desktop_atom == None)
+    window->type_desktop_atom = XInternAtom (display,
+                                             "_NET_WM_WINDOW_TYPE_DESKTOP",
+                                             False);
+
+  gdk_error_trap_push ();
+  result = XGetWindowProperty (display, xwindow, window->type_atom,
+                               0L, 1L, False, XA_ATOM, &type, &format,
+                               &items, &left, (unsigned char **) &atoms);
+
+  if (gdk_error_trap_pop () != 0 || result != Success)
+    return FALSE;
+
+  if (items && atoms[0] == window->type_desktop_atom)
+    {
+      XFree (atoms);
+      return TRUE;
+    }
+
+  XFree (atoms);
+  return FALSE;
+}
+
+static gboolean
+get_desktop (GfBackgroundWindow *window)
+{
+  GdkDisplay *display;
+  Display *xdisplay;
+  Window root;
+  Atom type;
+  int result;
+  int format;
+  unsigned long items;
+  unsigned long left;
+  unsigned long i;
+  Window *windows;
+  Window desktop;
+
+  display = gdk_display_get_default ();
+  xdisplay = GDK_DISPLAY_XDISPLAY (display);
+
+  if (window->client_list_atom == None)
+    window->client_list_atom = XInternAtom (xdisplay, "_NET_CLIENT_LIST",
+                                            False);
+
+  gdk_error_trap_push ();
+
+  root = XDefaultRootWindow (xdisplay);
+  result = XGetWindowProperty (xdisplay, root, window->client_list_atom,
+                               0L, 1024L, False, XA_WINDOW, &type, &format,
+                               &items, &left, (unsigned char **) &windows);
+
+  if (gdk_error_trap_pop () != 0 || result != Success)
+    return FALSE;
+
+  desktop = None;
+  for (i = 0; i < items; i++)
+    {
+      if (windows[i] == window->xbackground)
+        continue;
+
+      if (is_desktop_window (window, xdisplay, windows[i]))
+        {
+          desktop = windows[i];
+          break;
+        }
+    }
+
+  XFree (windows);
+
+  if (desktop == None)
+    return FALSE;
+
+  window->xdesktop = desktop;
+  window->desktop = create_window_from_xwindow (desktop);
+
+  return TRUE;
+}
+
+static Window
+get_desktop_manager (GfBackgroundWindow *window)
+{
+  GdkDisplay *display;
+  Display *xdisplay;
+
+  display = gdk_display_get_default ();
+  xdisplay = gdk_x11_display_get_xdisplay (display);
+
+  if (window->desktop_manager_atom == None)
+    {
+      GdkScreen *screen;
+      gint screen_number;
+      gchar *name;
+
+      screen = gdk_display_get_default_screen (display);
+      screen_number = gdk_screen_get_number (screen);
+
+      name = g_strdup_printf ("_NET_DESKTOP_MANAGER_S%d", screen_number);
+      window->desktop_manager_atom = XInternAtom (xdisplay, name, False);
+      g_free (name);
+    }
+
+  return XGetSelectionOwner (xdisplay, window->desktop_manager_atom);
+}
+
+static void
+handle_xevent (GfBackgroundWindow *window,
+               XEvent             *event)
+{
+  static gboolean is_desktop_above_background;
+
+  if (event->type == DestroyNotify && window->xdesktop != None)
+    {
+      if (window->xdesktop == event->xdestroywindow.window)
+        {
+          is_desktop_above_background = FALSE;
+
+          window->xdesktop = None;
+          g_clear_object (&window->desktop);
+
+          return;
+        }
+    }
+
+  if (get_desktop_manager (window) == None)
+    return;
+
+  if (window->xdesktop == None && get_desktop (window) == FALSE)
+    return;
+
+  if (event->type == ConfigureNotify)
+    {
+      if (event->xconfigure.window == window->xdesktop)
+        is_desktop_above_background = FALSE;
+      else if (event->xconfigure.window == window->xbackground)
+        is_desktop_above_background = FALSE;
+    }
+
+  if (is_desktop_above_background == FALSE)
+    {
+      if (window->desktop == NULL)
+        return;
+
+      gdk_window_restack (window->desktop, window->background, TRUE);
+      gdk_window_lower (window->background);
+
+      is_desktop_above_background = TRUE;
+    }
+}
+
+static GdkFilterReturn
+event_filter_func (GdkXEvent *xevent,
+                   GdkEvent  *event,
+                   gpointer   data)
+{
+  GfBackgroundWindow *window;
+  XEvent *e;
+
+  window = GF_BACKGROUND_WINDOW (data);
+  e = (GdkXEvent *) xevent;
+
+  switch (e->type)
+    {
+      case CirculateNotify:
+      case ConfigureNotify:
+      case CreateNotify:
+      case DestroyNotify:
+      case GravityNotify:
+      case MapNotify:
+      case MappingNotify:
+      case ReparentNotify:
+      case UnmapNotify:
+      case VisibilityNotify:
+        handle_xevent (window, e);
+        break;
+
+      default:
+        break;
+    }
+
+  return GDK_FILTER_CONTINUE;
+}
+
 static void
-screen_changed (GdkScreen *screen,
-                gpointer   user_data)
+gf_background_window_screen_changed (GdkScreen *screen,
+                                     gpointer   user_data)
 {
   GfBackgroundWindow *window;
+  GtkWidget *widget;
   gint width;
   gint height;
 
   window = GF_BACKGROUND_WINDOW (user_data);
+  widget = GTK_WIDGET (window);
+
   width = gdk_screen_get_width (screen);
   height = gdk_screen_get_height (screen);
 
-  g_object_set (window,
-                "width-request", width,
-                "height-request", height,
-                NULL);
+  gtk_widget_set_size_request (widget, width, height);
+}
+
+static void
+gf_background_window_dispose (GObject *object)
+{
+  GfBackgroundWindow *window;
+
+  window = GF_BACKGROUND_WINDOW (object);
+
+  g_clear_object (&window->desktop);
+
+  G_OBJECT_CLASS (gf_background_window_parent_class)->dispose (object);
+}
+
+static void
+gf_background_window_finalize (GObject *object)
+{
+  GfBackgroundWindow *window;
+  GdkScreen *screen;
+  GdkWindow *root;
+
+  window = GF_BACKGROUND_WINDOW (object);
+
+  screen = gdk_screen_get_default ();
+  root = gdk_screen_get_root_window (screen);
+
+  gdk_window_remove_filter (root, event_filter_func, window);
+
+  G_OBJECT_CLASS (gf_background_window_parent_class)->finalize (object);
 }
 
 static void
 gf_background_window_map (GtkWidget *widget)
 {
-  GdkWindow *window;
+  GfBackgroundWindow *window;
+
+  window = GF_BACKGROUND_WINDOW (widget);
 
   GTK_WIDGET_CLASS (gf_background_window_parent_class)->map (widget);
 
-  window = gtk_widget_get_window (widget);
+  gdk_window_lower (window->background);
+}
+
+static void
+gf_background_window_realize (GtkWidget *widget)
+{
+  GfBackgroundWindow *window;
+  GdkWindow *gdk_window;
+
+  window = GF_BACKGROUND_WINDOW (widget);
+
+  GTK_WIDGET_CLASS (gf_background_window_parent_class)->realize (widget);
+
+  gdk_window = gtk_widget_get_window (widget);
 
-  gdk_window_lower (window);
+  window->xbackground = gdk_x11_window_get_xid (gdk_window);
+  window->background = gdk_window;
 }
 
 static void
 gf_background_window_class_init (GfBackgroundWindowClass *window_class)
 {
+  GObjectClass *object_class;
   GtkWidgetClass *widget_class;
 
+  object_class= G_OBJECT_CLASS (window_class);
   widget_class = GTK_WIDGET_CLASS (window_class);
 
+  object_class->dispose = gf_background_window_dispose;
+  object_class->finalize = gf_background_window_finalize;
+
   widget_class->map = gf_background_window_map;
+  widget_class->realize = gf_background_window_realize;
 }
 
 static void
 gf_background_window_init (GfBackgroundWindow *window)
 {
   GdkScreen *screen;
+  GtkWindow *gtk_window;
+  GtkWidget *gtk_widget;
+  GdkWindow *root;
+  GdkEventMask mask;
 
   screen = gdk_screen_get_default ();
+  gtk_window = GTK_WINDOW (window);
+  gtk_widget = GTK_WIDGET (window);
 
   g_signal_connect_object (screen, "monitors-changed",
-                           G_CALLBACK (screen_changed), window,
-                           G_CONNECT_AFTER);
-
+                           G_CALLBACK (gf_background_window_screen_changed),
+                           window, G_CONNECT_AFTER);
   g_signal_connect_object (screen, "size-changed",
-                           G_CALLBACK (screen_changed), window,
-                           G_CONNECT_AFTER);
+                           G_CALLBACK (gf_background_window_screen_changed),
+                           window, G_CONNECT_AFTER);
+
+  gf_background_window_screen_changed (screen, window);
+  gtk_window_set_keep_below (gtk_window, TRUE);
+  gtk_widget_add_events (gtk_widget, GDK_STRUCTURE_MASK);
+  gtk_widget_realize (gtk_widget);
 
-  screen_changed (screen, window);
+  root = gdk_screen_get_root_window (screen);
+  mask = gdk_window_get_events (root);
+
+  gdk_window_set_events (root, mask | GDK_SUBSTRUCTURE_MASK);
+  gdk_window_add_filter (root, event_filter_func, window);
 }
 
 GtkWidget *
 gf_background_window_new (void)
 {
-  GtkWidget *window;
-
-  window = g_object_new (GF_TYPE_BACKGROUND_WINDOW,
-                         "accept-focus", FALSE,
-                         "app-paintable", TRUE,
-                         "decorated", FALSE,
-                         "resizable", FALSE,
-                         "skip-pager-hint", TRUE,
-                         "skip-taskbar-hint", TRUE,
-                         "type", GTK_WINDOW_TOPLEVEL,
-                         "type-hint", GDK_WINDOW_TYPE_HINT_DESKTOP,
-                         NULL);
-
-  gtk_window_set_keep_below (GTK_WINDOW (window), TRUE);
-  gtk_widget_realize (window);
-
-  return window;
+  return g_object_new (GF_TYPE_BACKGROUND_WINDOW,
+                       "accept-focus", FALSE,
+                       "app-paintable", TRUE,
+                       "decorated", FALSE,
+                       "resizable", FALSE,
+                       "skip-pager-hint", TRUE,
+                       "skip-taskbar-hint", TRUE,
+                       "type", GTK_WINDOW_TOPLEVEL,
+                       "type-hint", GDK_WINDOW_TYPE_HINT_DESKTOP,
+                        NULL);
 }
diff --git a/gnome-flashback/libdesktop-background/gf-desktop-background.c 
b/gnome-flashback/libdesktop-background/gf-desktop-background.c
index 7a109f8..0ab5c19 100644
--- a/gnome-flashback/libdesktop-background/gf-desktop-background.c
+++ b/gnome-flashback/libdesktop-background/gf-desktop-background.c
@@ -17,10 +17,8 @@
 
 #include "config.h"
 
-#include <gdk/gdkx.h>
 #include <gtk/gtk.h>
 #include <libgnome-desktop/gnome-bg.h>
-#include <X11/Xatom.h>
 
 #include "gf-background-window.h"
 #include "gf-desktop-background.h"
@@ -49,162 +47,6 @@ struct _GfDesktopBackground
 
 G_DEFINE_TYPE (GfDesktopBackground, gf_desktop_background, G_TYPE_OBJECT)
 
-static gboolean
-is_nautilus_desktop_manager (void)
-{
-  GdkDisplay *display;
-  Display *xdisplay;
-  GdkScreen *screen;
-  gint screen_number;
-  gchar *name;
-  Atom atom;
-  Window window;
-
-  display = gdk_display_get_default ();
-  xdisplay = GDK_DISPLAY_XDISPLAY (display);
-  screen = gdk_display_get_default_screen (display);
-  screen_number = gdk_screen_get_number (screen);
-
-  name = g_strdup_printf ("_NET_DESKTOP_MANAGER_S%d", screen_number);
-  atom = XInternAtom (xdisplay, name, False);
-  g_free (name);
-
-  window = XGetSelectionOwner (xdisplay, atom);
-
-  if (window != None)
-    return TRUE;
-
-  return FALSE;
-}
-
-static gboolean
-is_desktop_window (Display *display,
-                   Window   window)
-{
-  Atom window_type;
-  Atom desktop;
-  Atom type;
-  Atom *atoms;
-  int result;
-  int format;
-  unsigned long items;
-  unsigned long left;
-
-  window_type = XInternAtom (display, "_NET_WM_WINDOW_TYPE", False);
-  desktop = XInternAtom (display, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
-
-  result = XGetWindowProperty (display, window, window_type,
-                               0L, 1L, False, XA_ATOM, &type, &format,
-                               &items, &left, (unsigned char **) &atoms);
-
-  if (result != Success)
-    return FALSE;
-
-  if (items && atoms[0] == desktop)
-    {
-      XFree (atoms);
-      return TRUE;
-    }
-
-  XFree (atoms);
-  return FALSE;
-}
-
-static GdkWindow *
-get_nautilus_window (GfDesktopBackground *background)
-{
-  GdkDisplay *display;
-  GdkWindow *window;
-  Display *xdisplay;
-  Atom client_list;
-  Window root;
-  Atom type;
-  int result;
-  int format;
-  unsigned long items;
-  unsigned long left;
-  unsigned long i;
-  Window *windows;
-  Window nautilus;
-  GdkWindow *background_window;
-  Window desktop;
-
-  gdk_error_trap_push ();
-
-  display = gdk_display_get_default ();
-  xdisplay = GDK_DISPLAY_XDISPLAY (display);
-  client_list = XInternAtom (xdisplay, "_NET_CLIENT_LIST", False);
-  root = XDefaultRootWindow (xdisplay);
-
-  result = XGetWindowProperty (xdisplay, root, client_list,
-                               0L, 1024L, False, XA_WINDOW, &type, &format,
-                               &items, &left, (unsigned char **) &windows);
-
-  if (result != Success)
-    {
-      gdk_error_trap_pop_ignored ();
-      return NULL;
-    }
-
-  nautilus = None;
-  background_window = gtk_widget_get_window (background->background);
-  desktop = GDK_WINDOW_XID (background_window);
-
-  for (i = 0; i < items; i++)
-    {
-      if (is_desktop_window (xdisplay, windows[i]) && windows[i] != desktop)
-        {
-          nautilus = windows[i];
-          break;
-        }
-    }
-
-  XFree (windows);
-
-  window = NULL;
-  if (nautilus != None)
-    window = gdk_x11_window_foreign_new_for_display (display, nautilus);
-
-  gdk_error_trap_pop_ignored ();
-
-  return window;
-}
-
-static GdkFilterReturn
-event_filter_func (GdkXEvent *xevent,
-                   GdkEvent  *event,
-                   gpointer   data)
-{
-  static gboolean nautilus_raised = FALSE;
-  GfDesktopBackground *background;
-
-  background = GF_DESKTOP_BACKGROUND (data);
-
-  if (is_nautilus_desktop_manager ())
-    {
-      if (nautilus_raised == FALSE)
-        {
-          GdkWindow *nautilus;
-
-          nautilus = get_nautilus_window (background);
-
-          if (GDK_IS_WINDOW (nautilus))
-            {
-              gdk_window_hide (nautilus);
-              gdk_window_show (nautilus);
-
-              nautilus_raised = TRUE;
-            }
-        }
-    }
-  else
-    {
-      nautilus_raised = FALSE;
-    }
-
-  return GDK_FILTER_CONTINUE;
-}
-
 static void
 free_fade (GfDesktopBackground *background)
 {
@@ -484,8 +326,6 @@ gf_desktop_background_finalize (GObject *object)
   g_clear_object (&background->gnome_settings);
   g_clear_object (&background->background_settings);
 
-  gdk_window_remove_filter (NULL, event_filter_func, background);
-
   G_OBJECT_CLASS (gf_desktop_background_parent_class)->finalize (object);
 }
 
@@ -520,8 +360,6 @@ gf_desktop_background_init (GfDesktopBackground *background)
                     G_CALLBACK (size_allocate), background);
 
   queue_background_change (background);
-
-  gdk_window_add_filter (NULL, event_filter_func, background);
 }
 
 GfDesktopBackground *


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