[Xfce4-commits] <xfce4-panel:devel> Support transparent status icon.

Nick Schermer nick at xfce.org
Tue Aug 11 20:32:24 CEST 2009


Updating branch refs/heads/devel
         to 4b2f1f87c598e6a73bb15e2369017df2592d0110 (commit)
       from 628471e74812a5b6c290977643eb81e54472b37e (commit)

commit 4b2f1f87c598e6a73bb15e2369017df2592d0110
Author: Nick Schermer <nick at xfce.org>
Date:   Fri May 22 21:21:57 2009 +0200

    Support transparent status icon.
    
    Use code from the Gnome panel to support transparent tray icon.

 plugins/systray/Makefile.am       |    4 +-
 plugins/systray/systray-box.c     |   49 +++++-
 plugins/systray/systray-manager.c |  136 +++------------
 plugins/systray/systray-manager.h |   24 ++--
 plugins/systray/systray-socket.c  |  355 +++++++++++++++++++++++++++++++++++++
 plugins/systray/systray-socket.h  |   53 ++++++
 plugins/systray/systray.c         |    6 +-
 7 files changed, 496 insertions(+), 131 deletions(-)

diff --git a/plugins/systray/Makefile.am b/plugins/systray/Makefile.am
index 4b3ac13..3d2eb60 100644
--- a/plugins/systray/Makefile.am
+++ b/plugins/systray/Makefile.am
@@ -24,7 +24,9 @@ libsystray_la_SOURCES = \
 	systray-box.c \
 	systray-box.h \
 	systray-manager.c \
-	systray-manager.h
+	systray-manager.h \
+	systray-socket.c \
+	systray-socket.h
 
 libsystray_la_CFLAGS = \
 	$(LIBX11_CFLAGS) \
diff --git a/plugins/systray/systray-box.c b/plugins/systray/systray-box.c
index e264e86..2cd3f3c 100644
--- a/plugins/systray/systray-box.c
+++ b/plugins/systray/systray-box.c
@@ -30,6 +30,7 @@
 #include <common/panel-private.h>
 
 #include "systray-box.h"
+#include "systray-socket.h"
 
 #define BUTTON_SIZE        (16)
 #define SPACING            (2)
@@ -44,6 +45,8 @@ static void     systray_box_size_request       (GtkWidget       *widget,
                                                 GtkRequisition  *requisition);
 static void     systray_box_size_allocate      (GtkWidget       *widget,
                                                 GtkAllocation   *allocation);
+static gboolean systray_box_expose_event       (GtkWidget       *widget,
+                                                GdkEventExpose  *event);
 static void     systray_box_add                (GtkContainer    *container,
                                                 GtkWidget       *child);
 static void     systray_box_remove             (GtkContainer    *container,
@@ -132,6 +135,7 @@ systray_box_class_init (SystrayBoxClass *klass)
   gtkwidget_class = GTK_WIDGET_CLASS (klass);
   gtkwidget_class->size_request = systray_box_size_request;
   gtkwidget_class->size_allocate = systray_box_size_allocate;
+  gtkwidget_class->expose_event = systray_box_expose_event;
 
   gtkcontainer_class = GTK_CONTAINER_CLASS (klass);
   gtkcontainer_class->add = systray_box_add;
@@ -432,7 +436,50 @@ systray_box_size_allocate (GtkWidget     *widget,
 
       /* allocate widget size */
       gtk_widget_size_allocate (child_info->widget, &child_allocation);
-  }
+    }
+}
+
+
+
+static gboolean
+systray_box_expose_event (GtkWidget      *widget,
+                          GdkEventExpose *event)
+{
+  SystrayBox      *box = XFCE_SYSTRAY_BOX (widget);
+  cairo_t         *cr;
+  SystrayBoxChild *child_info;
+  GSList          *li;
+  gboolean         result;
+
+  result = GTK_WIDGET_CLASS (systray_box_parent_class)->expose_event (widget, event);
+
+  if (gtk_widget_is_composited (widget))
+    {
+      cr = gdk_cairo_create (widget->window);
+      gdk_cairo_region (cr, event->region);
+      cairo_clip (cr);
+
+      for (li = box->childeren; li != NULL; li = li->next)
+        {
+          child_info = li->data;
+
+          /* skip invisible or not composited children */
+          if (child_info->invalid
+              || (child_info->auto_hide && !box->show_hidden)
+              || !systray_socket_is_composited (XFCE_SYSTRAY_SOCKET (child_info->widget)))
+            continue;
+
+          /* paint the child */
+          gdk_cairo_set_source_pixmap (cr, child_info->widget->window,
+				                               child_info->widget->allocation.x,
+				                               child_info->widget->allocation.y);
+          cairo_paint (cr);
+        }
+
+      cairo_destroy (cr);
+    }
+
+  return result;
 }
 
 
diff --git a/plugins/systray/systray-manager.c b/plugins/systray/systray-manager.c
index f7f29c3..c1de20c 100644
--- a/plugins/systray/systray-manager.c
+++ b/plugins/systray/systray-manager.c
@@ -40,6 +40,7 @@
 #include <libxfce4util/libxfce4util.h>
 
 #include "systray-manager.h"
+#include "systray-socket.h"
 #include "systray-marshal.h"
 
 
@@ -139,7 +140,6 @@ struct _SystrayMessage
 
 
 static guint  systray_manager_signals[LAST_SIGNAL];
-static GQuark xwindow_quark = 0;
 
 
 
@@ -202,9 +202,6 @@ systray_manager_class_init (SystrayManagerClass *klass)
                     0, NULL, NULL,
                     g_cclosure_marshal_VOID__VOID,
                     G_TYPE_NONE, 0);
-
-  /* initialize quark */
-  xwindow_quark = g_quark_from_static_string ("systray-manager-xwindow");
 }
 
 
@@ -656,7 +653,8 @@ static void
 systray_manager_handle_cancel_message (SystrayManager      *manager,
                                        XClientMessageEvent *xevent)
 {
-  GtkSocket *socket;
+  GtkSocket       *socket;
+  GdkNativeWindow  window = xevent->data.l[2];
 
   panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
 
@@ -666,12 +664,10 @@ systray_manager_handle_cancel_message (SystrayManager      *manager,
   /* try to find the window in the list of known tray icons */
   socket = g_hash_table_lookup (manager->sockets, GUINT_TO_POINTER (xevent->window));
 
-  if (G_LIKELY (socket))
-    {
-      /* emit the cancelled signal */
-      g_signal_emit (manager, systray_manager_signals[MESSAGE_CANCELLED], 0,
-                     socket, xevent->data.l[2]);
-    }
+  /* emit the cancelled signal */
+  if (G_LIKELY (socket != NULL))
+    g_signal_emit (manager, systray_manager_signals[MESSAGE_CANCELLED],
+                   0, socket, window);
 }
 
 
@@ -680,66 +676,23 @@ static void
 systray_manager_handle_dock_request (SystrayManager      *manager,
                                      XClientMessageEvent *xevent)
 {
-  GtkWidget         *socket;
-  Window            *xwindow;
-  XWindowAttributes  attr;
-  GdkVisual         *visual;
-  GdkColormap       *colormap;
-  gint               result;
-  GdkScreen         *screen;
-  GdkDisplay        *display;
-  gboolean           release_colormap = FALSE;
+  GtkWidget       *socket;
+  GdkScreen       *screen;
+  GdkNativeWindow  window = xevent->data.l[2];
 
   panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
   panel_return_if_fail (GTK_IS_INVISIBLE (manager->invisible));
 
-  /* check if we already have this notification */
-  if (g_hash_table_lookup (manager->sockets, GUINT_TO_POINTER (xevent->data.l[2])))
+  /* check if we already have this window */
+  if (g_hash_table_lookup (manager->sockets, GUINT_TO_POINTER (window)))
     return;
 
-  /* get the window attributes, leave if this fails */
-  display = gtk_widget_get_display (manager->invisible);
-  gdk_error_trap_push ();
-  result = XGetWindowAttributes (GDK_DISPLAY_XDISPLAY (display),
-                                 xevent->data.l[2], &attr);
-  if (gdk_error_trap_pop () != 0 || result == 0)
-    return;
-
-  /* get the windows visual */
+  /* create the socket */
   screen = gtk_widget_get_screen (manager->invisible);
-  visual = gdk_x11_screen_lookup_visual (screen, attr.visual->visualid);
-  if (visual == NULL)
+  socket = systray_socket_new (screen, window);
+  if (G_UNLIKELY (socket == NULL))
     return;
 
-  /* get the correct colormap */
-  if (visual == gdk_screen_get_rgb_visual (screen))
-    colormap = gdk_screen_get_rgb_colormap (screen);
-  else if (visual == gdk_screen_get_rgba_visual (screen))
-    colormap = gdk_screen_get_rgba_colormap (screen);
-  else if (visual == gdk_screen_get_system_visual (screen))
-    colormap = gdk_screen_get_system_colormap (screen);
-  else
-    {
-      /* create custom colormap */
-      colormap = gdk_colormap_new (visual, FALSE);
-      release_colormap = TRUE;
-    }
-
-  /* create a new socket */
-  socket = gtk_socket_new ();
-  gtk_widget_set_colormap (GTK_WIDGET (socket), colormap);
-
-  /* allocate and set the xwindow */
-  xwindow = g_new (Window, 1);
-  *xwindow = xevent->data.l[2];
-
-  /* release the custom colormap */
-  if (release_colormap)
-    g_object_unref (G_OBJECT (colormap));
-
-  /* connect the xwindow data to the socket */
-  g_object_set_qdata_full (G_OBJECT (socket), xwindow_quark, xwindow, g_free);
-
   /* add the icon to the tray */
   g_signal_emit (manager, systray_manager_signals[ICON_ADDED], 0, socket);
 
@@ -752,10 +705,10 @@ systray_manager_handle_dock_request (SystrayManager      *manager,
           G_CALLBACK (systray_manager_handle_undock_request), manager);
 
       /* register the xembed client window id for this socket */
-      gtk_socket_add_id (GTK_SOCKET (socket), *xwindow);
+      gtk_socket_add_id (GTK_SOCKET (socket), window);
 
       /* add the socket to the list of known sockets */
-      g_hash_table_insert (manager->sockets, GUINT_TO_POINTER (*xwindow), socket);
+      g_hash_table_insert (manager->sockets, GUINT_TO_POINTER (window), socket);
     }
   else
     {
@@ -773,8 +726,8 @@ static gboolean
 systray_manager_handle_undock_request (GtkSocket *socket,
                                        gpointer   user_data)
 {
-  SystrayManager *manager = XFCE_SYSTRAY_MANAGER (user_data);
-  Window         *xwindow;
+  SystrayManager  *manager = XFCE_SYSTRAY_MANAGER (user_data);
+  GdkNativeWindow *window;
 
   panel_return_val_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager), FALSE);
 
@@ -782,13 +735,10 @@ systray_manager_handle_undock_request (GtkSocket *socket,
   g_signal_emit (manager, systray_manager_signals[ICON_REMOVED], 0, socket);
 
   /* get the xwindow */
-  xwindow = g_object_get_qdata (G_OBJECT (socket), xwindow_quark);
+  window = systray_socket_get_window (XFCE_SYSTRAY_SOCKET (socket));
 
   /* remove the socket from the list */
-  g_hash_table_remove (manager->sockets, GUINT_TO_POINTER (*xwindow));
-
-  /* unset object data */
-  g_object_set_qdata (G_OBJECT (socket), xwindow_quark, NULL);
+  g_hash_table_remove (manager->sockets, GUINT_TO_POINTER (*window));
 
   /* destroy the socket */
   return FALSE;
@@ -881,50 +831,6 @@ systray_manager_set_orientation (SystrayManager *manager,
 
 
 
-gchar *
-systray_manager_get_application_name (GtkWidget *socket)
-{
-  gchar         *name = NULL;
-  GdkDisplay    *display;
-  gint           succeed;
-  XTextProperty  xprop;
-  Window        *xwindow;
-
-  /* get the xwindow */
-  xwindow = g_object_get_qdata (G_OBJECT (socket), xwindow_quark);
-
-  if (G_LIKELY (xwindow != NULL))
-    {
-      /* get the display of the socket */
-      display = gtk_widget_get_display (socket);
-
-      /* avoid exiting the application on X errors */
-      gdk_error_trap_push ();
-
-      /* try to get the wm name (this is more relaiable with qt applications) */
-      succeed = XGetWMName (GDK_DISPLAY_XDISPLAY (display), *xwindow, &xprop);
-
-      /* check if everything went fine */
-      if (G_LIKELY (gdk_error_trap_pop () == 0 && succeed >= Success))
-        {
-          /* check the xprop content */
-          if (G_LIKELY (xprop.value && xprop.nitems > 0))
-            {
-              /* get the lowercase name if it's utf-8 valid */
-              if (G_LIKELY (g_utf8_validate ((const gchar *) xprop.value, xprop.nitems, NULL)))
-                name = g_utf8_strdown ((const gchar *) xprop.value, xprop.nitems);
-
-              /* cleanup */
-              XFree (xprop.value);
-            }
-        }
-    }
-
-  return name;
-}
-
-
-
 /**
  * tray messages
  **/
diff --git a/plugins/systray/systray-manager.h b/plugins/systray/systray-manager.h
index 455761f..aaec6b2 100644
--- a/plugins/systray/systray-manager.h
+++ b/plugins/systray/systray-manager.h
@@ -47,26 +47,26 @@ enum
 
 
 
-GType                systray_manager_get_type               (void) G_GNUC_CONST;
+GType           systray_manager_get_type             (void) G_GNUC_CONST;
 
-void                 systray_manager_register_type          (GTypeModule     *type_module);
+void            systray_manager_register_type        (GTypeModule     *type_module);
 
-GQuark               systray_manager_error_quark            (void);
+GQuark          systray_manager_error_quark          (void);
 
-SystrayManager      *systray_manager_new                    (void) G_GNUC_MALLOC;
+SystrayManager *systray_manager_new                  (void) G_GNUC_MALLOC;
 
-gboolean             systray_manager_check_running          (GdkScreen       *screen);
+gboolean        systray_manager_check_running        (GdkScreen       *screen);
 
-gboolean             systray_manager_register               (SystrayManager  *manager,
-                                                             GdkScreen        *screen,
-                                                             GError          **error);
+gboolean        systray_manager_register             (SystrayManager  *manager,
+                                                      GdkScreen        *screen,
+                                                      GError          **error);
 
-void                 systray_manager_unregister             (SystrayManager  *manager);
+void            systray_manager_unregister           (SystrayManager  *manager);
 
-void                 systray_manager_set_orientation        (SystrayManager  *manager,
-                                                             GtkOrientation   orientation);
+void            systray_manager_set_orientation      (SystrayManager  *manager,
+                                                      GtkOrientation   orientation);
 
-gchar               *systray_manager_get_application_name   (GtkWidget        *socket) G_GNUC_MALLOC;
+gchar          *systray_manager_get_application_name (GtkWidget        *socket) G_GNUC_MALLOC;
 
 
 #endif /* !__SYSTRAY_MANAGER_H__ */
diff --git a/plugins/systray/systray-socket.c b/plugins/systray/systray-socket.c
new file mode 100644
index 0000000..d942fd0
--- /dev/null
+++ b/plugins/systray/systray-socket.c
@@ -0,0 +1,355 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2002      Anders Carlsson <andersca at gnu.org>
+ * Copyright (c) 2003-2006 Vincent Untz
+ * Copyright (c) 2008      Red Hat, Inc.
+ * Copyright (c) 2009      Nick Schermer <nick at xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+#include <libxfce4panel/libxfce4panel.h>
+#include "systray-socket.h"
+
+
+
+struct _SystraySocketClass
+{
+  GtkSocketClass __parent__;
+};
+
+struct _SystraySocket
+{
+  GtkSocket __parent__;
+
+  /* plug window */
+  GdkNativeWindow window;
+
+  guint           is_composited : 1;
+  guint           parent_relative_bg : 1;
+};
+
+
+
+static void     systray_socket_realize       (GtkWidget      *widget);
+static void     systray_socket_size_allocate (GtkWidget      *widget,
+                                              GtkAllocation  *allocation);
+static gboolean systray_socket_expose_event  (GtkWidget      *widget,
+                                              GdkEventExpose *event);
+static void     systray_socket_style_set     (GtkWidget      *widget,
+                                              GtkStyle       *previous_style);
+
+
+
+XFCE_PANEL_DEFINE_TYPE (SystraySocket, systray_socket, GTK_TYPE_SOCKET)
+
+
+
+static void
+systray_socket_class_init (SystraySocketClass *klass)
+{
+  GtkWidgetClass *gtkwidget_class;
+
+  gtkwidget_class = GTK_WIDGET_CLASS (klass);
+  gtkwidget_class->realize = systray_socket_realize;
+  gtkwidget_class->size_allocate = systray_socket_size_allocate;
+  gtkwidget_class->expose_event = systray_socket_expose_event;
+  gtkwidget_class->style_set = systray_socket_style_set;
+}
+
+
+
+static void
+systray_socket_init (SystraySocket *socket)
+{
+}
+
+
+
+static void
+systray_socket_realize (GtkWidget *widget)
+{
+  SystraySocket *socket = XFCE_SYSTRAY_SOCKET (widget);
+  GdkVisual     *visual;
+  GdkColor       transparent = { 0, 0, 0, 0 };
+
+  GTK_WIDGET_CLASS (systray_socket_parent_class)->realize (widget);
+
+  visual = gtk_widget_get_visual (widget);
+  if (visual->red_prec + visual->blue_prec + visual->green_prec < visual->depth
+      && gdk_display_supports_composite (gtk_widget_get_display (widget)))
+    {
+      gdk_window_set_background (widget->window, &transparent);
+      gdk_window_set_composited (widget->window, TRUE);
+
+      socket->is_composited = TRUE;
+      socket->parent_relative_bg = FALSE;
+    }
+  else if (visual == gdk_drawable_get_visual (
+               GDK_DRAWABLE (gdk_window_get_parent (widget->window))))
+    {
+      gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
+
+      socket->is_composited = FALSE;
+      socket->parent_relative_bg = TRUE;
+    }
+  else
+    {
+      socket->is_composited = FALSE;
+      socket->parent_relative_bg = FALSE;
+    }
+
+  gtk_widget_set_app_paintable (widget,
+      socket->parent_relative_bg || socket->is_composited);
+
+  gtk_widget_set_double_buffered (widget, socket->parent_relative_bg);
+}
+
+
+
+static void
+systray_socket_size_allocate (GtkWidget     *widget,
+                              GtkAllocation *allocation)
+{
+  SystraySocket *socket = XFCE_SYSTRAY_SOCKET (widget);
+  gboolean       moved = allocation->x != widget->allocation.x
+                         || allocation->y != widget->allocation.y;
+  gboolean       resized = allocation->width != widget->allocation.width
+                           ||allocation->height != widget->allocation.height;
+
+  if ((moved || resized) && GTK_WIDGET_MAPPED (widget))
+    {
+      if (socket->is_composited)
+        gdk_window_invalidate_rect (gdk_window_get_parent (widget->window),
+                                    &widget->allocation, FALSE);
+    }
+
+  GTK_WIDGET_CLASS (systray_socket_parent_class)->size_allocate (widget, allocation);
+
+  if ((moved || resized) && GTK_WIDGET_MAPPED (widget))
+    {
+      if (socket->is_composited)
+        gdk_window_invalidate_rect (gdk_window_get_parent (widget->window),
+                                    &widget->allocation, FALSE);
+      else if (moved && socket->parent_relative_bg)
+        systray_socket_force_redraw (socket);
+    }
+}
+
+
+static gboolean
+systray_socket_expose_event (GtkWidget      *widget,
+                             GdkEventExpose *event)
+{
+  SystraySocket *socket = XFCE_SYSTRAY_SOCKET (widget);
+  cairo_t       *cr;
+
+  if (socket->is_composited)
+    {
+      /* clear to transparent */
+      cr = gdk_cairo_create (widget->window);
+      cairo_set_source_rgba (cr, 0, 0, 0, 0);
+      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+      gdk_cairo_region (cr, event->region);
+      cairo_fill (cr);
+      cairo_destroy (cr);
+    }
+  else if (socket->parent_relative_bg)
+    {
+      /* clear to parent-relative pixmap */
+      gdk_window_clear_area (widget->window,
+                             event->area.x,
+			     event->area.y,
+                             event->area.width,
+			     event->area.height);
+    }
+
+  return FALSE;
+}
+
+
+
+static void
+systray_socket_style_set (GtkWidget *widget,
+                          GtkStyle  *previous_style)
+{
+}
+
+
+
+GtkWidget *
+systray_socket_new (GdkScreen       *screen,
+                    GdkNativeWindow  window)
+{
+  SystraySocket     *socket;
+  GdkDisplay        *display;
+  XWindowAttributes  attr;
+  gint               result;
+  GdkVisual         *visual;
+  GdkColormap       *colormap;
+  gboolean           release_colormap = FALSE;
+
+  panel_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+  /* get the window attributes */
+  display = gdk_screen_get_display (screen);
+  gdk_error_trap_push ();
+  result = XGetWindowAttributes (GDK_DISPLAY_XDISPLAY (display),
+                                 window, &attr);
+
+  /* leave on an error or is the window does not exist */
+  if (gdk_error_trap_pop () != 0 || result == 0)
+    return NULL;
+
+  /* get the windows visual */
+  visual = gdk_x11_screen_lookup_visual (screen, attr.visual->visualid);
+  if (G_UNLIKELY (visual == NULL))
+    return NULL;
+
+  /* get the correct colormap */
+  if (visual == gdk_screen_get_rgb_visual (screen))
+    colormap = gdk_screen_get_rgb_colormap (screen);
+  else if (visual == gdk_screen_get_rgba_visual (screen))
+    colormap = gdk_screen_get_rgba_colormap (screen);
+  else if (visual == gdk_screen_get_system_visual (screen))
+    colormap = gdk_screen_get_system_colormap (screen);
+  else
+    {
+      /* create custom colormap */
+      colormap = gdk_colormap_new (visual, FALSE);
+      release_colormap = TRUE;
+    }
+
+  /* create a new socket */
+  socket = g_object_new (XFCE_TYPE_SYSTRAY_SOCKET, NULL);
+  gtk_widget_set_colormap (GTK_WIDGET (socket), colormap);
+  socket->window = window;
+
+  /* release the custom colormap */
+  if (release_colormap)
+    g_object_unref (G_OBJECT (colormap));
+
+  return GTK_WIDGET (socket);
+}
+
+
+
+void
+systray_socket_force_redraw (SystraySocket *socket)
+{
+  GtkWidget  *widget = GTK_WIDGET (socket);
+  XEvent      xev;
+  GdkDisplay *display;
+
+  panel_return_if_fail (XFCE_IS_SYSTRAY_SOCKET (socket));
+
+  if (GTK_WIDGET_MAPPED (socket) && socket->parent_relative_bg)
+    {
+      display = gtk_widget_get_display (widget);
+
+      xev.xexpose.type = Expose;
+      xev.xexpose.window = GDK_WINDOW_XWINDOW (GTK_SOCKET (socket)->plug_window);
+      xev.xexpose.x = 0;
+      xev.xexpose.y = 0;
+      xev.xexpose.width = widget->allocation.width;
+      xev.xexpose.height = widget->allocation.height;
+      xev.xexpose.count = 0;
+
+      gdk_error_trap_push ();
+      XSendEvent (GDK_DISPLAY_XDISPLAY (display),
+                  xev.xexpose.window,
+                  False, ExposureMask,
+                  &xev);
+      /* We have to sync to reliably catch errors from the XSendEvent(),
+       * since that is asynchronous.
+       */
+      XSync (GDK_DISPLAY_XDISPLAY (display), False);
+      gdk_error_trap_pop ();
+    }
+}
+
+
+
+gboolean
+systray_socket_is_composited (SystraySocket *socket)
+{
+  panel_return_val_if_fail (XFCE_IS_SYSTRAY_SOCKET (socket), FALSE);
+
+  return socket->is_composited;
+}
+
+
+
+gchar *
+systray_socket_get_title  (SystraySocket *socket)
+{
+  gchar         *name = NULL;
+  GdkDisplay    *display;
+  gint           succeed;
+  XTextProperty  xprop;
+
+  panel_return_val_if_fail (XFCE_IS_SYSTRAY_SOCKET (socket), NULL);
+
+  /* get the display of the socket */
+  display = gtk_widget_get_display (GTK_WIDGET (socket));
+
+  /* avoid exiting the application on X errors */
+  gdk_error_trap_push ();
+
+  /* try to get the wm name (this is more relaiable with qt applications) */
+  succeed = XGetWMName (GDK_DISPLAY_XDISPLAY (display), socket->window, &xprop);
+
+  /* check if everything went fine */
+  if (G_LIKELY (gdk_error_trap_pop () == 0 && succeed >= Success))
+    {
+      /* check the xprop content */
+      if (G_LIKELY (xprop.value && xprop.nitems > 0))
+	{
+	  /* get the lowercase name if it's utf-8 valid */
+	  if (g_utf8_validate ((const gchar *) xprop.value, xprop.nitems, NULL))
+	    name = g_utf8_strdown ((const gchar *) xprop.value, xprop.nitems);
+
+	  /* cleanup */
+	  XFree (xprop.value);
+	}
+    }
+
+  return name;
+}
+
+
+
+GdkNativeWindow *
+systray_socket_get_window (SystraySocket *socket)
+{
+  panel_return_val_if_fail (XFCE_IS_SYSTRAY_SOCKET (socket), NULL);
+
+  return &socket->window;
+}
diff --git a/plugins/systray/systray-socket.h b/plugins/systray/systray-socket.h
new file mode 100644
index 0000000..942df6d
--- /dev/null
+++ b/plugins/systray/systray-socket.h
@@ -0,0 +1,53 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2002      Anders Carlsson <andersca at gnu.org>
+ * Copyright (c) 2003-2006 Vincent Untz
+ * Copyright (c) 2008      Red Hat, Inc.
+ * Copyright (c) 2009      Nick Schermer <nick at xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __SYSTRAY_SOCKET_H__
+#define __SYSTRAY_SOCKET_H__
+
+#include <gtk/gtk.h>
+
+typedef struct _SystraySocketClass SystraySocketClass;
+typedef struct _SystraySocket      SystraySocket;
+
+#define XFCE_TYPE_SYSTRAY_SOCKET            (systray_socket_get_type ())
+#define XFCE_SYSTRAY_SOCKET(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFCE_TYPE_SYSTRAY_SOCKET, SystraySocket))
+#define XFCE_SYSTRAY_SOCKET_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), XFCE_TYPE_SYSTRAY_SOCKET, SystraySocketClass))
+#define XFCE_IS_SYSTRAY_SOCKET(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XFCE_TYPE_SYSTRAY_SOCKET))
+#define XFCE_IS_SYSTRAY_SOCKET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFCE_TYPE_SYSTRAY_SOCKET))
+#define XFCE_SYSTRAY_SOCKET_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), XFCE_TYPE_SYSTRAY_SOCKET, SystraySocketClass))
+
+GType            systray_socket_get_type      (void) G_GNUC_CONST;
+
+void             systray_socket_register_type (GTypeModule     *type_module);
+
+GtkWidget       *systray_socket_new           (GdkScreen       *screen,
+                                               GdkNativeWindow  window) G_GNUC_MALLOC;
+
+void             systray_socket_force_redraw  (SystraySocket   *socket);
+
+gboolean         systray_socket_is_composited (SystraySocket   *socket);
+
+gchar           *systray_socket_get_title     (SystraySocket   *socket) G_GNUC_MALLOC;
+
+GdkNativeWindow *systray_socket_get_window    (SystraySocket   *socket);
+
+#endif /* !__SYSTRAY_SOCKET_H__ */
diff --git a/plugins/systray/systray.c b/plugins/systray/systray.c
index bdbac93..9774016 100644
--- a/plugins/systray/systray.c
+++ b/plugins/systray/systray.c
@@ -30,6 +30,7 @@
 
 #include "systray.h"
 #include "systray-box.h"
+#include "systray-socket.h"
 #include "systray-manager.h"
 #include "systray-dialog_glade.h"
 
@@ -102,7 +103,8 @@ enum
 /* define the plugin */
 XFCE_PANEL_DEFINE_PLUGIN (SystrayPlugin, systray_plugin,
     systray_box_register_type,
-    systray_manager_register_type)
+    systray_manager_register_type,
+    systray_socket_register_type)
 
 
 
@@ -512,7 +514,7 @@ systray_plugin_icon_added (SystrayManager *manager,
   panel_return_if_fail (GTK_IS_WIDGET (icon));
 
   /* get the application name */
-  name = systray_manager_get_application_name (icon);
+  name = systray_socket_get_title (XFCE_SYSTRAY_SOCKET (icon));
 
   /* add the icon to the widget */
   systray_box_add_with_name (XFCE_SYSTRAY_BOX (plugin->box), icon, name);



More information about the Xfce4-commits mailing list