[Xfce4-commits] <xfce4-panel:master> Add support for more background options (bug #1731).

Nick Schermer noreply at xfce.org
Sun May 9 22:30:01 CEST 2010


Updating branch refs/heads/master
         to 8c9fcef677f360e82f5a8de7d3bbf7a2e206d55e (commit)
       from 5db31ffd871d39cbe4fb51862405aafac5cf1d0d (commit)

commit 8c9fcef677f360e82f5a8de7d3bbf7a2e206d55e
Author: Nick Schermer <nick at xfce.org>
Date:   Sun Apr 25 11:34:05 2010 +0200

    Add support for more background options (bug #1731).
    
    Add support for colored and image backgrounds. This makes theming the
    panel a lot easier and allows us to handle the colors and image
    positioning in the external plugins.
    
    The background image does not apply to the autohide window.

 common/panel-dbus.h                        |    3 +
 common/panel-xfconf.c                      |    5 +-
 libxfce4panel/xfce-panel-macros-46.h       |  115 +++++++++--
 libxfce4panel/xfce-panel-plugin-provider.h |    1 +
 panel/panel-application.c                  |   12 +
 panel/panel-base-window.c                  |  302 ++++++++++++++++++++++++---
 panel/panel-base-window.h                  |   15 ++-
 panel/panel-plugin-external-46.c           |  259 ++++++++++++++++--------
 panel/panel-plugin-external-46.h           |    8 +-
 panel/panel-plugin-external.c              |   59 ++++++
 panel/panel-plugin-external.h              |    6 +
 panel/panel-preferences-dialog.c           |  144 +++++++++++++-
 panel/panel-preferences-dialog.glade       |  184 +++++++++++++++---
 panel/panel-window.c                       |   30 +++-
 wrapper/main.c                             |   20 ++-
 wrapper/wrapper-plug.c                     |  179 ++++++++++++++---
 wrapper/wrapper-plug.h                     |    6 +
 17 files changed, 1134 insertions(+), 214 deletions(-)

diff --git a/common/panel-dbus.h b/common/panel-dbus.h
index 611456c..32d8c39 100644
--- a/common/panel-dbus.h
+++ b/common/panel-dbus.h
@@ -38,6 +38,9 @@
 #define SIGNAL_WRAPPER_SET_SENSITIVE    "i"
 #define SIGNAL_WRAPPER_BACKGROUND_ALPHA "j"
 #define SIGNAL_WRAPPER_QUIT             "k"
+#define SIGNAL_WRAPPER_BACKGROUND_COLOR "l"
+#define SIGNAL_WRAPPER_BACKGROUND_IMAGE "m"
+#define SIGNAL_WRAPPER_BACKGROUND_UNSET "n"
 
 /* special types for dbus communication */
 #define PANEL_TYPE_DBUS_SET_MESSAGE \
diff --git a/common/panel-xfconf.c b/common/panel-xfconf.c
index ccae3ae..5d45d11 100644
--- a/common/panel-xfconf.c
+++ b/common/panel-xfconf.c
@@ -109,7 +109,10 @@ panel_properties_bind (XfconfChannel       *channel,
       if (save_properties)
         panel_properties_store_value (channel, property, prop->type, object, prop->property);
 
-      xfconf_g_property_bind (channel, property, prop->type, object, prop->property);
+      if (G_LIKELY (prop->type != GDK_TYPE_COLOR))
+        xfconf_g_property_bind (channel, property, prop->type, object, prop->property);
+      else
+        xfconf_g_property_bind_gdkcolor (channel, property, object, prop->property);
 
       g_free (property);
     }
diff --git a/libxfce4panel/xfce-panel-macros-46.h b/libxfce4panel/xfce-panel-macros-46.h
index 2a6f3e5..e29acad 100644
--- a/libxfce4panel/xfce-panel-macros-46.h
+++ b/libxfce4panel/xfce-panel-macros-46.h
@@ -50,7 +50,9 @@ enum /*< skip >*/
   PANEL_CLIENT_EVENT_SET_SIZE,
   PANEL_CLIENT_EVENT_SHOW_ABOUT,
   PANEL_CLIENT_EVENT_SHOW_CONFIGURE,
-  PANEL_CLIENT_EVENT_QUIT
+  PANEL_CLIENT_EVENT_QUIT,
+  PANEL_CLIENT_EVENT_SET_BG_COLOR,
+  PANEL_CLIENT_EVENT_UNSET_BG
 };
 
 /*< private >*/
@@ -274,9 +276,13 @@ enum /*< skip >*/
  *                  for more information.
  **/
 #define XFCE_PANEL_PLUGIN_REGISTER_EXTERNAL_FULL(construct_func, preinit_func, check_func) \
-  static GdkAtom  _xpp_atom = GDK_NONE; \
-  static gdouble  _xpp_alpha = 1.00; \
-  static gboolean _xpp_composited = FALSE; \
+  static GdkAtom          _xpp_atom = GDK_NONE; \
+  static gdouble          _xpp_alpha = 1.00; \
+  static gboolean         _xpp_composited = FALSE; \
+  static guint            _xpp_bg_style = 0; \
+  static GdkColor         _xpp_bg_color = { 0, }; \
+  static const gchar     *_xpp_bg_image = NULL; \
+  static cairo_pattern_t *_xpp_bg_image_cache = NULL; \
   \
   static void \
   _xpp_quit_main_loop (void) \
@@ -357,6 +363,19 @@ enum /*< skip >*/
             _xpp_quit_main_loop (); \
             break; \
             \
+          case PANEL_CLIENT_EVENT_SET_BG_COLOR: \
+            _xpp_bg_color.red = event->data.s[1]; \
+            _xpp_bg_color.green = event->data.s[2]; \
+            _xpp_bg_color.blue = event->data.s[3]; \
+            _xpp_bg_style = 1; \
+            gtk_widget_queue_draw (plug); \
+            break; \
+            \
+          case PANEL_CLIENT_EVENT_UNSET_BG: \
+            _xpp_bg_style = 0; \
+            gtk_widget_queue_draw (plug); \
+            break; \
+            \
           default: \
             g_warning ("Received unknow client event %d", message); \
             break; \
@@ -417,29 +436,78 @@ enum /*< skip >*/
   _xpp_expose_event (GtkWidget      *plug, \
                      GdkEventExpose *event) \
   { \
-    cairo_t  *cr; \
-    GdkColor *color; \
+    cairo_t        *cr; \
+    const GdkColor *color; \
+    gdouble         real_alpha; \
+    GdkPixbuf      *pixbuf; \
+    GError         *error = NULL; \
+    \
+    if (!GTK_WIDGET_DRAWABLE (plug)) \
+      return FALSE; \
     \
-    if (_xpp_composited \
-        && GTK_WIDGET_DRAWABLE (plug) \
-        && _xpp_alpha < 1.00) \
+    if (G_UNLIKELY (_xpp_bg_style == 2)) \
       { \
         cr = gdk_cairo_create (gtk_widget_get_window (plug)); \
         cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); \
+        gdk_cairo_rectangle (cr, &event->area); \
+        cairo_clip (cr); \
         \
-        color = &(gtk_widget_get_style (plug)->bg[GTK_STATE_NORMAL]); \
-        cairo_set_source_rgba (cr, \
-                               color->red / 65535.00, \
-                               color->green / 65535.00, \
-                               color->blue / 65535.00, \
-                               _xpp_alpha); \
-        \
-        cairo_rectangle (cr, event->area.x, event->area.y, \
-                         event->area.width, event->area.height); \
+        if (G_LIKELY (_xpp_bg_image_cache != NULL)) \
+          { \
+            cairo_set_source (cr, _xpp_bg_image_cache); \
+            cairo_paint (cr); \
+          } \
+        else \
+          { \
+            /* load the image in a pixbuf */ \
+            pixbuf = gdk_pixbuf_new_from_file (_xpp_bg_image, &error); \
+            if (G_LIKELY (pixbuf != NULL)) \
+              { \
+                gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); \
+                g_object_unref (G_OBJECT (pixbuf)); \
+                \
+                _xpp_bg_image_cache = cairo_get_source (cr); \
+                cairo_pattern_reference (_xpp_bg_image_cache); \
+                cairo_pattern_set_extend (_xpp_bg_image_cache, CAIRO_EXTEND_REPEAT); \
+                cairo_paint (cr); \
+              } \
+            else \
+              { \
+                /* print error message */ \
+                g_warning ("Background image disabled, \"%s\" could not be loaded: %s", \
+                           _xpp_bg_image, error != NULL ? error->message : "No error"); \
+                g_error_free (error); \
+                \
+                /* disable background image */ \
+                _xpp_bg_style = 0; \
+              } \
+          } \
         \
-        cairo_fill (cr); \
         cairo_destroy (cr); \
       } \
+    else \
+      { \
+        real_alpha = _xpp_composited ? _xpp_alpha : 1.00; \
+        \
+        if (_xpp_bg_style == 1 || real_alpha < 1.00) \
+          { \
+            if (G_LIKELY (_xpp_bg_style == 0)) \
+              color = &(gtk_widget_get_style (plug)->bg[GTK_STATE_NORMAL]); \
+            else \
+              color = &_xpp_bg_color; \
+            \
+            cr = gdk_cairo_create (gtk_widget_get_window (plug)); \
+            cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); \
+            cairo_set_source_rgba (cr, \
+                                   color->red / 65535.00, \
+                                   color->green / 65535.00, \
+                                   color->blue / 65535.00, \
+                                   real_alpha); \
+            gdk_cairo_rectangle (cr, &event->area); \
+            cairo_fill (cr); \
+            cairo_destroy (cr); \
+          } \
+      } \
     \
     return FALSE; \
   } \
@@ -524,12 +592,21 @@ enum /*< skip >*/
         G_CALLBACK (_xpp_provider_signal), plug); \
     gtk_widget_show (xpp); \
     \
+    if (*argv[PLUGIN_ARGV_BACKGROUND_IMAGE] != '\0') \
+      { \
+        _xpp_bg_image = argv[PLUGIN_ARGV_BACKGROUND_IMAGE]; \
+        _xpp_bg_style = 2; \
+      } \
+    \
     g_signal_connect (G_OBJECT (plug), "client-event", \
        G_CALLBACK (_xpp_client_event), xpp); \
     gtk_widget_show (plug); \
     \
     gtk_main (); \
     \
+    if (_xpp_bg_image_cache != NULL) \
+      cairo_pattern_destroy (_xpp_bg_image_cache); \
+    \
     if (GTK_IS_WIDGET (plug)) \
       gtk_widget_destroy (plug); \
     \
diff --git a/libxfce4panel/xfce-panel-plugin-provider.h b/libxfce4panel/xfce-panel-plugin-provider.h
index b43be8d..1949b04 100644
--- a/libxfce4panel/xfce-panel-plugin-provider.h
+++ b/libxfce4panel/xfce-panel-plugin-provider.h
@@ -113,6 +113,7 @@ enum
   PLUGIN_ARGV_NAME,
   PLUGIN_ARGV_DISPLAY_NAME,
   PLUGIN_ARGV_COMMENT,
+  PLUGIN_ARGV_BACKGROUND_IMAGE,
   PLUGIN_ARGV_ARGUMENTS
 };
 
diff --git a/panel/panel-application.c b/panel/panel-application.c
index f1a32a0..ae3eb75 100644
--- a/panel/panel-application.c
+++ b/panel/panel-application.c
@@ -38,6 +38,8 @@
 #include <libxfce4panel/xfce-panel-plugin-provider.h>
 
 #include <panel/panel-dbus-service.h>
+#include <panel/panel-base-window.h>
+#include <panel/panel-plugin-external-46.h>
 #include <panel/panel-window.h>
 #include <panel/panel-application.h>
 #include <panel/panel-itembar.h>
@@ -268,6 +270,9 @@ panel_application_xfconf_window_bindings (PanelApplication *application,
     { "enter-opacity", G_TYPE_UINT },
     { "leave-opacity", G_TYPE_UINT },
     { "background-alpha", G_TYPE_UINT },
+    { "background-style", G_TYPE_UINT },
+    { "background-color", GDK_TYPE_COLOR },
+    { "background-image", G_TYPE_STRING },
     { "output-name", G_TYPE_STRING },
     { "position", G_TYPE_STRING },
     { "disable-struts", G_TYPE_BOOLEAN },
@@ -616,6 +621,13 @@ panel_application_plugin_insert (PanelApplication  *application,
   g_signal_connect (G_OBJECT (provider), "provider-signal",
       G_CALLBACK (panel_application_plugin_provider_signal), application);
 
+  /* work around the problem that we need a background before
+   * realizing for 4.6 panel plugins */
+  if (PANEL_BASE_WINDOW (window)->background_style == PANEL_BG_STYLE_IMAGE
+      && PANEL_IS_PLUGIN_EXTERNAL_46 (provider))
+    panel_plugin_external_46_set_background_image (PANEL_PLUGIN_EXTERNAL_46 (provider),
+        PANEL_BASE_WINDOW (window)->background_image);
+
   /* add the item to the panel */
   itembar = gtk_bin_get_child (GTK_BIN (window));
   panel_itembar_insert (PANEL_ITEMBAR (itembar),
diff --git a/panel/panel-base-window.c b/panel/panel-base-window.c
index 77eb5fe..ae51528 100644
--- a/panel/panel-base-window.c
+++ b/panel/panel-base-window.c
@@ -61,8 +61,14 @@ static void     panel_base_window_update_provider_info        (GtkWidget
                                                                gpointer              user_data);
 static gboolean panel_base_window_active_timeout              (gpointer              user_data);
 static void     panel_base_window_active_timeout_destroyed    (gpointer              user_data);
+static void     panel_base_window_set_plugin_data             (PanelBaseWindow      *window,
+                                                               GtkCallback           func);
 static void     panel_base_window_set_plugin_background_alpha (GtkWidget            *widget,
                                                                gpointer              user_data);
+static void     panel_base_window_set_plugin_background_color (GtkWidget            *widget,
+                                                               gpointer              user_data);
+static void     panel_base_window_set_plugin_background_image (GtkWidget            *widget,
+                                                               gpointer              user_data);
 
 
 
@@ -75,19 +81,24 @@ enum
   PROP_BORDERS,
   PROP_ACTIVE,
   PROP_COMPOSITED,
+  PROP_BACKGROUND_STYLE,
+  PROP_BACKGROUND_COLOR,
+  PROP_BACKGROUND_IMAGE
 };
 
 struct _PanelBaseWindowPrivate
 {
-  /* borders */
-  PanelBorders borders;
+  PanelBorders     borders;
 
-  /* settings */
-  gdouble      enter_opacity;
-  gdouble      leave_opacity;
+  /* background image cache */
+  cairo_pattern_t *bg_image_cache;
+
+  /* transparency settings */
+  gdouble          enter_opacity;
+  gdouble          leave_opacity;
 
   /* active window timeout id */
-  guint        active_timeout_id;
+  guint            active_timeout_id;
 };
 
 
@@ -138,6 +149,29 @@ panel_base_window_class_init (PanelBaseWindowClass *klass)
                                                       EXO_PARAM_READWRITE));
 
   g_object_class_install_property (gobject_class,
+                                   PROP_BACKGROUND_STYLE,
+                                   g_param_spec_uint ("background-style",
+                                                      NULL, NULL,
+                                                      PANEL_BG_STYLE_NONE,
+                                                      PANEL_BG_STYLE_IMAGE,
+                                                      PANEL_BG_STYLE_NONE,
+                                                      EXO_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_BACKGROUND_COLOR,
+                                   g_param_spec_boxed ("background-color",
+                                                       NULL, NULL,
+                                                       GDK_TYPE_COLOR,
+                                                       EXO_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_BACKGROUND_IMAGE,
+                                   g_param_spec_string ("background-image",
+                                                        NULL, NULL,
+                                                        NULL,
+                                                        EXO_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
                                    PROP_BORDERS,
                                    g_param_spec_uint ("borders",
                                                       NULL, NULL,
@@ -169,12 +203,16 @@ panel_base_window_init (PanelBaseWindow *window)
   window->is_composited = FALSE;
   window->background_alpha = 1.00;
 
+  window->background_style = PANEL_BG_STYLE_NONE;
+  window->background_image = NULL;
+  window->background_color = NULL;
+  window->priv->bg_image_cache = NULL;
+
   window->priv->enter_opacity = 1.00;
   window->priv->leave_opacity = 1.00;
   window->priv->borders = PANEL_BORDER_NONE;
   window->priv->active_timeout_id = 0;
 
-  /* set colormap */
   panel_base_window_composited_changed (GTK_WIDGET (window));
 }
 
@@ -203,6 +241,18 @@ panel_base_window_get_property (GObject    *object,
       g_value_set_uint (value, rint (window->background_alpha * 100.00));
       break;
 
+    case PROP_BACKGROUND_STYLE:
+      g_value_set_uint (value, window->background_style);
+      break;
+
+    case PROP_BACKGROUND_COLOR:
+      g_value_set_boxed (value, window->background_color);
+      break;
+
+    case PROP_BACKGROUND_IMAGE:
+      g_value_set_string (value, window->background_image);
+      break;
+
     case PROP_BORDERS:
       g_value_set_uint (value, priv->borders);
       break;
@@ -231,7 +281,7 @@ panel_base_window_set_property (GObject      *object,
 {
   PanelBaseWindow        *window = PANEL_BASE_WINDOW (object);
   PanelBaseWindowPrivate *priv = window->priv;
-  GtkWidget              *itembar;
+  PanelBgStyle            bg_style;
 
   switch (prop_id)
     {
@@ -254,10 +304,74 @@ panel_base_window_set_property (GObject      *object,
         gtk_widget_queue_draw (GTK_WIDGET (object));
 
       /* send the new background alpha to the external plugins */
-      itembar = gtk_bin_get_child (GTK_BIN (window));
-      if (G_LIKELY (itembar != NULL))
-        gtk_container_foreach (GTK_CONTAINER (itembar),
-            panel_base_window_set_plugin_background_alpha, window);
+      panel_base_window_set_plugin_data (window,
+          panel_base_window_set_plugin_background_alpha);
+      break;
+
+    case PROP_BACKGROUND_STYLE:
+      bg_style = g_value_get_uint (value);
+      if (window->background_style != bg_style)
+        {
+          window->background_style = bg_style;
+
+          if (priv->bg_image_cache != NULL)
+            {
+              /* destroy old image cache */
+              cairo_pattern_destroy (priv->bg_image_cache);
+              priv->bg_image_cache = NULL;
+            }
+
+          /* send information to external plugins */
+          if (window->background_style == PANEL_BG_STYLE_IMAGE
+              && window->background_image != NULL)
+            {
+              panel_base_window_set_plugin_data (window,
+                  panel_base_window_set_plugin_background_image);
+            }
+          else if (window->background_style == PANEL_BG_STYLE_NONE
+                   || (window->background_style == PANEL_BG_STYLE_COLOR
+                       && window->background_color != NULL))
+            {
+              panel_base_window_set_plugin_data (window,
+                  panel_base_window_set_plugin_background_color);
+            }
+
+          /* resize to update border size too */
+          gtk_widget_queue_resize (GTK_WIDGET (window));
+        }
+      break;
+
+    case PROP_BACKGROUND_COLOR:
+      if (window->background_color != NULL)
+        gdk_color_free (window->background_color);
+      window->background_color = g_value_dup_boxed (value);
+
+      if (window->background_style == PANEL_BG_STYLE_COLOR)
+        {
+          panel_base_window_set_plugin_data (window,
+              panel_base_window_set_plugin_background_color);
+          gtk_widget_queue_draw (GTK_WIDGET (window));
+        }
+      break;
+
+    case PROP_BACKGROUND_IMAGE:
+      /* store new filename */
+      g_free (window->background_image);
+      window->background_image = g_value_dup_string (value);
+
+      /* drop old cache */
+      if (priv->bg_image_cache != NULL)
+        {
+          cairo_pattern_destroy (priv->bg_image_cache);
+          priv->bg_image_cache = NULL;
+        }
+
+      if (window->background_style == PANEL_BG_STYLE_IMAGE)
+        {
+          panel_base_window_set_plugin_data (window,
+              panel_base_window_set_plugin_background_image);
+          gtk_widget_queue_draw (GTK_WIDGET (window));
+        }
       break;
 
     case PROP_BORDERS:
@@ -299,11 +413,18 @@ panel_base_window_set_property (GObject      *object,
 static void
 panel_base_window_finalize (GObject *object)
 {
-  PanelBaseWindowPrivate *priv = PANEL_BASE_WINDOW (object)->priv;
+  PanelBaseWindow *window = PANEL_BASE_WINDOW (object);
 
   /* stop running marching ants timeout */
-  if (priv->active_timeout_id != 0)
-    g_source_remove (priv->active_timeout_id);
+  if (window->priv->active_timeout_id != 0)
+    g_source_remove (window->priv->active_timeout_id);
+
+  /* release bg image data */
+  g_free (window->background_image);
+  if (window->priv->bg_image_cache != NULL)
+    cairo_pattern_destroy (window->priv->bg_image_cache);
+  if (window->background_color != NULL)
+    gdk_color_free (window->background_color);
 
   (*G_OBJECT_CLASS (panel_base_window_parent_class)->finalize) (object);
 }
@@ -315,7 +436,7 @@ panel_base_window_expose_event (GtkWidget      *widget,
                                 GdkEventExpose *event)
 {
   cairo_t                *cr;
-  GdkColor               *color;
+  const GdkColor         *color;
   PanelBaseWindow        *window = PANEL_BASE_WINDOW (widget);
   PanelBaseWindowPrivate *priv = window->priv;
   gdouble                 alpha;
@@ -324,6 +445,9 @@ panel_base_window_expose_event (GtkWidget      *widget,
   const gdouble           dashes[] = { 4.00, 4.00 };
   GTimeVal                timeval;
   gboolean                result;
+  GdkPixbuf              *pixbuf;
+  GError                 *error = NULL;
+  cairo_matrix_t          matrix = { 1, 0, 0, 1, 0, 0 }; /* identity matrix */
 
   result = (*GTK_WIDGET_CLASS (panel_base_window_parent_class)->expose_event) (widget, event);
 
@@ -337,27 +461,77 @@ panel_base_window_expose_event (GtkWidget      *widget,
   cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
   cairo_set_line_width (cr, 1.00);
 
-  /* clip the drawing area */
+  /* set rectangle to clip the drawing area */
   gdk_cairo_rectangle (cr, &event->area);
 
-  /* get background alpha */
-  alpha = window->is_composited ? window->background_alpha : 1.00;
-
-  /* only do something with the background when compositing is enabled */
-  if (G_UNLIKELY (alpha < 1.00))
+  if (window->background_style == PANEL_BG_STYLE_IMAGE)
     {
-      /* clip the drawing area, but preserve the rectangle */
-      cairo_clip_preserve (cr);
+      /* clip the drawing area */
+      cairo_clip (cr);
+
+      if (G_LIKELY (priv->bg_image_cache != NULL))
+        {
+          if (G_UNLIKELY (priv->active_timeout_id != 0))
+            cairo_matrix_init_translate (&matrix, -1, -1);
+
+          cairo_set_source (cr, priv->bg_image_cache);
+          cairo_pattern_set_matrix (priv->bg_image_cache, &matrix);
+          cairo_paint (cr);
+        }
+      else if (window->background_image != NULL)
+        {
+          /* load the image in a pixbuf */
+          pixbuf = gdk_pixbuf_new_from_file (window->background_image, &error);
+
+          if (G_LIKELY (pixbuf != NULL))
+            {
+              gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+              g_object_unref (G_OBJECT (pixbuf));
 
-      /* make the background transparent */
-      color = &(widget->style->bg[GTK_STATE_NORMAL]);
-      panel_util_set_source_rgba (cr, color, alpha);
-      cairo_fill (cr);
+              priv->bg_image_cache = cairo_get_source (cr);
+              cairo_pattern_reference (priv->bg_image_cache);
+              cairo_pattern_set_extend (priv->bg_image_cache, CAIRO_EXTEND_REPEAT);
+              cairo_paint (cr);
+            }
+          else
+            {
+              /* print error message */
+              g_warning ("Background image disabled, \"%s\" could not be loaded: %s",
+                         window->background_image, error != NULL ? error->message : "No error");
+              g_error_free (error);
+
+              /* disable background image mode */
+              window->background_style = PANEL_BG_STYLE_NONE;
+            }
+        }
     }
   else
     {
-      /* clip the drawing area */
-      cairo_clip (cr);
+      /* get background alpha */
+      alpha = window->is_composited ? window->background_alpha : 1.00;
+
+      /* get the background color */
+      if (window->background_style == PANEL_BG_STYLE_COLOR)
+        color = window->background_color;
+      else
+        color = &(widget->style->bg[GTK_STATE_NORMAL]);
+
+      /* only do something with the background when compositing is enabled */
+      if (G_UNLIKELY (alpha < 1.00
+          || window->background_style != PANEL_BG_STYLE_NONE))
+        {
+          /* clip the drawing area, but preserve the rectangle */
+          cairo_clip_preserve (cr);
+
+          /* draw the background */
+          panel_util_set_source_rgba (cr, color, alpha);
+          cairo_fill (cr);
+        }
+      else
+        {
+          /* clip the drawing area */
+          cairo_clip (cr);
+        }
     }
 
   /* draw marching ants selection if the timeout is running */
@@ -375,7 +549,7 @@ panel_base_window_expose_event (GtkWidget      *widget,
       cairo_rectangle (cr, 0.5, 0.5, width - 1, height - 1);
       cairo_stroke (cr);
     }
-  else
+  else if (window->background_style == PANEL_BG_STYLE_NONE)
     {
       if (PANEL_HAS_FLAG (priv->borders, PANEL_BORDER_BOTTOM | PANEL_BORDER_RIGHT))
         {
@@ -483,6 +657,13 @@ panel_base_window_composited_changed (GtkWidget *widget)
       gtk_widget_unrealize (widget);
     }
 
+  /* clear cairo image cache */
+  if (window->priv->bg_image_cache != NULL)
+    {
+      cairo_pattern_destroy (window->priv->bg_image_cache);
+      window->priv->bg_image_cache = NULL;
+    }
+
   /* get the widget screen */
   screen = gtk_window_get_screen (GTK_WINDOW (widget));
   panel_return_if_fail (GDK_IS_SCREEN (screen));
@@ -567,6 +748,19 @@ panel_base_window_active_timeout_destroyed (gpointer user_data)
 
 
 static void
+panel_base_window_set_plugin_data (PanelBaseWindow *window,
+                                   GtkCallback      func)
+{
+  GtkWidget *itembar;
+
+  itembar = gtk_bin_get_child (GTK_BIN (window));
+  if (G_LIKELY (itembar != NULL))
+    gtk_container_foreach (GTK_CONTAINER (itembar), func, window);
+}
+
+
+
+static void
 panel_base_window_set_plugin_background_alpha (GtkWidget *widget,
                                                gpointer   user_data)
 {
@@ -584,6 +778,44 @@ panel_base_window_set_plugin_background_alpha (GtkWidget *widget,
 
 
 
+static void
+panel_base_window_set_plugin_background_color (GtkWidget *widget,
+                                               gpointer   user_data)
+{
+  PanelBaseWindow *window = PANEL_BASE_WINDOW (user_data);
+  GdkColor        *color;
+
+  panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (widget));
+  panel_return_if_fail (PANEL_IS_BASE_WINDOW (user_data));
+
+  /* send null if the style is not a bg color */
+  color = window->background_style == PANEL_BG_STYLE_COLOR ? window->background_color : NULL;
+
+  if (PANEL_IS_PLUGIN_EXTERNAL (widget))
+    panel_plugin_external_set_background_color (PANEL_PLUGIN_EXTERNAL (widget), color);
+  else if (PANEL_IS_PLUGIN_EXTERNAL_46 (widget))
+    panel_plugin_external_46_set_background_color (PANEL_PLUGIN_EXTERNAL_46 (widget), color);
+}
+
+
+
+static void
+panel_base_window_set_plugin_background_image (GtkWidget *widget,
+                                               gpointer   user_data)
+{
+  panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (widget));
+  panel_return_if_fail (PANEL_IS_BASE_WINDOW (user_data));
+
+  if (PANEL_IS_PLUGIN_EXTERNAL (widget))
+    panel_plugin_external_set_background_image (PANEL_PLUGIN_EXTERNAL (widget),
+        PANEL_BASE_WINDOW (user_data)->background_image);
+  else if (PANEL_IS_PLUGIN_EXTERNAL_46 (widget))
+    panel_plugin_external_46_set_background_image (PANEL_PLUGIN_EXTERNAL_46 (widget),
+        PANEL_BASE_WINDOW (user_data)->background_image);
+}
+
+
+
 void
 panel_base_window_move_resize (PanelBaseWindow *window,
                                gint             x,
@@ -629,6 +861,8 @@ panel_base_window_get_borders (PanelBaseWindow *window)
   if (priv->active_timeout_id != 0)
     return PANEL_BORDER_TOP | PANEL_BORDER_BOTTOM
            | PANEL_BORDER_LEFT | PANEL_BORDER_RIGHT;
+  else if (window->background_style != PANEL_BG_STYLE_NONE)
+    return PANEL_BORDER_NONE;
 
   return priv->borders;
 }
@@ -636,9 +870,9 @@ panel_base_window_get_borders (PanelBaseWindow *window)
 
 
 void
-panel_util_set_source_rgba (cairo_t  *cr,
-                            GdkColor *color,
-                            gdouble   alpha)
+panel_util_set_source_rgba (cairo_t        *cr,
+                            const GdkColor *color,
+                            gdouble         alpha)
 {
   panel_return_if_fail (alpha >= 0.00 && alpha <= 1.00);
 
diff --git a/panel/panel-base-window.h b/panel/panel-base-window.h
index 78333e4..f74ac13 100644
--- a/panel/panel-base-window.h
+++ b/panel/panel-base-window.h
@@ -27,6 +27,7 @@ typedef struct _PanelBaseWindowClass   PanelBaseWindowClass;
 typedef struct _PanelBaseWindow        PanelBaseWindow;
 typedef struct _PanelBaseWindowPrivate PanelBaseWindowPrivate;
 typedef enum   _PanelBorders           PanelBorders;
+typedef enum   _PanelBgStyle           PanelBgStyle;
 
 #define PANEL_TYPE_BASE_WINDOW            (panel_base_window_get_type ())
 #define PANEL_BASE_WINDOW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), PANEL_TYPE_BASE_WINDOW, PanelBaseWindow))
@@ -44,6 +45,13 @@ enum _PanelBorders
   PANEL_BORDER_BOTTOM = 1 << 3
 };
 
+enum _PanelBgStyle
+{
+  PANEL_BG_STYLE_NONE,
+  PANEL_BG_STYLE_COLOR,
+  PANEL_BG_STYLE_IMAGE
+};
+
 struct _PanelBaseWindowClass
 {
   GtkWindowClass __parent__;
@@ -56,9 +64,12 @@ struct _PanelBaseWindow
   /*< private >*/
   PanelBaseWindowPrivate *priv;
 
-  /*< private >*/
   guint                   is_composited : 1;
+
   gdouble                 background_alpha;
+  PanelBgStyle            background_style;
+  GdkColor               *background_color;
+  gchar                  *background_image;
 };
 
 GType        panel_base_window_get_type    (void) G_GNUC_CONST;
@@ -77,7 +88,7 @@ void         panel_base_window_set_active  (PanelBaseWindow *window,
                                             gboolean         active);
 
 void         panel_util_set_source_rgba    (cairo_t         *cr,
-                                            GdkColor        *color,
+                                            const GdkColor  *color,
                                             gdouble          alpha);
 
 G_END_DECLS
diff --git a/panel/panel-plugin-external-46.c b/panel/panel-plugin-external-46.c
index 415d615..2e7c030 100644
--- a/panel/panel-plugin-external-46.c
+++ b/panel/panel-plugin-external-46.c
@@ -48,53 +48,55 @@
 
 
 
-static void         panel_plugin_external_46_provider_init         (XfcePanelPluginProviderInterface *iface);
-static void         panel_plugin_external_46_finalize              (GObject                          *object);
-static void         panel_plugin_external_46_get_property          (GObject                          *object,
-                                                                    guint                             prop_id,
-                                                                    GValue                           *value,
-                                                                    GParamSpec                       *pspec);
-static void         panel_plugin_external_46_set_property          (GObject                          *object,
-                                                                    guint                             prop_id,
-                                                                    const GValue                     *value,
-                                                                    GParamSpec                       *pspec);
-static void         panel_plugin_external_46_realize               (GtkWidget                        *widget);
-static void         panel_plugin_external_46_unrealize             (GtkWidget                        *widget);
-static gboolean     panel_plugin_external_46_client_event          (GtkWidget                        *widget,
-                                                                    GdkEventClient                   *event);
-static gboolean     panel_plugin_external_46_plug_removed          (GtkSocket                        *socket);
-static void         panel_plugin_external_46_plug_added            (GtkSocket                        *socket);
-static void         panel_plugin_external_46_send_client_event     (PanelPluginExternal46            *external,
-                                                                    gint                              message,
-                                                                    gint                              value);
-static void         panel_plugin_external_46_queue_add             (PanelPluginExternal46            *external,
-                                                                    gint                              message,
-                                                                    gint                              value);
-static const gchar *panel_plugin_external_46_get_name              (XfcePanelPluginProvider          *provider);
-static gint         panel_plugin_external_46_get_unique_id         (XfcePanelPluginProvider          *provider);
-static void         panel_plugin_external_46_set_size              (XfcePanelPluginProvider          *provider,
-                                                                    gint                              size);
-static void         panel_plugin_external_46_set_orientation       (XfcePanelPluginProvider          *provider,
-                                                                    GtkOrientation                    orientation);
-static void         panel_plugin_external_46_set_screen_position   (XfcePanelPluginProvider          *provider,
-                                                                    XfceScreenPosition                screen_position);
-static void         panel_plugin_external_46_save                  (XfcePanelPluginProvider          *provider);
-static gboolean     panel_plugin_external_46_get_show_configure    (XfcePanelPluginProvider          *provider);
-static void         panel_plugin_external_46_show_configure        (XfcePanelPluginProvider          *provider);
-static gboolean     panel_plugin_external_46_get_show_about        (XfcePanelPluginProvider          *provider);
-static void         panel_plugin_external_46_show_about            (XfcePanelPluginProvider          *provider);
-static void         panel_plugin_external_46_removed               (XfcePanelPluginProvider          *provider);
-static gboolean     panel_plugin_external_46_remote_event          (XfcePanelPluginProvider          *provider,
-                                                                    const gchar                      *name,
-                                                                    const GValue                     *value,
-                                                                    guint                            *handler_id);
-static void         panel_plugin_external_46_set_locked            (XfcePanelPluginProvider          *provider,
-                                                                    gboolean                          locked);
-static void         panel_plugin_external_46_set_sensitive         (PanelPluginExternal46            *external);
-static void         panel_plugin_external_46_child_watch           (GPid                              pid,
-                                                                    gint                              status,
-                                                                    gpointer                          user_data);
-static void         panel_plugin_external_46_child_watch_destroyed (gpointer                          user_data);
+static void         panel_plugin_external_46_provider_init            (XfcePanelPluginProviderInterface *iface);
+static void         panel_plugin_external_46_finalize                 (GObject                          *object);
+static void         panel_plugin_external_46_get_property             (GObject                          *object,
+                                                                       guint                             prop_id,
+                                                                       GValue                           *value,
+                                                                       GParamSpec                       *pspec);
+static void         panel_plugin_external_46_set_property             (GObject                          *object,
+                                                                       guint                             prop_id,
+                                                                       const GValue                     *value,
+                                                                       GParamSpec                       *pspec);
+static void         panel_plugin_external_46_realize                  (GtkWidget                        *widget);
+static void         panel_plugin_external_46_unrealize                (GtkWidget                        *widget);
+static gboolean     panel_plugin_external_46_client_event             (GtkWidget                        *widget,
+                                                                       GdkEventClient                   *event);
+static gboolean     panel_plugin_external_46_plug_removed             (GtkSocket                        *socket);
+static void         panel_plugin_external_46_plug_added               (GtkSocket                        *socket);
+static void         panel_plugin_external_46_send_client_event        (PanelPluginExternal46            *external,
+                                                                       GdkEventClient                   *event);
+static void         panel_plugin_external_46_send_client_event_simple (PanelPluginExternal46            *external,
+                                                                       gint                              message,
+                                                                       gint                              value);
+static void         panel_plugin_external_46_queue_add                (PanelPluginExternal46            *external,
+                                                                       gint                              message,
+                                                                       gint                              value);
+static const gchar *panel_plugin_external_46_get_name                 (XfcePanelPluginProvider          *provider);
+static gint         panel_plugin_external_46_get_unique_id            (XfcePanelPluginProvider          *provider);
+static void         panel_plugin_external_46_set_size                 (XfcePanelPluginProvider          *provider,
+                                                                       gint                              size);
+static void         panel_plugin_external_46_set_orientation          (XfcePanelPluginProvider          *provider,
+                                                                       GtkOrientation                    orientation);
+static void         panel_plugin_external_46_set_screen_position      (XfcePanelPluginProvider          *provider,
+                                                                       XfceScreenPosition                screen_position);
+static void         panel_plugin_external_46_save                     (XfcePanelPluginProvider          *provider);
+static gboolean     panel_plugin_external_46_get_show_configure       (XfcePanelPluginProvider          *provider);
+static void         panel_plugin_external_46_show_configure           (XfcePanelPluginProvider          *provider);
+static gboolean     panel_plugin_external_46_get_show_about           (XfcePanelPluginProvider          *provider);
+static void         panel_plugin_external_46_show_about               (XfcePanelPluginProvider          *provider);
+static void         panel_plugin_external_46_removed                  (XfcePanelPluginProvider          *provider);
+static gboolean     panel_plugin_external_46_remote_event             (XfcePanelPluginProvider          *provider,
+                                                                       const gchar                      *name,
+                                                                       const GValue                     *value,
+                                                                       guint                            *handler_id);
+static void         panel_plugin_external_46_set_locked               (XfcePanelPluginProvider          *provider,
+                                                                       gboolean                          locked);
+static void         panel_plugin_external_46_set_sensitive            (PanelPluginExternal46            *external);
+static void         panel_plugin_external_46_child_watch              (GPid                              pid,
+                                                                       gint                              status,
+                                                                       gpointer                          user_data);
+static void         panel_plugin_external_46_child_watch_destroyed    (gpointer                          user_data);
 
 
 
@@ -126,6 +128,9 @@ struct _PanelPluginExternal46
   guint             show_configure : 1;
   guint             show_about : 1;
 
+  /* background image location */
+  gchar            *background_image;
+
   /* child watch data */
   GPid              pid;
   guint             watch_id;
@@ -139,13 +144,6 @@ enum
   PROP_ARGUMENTS
 };
 
-typedef struct
-{
-  gint message;
-  gint value;
-}
-QueueItem;
-
 
 
 static GdkAtom panel_atom = GDK_NONE;
@@ -218,6 +216,7 @@ panel_plugin_external_46_init (PanelPluginExternal46 *external)
   external->restart_timer = NULL;
   external->show_configure = FALSE;
   external->show_about = FALSE;
+  external->background_image = NULL;
 
   /* signal to pass gtk_widget_set_sensitive() changes to the remote window */
   g_signal_connect (G_OBJECT (external), "notify::sensitive",
@@ -262,11 +261,12 @@ panel_plugin_external_46_finalize (GObject *object)
   if (external->queue != NULL)
     {
       for (li = external->queue; li != NULL; li = li->next)
-        g_slice_free (QueueItem, li->data);
+        g_slice_free (GdkEventClient, li->data);
       g_slist_free (external->queue);
     }
 
   g_strfreev (external->arguments);
+  g_free (external->background_image);
 
   if (external->restart_timer != NULL)
     g_timer_destroy (external->restart_timer);
@@ -374,6 +374,11 @@ panel_plugin_external_46_realize (GtkWidget *widget)
   argv[PLUGIN_ARGV_DISPLAY_NAME] = (gchar *) panel_module_get_display_name (external->module);
   argv[PLUGIN_ARGV_COMMENT] = (gchar *) panel_module_get_comment (external->module);
 
+  if (external->background_image != NULL)
+    argv[PLUGIN_ARGV_BACKGROUND_IMAGE] = (gchar *) external->background_image;
+  else
+    argv[PLUGIN_ARGV_BACKGROUND_IMAGE] = (gchar *) "";
+
   /* append the arguments */
   if (G_UNLIKELY (external->arguments != NULL))
     for (i = 0; external->arguments[i] != NULL; i++)
@@ -420,7 +425,7 @@ panel_plugin_external_46_unrealize (GtkWidget *widget)
   external->plug_embedded = FALSE;
 
   panel_debug (PANEL_DEBUG_DOMAIN_EXTERNAL46,
-               "Plugin %s-%d unrealized, quiting GtkPlug",
+               "plugin %s-%d unrealized, quiting GtkPlug",
                panel_module_get_name (external->module),
                external->unique_id);
 
@@ -433,7 +438,7 @@ panel_plugin_external_46_unrealize (GtkWidget *widget)
     }
 
   /* quit the plugin */
-  panel_plugin_external_46_send_client_event (external, PANEL_CLIENT_EVENT_QUIT, FALSE);
+  panel_plugin_external_46_send_client_event_simple (external, PANEL_CLIENT_EVENT_QUIT, FALSE);
 
   (*GTK_WIDGET_CLASS (panel_plugin_external_46_parent_class)->unrealize) (widget);
 }
@@ -547,13 +552,13 @@ panel_plugin_external_46_plug_added (GtkSocket *socket)
 {
   PanelPluginExternal46 *external = PANEL_PLUGIN_EXTERNAL_46 (socket);
   GSList                *li;
-  QueueItem             *item;
+  GdkEventClient        *event;
 
   /* plug has been added */
   external->plug_embedded = TRUE;
 
   panel_debug (PANEL_DEBUG_DOMAIN_EXTERNAL46,
-               "plugin  %d has been embedded, %d values in queue",
+               "plugin %d has been embedded, %d events in queue",
                external->unique_id, g_slist_length (external->queue));
 
   /* send all the messages in the queue */
@@ -562,11 +567,9 @@ panel_plugin_external_46_plug_added (GtkSocket *socket)
       external->queue = g_slist_reverse (external->queue);
       for (li = external->queue; li != NULL; li = li->next)
         {
-          item = li->data;
-          panel_plugin_external_46_send_client_event (external,
-                                                      item->message,
-                                                      item->value);
-          g_slice_free (QueueItem, item);
+          event = li->data;
+          panel_plugin_external_46_send_client_event (external, event);
+          g_slice_free (GdkEventClient, event);
         }
 
       g_slist_free (external->queue);
@@ -578,30 +581,44 @@ panel_plugin_external_46_plug_added (GtkSocket *socket)
 
 static void
 panel_plugin_external_46_send_client_event (PanelPluginExternal46 *external,
-                                            gint                   message,
-                                            gint                   value)
+                                            GdkEventClient        *event)
 {
-  GdkEventClient event;
-
   panel_return_if_fail (PANEL_IS_PLUGIN_EXTERNAL_46 (external));
   panel_return_if_fail (panel_atom != GDK_NONE);
   panel_return_if_fail (GDK_IS_WINDOW (GTK_WIDGET (external)->window));
 
-  event.type = GDK_CLIENT_EVENT;
-  event.window = GTK_WIDGET (external)->window;
-  event.send_event = TRUE;
-  event.message_type = panel_atom;
-  event.data_format = 16;
-  event.data.s[0] = message;
-  event.data.s[1] = value;
-  event.data.s[2] = 0;
+  /* complete event information */
+  event->type = GDK_CLIENT_EVENT;
+  event->window = GTK_WIDGET (external)->window;
+  event->send_event = TRUE;
+  event->message_type = panel_atom;
 
   gdk_error_trap_push ();
-  gdk_event_send_client_message ((GdkEvent *) &event,
+  gdk_event_send_client_message ((GdkEvent *) event,
       GDK_WINDOW_XID (gtk_socket_get_plug_window (GTK_SOCKET (external))));
   gdk_flush ();
   if (gdk_error_trap_pop () != 0)
-    g_warning ("Failed to send client event %d", message);
+    g_warning ("Failed to send client event %d", event->data.s[0]);
+}
+
+
+
+static void
+panel_plugin_external_46_send_client_event_simple (PanelPluginExternal46 *external,
+                                                   gint                   message,
+                                                   gint                   value)
+{
+  GdkEventClient event;
+
+  panel_return_if_fail (PANEL_IS_PLUGIN_EXTERNAL_46 (external));
+
+  /* set event data */
+  event.data_format = 16;
+  event.data.s[0] = message;
+  event.data.s[1] = value;
+  event.data.s[2] = 0;
+
+  panel_plugin_external_46_send_client_event (external, &event);
 }
 
 
@@ -611,23 +628,24 @@ panel_plugin_external_46_queue_add (PanelPluginExternal46 *external,
                                     gint                   message,
                                     gint                   value)
 {
-  QueueItem *item;
+  GdkEventClient *event;
 
   panel_return_if_fail (PANEL_IS_PLUGIN_EXTERNAL_46 (external));
 
   if (external->plug_embedded)
     {
       /* directly send the message */
-      panel_plugin_external_46_send_client_event (external, message, value);
+      panel_plugin_external_46_send_client_event_simple (external, message, value);
     }
   else
     {
       /* queue the message until the plug is embedded */
-      item = g_slice_new0 (QueueItem);
-      item->message = message;
-      item->value = value;
+      event = g_slice_new0 (GdkEventClient);
+      event->data_format = 16;
+      event->data.s[0] = message;
+      event->data.s[1] = value;
 
-      external->queue = g_slist_prepend (external->queue, item);
+      external->queue = g_slist_prepend (external->queue, event);
     }
 }
 
@@ -839,7 +857,7 @@ panel_plugin_external_46_child_watch (GPid     pid,
         case PLUGIN_EXIT_CHECK_FAILED:
         case PLUGIN_EXIT_NO_PROVIDER:
           panel_debug (PANEL_DEBUG_DOMAIN_EXTERNAL46,
-                       "Plugin exited with status %d. Removing from "
+                       "plugin exited with status %d. Removing from "
                        "configuration.", WEXITSTATUS (status));
 
           /* cleanup the plugin configuration (in panel-application) */
@@ -892,3 +910,74 @@ panel_plugin_external_46_set_background_alpha (PanelPluginExternal46 *external,
                                       PANEL_CLIENT_EVENT_SET_BACKGROUND_ALPHA,
                                       rint (alpha * 100.0));
 }
+
+
+
+void
+panel_plugin_external_46_set_background_color (PanelPluginExternal46 *external,
+                                               const GdkColor        *color)
+{
+  GdkEventClient *event;
+
+  panel_return_if_fail (PANEL_IS_PLUGIN_EXTERNAL_46 (external));
+
+  event = g_slice_new0 (GdkEventClient);
+
+  if (color != NULL)
+    {
+      event->data_format = 16;
+      event->data.s[0] = PANEL_CLIENT_EVENT_SET_BG_COLOR;
+      event->data.s[1] = color->red;
+      event->data.s[2] = color->green;
+      event->data.s[3] = color->blue;
+      event->data.s[4] = 0;
+    }
+  else
+    {
+      event->data_format = 16;
+      event->data.s[0] = PANEL_CLIENT_EVENT_UNSET_BG;
+    }
+
+  if (external->plug_embedded)
+    {
+      /* directly send the event */
+      panel_plugin_external_46_send_client_event (external, event);
+      g_slice_free (GdkEventClient, event);
+    }
+  else
+    {
+      /* queue the event until the plug is embedded */
+      external->queue = g_slist_prepend (external->queue, event);
+    }
+}
+
+
+void
+panel_plugin_external_46_set_background_image (PanelPluginExternal46 *external,
+                                               const gchar           *image)
+{
+  GtkWidget *window;
+
+  panel_return_if_fail (PANEL_IS_PLUGIN_EXTERNAL_46 (external));
+
+  /* store new file location */
+  g_free (external->background_image);
+  external->background_image = g_strdup (image);
+
+  /* restart the plugin if a process is already running */
+  if (external->plug_embedded)
+    {
+      panel_debug (PANEL_DEBUG_DOMAIN_EXTERNAL46,
+                   "going to restart plugin %d for background image change",
+                   external->unique_id);
+
+      gtk_widget_unrealize (GTK_WIDGET (external));
+      gtk_widget_hide (GTK_WIDGET (external));
+
+      window = gtk_widget_get_toplevel (GTK_WIDGET (external));
+      panel_return_if_fail (PANEL_IS_WINDOW (window));
+      panel_window_set_povider_info (PANEL_WINDOW (window), GTK_WIDGET (external));
+
+      gtk_widget_show (GTK_WIDGET (external));
+    }
+}
diff --git a/panel/panel-plugin-external-46.h b/panel/panel-plugin-external-46.h
index f5cb4c2..4b2ae26 100644
--- a/panel/panel-plugin-external-46.h
+++ b/panel/panel-plugin-external-46.h
@@ -42,9 +42,15 @@ GtkWidget *panel_plugin_external_46_new                  (PanelModule
                                                           gint                    unique_id,
                                                           gchar                 **arguments) G_GNUC_MALLOC;
 
-void       panel_plugin_external_46_set_background_alpha (PanelPluginExternal46   *external,
+void       panel_plugin_external_46_set_background_alpha (PanelPluginExternal46  *external,
                                                           gdouble                 alpha);
 
+void       panel_plugin_external_46_set_background_color (PanelPluginExternal46  *external,
+                                                          const GdkColor         *color);
+
+void       panel_plugin_external_46_set_background_image (PanelPluginExternal46  *external,
+                                                          const gchar            *image);
+
 G_END_DECLS
 
 #endif /* !__PANEL_PLUGIN_EXTERNAL_46_H__ */
diff --git a/panel/panel-plugin-external.c b/panel/panel-plugin-external.c
index a31dc45..55ed76a 100644
--- a/panel/panel-plugin-external.c
+++ b/panel/panel-plugin-external.c
@@ -457,6 +457,7 @@ panel_plugin_external_realize (GtkWidget *widget)
   argv[PLUGIN_ARGV_NAME] = (gchar *) panel_module_get_name (external->module);
   argv[PLUGIN_ARGV_DISPLAY_NAME] = (gchar *) panel_module_get_display_name (external->module);
   argv[PLUGIN_ARGV_COMMENT] = (gchar *) panel_module_get_comment (external->module);
+  argv[PLUGIN_ARGV_BACKGROUND_IMAGE] = (gchar *) ""; /* unused, for 4.6 plugins only */
 
   /* append the arguments */
   if (G_UNLIKELY (external->arguments != NULL))
@@ -1040,3 +1041,61 @@ panel_plugin_external_set_background_alpha (PanelPluginExternal *external,
 
   g_value_unset (&value);
 }
+
+
+
+void
+panel_plugin_external_set_background_color (PanelPluginExternal *external,
+                                            const GdkColor      *color)
+{
+  GValue       value = { 0, };
+  const gchar *prop;
+
+  panel_return_if_fail (PANEL_IS_PLUGIN_EXTERNAL (external));
+
+  if (G_LIKELY (color != NULL))
+    {
+      prop = SIGNAL_WRAPPER_BACKGROUND_COLOR;
+
+      g_value_init (&value, G_TYPE_STRING);
+      g_value_take_string (&value, gdk_color_to_string (color));
+    }
+  else
+    {
+      prop = SIGNAL_WRAPPER_BACKGROUND_UNSET;
+
+      g_value_init (&value, G_TYPE_BOOLEAN);
+    }
+
+  panel_plugin_external_queue_add (external, FALSE, prop, &value);
+
+  g_value_unset (&value);
+}
+
+
+
+void
+panel_plugin_external_set_background_image (PanelPluginExternal *external,
+                                            const gchar         *image)
+{
+  GValue value = { 0, };
+
+  panel_return_if_fail (PANEL_IS_PLUGIN_EXTERNAL (external));
+
+  if (G_UNLIKELY (image != NULL))
+    {
+      g_value_init (&value, G_TYPE_STRING);
+      g_value_set_string (&value, image);
+
+      panel_plugin_external_queue_add (external, FALSE,
+                                       SIGNAL_WRAPPER_BACKGROUND_IMAGE,
+                                       &value);
+
+      g_value_unset (&value);
+    }
+  else
+    {
+      /* unset the bg */
+      panel_plugin_external_set_background_color (external, NULL);
+    }
+}
diff --git a/panel/panel-plugin-external.h b/panel/panel-plugin-external.h
index 04c0a1b..7864ad7 100644
--- a/panel/panel-plugin-external.h
+++ b/panel/panel-plugin-external.h
@@ -45,6 +45,12 @@ GtkWidget *panel_plugin_external_new                  (PanelModule          *mod
 void       panel_plugin_external_set_background_alpha (PanelPluginExternal  *external,
                                                        gdouble               alpha);
 
+void       panel_plugin_external_set_background_color (PanelPluginExternal  *external,
+                                                       const GdkColor       *color);
+
+void       panel_plugin_external_set_background_image (PanelPluginExternal  *external,
+                                                       const gchar          *image);
+
 G_END_DECLS
 
 #endif /* !__PANEL_PLUGIN_EXTERNAL_H__ */
diff --git a/panel/panel-preferences-dialog.c b/panel/panel-preferences-dialog.c
index aca1304..1e80f49 100644
--- a/panel/panel-preferences-dialog.c
+++ b/panel/panel-preferences-dialog.c
@@ -53,6 +53,10 @@ static void panel_preferences_dialog_bindings_update (PanelPreferencesDialog *di
 
 static void panel_preferences_dialog_output_changed (GtkComboBox *combobox, PanelPreferencesDialog *dialog);
 
+static void panel_preferences_dialog_bg_style_changed (PanelPreferencesDialog *dialog);
+static void panel_preferences_dialog_bg_image_file_set (GtkFileChooserButton *button, PanelPreferencesDialog *dialog);
+static void panel_preferences_dialog_bg_image_notified (PanelPreferencesDialog *dialog);
+
 static void panel_preferences_dialog_panel_combobox_changed (GtkComboBox *combobox, PanelPreferencesDialog *dialog);
 static void panel_preferences_dialog_panel_combobox_rebuild (PanelPreferencesDialog *dialog);
 static void panel_preferences_dialog_panel_add (GtkWidget *widget, PanelPreferencesDialog *dialog);
@@ -108,6 +112,9 @@ struct _PanelPreferencesDialog
   /* changed signal for the active panel's itembar */
   gulong            items_changed_handler_id;
 
+  /* background image watch */
+  gulong            bg_image_notify_handler_id;
+
   /* changed signal for the output selector */
   gulong            output_changed_handler_id;
 };
@@ -167,6 +174,22 @@ panel_preferences_dialog_init (PanelPreferencesDialog *dialog)
   connect_signal ("panel-remove", "clicked", panel_preferences_dialog_panel_remove);
   connect_signal ("panel-combobox", "changed", panel_preferences_dialog_panel_combobox_changed);
 
+  /* style tab */
+  object = gtk_builder_get_object (GTK_BUILDER (dialog), "background-style");
+  panel_return_if_fail (G_IS_OBJECT (object));
+  g_signal_connect_swapped (G_OBJECT (object), "changed",
+      G_CALLBACK (panel_preferences_dialog_bg_style_changed), dialog);
+
+  object = gtk_builder_get_object (GTK_BUILDER (dialog), "composited");
+  panel_return_if_fail (G_IS_OBJECT (object));
+  g_signal_connect_swapped (G_OBJECT (object), "notify::visible",
+      G_CALLBACK (panel_preferences_dialog_bg_style_changed), dialog);
+
+  object = gtk_builder_get_object (GTK_BUILDER (dialog), "background-image");
+  panel_return_if_fail (GTK_IS_FILE_CHOOSER_BUTTON (object));
+  g_signal_connect (G_OBJECT (object), "file-set",
+    G_CALLBACK (panel_preferences_dialog_bg_image_file_set), dialog);
+
   /* items treeview and buttons */
   connect_signal ("item-up", "clicked", panel_preferences_dialog_item_move);
   connect_signal ("item-down", "clicked", panel_preferences_dialog_item_move);
@@ -232,12 +255,24 @@ panel_preferences_dialog_finalize (GObject *object)
   PanelPreferencesDialog *dialog = PANEL_PREFERENCES_DIALOG (object);
   GtkWidget              *itembar;
 
-  /* disconnect changed signal */
-  if (dialog->active != NULL && dialog->items_changed_handler_id != 0)
+  /* free bindings list */
+  g_slist_free (dialog->bindings);
+
+  if (dialog->active != NULL)
     {
-      itembar = gtk_bin_get_child (GTK_BIN (dialog->active));
-      g_signal_handler_disconnect (G_OBJECT (itembar),
-          dialog->items_changed_handler_id);
+      if (dialog->items_changed_handler_id != 0)
+        {
+          /* disconnect changed signal */
+          itembar = gtk_bin_get_child (GTK_BIN (dialog->active));
+          g_signal_handler_disconnect (G_OBJECT (itembar),
+              dialog->items_changed_handler_id);
+        }
+
+      if (dialog->bg_image_notify_handler_id != 0)
+        {
+          g_signal_handler_disconnect (G_OBJECT (dialog->active),
+              dialog->bg_image_notify_handler_id);
+        }
     }
 
   /* deselect all windows */
@@ -278,7 +313,7 @@ panel_preferences_dialog_bindings_unbind (PanelPreferencesDialog *dialog)
 {
   GSList *li;
 
-  if (dialog->bindings)
+  if (dialog->bindings != NULL)
     {
       /* remove all bindings */
       for (li = dialog->bindings; li != NULL; li = li->next)
@@ -287,6 +322,18 @@ panel_preferences_dialog_bindings_unbind (PanelPreferencesDialog *dialog)
       g_slist_free (dialog->bindings);
       dialog->bindings = NULL;
     }
+
+  /* disconnect image watch */
+  if (dialog->bg_image_notify_handler_id != 0)
+    {
+      if (dialog->active != NULL)
+        {
+          g_signal_handler_disconnect (G_OBJECT (dialog->active),
+              dialog->bg_image_notify_handler_id);
+        }
+
+      dialog->bg_image_notify_handler_id = 0;
+    }
 }
 
 
@@ -346,6 +393,13 @@ panel_preferences_dialog_bindings_update (PanelPreferencesDialog *dialog)
   panel_preferences_dialog_bindings_add (dialog, "enter-opacity", "value");
   panel_preferences_dialog_bindings_add (dialog, "leave-opacity", "value");
   panel_preferences_dialog_bindings_add (dialog, "composited", "visible");
+  panel_preferences_dialog_bindings_add (dialog, "background-style", "active");
+  panel_preferences_dialog_bindings_add (dialog, "background-color", "color");
+
+  /* watch image changes from the panel */
+  dialog->bg_image_notify_handler_id = g_signal_connect_swapped (G_OBJECT (dialog->active),
+      "notify::background-image", G_CALLBACK (panel_preferences_dialog_bg_image_notified), dialog);
+  panel_preferences_dialog_bg_image_notified (dialog);
 
   /* get run mode of the driver (multiple screens or randr) */
   display = gtk_widget_get_display (GTK_WIDGET (dialog->active));
@@ -508,6 +562,84 @@ panel_preferences_dialog_output_changed (GtkComboBox            *combobox,
 
 
 static void
+panel_preferences_dialog_bg_style_changed (PanelPreferencesDialog *dialog)
+{
+  gint      active;
+  GObject  *object;
+  gboolean  composited;
+
+  panel_return_if_fail (PANEL_IS_PREFERENCES_DIALOG (dialog));
+  panel_return_if_fail (PANEL_WINDOW (dialog->active));
+
+  object = gtk_builder_get_object (GTK_BUILDER (dialog), "background-style");
+  panel_return_if_fail (GTK_IS_COMBO_BOX (object));
+  active = gtk_combo_box_get_active (GTK_COMBO_BOX (object));
+
+  object = gtk_builder_get_object (GTK_BUILDER (dialog), "bg-alpha-box");
+  panel_return_if_fail (GTK_IS_WIDGET (object));
+  g_object_get (G_OBJECT (dialog->active), "composited", &composited, NULL);
+  g_object_set (G_OBJECT (object), "visible", composited && active < 2, NULL);
+
+  object = gtk_builder_get_object (GTK_BUILDER (dialog), "bg-color-box");
+  panel_return_if_fail (GTK_IS_WIDGET (object));
+  g_object_set (G_OBJECT (object), "visible", active == 1, NULL);
+
+  object = gtk_builder_get_object (GTK_BUILDER (dialog), "bg-image-box");
+  panel_return_if_fail (GTK_IS_WIDGET (object));
+  g_object_set (G_OBJECT (object), "visible", active == 2, NULL);
+}
+
+
+
+static void
+panel_preferences_dialog_bg_image_file_set (GtkFileChooserButton   *button,
+                                            PanelPreferencesDialog *dialog)
+{
+  gchar *filename;
+
+  panel_return_if_fail (GTK_IS_FILE_CHOOSER_BUTTON (button));
+  panel_return_if_fail (PANEL_IS_PREFERENCES_DIALOG (dialog));
+  panel_return_if_fail (PANEL_IS_WINDOW (dialog->active));
+
+  g_signal_handler_block (G_OBJECT (dialog->active),
+      dialog->bg_image_notify_handler_id);
+
+  filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (button));
+  g_object_set (G_OBJECT (dialog->active), "background-image", filename, NULL);
+  g_free (filename);
+
+  g_signal_handler_unblock (G_OBJECT (dialog->active),
+      dialog->bg_image_notify_handler_id);
+}
+
+
+
+static void
+panel_preferences_dialog_bg_image_notified (PanelPreferencesDialog *dialog)
+{
+  gchar   *filename;
+  GObject *button;
+
+  panel_return_if_fail (PANEL_IS_PREFERENCES_DIALOG (dialog));
+  panel_return_if_fail (PANEL_IS_WINDOW (dialog->active));
+
+  button = gtk_builder_get_object (GTK_BUILDER (dialog), "background-image");
+  panel_return_if_fail (GTK_IS_FILE_CHOOSER_BUTTON (button));
+
+  g_signal_handlers_block_by_func (G_OBJECT (button),
+      G_CALLBACK (panel_preferences_dialog_bg_image_file_set), dialog);
+
+  g_object_get (G_OBJECT (dialog->active), "background-image", &filename, NULL);
+  gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (button), filename != NULL ? filename : "");
+  g_free (filename);
+
+  g_signal_handlers_unblock_by_func (G_OBJECT (button),
+      G_CALLBACK (panel_preferences_dialog_bg_image_file_set), dialog);
+}
+
+
+
+static void
 panel_preferences_dialog_panel_sensitive (PanelPreferencesDialog *dialog)
 {
 
diff --git a/panel/panel-preferences-dialog.glade b/panel/panel-preferences-dialog.glade
index eafa71a..9c8485b 100644
--- a/panel/panel-preferences-dialog.glade
+++ b/panel/panel-preferences-dialog.glade
@@ -31,6 +31,23 @@
       <column type="gchararray"/>
     </columns>
   </object>
+  <object class="GtkListStore" id="styles-store">
+    <columns>
+      <!-- column-name title -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">None (use system style)</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Solid color</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Background image</col>
+      </row>
+    </data>
+  </object>
   <object class="XfceTitledDialog" id="dialog">
     <property name="title" translatable="yes">Xfce Panel</property>
     <property name="window_position">center-on-parent</property>
@@ -349,11 +366,12 @@
                                 </child>
                                 <child>
                                   <object class="GtkCheckButton" id="length-adjust">
-                                    <property name="label" translatable="yes">Automatically increase the length</property>
+                                    <property name="label" translatable="yes">A_utomatically increase the length</property>
                                     <property name="visible">True</property>
                                     <property name="can_focus">True</property>
                                     <property name="receives_default">False</property>
                                     <property name="tooltip_text" translatable="yes">Select this option to automatically increase the length of the panel if the plugins request more space.</property>
+                                    <property name="use_underline">True</property>
                                     <property name="draw_indicator">True</property>
                                   </object>
                                   <packing>
@@ -394,7 +412,7 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkVBox" id="composited">
+                  <object class="GtkVBox" id="vbox7">
                     <property name="visible">True</property>
                     <property name="border_width">6</property>
                     <property name="orientation">vertical</property>
@@ -409,35 +427,151 @@
                             <property name="visible">True</property>
                             <property name="left_padding">12</property>
                             <child>
-                              <object class="GtkHBox" id="hbox2">
+                              <object class="GtkVBox" id="vbox4">
                                 <property name="visible">True</property>
                                 <property name="border_width">6</property>
-                                <property name="spacing">12</property>
+                                <property name="orientation">vertical</property>
+                                <property name="spacing">6</property>
                                 <child>
-                                  <object class="GtkLabel" id="label7">
+                                  <object class="GtkHBox" id="hbox2">
                                     <property name="visible">True</property>
-                                    <property name="label" translatable="yes" comments="I18N: label for the background alha slider">_Alpha:</property>
-                                    <property name="use_underline">True</property>
-                                    <property name="mnemonic_widget">alpha-scale</property>
+                                    <property name="spacing">12</property>
+                                    <child>
+                                      <object class="GtkLabel" id="label7">
+                                        <property name="visible">True</property>
+                                        <property name="xalign">0</property>
+                                        <property name="label" translatable="yes">_Style:</property>
+                                        <property name="use_underline">True</property>
+                                        <property name="mnemonic_widget">background-style</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="position">0</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkComboBox" id="background-style">
+                                        <property name="visible">True</property>
+                                        <property name="model">styles-store</property>
+                                        <child>
+                                          <object class="GtkCellRendererText" id="cellrenderertext4"/>
+                                          <attributes>
+                                            <attribute name="text">0</attribute>
+                                          </attributes>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
                                   </object>
                                   <packing>
-                                    <property name="expand">False</property>
                                     <property name="position">0</property>
                                   </packing>
                                 </child>
                                 <child>
-                                  <object class="GtkHScale" id="alpha-scale">
+                                  <object class="GtkHBox" id="bg-alpha-box">
                                     <property name="visible">True</property>
-                                    <property name="can_focus">True</property>
-                                    <property name="tooltip_text" translatable="yes">Alpha value of the panel background, between 0 (transparent) and 100 (opaque).</property>
-                                    <property name="adjustment">background-alpha</property>
-                                    <property name="digits">0</property>
-                                    <property name="value_pos">right</property>
+                                    <property name="spacing">12</property>
+                                    <child>
+                                      <object class="GtkLabel" id="label15">
+                                        <property name="visible">True</property>
+                                        <property name="xalign">0</property>
+                                        <property name="label" translatable="yes">_Alpha:</property>
+                                        <property name="use_underline">True</property>
+                                        <property name="mnemonic_widget">bg-alpha-scale</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="position">0</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkHScale" id="bg-alpha-scale">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="tooltip_text" translatable="yes">Alpha value of the panel background, between 0 (transparent) and 100 (opaq
+ue).</property>
+                                        <property name="adjustment">background-alpha</property>
+                                        <property name="digits">0</property>
+                                        <property name="value_pos">right</property>
+                                      </object>
+                                      <packing>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
                                   </object>
                                   <packing>
                                     <property name="position">1</property>
                                   </packing>
                                 </child>
+                                <child>
+                                  <object class="GtkHBox" id="bg-color-box">
+                                    <property name="visible">True</property>
+                                    <property name="spacing">12</property>
+                                    <child>
+                                      <object class="GtkLabel" id="label16">
+                                        <property name="visible">True</property>
+                                        <property name="xalign">0</property>
+                                        <property name="label" translatable="yes">C_olor:</property>
+                                        <property name="use_underline">True</property>
+                                        <property name="mnemonic_widget">background-color</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="position">0</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkColorButton" id="background-color">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="receives_default">True</property>
+                                        <property name="title" translatable="yes">Pick a Panel Color</property>
+                                        <property name="color">#000000000000</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkHBox" id="bg-image-box">
+                                    <property name="visible">True</property>
+                                    <property name="spacing">12</property>
+                                    <child>
+                                      <object class="GtkLabel" id="label19">
+                                        <property name="visible">True</property>
+                                        <property name="xalign">0</property>
+                                        <property name="label" translatable="yes">_File:</property>
+                                        <property name="use_underline">True</property>
+                                        <property name="mnemonic_widget">background-image</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="position">0</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkFileChooserButton" id="background-image">
+                                        <property name="visible">True</property>
+                                        <property name="title" translatable="yes">Select A Background Image</property>
+                                      </object>
+                                      <packing>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="position">3</property>
+                                  </packing>
+                                </child>
                               </object>
                             </child>
                           </object>
@@ -458,14 +592,13 @@
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkFrame" id="frame4">
+                      <object class="GtkFrame" id="composited">
                         <property name="visible">True</property>
                         <property name="label_xalign">0</property>
                         <property name="shadow_type">none</property>
                         <child>
                           <object class="GtkAlignment" id="alignment4">
                             <property name="visible">True</property>
-                            <property name="bottom_padding">6</property>
                             <property name="left_padding">12</property>
                             <child>
                               <object class="GtkTable" id="table2">
@@ -558,7 +691,7 @@
                 <child type="tab">
                   <object class="GtkLabel" id="label12">
                     <property name="visible">True</property>
-                    <property name="label" translatable="yes">C_ompositing</property>
+                    <property name="label" translatable="yes">Appeara_nce</property>
                     <property name="use_underline">True</property>
                   </object>
                   <packing>
@@ -822,17 +955,18 @@
     <property name="step_increment">1</property>
     <property name="page_increment">10</property>
   </object>
-  <object class="GtkSizeGroup" id="composing-sizegroup">
+  <object class="GtkSizeGroup" id="display-sizegroup">
     <widgets>
-      <widget name="label7"/>
-      <widget name="label9"/>
-      <widget name="label10"/>
+      <widget name="label13"/>
+      <widget name="label1"/>
     </widgets>
   </object>
-  <object class="GtkSizeGroup" id="display-sizegroup">
+  <object class="GtkSizeGroup" id="bg-sizegroup">
     <widgets>
-      <widget name="label1"/>
-      <widget name="label13"/>
+      <widget name="label7"/>
+      <widget name="label15"/>
+      <widget name="label16"/>
+      <widget name="label19"/>
     </widgets>
   </object>
 </interface>
diff --git a/panel/panel-window.c b/panel/panel-window.c
index 3d3dcb8..c13e340 100644
--- a/panel/panel-window.c
+++ b/panel/panel-window.c
@@ -1972,7 +1972,8 @@ panel_window_set_autohide (PanelWindow *window,
   GtkWidget   *popup;
   guint        i;
   const gchar *properties[] = { "enter-opacity", "leave-opacity",
-                                "background-alpha", "borders" };
+                                "background-alpha", "borders",
+                                "background-style", "background-color" };
 
   panel_return_if_fail (PANEL_IS_WINDOW (window));
 
@@ -2326,20 +2327,41 @@ void
 panel_window_set_povider_info (PanelWindow *window,
                                GtkWidget   *provider)
 {
+  PanelBaseWindow *base_window = PANEL_BASE_WINDOW (window);
+
   panel_return_if_fail (PANEL_IS_WINDOW (window));
   panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (provider));
 
   xfce_panel_plugin_provider_set_locked (XFCE_PANEL_PLUGIN_PROVIDER (provider),
                                          panel_window_get_locked (window));
 
-  if (PANEL_BASE_WINDOW (window)->background_alpha < 1.0)
+  if (base_window->background_alpha < 1.0)
     {
       if (PANEL_IS_PLUGIN_EXTERNAL (provider))
         panel_plugin_external_set_background_alpha (PANEL_PLUGIN_EXTERNAL (provider),
-            PANEL_BASE_WINDOW (window)->background_alpha);
+            base_window->background_alpha);
       else if (PANEL_IS_PLUGIN_EXTERNAL_46 (provider))
         panel_plugin_external_46_set_background_alpha (PANEL_PLUGIN_EXTERNAL_46 (provider),
-            PANEL_BASE_WINDOW (window)->background_alpha);
+            base_window->background_alpha);
+    }
+
+  if (base_window->background_style == PANEL_BG_STYLE_COLOR)
+    {
+      if (PANEL_IS_PLUGIN_EXTERNAL (provider))
+        panel_plugin_external_set_background_color (PANEL_PLUGIN_EXTERNAL (provider),
+            base_window->background_color);
+      else if (PANEL_IS_PLUGIN_EXTERNAL_46 (provider))
+        panel_plugin_external_46_set_background_color (PANEL_PLUGIN_EXTERNAL_46 (provider),
+            base_window->background_color);
+    }
+  else if (base_window->background_style == PANEL_BG_STYLE_IMAGE)
+    {
+      if (PANEL_IS_PLUGIN_EXTERNAL (provider))
+        panel_plugin_external_set_background_image (PANEL_PLUGIN_EXTERNAL (provider),
+            base_window->background_image);
+      else if (PANEL_IS_PLUGIN_EXTERNAL_46 (provider))
+        panel_plugin_external_46_set_background_image (PANEL_PLUGIN_EXTERNAL_46 (provider),
+            base_window->background_image);
     }
 
   panel_window_set_plugin_orientation (provider, window);
diff --git a/wrapper/main.c b/wrapper/main.c
index 69e83d5..36a9ea8 100644
--- a/wrapper/main.c
+++ b/wrapper/main.c
@@ -90,11 +90,6 @@ wrapper_gproxy_set (DBusGProxy              *dbus_gproxy,
         xfce_panel_plugin_provider_set_screen_position (provider, g_value_get_uint (value));
       else if (strcmp (property, SIGNAL_SET_LOCKED) == 0)
         xfce_panel_plugin_provider_set_locked (provider, g_value_get_boolean (value));
-      else if (strcmp (property, SIGNAL_WRAPPER_BACKGROUND_ALPHA) == 0)
-        {
-          plug = g_object_get_qdata (G_OBJECT (provider), plug_quark);
-          wrapper_plug_set_background_alpha (plug, g_value_get_double (value));
-        }
       else if (strcmp (property, SIGNAL_SAVE) == 0)
         xfce_panel_plugin_provider_save (provider);
       else if (strcmp (property, SIGNAL_SHOW_CONFIGURE) == 0)
@@ -108,7 +103,20 @@ wrapper_gproxy_set (DBusGProxy              *dbus_gproxy,
       else if (strcmp (property, SIGNAL_WRAPPER_QUIT) == 0)
         gtk_main_quit ();
       else
-        panel_assert_not_reached ();
+        {
+          plug = g_object_get_qdata (G_OBJECT (provider), plug_quark);
+
+          if (strcmp (property, SIGNAL_WRAPPER_BACKGROUND_ALPHA) == 0)
+            wrapper_plug_set_background_alpha (plug, g_value_get_double (value));
+          else if (strcmp (property, SIGNAL_WRAPPER_BACKGROUND_COLOR) == 0)
+            wrapper_plug_set_background_color (plug, g_value_get_string (value));
+          else if (strcmp (property, SIGNAL_WRAPPER_BACKGROUND_IMAGE) == 0)
+            wrapper_plug_set_background_image (plug, g_value_get_string (value));
+          else if (strcmp (property, SIGNAL_WRAPPER_BACKGROUND_UNSET) == 0)
+            wrapper_plug_set_background_color (plug, NULL);
+          else
+            panel_assert_not_reached ();
+        }
 
       g_free (property);
       g_value_unset (value);
diff --git a/wrapper/wrapper-plug.c b/wrapper/wrapper-plug.c
index fcefe9c..cdeb124 100644
--- a/wrapper/wrapper-plug.c
+++ b/wrapper/wrapper-plug.c
@@ -29,8 +29,10 @@
 
 
 
-static gboolean wrapper_plug_expose_event (GtkWidget      *widget,
-                                           GdkEventExpose *event);
+static void     wrapper_plug_finalize         (GObject        *object);
+static gboolean wrapper_plug_expose_event     (GtkWidget      *widget,
+                                               GdkEventExpose *event);
+static void     wrapper_plug_background_reset (WrapperPlug    *plug);
 
 
 
@@ -43,11 +45,14 @@ struct _WrapperPlug
 {
   GtkPlug __parent__;
 
-  /* background alpha */
-  gdouble background_alpha;
-
   /* whether the wrapper has a rgba colormap */
-  guint   is_composited : 1;
+  guint            is_composited : 1;
+
+  /* background information */
+  gdouble          background_alpha;
+  GdkColor        *background_color;
+  gchar           *background_image;
+  cairo_pattern_t *background_image_cache;
 };
 
 
@@ -64,8 +69,12 @@ G_DEFINE_TYPE (WrapperPlug, wrapper_plug, GTK_TYPE_PLUG)
 static void
 wrapper_plug_class_init (WrapperPlugClass *klass)
 {
+  GObjectClass   *gobject_class;
   GtkWidgetClass *gtkwidget_class;
 
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = wrapper_plug_finalize;
+
   gtkwidget_class = GTK_WIDGET_CLASS (klass);
   gtkwidget_class->expose_event = wrapper_plug_expose_event;
 }
@@ -79,6 +88,9 @@ wrapper_plug_init (WrapperPlug *plug)
   GdkScreen   *screen;
 
   plug->background_alpha = 1.00;
+  plug->background_color = NULL;
+  plug->background_image = NULL;
+  plug->background_image_cache = NULL;
 
   gtk_widget_set_name (GTK_WIDGET (plug), "XfcePanelWindowWrapper");
 
@@ -110,43 +122,113 @@ wrapper_plug_init (WrapperPlug *plug)
 
 
 
+static void
+wrapper_plug_finalize (GObject *object)
+{
+  wrapper_plug_background_reset (WRAPPER_PLUG (object));
+
+  G_OBJECT_CLASS (wrapper_plug_parent_class)->finalize (object);
+}
+
+
+
 static gboolean
 wrapper_plug_expose_event (GtkWidget      *widget,
                            GdkEventExpose *event)
 {
-  WrapperPlug   *plug = WRAPPER_PLUG (widget);
-  cairo_t       *cr;
-  GdkColor      *color;
-  GtkStateType   state = GTK_STATE_NORMAL;
-  gdouble        alpha = plug->is_composited ? plug->background_alpha : 1.00;
-
-  if (GTK_WIDGET_DRAWABLE (widget) && alpha < 1.00)
+  WrapperPlug    *plug = WRAPPER_PLUG (widget);
+  cairo_t        *cr;
+  const GdkColor *color;
+  gdouble         alpha;
+  GdkPixbuf      *pixbuf;
+  GError         *error = NULL;
+
+  if (GTK_WIDGET_DRAWABLE (widget))
     {
-      /* create the cairo context */
-      cr = gdk_cairo_create (widget->window);
+      if (G_UNLIKELY (plug->background_image != NULL))
+        {
+          cr = gdk_cairo_create (widget->window);
+          cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+          gdk_cairo_rectangle (cr, &event->area);
+          cairo_clip (cr);
+
+          if (G_LIKELY (plug->background_image_cache != NULL))
+            {
+              cairo_set_source (cr, plug->background_image_cache);
+              cairo_paint (cr);
+            }
+          else
+            {
+              /* load the image in a pixbuf */
+              pixbuf = gdk_pixbuf_new_from_file (plug->background_image, &error);
+
+              if (G_LIKELY (pixbuf != NULL))
+                {
+                  gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+                  g_object_unref (G_OBJECT (pixbuf));
+
+                  plug->background_image_cache = cairo_get_source (cr);
+                  cairo_pattern_reference (plug->background_image_cache);
+                  cairo_pattern_set_extend (plug->background_image_cache, CAIRO_EXTEND_REPEAT);
+                  cairo_paint (cr);
+                }
+              else
+                {
+                  /* print error message */
+                  g_warning ("Background image disabled, \"%s\" could not be loaded: %s",
+                             plug->background_image, error != NULL ? error->message : "No error");
+                  g_error_free (error);
+
+                  /* disable background image */
+                  wrapper_plug_background_reset (plug);
+                }
+            }
+
+          cairo_destroy (cr);
+        }
+      else
+        {
+          alpha = plug->is_composited ? plug->background_alpha : 1.00;
+
+          if (alpha < 1.00 || plug->background_color != NULL)
+            {
+              /* get the background gdk color */
+              if (plug->background_color != NULL)
+                color = plug->background_color;
+              else
+                color = &(widget->style->bg[GTK_STATE_NORMAL]);
+
+              /* draw the background color */
+              cr = gdk_cairo_create (widget->window);
+              cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+              cairo_set_source_rgba (cr, PANEL_GDKCOLOR_TO_DOUBLE (color), alpha);
+              gdk_cairo_rectangle (cr, &event->area);
+              cairo_fill (cr);
+              cairo_destroy (cr);
+            }
+        }
+    }
 
-      /* get the background gdk color */
-      color = &(widget->style->bg[state]);
+  return GTK_WIDGET_CLASS (wrapper_plug_parent_class)->expose_event (widget, event);
+}
 
-      /* set the cairo source color */
-      cairo_set_source_rgba (cr, PANEL_GDKCOLOR_TO_DOUBLE (color),
-                             plug->background_alpha);
 
-      /* create retangle */
-      cairo_rectangle (cr, event->area.x, event->area.y,
-                       event->area.width, event->area.height);
 
-      /* draw on source */
-      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+static void
+wrapper_plug_background_reset (WrapperPlug *plug)
+{
+  panel_return_if_fail (WRAPPER_IS_PLUG (plug));
 
-      /* paint rectangle */
-      cairo_fill (cr);
+  if (plug->background_color != NULL)
+    gdk_color_free (plug->background_color);
+  plug->background_color = NULL;
 
-      /* destroy cairo context */
-      cairo_destroy (cr);
-    }
+  if (plug->background_image_cache != NULL)
+    cairo_pattern_destroy (plug->background_image_cache);
+  plug->background_image_cache = NULL;
 
-  return GTK_WIDGET_CLASS (wrapper_plug_parent_class)->expose_event (widget, event);
+  g_free (plug->background_image);
+  plug->background_image = NULL;
 }
 
 
@@ -181,3 +263,38 @@ wrapper_plug_set_background_alpha (WrapperPlug *plug,
   if (plug->is_composited)
     gtk_widget_queue_draw (GTK_WIDGET (plug));
 }
+
+
+
+
+void
+wrapper_plug_set_background_color (WrapperPlug *plug,
+                                   const gchar *color_string)
+{
+  GdkColor color = { 0, };
+
+  panel_return_if_fail (WRAPPER_IS_PLUG (plug));
+
+  wrapper_plug_background_reset (plug);
+
+  if (color_string != NULL
+      && gdk_color_parse (color_string, &color))
+    plug->background_color = gdk_color_copy (&color);
+
+  gtk_widget_queue_draw (GTK_WIDGET (plug));
+}
+
+
+
+void
+wrapper_plug_set_background_image (WrapperPlug *plug,
+                                   const gchar *image)
+{
+  panel_return_if_fail (WRAPPER_IS_PLUG (plug));
+
+  wrapper_plug_background_reset (plug);
+
+  plug->background_image = g_strdup (image);
+
+  gtk_widget_queue_draw (GTK_WIDGET (plug));
+}
diff --git a/wrapper/wrapper-plug.h b/wrapper/wrapper-plug.h
index 5a089af..ab0d3f5 100644
--- a/wrapper/wrapper-plug.h
+++ b/wrapper/wrapper-plug.h
@@ -44,6 +44,12 @@ WrapperPlug  *wrapper_plug_new                  (GdkNativeWindow  socket_id);
 void          wrapper_plug_set_background_alpha (WrapperPlug     *plug,
                                                  gdouble          alpha);
 
+void          wrapper_plug_set_background_color (WrapperPlug     *plug,
+                                                 const gchar     *color_string);
+
+void          wrapper_plug_set_background_image (WrapperPlug     *plug,
+                                                 const gchar     *image);
+
 G_END_DECLS
 
 #endif /* !__WRAPPER_PLUG_H__ */



More information about the Xfce4-commits mailing list