Mercurial > pidgin
changeset 3959:9c2d8579ff3e
[gaim-migrate @ 4141]
Gaim systray icon now has a right clickable menu
committer: Tailor Script <tailor@pidgin.im>
author | Herman Bloggs <hermanator12002@yahoo.com> |
---|---|
date | Wed, 13 Nov 2002 23:53:13 +0000 |
parents | 7569347560ed |
children | 7ba5f2e13ee8 |
files | src/win32/systray.c src/win32/systray.h |
diffstat | 2 files changed, 332 insertions(+), 72 deletions(-) [+] |
line wrap: on
line diff
--- a/src/win32/systray.c Wed Nov 13 23:52:16 2002 +0000 +++ b/src/win32/systray.c Wed Nov 13 23:53:13 2002 +0000 @@ -11,30 +11,46 @@ #include "gaim.h" #include "win32dep.h" #include "MinimizeToTray.h" +#include "ui.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 _GAIM_WIN { GAIM_LOGIN_WIN, GAIM_BUDDY_WIN, + GAIM_BACK_WIN, GAIM_WIN_COUNT }; - typedef enum _GAIM_WIN GAIM_WIN; -enum _GAIM_STATE { - GAIM_STATE_NONE = -1, - GAIM_STATE_HIDDEN, - GAIM_STATE_SHOWN, - GAIM_STATE_COUNT +enum _SYSTRAY_STATE { + SYSTRAY_STATE_CONN, + SYSTRAY_STATE_CONNECTING, + SYSTRAY_STATE_DISCONN, + SYSTRAY_STATE_AWAY, + SYSTRAY_STATE_COUNT }; +typedef enum _SYSTRAY_STATE SYSTRAY_STATE; -typedef enum _GAIM_STATE GAIM_STATE; +enum _SYSTRAY_CMND { + SYSTRAY_CMND_MENU_EXIT, + 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 @@ -42,15 +58,131 @@ 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 GAIM_WIN gaim_main_win=-1; static HWND gaim_windows[GAIM_WIN_COUNT]; -static GAIM_STATE main_win_state=-1; +static SYSTRAY_STATE st_state=SYSTRAY_STATE_DISCONN; +static HMENU systray_menu=0; +static HMENU systray_away_menu=0; + +/* + * GLOBALS + */ /* * 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; +} + +/* + * 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; + + /* 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; + AppendMenu(systray_away_menu, MF_STRING, item_count, a->name); + awy = g_slist_next(awy); + item_count+=1; + } + AppendMenu(systray_away_menu, MF_SEPARATOR, 0, 0); + AppendMenu(systray_away_menu, MF_STRING, SYSTRAY_CMND_SET_AWY_NEW, _("New")); + return systray_away_menu; +} + +static void systray_show_menu(int x, int y, BOOL connected) { + /* need to call this so that the menu disappears if clicking outside + of the menu scope */ + SetForegroundWindow(systray_hwnd); + + /* 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)) { + DeleteMenu(systray_menu, SYSTRAY_CMND_SIGNON, MF_BYCOMMAND); + InsertMenu(systray_menu, SYSTRAY_CMND_MENU_EXIT, + MF_BYCOMMAND | MF_STRING, SYSTRAY_CMND_SIGNOFF, _("Signoff")); + } + /* if away menu exists, remove and rebuild it */ + if(systray_away_menu) { + if(!DeleteMenu(systray_menu, (UINT)systray_away_menu, MF_BYCOMMAND)) + debug_printf("Error using DeleteMenu\n"); + } + InsertMenu(systray_menu, SYSTRAY_CMND_PREFS, + MF_BYCOMMAND | MF_POPUP | MF_STRING, (UINT)systray_create_awy_menu(), + _("Set Away Message")); + 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)) { + InsertMenu(systray_menu, (UINT)systray_away_menu, + MF_BYCOMMAND | MF_STRING, SYSTRAY_CMND_BACK, + _("I'm Back")); + } + } 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)) { + DeleteMenu(systray_menu, SYSTRAY_CMND_SIGNOFF, MF_BYCOMMAND); + InsertMenu(systray_menu, SYSTRAY_CMND_MENU_EXIT, + MF_BYCOMMAND | MF_STRING, SYSTRAY_CMND_SIGNON, _("Sign On")); + } + 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) { switch(msg) { @@ -68,20 +200,71 @@ case WM_COMMAND: debug_printf("WM_COMMAND\n"); + switch(LOWORD(wparam)) { + case SYSTRAY_CMND_MENU_EXIT: + do_quit(); + break; + case SYSTRAY_CMND_SIGNON: + debug_printf("signon\n"); + show_login(); + break; + case SYSTRAY_CMND_SIGNOFF: + debug_printf("signoff\n"); + signoff_all(); + break; + case SYSTRAY_CMND_AUTOLOGIN: + debug_printf("autologin\n"); + auto_login(); + break; + case SYSTRAY_CMND_PREFS: + debug_printf("Prefs\n"); + show_prefs(); + break; + case SYSTRAY_CMND_BACK: + debug_printf("I'm back\n"); + do_im_back(NULL, NULL); + break; + case SYSTRAY_CMND_SET_AWY_NEW: + debug_printf("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))) { + debug_printf("Set away message\n"); + systray_set_away(LOWORD(wparam)-SYSTRAY_CMND_SET_AWY); + } + } break; - case WM_TRAYMESSAGE: { if( lparam == WM_LBUTTONDBLCLK ) { /* If Gaim main win is hidden.. restore it */ - if( main_win_state == GAIM_STATE_HIDDEN ) { - RestoreWndFromTray(gaim_windows[gaim_main_win]); + if( st_state == SYSTRAY_STATE_DISCONN ) { + RestoreWndFromTray(gaim_windows[GAIM_LOGIN_WIN]); + } + else if( st_state == SYSTRAY_STATE_AWAY ) { + RestoreWndFromTray(gaim_windows[GAIM_BACK_WIN]); + RestoreWndFromTray(gaim_windows[GAIM_BUDDY_WIN]); + } + else if( st_state == SYSTRAY_STATE_CONN ) { + RestoreWndFromTray(gaim_windows[GAIM_BUDDY_WIN]); } debug_printf("Systray got double click\n"); } - if( lparam == WM_LBUTTONUP ) { - debug_printf("Systray got Left button up\n"); - } + if( lparam == WM_RBUTTONUP ) { + POINT mpoint; + GetCursorPos(&mpoint); + /* Are we connected ? */ + if(st_state == SYSTRAY_STATE_CONNECTING) + break; /* no menu when connecting */ + if(st_state == SYSTRAY_STATE_DISCONN) + systray_show_menu(mpoint.x, mpoint.y, 0); + else + systray_show_menu(mpoint.x, mpoint.y, 1); + } + break; } default: }/* end switch */ @@ -89,7 +272,8 @@ return DefWindowProc(hwnd, msg, wparam, lparam); } -static HWND create_hidenwin() { +/* Create hidden window to process systray messages */ +static HWND systray_create_hiddenwin() { WNDCLASSEX wcex; TCHAR wname[32]; @@ -115,6 +299,21 @@ return (CreateWindow(wname, "", 0, 0, 0, 0, 0, GetDesktopWindow(), NULL, wgaim_hinstance(), 0)); } +static void systray_create_menu(void) { + /* create popup menu */ + if((systray_menu = CreatePopupMenu())) { + if(!AppendMenu(systray_menu, MF_STRING, SYSTRAY_CMND_PREFS, _("Preferences"))) + debug_printf("AppendMenu error: %d\n", GetLastError()); + if(!AppendMenu(systray_menu, MF_STRING, SYSTRAY_CMND_AUTOLOGIN, _("Auto-login"))) + debug_printf("AppendMenu error: %d\n", GetLastError()); + if(!AppendMenu(systray_menu, MF_SEPARATOR, 0, 0)) + debug_printf("AppendMenu error: %d\n", GetLastError()); + if(!AppendMenu(systray_menu, MF_STRING, SYSTRAY_CMND_MENU_EXIT, _("Exit"))) + debug_printf("AppendMenu error: %d\n", GetLastError()); + } else + debug_printf("CreatePopupMenu error: %d\n", GetLastError()); +} + static void systray_init_icon(HWND hWnd, HICON icon) { ZeroMemory(&wgaim_nid,sizeof(wgaim_nid)); wgaim_nid.cbSize=sizeof(NOTIFYICONDATA); @@ -140,76 +339,120 @@ static void systray_minimize_win(HWND hWnd) { MinimizeWndToTray(hWnd); - main_win_state = GAIM_STATE_HIDDEN; +} + +static void systray_update_icon() { + switch(st_state) { + case SYSTRAY_STATE_CONN: + systray_change_icon(sysicon_conn, GAIM_SYSTRAY_HINT); + break; + case SYSTRAY_STATE_CONNECTING: + break; + case SYSTRAY_STATE_DISCONN: + systray_change_icon(sysicon_disconn, GAIM_SYSTRAY_DISCONN_HINT); + break; + case SYSTRAY_STATE_AWAY: + systray_change_icon(sysicon_away, GAIM_SYSTRAY_AWAY_HINT); + break; + } } -static GdkFilterReturn buddywin_filter( GdkXEvent *xevent, GdkEvent *event, gpointer data) { +static void systray_update_status() { + SYSTRAY_STATE old_state = st_state; + + if(connections) { + if(awaymessage) { + st_state = SYSTRAY_STATE_AWAY; + } else if(connecting_count) { + st_state = SYSTRAY_STATE_CONNECTING; + } else { + st_state = SYSTRAY_STATE_CONN; + } + } else { + if(connecting_count) { + st_state = SYSTRAY_STATE_CONNECTING; + } else { + st_state = SYSTRAY_STATE_DISCONN; + } + } + if(st_state != old_state) { + systray_update_icon(); + } +} + +/* + * GAIM WINDOW FILTERS + **********************/ + +static GdkFilterReturn st_buddywin_filter( GdkXEvent *xevent, GdkEvent *event, gpointer data) { MSG *msg = (MSG*)xevent; switch( msg->message ) { - case WM_SHOWWINDOW: - if(msg->wParam) { - debug_printf("Buddy window is being shown\n"); - /* Keep track of the main Gaim window */ - gaim_main_win = GAIM_BUDDY_WIN; - main_win_state = GAIM_STATE_SHOWN; - systray_change_icon(sysicon_conn, GAIM_SYSTRAY_HINT); + case WM_SYSCOMMAND: + if( msg->wParam == SC_MINIMIZE ) { + systray_minimize_win(msg->hwnd); + /* Also minimize I'm back window */ + if(st_state == SYSTRAY_STATE_AWAY) + systray_minimize_win(gaim_windows[GAIM_BACK_WIN]); + return GDK_FILTER_REMOVE; } - else - debug_printf("Buddy window is being hidden\n"); break; + case WM_CLOSE: + systray_minimize_win(msg->hwnd); + /* Also minimize I'm back window */ + if(st_state == SYSTRAY_STATE_AWAY) + systray_minimize_win(gaim_windows[GAIM_BACK_WIN]); + return GDK_FILTER_REMOVE; + } + + return GDK_FILTER_CONTINUE; +} + +static GdkFilterReturn st_loginwin_filter( GdkXEvent *xevent, GdkEvent *event, gpointer data) { + MSG *msg = (MSG*)xevent; + + switch( msg->message ) { + case WM_CLOSE: + systray_minimize_win(msg->hwnd); + return GDK_FILTER_REMOVE; + } + + return GDK_FILTER_CONTINUE; +} + +static GdkFilterReturn st_backwin_filter( GdkXEvent *xevent, GdkEvent *event, gpointer data) { + MSG *msg = (MSG*)xevent; + + switch( msg->message ) { case WM_SYSCOMMAND: if( msg->wParam == SC_MINIMIZE ) { systray_minimize_win(msg->hwnd); return GDK_FILTER_REMOVE; } break; - case WM_CLOSE: - systray_minimize_win(msg->hwnd); - debug_printf("Buddy window closed\n"); - return GDK_FILTER_REMOVE; - case WM_DESTROY: - debug_printf("Buddy window destroyed\n"); - break; } - return GDK_FILTER_CONTINUE; } -static GdkFilterReturn loginwin_filter( GdkXEvent *xevent, GdkEvent *event, gpointer data) { - MSG *msg = (MSG*)xevent; +/* + * GAIM EVENT CALLBACKS + ***********************/ + +static void st_signon(struct gaim_connection *gc, void *data) { + systray_update_status(); +} - switch( msg->message ) { - case WM_SHOWWINDOW: - if(msg->wParam) { - debug_printf("Login window is being shown\n"); - /* Keep track of the main Gaim window */ - gaim_main_win = GAIM_LOGIN_WIN; - main_win_state = GAIM_STATE_SHOWN; - systray_change_icon(sysicon_disconn, GAIM_SYSTRAY_DISCONN_HINT); - } - else - debug_printf("Login window is being hidden\n"); - break; -#if 0 - case WM_SYSCOMMAND: - if( msg->wParam == SC_MINIMIZE ) { - systray_minimize_win(msg->hwnd); - return GDK_FILTER_REMOVE; - } - break; -#endif - case WM_CLOSE: - systray_minimize_win(msg->hwnd); - debug_printf("Login window closed\n"); - return GDK_FILTER_REMOVE; - case WM_DESTROY: - debug_printf("Login window destroyed\n"); - break; - } +static void st_signoff(struct gaim_connection *gc, void *data) { + systray_update_status(); +} - return GDK_FILTER_CONTINUE; +static void st_away(struct gaim_connection *gc, void *data) { + systray_update_status(); +} + +static void st_back(struct gaim_connection *gc, void *data) { + systray_update_status(); } /* @@ -220,36 +463,52 @@ We use this hidden window to proccess WM_TRAYMESSAGE msgs. */ void wgaim_systray_init(void) { /* dummy window to process systray messages */ - systray_hwnd = create_hidenwin(); + systray_hwnd = systray_create_hiddenwin(); + + systray_create_menu(); /* Load icons, and init systray notify icon */ sysicon_disconn = LoadIcon(wgaim_hinstance(),MAKEINTRESOURCE(IDI_ICON2)); sysicon_conn = LoadIcon(wgaim_hinstance(),MAKEINTRESOURCE(IDI_ICON3)); + sysicon_away = LoadIcon(wgaim_hinstance(),MAKEINTRESOURCE(IDI_ICON4)); /* 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) { systray_remove_nid(); + DestroyMenu(systray_menu); + DestroyWindow(systray_hwnd); } /* This function is called after the buddy list has been created */ void wgaim_created_blistwin( GtkWidget *blist ) { gdk_window_add_filter (GTK_WIDGET(blist)->window, - buddywin_filter, + st_buddywin_filter, NULL); - gaim_main_win = GAIM_BUDDY_WIN; gaim_windows[GAIM_BUDDY_WIN] = GDK_WINDOW_HWND(GTK_WIDGET(blist)->window); } /* This function is called after the login window has been created */ void wgaim_created_loginwin( GtkWidget *loginwin ) { gdk_window_add_filter (GTK_WIDGET(loginwin)->window, - loginwin_filter, + st_loginwin_filter, NULL); - gaim_main_win = GAIM_LOGIN_WIN; gaim_windows[GAIM_LOGIN_WIN] = GDK_WINDOW_HWND(GTK_WIDGET(loginwin)->window); - /*systray_init_icon(GDK_WINDOW_HWND(GTK_WIDGET(loginwin)->window), sysicon_disconn);*/ } +void wgaim_created_backwin( GtkWidget *backwin ) { + gdk_window_add_filter (GTK_WIDGET(backwin)->window, + st_backwin_filter, + NULL); + gaim_windows[GAIM_BACK_WIN] = GDK_WINDOW_HWND(GTK_WIDGET(backwin)->window); +}
--- a/src/win32/systray.h Wed Nov 13 23:52:16 2002 +0000 +++ b/src/win32/systray.h Wed Nov 13 23:53:13 2002 +0000 @@ -12,6 +12,7 @@ extern void wgaim_systray_init(void); extern void wgaim_created_blistwin( GtkWidget *blist ); extern void wgaim_created_loginwin( GtkWidget *loginwin ); +extern void wgaim_created_backwin( GtkWidget *backwin ); extern void wgaim_systray_cleanup(void); #endif /* _SYSTRAY_H_ */