[gnome-flashback] desktop: handle !draw-background case



commit 9005220f2689e9f5ff3ee0e5f2e7296eded6a9fb
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Tue Oct 29 01:29:58 2019 +0200

    desktop: handle !draw-background case
    
    If we are not drawing background then desktop window will be
    transparent if screen is composited, otherwise we will draw surface
    from root window.

 configure.ac                                   |   1 +
 gnome-flashback/libdesktop/Makefile.am         |   1 +
 gnome-flashback/libdesktop/gf-desktop-window.c | 170 ++++++++++++++++++++++++-
 3 files changed, 166 insertions(+), 6 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 739796b..08253d0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -154,6 +154,7 @@ PKG_CHECK_MODULES([COMMON], [
 PKG_CHECK_MODULES([DESKTOP], [
   glib-2.0 >= $GLIB_REQUIRED
   gio-2.0 >= $GLIB_REQUIRED
+  gnome-desktop-3.0 >= $LIBGNOME_DESKTOP_REQUIRED
   gtk+-3.0 >= $GTK_REQUIRED
 ])
 
diff --git a/gnome-flashback/libdesktop/Makefile.am b/gnome-flashback/libdesktop/Makefile.am
index 73041c2..3a69aa9 100644
--- a/gnome-flashback/libdesktop/Makefile.am
+++ b/gnome-flashback/libdesktop/Makefile.am
@@ -5,6 +5,7 @@ noinst_LTLIBRARIES = \
        $(NULL)
 
 libdesktop_la_CPPFLAGS = \
+       -DGNOME_DESKTOP_USE_UNSTABLE_API \
        -I$(top_builddir)/gnome-flashback/libdesktop \
        $(NULL)
 
diff --git a/gnome-flashback/libdesktop/gf-desktop-window.c b/gnome-flashback/libdesktop/gf-desktop-window.c
index 161c412..69564ba 100644
--- a/gnome-flashback/libdesktop/gf-desktop-window.c
+++ b/gnome-flashback/libdesktop/gf-desktop-window.c
@@ -18,20 +18,25 @@
 #include "config.h"
 #include "gf-desktop-window.h"
 
+#include <gdk/gdkx.h>
+#include <libgnome-desktop/gnome-bg.h>
+
 #include "gf-background.h"
 #include "gf-icon-view.h"
 
 struct _GfDesktopWindow
 {
-  GtkWindow     parent;
+  GtkWindow        parent;
 
-  gboolean      draw_background;
-  GfBackground *background;
+  gboolean         draw_background;
+  GfBackground    *background;
+  gboolean         event_filter_added;
+  cairo_surface_t *surface;
 
-  gboolean      show_icons;
-  GtkWidget    *icon_view;
+  gboolean         show_icons;
+  GtkWidget       *icon_view;
 
-  gboolean      ready;
+  gboolean         ready;
 };
 
 enum
@@ -57,6 +62,98 @@ static guint window_signals[LAST_SIGNAL] = { 0 };
 
 G_DEFINE_TYPE (GfDesktopWindow, gf_desktop_window, GTK_TYPE_WINDOW)
 
+static void
+ensure_surface (GfDesktopWindow *self)
+{
+  GtkWidget *widget;
+  GdkScreen *screen;
+
+  widget = GTK_WIDGET (self);
+
+  screen = gtk_widget_get_screen (widget);
+
+  self->surface = gnome_bg_get_surface_from_root (screen);
+  gtk_widget_queue_draw (widget);
+}
+
+static GdkFilterReturn
+filter_func (GdkXEvent *xevent,
+             GdkEvent  *event,
+             gpointer   user_data)
+{
+  XEvent *x;
+  GdkAtom atom;
+  GfDesktopWindow *self;
+
+  x = (XEvent *) xevent;
+
+  if (x->type != PropertyNotify)
+    return GDK_FILTER_CONTINUE;
+
+  atom = gdk_atom_intern_static_string ("_XROOTPMAP_ID");
+
+  if (x->xproperty.atom != gdk_x11_atom_to_xatom (atom))
+    return GDK_FILTER_CONTINUE;
+
+  self = GF_DESKTOP_WINDOW (user_data);
+
+  g_clear_pointer (&self->surface, cairo_surface_destroy);
+  ensure_surface (self);
+
+  return GDK_FILTER_CONTINUE;
+}
+
+static void
+remove_event_filter (GfDesktopWindow *self)
+{
+  GdkScreen *screen;
+  GdkWindow *root;
+
+  if (!self->event_filter_added)
+    return;
+
+  screen = gtk_widget_get_screen (GTK_WIDGET (self));
+  root = gdk_screen_get_root_window (screen);
+
+  gdk_window_remove_filter (root, filter_func, self);
+  self->event_filter_added = FALSE;
+}
+
+static void
+add_event_filter (GfDesktopWindow *self)
+{
+  GdkScreen *screen;
+  GdkWindow *root;
+
+  if (self->event_filter_added)
+    return;
+
+  screen = gtk_widget_get_screen (GTK_WIDGET (self));
+  root = gdk_screen_get_root_window (screen);
+
+  gdk_window_add_filter (root, filter_func, self);
+  self->event_filter_added = TRUE;
+}
+
+static void
+composited_changed_cb (GdkScreen       *screen,
+                       GfDesktopWindow *self)
+{
+  if (self->draw_background)
+    return;
+
+  if (gdk_screen_is_composited (screen))
+    {
+      remove_event_filter (self);
+      g_clear_pointer (&self->surface, cairo_surface_destroy);
+    }
+  else
+    {
+      add_event_filter (self);
+      ensure_surface (self);
+    }
+}
+
 static void
 emit_ready (GfDesktopWindow *self)
 {
@@ -79,6 +176,9 @@ draw_background_changed (GfDesktopWindow *self)
 {
   if (self->draw_background)
     {
+      remove_event_filter (self);
+      g_clear_pointer (&self->surface, cairo_surface_destroy);
+
       g_assert (self->background == NULL);
       self->background = gf_background_new (GTK_WIDGET (self));
 
@@ -86,7 +186,19 @@ draw_background_changed (GfDesktopWindow *self)
     }
   else
     {
+      GdkScreen *screen;
+
       g_clear_object (&self->background);
+
+      screen = gtk_widget_get_screen (GTK_WIDGET (self));
+
+      if (!gdk_screen_is_composited (screen))
+        {
+          add_event_filter (self);
+          ensure_surface (self);
+        }
+
+      emit_ready (self);
     }
 }
 
@@ -161,6 +273,19 @@ gf_desktop_window_dispose (GObject *object)
   G_OBJECT_CLASS (gf_desktop_window_parent_class)->dispose (object);
 }
 
+static void
+gf_desktop_window_finalize (GObject *object)
+{
+  GfDesktopWindow *self;
+
+  self = GF_DESKTOP_WINDOW (object);
+
+  remove_event_filter (self);
+  g_clear_pointer (&self->surface, cairo_surface_destroy);
+
+  G_OBJECT_CLASS (gf_desktop_window_parent_class)->finalize (object);
+}
+
 static void
 gf_desktop_window_set_property (GObject      *object,
                                 guint         property_id,
@@ -187,6 +312,23 @@ gf_desktop_window_set_property (GObject      *object,
     }
 }
 
+static gboolean
+gf_desktop_window_draw (GtkWidget *widget,
+                        cairo_t   *cr)
+{
+  GfDesktopWindow *self;
+
+  self = GF_DESKTOP_WINDOW (widget);
+
+  if (self->surface != NULL)
+    {
+      cairo_set_source_surface (cr, self->surface, 0, 0);
+      cairo_paint (cr);
+    }
+
+  return GTK_WIDGET_CLASS (gf_desktop_window_parent_class)->draw (widget, cr);
+}
+
 static void
 gf_desktop_window_realize (GtkWidget *widget)
 {
@@ -245,8 +387,10 @@ gf_desktop_window_class_init (GfDesktopWindowClass *self_class)
 
   object_class->constructed = gf_desktop_window_constructed;
   object_class->dispose = gf_desktop_window_dispose;
+  object_class->finalize = gf_desktop_window_finalize;
   object_class->set_property = gf_desktop_window_set_property;
 
+  widget_class->draw = gf_desktop_window_draw;
   widget_class->realize = gf_desktop_window_realize;
 
   install_properties (object_class);
@@ -257,12 +401,25 @@ static void
 gf_desktop_window_init (GfDesktopWindow *self)
 {
   GParamSpecBoolean *spec;
+  GdkScreen *screen;
+  GdkWindow *root;
+  gint events;
 
   spec = (GParamSpecBoolean *) window_properties[PROP_DRAW_BACKGROUND];
   self->draw_background = spec->default_value;
 
   spec = (GParamSpecBoolean *) window_properties[PROP_SHOW_ICONS];
   self->show_icons =  spec->default_value;
+
+  screen = gtk_widget_get_screen (GTK_WIDGET (self));
+  root = gdk_screen_get_root_window (screen);
+  events = gdk_window_get_events (root);
+
+  gdk_window_set_events (root, events | GDK_PROPERTY_CHANGE_MASK);
+
+  g_signal_connect_object (screen, "composited-changed",
+                           G_CALLBACK (composited_changed_cb),
+                           self, 0);
 }
 
 GtkWidget *
@@ -270,6 +427,7 @@ gf_desktop_window_new (gboolean draw_background,
                        gboolean show_icons)
 {
   return g_object_new (GF_TYPE_DESKTOP_WINDOW,
+                       "app-paintable", TRUE,
                        "type", GTK_WINDOW_TOPLEVEL,
                        "type-hint", GDK_WINDOW_TYPE_HINT_DESKTOP,
                        "draw-background", draw_background,


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