Search code examples
c++user-interfacewinapi

Remove default title bar while keeping default borders (Win API and C++)


I am trying to replicate the GUI of the Powershell, Firefox, Word,... with the Win API in C++. We can see that the default title bar is removed and the client area is taking the whole window while keeping the default borders (see screenshot).

enter image description here

I want the window to respond to all functionalities correctly (aerosnap, resize, border colors, ...).

The closest I could get was by using a combination of

MARGINS margins = { 1 };
DwmExtendFrameIntoClientArea(hWnd, &margins);

and

case WM_NCCALCSIZE:
    return 0;

But the window does not have the resize handles anymore and the borders are not taking the right color (when "Show accent color on title bars and window borders" is enabled in settings).

Do you know the recipe to get the desired result ?


Solution

  • I read the Firefox source code and found my answer.

    All you have to do is create a WS_OVERLAPPEDWINDOW window and give the client area Rect for each WM_NCCALCSIZE message (read doc).

    case WM_NCCALCSIZE: {
        RECT* clientRect =
            wParam ? &(reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam))->rgrc[0] : (reinterpret_cast<RECT*>(lParam));
        clientRect->top += 0;
        clientRect->left += 7;
        clientRect->right -= 7;
        clientRect->bottom -= 7;
        return 0;
    }
    

    However, when the window shows up for the first time, there were some rebel pixels near the borders which did not want to be painted with the background color.

    The left border appears 1 pixel wider than the bottom one:

    Rebel pixel column

    I found out that those pixels were painted correctly as soon as the window was resized. So to solve it before the app is visible, I resized the window at start-up in the WM_ACTIVATE message:

    case WM_ACTIVATE: {
        static bool startup = true;
        if (startup) {
            startup = false;
            // Change values so that your window increases in all directions
            MoveWindow(hWnd, 100, 100, 800, 800, TRUE); 
        }
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    

    Note that you will have to implement the resize logic yourself in the WM_NCHITTEST message to get the arrow cursor (read doc).

    Finally I got a window with default borders only and I am free to paint the client area. Every functionality seems to work.

    Result:

    No title bar window