QWindowKit replaces the Qt title bar without losing what the OS does
Cross-platform frameless window framework for Qt. Support Windows, macOS, Linux.
At a glance
- What is it?
- QWindowKit is a C++ framework for Qt Widgets and Qt Quick that lets an application draw its own title bar while keeping the system behaviours the user expects, including window moving, resizing, system menus and Windows Snap Layout. It is a refactor of the FramelessHelper idea with a smaller API, and it depends on Qt private APIs, which is the trade-off to think about first.
- Who is it for?
- QWindowKit is worth adopting if your Qt application already draws a custom title bar and you have been reimplementing drag, resize and Snap Layout by hand, because the framework gives you the platform behaviour for Windows, macOS and Linux in one API and keeps the hit testing rules explicit.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A custom title bar is the easy part
Every application that decides to draw its own title bar discovers the same list of things the operating system was doing for it. The window has to drag. It has to resize from the edges, with the right hit zones and the right cursor. The system menu has to work, with the menu key, the right click, the window icon and the minimise, maximise and close buttons. On Windows 11 there is the Snap Layout hover that a user expects when they hover the maximise button. On macOS the traffic light buttons have to sit in the right place and the window has to round correctly, and the shadows and blur have to behave.
QWindowKit is a cross-platform window customization framework for Qt Widgets and Qt Quick, and the project states its purpose as helping applications replace the native title bar with a custom title bar while preserving important system behaviors such as window moving, resizing, system menus and Windows Snap Layout.
The platform-specific work lives in a single abstraction, the window agent, and the framework splits into three modules. QWindowKit::Core is the shared platform window infrastructure. QWindowKit::Widgets integrates with QWidget and QMainWindow. QWindowKit::Quick integrates with QQuickWindow and the QML Window type. The two build options are QWINDOWKIT_BUILD_WIDGETS, which is enabled by default, and QWINDOWKIT_BUILD_QUICK, which is disabled by default and must be turned on explicitly if you need Qt Quick support.
The lineage is stated too. The project inherits the core ideas and part of the implementation lineage from wangwenx190's FramelessHelper, with a refactored architecture and a smaller API surface, and the author is the same person behind the FramelessHelper.
The audience is a Qt application team that has already decided it wants its own title bar for branding reasons and is tired of reimplementing the platform behaviour.
Windows Snap Layout is a matter of registering roles
The Windows 11 feature is the one that changes how you write the code, and the documentation is explicit about it.
The feature list says Windows 11 Snap Layout support when system button roles are configured. The Quick Start shows what that means. After you install the window agent, you register each of the four system buttons with a role:
agent->setSystemButton(QWK::WindowAgentBase::WindowIcon, iconButton);
agent->setSystemButton(QWK::WindowAgentBase::Minimize, minimizeButton);
agent->setSystemButton(QWK::WindowAgentBase::Maximize, maximizeButton);
agent->setSystemButton(QWK::WindowAgentBase::Close, closeButton);The roles are WindowIcon, Minimize, Maximize and Close, and the point of registering them is not that QWindowKit draws the buttons. It is that the framework now knows which widget is which, and can therefore attach the platform behaviour to it, which in the case of Maximize on Windows 11 is the Snap Layout flyout that appears when the user hovers.
And the button behaviour itself is yours. The documentation says to connect it yourself:
connect(minimizeButton, &QPushButton::clicked, this, &QWidget::showMinimized);
connect(maximizeButton, &QPushButton::clicked, this, [this] {
isMaximized() ? showNormal() : showMaximized();
});
connect(closeButton, &QPushButton::clicked, this, &QWidget::close);So the division of labour is deliberate. QWindowKit handles the parts the platform requires, namely the hit zones, the drag regions, the system menu and the Snap Layout hook, and you handle the button semantics. The maximise button is a good illustration, because a frameless window has to implement the restore behaviour itself, since the platform no longer knows what the button means.
Windows 10 and 11 frameless window handling comes with optional system border workarounds, which is the other Windows specific feature in the list.
Hit testing decides where the window drags and where it clicks
There is one rule in the whole library that you have to get right, and it is worth reading carefully because everything else follows from it.
Areas inside the title bar that are not hit-test visible are treated as draggable window space. So the title bar is draggable by default, and anything you want to be interactive has to be declared. The API for that is setHitTestVisible:
agent->setHitTestVisible(menuBar, true);
agent->setHitTestVisible(searchBox, true);Without those two lines, a menu bar or a search box placed in the title bar would swallow the click, because the framework would treat the whole area as the drag handle. With them, the framework passes mouse events to the widget and only the remaining space drags the window.
The pattern generalises. Any interactive control that lives in the title bar, a button, a search field, a menu, a tab strip, has to be marked, and any decorative area does not. The inverse is also true, in the sense that the title bar itself is where the drag begins, which is the behaviour a user expects from a frameless window.
The same hit testing model is what makes the resize borders work, since the frame edges are handled by the same mechanism that decides what is a drag region and what is a client region. The documentation mentions the optional system border workarounds on Windows, which exist because some frameless windows lose the resize cursor at the edges, and the fix is a system border hack rather than something the framework can do purely with widgets.
For a team porting an existing frameless implementation, this is the part to check first, because the previous behaviour of your title bar probably assumed everything was draggable.
macOS polish on the screenshots, partial system menus on Linux
The feature list is where the differences between the platforms show, and they are worth reading as a quality ranking.
On macOS there is native system button positioning, and optional blur or glass style effects. The screenshots section shows a series of macOS variants, the default, glass in regular, clear, rounded, dark tint and light tint forms, and a legacy pair with dark blur and light blur. That is a design system for the window chrome, not a single look, and it is the part of the library with the most visual options.
On Linux the documentation is much more modest. There is a fallback implementation with partial native system menu support on Qt 6 under Wayland and X11, and the Linux screenshot is a single image rather than a set. The word fallback is doing the work there, and it tells you that on Linux you are getting a workable implementation rather than a complete one.
The Windows entry sits in between, with Snap Layout and border handling, and the supported platform list is Microsoft Windows, Apple macOS 11 or later, and GNU/Linux.
So the honest summary is that this is a Windows first library with a good macOS story and a functional Linux one, and the platform with the most native behaviour restored is also the one with the newest operating system features to restore.
One more piece of context for the whole project. The documentation states that QWindowKit uses Qt private APIs and platform-specific windowing behavior, and that older Qt releases may compile but can have known or unknown runtime issues. That sentence is the most important line in the requirements section, and it is why the recommended versions are given as specific numbers rather than as a minimum.
Building it, and the qmsetup dependency
The build is a clone with submodules and a standard CMake configure, build and install.
git clone --recursive https://github.com/stdware/qwindowkit
cd qwindowkitThe recursive clone matters, because the documentation notes that qmsetup is required and that if CMake cannot find an installed qmsetup package, the bundled submodule is used automatically. So a shallow clone without submodules may work or may not, depending on what is on the machine, and the documentation is candid about the fallback.
Then the three CMake commands:
cmake -S . -B build \
-DCMAKE_PREFIX_PATH=<QT_DIR> \
-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> \
-DQWINDOWKIT_BUILD_WIDGETS=ON \
-DQWINDOWKIT_BUILD_QUICK=ON
cmake --build build --config Release
cmake --install build --config ReleaseThe Quick module is off by default, so if you want Qt Quick support you pass QWINDOWKIT_BUILD_QUICK=ON yourself, as the example does. The Widgets module is on by default, so a Widgets only user needs no flags for it.
Consuming it is the same story in three build systems. With CMake you point at the installed package directory and link a component:
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
find_package(QWindowKit REQUIRED COMPONENTS Widgets)
target_link_libraries(my_widgets_app PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
QWindowKit::Widgets
)With qmake you include the generated .pri file, QWKWidgets.pri or QWKQuick.pri from the install tree. For MSBuild there is a separate Visual Studio guide in the docs. And the documentation also says QWindowKit can be added as a CMake subdirectory when it is vendored into your project, which is the route that avoids the install step entirely.
There is one more setup detail for Widgets that is easy to miss, because it is not in the API section. You must set Qt::AA_DontCreateNativeWidgetSiblings before constructing QApplication, and the Quick Start shows the attribute set on QCoreApplication before the QApplication is created.
Maintenance, the licence, and the private API caveat
The licence is Apache 2.0, in the LICENSE file at the root, and the project ships a second readme, README.zh-CN.md, alongside the English one, with the documentation available in both languages as well.
The repository is not archived, and the last push was on 2026-10-13, so the project is being worked on. The release history is 1.3.2 on 2025-02-09, 1.4.0 on 2025-05-23 and 1.5.0 on 2026-01-18, so a minor version roughly every eight months, which is the pace of a library that follows Qt rather than leads it.
The environment is documented in unusual detail, and that detail is the best guide to whether you can use it. The requirements table says Qt 5.12 or later, with Core and Gui required and Widgets and Quick optional, C++ 17 or later tested with MSVC, GCC and Clang, and CMake 3.19 or later with 3.20 recommended. The recommended Qt versions are 5.15.2 or later for the Qt 5 line and 6.6.2 or later for Qt 6. The tested compilers are MSVC 2019 and 2022 and MinGW GCC 13.2.0 on Windows, Clang 14.0.3 on macOS, and GCC 9.4.0 on Ubuntu.
So a team on a recent Qt 6 and a current compiler is in the supported area. A team on Qt 5.12, or on a compiler from 2019, is in the area the documentation warns about, where the library may compile and then behave strangely at runtime, because it reaches into Qt internals that are not part of the public API and can change between releases.
That is the trade to accept rather than a blocker to discover later. In exchange for using private APIs, you get frameless windows that behave the way the platform expects on three operating systems, and you take on the risk that a Qt upgrade changes behaviour underneath you.
Editorial conclusion
QWindowKit is worth adopting if your Qt application already draws a custom title bar and you have been reimplementing drag, resize and Snap Layout by hand, because the framework gives you the platform behaviour for Windows, macOS and Linux in one API and keeps the hit testing rules explicit. It is the wrong choice if you need long term support for a fixed Qt version, since the project states that it uses Qt private APIs and that older Qt releases may compile but can have known or unknown runtime issues. Before you adopt it, check your Qt version against the requirements table, note that the Quick module has to be enabled explicitly, and remember that the current release is 1.5.0 from 2026-01-18 with the repository pushed to on 2026-10-13.
Frequently asked questions
What is QWindowKit and what does it do for a Qt application?
It is a cross-platform window customization framework for Qt Widgets and Qt Quick that helps applications replace the native title bar with a custom one while preserving system behaviors such as window moving, resizing, system menus and Windows Snap Layout. It supports Microsoft Windows, Apple macOS 11 or later, and GNU/Linux.
How do I build QWindowKit from source?
Clone with submodules using git clone --recursive, then configure with cmake -S . -B build passing CMAKE_PREFIX_PATH and CMAKE_INSTALL_PREFIX, and build and install with cmake --build build --config Release and cmake --install build --config Release. qmsetup is required, and the bundled submodule is used automatically if CMake cannot find an installed one.
How do I get Windows Snap Layout in a QWindowKit application?
Register the system button roles with the window agent, using QWK::WindowAgentBase::WindowIcon, Minimize, Maximize and Close, and pass each the widget that acts as that button. The documentation states that Snap Layout support works when the system button roles are configured, and that you connect the button behaviour yourself.
Why is my title bar widget not clickable in QWindowKit?
Areas inside the title bar that are not hit-test visible are treated as draggable window space, so interactive controls have to be declared with agent->setHitTestVisible(widget, true). The Quick Start shows that applied to a menu bar and a search box.
Which Qt versions and compilers does QWindowKit support?
The requirements table lists Qt 5.12 or later with Core and Gui required and Widgets and Quick optional, C++ 17 or later, and CMake 3.19 or later, with recommended Qt versions of 5.15.2 or later and 6.6.2 or later. The project warns that it uses Qt private APIs and that older Qt releases may compile but can have known or unknown runtime issues.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/stdware-qwindowkit)Was this useful?