# HG changeset patch # User Casey Harkins # Date 1192730320 0 # Node ID 8b9c48347004b7dc8519a34df1618530d97d99a6 # Parent 33822d7271e5432c25000cbb81d59e4c06c88705# Parent ae330012956f7d355134bfa57dcb9d3140ae1ad5 propagate from branch 'im.pidgin.charkins.dockletgeom' (head 0ac7285573f2998a702d7cbc62e7e8cc91e616e8) to branch 'im.pidgin.pidgin.next.minor' (head 365b126365cc18309aea7f8eef0e9b2a19e6bda8) diff -r ae330012956f -r 8b9c48347004 pidgin/gtkdocklet-x11.c --- a/pidgin/gtkdocklet-x11.c Tue Oct 16 13:06:48 2007 +0000 +++ b/pidgin/gtkdocklet-x11.c Thu Oct 18 17:58:40 2007 +0000 @@ -229,6 +229,35 @@ } 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 @@ 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 diff -r ae330012956f -r 8b9c48347004 pidgin/gtkdocklet.c --- a/pidgin/gtkdocklet.c Tue Oct 16 13:06:48 2007 +0000 +++ b/pidgin/gtkdocklet.c Thu Oct 18 17:58:40 2007 +0000 @@ -709,6 +709,22 @@ return &i; } +gboolean +pidgin_docklet_get_geometry(gint *x, gint *y, gint *w, gint *h) +{ + if(visible && 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 && ui_ops && ui_ops->get_gdk_screen) + return ui_ops->get_gdk_screen(); + return NULL; +} + void pidgin_docklet_init() { diff -r ae330012956f -r 8b9c48347004 pidgin/gtkdocklet.h --- a/pidgin/gtkdocklet.h Tue Oct 16 13:06:48 2007 +0000 +++ b/pidgin/gtkdocklet.h Thu Oct 18 17:58:40 2007 +0000 @@ -35,6 +35,8 @@ 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_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); diff -r ae330012956f -r 8b9c48347004 pidgin/win32/gtkdocklet-win32.c --- a/pidgin/win32/gtkdocklet-win32.c Tue Oct 16 13:06:48 2007 +0000 +++ b/pidgin/win32/gtkdocklet-win32.c Thu Oct 18 17:58:40 2007 +0000 @@ -570,6 +570,199 @@ 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