im.pidgin.charkins.dockletgeom: 03054fd9afde1bcdafb721ed7712638568c3a3e1

charkins at pidgin.im charkins at pidgin.im
Fri Oct 12 11:05:32 EDT 2007


-----------------------------------------------------------------
Revision: 03054fd9afde1bcdafb721ed7712638568c3a3e1
Ancestor: fa0e512d79dfe479bc36c2436089b51854ef3eb5
Author: charkins at pidgin.im
Date: 2007-10-12T02:47:48
Branch: im.pidgin.charkins.dockletgeom

Modified files:
        pidgin/gtkdocklet-x11.c pidgin/gtkdocklet.c
        pidgin/gtkdocklet.h pidgin/win32/gtkdocklet-win32.c

ChangeLog: 

Add new API to the docklet for retrieving the geometry (x,y,w,h) and the
GdkScreen (if available). The win32 implementation of this is really ugly
and could use some testing.

Refs #521 and #1632.


-------------- next part --------------
============================================================
--- pidgin/gtkdocklet-x11.c	68cc7f0172e70e80c04e4d1b45a54c4bf5c2bd80
+++ pidgin/gtkdocklet-x11.c	e6229166e8ee5fdb2db1ca90d9ae635d2f534991
@@ -229,6 +229,35 @@ static gboolean
 }
 
 static gboolean
+docklet_x11_get_geometry(gint *x, gint *y, gint *w, gint *h)
+{
+	int lx,ly;
+	GtkWidget *widget = GTK_WIDGET(docklet);
+
+	if(docklet==NULL) return FALSE;
+
+	gdk_window_get_origin(GDK_WINDOW(widget->window), &lx, &ly);
+
+	if(x!=NULL) *x = lx + widget->allocation.x;
+	if(y!=NULL) *y = ly + widget->allocation.y;
+
+	if(w!=NULL) *w = widget->allocation.width;
+	if(h!=NULL) *h = widget->allocation.height;
+
+	return TRUE;
+}
+
+static GObject *
+docklet_x11_get_gdk_screen()
+{
+#if GTK_CHECK_VERSION(2,2,0)
+	return (GObject *)gtk_widget_get_screen(GTK_WIDGET(docklet));
+#else
+	return NULL;
+#endif
+}
+
+static gboolean
 docklet_x11_embed_timeout_cb()
 {
 	/* The docklet was not embedded within the timeout.
@@ -313,10 +342,12 @@ static struct docklet_ui_ops ui_ops =
 	docklet_x11_blank_icon,
 	docklet_x11_set_tooltip,
 #if GTK_CHECK_VERSION(2,2,0)
-	docklet_x11_position_menu
+	docklet_x11_position_menu,
 #else
-	NULL
+	NULL,
 #endif
+	docklet_x11_get_geometry,
+	docklet_x11_get_gdk_screen
 };
 
 void
============================================================
--- pidgin/gtkdocklet.c	4c73333047f68075a24e54bdf50f53c632f17e6b
+++ pidgin/gtkdocklet.c	f94b4f2e5579b5ee87895d4c7d5542e99ff28dae
@@ -709,6 +709,22 @@ pidgin_docklet_get_handle()
 	return &i;
 }
 
+gboolean
+pidgin_docklet_get_geometry(gint *x, gint *y, gint *w, gint *h)
+{
+	if(!visible) return FALSE;
+	if(ui_ops && ui_ops->get_geometry) return ui_ops->get_geometry(x, y, w, h);
+	return FALSE;
+}
+
+GObject *
+pidgin_docklet_get_gdk_screen()
+{
+	if(!visible) return NULL;
+	if(ui_ops && ui_ops->get_gdk_screen) return ui_ops->get_gdk_screen();
+	return NULL;
+}
+
 void
 pidgin_docklet_init()
 {
============================================================
--- pidgin/gtkdocklet.h	8dab0d2123705bc96206723eb99ae9919a3700c6
+++ pidgin/gtkdocklet.h	8225bc1dd1e72062a5b3cd032016f76a8550b9f9
@@ -35,6 +35,8 @@ struct docklet_ui_ops
 	void (*blank_icon)(void);
 	void (*set_tooltip)(gchar *);
 	GtkMenuPositionFunc position_menu;
+	gboolean (*get_geometry)(gint *x, gint *y, gint *w, gint *h);
+	GObject *(*get_gdk_screen)(void);
 };
 
 
@@ -49,6 +51,28 @@ void*pidgin_docklet_get_handle(void);
 void pidgin_docklet_uninit(void);
 void*pidgin_docklet_get_handle(void);
 
+/**
+ * Get the geometry of the docklet. Any of the parameters may be
+ * NULL if that value is not desired.
+ *
+ * @param x x coordinate of the top left corner of the docklet in screen coordinates
+ * @param y y coordinate of the top left corner of the docklet in screen coordinates
+ * @param w width of the docklet
+ * @param h height of the docklet
+ *
+ * @return TRUE if the geometry was found, otherwise FALSE
+ */
+gboolean pidgin_docklet_get_geometry(gint *x, gint *y, gint *w, gint *h);
+
+/**
+ * Get the GdkScreen of the docklet. If the GdkScreen is not available, including
+ * running on versions of Gtk/Gdk where GdkScreen does not exist (<2.2), NULL is
+ * returned.
+ *
+ * @return GdkScreen if available, otherwise NULL
+ */
+GObject *pidgin_docklet_get_gdk_screen(void);
+
 /* function in gtkdocklet-{x11,win32}.c */
 void docklet_ui_init(void);
 
============================================================
--- pidgin/win32/gtkdocklet-win32.c	8b3bf5723d39c1cf69f9557a44f7a0745d05634f
+++ pidgin/win32/gtkdocklet-win32.c	44915425e65d5e2d37de904b1ed53457d13a7918
@@ -570,7 +570,200 @@ static void winpidgin_tray_maximize(Pidg
 	RestoreWndFromTray(GDK_WINDOW_HWND(gtkblist->window->window));
 }
 
+/* Checks to see if a window matches a specified name. If it matches,
+ * the matched_hwnd pointer is set to the checked window.
+ *
+ * hwnd is the window to check
+ * matched_hwnd points to hwnd on a match
+ * name is the expected class name
+ * 
+ * returns TRUE if there was a match, otherwise FALSE
+ */
+static BOOL
+check_hwnd_class_name(HWND hwnd, HWND *matched_hwnd, char *name)
+{
+	TCHAR class_name[256];
 
+	/* get class name of window */
+	GetClassName(hwnd, class_name, 255);
+
+	/* compare class name with specified name */
+	if(strncmp(class_name, name, 255)!=0) return FALSE;
+
+	/* set matched_hwnd to hwnd */
+	*matched_hwnd = hwnd;
+	return TRUE;
+}
+
+/* callback for EnumChildWindows looking for TrayNotifyWnd */
+static BOOL CALLBACK
+find_tray_notify_hwnd_cb(HWND hwnd, LPARAM lparam)
+{
+	return !check_hwnd_class_name(hwnd, (HWND*)lparam, "TrayNotifyWnd");
+}
+
+/* callback for EnumChildWindows looking for ToolbarWindow32 */
+static BOOL CALLBACK
+find_tray_toolbar_hwnd_cb(HWND hwnd, LPARAM lparam)
+{
+	return !check_hwnd_class_name(hwnd, (HWND*)lparam, "ToolbarWindow32");
+}
+
+static HWND
+get_tray_toolbar_hwnd()
+{
+	HWND shell_tray_hwnd = NULL;
+	HWND tray_notify_hwnd = NULL;
+	HWND tray_toolbar_hwnd = NULL;
+
+	/* find the top-level window of the system tray area */
+	shell_tray_hwnd = FindWindow("Shell_TrayWnd", NULL);
+	if(!shell_tray_hwnd) return NULL;
+
+	/* enumerate over the shell_tray_hwnd children windows looking for the tray_notify_hwnd */
+	EnumChildWindows(shell_tray_hwnd, find_tray_notify_hwnd_cb, (LPARAM)&tray_notify_hwnd);
+	if(!tray_notify_hwnd || !IsWindow(tray_notify_hwnd)) return NULL;
+
+	/* enumerate over the tray_notify_hwnd children windows looking for tray_toolbar_hwnd */
+	EnumChildWindows(tray_notify_hwnd, find_tray_toolbar_hwnd_cb, (LPARAM)&tray_toolbar_hwnd);
+	if(!tray_toolbar_hwnd || !IsWindow(tray_toolbar_hwnd)) return NULL;
+
+	return tray_toolbar_hwnd;
+}
+
+
+/* Get the geometry of the tray icon. This might break if the user is running a
+ * non-standard shell, in which case this function will return FALSE. If the
+ * tray icon is hidden (possible >= winxp), then the geometry of the tray itself
+ * is returned. If FALSE is returned, x, y, w and h are left unchanged.
+ * Any of the parameters (x, y, w, h) may be NULL if that value is not
+ * desired.
+ *
+ * This code is based on the method and code described here by Irek Zielinski:
+ *     http://www.codeproject.com/shell/ctrayiconposition.asp?msg=999295
+ */
+static gboolean
+winpidgin_tray_get_geometry(gint *x, gint *y, gint *w, gint *h)
+{
+	/* systray_hwnd is the parent window of our systray icon */
+	HWND tray_toolbar_hwnd = NULL;
+	DWORD tray_toolbar_pid = -1;
+	HANDLE tray_toolbar_proc = NULL;
+	int tray_toolbar_bcount = 0;
+	LPVOID tray_toolbar_mem = NULL;
+
+	TBBUTTON button;
+	DWORD nbytes = -1;
+	DWORD hwnd_id_pair[2] = { -1, -1};
+	RECT rect;
+	POINT top_left;
+	POINT bot_right;
+	gboolean found_docklet = FALSE;
+	int i;
+
+	/* get the tray_toolbar_hwnd */
+	tray_toolbar_hwnd = get_tray_toolbar_hwnd();
+	if(!tray_toolbar_hwnd) {
+		return FALSE;
+	}
+
+	/* count buttons in the tray_toolbar_hwnd */
+	tray_toolbar_bcount = SendMessage(tray_toolbar_hwnd, TB_BUTTONCOUNT, 0, 0);
+	if(tray_toolbar_bcount < 1) {
+		return FALSE;
+	}
+
+	/* get pid of the tray_toolbar_hwnd parent process */
+	GetWindowThreadProcessId(tray_toolbar_hwnd, &tray_toolbar_pid);
+	if(tray_toolbar_pid <= 0) {
+		return FALSE;
+	}
+
+	/* open the tray_toolbar_hwnd parent process */
+	tray_toolbar_proc = OpenProcess(PROCESS_ALL_ACCESS, 0, tray_toolbar_pid);
+	if(!tray_toolbar_proc) {
+		return FALSE;
+	}
+
+	/* allocate some memory in the tray_toolbar_hwnd process space */
+	tray_toolbar_mem = VirtualAllocEx(tray_toolbar_proc, NULL, sizeof(TBBUTTON), MEM_COMMIT, PAGE_READWRITE);
+	if(!tray_toolbar_mem) {
+		CloseHandle(tray_toolbar_proc);
+		return FALSE;
+	}
+
+	/* loop through buttons, looking for the docklet */
+	for(i=0; i<tray_toolbar_bcount; i++) {
+
+		/* get the button */
+		SendMessage(tray_toolbar_hwnd, TB_GETBUTTON, i, (LPARAM)tray_toolbar_mem);
+		ReadProcessMemory(tray_toolbar_proc, tray_toolbar_mem, &button, sizeof(TBBUTTON), &nbytes);
+		if(nbytes < sizeof(TBBUTTON)) {
+			continue;
+		}
+
+		/* get the dwData from the button */
+		ReadProcessMemory(tray_toolbar_proc, (LPVOID)button.dwData, &hwnd_id_pair, sizeof(hwnd_id_pair), &nbytes);
+		if(nbytes < sizeof(hwnd_id_pair)) {
+			continue;
+		}
+
+		/* compare hwnd of button against systray_hwnd */
+		if((HWND)hwnd_id_pair[0] != systray_hwnd) {
+			continue;
+		}
+
+		/* check if button is hidden */
+		if(button.fsState & TBSTATE_HIDDEN) {
+			break;
+		}
+
+		/* get RECT of docklet icon */
+		SendMessage(tray_toolbar_hwnd, TB_GETITEMRECT, i, (LPARAM)tray_toolbar_mem);
+		ReadProcessMemory(tray_toolbar_proc, tray_toolbar_mem, &rect, sizeof(RECT), &nbytes);
+		if(nbytes < sizeof(RECT)) {
+			break;
+		}
+
+		/* translate to screen coordinates */
+		top_left.x = rect.left;
+		top_left.y = rect.top;
+		bot_right.x = rect.right;
+		bot_right.y = rect.bottom;
+
+		MapWindowPoints(tray_toolbar_hwnd, NULL, (LPPOINT)&top_left, 1);
+		MapWindowPoints(tray_toolbar_hwnd, NULL, (LPPOINT)&bot_right, 1);
+
+		found_docklet = TRUE;
+		break;
+	}
+
+	if(!found_docklet) {
+		/* fallback on geometry of tray itself */
+		GetWindowRect(tray_toolbar_hwnd, &rect);
+		if(x!=NULL) *x = rect.left;
+		if(y!=NULL) *y = rect.top;
+		if(w!=NULL) *w = rect.right - rect.left;
+		if(h!=NULL) *h = rect.bottom - rect.top;
+	} else {
+		if(x!=NULL) *x = top_left.x;
+		if(y!=NULL) *y = top_left.y;
+		if(w!=NULL) *w = bot_right.x - top_left.x;
+		if(h!=NULL) *h = bot_right.y - top_left.y;
+	}
+
+	/* clean up */
+	VirtualFreeEx(tray_toolbar_proc, tray_toolbar_mem, 0, MEM_RELEASE);
+	CloseHandle(tray_toolbar_proc);
+	return TRUE;
+}
+
+static GObject *
+winpidgin_tray_get_gdk_screen()
+{
+	return (GObject *)gdk_screen_get_default();
+}
+
 static void winpidgin_tray_create() {
 	OSVERSIONINFO osinfo;
 	/* dummy window to process systray messages */
@@ -658,7 +851,9 @@ static struct docklet_ui_ops winpidgin_t
 	winpidgin_tray_update_icon,
 	winpidgin_tray_blank_icon,
 	winpidgin_tray_set_tooltip,
-	NULL
+	NULL,
+	winpidgin_tray_get_geometry,
+	winpidgin_tray_get_gdk_screen
 };
 
 /* Used by docklet's plugin load func */


More information about the Commits mailing list