Question

On my Qt application i've used DwmExtendFrameIntoClientArea to extend the Aero Glass inside my window and i've handled the WM_NCCALCSIZE WinEvent to draw Qt widgets at the non client area.

Also, on my app i've handled the WM_NCRBUTTONUP WinEvent to display the window system(title bar) menu inside the client area of my window.

The menu works, i mean, i can restore, maximize, minimize and close the window through that menu, however, sometimes the enabled items of the menu does not match with the state of the window, example: Sometimes that menu don't enables restore but enables maximize on a window that is already maximized, while i have no problems with the system menu displayed through Windows TaskBar

The question: how do i properly show that menu matching with the current window state?

Code to listen WinEvents:

bool MainWindow::winEvent(MSG *msg, long *result)
{
    HWND hWnd = msg->hwnd;
    UINT message = msg->message;
    WPARAM wParam = msg->wParam;
    LPARAM lParam = msg->lParam;

    bool retval = false;
    LRESULT lRet = 0;

    switch(message)
    {
    case WM_NCHITTEST:
    {
        lRet = HitTestNCA(hWnd, lParam);
        DwmDefWindowProc(hWnd, message, wParam, lParam, &lRet);
        retval = true;
        break;
    }
    case WM_NCRBUTTONUP:
    {
        QPoint point = QCursor::pos();
        HMENU menu = GetSystemMenu(hWnd, FALSE);
        BOOL Selected = TrackPopupMenu(menu, TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, point.x(), point.y(), 0, hWnd, NULL);
        if(Selected) PostMessage(hWnd, WM_SYSCOMMAND, Selected, 0);
        break;
    }
    case WM_NCCALCSIZE:
    {
        retval = true;
        break;
    }
    default:
        break;
    }

    *result = lRet;

    if(retval) return true;

    return QMainWindow::winEvent(msg, result);
}
Was it helpful?

Solution

Based on the Firefox source code I've developed the following code that solves my problem:

HMENU hMenu = GetSystemMenu(hWnd, FALSE);

if (hMenu)
{
    MENUITEMINFO mii;
    mii.cbSize = sizeof(MENUITEMINFO);
    mii.fMask = MIIM_STATE;
    mii.fType = 0;

    // update the options
    mii.fState = MF_ENABLED;
    SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii);
    SetMenuItemInfo(hMenu, SC_SIZE, FALSE, &mii);
    SetMenuItemInfo(hMenu, SC_MOVE, FALSE, &mii);
    SetMenuItemInfo(hMenu, SC_MAXIMIZE, FALSE, &mii);
    SetMenuItemInfo(hMenu, SC_MINIMIZE, FALSE, &mii);

    mii.fState = MF_GRAYED;

    WINDOWPLACEMENT wp;
    GetWindowPlacement(hWnd, &wp);

    switch (wp.showCmd)
    {
    case SW_SHOWMAXIMIZED:
        SetMenuItemInfo(hMenu, SC_SIZE, FALSE, &mii);
        SetMenuItemInfo(hMenu, SC_MOVE, FALSE, &mii);
        SetMenuItemInfo(hMenu, SC_MAXIMIZE, FALSE, &mii);
        SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
        break;
    case SW_SHOWMINIMIZED:
        SetMenuItemInfo(hMenu, SC_MINIMIZE, FALSE, &mii);
        SetMenuDefaultItem(hMenu, SC_RESTORE, FALSE);
        break;
    case SW_SHOWNORMAL:
        SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii);
        SetMenuDefaultItem(hMenu, SC_CLOSE, FALSE);
        break;
    }

    LPARAM cmd = TrackPopupMenu(hMenu, (TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD),
                                GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), NULL, hWnd, NULL);

    if (cmd) PostMessage(hWnd, WM_SYSCOMMAND, cmd, 0);
}

Apparently you need to manually set the enabled and disabled items.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top