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_ */