Index: applets/notification_area/na-tray-child.h
===================================================================
--- applets/notification_area/na-tray-child.h	(revision 0)
+++ applets/notification_area/na-tray-child.h	(revision 0)
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* na-tray-child.h
+ * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
+ * Copyright (C) 2003-2006 Vincent Untz
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __NA_TRAY_CHILD_H__
+#define __NA_TRAY_CHILD_H__
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+G_BEGIN_DECLS
+
+#define NA_TYPE_TRAY_CHILD			(na_tray_child_get_type ())
+#define NA_TRAY_CHILD(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), NA_TYPE_TRAY_CHILD, NaTrayChild))
+#define NA_TRAY_CHILD_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST ((klass), NA_TYPE_TRAY_CHILD, NaTrayChildClass))
+#define NA_IS_TRAY_CHILD(obj)			(G_TYPE_CHECK_INSTANCE_TYPE ((obj), NA_TYPE_TRAY_CHILD))
+#define NA_IS_TRAY_CHILD_CLASS(klass)		(G_TYPE_CHECK_CLASS_TYPE ((klass), NA_TYPE_TRAY_CHILD))
+#define NA_TRAY_CHILD_GET_CLASS(obj)		(G_TYPE_INSTANCE_GET_CLASS ((obj), NA_TYPE_TRAY_CHILD, NaTrayChildClass))
+
+typedef struct _NaTrayChild	    NaTrayChild;
+typedef struct _NaTrayChildClass  NaTrayChildClass;
+typedef struct _NaTrayChildChild  NaTrayChildChild;
+
+struct _NaTrayChild
+{
+  GtkSocket parent_instance;
+  Window icon_window;
+  guint is_composited : 1;
+  guint parent_relative_bg : 1;
+};
+
+struct _NaTrayChildClass
+{
+  GtkSocketClass parent_class;
+};
+
+GType           na_tray_child_get_type        (void);
+
+GtkWidget      *na_tray_child_new           (GdkScreen   *screen,
+					     Window       icon_window);
+char           *na_tray_child_get_title     (NaTrayChild *child);
+gboolean        na_tray_child_is_composited (NaTrayChild *child);
+void            na_tray_child_force_redraw  (NaTrayChild *child);
+
+G_END_DECLS
+
+#endif /* __NA_TRAY_CHILD_H__ */
Index: applets/notification_area/na-tray.c
===================================================================
--- applets/notification_area/na-tray.c	(revision 11291)
+++ applets/notification_area/na-tray.c	(working copy)
@@ -120,7 +120,6 @@
   gtk_box_pack_end (GTK_BOX (priv->box), icon, FALSE, FALSE, 0);
 
   gtk_widget_show (icon);
-  na_tray_force_redraw (tray);
 }
 
 static void
@@ -136,8 +135,6 @@
 
   g_assert (tray->priv->trays_screen == trays_screen);
 
-  na_tray_force_redraw (tray);
-
   g_hash_table_remove (trays_screen->icon_table, icon);
   /* this will also destroy the tip associated to this icon */
   g_hash_table_remove (trays_screen->tip_table, icon);
@@ -404,11 +401,41 @@
       gtk_widget_set_size_request (priv->box, -1, MIN_BOX_SIZE);
       break;
     }
+}
 
-  na_tray_force_redraw (tray);
+/* Children with alpha channels have been set to be composited by calling
+ * gdk_window_set_composited(). We need to paint these children ourselves.
+ */
+static void
+na_tray_expose_icon (GtkWidget *widget,
+		     gpointer   data)
+{
+  cairo_t *cr = data;
+
+  if (na_tray_child_is_composited (NA_TRAY_CHILD (widget)))
+    {
+      gdk_cairo_set_source_pixmap (cr, widget->window,
+				   widget->allocation.x,
+				   widget->allocation.y);
+      cairo_paint (cr);
+    }
 }
 
 static void
+na_tray_expose_box (GtkWidget      *box,
+		    GdkEventExpose *event)
+{
+  cairo_t *cr = gdk_cairo_create (box->window);
+
+  gdk_cairo_region (cr, event->region);
+  cairo_clip (cr);
+
+  gtk_container_foreach (GTK_CONTAINER (box), na_tray_expose_icon, cr);
+
+  cairo_destroy (cr);
+}
+
+static void
 na_tray_init (NaTray *tray)
 {
   NaTrayPrivate *priv;
@@ -423,6 +450,8 @@
   gtk_widget_show (priv->frame);
 
   priv->box = na_obox_new ();
+  g_signal_connect (priv->box, "expose-event",
+		    G_CALLBACK (na_tray_expose_box), tray);
   gtk_box_set_spacing (GTK_BOX (priv->box), ICON_SPACING);
   gtk_container_add (GTK_CONTAINER (priv->frame), priv->box);
   gtk_widget_show (priv->box);
@@ -663,10 +692,8 @@
 {
   NaTrayPrivate *priv = tray->priv;
 
-  priv->idle_redraw_id = 0;
-  gtk_widget_hide (priv->box);
-  gtk_widget_show (priv->box);
-
+  gtk_container_foreach (GTK_CONTAINER (priv->box), (GtkCallback)na_tray_child_force_redraw, tray);
+  
   return FALSE;
 }
 
@@ -676,8 +703,6 @@
   NaTrayPrivate *priv = tray->priv;
 
   /* Force the icons to redraw their backgrounds.
-   * gtk_widget_queue_draw() doesn't work across process boundaries,
-   * so we do this instead.
    */
   if (priv->idle_redraw_id == 0)
     priv->idle_redraw_id = g_idle_add ((GSourceFunc) idle_redraw_cb, tray);
Index: applets/notification_area/na-tray.h
===================================================================
--- applets/notification_area/na-tray.h	(revision 11291)
+++ applets/notification_area/na-tray.h	(working copy)
@@ -41,7 +41,6 @@
 typedef struct _NaTray		NaTray;
 typedef struct _NaTrayPrivate	NaTrayPrivate;
 typedef struct _NaTrayClass	NaTrayClass;
-typedef struct _NaTrayChild	NaTrayChild;
 
 struct _NaTray
 {
Index: applets/notification_area/na-tray-manager.c
===================================================================
--- applets/notification_area/na-tray-manager.c	(revision 11291)
+++ applets/notification_area/na-tray-manager.c	(working copy)
@@ -254,120 +254,58 @@
 na_tray_manager_plug_removed (GtkSocket       *socket,
 			      NaTrayManager   *manager)
 {
-  Window *window;
+  NaTrayChild *child = NA_TRAY_CHILD (socket);
 
-  window = g_object_get_data (G_OBJECT (socket), "na-tray-child-window");
+  g_hash_table_remove (manager->socket_table, GINT_TO_POINTER (child->icon_window));
+  g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, child);
 
-  g_hash_table_remove (manager->socket_table, GINT_TO_POINTER (*window));
-  g_object_set_data (G_OBJECT (socket), "na-tray-child-window",
-		     NULL);
-  
-  g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, socket);
-
   /* This destroys the socket. */
   return FALSE;
 }
 
 static void
-na_tray_manager_make_socket_transparent (GtkWidget *widget,
-                                         gpointer   user_data)
-{
-  if (GTK_WIDGET_NO_WINDOW (widget))
-    return;
-
-  gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
-}
-
-static gboolean
-na_tray_manager_socket_exposed (GtkWidget      *widget,
-                                GdkEventExpose *event,
-                                gpointer        user_data)
-{
-  gdk_window_clear_area (widget->window,
-                         event->area.x, event->area.y,
-                         event->area.width, event->area.height);
-  return FALSE;
-}
-
-static void
-na_tray_manager_socket_style_set (GtkWidget *widget,
-                                  GtkStyle  *previous_style,
-                                  gpointer   user_data)
-{
-  if (widget->window == NULL)
-    return;
-
-  na_tray_manager_make_socket_transparent (widget, user_data);
-}
-
-static void
 na_tray_manager_handle_dock_request (NaTrayManager       *manager,
 				     XClientMessageEvent *xevent)
 {
-  GtkWidget *socket;
-  Window *window;
-  GtkRequisition req;
+  Window icon_window = xevent->data.l[2];
+  GtkWidget *child;
 
-  if (g_hash_table_lookup (manager->socket_table, GINT_TO_POINTER (xevent->data.l[2])))
+  if (g_hash_table_lookup (manager->socket_table, GINT_TO_POINTER (icon_window)))
     {
       /* We already got this notification earlier, ignore this one */
       return;
     }
-  
-  socket = gtk_socket_new ();
 
-  gtk_widget_set_app_paintable (socket, TRUE);
-  //FIXME: need to find a theme where this (and expose event) is needed
-  gtk_widget_set_double_buffered (socket, FALSE);
-  g_signal_connect (socket, "realize",
-                    G_CALLBACK (na_tray_manager_make_socket_transparent), NULL);
-  g_signal_connect (socket, "expose_event",
-                    G_CALLBACK (na_tray_manager_socket_exposed), NULL);
-  g_signal_connect_after (socket, "style_set",
-                          G_CALLBACK (na_tray_manager_socket_style_set), NULL);
-  
-  /* We need to set the child window here
-   * so that the client can call _get functions
-   * in the signal handler
-   */
-  window = g_new (Window, 1);
-  *window = xevent->data.l[2];
-      
-  g_object_set_data_full (G_OBJECT (socket),
-			  "na-tray-child-window",
-			  window, g_free);
+  child = na_tray_child_new (manager->screen, icon_window);
+  if (child == NULL) /* already gone or other error */
+    return;
+
   g_signal_emit (manager, manager_signals[TRAY_ICON_ADDED], 0,
-		 socket);
+		 child);
 
-  /* Add the socket only if it's been attached */
-  if (GTK_IS_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (socket))))
+  /* If the child wasn't attached, then destroy it */
+
+  if (!GTK_IS_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (child))))
     {
-      g_signal_connect (socket, "plug_removed",
-			G_CALLBACK (na_tray_manager_plug_removed), manager);
-      
-      gtk_socket_add_id (GTK_SOCKET (socket), *window);
+      gtk_widget_destroy (child);
+      return;
+    }
 
-      g_hash_table_insert (manager->socket_table, GINT_TO_POINTER (*window), socket);
+  g_signal_connect (child, "plug_removed",
+		    G_CALLBACK (na_tray_manager_plug_removed), manager);
 
-      /*
-       * Make sure the icons have a meaningfull size ...
-       */ 
-      req.width = req.height = 1;
-      gtk_widget_size_request (socket, &req);
-      /*
-      if ((req.width < 16) || (req.height < 16))
-      {
-          gint nw = MAX (24, req.width);
-          gint nh = MAX (24, req.height);
-          g_warning (_("tray icon has requested a size of (%i x %i), resizing to (%i x %i)"), 
-                      req.width, req.height, nw, nh);
-          gtk_widget_set_size_request(icon, nw,  nh);
-      }
-      */
-      gtk_widget_show(socket);
+  gtk_socket_add_id (GTK_SOCKET (child), icon_window);
+
+  if (!GTK_SOCKET (child)->plug_window)
+    {
+      /* Embedding failed, we won't get a plug-removed signal */
+      g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, child);
+      gtk_widget_destroy (child);
+      return;
     }
-  else
-    gtk_widget_destroy (socket);
+
+  g_hash_table_insert (manager->socket_table, GINT_TO_POINTER (icon_window), child);
+  gtk_widget_show (child);
 }
 
 static void
@@ -662,8 +600,58 @@
 #endif
 }
 
+static void
+na_tray_manager_set_visual_property (NaTrayManager *manager)
+{
 #ifdef GDK_WINDOWING_X11
+  GdkDisplay *display;
+  Visual     *xvisual;
+  Atom        visual_atom;
+  gulong      data[1];
 
+  if (!manager->invisible || !manager->invisible->window)
+    return;
+
+  /* The visual property is a hint to the tray icons as to what visual they
+   * should use for their windows. If the X server has RGBA colormaps, then
+   * we tell the tray icons to use a RGBA colormap and we'll composite the
+   * icon onto its parents with real transparency. Otherwise, we just tell
+   * the icon to use our colormap, and we'll do some hacks with parent
+   * relative backgrounds to simulate transparency.
+   */
+
+  display = gtk_widget_get_display (manager->invisible);
+  visual_atom = gdk_x11_get_xatom_by_name_for_display (display,
+						       "_NET_SYSTEM_TRAY_VISUAL");
+
+  if (gdk_screen_get_rgba_visual (manager->screen) != NULL &&
+      gdk_display_supports_composite (display))
+    {
+      xvisual = GDK_VISUAL_XVISUAL (gdk_screen_get_rgba_visual (manager->screen));
+    }
+  else
+    {
+      /* We actually want the visual of the tray where the icons will
+       * be embedded. In almost all cases, this will be the same as the visual
+       * of the screen
+       */
+      GdkColormap *colormap = gdk_screen_get_default_colormap (manager->screen);
+      xvisual = GDK_VISUAL_XVISUAL (gdk_colormap_get_visual (colormap));
+    }
+
+  data[0] = XVisualIDFromVisual (xvisual);
+
+  XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+		   GDK_WINDOW_XWINDOW (manager->invisible->window),
+                   visual_atom,
+		   XA_VISUALID, 32,
+		   PropModeReplace,
+		   (guchar *) &data, 1);
+#endif
+}
+
+#ifdef GDK_WINDOWING_X11
+
 static gboolean
 na_tray_manager_manage_screen_x11 (NaTrayManager *manager,
 				   GdkScreen     *screen)
@@ -684,6 +672,9 @@
   if (na_tray_manager_check_running_screen_x11 (screen))
     return FALSE;
 #endif
+  
+  manager->screen = screen;
+
   display = gdk_screen_get_display (screen);
   xscreen = GDK_SCREEN_XSCREEN (screen);
   
@@ -698,7 +689,11 @@
   manager->selection_atom = gdk_atom_intern (selection_atom_name, FALSE);
   g_free (selection_atom_name);
 
+  manager->invisible = invisible;
+  g_object_ref (G_OBJECT (manager->invisible));
+
   na_tray_manager_set_orientation_property (manager);
+  na_tray_manager_set_visual_property (manager);
   
   timestamp = gdk_x11_get_server_time (invisible->window);
 
@@ -730,9 +725,6 @@
 		  RootWindowOfScreen (xscreen),
 		  False, StructureNotifyMask, (XEvent *)&xev);
 
-      manager->invisible = invisible;
-      g_object_ref (G_OBJECT (manager->invisible));
-      
       opcode_atom = gdk_atom_intern ("_NET_SYSTEM_TRAY_OPCODE", FALSE);
       manager->opcode_atom = gdk_x11_atom_to_xatom_for_display (display,
                                                                 opcode_atom);
@@ -763,6 +755,10 @@
   else
     {
       gtk_widget_destroy (invisible);
+      g_object_unref (invisible);
+      manager->invisible = NULL;
+
+      manager->screen = NULL;
  
       return FALSE;
     }
@@ -821,67 +817,6 @@
 #endif
 }
 
-char *
-na_tray_manager_get_child_title (NaTrayManager      *manager,
-				 NaTrayManagerChild *child)
-{
-  char *retval = NULL;
-#ifdef GDK_WINDOWING_X11
-  GdkDisplay *display;
-  Window *child_window;
-  Atom utf8_string, atom, type;
-  int result;
-  int format;
-  gulong nitems;
-  gulong bytes_after;
-  gchar *val;
-
-  g_return_val_if_fail (NA_IS_TRAY_MANAGER (manager), NULL);
-  g_return_val_if_fail (GTK_IS_SOCKET (child), NULL);
-  
-  display = gdk_screen_get_display (manager->screen);
-
-  child_window = g_object_get_data (G_OBJECT (child),
-				    "na-tray-child-window");
-
-  utf8_string = gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING");
-  atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME");
-
-  gdk_error_trap_push ();
-
-  result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
-			       *child_window,
-			       atom,
-			       0, G_MAXLONG,
-			       False, utf8_string,
-			       &type, &format, &nitems,
-			       &bytes_after, (guchar **)&val);
-  
-  if (gdk_error_trap_pop () || result != Success)
-    return NULL;
-
-  if (type != utf8_string ||
-      format != 8 ||
-      nitems == 0)
-    {
-      if (val)
-	XFree (val);
-      return NULL;
-    }
-
-  if (!g_utf8_validate (val, nitems, NULL))
-    {
-      XFree (val);
-      return NULL;
-    }
-
-  retval = g_strndup (val, nitems);
-
-  XFree (val);
-#endif
-  return retval;
-}
-
 void
 na_tray_manager_set_orientation (NaTrayManager  *manager,
 				 GtkOrientation  orientation)
Index: applets/notification_area/na-tray-manager.h
===================================================================
--- applets/notification_area/na-tray-manager.h	(revision 11291)
+++ applets/notification_area/na-tray-manager.h	(working copy)
@@ -29,6 +29,8 @@
 #include <gdk/gdkx.h>
 #endif
 
+#include "na-tray-child.h"
+
 G_BEGIN_DECLS
 
 #define NA_TYPE_TRAY_MANAGER			(na_tray_manager_get_type ())
@@ -40,7 +42,6 @@
 	
 typedef struct _NaTrayManager	    NaTrayManager;
 typedef struct _NaTrayManagerClass  NaTrayManagerClass;
-typedef struct _NaTrayManagerChild  NaTrayManagerChild;
 
 struct _NaTrayManager
 {
@@ -64,18 +65,18 @@
   GObjectClass parent_class;
 
   void (* tray_icon_added)   (NaTrayManager      *manager,
-			      NaTrayManagerChild *child);
+			      NaTrayChild        *child);
   void (* tray_icon_removed) (NaTrayManager      *manager,
-			      NaTrayManagerChild *child);
+			      NaTrayChild        *child);
 
   void (* message_sent)      (NaTrayManager      *manager,
-			      NaTrayManagerChild *child,
+			      NaTrayChild        *child,
 			      const gchar        *message,
 			      glong               id,
 			      glong               timeout);
   
   void (* message_cancelled) (NaTrayManager      *manager,
-			      NaTrayManagerChild *child,
+			      NaTrayChild        *child,
 			      glong               id);
 
   void (* lost_selection)    (NaTrayManager      *manager);
@@ -87,8 +88,6 @@
 NaTrayManager  *na_tray_manager_new             (void);
 gboolean        na_tray_manager_manage_screen   (NaTrayManager      *manager,
 						 GdkScreen          *screen);
-char           *na_tray_manager_get_child_title (NaTrayManager      *manager,
-						 NaTrayManagerChild *child);
 void            na_tray_manager_set_orientation (NaTrayManager      *manager,
 						 GtkOrientation      orientation);
 GtkOrientation  na_tray_manager_get_orientation (NaTrayManager      *manager);
Index: applets/notification_area/Makefile.am
===================================================================
--- applets/notification_area/Makefile.am	(revision 11291)
+++ applets/notification_area/Makefile.am	(working copy)
@@ -22,6 +22,8 @@
 	obox.h					\
 	na-tray.c				\
 	na-tray.h				\
+	na-tray-child.c				\
+	na-tray-child.h				\
 	na-tray-manager.c			\
 	na-tray-manager.h			\
 	na-marshal.c				\
@@ -94,6 +96,8 @@
 	na-marshal.h		\
 	na-tray.c		\
 	na-tray.h		\
+	na-tray-child.c		\
+	na-tray-child.h		\
 	na-tray-manager.c	\
 	na-tray-manager.h	\
 	obox.c			\
Index: applets/notification_area/na-tray-child.c
===================================================================
--- applets/notification_area/na-tray-child.c	(revision 0)
+++ applets/notification_area/na-tray-child.c	(revision 0)
@@ -0,0 +1,386 @@
+/* na-tray-child.c
+ * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
+ * Copyright (C) 2003-2006 Vincent Untz
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "na-tray-child.h"
+
+#include <glib/gi18n.h>
+#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
+
+G_DEFINE_TYPE (NaTrayChild, na_tray_child, GTK_TYPE_SOCKET)
+
+static void
+na_tray_child_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (na_tray_child_parent_class)->finalize (object);
+}
+
+static void
+na_tray_child_realize (GtkWidget *widget)
+{
+  NaTrayChild *child = NA_TRAY_CHILD (widget);
+  GdkVisual *visual = gtk_widget_get_visual (widget);
+  gboolean visual_has_alpha;
+
+  GTK_WIDGET_CLASS (na_tray_child_parent_class)->realize (widget);
+
+  /* We have alpha if the visual has something other than red, green, and blue */
+  visual_has_alpha = visual->red_prec + visual->blue_prec + visual->green_prec < visual->depth;
+
+  if (visual_has_alpha && gdk_display_supports_composite (gtk_widget_get_display (widget)))
+    {
+      /* We have real transparency with an ARGB visual and the Composite extension.
+       */
+
+      /* Set a transparent background */
+      GdkColor transparent = { 0, 0, 0, 0 }; /* only pixel=0 matters */
+      gdk_window_set_background(widget->window, &transparent);
+      gdk_window_set_composited (widget->window, TRUE);
+
+      child->is_composited = TRUE;
+      child->parent_relative_bg = FALSE;
+    }
+  else if (visual == gdk_window_get_visual (gdk_window_get_parent (widget->window)))
+    {
+      /* Otherwise, if the visual matches the visual of the parent window, we can
+       * use a parent-relative background and fake transparency.
+       */
+      gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
+
+      child->is_composited = FALSE;
+      child->parent_relative_bg = TRUE;
+    }
+  else
+    {
+      /* Nothing to do; the icon will sit on top of an ugly gray box */
+
+      child->is_composited = FALSE;
+      child->parent_relative_bg = FALSE;
+    }
+
+  gtk_widget_set_app_paintable (GTK_WIDGET (child),
+				child->parent_relative_bg || child->is_composited);
+
+  /* Double-buffering will interfere with the parent-relative-background fake
+   * transparency, since the double-buffer code doesn't know how to fill in the
+   * background of the double-buffer correctly.
+   */
+  gtk_widget_set_double_buffered (GTK_WIDGET (child), child->parent_relative_bg);
+}
+
+static void
+na_tray_child_style_set (GtkWidget *widget,
+			 GtkStyle  *previous_style)
+{
+  /* The default handler resets the background according to the new
+   * style.  We either use a transparent background or a parent-relative background
+   * and ignore the style background. So, just don't chain up.
+   */
+}
+
+#if 0
+/* This is adapted from code that was commented out in na-tray-manager.c; the code
+ * in na-tray-manager.c wouldn't have worked reliably, this will. So maybe it can
+ * be reenabled. On other hand, things seem to be working fine without it.
+ *
+ * If reenabling, you need to hook it up in na_tray_child_class_init().
+ */
+static void
+na_tray_child_size_request (GtkWidget      *widget,
+			    GtkRequisition *request)
+{
+  GTK_WIDGET_CLASS (na_tray_child_parent_class)->size_request (widget, request);
+
+  /*
+   * Make sure the icons have a meaningful size ..
+   */ 
+  if ((request->width < 16) || (request->height < 16))
+    {
+      gint nw = MAX (24, request->width);
+      gint nh = MAX (24, request->height);
+      g_warning (_("tray icon has requested a size of (%i x %i), resizing to (%i x %i)"), 
+		 req.width, req.height, nw, nh);
+      request->width = nw;
+      request->height = nh;
+    }
+}
+#endif
+
+static void
+na_tray_child_size_allocate (GtkWidget      *widget,
+			     GtkAllocation  *allocation)
+{
+  NaTrayChild *child = NA_TRAY_CHILD (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;
+
+  /* When we are allocating the widget while mapped we need special handling for
+   * both real and fake transparency.
+   *
+   *  Real transparency: we need to invalidate and trigger a redraw of the old
+   *   and new areas. (GDK really should handle this for us, but doesn't as of
+   *   GTK+-2.14)
+   *
+   * Fake transparency: if the widget moved, we need to force the contents to be
+   *   redrawn with the new offset for the parent-relative background.
+   */
+  if ((moved || resized) && GTK_WIDGET_MAPPED (widget))
+    {
+      if (na_tray_child_is_composited (child))
+	gdk_window_invalidate_rect (gdk_window_get_parent (widget->window),
+				    &widget->allocation, FALSE);
+    }
+
+  GTK_WIDGET_CLASS (na_tray_child_parent_class)->size_allocate (widget, allocation);
+
+  if ((moved || resized) && GTK_WIDGET_MAPPED (widget))
+    {
+      if (na_tray_child_is_composited (NA_TRAY_CHILD (widget)))
+	gdk_window_invalidate_rect (gdk_window_get_parent (widget->window),
+				    &widget->allocation, FALSE);
+      else if (moved && child->parent_relative_bg)
+	na_tray_child_force_redraw (child);
+    }
+}
+
+/* The plug window should completely occupy the area of the child, so we won't
+ * get an expose event. But in case we do (the plug unmaps itself, say), this
+ * expose handler draws with real or fake transparency.
+ */
+static gboolean
+na_tray_child_expose_event (GtkWidget      *widget,
+			    GdkEventExpose *event)
+{
+  NaTrayChild *child = NA_TRAY_CHILD (widget);
+
+  if (na_tray_child_is_composited (child))
+    {
+      /* Clear to transparent */
+      cairo_t *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 (child->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
+na_tray_child_init (NaTrayChild *child)
+{
+}
+
+static void
+na_tray_child_class_init (NaTrayChildClass *klass)
+{
+  GObjectClass *gobject_class;
+  GtkWidgetClass *widget_class;
+
+  gobject_class = (GObjectClass *)klass;
+  widget_class = (GtkWidgetClass *)klass;
+
+  gobject_class->finalize = na_tray_child_finalize;
+  widget_class->style_set = na_tray_child_style_set;
+  widget_class->realize = na_tray_child_realize;
+  widget_class->size_allocate = na_tray_child_size_allocate;
+  widget_class->expose_event = na_tray_child_expose_event;
+}
+
+GtkWidget *
+na_tray_child_new (GdkScreen *screen,
+		   Window     icon_window)
+{
+  XWindowAttributes window_attributes;
+  Display *xdisplay;
+  NaTrayChild *child;
+  GdkVisual *visual;
+  GdkColormap *colormap;
+  gboolean new_colormap;
+  int result;
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+  g_return_val_if_fail (icon_window != None, NULL);
+
+  xdisplay = GDK_SCREEN_XDISPLAY (screen);
+
+  /* We need to determine the visual of the window we are embedding and create
+   * the socket in the same visual.
+   */
+
+  gdk_error_trap_push ();
+  result = XGetWindowAttributes (xdisplay, icon_window,
+				 &window_attributes);
+  gdk_error_trap_pop ();
+
+  if (!result) /* Window already gone */
+    return NULL;
+
+  visual = gdk_x11_screen_lookup_visual (screen,
+					 window_attributes.visual->visualid);
+  if (!visual) /* Icon window is on another screen? */
+    return NULL;
+
+  new_colormap = FALSE;
+
+  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
+    {
+      colormap = gdk_colormap_new (visual, FALSE);
+      new_colormap = TRUE;
+    }
+
+  child = g_object_new (NA_TYPE_TRAY_CHILD, NULL);
+  child->icon_window = icon_window;
+
+  gtk_widget_set_colormap (GTK_WIDGET (child), colormap);
+
+  if (new_colormap)
+    g_object_unref (colormap);
+
+  return GTK_WIDGET (child);
+}
+
+char *
+na_tray_child_get_title (NaTrayChild *child)
+{
+  char *retval = NULL;
+  GdkDisplay *display;
+  Atom utf8_string, atom, type;
+  int result;
+  int format;
+  gulong nitems;
+  gulong bytes_after;
+  gchar *val;
+
+  g_return_val_if_fail (NA_IS_TRAY_CHILD (child), NULL);
+
+  display = gtk_widget_get_display (GTK_WIDGET (child));
+
+  utf8_string = gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING");
+  atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME");
+
+  gdk_error_trap_push ();
+
+  result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
+			       child->icon_window,
+			       atom,
+			       0, G_MAXLONG,
+			       False, utf8_string,
+			       &type, &format, &nitems,
+			       &bytes_after, (guchar **)&val);
+  
+  if (gdk_error_trap_pop () || result != Success)
+    return NULL;
+
+  if (type != utf8_string ||
+      format != 8 ||
+      nitems == 0)
+    {
+      if (val)
+	XFree (val);
+      return NULL;
+    }
+
+  if (!g_utf8_validate (val, nitems, NULL))
+    {
+      XFree (val);
+      return NULL;
+    }
+
+  retval = g_strndup (val, nitems);
+
+  XFree (val);
+
+  return retval;
+}
+
+gboolean
+na_tray_child_is_composited (NaTrayChild *child)
+{
+  g_return_val_if_fail (NA_IS_TRAY_CHILD (child), FALSE);
+
+  return child->is_composited;
+}
+
+/* If we are faking transparency with a window-relative background, force a
+ * redraw of the icon. This should be called if the background changes or if
+ * the child is shifed with respect to the background.
+ */
+void
+na_tray_child_force_redraw (NaTrayChild *child)
+{
+  GtkWidget *widget = GTK_WIDGET (child);
+
+  if (GTK_WIDGET_MAPPED (child) && child->parent_relative_bg)
+    {
+#if 1
+      /* Sending an ExposeEvent might cause redraw problems if the
+       * icon is expecting the server to clear-to-background before
+       * the redraw. It should be ok for GtkStatusIcon or EggTrayIcon.
+       */
+      Display *xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget));
+      XEvent xev;
+
+      xev.xexpose.type = Expose;
+      xev.xexpose.window = GDK_WINDOW_XWINDOW (GTK_SOCKET (child)->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 (gtk_widget_get_display (widget)),
+		  xev.xexpose.window,
+		  False, ExposureMask,
+		  &xev);
+      /* We have to sync to reliably catch errors from the XSendEvent(),
+       * since that is asynchronous.
+       */
+      XSync (xdisplay, False);
+      gdk_error_trap_pop ();
+#else
+      /* Hiding and showing is the safe way to do it, but can result in more
+       * flickering.
+       */
+      gdk_window_hide (widget->window);
+      gdk_window_show (widget->window);
+#endif
+    }
+}
