| 1 /* |
|
| 2 * System tray icon (aka docklet) plugin for Gaim |
|
| 3 * |
|
| 4 * Copyright (C) 2002-3 Robert McQueen <robot101@debian.org> |
|
| 5 * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com> |
|
| 6 * Inspired by a similar plugin by: |
|
| 7 * John (J5) Palmieri <johnp@martianrock.com> |
|
| 8 * |
|
| 9 * This program is free software; you can redistribute it and/or |
|
| 10 * modify it under the terms of the GNU General Public License as |
|
| 11 * published by the Free Software Foundation; either version 2 of the |
|
| 12 * License, or (at your option) any later version. |
|
| 13 * |
|
| 14 * This program is distributed in the hope that it will be useful, but |
|
| 15 * WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
| 17 * General Public License for more details. |
|
| 18 * |
|
| 19 * You should have received a copy of the GNU General Public License |
|
| 20 * along with this program; if not, write to the Free Software |
|
| 21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
|
| 22 * 02111-1307, USA. |
|
| 23 */ |
|
| 24 |
|
| 25 #include <windows.h> |
|
| 26 #include <gdk/gdkwin32.h> |
|
| 27 #include <gdk/gdk.h> |
|
| 28 |
|
| 29 #include "internal.h" |
|
| 30 #include "gtkblist.h" |
|
| 31 #include "gtkprefs.h" |
|
| 32 #include "debug.h" |
|
| 33 |
|
| 34 #include "gaim.h" |
|
| 35 #include "gtkdialogs.h" |
|
| 36 |
|
| 37 #include "resource.h" |
|
| 38 #include "MinimizeToTray.h" |
|
| 39 #include "docklet.h" |
|
| 40 |
|
| 41 /* |
|
| 42 * DEFINES, MACROS & DATA TYPES |
|
| 43 */ |
|
| 44 #define WM_TRAYMESSAGE WM_USER /* User defined WM Message */ |
|
| 45 |
|
| 46 /* |
|
| 47 * LOCALS |
|
| 48 */ |
|
| 49 static HWND systray_hwnd=0; |
|
| 50 static HICON sysicon_disconn=0; |
|
| 51 static HICON sysicon_conn=0; |
|
| 52 static HICON sysicon_away=0; |
|
| 53 static HICON sysicon_pend=0; |
|
| 54 static HICON sysicon_awypend=0; |
|
| 55 static HICON sysicon_blank=0; |
|
| 56 static NOTIFYICONDATA wgaim_nid; |
|
| 57 |
|
| 58 |
|
| 59 static LRESULT CALLBACK systray_mainmsg_handler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { |
|
| 60 static UINT taskbarRestartMsg; /* static here means value is kept across multiple calls to this func */ |
|
| 61 |
|
| 62 switch(msg) { |
|
| 63 case WM_CREATE: |
|
| 64 gaim_debug(GAIM_DEBUG_INFO, "tray icon", "WM_CREATE\n"); |
|
| 65 taskbarRestartMsg = RegisterWindowMessage("TaskbarCreated"); |
|
| 66 break; |
|
| 67 |
|
| 68 case WM_TIMER: |
|
| 69 gaim_debug(GAIM_DEBUG_INFO, "tray icon", "WM_TIMER\n"); |
|
| 70 break; |
|
| 71 |
|
| 72 case WM_DESTROY: |
|
| 73 gaim_debug(GAIM_DEBUG_INFO, "tray icon", "WM_DESTROY\n"); |
|
| 74 break; |
|
| 75 |
|
| 76 case WM_TRAYMESSAGE: |
|
| 77 { |
|
| 78 int type = 0; |
|
| 79 |
|
| 80 /* We'll use Double Click - Single click over on linux */ |
|
| 81 if( lparam == WM_LBUTTONDBLCLK ) |
|
| 82 type = 1; |
|
| 83 else if( lparam == WM_MBUTTONUP ) |
|
| 84 type = 2; |
|
| 85 else if( lparam == WM_RBUTTONUP ) |
|
| 86 type = 3; |
|
| 87 else |
|
| 88 break; |
|
| 89 |
|
| 90 docklet_clicked(type); |
|
| 91 break; |
|
| 92 } |
|
| 93 default: |
|
| 94 if (msg == taskbarRestartMsg) { |
|
| 95 /* explorer crashed and left us hanging... |
|
| 96 This will put the systray icon back in it's place, when it restarts */ |
|
| 97 Shell_NotifyIcon(NIM_ADD,&wgaim_nid); |
|
| 98 } |
|
| 99 break; |
|
| 100 }/* end switch */ |
|
| 101 |
|
| 102 return DefWindowProc(hwnd, msg, wparam, lparam); |
|
| 103 } |
|
| 104 |
|
| 105 /* Create hidden window to process systray messages */ |
|
| 106 static HWND systray_create_hiddenwin() { |
|
| 107 WNDCLASSEX wcex; |
|
| 108 TCHAR wname[32]; |
|
| 109 |
|
| 110 strcpy(wname, "GaimWin"); |
|
| 111 |
|
| 112 wcex.cbSize = sizeof(WNDCLASSEX); |
|
| 113 |
|
| 114 wcex.style = 0; |
|
| 115 wcex.lpfnWndProc = (WNDPROC)systray_mainmsg_handler; |
|
| 116 wcex.cbClsExtra = 0; |
|
| 117 wcex.cbWndExtra = 0; |
|
| 118 wcex.hInstance = wgaim_hinstance(); |
|
| 119 wcex.hIcon = NULL; |
|
| 120 wcex.hCursor = NULL, |
|
| 121 wcex.hbrBackground = NULL; |
|
| 122 wcex.lpszMenuName = NULL; |
|
| 123 wcex.lpszClassName = wname; |
|
| 124 wcex.hIconSm = NULL; |
|
| 125 |
|
| 126 RegisterClassEx(&wcex); |
|
| 127 |
|
| 128 /* Create the window */ |
|
| 129 return (CreateWindow(wname, "", 0, 0, 0, 0, 0, GetDesktopWindow(), NULL, wgaim_hinstance(), 0)); |
|
| 130 } |
|
| 131 |
|
| 132 static void systray_init_icon(HWND hWnd, HICON icon) { |
|
| 133 ZeroMemory(&wgaim_nid,sizeof(wgaim_nid)); |
|
| 134 wgaim_nid.cbSize=sizeof(NOTIFYICONDATA); |
|
| 135 wgaim_nid.hWnd=hWnd; |
|
| 136 wgaim_nid.uID=0; |
|
| 137 wgaim_nid.uFlags=NIF_ICON | NIF_MESSAGE | NIF_TIP; |
|
| 138 wgaim_nid.uCallbackMessage=WM_TRAYMESSAGE; |
|
| 139 wgaim_nid.hIcon=icon; |
|
| 140 lstrcpy(wgaim_nid.szTip, ""); |
|
| 141 Shell_NotifyIcon(NIM_ADD,&wgaim_nid); |
|
| 142 docklet_embedded(); |
|
| 143 } |
|
| 144 |
|
| 145 static void systray_change_icon(HICON icon) { |
|
| 146 wgaim_nid.hIcon = icon; |
|
| 147 Shell_NotifyIcon(NIM_MODIFY,&wgaim_nid); |
|
| 148 } |
|
| 149 |
|
| 150 static void systray_remove_nid(void) { |
|
| 151 Shell_NotifyIcon(NIM_DELETE,&wgaim_nid); |
|
| 152 } |
|
| 153 |
|
| 154 static void wgaim_tray_update_icon(DockletStatus icon) { |
|
| 155 switch (icon) { |
|
| 156 case DOCKLET_STATUS_OFFLINE: |
|
| 157 systray_change_icon(sysicon_disconn); |
|
| 158 break; |
|
| 159 case DOCKLET_STATUS_CONNECTING: |
|
| 160 break; |
|
| 161 case DOCKLET_STATUS_ONLINE: |
|
| 162 systray_change_icon(sysicon_conn); |
|
| 163 break; |
|
| 164 case DOCKLET_STATUS_ONLINE_PENDING: |
|
| 165 systray_change_icon(sysicon_pend); |
|
| 166 break; |
|
| 167 case DOCKLET_STATUS_AWAY: |
|
| 168 systray_change_icon(sysicon_away); |
|
| 169 break; |
|
| 170 case DOCKLET_STATUS_AWAY_PENDING: |
|
| 171 systray_change_icon(sysicon_awypend); |
|
| 172 break; |
|
| 173 } |
|
| 174 } |
|
| 175 |
|
| 176 static void wgaim_tray_blank_icon() { |
|
| 177 systray_change_icon(sysicon_blank); |
|
| 178 } |
|
| 179 |
|
| 180 static void wgaim_tray_set_tooltip(gchar *tooltip) { |
|
| 181 if (tooltip) { |
|
| 182 char *locenc = NULL; |
|
| 183 locenc = g_locale_from_utf8(tooltip, -1, NULL, NULL, NULL); |
|
| 184 lstrcpyn(wgaim_nid.szTip, locenc, sizeof(wgaim_nid.szTip)/sizeof(TCHAR)); |
|
| 185 g_free(locenc); |
|
| 186 } else { |
|
| 187 lstrcpy(wgaim_nid.szTip, ""); |
|
| 188 } |
|
| 189 Shell_NotifyIcon(NIM_MODIFY, &wgaim_nid); |
|
| 190 } |
|
| 191 |
|
| 192 void wgaim_tray_minimize(GaimGtkBuddyList *gtkblist) { |
|
| 193 MinimizeWndToTray(GDK_WINDOW_HWND(gtkblist->window->window)); |
|
| 194 } |
|
| 195 |
|
| 196 void wgaim_tray_maximize(GaimGtkBuddyList *gtkblist) { |
|
| 197 RestoreWndFromTray(GDK_WINDOW_HWND(gtkblist->window->window)); |
|
| 198 } |
|
| 199 |
|
| 200 |
|
| 201 static void wgaim_tray_create() { |
|
| 202 OSVERSIONINFO osinfo; |
|
| 203 /* dummy window to process systray messages */ |
|
| 204 systray_hwnd = systray_create_hiddenwin(); |
|
| 205 |
|
| 206 osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); |
|
| 207 GetVersionEx(&osinfo); |
|
| 208 |
|
| 209 /* Load icons, and init systray notify icon |
|
| 210 * NOTE: Windows > XP only supports displaying 4-bit images in the Systray, |
|
| 211 * 2K and ME will use the highest color depth that the desktop will support, |
|
| 212 * but will scale it back to 4-bits for display. |
|
| 213 * That is why we use custom 4-bit icons for pre XP Windowses */ |
|
| 214 if (osinfo.dwMajorVersion == 5 && osinfo.dwMinorVersion > 0) { |
|
| 215 sysicon_disconn = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_OFFLINE_TRAY_ICON), IMAGE_ICON, 16, 16, 0); |
|
| 216 sysicon_conn = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_TRAY_ICON), IMAGE_ICON, 16, 16, 0); |
|
| 217 sysicon_away = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_AWAY_TRAY_ICON), IMAGE_ICON, 16, 16, 0); |
|
| 218 sysicon_pend = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_PEND_TRAY_ICON), IMAGE_ICON, 16, 16, 0); |
|
| 219 sysicon_awypend = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_AWAYPEND_TRAY_ICON), IMAGE_ICON, 16, 16, 0); |
|
| 220 } else { |
|
| 221 sysicon_disconn = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_OFFLINE_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0); |
|
| 222 sysicon_conn = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0); |
|
| 223 sysicon_away = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_AWAY_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0); |
|
| 224 sysicon_pend = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_PEND_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0); |
|
| 225 sysicon_awypend = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_AWAYPEND_TRAY_ICON_4BIT), IMAGE_ICON, 16, 16, 0); |
|
| 226 } |
|
| 227 sysicon_blank = (HICON)LoadImage(wgaim_hinstance(), MAKEINTRESOURCE(GAIM_BLANK_TRAY_ICON), IMAGE_ICON, 16, 16, 0); |
|
| 228 |
|
| 229 /* Create icon in systray */ |
|
| 230 systray_init_icon(systray_hwnd, sysicon_disconn); |
|
| 231 |
|
| 232 gaim_signal_connect(gaim_gtk_blist_get_handle(), "gtkblist-hiding", |
|
| 233 &handle, GAIM_CALLBACK(wgaim_tray_minimize), NULL); |
|
| 234 gaim_signal_connect(gaim_gtk_blist_get_handle(), "gtkblist-unhiding", |
|
| 235 &handle, GAIM_CALLBACK(wgaim_tray_maximize), NULL); |
|
| 236 |
|
| 237 gaim_debug(GAIM_DEBUG_INFO, "tray icon", "created\n"); |
|
| 238 } |
|
| 239 |
|
| 240 static void wgaim_tray_destroy() { |
|
| 241 gaim_signals_disconnect_by_handle(&handle); |
|
| 242 systray_remove_nid(); |
|
| 243 DestroyWindow(systray_hwnd); |
|
| 244 docklet_remove(); |
|
| 245 } |
|
| 246 |
|
| 247 static struct docklet_ui_ops wgaim_tray_ops = |
|
| 248 { |
|
| 249 wgaim_tray_create, |
|
| 250 wgaim_tray_destroy, |
|
| 251 wgaim_tray_update_icon, |
|
| 252 wgaim_tray_blank_icon, |
|
| 253 wgaim_tray_set_tooltip, |
|
| 254 NULL |
|
| 255 }; |
|
| 256 |
|
| 257 /* Used by docklet's plugin load func */ |
|
| 258 void docklet_ui_init() { |
|
| 259 docklet_set_ui_ops(&wgaim_tray_ops); |
|
| 260 } |
|