pidgin/win32/gtkdocklet-win32.c

branch
charkins.dockletgeom
changeset 20962
bca687215ee8
parent 20961
f69b1356bb55
child 22687
3cb9f701d421
equal deleted inserted replaced
20961:f69b1356bb55 20962:bca687215ee8
568 568
569 static void winpidgin_tray_maximize(PidginBuddyList *gtkblist) { 569 static void winpidgin_tray_maximize(PidginBuddyList *gtkblist) {
570 RestoreWndFromTray(GDK_WINDOW_HWND(gtkblist->window->window)); 570 RestoreWndFromTray(GDK_WINDOW_HWND(gtkblist->window->window));
571 } 571 }
572 572
573 /* Checks to see if a window matches a specified name. If it matches,
574 * the matched_hwnd pointer is set to the checked window.
575 *
576 * hwnd is the window to check
577 * matched_hwnd points to hwnd on a match
578 * name is the expected class name
579 *
580 * returns TRUE if there was a match, otherwise FALSE
581 */
582 static BOOL
583 check_hwnd_class_name(HWND hwnd, HWND *matched_hwnd, char *name)
584 {
585 TCHAR class_name[256];
586
587 /* get class name of window */
588 GetClassName(hwnd, class_name, 255);
589
590 /* compare class name with specified name */
591 if(strncmp(class_name, name, 255)!=0) return FALSE;
592
593 /* set matched_hwnd to hwnd */
594 *matched_hwnd = hwnd;
595 return TRUE;
596 }
597
598 /* callback for EnumChildWindows looking for TrayNotifyWnd */
599 static BOOL CALLBACK
600 find_tray_notify_hwnd_cb(HWND hwnd, LPARAM lparam)
601 {
602 return !check_hwnd_class_name(hwnd, (HWND*)lparam, "TrayNotifyWnd");
603 }
604
605 /* callback for EnumChildWindows looking for ToolbarWindow32 */
606 static BOOL CALLBACK
607 find_tray_toolbar_hwnd_cb(HWND hwnd, LPARAM lparam)
608 {
609 return !check_hwnd_class_name(hwnd, (HWND*)lparam, "ToolbarWindow32");
610 }
611
612 static HWND
613 get_tray_toolbar_hwnd()
614 {
615 HWND shell_tray_hwnd = NULL;
616 HWND tray_notify_hwnd = NULL;
617 HWND tray_toolbar_hwnd = NULL;
618
619 /* find the top-level window of the system tray area */
620 shell_tray_hwnd = FindWindow("Shell_TrayWnd", NULL);
621 if(!shell_tray_hwnd) return NULL;
622
623 /* enumerate over the shell_tray_hwnd children windows looking for the tray_notify_hwnd */
624 EnumChildWindows(shell_tray_hwnd, find_tray_notify_hwnd_cb, (LPARAM)&tray_notify_hwnd);
625 if(!tray_notify_hwnd || !IsWindow(tray_notify_hwnd)) return NULL;
626
627 /* enumerate over the tray_notify_hwnd children windows looking for tray_toolbar_hwnd */
628 EnumChildWindows(tray_notify_hwnd, find_tray_toolbar_hwnd_cb, (LPARAM)&tray_toolbar_hwnd);
629 if(!tray_toolbar_hwnd || !IsWindow(tray_toolbar_hwnd)) return NULL;
630
631 return tray_toolbar_hwnd;
632 }
633
634
635 /* Get the geometry of the tray icon. This might break if the user is running a
636 * non-standard shell, in which case this function will return FALSE. If the
637 * tray icon is hidden (possible >= winxp), then the geometry of the tray itself
638 * is returned. If FALSE is returned, x, y, w and h are left unchanged.
639 * Any of the parameters (x, y, w, h) may be NULL if that value is not
640 * desired.
641 *
642 * This code is based on the method and code described here by Irek Zielinski:
643 * http://www.codeproject.com/shell/ctrayiconposition.asp?msg=999295
644 */
645 static gboolean
646 winpidgin_tray_get_geometry(gint *x, gint *y, gint *w, gint *h)
647 {
648 /* systray_hwnd is the parent window of our systray icon */
649 HWND tray_toolbar_hwnd = NULL;
650 DWORD tray_toolbar_pid = -1;
651 HANDLE tray_toolbar_proc = NULL;
652 int tray_toolbar_bcount = 0;
653 LPVOID tray_toolbar_mem = NULL;
654
655 TBBUTTON button;
656 DWORD nbytes = -1;
657 DWORD hwnd_id_pair[2] = { -1, -1};
658 RECT rect;
659 POINT top_left;
660 POINT bot_right;
661 gboolean found_docklet = FALSE;
662 int i;
663
664 /* get the tray_toolbar_hwnd */
665 tray_toolbar_hwnd = get_tray_toolbar_hwnd();
666 if(!tray_toolbar_hwnd) {
667 return FALSE;
668 }
669
670 /* count buttons in the tray_toolbar_hwnd */
671 tray_toolbar_bcount = SendMessage(tray_toolbar_hwnd, TB_BUTTONCOUNT, 0, 0);
672 if(tray_toolbar_bcount < 1) {
673 return FALSE;
674 }
675
676 /* get pid of the tray_toolbar_hwnd parent process */
677 GetWindowThreadProcessId(tray_toolbar_hwnd, &tray_toolbar_pid);
678 if(tray_toolbar_pid <= 0) {
679 return FALSE;
680 }
681
682 /* open the tray_toolbar_hwnd parent process */
683 tray_toolbar_proc = OpenProcess(PROCESS_ALL_ACCESS, 0, tray_toolbar_pid);
684 if(!tray_toolbar_proc) {
685 return FALSE;
686 }
687
688 /* allocate some memory in the tray_toolbar_hwnd process space */
689 tray_toolbar_mem = VirtualAllocEx(tray_toolbar_proc, NULL, sizeof(TBBUTTON), MEM_COMMIT, PAGE_READWRITE);
690 if(!tray_toolbar_mem) {
691 CloseHandle(tray_toolbar_proc);
692 return FALSE;
693 }
694
695 /* loop through buttons, looking for the docklet */
696 for(i=0; i<tray_toolbar_bcount; i++) {
697
698 /* get the button */
699 SendMessage(tray_toolbar_hwnd, TB_GETBUTTON, i, (LPARAM)tray_toolbar_mem);
700 ReadProcessMemory(tray_toolbar_proc, tray_toolbar_mem, &button, sizeof(TBBUTTON), &nbytes);
701 if(nbytes < sizeof(TBBUTTON)) {
702 continue;
703 }
704
705 /* get the dwData from the button */
706 ReadProcessMemory(tray_toolbar_proc, (LPVOID)button.dwData, &hwnd_id_pair, sizeof(hwnd_id_pair), &nbytes);
707 if(nbytes < sizeof(hwnd_id_pair)) {
708 continue;
709 }
710
711 /* compare hwnd of button against systray_hwnd */
712 if((HWND)hwnd_id_pair[0] != systray_hwnd) {
713 continue;
714 }
715
716 /* check if button is hidden */
717 if(button.fsState & TBSTATE_HIDDEN) {
718 break;
719 }
720
721 /* get RECT of docklet icon */
722 SendMessage(tray_toolbar_hwnd, TB_GETITEMRECT, i, (LPARAM)tray_toolbar_mem);
723 ReadProcessMemory(tray_toolbar_proc, tray_toolbar_mem, &rect, sizeof(RECT), &nbytes);
724 if(nbytes < sizeof(RECT)) {
725 break;
726 }
727
728 /* translate to screen coordinates */
729 top_left.x = rect.left;
730 top_left.y = rect.top;
731 bot_right.x = rect.right;
732 bot_right.y = rect.bottom;
733
734 MapWindowPoints(tray_toolbar_hwnd, NULL, (LPPOINT)&top_left, 1);
735 MapWindowPoints(tray_toolbar_hwnd, NULL, (LPPOINT)&bot_right, 1);
736
737 found_docklet = TRUE;
738 break;
739 }
740
741 if(!found_docklet) {
742 /* fallback on geometry of tray itself */
743 GetWindowRect(tray_toolbar_hwnd, &rect);
744 if(x!=NULL) *x = rect.left;
745 if(y!=NULL) *y = rect.top;
746 if(w!=NULL) *w = rect.right - rect.left;
747 if(h!=NULL) *h = rect.bottom - rect.top;
748 } else {
749 if(x!=NULL) *x = top_left.x;
750 if(y!=NULL) *y = top_left.y;
751 if(w!=NULL) *w = bot_right.x - top_left.x;
752 if(h!=NULL) *h = bot_right.y - top_left.y;
753 }
754
755 /* clean up */
756 VirtualFreeEx(tray_toolbar_proc, tray_toolbar_mem, 0, MEM_RELEASE);
757 CloseHandle(tray_toolbar_proc);
758 return TRUE;
759 }
760
761 static GObject *
762 winpidgin_tray_get_gdk_screen()
763 {
764 return (GObject *)gdk_screen_get_default();
765 }
766 573
767 static void winpidgin_tray_create() { 574 static void winpidgin_tray_create() {
768 OSVERSIONINFO osinfo; 575 OSVERSIONINFO osinfo;
769 /* dummy window to process systray messages */ 576 /* dummy window to process systray messages */
770 systray_hwnd = systray_create_hiddenwin(); 577 systray_hwnd = systray_create_hiddenwin();
849 winpidgin_tray_create, 656 winpidgin_tray_create,
850 winpidgin_tray_destroy, 657 winpidgin_tray_destroy,
851 winpidgin_tray_update_icon, 658 winpidgin_tray_update_icon,
852 winpidgin_tray_blank_icon, 659 winpidgin_tray_blank_icon,
853 winpidgin_tray_set_tooltip, 660 winpidgin_tray_set_tooltip,
854 NULL, 661 NULL
855 winpidgin_tray_get_geometry,
856 winpidgin_tray_get_gdk_screen
857 }; 662 };
858 663
859 /* Used by docklet's plugin load func */ 664 /* Used by docklet's plugin load func */
860 void docklet_ui_init() { 665 void docklet_ui_init() {
861 /* Initialize the cached icons to NULL */ 666 /* Initialize the cached icons to NULL */

mercurial