Intellij IDEA Community Caption

Answered

Hi,

I have a question regarding how the Window Caption of the Intellij IDEA Community or Ultimate has been developed.

The caption seems to be a custom one comparing to the default Windows Caption which separates the Caption or Titlebar of the Client Area where all the widgets are present. I know that Intellij IDEA has been built mostly using Java, however I still believe some kind of Win32 Interaction must have been done in order to achieve such a custom caption, I was wondering if the code is available somewhere or at least something which could guide us on how we can achieve such a caption using either just Java or the Win32 API.

I had a look into some GitHub Samples which try to achieve a similar caption:

https://github.com/pillisan42/JFxBorderlessNative 

https://github.com/grassator/win32-window-custom-titlebar

https://github.com/melak47/BorderlessWindow

Yet I haven't actually found something that actually has some Client Area Handle or some interoperability with Java, the samples mentioned above have an attempt at solving the problem, but they do not provide a handle for the client area, for example the first example creates a custom Caption using JavaFX and JNI to communicate with the Windows API, however the implementation is very buggy, at least on Windows 11, the client area has some issues with the JavaFX widgets, meaning sometimes the wdigets are not reachable to interact with, no input is received when trying to click them, I believe the issue is related to this function WndProc(HWND hWnd).

I have found these forum posts here which seem to get really close of solving the problem having a almost perfect WindowProc Function.

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

https://discourse.glfw.org/t/making-a-custom-titlebar/2392/6

I was wondering how has the JetBrains Team developed such a complete Window Caption for the JetBrains products.

I know this might not be the right place to ask, but I haven't found any other topic more suitable.

I am also sorry if the question is not appropriate, but this really drives me insane and I haven't found anything on the official Jetbrains Intellij IDEA Community Repository that could help, maybe someone can guide me through it: https://github.com/JetBrains/intellij-community 

Update:

It seems that the above WinProc has solved the Caption problem in my case, the issue I was having was after removing the WS_SYSMENU and WS_CAPTION from the Window Handle (hWnd) there was still space taken at the top of the window, however after using the WinProc Quoted above the issue has been solved. and the widgets can be interacted correctly from JavaFX with the JNI.

Also found this FlatLaf WindowProc: https://github.com/JFormDesigner/FlatLaf/blob/main/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/FlatWndProc.cpp 

Perhaps something to look into for creating a caption like that, does anyone know another one?

Before using the WinProc above for the Custom Caption:

After (Notice the Perfect Flat Effect):

I am still curious about how the Jetbrains has handled the Intellij IDEA Caption, but my issue has been resolved.

Perhaps it would be a good idea to keep this Topic visible in case someone else is gonna encounter the same problem.

Also, in case someone is wondering how I have achieved the blur for the JavaFX Stage, I have used this:

// hWnD is the Window Handle
// Acrylic Effect, Windows 11 Only
#include <dwmapi.h>
BOOL dark = TRUE;
DwmSetWindowAttribute(hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &dark, sizeof(dark));

DWM_SYSTEMBACKDROP_TYPE backdrop = DWMSBT_TRANSIENTWINDOW;
DwmSetWindowAttribute(hWnd, DWMWA_SYSTEMBACKDROP_TYPE, &backdrop, sizeof backdrop);

// Mica Effect, Windows 11 Only
#include <dwmapi.h>
BOOL dark = TRUE;
DwmSetWindowAttribute(hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &dark, sizeof(dark));

DWM_SYSTEMBACKDROP_TYPE backdrop = DWMSBT_MAINWINDOW; // or DWMSBT_TABBEDWINDOW
DwmSetWindowAttribute(hWnd, DWMWA_SYSTEMBACKDROP_TYPE, &backdrop, sizeof backdrop);

I know it drained me of energy trying to find how to achieve those effects, perhaps it might help someone.

Kind regards,

Darie-Dragos Mitoiu

0
1 comment

Hi Dragos,

This forum is about IntelliJ Platform plugin development only, so this is the wrong place to ask this question.

If you want to dig into how this is implemented in the IntelliJ Platform, I suggest using UI Inspector: https://plugins.jetbrains.com/docs/intellij/internal-ui-inspector.html as a starting point.

1

Please sign in to leave a comment.