| 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(); |