changeset 14681:2c1781ea074c

[gaim-migrate @ 17433] Depluginize the docklet. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Thu, 05 Oct 2006 23:24:00 +0000
parents fa285d018c71
children 9b4268984921
files gtk/Makefile.am gtk/docklet-x11.c gtk/docklet.h gtk/eggtrayicon.c gtk/eggtrayicon.h gtk/gtkdocklet-win32.c gtk/gtkdocklet-x11.c gtk/gtkdocklet.c gtk/gtkdocklet.h gtk/gtkmain.c gtk/plugins/docklet/Makefile.am gtk/plugins/docklet/docklet-win32.c gtk/plugins/docklet/docklet-x11.c gtk/plugins/docklet/docklet.c gtk/plugins/docklet/docklet.h gtk/plugins/docklet/eggtrayicon.c gtk/plugins/docklet/eggtrayicon.h gtk/win32/MinimizeToTray.c gtk/win32/MinimizeToTray.h libgaim/util.c
diffstat 20 files changed, 2480 insertions(+), 2015 deletions(-) [+]
line wrap: on
line diff
--- a/gtk/Makefile.am	Wed Oct 04 20:31:44 2006 +0000
+++ b/gtk/Makefile.am	Thu Oct 05 23:24:00 2006 +0000
@@ -59,6 +59,7 @@
 bin_PROGRAMS = gaim
 
 gaim_SOURCES = \
+	eggtrayicon.c \
 	gaimcombobox.c \
 	gaimstock.c \
 	gtkaccount.c \
@@ -73,6 +74,8 @@
 	gtkdebug.c \
 	gtkdialogs.c \
 	gtkdnd-hints.c \
+	gtkdocklet.c \
+	gtkdocklet-x11.c \
 	gtkeventloop.c \
 	gtkexpander.c \
 	gtkft.c \
@@ -100,6 +103,7 @@
 	gtkwhiteboard.c
 
 gaim_headers = \
+	eggtrayicon.h \
 	gtkaccount.h \
 	gtkblist.h \
 	gtkcelllayout.h \
@@ -116,6 +120,7 @@
 	gtkdebug.h \
 	gtkdialogs.h \
 	gtkdnd-hints.h \
+	gtkdocklet.h \
 	gtkeventloop.h \
 	gtkexpander.h \
 	gtkft.h \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gtk/docklet-x11.c	Thu Oct 05 23:24:00 2006 +0000
@@ -0,0 +1,305 @@
+/*
+ * System tray icon (aka docklet) plugin for Gaim
+ *
+ * Copyright (C) 2002-3 Robert McQueen <robot101@debian.org>
+ * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com>
+ * Inspired by a similar plugin by:
+ *  John (J5) Palmieri <johnp@martianrock.com>
+ * 
+ * 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.
+ */
+
+#include "internal.h"
+#include "gtkgaim.h"
+#include "debug.h"
+#include "gaimstock.h"
+
+#include "gaim.h"
+#include "gtkdialogs.h"
+
+#include "eggtrayicon.h"
+#include "docklet.h"
+
+#define EMBED_TIMEOUT 5000
+
+/* globals */
+static EggTrayIcon *docklet = NULL;
+static GtkWidget *image = NULL;
+static GtkTooltips *tooltips = NULL;
+static GdkPixbuf *blank_icon = NULL;
+static int embed_timeout = 0;
+
+/* protos */
+static void docklet_x11_create(void);
+
+static gboolean
+docklet_x11_create_cb()
+{
+	docklet_x11_create();
+
+	return FALSE; /* for when we're called by the glib idle handler */
+}
+
+static void
+docklet_x11_embedded_cb(GtkWidget *widget, void *data)
+{
+	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "embedded\n");
+	
+	g_source_remove(embed_timeout);
+	embed_timeout = 0;
+	docklet_embedded();
+}
+
+static void
+docklet_x11_destroyed_cb(GtkWidget *widget, void *data)
+{
+	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "destroyed\n");
+
+	docklet_remove();
+
+	g_object_unref(G_OBJECT(docklet));
+	docklet = NULL;
+
+	g_idle_add(docklet_x11_create_cb, &handle);
+}
+
+static void
+docklet_x11_clicked_cb(GtkWidget *button, GdkEventButton *event, void *data)
+{
+	if (event->type != GDK_BUTTON_PRESS)
+		return;
+
+	docklet_clicked(event->button);
+}
+
+static void
+docklet_x11_update_icon(DockletStatus icon)
+{
+	const gchar *icon_name = NULL;
+
+	g_return_if_fail(image != NULL);
+
+	switch (icon) {
+		case DOCKLET_STATUS_OFFLINE:
+			icon_name = GAIM_STOCK_ICON_OFFLINE;
+			break;
+		case DOCKLET_STATUS_CONNECTING:
+			icon_name = GAIM_STOCK_ICON_CONNECT;
+			break;
+		case DOCKLET_STATUS_ONLINE:
+			icon_name = GAIM_STOCK_ICON_ONLINE;
+			break;
+		case DOCKLET_STATUS_ONLINE_PENDING:
+			icon_name = GAIM_STOCK_ICON_ONLINE_MSG;
+			break;
+		case DOCKLET_STATUS_AWAY:
+			icon_name = GAIM_STOCK_ICON_AWAY;
+			break;
+		case DOCKLET_STATUS_AWAY_PENDING:
+			icon_name = GAIM_STOCK_ICON_AWAY_MSG;
+			break;
+	}
+
+	if(icon_name)
+		gtk_image_set_from_stock(GTK_IMAGE(image), icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR);
+
+#if 0
+	GdkPixbuf *p;
+	GdkBitmap *mask = NULL;
+
+	p = gtk_widget_render_icon(GTK_WIDGET(image), icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
+
+	if (p && (gdk_pixbuf_get_colorspace(p) == GDK_COLORSPACE_RGB) && (gdk_pixbuf_get_bits_per_sample(p) == 8)
+	   && (gdk_pixbuf_get_has_alpha(p)) && (gdk_pixbuf_get_n_channels(p) == 4)) {
+		int len = gdk_pixbuf_get_width(p) * gdk_pixbuf_get_height(p);
+		guchar *data = gdk_pixbuf_get_pixels(p);
+		guchar *bitmap = g_malloc((len / 8) + 1);
+		int i;
+
+		for (i = 0; i < len; i++)
+			if (data[i*4 + 3] > 55)
+				bitmap[i/8] |= 1 << i % 8;
+			else
+				bitmap[i/8] &= ~(1 << i % 8);
+
+		mask = gdk_bitmap_create_from_data(GDK_DRAWABLE(GTK_WIDGET(image)->window), bitmap, gdk_pixbuf_get_width(p), gdk_pixbuf_get_height(p));
+		g_free(bitmap);
+	}
+
+	if (mask)
+		gdk_window_shape_combine_mask(image->window, mask, 0, 0);
+
+	g_object_unref(G_OBJECT(p));
+#endif
+}
+
+static void
+docklet_x11_blank_icon()
+{
+	if (!blank_icon) {
+		gint width, height;
+
+		gtk_icon_size_lookup(GTK_ICON_SIZE_LARGE_TOOLBAR, &width, &height);
+		blank_icon = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
+		gdk_pixbuf_fill(blank_icon, 0);
+	}
+
+	gtk_image_set_from_pixbuf(GTK_IMAGE(image), blank_icon);
+}
+
+static void
+docklet_x11_set_tooltip(gchar *tooltip)
+{
+	if (!tooltips)
+		tooltips = gtk_tooltips_new();
+
+	/* image->parent is a GtkEventBox */
+	if (tooltip) {
+		gtk_tooltips_enable(tooltips);
+		gtk_tooltips_set_tip(tooltips, image->parent, tooltip, NULL);
+	} else {
+		gtk_tooltips_set_tip(tooltips, image->parent, "", NULL);
+		gtk_tooltips_disable(tooltips);
+	}
+}
+
+#if GTK_CHECK_VERSION(2,2,0)
+static void
+docklet_x11_position_menu(GtkMenu *menu, int *x, int *y, gboolean *push_in,
+						  gpointer user_data)
+{
+	GtkWidget *widget = GTK_WIDGET(docklet);
+	GtkRequisition req;
+	gint menu_xpos, menu_ypos;
+
+	gtk_widget_size_request(GTK_WIDGET(menu), &req);
+	gdk_window_get_origin(widget->window, &menu_xpos, &menu_ypos);
+
+	menu_xpos += widget->allocation.x;
+	menu_ypos += widget->allocation.y;
+
+	if (menu_ypos > gdk_screen_get_height(gtk_widget_get_screen(widget)) / 2)
+		menu_ypos -= req.height;
+	else
+		menu_ypos += widget->allocation.height;
+
+	*x = menu_xpos;
+	*y = menu_ypos;
+
+	*push_in = TRUE;
+}
+#endif
+
+static void
+docklet_x11_destroy()
+{
+	g_return_if_fail(docklet != NULL);
+
+	docklet_remove();
+
+	g_signal_handlers_disconnect_by_func(G_OBJECT(docklet), G_CALLBACK(docklet_x11_destroyed_cb), NULL);
+	gtk_widget_destroy(GTK_WIDGET(docklet));
+
+	g_object_unref(G_OBJECT(docklet));
+	docklet = NULL;
+
+	if (blank_icon)
+		g_object_unref(G_OBJECT(blank_icon));
+	blank_icon = NULL;
+
+	image = NULL;
+
+	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "destroyed\n");
+}
+
+static gboolean
+docklet_x11_embed_timeout_cb()
+{
+	/* The docklet was not embedded within the timeout.
+	 * Remove it as a visibility manager, but leave the plugin
+	 * loaded so that it can embed automatically if/when a notification
+	 * area becomes available.
+	 */
+	gaim_debug_info("tray icon", "failed to embed within timeout\n");
+	docklet_remove();
+
+	return FALSE;
+}
+
+static void
+docklet_x11_create()
+{
+	GtkWidget *box;
+
+	if (docklet) {
+		/* if this is being called when a tray icon exists, it's because
+		   something messed up. try destroying it before we proceed,
+		   although docklet_refcount may be all hosed. hopefully won't happen. */
+		gaim_debug(GAIM_DEBUG_WARNING, "tray icon", "trying to create icon but it already exists?\n");
+		docklet_x11_destroy();
+	}
+
+	docklet = egg_tray_icon_new("Gaim");
+	box = gtk_event_box_new();
+	image = gtk_image_new();
+
+	g_signal_connect(G_OBJECT(docklet), "embedded", G_CALLBACK(docklet_x11_embedded_cb), NULL);
+	g_signal_connect(G_OBJECT(docklet), "destroy", G_CALLBACK(docklet_x11_destroyed_cb), NULL);
+	g_signal_connect(G_OBJECT(box), "button-press-event", G_CALLBACK(docklet_x11_clicked_cb), NULL);
+
+	gtk_container_add(GTK_CONTAINER(box), image);
+	gtk_container_add(GTK_CONTAINER(docklet), box);
+
+	if (!gtk_check_version(2,4,0))
+		g_object_set(G_OBJECT(box), "visible-window", FALSE, NULL);
+
+	gtk_widget_show_all(GTK_WIDGET(docklet));
+
+	/* ref the docklet before we bandy it about the place */
+	g_object_ref(G_OBJECT(docklet));
+
+	/* This is a hack to avoid a race condition between the docklet getting
+	 * embedded in the notification area and the gtkblist restoring its
+	 * previous visibility state.  If the docklet does not get embedded within
+	 * the timeout, it will be removed as a visibility manager until it does
+	 * get embedded.  Ideally, we would only call docklet_embedded() when the
+	 * icon was actually embedded.
+	 */
+	docklet_embedded();
+	embed_timeout = g_timeout_add(EMBED_TIMEOUT, docklet_x11_embed_timeout_cb, NULL);
+
+	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "created\n");
+}
+
+static struct docklet_ui_ops ui_ops =
+{
+	docklet_x11_create,
+	docklet_x11_destroy,
+	docklet_x11_update_icon,
+	docklet_x11_blank_icon,
+	docklet_x11_set_tooltip,
+#if GTK_CHECK_VERSION(2,2,0)
+	docklet_x11_position_menu
+#else
+	NULL
+#endif
+};
+
+void
+docklet_ui_init()
+{
+	docklet_set_ui_ops(&ui_ops);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gtk/docklet.h	Thu Oct 05 23:24:00 2006 +0000
@@ -0,0 +1,61 @@
+/* 
+ * System tray icon (aka docklet) plugin for Gaim
+ * 
+ * Copyright (C) 2002-3 Robert McQueen <robot101@debian.org>
+ * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com>
+ * Inspired by a similar plugin by:
+ *  John (J5) Palmieri <johnp@martianrock.com>
+ * 
+ * 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 _DOCKLET_H_
+#define _DOCKLET_H_
+
+typedef enum
+{
+	DOCKLET_STATUS_OFFLINE,
+	DOCKLET_STATUS_ONLINE,
+	DOCKLET_STATUS_ONLINE_PENDING,
+	DOCKLET_STATUS_AWAY,
+	DOCKLET_STATUS_AWAY_PENDING,
+	DOCKLET_STATUS_CONNECTING
+} DockletStatus;
+
+struct docklet_ui_ops
+{
+	void (*create)(void);
+	void (*destroy)(void);
+	void (*update_icon)(DockletStatus);
+	void (*blank_icon)(void);
+	void (*set_tooltip)(gchar *);
+	GtkMenuPositionFunc position_menu;
+};
+
+/* useful for setting idle callbacks that will be cleaned up */
+extern GaimPlugin *handle;
+
+/* functions in docklet.c */
+void docklet_clicked(int);
+void docklet_embedded(void);
+void docklet_remove(void);
+void docklet_set_ui_ops(struct docklet_ui_ops *);
+void docklet_unload(void);
+
+/* function in docklet-{x11,win32}.c */
+void docklet_ui_init(void);
+
+#endif /* _DOCKLET_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gtk/eggtrayicon.c	Thu Oct 05 23:24:00 2006 +0000
@@ -0,0 +1,572 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* eggtrayicon.c
+ * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
+ *
+ * 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 "eggtrayicon.h"
+
+#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
+
+#define _(x) x
+#define N_(x) x
+
+#define SYSTEM_TRAY_REQUEST_DOCK    0
+#define SYSTEM_TRAY_BEGIN_MESSAGE   1
+#define SYSTEM_TRAY_CANCEL_MESSAGE  2
+
+#define SYSTEM_TRAY_ORIENTATION_HORZ 0
+#define SYSTEM_TRAY_ORIENTATION_VERT 1
+
+enum {
+  PROP_0,
+  PROP_ORIENTATION
+};
+         
+static GtkPlugClass *parent_class = NULL;
+
+static void egg_tray_icon_init (EggTrayIcon *icon);
+static void egg_tray_icon_class_init (EggTrayIconClass *klass);
+
+static void egg_tray_icon_get_property (GObject    *object,
+					guint       prop_id,
+					GValue     *value,
+					GParamSpec *pspec);
+
+static void egg_tray_icon_realize   (GtkWidget *widget);
+static void egg_tray_icon_unrealize (GtkWidget *widget);
+
+static void egg_tray_icon_add (GtkContainer *container,
+                               GtkWidget *widget);
+
+static void egg_tray_icon_update_manager_window    (EggTrayIcon *icon,
+						    gboolean     dock_if_realized);
+static void egg_tray_icon_manager_window_destroyed (EggTrayIcon *icon);
+
+GType
+egg_tray_icon_get_type (void)
+{
+  static GType our_type = 0;
+
+  if (our_type == 0)
+    {
+      our_type = g_type_from_name("EggTrayIcon");
+
+      if (our_type == 0)
+        {
+      static const GTypeInfo our_info =
+      {
+	sizeof (EggTrayIconClass),
+	(GBaseInitFunc) NULL,
+	(GBaseFinalizeFunc) NULL,
+	(GClassInitFunc) egg_tray_icon_class_init,
+	NULL, /* class_finalize */
+	NULL, /* class_data */
+	sizeof (EggTrayIcon),
+	0,    /* n_preallocs */
+	(GInstanceInitFunc) egg_tray_icon_init,
+	NULL /* value_table */
+      };
+
+      our_type = g_type_register_static (GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0);
+        }
+      else if (parent_class == NULL)
+        {
+          /* we're reheating the old class from a previous instance -  engage ugly hack =( */
+          egg_tray_icon_class_init((EggTrayIconClass *)g_type_class_peek(our_type));
+        }
+    }
+
+  return our_type;
+}
+
+static void
+egg_tray_icon_init (EggTrayIcon *icon)
+{
+  icon->stamp = 1;
+  icon->orientation = GTK_ORIENTATION_HORIZONTAL;
+  
+  gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK);
+}
+
+static void
+egg_tray_icon_class_init (EggTrayIconClass *klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *)klass;
+  GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
+  GtkContainerClass *container_class = (GtkContainerClass *)klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->get_property = egg_tray_icon_get_property;
+
+  widget_class->realize   = egg_tray_icon_realize;
+  widget_class->unrealize = egg_tray_icon_unrealize;
+
+  container_class->add = egg_tray_icon_add;
+
+  g_object_class_install_property (gobject_class,
+				   PROP_ORIENTATION,
+				   g_param_spec_enum ("orientation",
+						      _("Orientation"),
+						      _("The orientation of the tray."),
+						      GTK_TYPE_ORIENTATION,
+						      GTK_ORIENTATION_HORIZONTAL,
+						      G_PARAM_READABLE));
+}
+
+static void
+egg_tray_icon_get_property (GObject    *object,
+			    guint       prop_id,
+			    GValue     *value,
+			    GParamSpec *pspec)
+{
+  EggTrayIcon *icon = EGG_TRAY_ICON (object);
+
+  switch (prop_id)
+    {
+    case PROP_ORIENTATION:
+      g_value_set_enum (value, icon->orientation);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+egg_tray_icon_get_orientation_property (EggTrayIcon *icon)
+{
+  Display *xdisplay;
+  Atom type;
+  int format;
+  union {
+	gulong *prop;
+	guchar *prop_ch;
+  } prop = { NULL };
+  gulong nitems;
+  gulong bytes_after;
+  int error, result;
+
+  g_return_if_fail(icon->manager_window != None);
+
+#if GTK_CHECK_VERSION(2,1,0)
+  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
+#else
+  xdisplay = gdk_display;
+#endif
+
+  gdk_error_trap_push ();
+  type = None;
+  result = XGetWindowProperty (xdisplay,
+			       icon->manager_window,
+			       icon->orientation_atom,
+			       0, G_MAXLONG, FALSE,
+			       XA_CARDINAL,
+			       &type, &format, &nitems,
+			       &bytes_after, &(prop.prop_ch));
+  error = gdk_error_trap_pop ();
+
+  if (error || result != Success)
+    return;
+
+  if (type == XA_CARDINAL)
+    {
+      GtkOrientation orientation;
+
+      orientation = (prop.prop [0] == SYSTEM_TRAY_ORIENTATION_HORZ) ?
+					GTK_ORIENTATION_HORIZONTAL :
+					GTK_ORIENTATION_VERTICAL;
+
+      if (icon->orientation != orientation)
+	{
+	  icon->orientation = orientation;
+
+	  g_object_notify (G_OBJECT (icon), "orientation");
+	}
+    }
+
+  if (prop.prop)
+    XFree (prop.prop);
+}
+
+static GdkFilterReturn
+egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_data)
+{
+  EggTrayIcon *icon = user_data;
+  XEvent *xev = (XEvent *)xevent;
+
+  if (xev->xany.type == ClientMessage &&
+      xev->xclient.message_type == icon->manager_atom &&
+      xev->xclient.data.l[1] == icon->selection_atom)
+    {
+      egg_tray_icon_update_manager_window (icon, TRUE);
+    }
+  else if (xev->xany.window == icon->manager_window)
+    {
+      if (xev->xany.type == PropertyNotify &&
+	  xev->xproperty.atom == icon->orientation_atom)
+	{
+	  egg_tray_icon_get_orientation_property (icon);
+	}
+      if (xev->xany.type == DestroyNotify)
+	{
+	  egg_tray_icon_manager_window_destroyed (icon);
+	}
+    }
+  
+  return GDK_FILTER_CONTINUE;
+}
+
+static void
+egg_tray_icon_unrealize (GtkWidget *widget)
+{
+  EggTrayIcon *icon = EGG_TRAY_ICON (widget);
+  GdkWindow *root_window;
+
+  if (icon->manager_window != None)
+    {
+      GdkWindow *gdkwin;
+
+#if GTK_CHECK_VERSION(2,1,0)
+      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (widget),
+                                              icon->manager_window);
+#else
+      gdkwin = gdk_window_lookup (icon->manager_window);
+#endif
+
+      gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
+    }
+
+#if GTK_CHECK_VERSION(2,1,0)
+  root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
+#else
+  root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ());
+#endif
+
+  gdk_window_remove_filter (root_window, egg_tray_icon_manager_filter, icon);
+
+  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+}
+
+static void
+egg_tray_icon_send_manager_message (EggTrayIcon *icon,
+				    long         message,
+				    Window       window,
+				    long         data1,
+				    long         data2,
+				    long         data3)
+{
+  XClientMessageEvent ev;
+  Display *display;
+  
+  ev.type = ClientMessage;
+  ev.window = window;
+  ev.message_type = icon->system_tray_opcode_atom;
+  ev.format = 32;
+  ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window);
+  ev.data.l[1] = message;
+  ev.data.l[2] = data1;
+  ev.data.l[3] = data2;
+  ev.data.l[4] = data3;
+
+#if GTK_CHECK_VERSION(2,1,0)
+  display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
+#else
+  display = gdk_display;
+#endif
+
+  gdk_error_trap_push ();
+  XSendEvent (display,
+	      icon->manager_window, False, NoEventMask, (XEvent *)&ev);
+  XSync (display, False);
+  gdk_error_trap_pop ();
+}
+
+static void
+egg_tray_icon_send_dock_request (EggTrayIcon *icon)
+{
+  egg_tray_icon_send_manager_message (icon,
+				      SYSTEM_TRAY_REQUEST_DOCK,
+				      icon->manager_window,
+				      gtk_plug_get_id (GTK_PLUG (icon)),
+				      0, 0);
+}
+
+static void
+egg_tray_icon_update_manager_window (EggTrayIcon *icon,
+				     gboolean     dock_if_realized)
+{
+  Display *xdisplay;
+  
+  if (icon->manager_window != None)
+    return;
+
+#if GTK_CHECK_VERSION(2,1,0)
+  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
+#else
+  xdisplay = gdk_display;
+#endif
+
+  XGrabServer (xdisplay);
+  
+  icon->manager_window = XGetSelectionOwner (xdisplay,
+					     icon->selection_atom);
+
+  if (icon->manager_window != None)
+    XSelectInput (xdisplay,
+		  icon->manager_window, StructureNotifyMask|PropertyChangeMask);
+
+  XUngrabServer (xdisplay);
+  XFlush (xdisplay);
+  
+  if (icon->manager_window != None)
+    {
+      GdkWindow *gdkwin;
+
+#if GTK_CHECK_VERSION(2,1,0)
+      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
+					      icon->manager_window);
+#else
+      gdkwin = gdk_window_lookup (icon->manager_window);
+#endif
+
+      gdk_window_add_filter (gdkwin, egg_tray_icon_manager_filter, icon);
+
+      if (dock_if_realized && GTK_WIDGET_REALIZED (icon))
+	egg_tray_icon_send_dock_request (icon);
+
+      egg_tray_icon_get_orientation_property (icon);
+    }
+}
+
+static void
+egg_tray_icon_manager_window_destroyed (EggTrayIcon *icon)
+{
+  GdkWindow *gdkwin;
+  
+  g_return_if_fail (icon->manager_window != None);
+
+#if GTK_CHECK_VERSION(2,1,0)
+  gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
+					  icon->manager_window);
+#else
+  gdkwin = gdk_window_lookup (icon->manager_window);
+#endif
+
+  gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
+
+  icon->manager_window = None;
+
+  egg_tray_icon_update_manager_window (icon, TRUE);
+}
+
+static gboolean
+transparent_expose_event (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
+make_transparent_again (GtkWidget *widget, GtkStyle *previous_style,
+                       gpointer user_data)
+{
+	gdk_window_set_back_pixmap(widget->window, NULL, TRUE);
+}
+
+static void
+make_transparent (GtkWidget *widget, gpointer user_data)
+{
+	if (GTK_WIDGET_NO_WINDOW (widget) || GTK_WIDGET_APP_PAINTABLE (widget))
+		return;
+
+	gtk_widget_set_app_paintable (widget, TRUE);
+	gtk_widget_set_double_buffered (widget, FALSE);
+	gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
+	g_signal_connect (widget, "expose_event",
+	                 G_CALLBACK (transparent_expose_event), NULL);
+	g_signal_connect_after (widget, "style_set",
+	                       G_CALLBACK (make_transparent_again), NULL);
+}
+
+static void
+egg_tray_icon_realize (GtkWidget *widget)
+{
+  EggTrayIcon *icon = EGG_TRAY_ICON (widget);
+  gint screen;
+  Display *xdisplay;
+  char buffer[256];
+  GdkWindow *root_window;
+
+  if (GTK_WIDGET_CLASS (parent_class)->realize)
+    GTK_WIDGET_CLASS (parent_class)->realize (widget);
+
+  make_transparent (widget, NULL);
+
+#if GTK_CHECK_VERSION(2,1,0)
+  screen = gdk_screen_get_number (gtk_widget_get_screen (widget));
+  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget));
+#else
+  screen = XScreenNumberOfScreen (DefaultScreenOfDisplay (gdk_display));
+  xdisplay = gdk_display;
+#endif
+
+  /* Now see if there's a manager window around */
+  g_snprintf (buffer, sizeof (buffer),
+	      "_NET_SYSTEM_TRAY_S%d",
+	      screen);
+
+  icon->selection_atom = XInternAtom (xdisplay, buffer, False);
+  
+  icon->manager_atom = XInternAtom (xdisplay, "MANAGER", False);
+  
+  icon->system_tray_opcode_atom = XInternAtom (xdisplay,
+						   "_NET_SYSTEM_TRAY_OPCODE",
+						   False);
+
+  icon->orientation_atom = XInternAtom (xdisplay,
+					"_NET_SYSTEM_TRAY_ORIENTATION",
+					False);
+
+  egg_tray_icon_update_manager_window (icon, FALSE);
+  egg_tray_icon_send_dock_request (icon);
+
+#if GTK_CHECK_VERSION(2,1,0)
+  root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
+#else
+  root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ());
+#endif
+
+  /* Add a root window filter so that we get changes on MANAGER */
+  gdk_window_add_filter (root_window,
+			 egg_tray_icon_manager_filter, icon);
+}
+
+static void
+egg_tray_icon_add (GtkContainer *container, GtkWidget *widget)
+{
+	g_signal_connect (widget, "realize",
+	                 G_CALLBACK (make_transparent), NULL);
+	GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
+}
+
+#if GTK_CHECK_VERSION(2,1,0)
+EggTrayIcon *
+egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name)
+{
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+  return g_object_new (EGG_TYPE_TRAY_ICON, "screen", screen, "title", name, NULL);
+}
+#endif
+
+EggTrayIcon*
+egg_tray_icon_new (const gchar *name)
+{
+  return g_object_new (EGG_TYPE_TRAY_ICON, "title", name, NULL);
+}
+
+guint
+egg_tray_icon_send_message (EggTrayIcon *icon,
+			    gint         timeout,
+			    const gchar *message,
+			    gint         len)
+{
+  guint stamp;
+  
+  g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0);
+  g_return_val_if_fail (timeout >= 0, 0);
+  g_return_val_if_fail (message != NULL, 0);
+		     
+  if (icon->manager_window == None)
+    return 0;
+
+  if (len < 0)
+    len = strlen (message);
+
+  stamp = icon->stamp++;
+  
+  /* Get ready to send the message */
+  egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE,
+				      (Window)gtk_plug_get_id (GTK_PLUG (icon)),
+				      timeout, len, stamp);
+
+  /* Now to send the actual message */
+  gdk_error_trap_push ();
+  while (len > 0)
+    {
+      XClientMessageEvent ev;
+      Display *xdisplay;
+
+#if GTK_CHECK_VERSION(2,1,0)
+      xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
+#else
+      xdisplay = gdk_display;
+#endif
+
+      ev.type = ClientMessage;
+      ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon));
+      ev.format = 8;
+      ev.message_type = XInternAtom (xdisplay,
+				     "_NET_SYSTEM_TRAY_MESSAGE_DATA", False);
+      if (len > 20)
+	{
+	  memcpy (&ev.data, message, 20);
+	  len -= 20;
+	  message += 20;
+	}
+      else
+	{
+	  memcpy (&ev.data, message, len);
+	  len = 0;
+	}
+
+      XSendEvent (xdisplay,
+		  icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev);
+      XSync (xdisplay, False);
+    }
+  gdk_error_trap_pop ();
+
+  return stamp;
+}
+
+void
+egg_tray_icon_cancel_message (EggTrayIcon *icon,
+			      guint        id)
+{
+  g_return_if_fail (EGG_IS_TRAY_ICON (icon));
+  g_return_if_fail (id > 0);
+  
+  egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE,
+				      (Window)gtk_plug_get_id (GTK_PLUG (icon)),
+				      id, 0, 0);
+}
+
+GtkOrientation
+egg_tray_icon_get_orientation (EggTrayIcon *icon)
+{
+  g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), GTK_ORIENTATION_HORIZONTAL);
+
+  return icon->orientation;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gtk/eggtrayicon.h	Thu Oct 05 23:24:00 2006 +0000
@@ -0,0 +1,80 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* eggtrayicon.h
+ * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
+ *
+ * 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 __EGG_TRAY_ICON_H__
+#define __EGG_TRAY_ICON_H__
+
+#include <gtk/gtkplug.h>
+#include <gtk/gtkversion.h>
+#include <gdk/gdkx.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_TRAY_ICON		(egg_tray_icon_get_type ())
+#define EGG_TRAY_ICON(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TRAY_ICON, EggTrayIcon))
+#define EGG_TRAY_ICON_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TRAY_ICON, EggTrayIconClass))
+#define EGG_IS_TRAY_ICON(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TRAY_ICON))
+#define EGG_IS_TRAY_ICON_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TRAY_ICON))
+#define EGG_TRAY_ICON_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TRAY_ICON, EggTrayIconClass))
+	
+typedef struct _EggTrayIcon	  EggTrayIcon;
+typedef struct _EggTrayIconClass  EggTrayIconClass;
+
+struct _EggTrayIcon
+{
+  GtkPlug parent_instance;
+
+  guint stamp;
+  
+  Atom selection_atom;
+  Atom manager_atom;
+  Atom system_tray_opcode_atom;
+  Atom orientation_atom;
+  Window manager_window;
+
+  GtkOrientation orientation;
+};
+
+struct _EggTrayIconClass
+{
+  GtkPlugClass parent_class;
+};
+
+GType        egg_tray_icon_get_type       (void);
+
+#if GTK_CHECK_VERSION(2,1,0)
+EggTrayIcon *egg_tray_icon_new_for_screen (GdkScreen   *screen,
+					   const gchar *name);
+#endif
+
+EggTrayIcon *egg_tray_icon_new            (const gchar *name);
+
+guint        egg_tray_icon_send_message   (EggTrayIcon *icon,
+					   gint         timeout,
+					   const char  *message,
+					   gint         len);
+void         egg_tray_icon_cancel_message (EggTrayIcon *icon,
+					   guint        id);
+
+GtkOrientation egg_tray_icon_get_orientation (EggTrayIcon *icon);
+					    
+G_END_DECLS
+
+#endif /* __EGG_TRAY_ICON_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gtk/gtkdocklet-win32.c	Thu Oct 05 23:24:00 2006 +0000
@@ -0,0 +1,263 @@
+/*
+ * System tray icon (aka docklet) plugin for Gaim
+ *
+ * Copyright (C) 2002-3 Robert McQueen <robot101@debian.org>
+ * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com>
+ * Inspired by a similar plugin by:
+ *  John (J5) Palmieri <johnp@martianrock.com>
+ * 
+ * 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.
+ */
+
+#include <windows.h>
+#include <gdk/gdkwin32.h>
+#include <gdk/gdk.h>
+
+#include "internal.h"
+#include "gtkblist.h"
+#include "gtkprefs.h"
+#include "debug.h"
+
+#include "gaim.h"
+#include "gtkdialogs.h"
+
+#include "resource.h"
+#include "MinimizeToTray.h"
+#include "gtkwin32dep.h"
+#include "docklet.h"
+
+/*
+ *  DEFINES, MACROS & DATA TYPES
+ */
+#define WM_TRAYMESSAGE WM_USER /* User defined WM Message */
+
+/*
+ *  LOCALS
+ */
+static HWND systray_hwnd=0;
+static HICON sysicon_disconn=0;
+static HICON sysicon_conn=0;
+static HICON sysicon_away=0;
+static HICON sysicon_pend=0;
+static HICON sysicon_awypend=0;
+static HICON sysicon_blank=0;
+static NOTIFYICONDATA wgaim_nid;
+
+
+static LRESULT CALLBACK systray_mainmsg_handler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+	static UINT taskbarRestartMsg; /* static here means value is kept across multiple calls to this func */
+
+	switch(msg) {
+	case WM_CREATE:
+		gaim_debug(GAIM_DEBUG_INFO, "tray icon", "WM_CREATE\n");
+		taskbarRestartMsg = RegisterWindowMessage("TaskbarCreated");
+		break;
+		
+	case WM_TIMER:
+		gaim_debug(GAIM_DEBUG_INFO, "tray icon", "WM_TIMER\n");
+		break;
+
+	case WM_DESTROY:
+		gaim_debug(GAIM_DEBUG_INFO, "tray icon", "WM_DESTROY\n");
+		break;
+
+	case WM_TRAYMESSAGE:
+	{
+		int type = 0;
+
+		/* We'll use Double Click - Single click over on linux */
+		if( lparam == WM_LBUTTONDBLCLK )
+			type = 1;
+		else if( lparam == WM_MBUTTONUP )
+			type = 2;
+		else if( lparam == WM_RBUTTONUP )
+			type = 3;
+		else
+			break;
+
+		docklet_clicked(type);
+		break;
+	}
+	default: 
+		if (msg == taskbarRestartMsg) {
+			/* explorer crashed and left us hanging... 
+			   This will put the systray icon back in it's place, when it restarts */
+			Shell_NotifyIcon(NIM_ADD,&wgaim_nid);
+		}
+		break;
+	}/* end switch */
+
+	return DefWindowProc(hwnd, msg, wparam, lparam);
+}
+
+/* Create hidden window to process systray messages */
+static HWND systray_create_hiddenwin() {
+	WNDCLASSEX wcex;
+	TCHAR wname[32];
+
+	strcpy(wname, "GaimWin");
+
+	wcex.cbSize = sizeof(WNDCLASSEX);
+
+	wcex.style		= 0;
+	wcex.lpfnWndProc	= (WNDPROC)systray_mainmsg_handler;
+	wcex.cbClsExtra		= 0;
+	wcex.cbWndExtra		= 0;
+	wcex.hInstance		= gtkwgaim_hinstance();
+	wcex.hIcon		= NULL;
+	wcex.hCursor		= NULL,
+	wcex.hbrBackground	= NULL;
+	wcex.lpszMenuName	= NULL;
+	wcex.lpszClassName	= wname;
+	wcex.hIconSm		= NULL;
+
+	RegisterClassEx(&wcex);
+
+	/* Create the window */
+	return (CreateWindow(wname, "", 0, 0, 0, 0, 0, GetDesktopWindow(), NULL, gtkwgaim_hinstance(), 0));
+}
+
+static void systray_init_icon(HWND hWnd, HICON icon) {
+	ZeroMemory(&wgaim_nid,sizeof(wgaim_nid));
+	wgaim_nid.cbSize=sizeof(NOTIFYICONDATA);
+	wgaim_nid.hWnd=hWnd;
+	wgaim_nid.uID=0;
+	wgaim_nid.uFlags=NIF_ICON | NIF_MESSAGE | NIF_TIP;
+	wgaim_nid.uCallbackMessage=WM_TRAYMESSAGE;
+	wgaim_nid.hIcon=icon;
+	lstrcpy(wgaim_nid.szTip, "Gaim");
+	Shell_NotifyIcon(NIM_ADD,&wgaim_nid);
+	docklet_embedded();
+}
+
+static void systray_change_icon(HICON icon) {
+	wgaim_nid.hIcon = icon;
+	Shell_NotifyIcon(NIM_MODIFY,&wgaim_nid);
+}
+
+static void systray_remove_nid(void) {
+	Shell_NotifyIcon(NIM_DELETE,&wgaim_nid);
+}
+
+static void wgaim_tray_update_icon(DockletStatus icon) {
+	switch (icon) {
+		case DOCKLET_STATUS_OFFLINE:
+			systray_change_icon(sysicon_disconn);
+			break;
+		case DOCKLET_STATUS_CONNECTING:
+			break;
+		case DOCKLET_STATUS_ONLINE:
+			systray_change_icon(sysicon_conn);
+			break;
+		case DOCKLET_STATUS_ONLINE_PENDING:
+			systray_change_icon(sysicon_pend);
+			break;
+		case DOCKLET_STATUS_AWAY:
+			systray_change_icon(sysicon_away);
+			break;
+		case DOCKLET_STATUS_AWAY_PENDING:
+			systray_change_icon(sysicon_awypend);
+			break;
+	}
+}
+
+static void wgaim_tray_blank_icon() {
+	systray_change_icon(sysicon_blank);
+}
+
+static void wgaim_tray_set_tooltip(gchar *tooltip) {
+	if (tooltip) {
+		char *locenc = NULL;
+		locenc = g_locale_from_utf8(tooltip, -1, NULL, NULL, NULL);
+		lstrcpyn(wgaim_nid.szTip, locenc, sizeof(wgaim_nid.szTip)/sizeof(TCHAR));
+		g_free(locenc);
+	} else {
+		lstrcpy(wgaim_nid.szTip, "Gaim");
+	}
+	Shell_NotifyIcon(NIM_MODIFY, &wgaim_nid);
+}
+
+void wgaim_tray_minimize(GaimGtkBuddyList *gtkblist) {
+	MinimizeWndToTray(GDK_WINDOW_HWND(gtkblist->window->window));
+}
+
+void wgaim_tray_maximize(GaimGtkBuddyList *gtkblist) {
+	RestoreWndFromTray(GDK_WINDOW_HWND(gtkblist->window->window));
+}
+
+
+static void wgaim_tray_create() {
+	OSVERSIONINFO osinfo;
+	/* dummy window to process systray messages */
+	systray_hwnd = systray_create_hiddenwin();
+
+	osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+	GetVersionEx(&osinfo);
+
+	/* Load icons, and init systray notify icon
+	 * NOTE: Windows < XP only supports displaying 4-bit images in the Systray,
+	 *  2K and ME will use the highest color depth that the desktop will support,
+	 *  but will scale it back to 4-bits for display.
+	 * That is why we use custom 4-bit icons for pre XP Windowses */
+	if ((osinfo.dwMajorVersion == 5 && osinfo.dwMinorVersion > 0) ||
+		(osinfo.dwMajorVersion >= 6))
+	{
+		sysicon_disconn = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_OFFLINE_TRAY_ICON), IMAGE_ICON, 16, 16, 0);
+		sysicon_conn = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_TRAY_ICON), IMAGE_ICON, 16, 16, 0);
+		sysicon_away = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_AWAY_TRAY_ICON), IMAGE_ICON, 16, 16, 0);
+		sysicon_pend = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_PEND_TRAY_ICON), IMAGE_ICON, 16, 16, 0);
+		sysicon_awypend = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_AWAYPEND_TRAY_ICON), IMAGE_ICON, 16, 16, 0);
+	} else {
+		sysicon_disconn = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_OFFLINE_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0);
+		sysicon_conn = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0);
+		sysicon_away = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_AWAY_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0);
+		sysicon_pend = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_PEND_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0);
+		sysicon_awypend = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_AWAYPEND_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0);
+	}
+	sysicon_blank = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_BLANK_TRAY_ICON), IMAGE_ICON, 16, 16, 0);
+
+	/* Create icon in systray */
+	systray_init_icon(systray_hwnd, sysicon_disconn);
+
+	gaim_signal_connect(gaim_gtk_blist_get_handle(), "gtkblist-hiding", 
+			&handle, GAIM_CALLBACK(wgaim_tray_minimize), NULL);
+	gaim_signal_connect(gaim_gtk_blist_get_handle(), "gtkblist-unhiding", 
+			&handle, GAIM_CALLBACK(wgaim_tray_maximize), NULL);
+
+	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "created\n");
+}
+
+static void wgaim_tray_destroy() {
+	gaim_signals_disconnect_by_handle(&handle);
+	systray_remove_nid();
+	DestroyWindow(systray_hwnd);
+	docklet_remove();
+}
+
+static struct docklet_ui_ops wgaim_tray_ops =
+{
+	wgaim_tray_create,
+	wgaim_tray_destroy,
+	wgaim_tray_update_icon,
+	wgaim_tray_blank_icon,
+	wgaim_tray_set_tooltip,
+	NULL
+};
+
+/* Used by docklet's plugin load func */
+void docklet_ui_init() {
+	docklet_set_ui_ops(&wgaim_tray_ops);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gtk/gtkdocklet-x11.c	Thu Oct 05 23:24:00 2006 +0000
@@ -0,0 +1,305 @@
+/*
+ * System tray icon (aka docklet) plugin for Gaim
+ *
+ * Copyright (C) 2002-3 Robert McQueen <robot101@debian.org>
+ * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com>
+ * Inspired by a similar plugin by:
+ *  John (J5) Palmieri <johnp@martianrock.com>
+ * 
+ * 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.
+ */
+
+#include "internal.h"
+#include "gtkgaim.h"
+#include "debug.h"
+#include "gaimstock.h"
+
+#include "gaim.h"
+#include "gtkdialogs.h"
+
+#include "eggtrayicon.h"
+#include "gtkdocklet.h"
+
+#define EMBED_TIMEOUT 5000
+
+/* globals */
+static EggTrayIcon *docklet = NULL;
+static GtkWidget *image = NULL;
+static GtkTooltips *tooltips = NULL;
+static GdkPixbuf *blank_icon = NULL;
+static int embed_timeout = 0;
+
+/* protos */
+static void docklet_x11_create(void);
+
+static gboolean
+docklet_x11_create_cb()
+{
+	docklet_x11_create();
+
+	return FALSE; /* for when we're called by the glib idle handler */
+}
+
+static void
+docklet_x11_embedded_cb(GtkWidget *widget, void *data)
+{
+	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "embedded\n");
+	
+	g_source_remove(embed_timeout);
+	embed_timeout = 0;
+	gaim_gtk_docklet_embedded();
+}
+
+static void
+docklet_x11_destroyed_cb(GtkWidget *widget, void *data)
+{
+	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "destroyed\n");
+
+	gaim_gtk_docklet_remove();
+
+	g_object_unref(G_OBJECT(docklet));
+	docklet = NULL;
+
+	g_idle_add(docklet_x11_create_cb, NULL);
+}
+
+static void
+docklet_x11_clicked_cb(GtkWidget *button, GdkEventButton *event, void *data)
+{
+	if (event->type != GDK_BUTTON_PRESS)
+		return;
+
+	gaim_gtk_docklet_clicked(event->button);
+}
+
+static void
+docklet_x11_update_icon(DockletStatus icon)
+{
+	const gchar *icon_name = NULL;
+
+	g_return_if_fail(image != NULL);
+
+	switch (icon) {
+		case DOCKLET_STATUS_OFFLINE:
+			icon_name = GAIM_STOCK_ICON_OFFLINE;
+			break;
+		case DOCKLET_STATUS_CONNECTING:
+			icon_name = GAIM_STOCK_ICON_CONNECT;
+			break;
+		case DOCKLET_STATUS_ONLINE:
+			icon_name = GAIM_STOCK_ICON_ONLINE;
+			break;
+		case DOCKLET_STATUS_ONLINE_PENDING:
+			icon_name = GAIM_STOCK_ICON_ONLINE_MSG;
+			break;
+		case DOCKLET_STATUS_AWAY:
+			icon_name = GAIM_STOCK_ICON_AWAY;
+			break;
+		case DOCKLET_STATUS_AWAY_PENDING:
+			icon_name = GAIM_STOCK_ICON_AWAY_MSG;
+			break;
+	}
+
+	if(icon_name)
+		gtk_image_set_from_stock(GTK_IMAGE(image), icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR);
+
+#if 0
+	GdkPixbuf *p;
+	GdkBitmap *mask = NULL;
+
+	p = gtk_widget_render_icon(GTK_WIDGET(image), icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
+
+	if (p && (gdk_pixbuf_get_colorspace(p) == GDK_COLORSPACE_RGB) && (gdk_pixbuf_get_bits_per_sample(p) == 8)
+	   && (gdk_pixbuf_get_has_alpha(p)) && (gdk_pixbuf_get_n_channels(p) == 4)) {
+		int len = gdk_pixbuf_get_width(p) * gdk_pixbuf_get_height(p);
+		guchar *data = gdk_pixbuf_get_pixels(p);
+		guchar *bitmap = g_malloc((len / 8) + 1);
+		int i;
+
+		for (i = 0; i < len; i++)
+			if (data[i*4 + 3] > 55)
+				bitmap[i/8] |= 1 << i % 8;
+			else
+				bitmap[i/8] &= ~(1 << i % 8);
+
+		mask = gdk_bitmap_create_from_data(GDK_DRAWABLE(GTK_WIDGET(image)->window), bitmap, gdk_pixbuf_get_width(p), gdk_pixbuf_get_height(p));
+		g_free(bitmap);
+	}
+
+	if (mask)
+		gdk_window_shape_combine_mask(image->window, mask, 0, 0);
+
+	g_object_unref(G_OBJECT(p));
+#endif
+}
+
+static void
+docklet_x11_blank_icon()
+{
+	if (!blank_icon) {
+		gint width, height;
+
+		gtk_icon_size_lookup(GTK_ICON_SIZE_LARGE_TOOLBAR, &width, &height);
+		blank_icon = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
+		gdk_pixbuf_fill(blank_icon, 0);
+	}
+
+	gtk_image_set_from_pixbuf(GTK_IMAGE(image), blank_icon);
+}
+
+static void
+docklet_x11_set_tooltip(gchar *tooltip)
+{
+	if (!tooltips)
+		tooltips = gtk_tooltips_new();
+
+	/* image->parent is a GtkEventBox */
+	if (tooltip) {
+		gtk_tooltips_enable(tooltips);
+		gtk_tooltips_set_tip(tooltips, image->parent, tooltip, NULL);
+	} else {
+		gtk_tooltips_set_tip(tooltips, image->parent, "", NULL);
+		gtk_tooltips_disable(tooltips);
+	}
+}
+
+#if GTK_CHECK_VERSION(2,2,0)
+static void
+docklet_x11_position_menu(GtkMenu *menu, int *x, int *y, gboolean *push_in,
+						  gpointer user_data)
+{
+	GtkWidget *widget = GTK_WIDGET(docklet);
+	GtkRequisition req;
+	gint menu_xpos, menu_ypos;
+
+	gtk_widget_size_request(GTK_WIDGET(menu), &req);
+	gdk_window_get_origin(widget->window, &menu_xpos, &menu_ypos);
+
+	menu_xpos += widget->allocation.x;
+	menu_ypos += widget->allocation.y;
+
+	if (menu_ypos > gdk_screen_get_height(gtk_widget_get_screen(widget)) / 2)
+		menu_ypos -= req.height;
+	else
+		menu_ypos += widget->allocation.height;
+
+	*x = menu_xpos;
+	*y = menu_ypos;
+
+	*push_in = TRUE;
+}
+#endif
+
+static void
+docklet_x11_destroy()
+{
+	g_return_if_fail(docklet != NULL);
+
+	gaim_gtk_docklet_remove();
+
+	g_signal_handlers_disconnect_by_func(G_OBJECT(docklet), G_CALLBACK(docklet_x11_destroyed_cb), NULL);
+	gtk_widget_destroy(GTK_WIDGET(docklet));
+
+	g_object_unref(G_OBJECT(docklet));
+	docklet = NULL;
+
+	if (blank_icon)
+		g_object_unref(G_OBJECT(blank_icon));
+	blank_icon = NULL;
+
+	image = NULL;
+
+	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "destroyed\n");
+}
+
+static gboolean
+docklet_x11_embed_timeout_cb()
+{
+	/* The docklet was not embedded within the timeout.
+	 * Remove it as a visibility manager, but leave the plugin
+	 * loaded so that it can embed automatically if/when a notification
+	 * area becomes available.
+	 */
+	gaim_debug_info("tray icon", "failed to embed within timeout\n");
+	gaim_gtk_docklet_remove();
+	
+	return FALSE;
+}
+
+static void
+docklet_x11_create()
+{
+	GtkWidget *box;
+
+	if (docklet) {
+		/* if this is being called when a tray icon exists, it's because
+		   something messed up. try destroying it before we proceed,
+		   although docklet_refcount may be all hosed. hopefully won't happen. */
+		gaim_debug(GAIM_DEBUG_WARNING, "tray icon", "trying to create icon but it already exists?\n");
+		docklet_x11_destroy();
+	}
+
+	docklet = egg_tray_icon_new("Gaim");
+	box = gtk_event_box_new();
+	image = gtk_image_new();
+
+	g_signal_connect(G_OBJECT(docklet), "embedded", G_CALLBACK(docklet_x11_embedded_cb), NULL);
+	g_signal_connect(G_OBJECT(docklet), "destroy", G_CALLBACK(docklet_x11_destroyed_cb), NULL);
+	g_signal_connect(G_OBJECT(box), "button-press-event", G_CALLBACK(docklet_x11_clicked_cb), NULL);
+
+	gtk_container_add(GTK_CONTAINER(box), image);
+	gtk_container_add(GTK_CONTAINER(docklet), box);
+
+	if (!gtk_check_version(2,4,0))
+		g_object_set(G_OBJECT(box), "visible-window", FALSE, NULL);
+
+	gtk_widget_show_all(GTK_WIDGET(docklet));
+
+	/* ref the docklet before we bandy it about the place */
+	g_object_ref(G_OBJECT(docklet));
+
+	/* This is a hack to avoid a race condition between the docklet getting
+	 * embedded in the notification area and the gtkblist restoring its
+	 * previous visibility state.  If the docklet does not get embedded within
+	 * the timeout, it will be removed as a visibility manager until it does
+	 * get embedded.  Ideally, we would only call docklet_embedded() when the
+	 * icon was actually embedded.
+	 */
+	gaim_gtk_docklet_embedded();
+	embed_timeout = g_timeout_add(EMBED_TIMEOUT, docklet_x11_embed_timeout_cb, NULL);
+
+	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "created\n");
+}
+
+static struct docklet_ui_ops ui_ops =
+{
+	docklet_x11_create,
+	docklet_x11_destroy,
+	docklet_x11_update_icon,
+	docklet_x11_blank_icon,
+	docklet_x11_set_tooltip,
+#if GTK_CHECK_VERSION(2,2,0)
+	docklet_x11_position_menu
+#else
+	NULL
+#endif
+};
+
+void
+docklet_ui_init()
+{
+	gaim_gtk_docklet_set_ui_ops(&ui_ops);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gtk/gtkdocklet.c	Thu Oct 05 23:24:00 2006 +0000
@@ -0,0 +1,694 @@
+/*
+ * System tray icon (aka docklet) plugin for Gaim
+ *
+ * Copyright (C) 2002-3 Robert McQueen <robot101@debian.org>
+ * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com>
+ * Inspired by a similar plugin by:
+ *  John (J5) Palmieri <johnp@martianrock.com>
+ *
+ * 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.
+ */
+#include "internal.h"
+#include "gtkgaim.h"
+
+#include "core.h"
+#include "conversation.h"
+#include "debug.h"
+#include "prefs.h"
+#include "signals.h"
+#include "sound.h"
+#include "version.h"
+
+#include "gtkaccount.h"
+#include "gtkblist.h"
+#include "gtkconv.h"
+#include "gtkft.h"
+#include "gtkplugin.h"
+#include "gtkprefs.h"
+#include "gtksavedstatuses.h"
+#include "gtksound.h"
+#include "gtkutils.h"
+#include "gaimstock.h"
+#include "gtkdocklet.h"
+
+#include "gaim.h"
+#include "gtkdialogs.h"
+
+#ifndef DOCKLET_TOOLTIP_LINE_LIMIT
+#define DOCKLET_TOOLTIP_LINE_LIMIT 5
+#endif
+
+/* globals */
+static struct docklet_ui_ops *ui_ops = NULL;
+static DockletStatus status = DOCKLET_STATUS_OFFLINE;
+static gboolean enable_join_chat = FALSE;
+static guint docklet_blinking_timer = 0;
+static gboolean visibility_manager = FALSE;
+
+/**************************************************************************
+ * docklet status and utility functions
+ **************************************************************************/
+static gboolean
+docklet_blink_icon()
+{
+	static gboolean blinked = FALSE;
+	gboolean ret = FALSE; /* by default, don't keep blinking */
+
+	blinked = !blinked;
+
+	switch (status) {
+		case DOCKLET_STATUS_ONLINE_PENDING:
+		case DOCKLET_STATUS_AWAY_PENDING:
+			if (blinked) {
+				if (ui_ops && ui_ops->blank_icon)
+					ui_ops->blank_icon();
+			} else {
+				if (ui_ops && ui_ops->update_icon)
+					ui_ops->update_icon(status);
+			}
+			ret = TRUE; /* keep blinking */
+			break;
+		default:
+			docklet_blinking_timer = 0;
+			blinked = FALSE;
+			break;
+	}
+
+	return ret;
+}
+
+static GList *
+get_pending_list(guint max)
+{
+	const char *im = gaim_prefs_get_string("/plugins/gtk/docklet/blink_im");
+	const char *chat = gaim_prefs_get_string("/plugins/gtk/docklet/blink_chat");
+	GList *l_im = NULL;
+	GList *l_chat = NULL;
+
+	if (im != NULL && strcmp(im, "always") == 0) {
+		l_im = gaim_gtk_conversations_find_unseen_list(GAIM_CONV_TYPE_IM,
+													   GAIM_UNSEEN_TEXT,
+													   FALSE, max);
+	} else if (im != NULL && strcmp(im, "hidden") == 0) {
+		l_im = gaim_gtk_conversations_find_unseen_list(GAIM_CONV_TYPE_IM,
+													   GAIM_UNSEEN_TEXT,
+													   TRUE, max);
+	}
+
+	if (chat != NULL && strcmp(chat, "always") == 0) {
+		l_chat = gaim_gtk_conversations_find_unseen_list(GAIM_CONV_TYPE_CHAT,
+													   GAIM_UNSEEN_TEXT,
+													   FALSE, max);
+	} else if (chat != NULL && strcmp(chat, "nick") == 0) {
+		l_chat = gaim_gtk_conversations_find_unseen_list(GAIM_CONV_TYPE_CHAT,
+													   GAIM_UNSEEN_NICK,
+													   FALSE, max);
+	}
+
+	if (l_im != NULL && l_chat != NULL)
+		return g_list_concat(l_im, l_chat);
+	else if (l_im != NULL)
+		return l_im;
+	else
+		return l_chat;
+}
+
+static gboolean
+docklet_update_status()
+{
+	GList *convs;
+	GList *l;
+	int count;
+	DockletStatus newstatus = DOCKLET_STATUS_OFFLINE;
+	gboolean pending = FALSE;
+
+	/* determine if any ims have unseen messages */
+	convs = get_pending_list(DOCKLET_TOOLTIP_LINE_LIMIT);
+
+	if (convs != NULL) {
+		pending = TRUE;
+
+		/* set tooltip if messages are pending */
+		if (ui_ops->set_tooltip) {
+			GString *tooltip_text = g_string_new("");
+			for (l = convs, count = 0 ; l != NULL ; l = l->next, count++) {
+				if (GAIM_IS_GTK_CONVERSATION(l->data)) {
+					GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION((GaimConversation *)l->data);
+					if (count == DOCKLET_TOOLTIP_LINE_LIMIT - 1)
+						g_string_append(tooltip_text, _("Right-click for more unread messages...\n"));
+					else
+						g_string_append_printf(tooltip_text,
+							ngettext("%d unread message from %s\n", "%d unread messages from %s\n", gtkconv->unseen_count),
+							gtkconv->unseen_count,
+							gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)));
+				}
+			}
+
+			/* get rid of the last newline */
+			if (tooltip_text->len > 0)
+				tooltip_text = g_string_truncate(tooltip_text, tooltip_text->len - 1);
+
+			ui_ops->set_tooltip(tooltip_text->str);
+
+			g_string_free(tooltip_text, TRUE);
+		}
+
+		g_list_free(convs);
+
+	} else if (ui_ops->set_tooltip) {
+		ui_ops->set_tooltip(NULL);
+	}
+
+	/* iterate through all accounts and determine which
+	 * status to show in the tray icon based on the following
+	 * ranks (highest encountered rank will be used):
+	 *
+	 *     1) OFFLINE
+	 *     2) ONLINE
+	 *     3) ONLINE_PENDING
+	 *     4) AWAY
+	 *     5) AWAY_PENDING
+	 *     6) CONNECTING
+	 */
+	for(l = gaim_accounts_get_all(); l != NULL; l = l->next) {
+		DockletStatus tmpstatus = DOCKLET_STATUS_OFFLINE;
+
+		GaimAccount *account = (GaimAccount*)l->data;
+		GaimStatus *account_status;
+
+		if (!gaim_account_get_enabled(account, GAIM_GTK_UI))
+			continue;
+
+		if (gaim_account_is_disconnected(account))
+			continue;
+
+		account_status = gaim_account_get_active_status(account);
+
+		if (gaim_account_is_connecting(account)) {
+			tmpstatus = DOCKLET_STATUS_CONNECTING;
+		} else if (gaim_status_is_online(account_status)) {
+			if (!gaim_status_is_available(account_status)) {
+				if (pending)
+					tmpstatus = DOCKLET_STATUS_AWAY_PENDING;
+				else
+					tmpstatus = DOCKLET_STATUS_AWAY;
+			}
+			else {
+				if (pending)
+					tmpstatus = DOCKLET_STATUS_ONLINE_PENDING;
+				else
+					tmpstatus = DOCKLET_STATUS_ONLINE;
+			}
+		}
+
+		if (tmpstatus > newstatus)
+			newstatus = tmpstatus;
+	}
+
+	/* update the icon if we changed status */
+	if (status != newstatus) {
+		status = newstatus;
+
+		if (ui_ops && ui_ops->update_icon)
+			ui_ops->update_icon(status);
+
+		/* and schedule the blinker function if messages are pending */
+		if ((status == DOCKLET_STATUS_ONLINE_PENDING
+				|| status == DOCKLET_STATUS_AWAY_PENDING)
+			&& docklet_blinking_timer == 0) {
+				docklet_blinking_timer = g_timeout_add(500, docklet_blink_icon, NULL);
+		}
+	}
+
+	return FALSE; /* for when we're called by the glib idle handler */
+}
+
+static gboolean
+online_account_supports_chat()
+{
+	GList *c = NULL;
+	c = gaim_connections_get_all();
+
+	while(c != NULL) {
+		GaimConnection *gc = c->data;
+		GaimPluginProtocolInfo *prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
+		if (prpl_info != NULL && prpl_info->chat_info != NULL)
+			return TRUE;
+		c = c->next;
+	}
+
+	return FALSE;
+}
+
+/**************************************************************************
+ * callbacks and signal handlers
+ **************************************************************************/
+static void 
+gaim_quit_cb() 
+{
+	/* TODO: confirm quit while pending */
+}
+
+static void
+docklet_update_status_cb(void *data)
+{
+	docklet_update_status();
+}
+
+static void
+docklet_prefs_cb(const char *name, GaimPrefType type,
+				 gconstpointer val, gpointer data)
+{
+	docklet_update_status();
+}
+
+static void
+docklet_conv_updated_cb(GaimConversation *conv, GaimConvUpdateType type)
+{
+	if (type == GAIM_CONV_UPDATE_UNSEEN)
+		docklet_update_status();
+}
+
+static void
+docklet_signed_on_cb(GaimConnection *gc)
+{
+	if (!enable_join_chat) {
+		if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info != NULL)
+			enable_join_chat = TRUE;
+	}
+	docklet_update_status();
+}
+
+static void
+docklet_signed_off_cb(GaimConnection *gc)
+{
+	if (enable_join_chat) {
+		if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info != NULL)
+			enable_join_chat = online_account_supports_chat();
+	}
+	docklet_update_status();
+}
+
+/**************************************************************************
+ * docklet pop-up menu
+ **************************************************************************/
+static void
+docklet_toggle_mute(GtkWidget *toggle, void *data)
+{
+	gaim_prefs_set_bool("/gaim/gtk/sound/mute", GTK_CHECK_MENU_ITEM(toggle)->active);
+}
+
+static void
+docklet_toggle_blist(GtkWidget *toggle, void *data)
+{
+	gaim_blist_set_visible(GTK_CHECK_MENU_ITEM(toggle)->active);
+}
+
+#ifdef _WIN32
+/* This is a workaround for a bug in windows GTK+. Clicking outside of the
+   menu does not get rid of it, so instead we get rid of it as soon as the
+   pointer leaves the menu. */
+static gboolean 
+hide_docklet_menu(gpointer data)
+{
+	if (data != NULL) {
+		gtk_menu_popdown(GTK_MENU(data));
+	}
+	return FALSE;
+}
+
+static gboolean
+docklet_menu_leave_enter(GtkWidget *menu, GdkEventCrossing *event, void *data)
+{
+	static guint hide_docklet_timer = 0;
+	if (event->type == GDK_LEAVE_NOTIFY && event->detail == GDK_NOTIFY_ANCESTOR) {
+		gaim_debug(GAIM_DEBUG_INFO, "docklet", "menu leave-notify-event\n");
+		/* Add some slop so that the menu doesn't annoyingly disappear when mousing around */
+		if (hide_docklet_timer == 0) {
+			hide_docklet_timer = gaim_timeout_add(500,
+					hide_docklet_menu, menu);
+		}
+	} else if (event->type == GDK_ENTER_NOTIFY && event->detail == GDK_NOTIFY_ANCESTOR) {
+		gaim_debug(GAIM_DEBUG_INFO, "docklet", "menu enter-notify-event\n");
+		if (hide_docklet_timer != 0) {
+			/* Cancel the hiding if we reenter */
+
+			gaim_timeout_remove(hide_docklet_timer);
+			hide_docklet_timer = 0;
+		}
+	}
+	return FALSE;
+}
+#endif
+
+static void
+show_custom_status_editor_cb(GtkMenuItem *menuitem, gpointer user_data)
+{
+	GaimSavedStatus *saved_status;
+	saved_status = gaim_savedstatus_get_current();
+	gaim_gtk_status_editor_show(FALSE,
+		gaim_savedstatus_is_transient(saved_status) ? saved_status : NULL);
+}
+
+static void
+activate_status_primitive_cb(GtkMenuItem *menuitem, gpointer user_data)
+{
+	GaimStatusPrimitive primitive;
+	GaimSavedStatus *saved_status;
+
+	primitive = GPOINTER_TO_INT(user_data);
+
+	/* Try to lookup an already existing transient saved status */
+	saved_status = gaim_savedstatus_find_transient_by_type_and_message(primitive, NULL);
+
+	/* Create a new transient saved status if we weren't able to find one */
+	if (saved_status == NULL)
+		saved_status = gaim_savedstatus_new(NULL, primitive);
+
+	/* Set the status for each account */
+	gaim_savedstatus_activate(saved_status);
+}
+
+static void
+activate_saved_status_cb(GtkMenuItem *menuitem, gpointer user_data)
+{
+	time_t creation_time;
+	GaimSavedStatus *saved_status;
+
+	creation_time = GPOINTER_TO_INT(user_data);
+	saved_status = gaim_savedstatus_find_by_creation_time(creation_time);
+	if (saved_status != NULL)
+		gaim_savedstatus_activate(saved_status);
+}
+
+static GtkWidget *
+new_menu_item_with_gaim_icon(GtkWidget *menu, const char *str, GaimStatusPrimitive primitive, GtkSignalFunc sf, gpointer data, guint accel_key, guint accel_mods, char *mod)
+{
+	GtkWidget *menuitem;
+	GdkPixbuf *pixbuf;
+	GtkWidget *image;
+
+	menuitem = gtk_image_menu_item_new_with_mnemonic(str);
+
+	if (menu)
+		gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+
+	if (sf)
+		g_signal_connect(G_OBJECT(menuitem), "activate", sf, data);
+
+	pixbuf = gaim_gtk_create_gaim_icon_with_status(primitive, 0.5);
+	image = gtk_image_new_from_pixbuf(pixbuf);
+	g_object_unref(pixbuf);
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
+
+	gtk_widget_show_all(menuitem);
+
+	return menuitem;
+}
+
+static GtkWidget *
+docklet_status_submenu()
+{
+	GtkWidget *submenu, *menuitem;
+	GList *popular_statuses, *cur;
+
+	submenu = gtk_menu_new();
+	menuitem = gtk_menu_item_new_with_label(_("Change Status"));
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
+
+	new_menu_item_with_gaim_icon(submenu, _("Available"),
+		GAIM_STATUS_AVAILABLE, G_CALLBACK(activate_status_primitive_cb),
+		GINT_TO_POINTER(GAIM_STATUS_AVAILABLE), 0, 0, NULL);
+
+	new_menu_item_with_gaim_icon(submenu, _("Away"),
+		GAIM_STATUS_AWAY, G_CALLBACK(activate_status_primitive_cb),
+		GINT_TO_POINTER(GAIM_STATUS_AWAY), 0, 0, NULL);
+
+	new_menu_item_with_gaim_icon(submenu, _("Invisible"),
+		GAIM_STATUS_INVISIBLE, G_CALLBACK(activate_status_primitive_cb),
+		GINT_TO_POINTER(GAIM_STATUS_INVISIBLE), 0, 0, NULL);
+
+	new_menu_item_with_gaim_icon(submenu, _("Offline"),
+		GAIM_STATUS_OFFLINE, G_CALLBACK(activate_status_primitive_cb),
+		GINT_TO_POINTER(GAIM_STATUS_OFFLINE), 0, 0, NULL);
+
+	popular_statuses = gaim_savedstatuses_get_popular(6);
+	if (popular_statuses != NULL)
+		gaim_separator(submenu);
+	for (cur = popular_statuses; cur != NULL; cur = cur->next)
+	{
+		GaimSavedStatus *saved_status = cur->data;
+		time_t creation_time = gaim_savedstatus_get_creation_time(saved_status);
+		new_menu_item_with_gaim_icon(submenu,
+			gaim_savedstatus_get_title(saved_status),
+			gaim_savedstatus_get_type(saved_status), G_CALLBACK(activate_saved_status_cb),
+			GINT_TO_POINTER(creation_time), 0, 0, NULL);
+	}
+	g_list_free(popular_statuses);
+
+	gaim_separator(submenu);
+
+	new_menu_item_with_gaim_icon(submenu, _("New..."), GAIM_STATUS_AVAILABLE, G_CALLBACK(show_custom_status_editor_cb), NULL, 0, 0, NULL);
+	new_menu_item_with_gaim_icon(submenu, _("Saved..."), GAIM_STATUS_AVAILABLE, G_CALLBACK(gaim_gtk_status_window_show), NULL, 0, 0, NULL);
+
+	return menuitem;
+}
+
+static void
+docklet_menu() {
+	static GtkWidget *menu = NULL;
+	GtkWidget *menuitem;
+
+	if (menu) {
+		gtk_widget_destroy(menu);
+	}
+
+	menu = gtk_menu_new();
+
+	menuitem = gtk_check_menu_item_new_with_label(_("Show Buddy List"));
+	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), gaim_prefs_get_bool("/gaim/gtk/blist/list_visible"));
+	g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(docklet_toggle_blist), NULL);
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+
+	menuitem = gtk_menu_item_new_with_label(_("Unread Messages"));
+
+	if (status == DOCKLET_STATUS_ONLINE_PENDING || status == DOCKLET_STATUS_AWAY_PENDING) {
+		GtkWidget *submenu = gtk_menu_new();
+		GList *l = get_pending_list(0);
+		if (l == NULL) {
+			gtk_widget_set_sensitive(menuitem, FALSE);
+			gaim_debug_warning("docklet",
+				"status indicates messages pending, but no conversations with unseen messages were found.");
+		} else {
+			gaim_gtk_conversations_fill_menu(submenu, l);
+			g_list_free(l);
+			gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
+		}
+	} else {
+		gtk_widget_set_sensitive(menuitem, FALSE);
+	}
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+
+	gaim_separator(menu);
+
+	menuitem = gaim_new_item_from_stock(menu, _("New Message..."), GAIM_STOCK_IM, G_CALLBACK(gaim_gtkdialogs_im), NULL, 0, 0, NULL);
+	if (status == DOCKLET_STATUS_OFFLINE)
+		gtk_widget_set_sensitive(menuitem, FALSE);
+
+	menuitem = docklet_status_submenu();
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+
+	gaim_separator(menu);
+
+	gaim_new_item_from_stock(menu, _("Accounts"), GAIM_STOCK_ACCOUNTS, G_CALLBACK(gaim_gtk_accounts_window_show), NULL, 0, 0, NULL);
+	gaim_new_item_from_stock(menu, _("Plugins"), GAIM_STOCK_PLUGIN, G_CALLBACK(gaim_gtk_plugin_dialog_show), NULL, 0, 0, NULL);
+	gaim_new_item_from_stock(menu, _("Preferences"), GTK_STOCK_PREFERENCES, G_CALLBACK(gaim_gtk_prefs_show), NULL, 0, 0, NULL);
+
+	gaim_separator(menu);
+
+	menuitem = gtk_check_menu_item_new_with_label(_("Mute Sounds"));
+	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), gaim_prefs_get_bool("/gaim/gtk/sound/mute"));
+	if (!strcmp(gaim_prefs_get_string("/gaim/gtk/sound/method"), "none"))
+		gtk_widget_set_sensitive(GTK_WIDGET(menuitem), FALSE);
+	g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(docklet_toggle_mute), NULL);
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+
+	gaim_separator(menu);
+
+	/* TODO: need a submenu to change status, this needs to "link" 
+	 * to the status in the buddy list gtkstatusbox
+	 */
+
+	gaim_new_item_from_stock(menu, _("Quit"), GTK_STOCK_QUIT, G_CALLBACK(gaim_core_quit), NULL, 0, 0, NULL);
+
+#ifdef _WIN32
+	g_signal_connect(menu, "leave-notify-event", G_CALLBACK(docklet_menu_leave_enter), NULL);
+	g_signal_connect(menu, "enter-notify-event", G_CALLBACK(docklet_menu_leave_enter), NULL);
+#endif
+	gtk_widget_show_all(menu);
+	gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
+				   ui_ops->position_menu,
+				   NULL, 0, gtk_get_current_event_time());
+}
+
+/**************************************************************************
+ * public api for ui_ops
+ **************************************************************************/
+void
+gaim_gtk_docklet_clicked(int button_type)
+{
+	switch (button_type) {
+		case 1:
+			if (status == DOCKLET_STATUS_ONLINE_PENDING || status == DOCKLET_STATUS_AWAY_PENDING) {
+				GList *l = get_pending_list(1);
+				if (l != NULL) {
+					gaim_gtkconv_present_conversation((GaimConversation *)l->data);
+					g_list_free(l);
+				}
+			} else {
+				gaim_gtk_blist_toggle_visibility();
+			}
+			break;
+		case 3:
+			docklet_menu();
+			break;
+	}
+}
+
+void
+gaim_gtk_docklet_embedded()
+{
+	if (!visibility_manager) {
+		gaim_gtk_blist_visibility_manager_add();
+		visibility_manager = TRUE;
+	}
+	docklet_update_status();
+	if (ui_ops && ui_ops->update_icon)
+		ui_ops->update_icon(status);
+}
+
+void
+gaim_gtk_docklet_remove()
+{
+	if (visibility_manager) {
+		gaim_gtk_blist_visibility_manager_remove();
+		visibility_manager = FALSE;
+	}
+}
+
+void
+gaim_gtk_docklet_set_ui_ops(struct docklet_ui_ops *ops)
+{
+	ui_ops = ops;
+}
+
+void*
+gaim_gtk_docklet_get_handle()
+{
+	static int i;
+	return &i;
+}
+
+void 
+gaim_gtk_docklet_init()
+{
+	void *conn_handle = gaim_connections_get_handle();
+	void *conv_handle = gaim_conversations_get_handle();
+	void *accounts_handle = gaim_accounts_get_handle();
+	void *core_handle = gaim_get_core();
+	void *docklet_handle = gaim_gtk_docklet_get_handle();
+	
+	gaim_debug(GAIM_DEBUG_INFO, "docklet", "plugin loaded\n");
+
+        gaim_prefs_add_none("/plugins/gtk/docklet");
+        gaim_prefs_add_string("/plugins/gtk/docklet/blink_im", "hidden");
+        gaim_prefs_add_string("/plugins/gtk/docklet/blink_chat", "never");
+	
+	docklet_ui_init();
+	if (ui_ops && ui_ops->create)
+		ui_ops->create();
+	gaim_signal_connect(conn_handle, "signed-on",
+	    		    docklet_handle, GAIM_CALLBACK(docklet_signed_on_cb), NULL);
+	gaim_signal_connect(conn_handle, "signed-off",
+			    docklet_handle, GAIM_CALLBACK(docklet_signed_off_cb), NULL);
+	gaim_signal_connect(accounts_handle, "account-status-changed",
+			    docklet_handle, GAIM_CALLBACK(docklet_update_status_cb), NULL);
+	gaim_signal_connect(conv_handle, "received-im-msg",
+			    docklet_handle, GAIM_CALLBACK(docklet_update_status_cb), NULL);
+	gaim_signal_connect(conv_handle, "conversation-created",
+			    docklet_handle, GAIM_CALLBACK(docklet_update_status_cb), NULL);
+	gaim_signal_connect(conv_handle, "deleting-conversation",
+			    docklet_handle, GAIM_CALLBACK(docklet_update_status_cb), NULL);
+	gaim_signal_connect(conv_handle, "conversation-updated",
+			    docklet_handle, GAIM_CALLBACK(docklet_conv_updated_cb), NULL);
+
+	gaim_signal_connect(core_handle, "quitting",
+						NULL, GAIM_CALLBACK(gaim_quit_cb), NULL);
+
+/*	gaim_prefs_connect_callback(plugin, "/plugins/gtk/docklet/blink_im",
+								docklet_prefs_cb, NULL);
+	gaim_prefs_connect_callback(plugin, "/plugins/gtk/docklet/blink_chat",
+								docklet_prefs_cb, NULL);
+*/
+	enable_join_chat = online_account_supports_chat();
+}
+
+void
+gaim_gtk_docklet_uninit()
+{
+	if (ui_ops && ui_ops->destroy)
+		ui_ops->destroy();
+}
+
+static GtkWidget *
+plugin_config_frame(GaimPlugin *plugin)
+{
+	GtkWidget *frame;
+	GtkWidget *vbox;
+	GtkSizeGroup *sg;
+	GtkWidget *dd;
+
+	frame = gtk_vbox_new(FALSE, 18);
+	gtk_container_set_border_width(GTK_CONTAINER(frame), 12);
+
+	vbox = gaim_gtk_make_frame(frame, _("Blink tray icon for unread..."));
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+
+	dd = gaim_gtk_prefs_dropdown(vbox, _("_Instant Messages:"),
+							GAIM_PREF_STRING, "/plugins/gtk/docklet/blink_im",
+							_("Never"), "never",
+							_("In hidden conversations"), "hidden",
+							_("Always"), "always",
+							NULL);
+	gtk_size_group_add_widget(sg, dd);
+
+	dd = gaim_gtk_prefs_dropdown(vbox, _("C_hat Messages:"),
+							GAIM_PREF_STRING, "/plugins/gtk/docklet/blink_chat",
+							_("Never"), "never",
+							_("When my nick is said"), "nick",
+							_("Always"), "always",
+							NULL);
+	gtk_size_group_add_widget(sg, dd);
+
+	gtk_widget_show_all(frame);
+	return frame;
+}
+
+static GaimGtkPluginUiInfo ui_info =
+{
+	plugin_config_frame,
+	0 /* page_num (Reserved) */
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gtk/gtkdocklet.h	Thu Oct 05 23:24:00 2006 +0000
@@ -0,0 +1,62 @@
+/* 
+ * System tray icon (aka docklet) plugin for Gaim
+ * 
+ * Copyright (C) 2002-3 Robert McQueen <robot101@debian.org>
+ * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com>
+ * Inspired by a similar plugin by:
+ *  John (J5) Palmieri <johnp@martianrock.com>
+ * 
+ * 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 _GTKDOCKLET_H_
+#define _GTKDOCKLET_H_
+
+typedef enum
+{
+	DOCKLET_STATUS_OFFLINE,
+	DOCKLET_STATUS_ONLINE,
+	DOCKLET_STATUS_ONLINE_PENDING,
+	DOCKLET_STATUS_AWAY,
+	DOCKLET_STATUS_AWAY_PENDING,
+	DOCKLET_STATUS_CONNECTING
+} DockletStatus;
+
+struct docklet_ui_ops
+{
+	void (*create)(void);
+	void (*destroy)(void);
+	void (*update_icon)(DockletStatus);
+	void (*blank_icon)(void);
+	void (*set_tooltip)(gchar *);
+	GtkMenuPositionFunc position_menu;
+};
+
+
+/* functions in docklet.c */
+void gaim_gtk_docklet_clicked(int);
+void gaim_gtk_docklet_embedded(void);
+void gaim_gtk_docklet_remove(void);
+void gaim_gtk_docklet_set_ui_ops(struct docklet_ui_ops *);
+void gaim_gtk_docklet_unload(void);
+void gaim_gtk_docklet_init();
+void gaim_gtk_docklet_uninit();
+void*gaim_gtk_docklet_get_handle();
+
+/* function in docklet-{x11,win32}.c */
+void docklet_ui_init(void);
+
+#endif /* _GTKDOCKLET_H_ */
--- a/gtk/gtkmain.c	Wed Oct 04 20:31:44 2006 +0000
+++ b/gtk/gtkmain.c	Thu Oct 05 23:24:00 2006 +0000
@@ -46,6 +46,7 @@
 #include "gtkconv.h"
 #include "gtkdebug.h"
 #include "gtkdialogs.h"
+#include "gtkdocklet.h"
 #include "gtkeventloop.h"
 #include "gtkft.h"
 #include "gtkidle.h"
@@ -310,6 +311,7 @@
 	gaim_gtk_conversations_uninit();
 	gaim_gtk_status_uninit();
 	gaim_gtk_blist_uninit();
+	gaim_gtk_docklet_uninit();
 	gaim_gtk_connection_uninit();
 	gaim_gtk_account_uninit();
 	gaim_gtk_xfers_uninit();
@@ -719,6 +721,7 @@
 
 	/* load plugins we had when we quit */
 	gaim_plugins_load_saved("/gaim/gtk/plugins/loaded");
+	gaim_gtk_docklet_init();
 
 	/* TODO: Move pounces loading into gaim_pounces_init() */
 	gaim_pounces_load();
--- a/gtk/plugins/docklet/Makefile.am	Wed Oct 04 20:31:44 2006 +0000
+++ b/gtk/plugins/docklet/Makefile.am	Thu Oct 05 23:24:00 2006 +0000
@@ -1,8 +1,4 @@
-EXTRA_DIST = \
-		Makefile.mingw   \
-		docklet-win32.c  \
-		MinimizeToTray.c \
-		MinimizeToTray.h
+EXTRA_DIST = Makefile.mingw   
 
 plugindir = $(libdir)/gaim
 
@@ -12,12 +8,7 @@
 
 plugin_LTLIBRARIES = docklet.la
 
-docklet_la_SOURCES = \
-	eggtrayicon.h \
-	eggtrayicon.c \
-	docklet.h \
-	docklet.c \
-	docklet-x11.c
+docklet_la_SOURCES = docklet.c 
 
 docklet_la_LIBADD = $(GTK_LIBS)
 
--- a/gtk/plugins/docklet/docklet-win32.c	Wed Oct 04 20:31:44 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,263 +0,0 @@
-/*
- * System tray icon (aka docklet) plugin for Gaim
- *
- * Copyright (C) 2002-3 Robert McQueen <robot101@debian.org>
- * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com>
- * Inspired by a similar plugin by:
- *  John (J5) Palmieri <johnp@martianrock.com>
- * 
- * 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.
- */
-
-#include <windows.h>
-#include <gdk/gdkwin32.h>
-#include <gdk/gdk.h>
-
-#include "internal.h"
-#include "gtkblist.h"
-#include "gtkprefs.h"
-#include "debug.h"
-
-#include "gaim.h"
-#include "gtkdialogs.h"
-
-#include "resource.h"
-#include "MinimizeToTray.h"
-#include "gtkwin32dep.h"
-#include "docklet.h"
-
-/*
- *  DEFINES, MACROS & DATA TYPES
- */
-#define WM_TRAYMESSAGE WM_USER /* User defined WM Message */
-
-/*
- *  LOCALS
- */
-static HWND systray_hwnd=0;
-static HICON sysicon_disconn=0;
-static HICON sysicon_conn=0;
-static HICON sysicon_away=0;
-static HICON sysicon_pend=0;
-static HICON sysicon_awypend=0;
-static HICON sysicon_blank=0;
-static NOTIFYICONDATA wgaim_nid;
-
-
-static LRESULT CALLBACK systray_mainmsg_handler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
-	static UINT taskbarRestartMsg; /* static here means value is kept across multiple calls to this func */
-
-	switch(msg) {
-	case WM_CREATE:
-		gaim_debug(GAIM_DEBUG_INFO, "tray icon", "WM_CREATE\n");
-		taskbarRestartMsg = RegisterWindowMessage("TaskbarCreated");
-		break;
-		
-	case WM_TIMER:
-		gaim_debug(GAIM_DEBUG_INFO, "tray icon", "WM_TIMER\n");
-		break;
-
-	case WM_DESTROY:
-		gaim_debug(GAIM_DEBUG_INFO, "tray icon", "WM_DESTROY\n");
-		break;
-
-	case WM_TRAYMESSAGE:
-	{
-		int type = 0;
-
-		/* We'll use Double Click - Single click over on linux */
-		if( lparam == WM_LBUTTONDBLCLK )
-			type = 1;
-		else if( lparam == WM_MBUTTONUP )
-			type = 2;
-		else if( lparam == WM_RBUTTONUP )
-			type = 3;
-		else
-			break;
-
-		docklet_clicked(type);
-		break;
-	}
-	default: 
-		if (msg == taskbarRestartMsg) {
-			/* explorer crashed and left us hanging... 
-			   This will put the systray icon back in it's place, when it restarts */
-			Shell_NotifyIcon(NIM_ADD,&wgaim_nid);
-		}
-		break;
-	}/* end switch */
-
-	return DefWindowProc(hwnd, msg, wparam, lparam);
-}
-
-/* Create hidden window to process systray messages */
-static HWND systray_create_hiddenwin() {
-	WNDCLASSEX wcex;
-	TCHAR wname[32];
-
-	strcpy(wname, "GaimWin");
-
-	wcex.cbSize = sizeof(WNDCLASSEX);
-
-	wcex.style		= 0;
-	wcex.lpfnWndProc	= (WNDPROC)systray_mainmsg_handler;
-	wcex.cbClsExtra		= 0;
-	wcex.cbWndExtra		= 0;
-	wcex.hInstance		= gtkwgaim_hinstance();
-	wcex.hIcon		= NULL;
-	wcex.hCursor		= NULL,
-	wcex.hbrBackground	= NULL;
-	wcex.lpszMenuName	= NULL;
-	wcex.lpszClassName	= wname;
-	wcex.hIconSm		= NULL;
-
-	RegisterClassEx(&wcex);
-
-	/* Create the window */
-	return (CreateWindow(wname, "", 0, 0, 0, 0, 0, GetDesktopWindow(), NULL, gtkwgaim_hinstance(), 0));
-}
-
-static void systray_init_icon(HWND hWnd, HICON icon) {
-	ZeroMemory(&wgaim_nid,sizeof(wgaim_nid));
-	wgaim_nid.cbSize=sizeof(NOTIFYICONDATA);
-	wgaim_nid.hWnd=hWnd;
-	wgaim_nid.uID=0;
-	wgaim_nid.uFlags=NIF_ICON | NIF_MESSAGE | NIF_TIP;
-	wgaim_nid.uCallbackMessage=WM_TRAYMESSAGE;
-	wgaim_nid.hIcon=icon;
-	lstrcpy(wgaim_nid.szTip, "Gaim");
-	Shell_NotifyIcon(NIM_ADD,&wgaim_nid);
-	docklet_embedded();
-}
-
-static void systray_change_icon(HICON icon) {
-	wgaim_nid.hIcon = icon;
-	Shell_NotifyIcon(NIM_MODIFY,&wgaim_nid);
-}
-
-static void systray_remove_nid(void) {
-	Shell_NotifyIcon(NIM_DELETE,&wgaim_nid);
-}
-
-static void wgaim_tray_update_icon(DockletStatus icon) {
-	switch (icon) {
-		case DOCKLET_STATUS_OFFLINE:
-			systray_change_icon(sysicon_disconn);
-			break;
-		case DOCKLET_STATUS_CONNECTING:
-			break;
-		case DOCKLET_STATUS_ONLINE:
-			systray_change_icon(sysicon_conn);
-			break;
-		case DOCKLET_STATUS_ONLINE_PENDING:
-			systray_change_icon(sysicon_pend);
-			break;
-		case DOCKLET_STATUS_AWAY:
-			systray_change_icon(sysicon_away);
-			break;
-		case DOCKLET_STATUS_AWAY_PENDING:
-			systray_change_icon(sysicon_awypend);
-			break;
-	}
-}
-
-static void wgaim_tray_blank_icon() {
-	systray_change_icon(sysicon_blank);
-}
-
-static void wgaim_tray_set_tooltip(gchar *tooltip) {
-	if (tooltip) {
-		char *locenc = NULL;
-		locenc = g_locale_from_utf8(tooltip, -1, NULL, NULL, NULL);
-		lstrcpyn(wgaim_nid.szTip, locenc, sizeof(wgaim_nid.szTip)/sizeof(TCHAR));
-		g_free(locenc);
-	} else {
-		lstrcpy(wgaim_nid.szTip, "Gaim");
-	}
-	Shell_NotifyIcon(NIM_MODIFY, &wgaim_nid);
-}
-
-void wgaim_tray_minimize(GaimGtkBuddyList *gtkblist) {
-	MinimizeWndToTray(GDK_WINDOW_HWND(gtkblist->window->window));
-}
-
-void wgaim_tray_maximize(GaimGtkBuddyList *gtkblist) {
-	RestoreWndFromTray(GDK_WINDOW_HWND(gtkblist->window->window));
-}
-
-
-static void wgaim_tray_create() {
-	OSVERSIONINFO osinfo;
-	/* dummy window to process systray messages */
-	systray_hwnd = systray_create_hiddenwin();
-
-	osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-	GetVersionEx(&osinfo);
-
-	/* Load icons, and init systray notify icon
-	 * NOTE: Windows < XP only supports displaying 4-bit images in the Systray,
-	 *  2K and ME will use the highest color depth that the desktop will support,
-	 *  but will scale it back to 4-bits for display.
-	 * That is why we use custom 4-bit icons for pre XP Windowses */
-	if ((osinfo.dwMajorVersion == 5 && osinfo.dwMinorVersion > 0) ||
-		(osinfo.dwMajorVersion >= 6))
-	{
-		sysicon_disconn = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_OFFLINE_TRAY_ICON), IMAGE_ICON, 16, 16, 0);
-		sysicon_conn = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_TRAY_ICON), IMAGE_ICON, 16, 16, 0);
-		sysicon_away = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_AWAY_TRAY_ICON), IMAGE_ICON, 16, 16, 0);
-		sysicon_pend = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_PEND_TRAY_ICON), IMAGE_ICON, 16, 16, 0);
-		sysicon_awypend = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_AWAYPEND_TRAY_ICON), IMAGE_ICON, 16, 16, 0);
-	} else {
-		sysicon_disconn = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_OFFLINE_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0);
-		sysicon_conn = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0);
-		sysicon_away = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_AWAY_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0);
-		sysicon_pend = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_PEND_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0);
-		sysicon_awypend = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_AWAYPEND_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0);
-	}
-	sysicon_blank = (HICON)LoadImage(gtkwgaim_hinstance(), MAKEINTRESOURCE(GAIM_BLANK_TRAY_ICON), IMAGE_ICON, 16, 16, 0);
-
-	/* Create icon in systray */
-	systray_init_icon(systray_hwnd, sysicon_disconn);
-
-	gaim_signal_connect(gaim_gtk_blist_get_handle(), "gtkblist-hiding", 
-			&handle, GAIM_CALLBACK(wgaim_tray_minimize), NULL);
-	gaim_signal_connect(gaim_gtk_blist_get_handle(), "gtkblist-unhiding", 
-			&handle, GAIM_CALLBACK(wgaim_tray_maximize), NULL);
-
-	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "created\n");
-}
-
-static void wgaim_tray_destroy() {
-	gaim_signals_disconnect_by_handle(&handle);
-	systray_remove_nid();
-	DestroyWindow(systray_hwnd);
-	docklet_remove();
-}
-
-static struct docklet_ui_ops wgaim_tray_ops =
-{
-	wgaim_tray_create,
-	wgaim_tray_destroy,
-	wgaim_tray_update_icon,
-	wgaim_tray_blank_icon,
-	wgaim_tray_set_tooltip,
-	NULL
-};
-
-/* Used by docklet's plugin load func */
-void docklet_ui_init() {
-	docklet_set_ui_ops(&wgaim_tray_ops);
-}
--- a/gtk/plugins/docklet/docklet-x11.c	Wed Oct 04 20:31:44 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,305 +0,0 @@
-/*
- * System tray icon (aka docklet) plugin for Gaim
- *
- * Copyright (C) 2002-3 Robert McQueen <robot101@debian.org>
- * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com>
- * Inspired by a similar plugin by:
- *  John (J5) Palmieri <johnp@martianrock.com>
- * 
- * 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.
- */
-
-#include "internal.h"
-#include "gtkgaim.h"
-#include "debug.h"
-#include "gaimstock.h"
-
-#include "gaim.h"
-#include "gtkdialogs.h"
-
-#include "eggtrayicon.h"
-#include "docklet.h"
-
-#define EMBED_TIMEOUT 5000
-
-/* globals */
-static EggTrayIcon *docklet = NULL;
-static GtkWidget *image = NULL;
-static GtkTooltips *tooltips = NULL;
-static GdkPixbuf *blank_icon = NULL;
-static int embed_timeout = 0;
-
-/* protos */
-static void docklet_x11_create(void);
-
-static gboolean
-docklet_x11_create_cb()
-{
-	docklet_x11_create();
-
-	return FALSE; /* for when we're called by the glib idle handler */
-}
-
-static void
-docklet_x11_embedded_cb(GtkWidget *widget, void *data)
-{
-	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "embedded\n");
-	
-	g_source_remove(embed_timeout);
-	embed_timeout = 0;
-	docklet_embedded();
-}
-
-static void
-docklet_x11_destroyed_cb(GtkWidget *widget, void *data)
-{
-	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "destroyed\n");
-
-	docklet_remove();
-
-	g_object_unref(G_OBJECT(docklet));
-	docklet = NULL;
-
-	g_idle_add(docklet_x11_create_cb, &handle);
-}
-
-static void
-docklet_x11_clicked_cb(GtkWidget *button, GdkEventButton *event, void *data)
-{
-	if (event->type != GDK_BUTTON_PRESS)
-		return;
-
-	docklet_clicked(event->button);
-}
-
-static void
-docklet_x11_update_icon(DockletStatus icon)
-{
-	const gchar *icon_name = NULL;
-
-	g_return_if_fail(image != NULL);
-
-	switch (icon) {
-		case DOCKLET_STATUS_OFFLINE:
-			icon_name = GAIM_STOCK_ICON_OFFLINE;
-			break;
-		case DOCKLET_STATUS_CONNECTING:
-			icon_name = GAIM_STOCK_ICON_CONNECT;
-			break;
-		case DOCKLET_STATUS_ONLINE:
-			icon_name = GAIM_STOCK_ICON_ONLINE;
-			break;
-		case DOCKLET_STATUS_ONLINE_PENDING:
-			icon_name = GAIM_STOCK_ICON_ONLINE_MSG;
-			break;
-		case DOCKLET_STATUS_AWAY:
-			icon_name = GAIM_STOCK_ICON_AWAY;
-			break;
-		case DOCKLET_STATUS_AWAY_PENDING:
-			icon_name = GAIM_STOCK_ICON_AWAY_MSG;
-			break;
-	}
-
-	if(icon_name)
-		gtk_image_set_from_stock(GTK_IMAGE(image), icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR);
-
-#if 0
-	GdkPixbuf *p;
-	GdkBitmap *mask = NULL;
-
-	p = gtk_widget_render_icon(GTK_WIDGET(image), icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
-
-	if (p && (gdk_pixbuf_get_colorspace(p) == GDK_COLORSPACE_RGB) && (gdk_pixbuf_get_bits_per_sample(p) == 8)
-	   && (gdk_pixbuf_get_has_alpha(p)) && (gdk_pixbuf_get_n_channels(p) == 4)) {
-		int len = gdk_pixbuf_get_width(p) * gdk_pixbuf_get_height(p);
-		guchar *data = gdk_pixbuf_get_pixels(p);
-		guchar *bitmap = g_malloc((len / 8) + 1);
-		int i;
-
-		for (i = 0; i < len; i++)
-			if (data[i*4 + 3] > 55)
-				bitmap[i/8] |= 1 << i % 8;
-			else
-				bitmap[i/8] &= ~(1 << i % 8);
-
-		mask = gdk_bitmap_create_from_data(GDK_DRAWABLE(GTK_WIDGET(image)->window), bitmap, gdk_pixbuf_get_width(p), gdk_pixbuf_get_height(p));
-		g_free(bitmap);
-	}
-
-	if (mask)
-		gdk_window_shape_combine_mask(image->window, mask, 0, 0);
-
-	g_object_unref(G_OBJECT(p));
-#endif
-}
-
-static void
-docklet_x11_blank_icon()
-{
-	if (!blank_icon) {
-		gint width, height;
-
-		gtk_icon_size_lookup(GTK_ICON_SIZE_LARGE_TOOLBAR, &width, &height);
-		blank_icon = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
-		gdk_pixbuf_fill(blank_icon, 0);
-	}
-
-	gtk_image_set_from_pixbuf(GTK_IMAGE(image), blank_icon);
-}
-
-static void
-docklet_x11_set_tooltip(gchar *tooltip)
-{
-	if (!tooltips)
-		tooltips = gtk_tooltips_new();
-
-	/* image->parent is a GtkEventBox */
-	if (tooltip) {
-		gtk_tooltips_enable(tooltips);
-		gtk_tooltips_set_tip(tooltips, image->parent, tooltip, NULL);
-	} else {
-		gtk_tooltips_set_tip(tooltips, image->parent, "", NULL);
-		gtk_tooltips_disable(tooltips);
-	}
-}
-
-#if GTK_CHECK_VERSION(2,2,0)
-static void
-docklet_x11_position_menu(GtkMenu *menu, int *x, int *y, gboolean *push_in,
-						  gpointer user_data)
-{
-	GtkWidget *widget = GTK_WIDGET(docklet);
-	GtkRequisition req;
-	gint menu_xpos, menu_ypos;
-
-	gtk_widget_size_request(GTK_WIDGET(menu), &req);
-	gdk_window_get_origin(widget->window, &menu_xpos, &menu_ypos);
-
-	menu_xpos += widget->allocation.x;
-	menu_ypos += widget->allocation.y;
-
-	if (menu_ypos > gdk_screen_get_height(gtk_widget_get_screen(widget)) / 2)
-		menu_ypos -= req.height;
-	else
-		menu_ypos += widget->allocation.height;
-
-	*x = menu_xpos;
-	*y = menu_ypos;
-
-	*push_in = TRUE;
-}
-#endif
-
-static void
-docklet_x11_destroy()
-{
-	g_return_if_fail(docklet != NULL);
-
-	docklet_remove();
-
-	g_signal_handlers_disconnect_by_func(G_OBJECT(docklet), G_CALLBACK(docklet_x11_destroyed_cb), NULL);
-	gtk_widget_destroy(GTK_WIDGET(docklet));
-
-	g_object_unref(G_OBJECT(docklet));
-	docklet = NULL;
-
-	if (blank_icon)
-		g_object_unref(G_OBJECT(blank_icon));
-	blank_icon = NULL;
-
-	image = NULL;
-
-	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "destroyed\n");
-}
-
-static gboolean
-docklet_x11_embed_timeout_cb()
-{
-	/* The docklet was not embedded within the timeout.
-	 * Remove it as a visibility manager, but leave the plugin
-	 * loaded so that it can embed automatically if/when a notification
-	 * area becomes available.
-	 */
-	gaim_debug_info("tray icon", "failed to embed within timeout\n");
-	docklet_remove();
-
-	return FALSE;
-}
-
-static void
-docklet_x11_create()
-{
-	GtkWidget *box;
-
-	if (docklet) {
-		/* if this is being called when a tray icon exists, it's because
-		   something messed up. try destroying it before we proceed,
-		   although docklet_refcount may be all hosed. hopefully won't happen. */
-		gaim_debug(GAIM_DEBUG_WARNING, "tray icon", "trying to create icon but it already exists?\n");
-		docklet_x11_destroy();
-	}
-
-	docklet = egg_tray_icon_new("Gaim");
-	box = gtk_event_box_new();
-	image = gtk_image_new();
-
-	g_signal_connect(G_OBJECT(docklet), "embedded", G_CALLBACK(docklet_x11_embedded_cb), NULL);
-	g_signal_connect(G_OBJECT(docklet), "destroy", G_CALLBACK(docklet_x11_destroyed_cb), NULL);
-	g_signal_connect(G_OBJECT(box), "button-press-event", G_CALLBACK(docklet_x11_clicked_cb), NULL);
-
-	gtk_container_add(GTK_CONTAINER(box), image);
-	gtk_container_add(GTK_CONTAINER(docklet), box);
-
-	if (!gtk_check_version(2,4,0))
-		g_object_set(G_OBJECT(box), "visible-window", FALSE, NULL);
-
-	gtk_widget_show_all(GTK_WIDGET(docklet));
-
-	/* ref the docklet before we bandy it about the place */
-	g_object_ref(G_OBJECT(docklet));
-
-	/* This is a hack to avoid a race condition between the docklet getting
-	 * embedded in the notification area and the gtkblist restoring its
-	 * previous visibility state.  If the docklet does not get embedded within
-	 * the timeout, it will be removed as a visibility manager until it does
-	 * get embedded.  Ideally, we would only call docklet_embedded() when the
-	 * icon was actually embedded.
-	 */
-	docklet_embedded();
-	embed_timeout = g_timeout_add(EMBED_TIMEOUT, docklet_x11_embed_timeout_cb, NULL);
-
-	gaim_debug(GAIM_DEBUG_INFO, "tray icon", "created\n");
-}
-
-static struct docklet_ui_ops ui_ops =
-{
-	docklet_x11_create,
-	docklet_x11_destroy,
-	docklet_x11_update_icon,
-	docklet_x11_blank_icon,
-	docklet_x11_set_tooltip,
-#if GTK_CHECK_VERSION(2,2,0)
-	docklet_x11_position_menu
-#else
-	NULL
-#endif
-};
-
-void
-docklet_ui_init()
-{
-	docklet_set_ui_ops(&ui_ops);
-}
--- a/gtk/plugins/docklet/docklet.c	Wed Oct 04 20:31:44 2006 +0000
+++ b/gtk/plugins/docklet/docklet.c	Thu Oct 05 23:24:00 2006 +0000
@@ -23,730 +23,9 @@
  */
 #include "internal.h"
 #include "gtkgaim.h"
-
+#include "gtkplugin.h"
 #include "core.h"
-#include "conversation.h"
-#include "debug.h"
-#include "prefs.h"
-#include "signals.h"
-#include "sound.h"
 #include "version.h"
 
-#include "gtkaccount.h"
-#include "gtkblist.h"
-#include "gtkconv.h"
-#include "gtkft.h"
-#include "gtkplugin.h"
-#include "gtkprefs.h"
-#include "gtksavedstatuses.h"
-#include "gtksound.h"
-#include "gtkutils.h"
-#include "gaimstock.h"
-#include "docklet.h"
-
-#include "gaim.h"
-#include "gtkdialogs.h"
-
-#define DOCKLET_PLUGIN_ID "gtk-docklet"
-
-#ifndef DOCKLET_TOOLTIP_LINE_LIMIT
-#define DOCKLET_TOOLTIP_LINE_LIMIT 5
-#endif
-
-/* globals */
-GaimPlugin *handle = NULL;
-static struct docklet_ui_ops *ui_ops = NULL;
-static DockletStatus status = DOCKLET_STATUS_OFFLINE;
-static gboolean enable_join_chat = FALSE;
-static guint docklet_blinking_timer = 0;
-static gboolean visibility_manager = FALSE;
-
-/**************************************************************************
- * docklet status and utility functions
- **************************************************************************/
-static gboolean
-docklet_blink_icon()
-{
-	static gboolean blinked = FALSE;
-	gboolean ret = FALSE; /* by default, don't keep blinking */
-
-	blinked = !blinked;
-
-	switch (status) {
-		case DOCKLET_STATUS_ONLINE_PENDING:
-		case DOCKLET_STATUS_AWAY_PENDING:
-			if (blinked) {
-				if (ui_ops && ui_ops->blank_icon)
-					ui_ops->blank_icon();
-			} else {
-				if (ui_ops && ui_ops->update_icon)
-					ui_ops->update_icon(status);
-			}
-			ret = TRUE; /* keep blinking */
-			break;
-		default:
-			docklet_blinking_timer = 0;
-			blinked = FALSE;
-			break;
-	}
-
-	return ret;
-}
-
-static GList *
-get_pending_list(guint max)
-{
-	const char *im = gaim_prefs_get_string("/plugins/gtk/docklet/blink_im");
-	const char *chat = gaim_prefs_get_string("/plugins/gtk/docklet/blink_chat");
-	GList *l_im = NULL;
-	GList *l_chat = NULL;
-
-	if (im != NULL && strcmp(im, "always") == 0) {
-		l_im = gaim_gtk_conversations_find_unseen_list(GAIM_CONV_TYPE_IM,
-													   GAIM_UNSEEN_TEXT,
-													   FALSE, max);
-	} else if (im != NULL && strcmp(im, "hidden") == 0) {
-		l_im = gaim_gtk_conversations_find_unseen_list(GAIM_CONV_TYPE_IM,
-													   GAIM_UNSEEN_TEXT,
-													   TRUE, max);
-	}
-
-	if (chat != NULL && strcmp(chat, "always") == 0) {
-		l_chat = gaim_gtk_conversations_find_unseen_list(GAIM_CONV_TYPE_CHAT,
-													   GAIM_UNSEEN_TEXT,
-													   FALSE, max);
-	} else if (chat != NULL && strcmp(chat, "nick") == 0) {
-		l_chat = gaim_gtk_conversations_find_unseen_list(GAIM_CONV_TYPE_CHAT,
-													   GAIM_UNSEEN_NICK,
-													   FALSE, max);
-	}
-
-	if (l_im != NULL && l_chat != NULL)
-		return g_list_concat(l_im, l_chat);
-	else if (l_im != NULL)
-		return l_im;
-	else
-		return l_chat;
-}
-
-static gboolean
-docklet_update_status()
-{
-	GList *convs;
-	GList *l;
-	int count;
-	DockletStatus newstatus = DOCKLET_STATUS_OFFLINE;
-	gboolean pending = FALSE;
-
-	/* determine if any ims have unseen messages */
-	convs = get_pending_list(DOCKLET_TOOLTIP_LINE_LIMIT);
-
-	if (convs != NULL) {
-		pending = TRUE;
-
-		/* set tooltip if messages are pending */
-		if (ui_ops->set_tooltip) {
-			GString *tooltip_text = g_string_new("");
-			for (l = convs, count = 0 ; l != NULL ; l = l->next, count++) {
-				if (GAIM_IS_GTK_CONVERSATION(l->data)) {
-					GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION((GaimConversation *)l->data);
-					if (count == DOCKLET_TOOLTIP_LINE_LIMIT - 1)
-						g_string_append(tooltip_text, _("Right-click for more unread messages...\n"));
-					else
-						g_string_append_printf(tooltip_text,
-							ngettext("%d unread message from %s\n", "%d unread messages from %s\n", gtkconv->unseen_count),
-							gtkconv->unseen_count,
-							gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)));
-				}
-			}
-
-			/* get rid of the last newline */
-			if (tooltip_text->len > 0)
-				tooltip_text = g_string_truncate(tooltip_text, tooltip_text->len - 1);
-
-			ui_ops->set_tooltip(tooltip_text->str);
-
-			g_string_free(tooltip_text, TRUE);
-		}
-
-		g_list_free(convs);
-
-	} else if (ui_ops->set_tooltip) {
-		ui_ops->set_tooltip(NULL);
-	}
-
-	/* iterate through all accounts and determine which
-	 * status to show in the tray icon based on the following
-	 * ranks (highest encountered rank will be used):
-	 *
-	 *     1) OFFLINE
-	 *     2) ONLINE
-	 *     3) ONLINE_PENDING
-	 *     4) AWAY
-	 *     5) AWAY_PENDING
-	 *     6) CONNECTING
-	 */
-	for(l = gaim_accounts_get_all(); l != NULL; l = l->next) {
-		DockletStatus tmpstatus = DOCKLET_STATUS_OFFLINE;
-
-		GaimAccount *account = (GaimAccount*)l->data;
-		GaimStatus *account_status;
-
-		if (!gaim_account_get_enabled(account, GAIM_GTK_UI))
-			continue;
-
-		if (gaim_account_is_disconnected(account))
-			continue;
-
-		account_status = gaim_account_get_active_status(account);
-
-		if (gaim_account_is_connecting(account)) {
-			tmpstatus = DOCKLET_STATUS_CONNECTING;
-		} else if (gaim_status_is_online(account_status)) {
-			if (!gaim_status_is_available(account_status)) {
-				if (pending)
-					tmpstatus = DOCKLET_STATUS_AWAY_PENDING;
-				else
-					tmpstatus = DOCKLET_STATUS_AWAY;
-			}
-			else {
-				if (pending)
-					tmpstatus = DOCKLET_STATUS_ONLINE_PENDING;
-				else
-					tmpstatus = DOCKLET_STATUS_ONLINE;
-			}
-		}
-
-		if (tmpstatus > newstatus)
-			newstatus = tmpstatus;
-	}
-
-	/* update the icon if we changed status */
-	if (status != newstatus) {
-		status = newstatus;
-
-		if (ui_ops && ui_ops->update_icon)
-			ui_ops->update_icon(status);
-
-		/* and schedule the blinker function if messages are pending */
-		if ((status == DOCKLET_STATUS_ONLINE_PENDING
-				|| status == DOCKLET_STATUS_AWAY_PENDING)
-			&& docklet_blinking_timer == 0) {
-				docklet_blinking_timer = g_timeout_add(500, docklet_blink_icon, &handle);
-		}
-	}
-
-	return FALSE; /* for when we're called by the glib idle handler */
-}
-
-static gboolean
-online_account_supports_chat()
-{
-	GList *c = NULL;
-	c = gaim_connections_get_all();
-
-	while(c != NULL) {
-		GaimConnection *gc = c->data;
-		GaimPluginProtocolInfo *prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
-		if (prpl_info != NULL && prpl_info->chat_info != NULL)
-			return TRUE;
-		c = c->next;
-	}
-
-	return FALSE;
-}
-
-/**************************************************************************
- * callbacks and signal handlers
- **************************************************************************/
-static void 
-gaim_quit_cb() 
-{
-	/* TODO: confirm quit while pending */
-}
-
-static void
-docklet_update_status_cb(void *data)
-{
-	docklet_update_status();
-}
-
-static void
-docklet_prefs_cb(const char *name, GaimPrefType type,
-				 gconstpointer val, gpointer data)
-{
-	docklet_update_status();
-}
-
-static void
-docklet_conv_updated_cb(GaimConversation *conv, GaimConvUpdateType type)
-{
-	if (type == GAIM_CONV_UPDATE_UNSEEN)
-		docklet_update_status();
-}
-
-static void
-docklet_signed_on_cb(GaimConnection *gc)
-{
-	if (!enable_join_chat) {
-		if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info != NULL)
-			enable_join_chat = TRUE;
-	}
-	docklet_update_status();
-}
-
-static void
-docklet_signed_off_cb(GaimConnection *gc)
-{
-	if (enable_join_chat) {
-		if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info != NULL)
-			enable_join_chat = online_account_supports_chat();
-	}
-	docklet_update_status();
-}
-
-/**************************************************************************
- * docklet pop-up menu
- **************************************************************************/
-static void
-docklet_toggle_mute(GtkWidget *toggle, void *data)
-{
-	gaim_prefs_set_bool("/gaim/gtk/sound/mute", GTK_CHECK_MENU_ITEM(toggle)->active);
-}
-
-static void
-docklet_toggle_blist(GtkWidget *toggle, void *data)
-{
-	gaim_blist_set_visible(GTK_CHECK_MENU_ITEM(toggle)->active);
-}
-
-#ifdef _WIN32
-/* This is a workaround for a bug in windows GTK+. Clicking outside of the
-   menu does not get rid of it, so instead we get rid of it as soon as the
-   pointer leaves the menu. */
-static gboolean 
-hide_docklet_menu(gpointer data)
-{
-	if (data != NULL) {
-		gtk_menu_popdown(GTK_MENU(data));
-	}
-	return FALSE;
-}
-
-static gboolean
-docklet_menu_leave_enter(GtkWidget *menu, GdkEventCrossing *event, void *data)
-{
-	static guint hide_docklet_timer = 0;
-	if (event->type == GDK_LEAVE_NOTIFY && event->detail == GDK_NOTIFY_ANCESTOR) {
-		gaim_debug(GAIM_DEBUG_INFO, "docklet", "menu leave-notify-event\n");
-		/* Add some slop so that the menu doesn't annoyingly disappear when mousing around */
-		if (hide_docklet_timer == 0) {
-			hide_docklet_timer = gaim_timeout_add(500,
-					hide_docklet_menu, menu);
-		}
-	} else if (event->type == GDK_ENTER_NOTIFY && event->detail == GDK_NOTIFY_ANCESTOR) {
-		gaim_debug(GAIM_DEBUG_INFO, "docklet", "menu enter-notify-event\n");
-		if (hide_docklet_timer != 0) {
-			/* Cancel the hiding if we reenter */
-
-			gaim_timeout_remove(hide_docklet_timer);
-			hide_docklet_timer = 0;
-		}
-	}
-	return FALSE;
-}
-#endif
-
-static void
-show_custom_status_editor_cb(GtkMenuItem *menuitem, gpointer user_data)
-{
-	GaimSavedStatus *saved_status;
-	saved_status = gaim_savedstatus_get_current();
-	gaim_gtk_status_editor_show(FALSE,
-		gaim_savedstatus_is_transient(saved_status) ? saved_status : NULL);
-}
-
-static void
-activate_status_primitive_cb(GtkMenuItem *menuitem, gpointer user_data)
-{
-	GaimStatusPrimitive primitive;
-	GaimSavedStatus *saved_status;
-
-	primitive = GPOINTER_TO_INT(user_data);
-
-	/* Try to lookup an already existing transient saved status */
-	saved_status = gaim_savedstatus_find_transient_by_type_and_message(primitive, NULL);
-
-	/* Create a new transient saved status if we weren't able to find one */
-	if (saved_status == NULL)
-		saved_status = gaim_savedstatus_new(NULL, primitive);
-
-	/* Set the status for each account */
-	gaim_savedstatus_activate(saved_status);
-}
-
-static void
-activate_saved_status_cb(GtkMenuItem *menuitem, gpointer user_data)
-{
-	time_t creation_time;
-	GaimSavedStatus *saved_status;
 
-	creation_time = GPOINTER_TO_INT(user_data);
-	saved_status = gaim_savedstatus_find_by_creation_time(creation_time);
-	if (saved_status != NULL)
-		gaim_savedstatus_activate(saved_status);
-}
 
-static GtkWidget *
-new_menu_item_with_gaim_icon(GtkWidget *menu, const char *str, GaimStatusPrimitive primitive, GtkSignalFunc sf, gpointer data, guint accel_key, guint accel_mods, char *mod)
-{
-	GtkWidget *menuitem;
-	GdkPixbuf *pixbuf;
-	GtkWidget *image;
-
-	menuitem = gtk_image_menu_item_new_with_mnemonic(str);
-
-	if (menu)
-		gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-
-	if (sf)
-		g_signal_connect(G_OBJECT(menuitem), "activate", sf, data);
-
-	pixbuf = gaim_gtk_create_gaim_icon_with_status(primitive, 0.5);
-	image = gtk_image_new_from_pixbuf(pixbuf);
-	g_object_unref(pixbuf);
-	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
-
-	gtk_widget_show_all(menuitem);
-
-	return menuitem;
-}
-
-static GtkWidget *
-docklet_status_submenu()
-{
-	GtkWidget *submenu, *menuitem;
-	GList *popular_statuses, *cur;
-
-	submenu = gtk_menu_new();
-	menuitem = gtk_menu_item_new_with_label(_("Change Status"));
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
-
-	new_menu_item_with_gaim_icon(submenu, _("Available"),
-		GAIM_STATUS_AVAILABLE, G_CALLBACK(activate_status_primitive_cb),
-		GINT_TO_POINTER(GAIM_STATUS_AVAILABLE), 0, 0, NULL);
-
-	new_menu_item_with_gaim_icon(submenu, _("Away"),
-		GAIM_STATUS_AWAY, G_CALLBACK(activate_status_primitive_cb),
-		GINT_TO_POINTER(GAIM_STATUS_AWAY), 0, 0, NULL);
-
-	new_menu_item_with_gaim_icon(submenu, _("Invisible"),
-		GAIM_STATUS_INVISIBLE, G_CALLBACK(activate_status_primitive_cb),
-		GINT_TO_POINTER(GAIM_STATUS_INVISIBLE), 0, 0, NULL);
-
-	new_menu_item_with_gaim_icon(submenu, _("Offline"),
-		GAIM_STATUS_OFFLINE, G_CALLBACK(activate_status_primitive_cb),
-		GINT_TO_POINTER(GAIM_STATUS_OFFLINE), 0, 0, NULL);
-
-	popular_statuses = gaim_savedstatuses_get_popular(6);
-	if (popular_statuses != NULL)
-		gaim_separator(submenu);
-	for (cur = popular_statuses; cur != NULL; cur = cur->next)
-	{
-		GaimSavedStatus *saved_status = cur->data;
-		time_t creation_time = gaim_savedstatus_get_creation_time(saved_status);
-		new_menu_item_with_gaim_icon(submenu,
-			gaim_savedstatus_get_title(saved_status),
-			gaim_savedstatus_get_type(saved_status), G_CALLBACK(activate_saved_status_cb),
-			GINT_TO_POINTER(creation_time), 0, 0, NULL);
-	}
-	g_list_free(popular_statuses);
-
-	gaim_separator(submenu);
-
-	new_menu_item_with_gaim_icon(submenu, _("New..."), GAIM_STATUS_AVAILABLE, G_CALLBACK(show_custom_status_editor_cb), NULL, 0, 0, NULL);
-	new_menu_item_with_gaim_icon(submenu, _("Saved..."), GAIM_STATUS_AVAILABLE, G_CALLBACK(gaim_gtk_status_window_show), NULL, 0, 0, NULL);
-
-	return menuitem;
-}
-
-static void
-docklet_menu() {
-	static GtkWidget *menu = NULL;
-	GtkWidget *menuitem;
-
-	if (menu) {
-		gtk_widget_destroy(menu);
-	}
-
-	menu = gtk_menu_new();
-
-	menuitem = gtk_check_menu_item_new_with_label(_("Show Buddy List"));
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), gaim_prefs_get_bool("/gaim/gtk/blist/list_visible"));
-	g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(docklet_toggle_blist), NULL);
-	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-
-	menuitem = gtk_menu_item_new_with_label(_("Unread Messages"));
-
-	if (status == DOCKLET_STATUS_ONLINE_PENDING || status == DOCKLET_STATUS_AWAY_PENDING) {
-		GtkWidget *submenu = gtk_menu_new();
-		GList *l = get_pending_list(0);
-		if (l == NULL) {
-			gtk_widget_set_sensitive(menuitem, FALSE);
-			gaim_debug_warning("docklet",
-				"status indicates messages pending, but no conversations with unseen messages were found.");
-		} else {
-			gaim_gtk_conversations_fill_menu(submenu, l);
-			g_list_free(l);
-			gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
-		}
-	} else {
-		gtk_widget_set_sensitive(menuitem, FALSE);
-	}
-	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-
-	gaim_separator(menu);
-
-	menuitem = gaim_new_item_from_stock(menu, _("New Message..."), GAIM_STOCK_IM, G_CALLBACK(gaim_gtkdialogs_im), NULL, 0, 0, NULL);
-	if (status == DOCKLET_STATUS_OFFLINE)
-		gtk_widget_set_sensitive(menuitem, FALSE);
-
-	menuitem = docklet_status_submenu();
-	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-
-	gaim_separator(menu);
-
-	gaim_new_item_from_stock(menu, _("Accounts"), GAIM_STOCK_ACCOUNTS, G_CALLBACK(gaim_gtk_accounts_window_show), NULL, 0, 0, NULL);
-	gaim_new_item_from_stock(menu, _("Plugins"), GAIM_STOCK_PLUGIN, G_CALLBACK(gaim_gtk_plugin_dialog_show), NULL, 0, 0, NULL);
-	gaim_new_item_from_stock(menu, _("Preferences"), GTK_STOCK_PREFERENCES, G_CALLBACK(gaim_gtk_prefs_show), NULL, 0, 0, NULL);
-
-	gaim_separator(menu);
-
-	menuitem = gtk_check_menu_item_new_with_label(_("Mute Sounds"));
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), gaim_prefs_get_bool("/gaim/gtk/sound/mute"));
-	if (!strcmp(gaim_prefs_get_string("/gaim/gtk/sound/method"), "none"))
-		gtk_widget_set_sensitive(GTK_WIDGET(menuitem), FALSE);
-	g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(docklet_toggle_mute), NULL);
-	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-
-	gaim_separator(menu);
-
-	/* TODO: need a submenu to change status, this needs to "link" 
-	 * to the status in the buddy list gtkstatusbox
-	 */
-
-	gaim_new_item_from_stock(menu, _("Quit"), GTK_STOCK_QUIT, G_CALLBACK(gaim_core_quit), NULL, 0, 0, NULL);
-
-#ifdef _WIN32
-	g_signal_connect(menu, "leave-notify-event", G_CALLBACK(docklet_menu_leave_enter), NULL);
-	g_signal_connect(menu, "enter-notify-event", G_CALLBACK(docklet_menu_leave_enter), NULL);
-#endif
-	gtk_widget_show_all(menu);
-	gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
-				   ui_ops->position_menu,
-				   NULL, 0, gtk_get_current_event_time());
-}
-
-/**************************************************************************
- * public api for ui_ops
- **************************************************************************/
-void
-docklet_clicked(int button_type)
-{
-	switch (button_type) {
-		case 1:
-			if (status == DOCKLET_STATUS_ONLINE_PENDING || status == DOCKLET_STATUS_AWAY_PENDING) {
-				GList *l = get_pending_list(1);
-				if (l != NULL) {
-					gaim_gtkconv_present_conversation((GaimConversation *)l->data);
-					g_list_free(l);
-				}
-			} else {
-				gaim_gtk_blist_toggle_visibility();
-			}
-			break;
-		case 3:
-			docklet_menu();
-			break;
-	}
-}
-
-void
-docklet_embedded()
-{
-	if (!visibility_manager) {
-		gaim_gtk_blist_visibility_manager_add();
-		visibility_manager = TRUE;
-	}
-	docklet_update_status();
-	if (ui_ops && ui_ops->update_icon)
-		ui_ops->update_icon(status);
-}
-
-void
-docklet_remove()
-{
-	if (visibility_manager) {
-		gaim_gtk_blist_visibility_manager_remove();
-		visibility_manager = FALSE;
-	}
-}
-
-void
-docklet_unload()
-{
-	gaim_plugin_unload(handle);
-}
-
-void
-docklet_set_ui_ops(struct docklet_ui_ops *ops)
-{
-	ui_ops = ops;
-}
-
-/**************************************************************************
- * plugin glue
- **************************************************************************/
-static gboolean
-plugin_load(GaimPlugin *plugin)
-{
-	void *conn_handle = gaim_connections_get_handle();
-	void *conv_handle = gaim_conversations_get_handle();
-	void *accounts_handle = gaim_accounts_get_handle();
-	void *core_handle = gaim_get_core();
-
-	gaim_debug(GAIM_DEBUG_INFO, "docklet", "plugin loaded\n");
-
-	handle = plugin;
-
-	docklet_ui_init();
-	if (ui_ops && ui_ops->create)
-		ui_ops->create();
-	gaim_signal_connect(conn_handle, "signed-on",
-						plugin, GAIM_CALLBACK(docklet_signed_on_cb), NULL);
-	gaim_signal_connect(conn_handle, "signed-off",
-						plugin, GAIM_CALLBACK(docklet_signed_off_cb), NULL);
-	gaim_signal_connect(accounts_handle, "account-status-changed",
-						plugin, GAIM_CALLBACK(docklet_update_status_cb), NULL);
-	gaim_signal_connect(conv_handle, "received-im-msg",
-						plugin, GAIM_CALLBACK(docklet_update_status_cb), NULL);
-	gaim_signal_connect(conv_handle, "conversation-created",
-						plugin, GAIM_CALLBACK(docklet_update_status_cb), NULL);
-	gaim_signal_connect(conv_handle, "deleting-conversation",
-						plugin, GAIM_CALLBACK(docklet_update_status_cb), NULL);
-	gaim_signal_connect(conv_handle, "conversation-updated",
-						plugin, GAIM_CALLBACK(docklet_conv_updated_cb), NULL);
-
-	gaim_signal_connect(core_handle, "quitting",
-						plugin, GAIM_CALLBACK(gaim_quit_cb), NULL);
-
-	gaim_prefs_connect_callback(plugin, "/plugins/gtk/docklet/blink_im",
-								docklet_prefs_cb, NULL);
-	gaim_prefs_connect_callback(plugin, "/plugins/gtk/docklet/blink_chat",
-								docklet_prefs_cb, NULL);
-
-	enable_join_chat = online_account_supports_chat();
-
-	return TRUE;
-}
-
-static gboolean
-plugin_unload(GaimPlugin *plugin)
-{
-	if (ui_ops && ui_ops->destroy)
-		ui_ops->destroy();
-
-	/* remove callbacks */
-	gaim_signals_disconnect_by_handle(handle);
-	gaim_prefs_disconnect_by_handle(handle);
-
-	gaim_debug(GAIM_DEBUG_INFO, "docklet", "plugin unloaded\n");
-
-	return TRUE;
-}
-
-static GtkWidget *
-plugin_config_frame(GaimPlugin *plugin)
-{
-	GtkWidget *frame;
-	GtkWidget *vbox;
-	GtkSizeGroup *sg;
-	GtkWidget *dd;
-
-	frame = gtk_vbox_new(FALSE, 18);
-	gtk_container_set_border_width(GTK_CONTAINER(frame), 12);
-
-	vbox = gaim_gtk_make_frame(frame, _("Blink tray icon for unread..."));
-	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
-
-	dd = gaim_gtk_prefs_dropdown(vbox, _("_Instant Messages:"),
-							GAIM_PREF_STRING, "/plugins/gtk/docklet/blink_im",
-							_("Never"), "never",
-							_("In hidden conversations"), "hidden",
-							_("Always"), "always",
-							NULL);
-	gtk_size_group_add_widget(sg, dd);
-
-	dd = gaim_gtk_prefs_dropdown(vbox, _("C_hat Messages:"),
-							GAIM_PREF_STRING, "/plugins/gtk/docklet/blink_chat",
-							_("Never"), "never",
-							_("When my nick is said"), "nick",
-							_("Always"), "always",
-							NULL);
-	gtk_size_group_add_widget(sg, dd);
-
-	gtk_widget_show_all(frame);
-	return frame;
-}
-
-static GaimGtkPluginUiInfo ui_info =
-{
-	plugin_config_frame,
-	0 /* page_num (Reserved) */
-};
-
-static GaimPluginInfo info =
-{
-	GAIM_PLUGIN_MAGIC,
-	GAIM_MAJOR_VERSION,
-	GAIM_MINOR_VERSION,
-	GAIM_PLUGIN_STANDARD,                             /**< type           */
-	GAIM_GTK_PLUGIN_TYPE,                             /**< ui_requirement */
-	0,                                                /**< flags          */
-	NULL,                                             /**< dependencies   */
-	GAIM_PRIORITY_DEFAULT,                            /**< priority       */
-
-	DOCKLET_PLUGIN_ID,                                /**< id             */
-	N_("System Tray Icon"),                           /**< name           */
-	VERSION,                                          /**< version        */
-	                                                  /**  summary        */
-	N_("Displays an icon for Gaim in the system tray."),
-	                                                  /**  description    */
-	N_("Displays a system tray icon (in GNOME, KDE, or Windows for example) "
-	   "to show the current status of Gaim, allow fast access to commonly "
-	   "used functions, and to toggle display of the buddy list. "
-	   "Also provides options to blink for unread messages."),
-	                                                  /** author          */
-	"Robert McQueen <robot101@debian.org>"
-	"\n\t\t\tCasey Harkins <charkins@users.sf.net>",
-	GAIM_WEBSITE,                                     /**< homepage       */
-
-	plugin_load,                                      /**< load           */
-	plugin_unload,                                    /**< unload         */
-	NULL,                                             /**< destroy        */
-
-	&ui_info,                                         /**< ui_info        */
-	NULL,                                             /**< extra_info     */
-	NULL,
-	NULL
-};
-
-static void
-plugin_init(GaimPlugin *plugin)
-{
-	gaim_prefs_add_none("/plugins/gtk/docklet");
-	gaim_prefs_add_string("/plugins/gtk/docklet/blink_im", "hidden");
-	gaim_prefs_add_string("/plugins/gtk/docklet/blink_chat", "never");
-}
-
-GAIM_INIT_PLUGIN(docklet, plugin_init, info)
--- a/gtk/plugins/docklet/docklet.h	Wed Oct 04 20:31:44 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/* 
- * System tray icon (aka docklet) plugin for Gaim
- * 
- * Copyright (C) 2002-3 Robert McQueen <robot101@debian.org>
- * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com>
- * Inspired by a similar plugin by:
- *  John (J5) Palmieri <johnp@martianrock.com>
- * 
- * 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 _DOCKLET_H_
-#define _DOCKLET_H_
-
-typedef enum
-{
-	DOCKLET_STATUS_OFFLINE,
-	DOCKLET_STATUS_ONLINE,
-	DOCKLET_STATUS_ONLINE_PENDING,
-	DOCKLET_STATUS_AWAY,
-	DOCKLET_STATUS_AWAY_PENDING,
-	DOCKLET_STATUS_CONNECTING
-} DockletStatus;
-
-struct docklet_ui_ops
-{
-	void (*create)(void);
-	void (*destroy)(void);
-	void (*update_icon)(DockletStatus);
-	void (*blank_icon)(void);
-	void (*set_tooltip)(gchar *);
-	GtkMenuPositionFunc position_menu;
-};
-
-/* useful for setting idle callbacks that will be cleaned up */
-extern GaimPlugin *handle;
-
-/* functions in docklet.c */
-void docklet_clicked(int);
-void docklet_embedded(void);
-void docklet_remove(void);
-void docklet_set_ui_ops(struct docklet_ui_ops *);
-void docklet_unload(void);
-
-/* function in docklet-{x11,win32}.c */
-void docklet_ui_init(void);
-
-#endif /* _DOCKLET_H_ */
--- a/gtk/plugins/docklet/eggtrayicon.c	Wed Oct 04 20:31:44 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,572 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* eggtrayicon.c
- * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
- *
- * 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 "eggtrayicon.h"
-
-#include <gdk/gdkx.h>
-#include <X11/Xatom.h>
-
-#define _(x) x
-#define N_(x) x
-
-#define SYSTEM_TRAY_REQUEST_DOCK    0
-#define SYSTEM_TRAY_BEGIN_MESSAGE   1
-#define SYSTEM_TRAY_CANCEL_MESSAGE  2
-
-#define SYSTEM_TRAY_ORIENTATION_HORZ 0
-#define SYSTEM_TRAY_ORIENTATION_VERT 1
-
-enum {
-  PROP_0,
-  PROP_ORIENTATION
-};
-         
-static GtkPlugClass *parent_class = NULL;
-
-static void egg_tray_icon_init (EggTrayIcon *icon);
-static void egg_tray_icon_class_init (EggTrayIconClass *klass);
-
-static void egg_tray_icon_get_property (GObject    *object,
-					guint       prop_id,
-					GValue     *value,
-					GParamSpec *pspec);
-
-static void egg_tray_icon_realize   (GtkWidget *widget);
-static void egg_tray_icon_unrealize (GtkWidget *widget);
-
-static void egg_tray_icon_add (GtkContainer *container,
-                               GtkWidget *widget);
-
-static void egg_tray_icon_update_manager_window    (EggTrayIcon *icon,
-						    gboolean     dock_if_realized);
-static void egg_tray_icon_manager_window_destroyed (EggTrayIcon *icon);
-
-GType
-egg_tray_icon_get_type (void)
-{
-  static GType our_type = 0;
-
-  if (our_type == 0)
-    {
-      our_type = g_type_from_name("EggTrayIcon");
-
-      if (our_type == 0)
-        {
-      static const GTypeInfo our_info =
-      {
-	sizeof (EggTrayIconClass),
-	(GBaseInitFunc) NULL,
-	(GBaseFinalizeFunc) NULL,
-	(GClassInitFunc) egg_tray_icon_class_init,
-	NULL, /* class_finalize */
-	NULL, /* class_data */
-	sizeof (EggTrayIcon),
-	0,    /* n_preallocs */
-	(GInstanceInitFunc) egg_tray_icon_init,
-	NULL /* value_table */
-      };
-
-      our_type = g_type_register_static (GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0);
-        }
-      else if (parent_class == NULL)
-        {
-          /* we're reheating the old class from a previous instance -  engage ugly hack =( */
-          egg_tray_icon_class_init((EggTrayIconClass *)g_type_class_peek(our_type));
-        }
-    }
-
-  return our_type;
-}
-
-static void
-egg_tray_icon_init (EggTrayIcon *icon)
-{
-  icon->stamp = 1;
-  icon->orientation = GTK_ORIENTATION_HORIZONTAL;
-  
-  gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK);
-}
-
-static void
-egg_tray_icon_class_init (EggTrayIconClass *klass)
-{
-  GObjectClass *gobject_class = (GObjectClass *)klass;
-  GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
-  GtkContainerClass *container_class = (GtkContainerClass *)klass;
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  gobject_class->get_property = egg_tray_icon_get_property;
-
-  widget_class->realize   = egg_tray_icon_realize;
-  widget_class->unrealize = egg_tray_icon_unrealize;
-
-  container_class->add = egg_tray_icon_add;
-
-  g_object_class_install_property (gobject_class,
-				   PROP_ORIENTATION,
-				   g_param_spec_enum ("orientation",
-						      _("Orientation"),
-						      _("The orientation of the tray."),
-						      GTK_TYPE_ORIENTATION,
-						      GTK_ORIENTATION_HORIZONTAL,
-						      G_PARAM_READABLE));
-}
-
-static void
-egg_tray_icon_get_property (GObject    *object,
-			    guint       prop_id,
-			    GValue     *value,
-			    GParamSpec *pspec)
-{
-  EggTrayIcon *icon = EGG_TRAY_ICON (object);
-
-  switch (prop_id)
-    {
-    case PROP_ORIENTATION:
-      g_value_set_enum (value, icon->orientation);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-egg_tray_icon_get_orientation_property (EggTrayIcon *icon)
-{
-  Display *xdisplay;
-  Atom type;
-  int format;
-  union {
-	gulong *prop;
-	guchar *prop_ch;
-  } prop = { NULL };
-  gulong nitems;
-  gulong bytes_after;
-  int error, result;
-
-  g_return_if_fail(icon->manager_window != None);
-
-#if GTK_CHECK_VERSION(2,1,0)
-  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
-#else
-  xdisplay = gdk_display;
-#endif
-
-  gdk_error_trap_push ();
-  type = None;
-  result = XGetWindowProperty (xdisplay,
-			       icon->manager_window,
-			       icon->orientation_atom,
-			       0, G_MAXLONG, FALSE,
-			       XA_CARDINAL,
-			       &type, &format, &nitems,
-			       &bytes_after, &(prop.prop_ch));
-  error = gdk_error_trap_pop ();
-
-  if (error || result != Success)
-    return;
-
-  if (type == XA_CARDINAL)
-    {
-      GtkOrientation orientation;
-
-      orientation = (prop.prop [0] == SYSTEM_TRAY_ORIENTATION_HORZ) ?
-					GTK_ORIENTATION_HORIZONTAL :
-					GTK_ORIENTATION_VERTICAL;
-
-      if (icon->orientation != orientation)
-	{
-	  icon->orientation = orientation;
-
-	  g_object_notify (G_OBJECT (icon), "orientation");
-	}
-    }
-
-  if (prop.prop)
-    XFree (prop.prop);
-}
-
-static GdkFilterReturn
-egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_data)
-{
-  EggTrayIcon *icon = user_data;
-  XEvent *xev = (XEvent *)xevent;
-
-  if (xev->xany.type == ClientMessage &&
-      xev->xclient.message_type == icon->manager_atom &&
-      xev->xclient.data.l[1] == icon->selection_atom)
-    {
-      egg_tray_icon_update_manager_window (icon, TRUE);
-    }
-  else if (xev->xany.window == icon->manager_window)
-    {
-      if (xev->xany.type == PropertyNotify &&
-	  xev->xproperty.atom == icon->orientation_atom)
-	{
-	  egg_tray_icon_get_orientation_property (icon);
-	}
-      if (xev->xany.type == DestroyNotify)
-	{
-	  egg_tray_icon_manager_window_destroyed (icon);
-	}
-    }
-  
-  return GDK_FILTER_CONTINUE;
-}
-
-static void
-egg_tray_icon_unrealize (GtkWidget *widget)
-{
-  EggTrayIcon *icon = EGG_TRAY_ICON (widget);
-  GdkWindow *root_window;
-
-  if (icon->manager_window != None)
-    {
-      GdkWindow *gdkwin;
-
-#if GTK_CHECK_VERSION(2,1,0)
-      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (widget),
-                                              icon->manager_window);
-#else
-      gdkwin = gdk_window_lookup (icon->manager_window);
-#endif
-
-      gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
-    }
-
-#if GTK_CHECK_VERSION(2,1,0)
-  root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
-#else
-  root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ());
-#endif
-
-  gdk_window_remove_filter (root_window, egg_tray_icon_manager_filter, icon);
-
-  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
-    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
-}
-
-static void
-egg_tray_icon_send_manager_message (EggTrayIcon *icon,
-				    long         message,
-				    Window       window,
-				    long         data1,
-				    long         data2,
-				    long         data3)
-{
-  XClientMessageEvent ev;
-  Display *display;
-  
-  ev.type = ClientMessage;
-  ev.window = window;
-  ev.message_type = icon->system_tray_opcode_atom;
-  ev.format = 32;
-  ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window);
-  ev.data.l[1] = message;
-  ev.data.l[2] = data1;
-  ev.data.l[3] = data2;
-  ev.data.l[4] = data3;
-
-#if GTK_CHECK_VERSION(2,1,0)
-  display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
-#else
-  display = gdk_display;
-#endif
-
-  gdk_error_trap_push ();
-  XSendEvent (display,
-	      icon->manager_window, False, NoEventMask, (XEvent *)&ev);
-  XSync (display, False);
-  gdk_error_trap_pop ();
-}
-
-static void
-egg_tray_icon_send_dock_request (EggTrayIcon *icon)
-{
-  egg_tray_icon_send_manager_message (icon,
-				      SYSTEM_TRAY_REQUEST_DOCK,
-				      icon->manager_window,
-				      gtk_plug_get_id (GTK_PLUG (icon)),
-				      0, 0);
-}
-
-static void
-egg_tray_icon_update_manager_window (EggTrayIcon *icon,
-				     gboolean     dock_if_realized)
-{
-  Display *xdisplay;
-  
-  if (icon->manager_window != None)
-    return;
-
-#if GTK_CHECK_VERSION(2,1,0)
-  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
-#else
-  xdisplay = gdk_display;
-#endif
-
-  XGrabServer (xdisplay);
-  
-  icon->manager_window = XGetSelectionOwner (xdisplay,
-					     icon->selection_atom);
-
-  if (icon->manager_window != None)
-    XSelectInput (xdisplay,
-		  icon->manager_window, StructureNotifyMask|PropertyChangeMask);
-
-  XUngrabServer (xdisplay);
-  XFlush (xdisplay);
-  
-  if (icon->manager_window != None)
-    {
-      GdkWindow *gdkwin;
-
-#if GTK_CHECK_VERSION(2,1,0)
-      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
-					      icon->manager_window);
-#else
-      gdkwin = gdk_window_lookup (icon->manager_window);
-#endif
-
-      gdk_window_add_filter (gdkwin, egg_tray_icon_manager_filter, icon);
-
-      if (dock_if_realized && GTK_WIDGET_REALIZED (icon))
-	egg_tray_icon_send_dock_request (icon);
-
-      egg_tray_icon_get_orientation_property (icon);
-    }
-}
-
-static void
-egg_tray_icon_manager_window_destroyed (EggTrayIcon *icon)
-{
-  GdkWindow *gdkwin;
-  
-  g_return_if_fail (icon->manager_window != None);
-
-#if GTK_CHECK_VERSION(2,1,0)
-  gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
-					  icon->manager_window);
-#else
-  gdkwin = gdk_window_lookup (icon->manager_window);
-#endif
-
-  gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
-
-  icon->manager_window = None;
-
-  egg_tray_icon_update_manager_window (icon, TRUE);
-}
-
-static gboolean
-transparent_expose_event (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
-make_transparent_again (GtkWidget *widget, GtkStyle *previous_style,
-                       gpointer user_data)
-{
-	gdk_window_set_back_pixmap(widget->window, NULL, TRUE);
-}
-
-static void
-make_transparent (GtkWidget *widget, gpointer user_data)
-{
-	if (GTK_WIDGET_NO_WINDOW (widget) || GTK_WIDGET_APP_PAINTABLE (widget))
-		return;
-
-	gtk_widget_set_app_paintable (widget, TRUE);
-	gtk_widget_set_double_buffered (widget, FALSE);
-	gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
-	g_signal_connect (widget, "expose_event",
-	                 G_CALLBACK (transparent_expose_event), NULL);
-	g_signal_connect_after (widget, "style_set",
-	                       G_CALLBACK (make_transparent_again), NULL);
-}
-
-static void
-egg_tray_icon_realize (GtkWidget *widget)
-{
-  EggTrayIcon *icon = EGG_TRAY_ICON (widget);
-  gint screen;
-  Display *xdisplay;
-  char buffer[256];
-  GdkWindow *root_window;
-
-  if (GTK_WIDGET_CLASS (parent_class)->realize)
-    GTK_WIDGET_CLASS (parent_class)->realize (widget);
-
-  make_transparent (widget, NULL);
-
-#if GTK_CHECK_VERSION(2,1,0)
-  screen = gdk_screen_get_number (gtk_widget_get_screen (widget));
-  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget));
-#else
-  screen = XScreenNumberOfScreen (DefaultScreenOfDisplay (gdk_display));
-  xdisplay = gdk_display;
-#endif
-
-  /* Now see if there's a manager window around */
-  g_snprintf (buffer, sizeof (buffer),
-	      "_NET_SYSTEM_TRAY_S%d",
-	      screen);
-
-  icon->selection_atom = XInternAtom (xdisplay, buffer, False);
-  
-  icon->manager_atom = XInternAtom (xdisplay, "MANAGER", False);
-  
-  icon->system_tray_opcode_atom = XInternAtom (xdisplay,
-						   "_NET_SYSTEM_TRAY_OPCODE",
-						   False);
-
-  icon->orientation_atom = XInternAtom (xdisplay,
-					"_NET_SYSTEM_TRAY_ORIENTATION",
-					False);
-
-  egg_tray_icon_update_manager_window (icon, FALSE);
-  egg_tray_icon_send_dock_request (icon);
-
-#if GTK_CHECK_VERSION(2,1,0)
-  root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
-#else
-  root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ());
-#endif
-
-  /* Add a root window filter so that we get changes on MANAGER */
-  gdk_window_add_filter (root_window,
-			 egg_tray_icon_manager_filter, icon);
-}
-
-static void
-egg_tray_icon_add (GtkContainer *container, GtkWidget *widget)
-{
-	g_signal_connect (widget, "realize",
-	                 G_CALLBACK (make_transparent), NULL);
-	GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
-}
-
-#if GTK_CHECK_VERSION(2,1,0)
-EggTrayIcon *
-egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name)
-{
-  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
-
-  return g_object_new (EGG_TYPE_TRAY_ICON, "screen", screen, "title", name, NULL);
-}
-#endif
-
-EggTrayIcon*
-egg_tray_icon_new (const gchar *name)
-{
-  return g_object_new (EGG_TYPE_TRAY_ICON, "title", name, NULL);
-}
-
-guint
-egg_tray_icon_send_message (EggTrayIcon *icon,
-			    gint         timeout,
-			    const gchar *message,
-			    gint         len)
-{
-  guint stamp;
-  
-  g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0);
-  g_return_val_if_fail (timeout >= 0, 0);
-  g_return_val_if_fail (message != NULL, 0);
-		     
-  if (icon->manager_window == None)
-    return 0;
-
-  if (len < 0)
-    len = strlen (message);
-
-  stamp = icon->stamp++;
-  
-  /* Get ready to send the message */
-  egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE,
-				      (Window)gtk_plug_get_id (GTK_PLUG (icon)),
-				      timeout, len, stamp);
-
-  /* Now to send the actual message */
-  gdk_error_trap_push ();
-  while (len > 0)
-    {
-      XClientMessageEvent ev;
-      Display *xdisplay;
-
-#if GTK_CHECK_VERSION(2,1,0)
-      xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
-#else
-      xdisplay = gdk_display;
-#endif
-
-      ev.type = ClientMessage;
-      ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon));
-      ev.format = 8;
-      ev.message_type = XInternAtom (xdisplay,
-				     "_NET_SYSTEM_TRAY_MESSAGE_DATA", False);
-      if (len > 20)
-	{
-	  memcpy (&ev.data, message, 20);
-	  len -= 20;
-	  message += 20;
-	}
-      else
-	{
-	  memcpy (&ev.data, message, len);
-	  len = 0;
-	}
-
-      XSendEvent (xdisplay,
-		  icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev);
-      XSync (xdisplay, False);
-    }
-  gdk_error_trap_pop ();
-
-  return stamp;
-}
-
-void
-egg_tray_icon_cancel_message (EggTrayIcon *icon,
-			      guint        id)
-{
-  g_return_if_fail (EGG_IS_TRAY_ICON (icon));
-  g_return_if_fail (id > 0);
-  
-  egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE,
-				      (Window)gtk_plug_get_id (GTK_PLUG (icon)),
-				      id, 0, 0);
-}
-
-GtkOrientation
-egg_tray_icon_get_orientation (EggTrayIcon *icon)
-{
-  g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), GTK_ORIENTATION_HORIZONTAL);
-
-  return icon->orientation;
-}
--- a/gtk/plugins/docklet/eggtrayicon.h	Wed Oct 04 20:31:44 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* eggtrayicon.h
- * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
- *
- * 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 __EGG_TRAY_ICON_H__
-#define __EGG_TRAY_ICON_H__
-
-#include <gtk/gtkplug.h>
-#include <gtk/gtkversion.h>
-#include <gdk/gdkx.h>
-
-G_BEGIN_DECLS
-
-#define EGG_TYPE_TRAY_ICON		(egg_tray_icon_get_type ())
-#define EGG_TRAY_ICON(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TRAY_ICON, EggTrayIcon))
-#define EGG_TRAY_ICON_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TRAY_ICON, EggTrayIconClass))
-#define EGG_IS_TRAY_ICON(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TRAY_ICON))
-#define EGG_IS_TRAY_ICON_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TRAY_ICON))
-#define EGG_TRAY_ICON_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TRAY_ICON, EggTrayIconClass))
-	
-typedef struct _EggTrayIcon	  EggTrayIcon;
-typedef struct _EggTrayIconClass  EggTrayIconClass;
-
-struct _EggTrayIcon
-{
-  GtkPlug parent_instance;
-
-  guint stamp;
-  
-  Atom selection_atom;
-  Atom manager_atom;
-  Atom system_tray_opcode_atom;
-  Atom orientation_atom;
-  Window manager_window;
-
-  GtkOrientation orientation;
-};
-
-struct _EggTrayIconClass
-{
-  GtkPlugClass parent_class;
-};
-
-GType        egg_tray_icon_get_type       (void);
-
-#if GTK_CHECK_VERSION(2,1,0)
-EggTrayIcon *egg_tray_icon_new_for_screen (GdkScreen   *screen,
-					   const gchar *name);
-#endif
-
-EggTrayIcon *egg_tray_icon_new            (const gchar *name);
-
-guint        egg_tray_icon_send_message   (EggTrayIcon *icon,
-					   gint         timeout,
-					   const char  *message,
-					   gint         len);
-void         egg_tray_icon_cancel_message (EggTrayIcon *icon,
-					   guint        id);
-
-GtkOrientation egg_tray_icon_get_orientation (EggTrayIcon *icon);
-					    
-G_END_DECLS
-
-#endif /* __EGG_TRAY_ICON_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gtk/win32/MinimizeToTray.c	Thu Oct 05 23:24:00 2006 +0000
@@ -0,0 +1,119 @@
+/* MinimizeToTray
+ *
+ * A couple of routines to show how to make it produce a custom caption
+ * animation to make it look like we are minimizing to and maximizing
+ * from the system tray
+ *
+ * These routines are public domain, but it would be nice if you dropped
+ * me a line if you use them!
+ *
+ * 1.0 29.06.2000 Initial version
+ * 1.1 01.07.2000 The window retains it's place in the Z-order of windows
+ *     when minimized/hidden. This means that when restored/shown, it doesn't
+ *     always appear as the foreground window unless we call SetForegroundWindow
+ *
+ * Copyright 2000 Matthew Ellis <m.t.ellis@bigfoot.com>
+ */
+#define _WIN32_WINNT 0x0500
+#include <windows.h>
+#include "MinimizeToTray.h"
+
+#define DEFAULT_RECT_WIDTH 150
+#define DEFAULT_RECT_HEIGHT 30
+
+static void GetTrayWndRect(LPRECT lpTrayRect) {
+	APPBARDATA appBarData;
+	HWND hShellTrayWnd = FindWindowEx(NULL, NULL, TEXT("Shell_TrayWnd"),
+		NULL);
+
+	if(hShellTrayWnd) {
+		HWND hTrayNotifyWnd = FindWindowEx(hShellTrayWnd, NULL,
+			TEXT("TrayNotifyWnd"), NULL);
+
+		if(hTrayNotifyWnd) {
+			GetWindowRect(hTrayNotifyWnd,lpTrayRect);
+			return;
+		}
+	}
+
+	appBarData.cbSize = sizeof(appBarData);
+	if(SHAppBarMessage(ABM_GETTASKBARPOS, &appBarData)) {
+		switch(appBarData.uEdge) {
+			case ABE_LEFT:
+			case ABE_RIGHT:
+				lpTrayRect->top = appBarData.rc.bottom - 100;
+				lpTrayRect->bottom = appBarData.rc.bottom - 16;
+				lpTrayRect->left = appBarData.rc.left;
+				lpTrayRect->right = appBarData.rc.right;
+				break;
+			case ABE_TOP:
+			case ABE_BOTTOM:
+				lpTrayRect->top = appBarData.rc.top;
+				lpTrayRect->bottom = appBarData.rc.bottom;
+				lpTrayRect->left = appBarData.rc.right - 100;
+				lpTrayRect->right = appBarData.rc.right - 16;
+				break;
+		}
+		return;
+	}
+
+	hShellTrayWnd = FindWindowEx(NULL, NULL, TEXT("Shell_TrayWnd"), NULL);
+	if(hShellTrayWnd) {
+		GetWindowRect(hShellTrayWnd, lpTrayRect);
+		if(lpTrayRect->right-lpTrayRect->left > DEFAULT_RECT_WIDTH)
+			lpTrayRect->left = lpTrayRect->right - DEFAULT_RECT_WIDTH;
+		if(lpTrayRect->bottom-lpTrayRect->top > DEFAULT_RECT_HEIGHT)
+			lpTrayRect->top=lpTrayRect->bottom - DEFAULT_RECT_HEIGHT;
+
+		return;
+	}
+
+	SystemParametersInfo(SPI_GETWORKAREA, 0, lpTrayRect, 0);
+	lpTrayRect->left = lpTrayRect->right - DEFAULT_RECT_WIDTH;
+	lpTrayRect->top = lpTrayRect->bottom - DEFAULT_RECT_HEIGHT;
+}
+
+static BOOL GetDoAnimateMinimize(void) {
+	ANIMATIONINFO ai;
+
+	ai.cbSize = sizeof(ai);
+	SystemParametersInfo(SPI_GETANIMATION, sizeof(ai), &ai, 0);
+
+	return ai.iMinAnimate ? TRUE : FALSE;
+}
+
+void MinimizeWndToTray(HWND hWnd) {
+
+	if(!IsWindowVisible(hWnd))
+		return;
+
+	if(GetDoAnimateMinimize()) {
+		RECT rcFrom, rcTo;
+
+		GetWindowRect(hWnd, &rcFrom);
+		GetTrayWndRect(&rcTo);
+
+		DrawAnimatedRects(hWnd, IDANI_CAPTION, &rcFrom, &rcTo);
+	}
+
+	ShowWindow(hWnd, SW_HIDE);
+}
+
+void RestoreWndFromTray(HWND hWnd) {
+
+	if(IsWindowVisible(hWnd))
+		return;
+
+	if(GetDoAnimateMinimize()) {
+		RECT rcFrom, rcTo;
+		GetTrayWndRect(&rcFrom);
+		GetWindowRect(hWnd, &rcTo);
+
+		DrawAnimatedRects(hWnd, IDANI_CAPTION, &rcFrom, &rcTo);
+	}
+
+	ShowWindow(hWnd, SW_SHOW);
+	SetActiveWindow(hWnd);
+	SetForegroundWindow(hWnd);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gtk/win32/MinimizeToTray.h	Thu Oct 05 23:24:00 2006 +0000
@@ -0,0 +1,7 @@
+#ifndef _MINIMIZE_TO_TRAY_H_
+#define _MINIMIZE_TO_TRAY_H_
+
+void MinimizeWndToTray(HWND hWnd);
+void RestoreWndFromTray(HWND hWnd);
+
+#endif /* _MINIMIZE_TO_TRAY_H_ */
--- a/libgaim/util.c	Wed Oct 04 20:31:44 2006 +0000
+++ b/libgaim/util.c	Thu Oct 05 23:24:00 2006 +0000
@@ -2577,7 +2577,7 @@
 #endif
 }
 
-gboolean
+inline gboolean
 gaim_running_osx(void)
 {
 #if defined(__APPLE__)