Mercurial > pidgin
view src/win32/systray.c @ 5939:3014de25a8a4
[gaim-migrate @ 6379]
Tim Ringenbach writes:
"Here's a one liner to make gaim process YAHOO_SERVICE_CHATMSG packets,
which are the same as normal YAHOO_SERVICE_MESSAGE packets, although
they seem less featureful. The java client at chat.yahoo.com sends
these. It receives the normal ones that gaim sends back fine however.
Without this patch, IMs from the java yahoo chat client (possibly
others?) just get ignored, which is probably a BadThing(TM)."
I tend to agree that missing messages is a Bad Thing, and i know sean won't
look at this patch. He'll probly just reverse it because he probly won't
like it, but hopefully this way he might at least give some feedback, and
maybe it will even stay in and do gaim some good.
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Sat, 21 Jun 2003 13:35:23 +0000 |
parents | 9657e243d001 |
children |
line wrap: on
line source
/* * gaim * * File: systray.c * Date: November, 2002 * Description: Windows Gaim systray module * * Copyright (C) 2002-2003, Herman Bloggs <hermanator12002@yahoo.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 "internal.h" #include "gtkblist.h" #include "gtkprefs.h" #include "debug.h" #include "gaim.h" #include "ui.h" #include "resource.h" #include "MinimizeToTray.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 */ #define MAX_AWY_MESSAGES 50 enum _SYSTRAY_STATE { SYSTRAY_STATE_ONLINE, SYSTRAY_STATE_ONLINE_CONNECTING, SYSTRAY_STATE_OFFLINE, SYSTRAY_STATE_OFFLINE_CONNECTING, SYSTRAY_STATE_AWAY, SYSTRAY_STATE_COUNT }; typedef enum _SYSTRAY_STATE SYSTRAY_STATE; enum _SYSTRAY_CMND { SYSTRAY_CMND_MENU_EXIT=100, SYSTRAY_CMND_SIGNON, SYSTRAY_CMND_SIGNOFF, SYSTRAY_CMND_AUTOLOGIN, SYSTRAY_CMND_PREFS, SYSTRAY_CMND_BACK, SYSTRAY_CMND_SET_AWY_NEW, SYSTRAY_CMND_SET_AWY, SYSTRAY_CMND_SET_AWY_LAST=SYSTRAY_CMND_SET_AWY+MAX_AWY_MESSAGES }; typedef enum _SYSTRAY_CMND SYSTRAY_CMND; /* * LOCALS */ static HWND systray_hwnd=0; static HICON sysicon_disconn=0; static HICON sysicon_conn=0; static HICON sysicon_away=0; static NOTIFYICONDATA wgaim_nid; static SYSTRAY_STATE st_state=SYSTRAY_STATE_OFFLINE; static HMENU systray_menu=0; static HMENU systray_away_menu=0; /* * GLOBALS */ extern GtkWidget *imaway; /* * PRIVATE CODE */ /* * SYSTRAY HELPERS ********************/ /* Returns 1 if menu item exists, 0 if not */ static int IsMenuItem( HMENU hMenu, UINT id ) { if(0xFFFFFFFF == GetMenuState(hMenu, id, MF_BYCOMMAND)) return 0; else return 1; } static int GetMenuItemPosition( HMENU hMenu, UINT id ) { int count = GetMenuItemCount(hMenu); int i; for(i=0;i<count;i++) { if(GetMenuItemID(hMenu, i)==id) return i; } return -1; } /* * WGAIM SYSTRAY GUI ********************/ static HMENU systray_create_awy_menu(void) { int item_count = SYSTRAY_CMND_SET_AWY; struct away_message *a = NULL; GSList *awy = away_messages; char* locenc=NULL; /* Delete previous away submenu */ if(systray_away_menu) { DestroyMenu(systray_away_menu); systray_away_menu = 0; } systray_away_menu = CreatePopupMenu(); while (awy && (item_count <= SYSTRAY_CMND_SET_AWY+MAX_AWY_MESSAGES)) { a = (struct away_message *)awy->data; locenc = g_locale_from_utf8(a->name, -1, NULL, NULL, NULL); AppendMenu(systray_away_menu, MF_STRING, item_count, locenc); g_free(locenc); awy = g_slist_next(awy); item_count+=1; } AppendMenu(systray_away_menu, MF_SEPARATOR, 0, 0); locenc = g_locale_from_utf8(_("New"), -1, NULL, NULL, NULL); AppendMenu(systray_away_menu, MF_STRING, SYSTRAY_CMND_SET_AWY_NEW, locenc); g_free(locenc); return systray_away_menu; } static void systray_show_menu(int x, int y, BOOL connected) { char* locenc=NULL; /* need to call this so that the menu disappears if clicking outside of the menu scope */ SetForegroundWindow(systray_hwnd); /* in both connected and disconnected case delete away message menu */ if(systray_away_menu) { if(!DeleteMenu(systray_menu, (UINT)systray_away_menu, MF_BYCOMMAND)) gaim_debug(GAIM_DEBUG_ERROR, "wgaim_systray", "Error using DeleteMenu\n"); } /* Different menus depending on signed on/off state */ if(connected) { /* If signoff item dosn't exist.. create it */ if(!IsMenuItem(systray_menu, SYSTRAY_CMND_SIGNOFF)) { int pos; DeleteMenu(systray_menu, SYSTRAY_CMND_SIGNON, MF_BYCOMMAND); locenc = g_locale_from_utf8(_("Signoff"), -1, NULL, NULL, NULL); pos = GetMenuItemPosition(systray_menu, SYSTRAY_CMND_MENU_EXIT) - 1; if(!InsertMenu(systray_menu, pos, MF_BYPOSITION | MF_STRING, SYSTRAY_CMND_SIGNOFF, locenc)) gaim_debug(GAIM_DEBUG_ERROR, "wgaim_systray", "InsertMenu failed: %s\n", GetLastError()); gaim_debug(GAIM_DEBUG_INFO, "wgaim_systray", "Inserted Menu with ID: %d\n", SYSTRAY_CMND_SIGNOFF); g_free(locenc); } locenc = g_locale_from_utf8(_("Set Away Message"), -1, NULL, NULL, NULL); InsertMenu(systray_menu, SYSTRAY_CMND_PREFS, MF_BYCOMMAND | MF_POPUP | MF_STRING, (UINT)systray_create_awy_menu(), locenc); g_free(locenc); EnableMenuItem(systray_menu, SYSTRAY_CMND_AUTOLOGIN, MF_GRAYED); /* If away, put "I'm Back" option in menu */ if(st_state == SYSTRAY_STATE_AWAY) { if(!IsMenuItem(systray_menu, SYSTRAY_CMND_BACK)) { locenc = g_locale_from_utf8(_("I'm Back"), -1, NULL, NULL, NULL); InsertMenu(systray_menu, (UINT)systray_away_menu, MF_BYCOMMAND | MF_STRING, SYSTRAY_CMND_BACK, locenc); g_free(locenc); } } else { /* Delete I'm Back item if it exists */ DeleteMenu(systray_menu, SYSTRAY_CMND_BACK, MF_BYCOMMAND); } } else { /* If signon item dosn't exist.. create it */ if(!IsMenuItem(systray_menu, SYSTRAY_CMND_SIGNON)) { int pos; DeleteMenu(systray_menu, SYSTRAY_CMND_SIGNOFF, MF_BYCOMMAND); locenc = g_locale_from_utf8(_("Sign On"), -1, NULL, NULL, NULL); pos = GetMenuItemPosition(systray_menu, SYSTRAY_CMND_MENU_EXIT) - 1; if(!InsertMenu(systray_menu, pos, MF_BYPOSITION | MF_STRING, SYSTRAY_CMND_SIGNON, locenc)) gaim_debug(GAIM_DEBUG_ERROR, "wgaim_systray", "InsertMenu failed: %s\n", GetLastError()); g_free(locenc); } EnableMenuItem(systray_menu, SYSTRAY_CMND_AUTOLOGIN, MF_ENABLED); EnableMenuItem(systray_menu, (UINT)systray_away_menu, MF_GRAYED); /* Delete I'm Back item if it exists */ DeleteMenu(systray_menu, SYSTRAY_CMND_BACK, MF_BYCOMMAND); } TrackPopupMenu(systray_menu, // handle to shortcut menu TPM_RIGHTALIGN | TPM_BOTTOMALIGN | TPM_LEFTBUTTON, x, // horizontal position, in screen coordinates y, // vertical position, in screen coordinates 0, // reserved, must be zero systray_hwnd, // handle to owner window NULL // ignored ); } /* Set nth away message from away_messages list */ static void systray_set_away(int nth) { int item_count = 0; GSList *awy = away_messages; struct away_message *a = NULL; while (awy && (item_count != nth)) { awy = g_slist_next(awy); item_count+=1; } if(awy) { a = (struct away_message *)awy->data; do_away_message(NULL, a); } } 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_COMMAND: gaim_debug(GAIM_DEBUG_INFO, "wgaim_systray", "WM_COMMAND\n"); switch(LOWORD(wparam)) { case SYSTRAY_CMND_MENU_EXIT: do_quit(); break; case SYSTRAY_CMND_SIGNON: gaim_debug(GAIM_DEBUG_INFO, "wgaim_systray", "signon\n"); show_login(); break; case SYSTRAY_CMND_SIGNOFF: gaim_debug(GAIM_DEBUG_INFO, "wgaim_systray", "signoff\n"); gaim_connections_disconnect_all(); break; case SYSTRAY_CMND_AUTOLOGIN: gaim_debug(GAIM_DEBUG_INFO, "wgaim_systray", "autologin\n"); gaim_accounts_auto_login(GAIM_GTK_UI); break; case SYSTRAY_CMND_PREFS: gaim_debug(GAIM_DEBUG_INFO, "wgaim_systray", "Prefs\n"); gaim_gtk_prefs_show(); break; case SYSTRAY_CMND_BACK: gaim_debug(GAIM_DEBUG_INFO, "wgaim_systray", "I'm back\n"); do_im_back(NULL, NULL); break; case SYSTRAY_CMND_SET_AWY_NEW: gaim_debug(GAIM_DEBUG_INFO, "wgaim_systray", "New away item\n"); create_away_mess(NULL, NULL); break; default: /* SYSTRAY_CMND_SET_AWY */ if((LOWORD(wparam) >= SYSTRAY_CMND_SET_AWY) && (LOWORD(wparam) <= (SYSTRAY_CMND_SET_AWY + MAX_AWY_MESSAGES))) { gaim_debug(GAIM_DEBUG_INFO, "wgaim_systray", "Set away message\n"); systray_set_away(LOWORD(wparam)-SYSTRAY_CMND_SET_AWY); } } break; case WM_TRAYMESSAGE: { if( lparam == WM_LBUTTONDBLCLK ) { /* Double Click */ /* Either hide or show current window (login or buddy) */ gaim_gtk_blist_docklet_toggle(); gaim_debug(GAIM_DEBUG_INFO, "wgaim_systray", "Systray got double click\n"); } if( lparam == WM_RBUTTONUP ) { /* Right Click */ POINT mpoint; GetCursorPos(&mpoint); switch(st_state) { case SYSTRAY_STATE_OFFLINE: case SYSTRAY_STATE_OFFLINE_CONNECTING: systray_show_menu(mpoint.x, mpoint.y, 0); break; default: systray_show_menu(mpoint.x, mpoint.y, 1); } } 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_create_menu(void) { char* locenc=NULL; /* create popup menu */ if((systray_menu = CreatePopupMenu())) { if(!AppendMenu(systray_menu, MF_STRING, SYSTRAY_CMND_PREFS, (locenc=g_locale_from_utf8(_("Preferences"), -1, NULL, NULL, NULL)))) gaim_debug(GAIM_DEBUG_ERROR, "wgaim_systray", "AppendMenu error: %ld\n", GetLastError()); g_free(locenc); if(!AppendMenu(systray_menu, MF_STRING, SYSTRAY_CMND_AUTOLOGIN, (locenc=g_locale_from_utf8(_("Auto-login"), -1, NULL, NULL, NULL)))) gaim_debug(GAIM_DEBUG_ERROR, "wgaim_systray", "AppendMenu error: %ld\n", GetLastError()); g_free(locenc); if(!AppendMenu(systray_menu, MF_SEPARATOR, 0, 0)) gaim_debug(GAIM_DEBUG_ERROR, "wgaim_systray", "AppendMenu error: %ld\n", GetLastError()); if(!AppendMenu(systray_menu, MF_STRING, SYSTRAY_CMND_MENU_EXIT, (locenc=g_locale_from_utf8(_("Exit"), -1, NULL, NULL, NULL)))) gaim_debug(GAIM_DEBUG_ERROR, "wgaim_systray", "AppendMenu error: %ld\n", GetLastError()); g_free(locenc); } else gaim_debug(GAIM_DEBUG_ERROR, "wgaim_systray", "CreatePopupMenu error: %ld\n", GetLastError()); } 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); } 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 systray_update_icon() { switch(st_state) { case SYSTRAY_STATE_ONLINE: systray_change_icon(sysicon_conn, GAIM_SYSTRAY_HINT); break; case SYSTRAY_STATE_ONLINE_CONNECTING: case SYSTRAY_STATE_OFFLINE_CONNECTING: break; case SYSTRAY_STATE_OFFLINE: systray_change_icon(sysicon_disconn, GAIM_SYSTRAY_DISCONN_HINT); break; case SYSTRAY_STATE_AWAY: systray_change_icon(sysicon_away, GAIM_SYSTRAY_AWAY_HINT); break; case SYSTRAY_STATE_COUNT: /* not a state, here to avoid warning */ default: } } static void systray_update_status() { SYSTRAY_STATE old_state = st_state; if(gaim_connections_get_all()) { if(awaymessage) { st_state = SYSTRAY_STATE_AWAY; } else if(gaim_connections_get_connecting()) { st_state = SYSTRAY_STATE_ONLINE_CONNECTING; } else { st_state = SYSTRAY_STATE_ONLINE; } } else { if(gaim_connections_get_connecting()) { st_state = SYSTRAY_STATE_OFFLINE_CONNECTING; } else { st_state = SYSTRAY_STATE_OFFLINE; } } if(st_state != old_state) { systray_update_icon(); } } /* * GAIM EVENT CALLBACKS ***********************/ static void st_signon(GaimConnection *gc, void *data) { systray_update_status(); } static void st_signoff(GaimConnection *gc, void *data) { systray_update_status(); } static void st_away(GaimConnection *gc, void *data) { systray_update_status(); } static void st_back(GaimConnection *gc, void *data) { systray_update_status(); } /* * PUBLIC CODE */ /* Create a hidden window and associate it with the systray icon. We use this hidden window to proccess WM_TRAYMESSAGE msgs. */ void wgaim_systray_init(void) { gaim_gtk_blist_docklet_add(); /* dummy window to process systray messages */ systray_hwnd = systray_create_hiddenwin(); systray_create_menu(); /* 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); /* Create icon in systray */ systray_init_icon(systray_hwnd, sysicon_disconn); /* Register Gaim event callbacks */ gaim_signal_connect(NULL, event_signon, st_signon, NULL); gaim_signal_connect(NULL, event_signoff, st_signoff, NULL); gaim_signal_connect(NULL, event_away, st_away, NULL); gaim_signal_connect(NULL, event_back, st_back, NULL); /*gaim_signal_connect(NULL, event_connecting, wgaim_st_connecting, NULL); gaim_signal_connect(NULL, event_im_displayed_rcvd, wgaim_st_im_displayed_recv, NULL);*/ } void wgaim_systray_cleanup(void) { /*gaim_gtk_blist_docklet_remove();*/ systray_remove_nid(); DestroyMenu(systray_menu); DestroyWindow(systray_hwnd); } void wgaim_systray_minimize( GtkWidget *window ) { MinimizeWndToTray(GDK_WINDOW_HWND(window->window)); } void wgaim_systray_maximize( GtkWidget *window ) { RestoreWndFromTray(GDK_WINDOW_HWND(window->window)); }