Remove titlebar but keep decorations like border, shadow, rounded corners with glfw

yasa 5 Reputation points
2023-06-06T22:22:32.7433333+00:00

So like I said in the title, I want to have a custom title bar like for example chrome, discord, steam, etc... To do so I want to remove the existing one so that I can draw my own.

Right now , im using the glfw native access to completely disable the title bar so that I can draw my own with opengl. I have found a method that kinda works but there is an issue.

At the top of the window where there was a titlebar before, there is a very thin white frame which in my testing does not have any purpose and just exists for no reason. It's really annoying and I cant find a way to remove it.

The code I used to disable the titlebar:

void disableTitlebar(GLFWwindow* window)
    {
        HWND hWnd = glfwGetWin32Window(window);

        // Remove the title bar
        LONG_PTR lStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
        lStyle &= ~WS_CAPTION;
        SetWindowLongPtr(hWnd, GWL_STYLE, lStyle);

        // Set the window shape and rounded corners
        DWMNCRENDERINGPOLICY policy = DWMNCRP_ENABLED;
        DwmSetWindowAttribute(hWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof(policy));

        // Extend the frame into the client area
        MARGINS margins = { -1 };
        DwmExtendFrameIntoClientArea(hWnd, &margins);

        // Adjust the window size to remove the thin frame at the top
        RECT windowRect;
        GetWindowRect(hWnd, &windowRect);
        SetWindowPos(hWnd, NULL, 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, SWP_FRAMECHANGED | SWP_NOMOVE);
    }

Here is a screenshot of the issue im talking about: imgur link

Any help would be appreciated 😊

Tried tweaking the margins value and looked online but I couldn't find a solution that uses glfw.

Even asked chat gpt, no help from him either.

Windows development | Windows API - Win32
Developer technologies | C++
{count} votes

1 answer

Sort by: Most helpful
  1. yasa 5 Reputation points
    2023-06-10T19:52:33.0133333+00:00

    I found a solution that did exactly what I wanted.

    Here is the final code.

        WNDPROC original_proc;
    
        LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        {
            switch (uMsg)
            {
                case WM_NCCALCSIZE:
                {
                    // Remove the window's standard sizing border
                    if (wParam == TRUE && lParam != NULL)
                    {
                        NCCALCSIZE_PARAMS* pParams = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
                        pParams->rgrc[0].top += 1;
                        pParams->rgrc[0].right -= 2;
                        pParams->rgrc[0].bottom -= 2;
                        pParams->rgrc[0].left += 2;
                    }
                    return 0;
                }
                case WM_NCPAINT:
                {
                    // Prevent the non-client area from being painted
                    return 0;
                }
                case WM_NCHITTEST:
                {
                    // Expand the hit test area for resizing
                    const int borderWidth = 8; // Adjust this value to control the hit test area size
    
                    POINTS mousePos = MAKEPOINTS(lParam);
                    POINT clientMousePos = { mousePos.x, mousePos.y };
                    ScreenToClient(hWnd, &clientMousePos);
    
                    RECT windowRect;
                    GetClientRect(hWnd, &windowRect);
    
                    if (clientMousePos.y >= windowRect.bottom - borderWidth)
                    {
                        if (clientMousePos.x <= borderWidth)
                            return HTBOTTOMLEFT;
                        else if (clientMousePos.x >= windowRect.right - borderWidth)
                            return HTBOTTOMRIGHT;
                        else
                            return HTBOTTOM;
                    }
                    else if (clientMousePos.y <= borderWidth)
                    {
                        if (clientMousePos.x <= borderWidth)
                            return HTTOPLEFT;
                        else if (clientMousePos.x >= windowRect.right - borderWidth)
                            return HTTOPRIGHT;
                        else
                            return HTTOP;
                    }
                    else if (clientMousePos.x <= borderWidth)
                    {
                        return HTLEFT;
                    }
                    else if (clientMousePos.x >= windowRect.right - borderWidth)
                    {
                        return HTRIGHT;
                    }
    
                    break;
                }
            }
            
            return CallWindowProc(original_proc, hWnd, uMsg, wParam, lParam);
        }
        void disableTitlebar(GLFWwindow* window)
        {
            HWND hWnd = glfwGetWin32Window(window);
    
            LONG_PTR lStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
            lStyle |= WS_THICKFRAME;
            lStyle &= ~WS_CAPTION;
            SetWindowLongPtr(hWnd, GWL_STYLE, lStyle);
    
            RECT windowRect;
            GetWindowRect(hWnd, &windowRect);
            int width = windowRect.right - windowRect.left;
            int height = windowRect.bottom - windowRect.top;
    
            original_proc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
            (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WindowProc));
            SetWindowPos(hWnd, NULL, 0, 0, width, height, SWP_FRAMECHANGED | SWP_NOMOVE);
        }
    
    1 person found this answer helpful.
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.