Search code examples
winapitrayicon

Toggle window visibility on tray icon click using WinAPI


How can I bring a window to the top if not there, and close it otherwise, when the tray icon is clicked, using the Windows API? That is, very similar to what the taskbar icon does. By bring to the top I mean fully visible to the user.

I cannot find a way to tell whether the window is on top or not, because when the tray icon is clicked, the taskbar is always on top. I tried inspecting the Z-order of the windows but it looks inconsistent. For example, when the application window is on top and tray icon is clicked, I would expect a constant number of taskbar/tray windows to be brought to top, and the window immediately following them being the one that was on top. But that's not the case, it seems.

I could mostly implement it, the problem is that the toggle doesn't care whether the window is open and fully visible to the user (on top). When the tray icon is clicked and the window is currently closed, it is opened and brought to top correctly. When the window is open and on top, it is also closed correctly. However, when the window is open but not on top, it will be closed instead of being brought to foreground.


Solution

  • Thanks to Mike Gelfand who solved the problem! The following function will return:

    • -1 when window is closed
    • 0 when window is fully visible
    • 1 or above when window is open but not fully visible
    int GetMyWindowLevel(HWND myWindow) {
    
        WINDOWINFO myWindowInfo;
        myWindowInfo.cbSize = sizeof(myWindowInfo);
        if (!GetWindowInfo(myWindow, &myWindowInfo))
            return -1;
    
        int myWindowLevel = -1;
        HWND currentWindow = GetTopWindow(NULL);
    
        for (; currentWindow != NULL;
            currentWindow = GetNextWindow(currentWindow, GW_HWNDNEXT)) {
    
            WINDOWINFO currentWindowInfo;
            currentWindowInfo.cbSize = sizeof(currentWindowInfo);
            if (!GetWindowInfo(currentWindow, &currentWindowInfo))
                continue;
    
            if ((currentWindowInfo.dwExStyle & WS_EX_TOPMOST) !=
                (myWindowInfo.dwExStyle & WS_EX_TOPMOST) ||
                (currentWindowInfo.dwStyle & WS_POPUP) != 0)
                continue;
    
            ++myWindowLevel;
            if (currentWindow == myWindow)
                break;
        }
        return currentWindow == myWindow ? myWindowLevel : -1;
    }