Use persistent surface image of panel background, and Cairo for plugins BG.
authorAndriy Grytsenko <andrej@rep.kiev.ua>
Wed, 26 Nov 2014 12:57:26 +0000 (14:57 +0200)
committerAndriy Grytsenko <andrej@rep.kiev.ua>
Wed, 26 Nov 2014 12:57:26 +0000 (14:57 +0200)
This way updating background should be faster since it will not request
root image for each single widget (including all children) background.
Also this fixes background of plugins when image is configured,
both placement and alpha color, which was heavily broken before.

ChangeLog
src/configurator.c
src/panel.c
src/private.h

index 347673e..26b8987 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -75,6 +75,9 @@
     time somewhere at the screen.
 * Fixed calendar and configuration windows blinking on their appearance.
 * Fixed panel update when background image changed in configuration.
+* Changed to use persistent background image for panel and Cairo. This
+    way updating background should be faster, and also fixed background
+    of plugins when image is used, both placement and alpha color.
 
 0.7.2
 -------------------------------------------------------------------------
index e21c250..5315ed0 100644 (file)
@@ -363,7 +363,6 @@ static void background_file_helper(Panel * p, GtkWidget * toggle, GtkFileChooser
     {
         g_free(p->background_file);
         p->background_file = file;
-        p->background = FALSE; /* mark it for update below */
         UPDATE_GLOBAL_STRING(p, "backgroundfile", p->background_file);
     }
 
@@ -373,11 +372,11 @@ static void background_file_helper(Panel * p, GtkWidget * toggle, GtkFileChooser
         {
             p->transparent = FALSE;
             p->background = TRUE;
-            panel_update_background(p);
             UPDATE_GLOBAL_INT(p, "transparent", p->transparent);
             UPDATE_GLOBAL_INT(p, "background", p->background);
         }
     }
+    panel_update_background(p);
 }
 
 static void background_toggle( GtkWidget *b, Panel* p)
index c15de66..36ba140 100644 (file)
@@ -121,6 +121,11 @@ static void panel_stop_gui(LXPanel *self)
         XSync(xdisplay, True);
         p->initialized = FALSE;
     }
+    if (p->surface != NULL)
+    {
+        cairo_surface_destroy(p->surface);
+        p->surface = NULL;
+    }
 
     if (p->background_update_queued)
     {
@@ -618,43 +623,87 @@ void _panel_determine_background_pixmap(LXPanel * panel, GtkWidget * widget)
     GdkPixmap * pixmap = NULL;
     GdkWindow * window = gtk_widget_get_window(widget);
     Panel * p = panel->priv;
-
-    /* Free p->bg if it is not going to be used. */
-    if (( ! p->transparent) && (p->bg != NULL))
+    cairo_t *cr;
+    GtkAllocation alloc;
+    gint x = 0, y = 0;
+
+    if (!p->background && !p->transparent)
+        goto not_paintable;
+    else if (p->aw <= 1 || p->ah <= 1)
+        goto not_paintable;
+    else if (p->surface == NULL)
     {
-        g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, panel);
-        g_object_unref(p->bg);
-        p->bg = NULL;
-    }
+        GdkPixbuf *pixbuf = NULL;
 
-    if (p->background)
-    {
-        /* User specified background pixmap. */
-        if (p->background_file != NULL)
-            pixmap = fb_bg_get_pix_from_file(widget, p->background_file);
-    }
-
-    else if (p->transparent)
-    {
-        /* Transparent.  Determine the appropriate value from the root pixmap. */
-        if (p->bg == NULL)
+        p->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, p->aw, p->ah);
+        cr = cairo_create(p->surface);
+        if (p->background)
         {
-            p->bg = fb_bg_get_for_display();
-            g_signal_connect(G_OBJECT(p->bg), "changed", G_CALLBACK(on_root_bg_changed), panel);
+            /* User specified background pixmap. */
+            pixbuf = gdk_pixbuf_new_from_file(p->background_file, NULL);
+        }
+        if (p->transparent || (pixbuf != NULL && gdk_pixbuf_get_has_alpha(pixbuf)))
+        {
+            if (p->bg == NULL)
+            {
+                p->bg = fb_bg_get_for_display();
+                g_signal_connect(G_OBJECT(p->bg), "changed", G_CALLBACK(on_root_bg_changed), panel);
+            }
+            /* Transparent.  Determine the appropriate value from the root pixmap. */
+            pixmap = fb_bg_get_xroot_pix_for_win(p->bg, widget);
+            gdk_cairo_set_source_pixmap(cr, pixmap, 0, 0);
+            cairo_paint(cr);
+            g_object_unref(pixmap);
         }
-        pixmap = fb_bg_get_xroot_pix_for_win(p->bg, widget);
-        if ((pixmap != NULL) && (pixmap != GDK_NO_BG) && (p->alpha != 0))
-            fb_bg_composite(pixmap, &p->gtintcolor, p->alpha);
+        else if (p->bg != NULL)
+        {
+            g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, panel);
+            g_object_unref(p->bg);
+            p->bg = NULL;
+        }
+        if (pixbuf != NULL)
+        {
+            gint w = gdk_pixbuf_get_width(pixbuf);
+            gint h = gdk_pixbuf_get_height(pixbuf);
+
+            /* Tile the image */
+            for (y = 0; y < p->ah; y += h)
+                for (x = 0; x < p->aw; x += w)
+                {
+                    gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y);
+                    cairo_paint(cr);
+                }
+            y = 0;
+            g_object_unref(pixbuf);
+        }
+        cairo_destroy(cr);
     }
 
-    if (pixmap != NULL)
+    if (p->surface != NULL)
     {
-        gtk_widget_set_app_paintable(widget, TRUE );
+        gtk_widget_set_app_paintable(widget, TRUE);
+        gtk_widget_get_allocation(widget, &alloc);
+        pixmap = gdk_pixmap_new(window, alloc.width, alloc.height, -1);
+        cr = gdk_cairo_create(pixmap);
+        gtk_widget_translate_coordinates(widget, GTK_WIDGET(panel), 0, 0, &x, &y);
+        cairo_set_source_surface(cr, p->surface, 0.0 - x, 0.0 - y);
+        cairo_paint(cr);
+        cairo_destroy(cr);
         gdk_window_set_back_pixmap(window, pixmap, FALSE);
         g_object_unref(pixmap);
     }
     else
+    {
+not_paintable:
         gtk_widget_set_app_paintable(widget, FALSE);
+        /* Free p->bg if it is not going to be used. */
+        if (p->bg != NULL)
+        {
+            g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, panel);
+            g_object_unref(p->bg);
+            p->bg = NULL;
+        }
+    }
 }
 
 /* Update the background of the entire panel.
@@ -669,6 +718,13 @@ static void _panel_update_background(LXPanel * p)
     GtkWidget *w = GTK_WIDGET(p);
     GList *plugins = NULL, *l;
 
+    /* reset background image */
+    if (p->priv->surface != NULL)
+    {
+        cairo_surface_destroy(p->priv->surface);
+        p->priv->surface = NULL;
+    }
+
     /* Redraw the top level widget. */
     _panel_determine_background_pixmap(p, w);
     gdk_window_clear(gtk_widget_get_window(w));
index a3b2f10..4dd0551 100644 (file)
@@ -146,6 +146,7 @@ struct _Panel {
     guint mouse_timeout;
     //gint dyn_space;                     /* Space for expandable plugins */
     //guint calculate_size_idle;          /* The idle handler for dyn_space calc */
+    cairo_surface_t *surface;           /* Panel background */
 };
 
 typedef struct {