# HG changeset patch # User Herman Bloggs # Date 1057878787 0 # Node ID b2c8e08508af41bd2daf66542dcf0ff6e9731315 # Parent 8d6aa792e0f68edd7ad234f5c754bebabf349e90 [gaim-migrate @ 6536] Integrated Win Gaim systray to the docklet plugin committer: Tailor Script diff -r 8d6aa792e0f6 -r b2c8e08508af plugins/docklet/Makefile.am --- a/plugins/docklet/Makefile.am Thu Jul 10 18:56:52 2003 +0000 +++ b/plugins/docklet/Makefile.am Thu Jul 10 23:13:07 2003 +0000 @@ -7,9 +7,11 @@ plugin_LTLIBRARIES = docklet.la docklet_la_SOURCES = \ + docklet.h \ docklet.c \ eggtrayicon.h \ - eggtrayicon.c + eggtrayicon.c \ + trayicon-x11.c endif diff -r 8d6aa792e0f6 -r b2c8e08508af plugins/docklet/Makefile.mingw --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/docklet/Makefile.mingw Thu Jul 10 23:13:07 2003 +0000 @@ -0,0 +1,121 @@ +# +# Makefile.mingw +# +# Description: Makefile for docklet plugin. +# + +# +# PATHS +# + +GTK_TOP := ../../../../win32-dev/gtk_2_0 +GAIM_TOP := ../../.. +GAIM_INSTALL_DIR := $(GAIM_TOP)/win32-install-dir +DLL_INSTALL_DIR := $(GAIM_INSTALL_DIR)/plugins + +## +## VARIABLE DEFINITIONS +## + +TARGET = docklet + +# Compiler Options + +CFLAGS = + +DEFINES = + +## +## INCLUDE MAKEFILES +## + +include $(GAIM_TOP)/src/win32/global.mak + +## +## INCLUDE PATHS +## + +INCLUDE_PATHS += -I. \ + -I$(GTK_TOP)/include \ + -I$(GTK_TOP)/include/gtk-2.0 \ + -I$(GTK_TOP)/include/glib-2.0 \ + -I$(GTK_TOP)/include/pango-1.0 \ + -I$(GTK_TOP)/include/atk-1.0 \ + -I$(GTK_TOP)/lib/glib-2.0/include \ + -I$(GTK_TOP)/lib/gtk-2.0/include \ + -I$(GAIM_TOP)/src \ + -I$(GAIM_TOP)/src/win32 \ + -I$(GAIM_TOP) + + +LIB_PATHS = -L$(GTK_TOP)/lib \ + -L$(GAIM_TOP)/src + + +## +## SOURCES, OBJECTS +## + +C_SRC = docklet.c \ + trayicon-win32.c + + +OBJECTS = $(C_SRC:%.c=%.o) + + +## +## LIBRARIES +## + +LIBS = -lgtk-win32-2.0 \ + -lglib-2.0 \ + -lgdk-win32-2.0 \ + -lgmodule-2.0 \ + -lgobject-2.0 \ + -lws2_32 \ + -lintl \ + -lgaim + + +## +## RULES +## + +# How to make a C file + +%.o: %.c + $(CC) $(CFLAGS) $(DEFINES) $(INCLUDE_PATHS) -o $@ -c $< + +## +## TARGET DEFINITIONS +## + +.PHONY: all clean + +all: $(TARGET).dll + +install: + cp $(TARGET).dll $(DLL_INSTALL_DIR) + + +## +## BUILD Dependencies +## + +$(GAIM_TOP)/src/gaim.lib: + $(MAKE) -C $(GAIM_TOP)/src -f Makefile.mingw gaim.lib + +## +## BUILD DLL +## + +$(TARGET).dll: $(OBJECTS) $(GAIM_TOP)/src/gaim.lib + $(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -o $(TARGET).dll + +## +## CLEAN RULES +## + +clean: + rm -rf *.o + rm -rf $(TARGET).dll diff -r 8d6aa792e0f6 -r b2c8e08508af plugins/docklet/docklet.c --- a/plugins/docklet/docklet.c Thu Jul 10 18:56:52 2003 +0000 +++ b/plugins/docklet/docklet.c Thu Jul 10 23:13:07 2003 +0000 @@ -1,5 +1,6 @@ /* System tray icon (aka docklet) plugin for Gaim * Copyright (C) 2002 Robert McQueen + * Copyright (C) 2003 Herman Bloggs * Inspired by a similar plugin by: * John (J5) Palmieri * @@ -41,36 +42,29 @@ #include "gtksound.h" #include "gtkutils.h" #include "stock.h" - -#include "eggtrayicon.h" +#include "docklet.h" #include "gaim.h" #include "ui.h" #define DOCKLET_PLUGIN_ID "gtk-docklet" -/* types */ -enum docklet_status { - offline, - offline_connecting, - online, - online_connecting, - online_pending, - away, - away_pending -}; +/* globals */ +static struct gaim_tray_ops *tray_ops = NULL; +static enum docklet_status status=offline; +static enum docklet_status icon=offline; +#ifdef _WIN32 +__declspec(dllimport) GSList *unread_message_queue; +__declspec(dllimport) GSList *away_messages; +__declspec(dllimport) struct away_message *awaymessage; +__declspec(dllimport) GSList *message_queue; +#endif /* functions */ -static gboolean docklet_create(); +extern void trayicon_init(); static gboolean docklet_update_status(); static gboolean plugin_unload(GaimPlugin *plugin); -/* globals */ -static EggTrayIcon *docklet = NULL; -static GtkWidget *image = NULL; -static enum docklet_status status; -static enum docklet_status icon; - static void docklet_toggle_mute(GtkWidget *toggle, void *data) { gaim_gtk_sound_set_mute(GTK_CHECK_MENU_ITEM(toggle)->active); } @@ -83,13 +77,22 @@ gaim_accounts_auto_login(GAIM_GTK_UI); } -static void docklet_flush_queue() { - if (unread_message_queue) { - purge_away_queue(&unread_message_queue); +#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 menu_leave(GtkWidget *menu, + GdkEventCrossing *event, + gpointer user_data) { + if(event->detail == GDK_NOTIFY_ANCESTOR) { + gaim_debug(GAIM_DEBUG_INFO, "docklet", "leave-notify-event\n"); + gtk_menu_popdown(GTK_MENU(menu)); } + return FALSE; } +#endif -static void docklet_menu(GdkEventButton *event) { +static void docklet_menu() { static GtkWidget *menu = NULL; GtkWidget *entry; @@ -98,7 +101,9 @@ } menu = gtk_menu_new(); - +#ifdef _WIN32 + g_signal_connect(menu, "leave-notify-event", G_CALLBACK(menu_leave), NULL); +#endif switch (status) { case offline: case offline_connecting: @@ -178,64 +183,7 @@ gaim_new_item_from_stock(menu, _("Quit"), GTK_STOCK_QUIT, G_CALLBACK(do_quit), NULL, 0, 0, 0); gtk_widget_show_all(menu); - gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time); -} - -static void docklet_clicked(GtkWidget *button, GdkEventButton *event, void *data) { - if (event->type != GDK_BUTTON_PRESS) - return; - - switch (event->button) { - case 1: - if (unread_message_queue) { - docklet_flush_queue(); - docklet_update_status(); - } else { - gaim_gtk_blist_docklet_toggle(); - } - break; - case 2: - switch (status) { - case offline: - case offline_connecting: - docklet_auto_login(); - break; - default: - break; - } - break; - case 3: - docklet_menu(event); - break; - } -} - -static void docklet_update_icon() { - const gchar *icon_name = NULL; - - switch (icon) { - case offline: - icon_name = GAIM_STOCK_ICON_OFFLINE; - break; - case offline_connecting: - case online_connecting: - icon_name = GAIM_STOCK_ICON_CONNECT; - break; - case online: - icon_name = GAIM_STOCK_ICON_ONLINE; - break; - case online_pending: - icon_name = GAIM_STOCK_ICON_ONLINE_MSG; - break; - case away: - icon_name = GAIM_STOCK_ICON_AWAY; - break; - case away_pending: - icon_name = GAIM_STOCK_ICON_AWAY_MSG; - break; - } - - gtk_image_set_from_stock(GTK_IMAGE(image), icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time()); } static gboolean docklet_blink_icon() { @@ -260,7 +208,8 @@ return FALSE; } - docklet_update_icon(); + if(tray_ops->update_icon) + tray_ops->update_icon(icon); return TRUE; /* keep blinking */ } @@ -295,78 +244,14 @@ /* update the icon if we changed status */ if (status != oldstatus) { icon = status; - docklet_update_icon(); + if(tray_ops->update_icon) + tray_ops->update_icon(icon); /* and schedule the blinker function if messages are pending */ if (status == online_pending || status == away_pending) { - g_timeout_add(500, docklet_blink_icon, &docklet); + g_timeout_add(500, docklet_blink_icon, NULL); } } - - return FALSE; /* for when we're called by the glib idle handler */ -} - -static void docklet_embedded(GtkWidget *widget, void *data) { - gaim_debug(GAIM_DEBUG_INFO, "docklet", "Tray Icon: embedded\n"); - gaim_gtk_blist_docklet_add(); -} - -static void docklet_remove_callbacks() { - gaim_debug(GAIM_DEBUG_INFO, "docklet", "Tray Icon: removing callbacks"); - - while (g_source_remove_by_user_data(&docklet)) { - gaim_debug(GAIM_DEBUG_INFO, NULL, "."); - } - - gaim_debug(GAIM_DEBUG_INFO, NULL, "\n"); -} - -static void docklet_destroyed(GtkWidget *widget, void *data) { - gaim_debug(GAIM_DEBUG_INFO, "docklet", "Tray Icon: destroyed\n"); - - gaim_gtk_blist_docklet_remove(); - - docklet_flush_queue(); - - docklet_remove_callbacks(); - - g_object_unref(G_OBJECT(docklet)); - docklet = NULL; - - g_idle_add(docklet_create, &docklet); -} - -static gboolean docklet_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, "docklet", - "Tray Icon: trying to create icon but it already exists?\n"); - plugin_unload(NULL); - } - - 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_embedded), NULL); - g_signal_connect(G_OBJECT(docklet), "destroy", G_CALLBACK(docklet_destroyed), NULL); - g_signal_connect(G_OBJECT(box), "button-press-event", G_CALLBACK(docklet_clicked), NULL); - - gtk_container_add(GTK_CONTAINER(box), image); - gtk_container_add(GTK_CONTAINER(docklet), box); - gtk_widget_show_all(GTK_WIDGET(docklet)); - - /* ref the docklet before we bandy it about the place */ - g_object_ref(G_OBJECT(docklet)); - docklet_update_status(); - docklet_update_icon(); - - gaim_debug(GAIM_DEBUG_INFO, "docklet", "Tray Icon: created\n"); - return FALSE; /* for when we're called by the glib idle handler */ } @@ -398,7 +283,7 @@ message so we need to see if the status (and hence icon) needs changing. do this when idle so that all message processing is completed, queuing etc, before we run. */ - g_idle_add(docklet_update_status, &docklet); + g_idle_add(docklet_update_status, NULL); } /* static void gaim_buddy_signon(GaimConnection *gc, char *who, void *data) { @@ -416,13 +301,70 @@ static void gaim_new_conversation(char *who, void *data) { } */ +/* + * Public Code + */ +void docklet_clicked(int button_type) { + switch (button_type) { + case 1: + if (unread_message_queue) { + docklet_flush_queue(); + docklet_update_status(); + } else { + gaim_gtk_blist_docklet_toggle(); + } + break; + case 2: + switch (status) { + case offline: + case offline_connecting: + docklet_auto_login(); + break; + default: + break; + } + break; + case 3: + docklet_menu(); + break; + } +} + +void docklet_embedded() { + gaim_debug(GAIM_DEBUG_INFO, "docklet", "Tray Icon: embedded\n"); + gaim_gtk_blist_docklet_add(); +} + +void docklet_flush_queue() { + if (unread_message_queue) { + purge_away_queue(&unread_message_queue); + } +} + + +/* Set Platform Dependent Code */ +void docklet_set_tray_ops(struct gaim_tray_ops *ops) { + tray_ops = ops; +} + + +/* + * PLUGIN CODE + */ + static gboolean plugin_load(GaimPlugin *plugin) { + trayicon_init(); + if(tray_ops->create) + tray_ops->create(); + gaim_prefs_add_none("/plugins/gtk/docklet"); gaim_prefs_add_bool("/plugins/gtk/docklet/queue_messages", FALSE); - docklet_create(NULL); + docklet_update_status(); + if(tray_ops->update_icon) + tray_ops->update_icon(icon); gaim_signal_connect(plugin, event_signon, gaim_signon, NULL); gaim_signal_connect(plugin, event_signoff, gaim_signoff, NULL); @@ -435,30 +377,23 @@ gaim_signal_connect(plugin, event_buddy_back, gaim_buddy_back, NULL); gaim_signal_connect(plugin, event_new_conversation, gaim_new_conversation, NULL); */ + gaim_debug(GAIM_DEBUG_INFO, "docklet", "Plugin loaded\n"); + return TRUE; } static gboolean plugin_unload(GaimPlugin *plugin) { - if (GTK_WIDGET_VISIBLE(docklet)) { - gaim_gtk_blist_docklet_remove(); - } - + gaim_gtk_blist_docklet_remove(); docklet_flush_queue(); - - docklet_remove_callbacks(); - - g_signal_handlers_disconnect_by_func(G_OBJECT(docklet), G_CALLBACK(docklet_destroyed), NULL); - gtk_widget_destroy(GTK_WIDGET(docklet)); - - g_object_unref(G_OBJECT(docklet)); - docklet = NULL; - /* XXX: do this while gaim has no other way to toggle the global mute */ gaim_gtk_sound_set_mute(FALSE); - gaim_debug(GAIM_DEBUG_INFO, "docklet", "Tray Icon: removed\n"); + if(tray_ops->destroy) + tray_ops->destroy(); + + gaim_debug(GAIM_DEBUG_INFO, "docklet", "Plugin unloaded\n"); return TRUE; } @@ -507,10 +442,10 @@ /** summary */ N_("Displays an icon for Gaim in the system tray."), /** description */ - N_("Interacts with a Notification Area applet (in GNOME or KDE, " - "for example) to display the current status of Gaim, allow fast " - "access to commonly used functions, and to toggle display of the " - "buddy list or login window. Also allows messages to be queued " + N_("Interacts with a Notification Area applet (in GNOME, KDE or " + "Windows for example) to display the current status of Gaim, allow " + "fast access to commonly used functions, and to toggle display of " + "the buddy list or login window. Also allows messages to be queued " "until the icon is clicked, similar to ICQ."), "Robert McQueen ", /**< author */ WEBSITE, /**< homepage */ diff -r 8d6aa792e0f6 -r b2c8e08508af plugins/docklet/docklet.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/docklet/docklet.h Thu Jul 10 23:13:07 2003 +0000 @@ -0,0 +1,47 @@ +/* System tray icon (aka docklet) plugin for Gaim + * Copyright (C) 2002 Robert McQueen + * Copyright (C) 2003 Herman Bloggs + * Inspired by a similar plugin by: + * John (J5) Palmieri + * + * 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_ + +enum docklet_status { + offline, + offline_connecting, + online, + online_connecting, + online_pending, + away, + away_pending +}; + +struct gaim_tray_ops +{ + void (*create)(); + void (*destroy)(); + void (*update_icon)(enum docklet_status); +}; + +void docklet_clicked(int button_type); +void docklet_embedded(); +void docklet_set_tray_ops(struct gaim_tray_ops *ops); +void docklet_flush_queue(); + +#endif /* _DOCKLET_H_ */ diff -r 8d6aa792e0f6 -r b2c8e08508af plugins/docklet/trayicon-win32.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/docklet/trayicon-win32.c Thu Jul 10 23:13:07 2003 +0000 @@ -0,0 +1,215 @@ +/* System tray icon (aka docklet) plugin for Gaim + * Copyright (C) 2002 Robert McQueen + * Copyright (C) 2003 Herman Bloggs + * Inspired by a similar plugin by: + * John (J5) Palmieri + * + * 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 +#include +#include + +#include "internal.h" +#include "gtkblist.h" +#include "gtkprefs.h" +#include "debug.h" + +#include "gaim.h" +#include "ui.h" + +#include "resource.h" +#include "MinimizeToTray.h" +#include "docklet.h" + +/* + * DEFINES, MACROS & DATA TYPES + */ +#define GAIM_SYSTRAY_HINT _("Gaim Instant Messenger") +#define GAIM_SYSTRAY_DISCONN_HINT _("Gaim Instant Messenger - Signed off") +#define GAIM_SYSTRAY_AWAY_HINT _("Gaim Instant Messenger - Away") +#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 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, "wgaim_systray", "WM_CREATE\n"); + taskbarRestartMsg = RegisterWindowMessage("TaskbarCreated"); + break; + + case WM_TIMER: + gaim_debug(GAIM_DEBUG_INFO, "wgaim_systray", "WM_TIMER\n"); + break; + + case WM_DESTROY: + gaim_debug(GAIM_DEBUG_INFO, "wgaim_systray", "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 = wgaim_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, wgaim_hinstance(), 0)); +} + +static void systray_init_icon(HWND hWnd, HICON icon) { + char* locenc=NULL; + + 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; + locenc=g_locale_from_utf8(GAIM_SYSTRAY_DISCONN_HINT, -1, NULL, NULL, NULL); + strcpy(wgaim_nid.szTip, locenc); + g_free(locenc); + Shell_NotifyIcon(NIM_ADD,&wgaim_nid); + docklet_embedded(); +} + +static void systray_change_icon(HICON icon, char* text) { + char *locenc=NULL; + wgaim_nid.hIcon = icon; + locenc = g_locale_from_utf8(text, -1, NULL, NULL, NULL); + lstrcpy(wgaim_nid.szTip, locenc); + g_free(locenc); + Shell_NotifyIcon(NIM_MODIFY,&wgaim_nid); +} + +static void systray_remove_nid(void) { + Shell_NotifyIcon(NIM_DELETE,&wgaim_nid); +} + +static void wgaim_tray_update_icon(enum docklet_status icon) { + switch (icon) { + case offline: + systray_change_icon(sysicon_disconn, GAIM_SYSTRAY_DISCONN_HINT); + break; + case offline_connecting: + case online_connecting: + break; + case online: + systray_change_icon(sysicon_conn, GAIM_SYSTRAY_HINT); + break; + case online_pending: + systray_change_icon(sysicon_pend, GAIM_SYSTRAY_HINT); + break; + case away: + systray_change_icon(sysicon_away, GAIM_SYSTRAY_AWAY_HINT); + break; + case away_pending: + systray_change_icon(sysicon_awypend, GAIM_SYSTRAY_AWAY_HINT); + break; + } +} + +static void wgaim_tray_create() { + /* dummy window to process systray messages */ + systray_hwnd = systray_create_hiddenwin(); + + /* Load icons, and init systray notify icon */ + sysicon_disconn = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_OFFLINE_TRAY_ICON), IMAGE_ICON, 16, 16, 0); + sysicon_conn = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_TRAY_ICON), IMAGE_ICON, 16, 16, 0); + sysicon_away = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_AWAY_TRAY_ICON), IMAGE_ICON, 16, 16, 0); + sysicon_pend = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_PEND_TRAY_ICON), IMAGE_ICON, 16, 16, 0); + sysicon_awypend = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_AWAYPEND_TRAY_ICON), IMAGE_ICON, 16, 16, 0); + + /* Create icon in systray */ + systray_init_icon(systray_hwnd, sysicon_disconn); + gaim_debug(GAIM_DEBUG_INFO, "docklet", "Tray Icon: created\n"); +} + +static void wgaim_tray_destroy() { + systray_remove_nid(); + DestroyWindow(systray_hwnd); +} + +static struct gaim_tray_ops wgaim_tray_ops = +{ + wgaim_tray_create, + wgaim_tray_destroy, + wgaim_tray_update_icon +}; + +/* Used by docklet's plugin load func */ +void trayicon_init() { + docklet_set_tray_ops(&wgaim_tray_ops); +} diff -r 8d6aa792e0f6 -r b2c8e08508af plugins/docklet/trayicon-x11.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/docklet/trayicon-x11.c Thu Jul 10 23:13:07 2003 +0000 @@ -0,0 +1,160 @@ +/* System tray icon (aka docklet) plugin for Gaim + * Copyright (C) 2002 Robert McQueen + * Copyright (C) 2003 Herman Bloggs + * Inspired by a similar plugin by: + * John (J5) Palmieri + * + * 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 "debug.h" +#include "stock.h" + +#include "gaim.h" +#include "ui.h" + +#include "eggtrayicon.h" +#include "docklet.h" + + +/* globals */ +static EggTrayIcon *docklet = NULL; +static GtkWidget *image = NULL; + +/* protos */ +static void gaim_tray_remove_callbacks(); +static void gaim_tray_create(); + +static void gaim_tray_embedded_cb(GtkWidget *widget, void *data) { + docklet_embedded(); +} + +static gboolean gaim_tray_create_cb() { + gaim_tray_create(); + return FALSE; /* for when we're called by the glib idle handler */ +} + +static void gaim_tray_clicked_cb(GtkWidget *button, GdkEventButton *event, void *data) { + if (event->type != GDK_BUTTON_PRESS) + return; + docklet_clicked(event->button); +} + +static void gaim_tray_destroyed_cb(GtkWidget *widget, void *data) { + gaim_debug(GAIM_DEBUG_INFO, "docklet", "Tray Icon: destroyed\n"); + + docklet_flush_queue(); + + gaim_tray_remove_callbacks(); + + g_object_unref(G_OBJECT(docklet)); + docklet = NULL; + + g_idle_add(gaim_tray_create_cb, &docklet); +} + +static void gaim_tray_remove_callbacks() { + gaim_debug(GAIM_DEBUG_INFO, "docklet", "Tray Icon: removing callbacks"); + + while (g_source_remove_by_user_data(&docklet)) { + gaim_debug(GAIM_DEBUG_INFO, NULL, "."); + } + + gaim_debug(GAIM_DEBUG_INFO, NULL, "\n"); +} + + +static void gaim_tray_update_icon(enum docklet_status icon) { + const gchar *icon_name = NULL; + + switch (icon) { + case offline: + icon_name = GAIM_STOCK_ICON_OFFLINE; + break; + case offline_connecting: + case online_connecting: + icon_name = GAIM_STOCK_ICON_CONNECT; + break; + case online: + icon_name = GAIM_STOCK_ICON_ONLINE; + break; + case online_pending: + icon_name = GAIM_STOCK_ICON_ONLINE_MSG; + break; + case away: + icon_name = GAIM_STOCK_ICON_AWAY; + break; + case away_pending: + icon_name = GAIM_STOCK_ICON_AWAY_MSG; + break; + } + + gtk_image_set_from_stock(GTK_IMAGE(image), icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR); +} + +static void gaim_tray_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, "docklet", + "Tray Icon: trying to create icon but it already exists?\n"); + /*plugin_unload(NULL);*/ + } + + docklet = egg_tray_icon_new("Gaim"); + box = gtk_event_box_new(); + image = gtk_image_new(); + + g_signal_connect(G_OBJECT(docklet), "embedded", G_CALLBACK(gaim_tray_embedded_cb), NULL); + g_signal_connect(G_OBJECT(docklet), "destroy", G_CALLBACK(gaim_tray_destroyed_cb), NULL); + g_signal_connect(G_OBJECT(box), "button-press-event", G_CALLBACK(gaim_tray_clicked_cb), NULL); + + gtk_container_add(GTK_CONTAINER(box), image); + gtk_container_add(GTK_CONTAINER(docklet), box); + gtk_widget_show_all(GTK_WIDGET(docklet)); + + /* ref the docklet before we bandy it about the place */ + g_object_ref(G_OBJECT(docklet)); + + gaim_debug(GAIM_DEBUG_INFO, "docklet", "Tray Icon: created\n"); +} + +static void gaim_tray_destroy() { + gaim_tray_remove_callbacks(); + + g_signal_handlers_disconnect_by_func(G_OBJECT(docklet), G_CALLBACK(gaim_tray_destroyed_cb), NULL); + gtk_widget_destroy(GTK_WIDGET(docklet)); + + g_object_unref(G_OBJECT(docklet)); + docklet = NULL; + + gaim_debug(GAIM_DEBUG_INFO, "docklet", "Tray Icon: removed\n"); +} + +static struct gaim_tray_ops tray_ops = +{ + gaim_tray_create, + gaim_tray_destroy, + gaim_tray_update_icon +}; + +/* Used by docklet's plugin load func */ +void trayicon_init() { + docklet_set_tray_ops(&tray_ops); +}