# Making a custom titlebar

**URL:** <https://discourse.glfw.org/t/making-a-custom-titlebar/2392>\
**Category:** support\
**Created:** [June 3, 2023, 6:47pm UTC](https://discourse.glfw.org/t/making-a-custom-titlebar/2392 "2023-06-03T18:47:15Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![BleastT](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.glfw.org/bleastt/32/774_2.png) [@BleastT](https://discourse.glfw.org/u/BleastT)\
**Post date:** [June 3, 2023, 6:47pm UTC](https://discourse.glfw.org/t/making-a-custom-titlebar/2392/1 "2023-06-03T18:47:16Z")

</div>

I want to disable the current titlebar and draw my own with opengl.

I decided to use GLFW\_DECORATED → GLFW\_FALSE, but this disable everything.

So I had the idea of making the window transparent and draw the screen, reimplement dragging and resizing and all that basic stuff.

My question is, is it even possible to do all the above and if yes, can I still snap the window on my screen in windows 10-11?

Is there a better option to make a custom titlebar?

---

<div class="post-metadata">

**Author:** ![dougbinks](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.glfw.org/dougbinks/32/39_2.png) [@dougbinks](https://discourse.glfw.org/u/dougbinks)\
**Post date:** [June 3, 2023, 7:12pm UTC](https://discourse.glfw.org/t/making-a-custom-titlebar/2392/2 "2023-06-03T19:12:34Z")

</div>

There is a similar question I answered about this here:

> [@Support for undecorated resizeable window](https://discourse.glfw.org/t/support-for-undecorated-resizeable-window/2344/2):
>
> You can resize and move an undecorated window using glfwGetWindowSize and glfwSetWindowPos. These can be used alongside your own UI to provide drag and resizing. For an example of this see the [Dear ImGui Docking branch with viewports](https://github.com/ocornut/imgui/issues/2109). One problem with this is that you no longer receive OS resizing events such as the Windows WIN+LEFT for tiling the window on a part of the screen. I am not sure of the status of the linked issue, but it appears the fork mentioned no longer exists. A newer version…

So you do currently loose aero snap on Windows.

---

<div class="post-metadata">

**Author:** ![dougbinks](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.glfw.org/dougbinks/32/39_2.png) [@dougbinks](https://discourse.glfw.org/u/dougbinks)\
**Post date:** [June 3, 2023, 7:40pm UTC](https://discourse.glfw.org/t/making-a-custom-titlebar/2392/3 "2023-06-03T19:40:58Z")

</div>

If you know Win32 code it is possible to alter GLFW to get borderless with snapping to work, but you’ll need to implement your own move and size controls.

See:

> <https://stackoverflow.com/questions/16765561/borderless-window-using-areo-snap-shadow-minimize-animation-and-shake>

The basic changes in `win32_window.c` were:

```auto
static DWORD getWindowStyle(const _GLFWwindow* window)
{
    DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

    if (window->monitor)
        style |= WS_POPUP;
    else
    {
        style |= WS_SYSMENU | WS_MINIMIZEBOX;

        if (window->decorated)
        {
            style |= WS_CAPTION;

            if (window->resizable)
                style |= WS_MAXIMIZEBOX | WS_THICKFRAME;
        }
        else
            style |= WS_POPUP | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION;
    }

    return style;
}

```

and also add the following on lines 1118 in `win32_window.c` just before the `case WM_PAINT` line.

```auto
        case WM_NCCALCSIZE:
        if (!window->decorated) {
            return 0;
        }
        break;

```

This maximizes slightly weirdly for me so it may need some further work.

---

<div class="post-metadata">

**Author:** ![mmozeiko](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.glfw.org/mmozeiko/32/29_2.png) [@mmozeiko](https://discourse.glfw.org/u/mmozeiko)\
**Post date:** [June 3, 2023, 8:03pm UTC](https://discourse.glfw.org/t/making-a-custom-titlebar/2392/4 "2023-06-03T20:03:02Z")

</div>

I’m not sure if this helps, but I find this [GitHub - rossy/borderless-window: A minimal borderless window with the Windows API](https://github.com/rossy/borderless-window) a really good example on how to do borderless window with all contents custom draw, and window obeying regular rules about shortcuts and interaction with desktop. There are a lot of tiny things you need to take care for window to behave reasonably well.

---

<div class="post-metadata">

**Author:** ![BleastT](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.glfw.org/bleastt/32/774_2.png) [@BleastT](https://discourse.glfw.org/u/BleastT)\
**Post date:** [June 3, 2023, 8:35pm UTC](https://discourse.glfw.org/t/making-a-custom-titlebar/2392/5 "2023-06-03T20:35:17Z")

</div>

Is there any documentation to add something like this for linux and macos as well?

---

<div class="post-metadata">

**Author:** ![BleastT](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.glfw.org/bleastt/32/774_2.png) [@BleastT](https://discourse.glfw.org/u/BleastT)\
**Post date:** [June 4, 2023, 11:59pm UTC](https://discourse.glfw.org/t/making-a-custom-titlebar/2392/6 "2023-06-04T23:59:34Z")

</div>

Hey so on windows i added this code:

```auto
#define GLFW_EXPOSE_NATIVE_WIN32
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>

#include <Windows.h>
#include <dwmapi.h>

    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 = { 0 };
        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);
    }

```

With this, the titlebar disappear and im able to keep resizing and rounded corners. Snapping the window also works on windows 11-10.

Unfortunately there is a small issue. In the place where there was the title bar, there is a very thin white frame which does not have any purpose. It’s just there and it’s really annoying.  
I cant find a way to remove it ☹

 ![Screenshot 2023-06-04 180335](https://canada1.discourse-cdn.com/flex035/uploads/glfw/original/1X/51f92314d93b9cb2d67ea53a81b6c5683937a712.png)

---

<div class="post-metadata">

**Author:** ![BleastT](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.glfw.org/bleastt/32/774_2.png) [@BleastT](https://discourse.glfw.org/u/BleastT)\
**Post date:** [June 10, 2023, 7:59pm UTC](https://discourse.glfw.org/t/making-a-custom-titlebar/2392/7 "2023-06-10T19:59:13Z")

</div>

Hey, so finally I was able to find a soluion. Figuring out a solution completely drained my energy 😅 😅 .

Anyway here is the final code that I used to remove the titlebar on windows. I also implemented the same thing for macos and linux but I wont post them since I dont know if they work.

```
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);
}

```

With this code, you can basically keep all the native functionnality of glfw and windows like snapping the window or resizing and I think you still have rounded corners in windows11(I have to verify that).

---

<div class="post-metadata">

**Author:** ![akash1474](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.glfw.org/akash1474/32/817_2.png) [@akash1474](https://discourse.glfw.org/u/akash1474)\
**Post date:** [October 1, 2023, 4:55pm UTC](https://discourse.glfw.org/t/making-a-custom-titlebar/2392/8 "2023-10-01T16:55:26Z")

</div>

@BleastT can you please attach your win32\_window.c file here or if possible link to your github repo where you implemented it would be great… That top resize border is draining my energy now 😅 😅. I am working on windows 10.

---

<div class="post-metadata">

**Author:** ![BleastT](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.glfw.org/bleastt/32/774_2.png) [@BleastT](https://discourse.glfw.org/u/BleastT)\
**Post date:** [October 12, 2023, 1:55am UTC](https://discourse.glfw.org/t/making-a-custom-titlebar/2392/9 "2023-10-12T01:55:24Z")

</div>

Hey sorry for taking so long to respond . I stopped working on this project so I don’t have the GitHub  
Repo but I remember how it works . So basically you don’t need to recompile the glfw source code yourself . I did not touch the win32\_window.c. I simply added that code in a Cpp file and it overwrite the window procedure used by glfw . So just copy the copy put in a Cpp file and you can just call the disable title bar function with no other work needed
