Mercurial > pidgin.yaz
changeset 21257:8b9c48347004
propagate from branch 'im.pidgin.charkins.dockletgeom' (head 0ac7285573f2998a702d7cbc62e7e8cc91e616e8)
to branch 'im.pidgin.pidgin.next.minor' (head 365b126365cc18309aea7f8eef0e9b2a19e6bda8)
author | Casey Harkins <charkins@pidgin.im> |
---|---|
date | Thu, 18 Oct 2007 17:58:40 +0000 |
parents | 33822d7271e5 (diff) ae330012956f (current diff) |
children | d655c8a8d297 |
files | pidgin/gtkdocklet.c |
diffstat | 4 files changed, 269 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- 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
--- 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() {
--- 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);
--- 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<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; @@ -658,7 +851,9 @@ 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 */