QWindowKit Documentation

repository·main·Indexed 22 days ago

https://github.com/stdware/qwindowkit

A cross-platform framework for customizing window frames in Qt Widgets and Qt Quick applications. QWindowKit allows developers to replace native title bars with custom UI while preserving essential system behaviors such as window dragging, resizing, and Windows Snap Layout. It provides support for platform-specific visual effects, including Windows Mica/Acrylic and macOS glass effects, and includes a FramelessHelper for advanced window management.

Tokens
12.9K
Snippets
44
Records
48
Agent score
77%

What's inside QWindowKit

  1. How WindowAgent works in Qt Quick (QML)

    main

    To use QWindowKit in QML, you must first register the QWindowKit types in your C++ main.cpp and ensure the window supports transparency.

    Setup Steps:

    1. In main.cpp, call QQuickWindow::setDefaultAlphaBuffer(true) before creating any windows. This is required for transparency and platform effects like Mica or Acrylic.
    2. Call QWK::registerTypes(&engine) after creating your QQmlApplicationEngine.
    3. In QML, import QWindowKit 1.0 and use the WindowAgent component.

    Usage Pattern: Inside a Component.onCompleted block in your QML file, initialize the agent:

    WindowAgent {
        id: windowAgent
    }
    
    Component.onCompleted: {
        windowAgent.setup(window)
        windowAgent.setTitleBar(titleBar)
        windowAgent.setSystemButton(WindowAgent.Minimize, minButton)
        windowAgent.setSystemButton(WindowAgent.Maximize, maxButton)
        windowAgent.setSystemButton(WindowAgent.Close, closeButton)
    }

    Interaction: Just like in Widgets, if a control in the title bar (like a Button) needs mouse input, you must call windowAgent.setHitTestVisible(controlId, true) within Component.onCompleted or a similar lifecycle event.

    // main.cpp setup
    QQuickWindow::setDefaultAlphaBuffer(true);
    QQmlApplicationEngine engine;
    QWK::registerTypes(&engine);
    
    // Main.qml usage
    import QWindowKit 1.0
    
    Window {
        id: window
        WindowAgent {
            id: windowAgent
        }
        
        Rectangle {
            id: titleBar
            // ...
        }
    
        Component.onCompleted: {
            windowAgent.setup(window)
            windowAgent.setTitleBar(titleBar)
        }
    }
  2. Important Usage Constraints and Best Practices

    main

    To ensure stability and correct behavior, follow these guidelines:

    • Setup Timing: Call setup() as early as possible, typically in the first half of the top-level window's constructor. Set size constraints (min/max/fixed) after QWindowKit initialization.
    • Do Not Modify Flags: Once WidgetWindowAgent::setup() is called, do not modify the window flags using QWidget::setWindowFlags().
    • Avoid Runtime Border Switching: Do not attempt to switch between custom and native system borders at runtime. If switching is required, destroy and recreate the window.
    • Native Sub-widgets: If a child widget uses Qt::WA_NativeWindow, enable Qt::WA_DontCreateNativeAncestors before creating the native ancestor window.
    • Size Constraints: Avoid setting maximum width or height constraints on windows that are also set to be maximized, as this can interfere with Qt's reporting of native maximized geometry.
    • Qt Quick (Windows 10/D3D): For Qt Quick using D3D11/D3D12 on Windows 10, a white line may appear at the top. In Qt 6.7+, you can try setting the environment variable QT_QPA_DISABLE_REDIRECTION_SURFACE=1 before creating QCoreApplication (do not use this with OpenGL or Vulkan).
  3. Platform-specific behavior for FramelessHelper

    main

    Windows

    • Windows Version: Highly recommended to use Windows 10 (version 1809 or newer) or Windows 11 for stability. Windows 7 is supported but not recommended. Older versions of Windows 10 (e.g., 1507, 1607) may have compatibility issues.
    • DWM Composition: If DWM is disabled (rare on Windows 7), corners may appear round instead of square. Re-enabling DWM restores square corners.

    Linux

    • Wayland: FramelessHelper will force the application to use the XCB platform plugin when running on Wayland.
    • Resizing: The resize area is located inside the window.

    macOS

    • Resizing: Some users have reported issues with windows not being resizable on older macOS versions.
  4. How WidgetWindowAgent works in Qt Widgets

    main

    To use custom title bars in a QWidget or QMainWindow application, follow these requirements:

    1. Global Attribute: You MUST set QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings) before creating the QApplication instance.
    2. Agent Lifecycle: Every top-level window requires its own QWK::WidgetWindowAgent. Call m_windowAgent->setup(this) as early as possible in the window's lifecycle.
    3. Title Bar Definition: Use setTitleBar(widget) to designate the area that handles window dragging.
    4. Hit Testing: By default, the title bar area intercepts mouse events for dragging. If you place interactive controls (like QMenuBar, QPushButton, or QLineEdit) inside the title bar, you MUST call setHitTestVisible(widget, true) on them so they can receive clicks.
    5. System Buttons: Use setSystemButton(role, widget) to associate your custom buttons with system actions (Minimize, Maximize, Close, etc.). Note that QWindowKit only identifies the role; you must still manually connect the button's clicked signal to the window's corresponding slot (e.g., showMinimized()).
    // In your MainWindow setup
    m_windowAgent = new QWK::WidgetWindowAgent(this);
    m_windowAgent->setup(this);
    
    // Define title bar and buttons
    m_windowAgent->setTitleBar(titleBar);
    m_windowAgent->setSystemButton(QWK::WindowAgentBase::Minimize, minButton);
    
    // IMPORTANT: Make interactive controls clickable
    m_windowAgent->setHitTestVisible(menuBar, true);
  5. Integrate QWindowKit into a Visual Studio project using Property Sheets

    main

    To integrate QWindowKit into an existing Visual Studio project, you must add the provided .props file to your project's Property Manager. This ensures the necessary build configurations and dependencies are applied to your project.

    1. Open the Property Manager in Visual Studio via View -> Other Windows -> Property Manager.
    2. Right-click your project name within the Property Manager window.
    3. Select Add Existing Property Sheet....
    4. Navigate to the QWindowKit.props file located in the following directory: [Build output folder of QWindowKit]\share\QWindowKit.
    5. Click Open to complete the integration.
    # Steps to add QWindowKit.props in Visual Studio
    1. View > Other Windows > Property Manager
    2. Right-click Project > Add Existing Property Sheet...
    3. Select [QWindowKit_Build_Output]/share/QWindowKit/QWindowKit.props
  6. Quick Start: Custom Title Bar with Qt Quick (QML)

    main

    To use custom title bars in a Qt Quick application:

    1. Register Types: In your C++ main function, call QWK::registerTypes(&engine) after creating the QQmlApplicationEngine.
    2. Set Alpha Buffer: Call QQuickWindow::setDefaultAlphaBuffer(true) before creating the QGuiApplication.
    3. Use WindowAgent in QML: Import QWindowKit 1.0 and use the WindowAgent component inside your Window.
    4. Initialize Agent: In the Component.onCompleted handler of your QML window, call windowAgent.setup(window) and windowAgent.setTitleBar(titleBar).
    // C++ Setup
    QQuickWindow::setDefaultAlphaBuffer(true);
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    QWK::registerTypes(&engine);
    engine.load(QUrl(QStringLiteral("qrc:/Main.qml")));
    app.exec();
    // QML Usage
    import QtQuick
    import QtQuick.Window
    import QWindowKit 1.0
    
    Window {
        id: window
        visible: false
    
        WindowAgent {
            id: windowAgent
        }
    
        Rectangle {
            id: titleBar
            height: 40
            width: parent.width
        }
    
        Component.onCompleted: {
            windowAgent.setup(window)
            windowAgent.setTitleBar(titleBar)
            window.visible = true
        }
    }
  7. When to call setup() in C++ and QML

    main

    The setup() method should be called early in the window lifecycle, ideally in the constructor before complex child widgets or size constraints are applied.

    In C++ (QWidget/QMainWindow) Call it immediately after instantiating the agent in the constructor.

    In QML Call it within the Component.onCompleted handler.

    // C++ Example
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
    {
        m_agent = new QWK::WidgetWindowAgent(this);
        m_agent->setup(this);
    
        setMinimumSize(640, 480);
        setupUi();
    }
    // QML Example
    Component.onCompleted: {
        windowAgent.setup(window)
        windowAgent.setTitleBar(titleBar)
        window.visible = true
    }
  8. Integrate QWindowKit with qmake

    main

    To use QWindowKit in a qmake project, install it via CMake first, then include the generated .pri files in your .pro file.

    # Widgets
    include("<INSTALL_DIR>/share/QWindowKit/qmake/QWKWidgets.pri")
    
    # Quick
    include("<INSTALL_DIR>/share/QWindowKit/qmake/QWKQuick.pri")
  9. Install and build QWindowKit

    main

    To build QWindowKit from source, clone the repository recursively to include submodules, then use CMake to configure, build, and install. You can explicitly enable support for Qt Widgets and Qt Quick via CMake flags.

    Requirements:

    • Qt: 5.12+ (Recommended: 5.15.2+ or 6.6.2+). Requires QtCore and QtGui.
    • C++: C++17 or higher.
    • CMake: 3.19+ (3.20+ recommended).

    Build Steps:

    1. Clone the repository:
      git clone --recursive https://github.com/stdware/qwindowkit
      cd qwindowkit
    2. Configure, build, and install:
      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 Release
    git clone --recursive https://github.com/stdware/qwindowkit
    cd qwindowkit
    
    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 Release
  10. Integrate QWindowKit with CMake

    main

    After installing QWindowKit, you can integrate it into your CMake project by specifying the installation directory and finding the required packages.

    For Widgets applications: Requires Qt6::Widgets (or Qt5 equivalent) and QWindowKit::Widgets.

    For Quick applications: Requires Qt6::Quick, Qt6::Qml, and QWindowKit::Quick.

    # For Widgets
    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
    )
    
    # For Quick
    find_package(Qt6 REQUIRED COMPONENTS Core Gui Quick Qml)
    find_package(QWindowKit REQUIRED COMPONENTS Quick)
    
    target_link_libraries(my_quick_app PRIVATE
        Qt6::Core
        Qt6::Gui
        Qt6::Quick
        Qt6::Qml
        QWindowKit::Quick
    )
  11. Force Qt window context on Linux

    main

    On Linux, QWindowKit behavior varies significantly between desktop environments and window managers. For applications prioritizing compatibility, you can force the use of the Qt fallback implementation by adding this flag to your CMake configuration:

    -DQWINDOWKIT_FORCE_QT_WINDOW_CONTEXT=ON
  12. Build and install QWindowKit from source

    main

    To build QWindowKit, clone the repository recursively and use CMake. You must provide the path to your Qt installation via CMAKE_PREFIX_PATH.

    On Windows:

    git clone --recursive https://github.com/stdware/qwindowkit
    cd qwindowkit
    
    cmake -S . -B build ^
      -DCMAKE_PREFIX_PATH=C:/Qt/6.7.3/msvc2019_64 ^
      -DCMAKE_INSTALL_PREFIX=C:/Libraries/QWindowKit ^
      -DQWINDOWKIT_BUILD_WIDGETS=ON ^
      -DQWINDOWKIT_BUILD_QUICK=ON ^
      -DQWINDOWKIT_BUILD_EXAMPLES=OFF
    
    cmake --build build --config Release
    cmake --install build --config Release

    On Linux or macOS:

    git clone --recursive https://github.com/stdware/qwindowkit
    cd qwindowkit
    
    cmake -S . -B build \
      -DCMAKE_PREFIX_PATH=/path/to/Qt \
      -DCMAKE_INSTALL_PREFIX=/opt/qwindowkit \
      -DQWINDOWKIT_BUILD_WIDGETS=ON \
      -DQWINDOWKIT_BUILD_QUICK=ON
    
    cmake --build build --config Release
    cmake --install build --config Release
    # Windows example
    cmake -S . -B build \
      -DCMAKE_PREFIX_PATH=C:/Qt/6.7.3/msvc2019_64 \
      -DCMAKE_INSTALL_PREFIX=C:/Libraries/QWindowKit \
      -DQWINDOWKIT_BUILD_WIDGETS=ON \
      -DQWINDOWKIT_BUILD_QUICK=ON \
      -DQWINDOWKIT_BUILD_EXAMPLES=OFF
    
    cmake --build build --config Release
    cmake --install build --config Release