Introduction

KDDockWidgetsLogo

KDDockWidgets is a Qt dock widget library written by KDAB, suitable for replacing QDockWidget and implementing advanced functionalities missing in Qt.

Although KDDockWidgets is ready to be used out of the box, it can also be seen as a framework to allow building very tailored custom docking systems. It tries to expose every internal widget and every knob for the app developer to tune.

You will find more information in these places:

We also have an in browser demo. Note however that this demo isn't fully featured, as it's running on Qt for WebAssembly.

Motivation

Throughout the years KDAB contributed and funded bug fixes and features to QDockWidget. Sadly, this was very painful. Each bug fix or feature took many days of implementation, and an equal number of days just to fix dozens of regressions.

QDockWidget mixes GUI code with logic with state, making it very hard to move forward with new features. Furthermore, our customers were getting more creative with their requests, so it was clear we needed a better docking framework.

Features

  • Provide advanced docking that QDockWidget doesn't support
    • Native window resize on Windows (allowing for Aero-snap even with custom title bar decorations)
    • Arrow drop indicators for great drop precision
    • Allow for totally different, user provided, drop indicator types
    • Nesting dock widgets in a floating window and docking that group back to main window
    • Docking to any main window, not only to the parent main window
    • Docking to center of main window, or simply removing the concept of "central widget"
    • Main window supporting detachable tabs in center widget
    • Detaching arbitrary tabs from a tab bar into a dock area
    • Supporting more than 1 main window
    • Support for affinities, making some dock widgets only dockable on certain main windows
    • Allow to hide TitleBar and just show tabs. Allows dragging via the tab bar.
    • Exposing inner helper widgets so the user can customize them or provide his own
      • Customize tab widgets
      • Customize title bars
      • Customize window frames
      • Custom widget separators
  • Cross-platform (macOS, Linux, Windows, WebAssembly, Wayland, X11/XCB, EGLFS are working) See README-Wayland.md and README-WASM.md for platform specific information.
  • Layouting engine honouring min/max size constraints and some size policies
  • PySide bindings
  • Clean codebase
    • Not mixing GUI with state with logic with animations
    • Great test coverage, even the GUI and DnD operations are tested. 200 tests currently.
    • Fuzzer for doing random testing and finding bugs
  • Lazy separator resize
  • Reordering tabs with mouse
  • Partial layout save/restore, affecting only a chosen sub-set
  • Double click on title bar to maximize
  • Double click on separator to distribute equally
  • Show close button on tabs
  • Allow to make a dock widget non-closable and/or non-dockable
  • Optional minimize and maximize button on the title bar
  • FloatingWindows can be utility windows or full native

Screen capture

Screen capture

Installation

Requirements

  • CMake >= 3.15
  • Qt 5.15.x or Qt6 >= 6.2
  • Ninja (Other generators might work but are untested)
  • C++17 capable compiler. Minimum VS2019 on Windows.
  • Qt X11Extras module if on Linux/X11
  • Qt Quick and QuickControls2 modules if using the QtQuick support
  • Qt private development headers, for instance, for Qt5:
    • SUSE: libqt5-qtbase-private-headers-devel
    • Ubuntu, debian-based: qtbase5-private-dev
    • Fedora, redhat-based: qt5-qtbase-private-devel
    • others: consult your distro

Building

Although the build system supports many options, you'll mostly use -DKDDockWidgets_QT6=ON, or don't use any option, which defaults to Qt 5.

By default, KDDW will be built with support for both QtWidgets and QtQuick. If you want to save some binary space and compile time, consider passing -DKDDockWidgets_FRONTENDS="qtwidgets" or -DKDDockWidgets_FRONTENDS="qtquick".

Open a terminal capable of building Qt applications (make sure you have cmake, ninja, compiler, Qt, etc in PATH) and run:

cmake -G Ninja -DCMAKE_INSTALL_PREFIX=/path/where/to/install ../path/to/kddockwidgets
cmake --build .
cmake --build . --target install

If you don't have Qt in PATH, then you'll also need -DCMAKE_PREFIX_PATH=/<path_to_qt>/5.15/gcc_x64/ (adjust to your case). It's important that this path contains the lib/cmake/ folder, otherwise you'll get errors about Qt not being found.

Feel free to use your favorite IDE instead.

The installation directory defaults to c:\KDAB\KDDockWidgets-<version> on Windows and /usr/local/KDAB/KDDockWidgets-<version> on non-Windows.

Change the installation location by passing the option -DCMAKE_INSTALL_PREFIX=/install/path to CMake.

Using

Now that you've built and installed KDDW, you can use it.

Let's start by building an example:

cd path/to/kddockwidgets/examples/dockwidgets/
cmake -G Ninja -DCMAKE_PREFIX_PATH=/path/where/to/install
cmake --build .
./bin/qtwidgets_dockwidgets

Linking your own app to KDDockWidgets

You can simply inspect the examples to see how it's done. But the gist is:

Edit your CMakeLists.txt:

find_package(KDDockWidgets REQUIRED) // For Qt6, use KDDockWidgets-qt6 instead here.
...
target_link_libraries(myapp PRIVATE KDAB::kddockwidgets)

Finally, don't forget to build your app with -DCMAKE_PREFIX_PATH=/path/to/installed/kddw/.

Using with Non-CMake build systems

When consuming KDDW via CMake some details are implicitly setup for you. If you don't use CMake then you'll need to do the following manually:

  • KDDW_FRONTEND_QT needs to be defined.
  • KDDW_FRONTEND_QTWIDGETS needs to be defined, if QtWidgets.
  • KDDW_FRONTEND_QTQUICK needs to be defined, if QtQuick.

The above can be achieved by passing, for example -DKDDW_FRONTEND_QT -DKDDW_FRONTEND_QTWIDGETS to your compiler.

Additionally, the include path needs to be setup. This is usually ${YOUR_KDDW_INSTALL_PREFIX}/include/

And finally, the library needs to be linked against. It's called libkddockwidgets.so (Qt5) or libkddockwidgets-qt6.so (Qt6). On Windows it's called kddockwidgets2.lib or kddockwidgets-qt62.lib, respectively. Note that debug builds are suffixed with d, for example kddockwidgets2d.lib.

minimal

This minimal example is a good place to start, and often enough.

View the source in GitHub.

For more advanced usage, see the full example.

full example

This example tries to show most of KDDockWidget's functionality in a single example.
It is not meant to be copy-pasted entirely. Instead, copy only the functionalities you need.

View the source in GitHub.

If you just want to get started quickly, see the minimal instead.

Run ./bin/qtwidgets_dockwidgets --help to see the available options:

Usage: ./bin/qtwidgets_dockwidgets [options] savedlayout
KDDockWidgets example application

Options:
  -h, --help                                   Displays help on commandline
                                               options.
  --help-all                                   Displays help including Qt
                                               specific options.
  -p                                           Shows how to style framework
                                               internals via ViewFactory
  -r                                           Support re-ordering tabs with
                                               mouse
  -t                                           Hide titlebars when tabs are
                                               visible
  -q                                           Don't hide title bars if
                                               floating, even if
                                               Flag_HideTitleBarWhenTabsVisible
                                               is specified.
  -z                                           Show tabs even if there's only
                                               one
  -l                                           Use lazy resize
  -m                                           Shows two multiple main windows
  -i                                           Only usable with -m. Make the
                                               two main windows incompatible
                                               with each other. (Illustrates
                                               (MainWindowBase::setAffinityName)
  -c                                           Tabs have a close button
  -n                                           DockWidget #0 will be
                                               non-closable
  -s                                           Don't restore main window
                                               geometry, restore dock widgets in
                                               relative sizes
  -x                                           Double clicking a title bar will
                                               maximize a floating window
  -d                                           DockWidget #9 will be
                                               non-dockable
  -b                                           Floating dockWidgets have
                                               maximize/restore buttons instead
                                               of float/dock button
  -k                                           Floating dockWidgets have a
                                               minimize button. Implies not
                                               being an utility window
                                               (~Qt::Tool)
  -y                                           Use segmented indicators instead
                                               of classical
  -u                                           FloatingWindows will be normal
                                               windows instead of utility
                                               windows
  -o                                           FloatingWindows will have
                                               Qt::WindowStaysOnTopHint. Implies
                                               not being an utility window (try
                                               it with -u too)
  -g                                           Make dock #8 have a max-size of
                                               200x200.
  -w                                           Enables auto-hide/minimization
                                               to side-bar support
  --close-only-current-tab                     The title bar's close button
                                               will only close the current tab
                                               instead of all. Illustrates using
                                               Config::Flag_CloseOnlyCurrentTab
  --dont-close-widget-before-restore           DockWidgets 6, 7 and 8 won't be
                                               closed before a restore.
                                               Illustrates
                                               LayoutSaverOption::Skip
  --block-close-event                          DockWidget #0 will block close
                                               events
  --programmatic-drag                          Shows how to start a drag
                                               programmatically (advanced usage)
  --show-buttons-in-tabbar-if-titlebar-hidden  If we're not using title bars
                                               we'll still show the close and
                                               float button in the tab bar
  --central-widget                             The main window will have a
                                               non-detachable central widget
  --allow-switch-tabs-via-menu                 Allow switching tabs via context
                                               menu in tabs area
  --hide-certain-docking-indicators            Illustrates usage of
                                               Config::setDropIndicatorAllowedFu
                                               nc()
  --ctrl-toggles-drop-indicators               Ctrl key toggles drop indicators
  -f                                           Persistent central group
  --no-qttool                                  (internal) Don't use Qt::Tool
  --no-parent-for-floating                     (internal) FloatingWindows won't
                                               have a parent
  --native-title-bar                           (internal) FloatingWindows a
                                               native title bar
  --no-drop-indicators                         (internal) Don't use any drop
                                               indicators

Arguments:
  savedlayout                                  loads the specified json file at
                                               startup

mdi

This example shows the MDI related features.
The MDI support is enough to replace Qt's QMdiArea.

View the source in GitHub.

If you need both docking and mdi, then see this example instead.

mdi with docking

Shows how to use MDI but still be able to use dock widgets.

Only supported for QtWidgets.

View the source in GitHub.

full example

This example tries to show most of KDDockWidget's functionality in a single example.
It is not meant to be copy-pasted entirely. Instead, copy only the functionalities you need.

Note: This example is not as complete as the QtWidgets counter-part, it's missing many options that are supported by our QtQuick implementation but just not showed in the example.

View the source at GitHub.

Run ./bin/qtquick_dockwidgets --help to see the available options:

KDDockWidgets example application

Options:
  -h, --help                Displays help on commandline options.
  --help-all                Displays help including Qt specific options.
  -t                        Hide titlebars when tabs are visible
  -z                        Show tabs even if there's only one
  -b                        Floating dockWidgets have maximize/restore buttons
                            instead of float/dock button
  -k                        Floating dockWidgets have a minimize button.
                            Implies not being an utility window (~Qt::Tool)
  --no-qttool               (internal) Don't use Qt::Tool
  --no-parent-for-floating  (internal) FloatingWindows won't have a parent
  --no-drop-indicators      (internal) Don't use any drop indicators

customtabbar

This example shows how to customize the tabbar.

View the source in GitHub.

customtitlebar

This example shows how to customize the titlebar.

View the source in GitHub.

customseparator

This example shows how to customize the separators.

View the source in GitHub.

mdi

This example shows the MDI related features.
The MDI support is enough to replace Qt's QMdiArea.

View the source in GitHub.

Python bindings

These are the instructions for building the Python bindings for KDDockWidgets.

Make sure you have PySide6, shiboken6 and shiboken6-generator installed. Their versions need to match your exact Qt version. Since Qt 6.6 all these 3 packages are in PyPi, so you can simply install them with pip. For other Qt versions, consult the respective documentation.

% python3 -m pip install shiboken6==6.6 pyside6==6.6 shiboken6_generator==6.6

A C++17 compliant C++ compiler is also required.

For more info visit https://doc.qt.io/qtforpython/shiboken6/gettingstarted.html.

Not supported:

  • debug builds
  • static builds
  • python2
  • only some 32-bit platforms are supported (see https://wiki.qt.io/Qt_for_Python)
  • Qt5. It probably works, but don't report bugs unless they are reproducible with Qt 6 as well

Tell CMake to build the bindings by passing the `-DKDDockWidgets_PYTHON_BINDINGS=True' option, followed by the make command.

The bindings will be installed to the passed -DCMAKE_INSTALL_PREFIX, which might require setting the PYTHONPATH env variable to point to that path when running applications. Alternatively, configure the bindings install location by passing -DKDDockWidgets_PYTHON_BINDINGS_INSTALL_PREFIX=/usr/lib/python3.9/site-packages to CMake (adjust to the python path on your system).

To run the KDDW python example

    export PYTHONPATH=/kddw/install/path # Only if needed
    cd python/examples/
    rcc -g python -o rc_assets.py ../../examples/dockwidgets/resources_example.qrc
    python3 main.py

Build Issues

  • You can override the default Python3 version found by CMake (usually the newest version available) by passing the Python3_EXECUTABLE value to CMake, i.e.
    cmake -DPython3_EXECUTABLE=/usr/bin/python3.10 ....
  • If you see errors like "Unable to locate Clang's built-in include directory" then first make sure you have llvm installed. If you still have problems try setting the environment variable LLVM_INSTALL_DIR to point to your llvm installation.

    Examples:

    export LLVM_INSTALL_DIR=/usr/local/opt/llvm-15
    set "LLVM_INSTALL_DIR=C:\Program Files\LLVM" #Windows
  • When building the examples you may encounter errors loading shared libraries from shiboken2_generator.

    Try:

    export LD_LIBRARY_PATH=/usr/local/lib/python/dist-packages/PySide6/Qt/lib #linux
    export DYLD_LIBRARY_PATH=/usr/local/lib/python/dist-packages/PySide6/Qt/lib #Mac
    (Adjust to wherever your PySide is installed)
  • On Windows the libclang.dll that ships with QtForPython is not compatible with MSVC2. To fix this, copy the libclang.dll that comes with llvm into shiboken2, like so:
    cd C:\Python39\Lib\site-packages\shiboken6_generator
    copy libclang.dll libclang.dll.save
    copy "C:\Program Files\llvm\bin\libclang.dll" libclang.dll
    (Python3 installation in C:\Python39 and llvm in c:\Program Files\llvm. adjust as needed)
  • On macOS if you see cstdlib:145:9: error: no member named quick_exit in the global namespace with XCode 15, try making the SDKROOT env variable point to the XCode 14.2 SDK or download a more recent PySide6.

QtWidgets

QtWidgets is the original KDDW frontend, hence it's the most feature complete.
Although this is still the recommended frontend, you can also chose QtQuick and open a bug report for any missing feature.

By default a KDDW build will support both QtWidgets and QtQuick. If you only need QtWidgets then you should configure KDDW with:

-DKDDockWidgets_FRONTENDS="qtwidgets"

Simply to reduce binary size.

If you do have both QtWidgets and QtQuick support built, then don't forget to:

KDDockWidgets::initFrontend(KDDockWidgets::FrontendType::QtWidgets);

QtQuick

KDDockWidgets for QtQuick requires Qt >= 6.2.1.

Qt 5.15 will probably work, but it's not built or tested by KDAB CI, we advise users to move to Qt 6 as soon as possible.

By default a KDDW build will support both QtWidgets and QtQuick. If you only need QtQuick then you should configure KDDW with:

-DKDDockWidgets_FRONTENDS="qtquick"

If you do have both QtWidgets and QtQuick support built, then don't forget to:

KDDockWidgets::initFrontend(KDDockWidgets::FrontendType::QtQuick);

Troubleshooting

  • QtGraphicalEffects is not supported, as it's buggy when moving between different QWindows. See for example QTBUG-94943, KDDockWidgets issue #213. Also search the Qt bug tracker for "QQuickItem: Cannot use same item on different windows at the same time"

  • Very rarely, in some Nvidia/X11 setups, floating/docking has noticeable lag (like 1 second) This could be solved by going to Nvidia's settings and making sure all monitors have the same refresh rate and disabling "Allow Flipping". It's not known why this solves it. Might also be a bug in Qt.

  • "EGLFS: OpenGL windows cannot be mixed with others" QtQuick on EGLFS does not support having more than 1 window. This is a known QtQuick limitation. The QtWidgets stack worksaround this by compositing all windows into a single native window.

  • module "QtQuick.Controls" is not installed

Set the QML_IMPORT_PATH env var pointing to your Qt qml plugin dir or check the Qt documentation on how to deploy QtQuick applications.

# Replace with your actual path
export QML_IMPORT_PATH=/home/user/Qt/5.15.2/gcc_64/qml

Flutter

⚠️ This document is intended for KDDW developers.
⚠️ The flutter port is not ready for the general public.
⚠️ The flutter port is on hold, waiting for multi-window support upstream.

Requirements

Build instructions

Adjust paths as needed.
Checkout branch 2.0.

Linux

Preparatives:

export KDDW_SOURCE_DIR=/home/user/somewhere/kddockwidgets/

Release build (Recommended):

export DARTAGNAN_BINDINGSLIB_PATH=$KDDW_SOURCE_DIR/build-release-flutter/lib
cd $KDDW_SOURCE_DIR
cmake --preset=release-flutter
cmake --build build-release-flutter

If you need to run tests, then you need a developer build, which is a bit more involved.
You'll need to point FLUTTER_ENGINE_FOLDER to the folder containing a vanilla flutter engine along with flutter_embedder.h.

Developer build:

export DARTAGNAN_BINDINGSLIB_PATH=$KDDW_SOURCE_DIR/build-dev-flutter/lib
export FLUTTER_ENGINE_FOLDER=/home/user/somewhere/flutter-embedder/
cd $KDDW_SOURCE_DIR
cmake --preset=dev-flutter
cmake --build build-dev-flutter

Running the example

cd $KDDW_SOURCE_DIR/examples/flutter
flutter run -d linux # Or macos/windows or nothing if you only have 1 flutter "device"

macOS

Similar to Linux. The dev preset is not supported though, only release-flutter.

Windows

Similar to Linux, just use cmd syntax or so.
The dev preset is not supported though, only release-flutter.

Development tips

Running the tests

On Linux, get a developer build (see above), then run:

dart run_flutter_tests.dart build-dev-flutter/

Pending work

  • Support flutter multi-window

  • More styling

  • Make more tests pass

  • Figure out packaging, probably once Dart's Native Assets is released

Windows

KDDockWidgets not only works fine on Windows it also implements some native features:

  • Aero-snap support (drag to screen edges to partially-maximize windows)
  • Support for native Windows drop shadow around the frame
  • Support mixing with MFC event loop

Note: MinGW compiler is not tested, but probably works.
Note: KDDW is tested with Windows 10 and 11. Windows 7 can be made to work, upon request.

macOS

macOS is supported and historically KDDockWidgets hasn't received any bug reports regarding this platform.

X11/XCB

KDDockWidgets is developed and tested under KWin. Many other window managers also work, but they are less tested.
Please report a bug if you use a popular window manager and it's not working correctly.

Note: Not all features will work across all window managers. Flag_NativeTitleBar for example doesn't work with KWin, as this window manager doesn't send any mouse event to KDDW.

Wayland

Wayland is supported and has been tested on KDE (Kwin) and weston.

Limitations

Wayland works very differently than traditional desktops and imposes us some limitations. Here's a list of different behaviours which KDDockWidgets will have when running on Wayland:

  • A title bar can either be used for drag&dock or for moving the window around.

  • For this reason, floating windows now have two title bars. The native one, drawn by the server and the client one, drawn by KDDockWidgets. The native one allows you to drag the window around but not drop/dock. The client title bar allows you to perform a drag and drop/dock but not move the window around.

  • You can detach a window by:

    • Clicking the title-bar's float button
    • Double-clicking the title bar of a docked widget
    • Double-clicking a tab
    • If no title bar is shown, double-clicking the empty space of the tab bar will detach the entire group of tabbed dock widgets
  • Layout save/restore won't restore the position of floating windows, as wayland doesn't allow us to set geometry.

  • Kwin specific:

    • The pixmap that's shown during a drag can't be bigger than 250x250. Might be a bug.

All in all it's pretty decent and usable. Any further improvements should be done at the server or protocol level now.

EGLFS

Qt EGLFS is limited to max 1 OpenGL window. This means QtQuick is not supported, as KDDW is by nature multi-window.
QtWidgets works ok though. It can be a bit flaky sometimes but that's due to bugs in Qt EGLFS.

WebAssembly

KDDockWidgets works with WebAssembly with the following known limitations:

  • Depending on the browser, glitches, slowness, or lack of transparency while dragging windows might happen. This is specially true on Linux on browsers with 3D acceleration disabled. Please file a bug with Qt or your distro as it's out of scope for KDDW to fix.

  • Qt 5 WASM probably works, but is unsupported and untested.

  • KDDW QtQuick is untested on WASM

Demo

A demo is available at https://demos.kdab.com/wasm/kddockwidgets/dockwidgets.html.

Building KDDW

This can be done by following the generic instructions at https://doc.qt.io/qt-6/wasm.html.

For a Linux system, it's something like this (adjust paths):

$ source ~/emsdk/emsdk_env.sh
$ em++ --version # Needs to be 3.1.37 for Qt 6.6.0
$ cd KDDockWidgets/
$ ~/Qt/6.6.0/wasm_multithread/bin/qt-cmake --preset=wasm-release
$ cd build-wasm-release/
$ ninja kddockwidgets

Builds tips for your own app

  • Use qt_add_executable instead of add_executable, otherwise the *.html file won't be generated.
  • Link to libkddockwidgets-qt6.a
  • As the build is static, don't forget to initialize KDDW's resources:
#ifdef QT_STATIC
    Q_INIT_RESOURCE(kddockwidgets_resources);
#endif

offscreen

KDDockWidgets is well tested under the offscreen Qt QPA.

$ myapp -platform offscreen

offscreen is useful for running your GUI tests without worrying about random focus or window activation issues.
It also allows you to run several GUI tests in parallel.

Custom Behaviour

While KDDockWidget's defaults work for most users, it contains countless settings that can be adjusted.
The main place to find tunable behaviour is in Config.h.
Go over all method's documentation and feel free to use anything not marked as @internal.

The Config::Flag is particularly interesting. Example:

#include <kddockwidgets/Config.h>

KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);

Other useful places to modify:

  • KDDockWidgets::DockWidgetOptions (passed via DockWidget CTOR)
  • KDDockWidgets::MainWindowOptions (passed via MainWindow CTOR)
  • KDDockWidgets::RestoreOptions (passed via LayoutSaver CTOR)
  • Possibly other enums in KDDockWidget.h
  • All the API in core/DockWidget.h, qtwidgets/views/DockWidget.h, qtquick/views/DockWidget.h
  • Private API

Custom Styling

KDDockWidgets allows you to derive from several internal widgets (now called views, more QWidget agnostic term) and provide your own paintEvent and sizings (or .qml files for QtQuick).

You can derive any of these components:

  • MainWindow
  • DockWidget
  • FloatingWindow, the window containing one or more dock widgets
  • TitleBar
  • Group, a group of tabbed dock widgets with a titlebar
  • TabBar, similar concept to QTabBar
  • Stack, similar concept to QTabWidget.
  • Separator, allows resizing dock widgets inside a layout
  • RubberBand, indicates the drop location when dragging
  • SideBar, the sidebar when using the "auto hide feature"
  • ClassicDropIndicatorOverlay, the drop indicators
  • SegmentedDropIndicatorOverlay, the drop indicators in segmented mode

After deriving one or more of the above, create a custom ViewFactory.h which returns your derived instances. Then call KDDockWidgets::Config::self().setViewFactory(new MyCustomWidgetFactory());.

See examples/dockwidgets/MyViewFactory.h for QtWidgets, or examples/qtquick/customtitlebar/ for QtQuick.

CSS

Qt StyleSheets are not, and will not, be supported. See the comments in examples/dockwidgets/MyTitleBar_CSS.h for why. You can however use some minimal CSS, as shown in that example, just don't report bugs about it.

min/max sizing

QtWidgets

KDDW will honour min/max constraints set on the guest widget.
You can run the example qtwidgets_dockwidgets -g to see the max-size in action.
Setting the constraints directly on DockWidget is not advised.

QtQuick

Minimum sizes are supported but not maximum sizes.
There's no public API to set the minimum sizes, but you can set a special property called kddockwidgets_min_size on your guest item.
For an example, run the qtquick_dockwidgets sample executable, then go to "File" menu, and chose New widget with min-size.

Note that while KDDW floating windows and docked widgets will honour the min size, the main window itself won't, as that's an item completely controlled by the user. Maybe we could expose the main window's KDDW layout min/max size, then users could use that to calculate the main window's min/max.

Public and Private API

KDDockWidget guarantees source-compatibility for the public API, only.
Users seeking more advanced usage are welcome to use the private API, which can in theory break source-compat between releases. In practice however, the private API won't be changing much. Expect the public API to have much better documentation though.

Public API

The API is mostly MainWindow and DockWidget and a few other classes. Here's a list of headers you can #include:

<kddockwidgets/LayoutSaver.h>
<kddockwidgets/Config.h>
<kddockwidgets/KDDockWidgets.h>

<kddockwidgets/qtwidgets/views/DockWidget.h>
<kddockwidgets/qtwidgets/views/MainWindow.h>
<kddockwidgets/qtwidgets/views/MainWindowMDI.h>

<kddockwidgets/qtquick/views/DockWidget.h>
<kddockwidgets/qtquick/views/MainWindow.h>
<kddockwidgets/qtquick/views/MainWindowMDI.h>

Private API

Everything else.

Architecture and Concepts

KDDockWidgets is divided into Core and one frontend for each supported GUI toolkit.
The Core is pure C++ with no dependency on Qt. Business logic and state often lives here, and classes are namespaced with KDDockWidgets::Core::.
We have two complete frontends, qtwidgets and qtquick and a third one called flutter, which is lacking some futures still. Their code is namespaced with KDDockWidgets::QtWidgets, KDDockWidgets::QtQuick and KDDockWidgets::Flutter respectively.

Views and Controllers

View is a fancy word that meant QWidget. Since we introduced support for non-QtWidget toolkits we needed to drop the QWidget nomenculature. For QtQuick, views are QQuickItems, and for Flutter, they are StatefullWidget.

While views are something graphical, which depends on the rendering technology you're using, Controllers on the other hand are gui-agnostic, they live in Core, and are reused by all frontends.

Non-exhaustive list of controllers and views:

  • TitleBar
  • TabBar
  • Stack
  • Group
  • DockWidget
  • MainWindow
  • FloatingWindow
  • DropArea

For each of the above there's a View and a Controller. For example, for TitleBar, there's Core::TitleBar, implemented in src/core/TitleBar.cpp, which is rendered by QtWidgets::TitleBar (or QtQuick::TitleBar or Flutter::TitleBar), implemented in /src/qtwidgets/views/TitleBar.cpp and so on.

Porting to another GUI toolkit involves reimplementing all views.
Here's a brief description of each.

Guest View

This is the view that the user (library user) wants to dock. It has some custom content that is only relevant for the application. From KDDW's perspective we don't care what's inside, we'll just help dock it.

DockWidget

The DockWidget is a visual container for the Guest, in other words, its visual parent. Visually, DockWidget and Guest might be indistinguishable, except for some margin added by DockWidget. One reason to have this extra indirection is that it allows us to have a common API to deal with the Guest. Since guest is provided by the application developer it doesn't have any interface.

TitleBar

A TitleBar is the area that has the dock widget title and the float and close buttons. Usually KDDW won't use native OS title bars but draw its own.

TabBar

DockWidgets can be grouped together in tabs. A tab bar is just a group of tabs. In Qt this is something like QTabBar.

Stack

A stack is closely related to TabBar. A stack is a group of dock widgets where only one is visible at a time, the visible one is controlled by the current tab. In Qt this would be QTabWidget.

Group

The Group is a container that ties the previous concepts all together. It's composed of 1 or more tabbed DockWidgets, a TitleBar, a Stack and a TabBar.

Layout

Represents a docking layout. Currently 2 are supported, the traditional nested docking with resizable splitters (this is the default), implemented by MultiSplitter. And a MDI layout, where the dock widgets can be arbitrary positioned and even overlap inside an area.

The layouts deal in Frame. You add Frame objects to a layout.

Separator

A visual separator between two widgets, which allows the user to resize dock widgets with mouse.

FloatingWindow

When a dock widget isn't embedded into a window it's said to be floating. It's its own top-level native window. This class ties all the previous together. It contains one layout, which contains multiple groups.

MainWindow

Not much different from FloatingWindow technically, but users will often add status bar, tool bar and menu bars to a main window, while FloatingWindow is just an utility window (Qt::Tool). MainWindow also has support for a SideBar.

A side bar is a place in the MainWindow where you can "minimize" dock widgets. It's also called the auto-hide future. When you send a dock widget to the sidebar it will close but show a button in the sidebar, if you press it, it will show the dock widget as an overlay.

Platform, Screen, Window, ViewFactory

Not everything is a View/Controller. There's a bunch of other abstractions that need to be implemented when creating a new frontend.

While Qt has QGuiApplication, QScreen, QWindow we have similar abstractions but in a more toolkit agnostic way. See all the pure virtual methods in Core::Platform, Core::Screen, Core::Window and View::Factory and implement them.

Layouting engine

This is like the core of the core, it lives in src/core/layouting. The code there doesn't know anything about docking or dnd. It implements our layouting, which is a recursively nested layout. Imagine a layout composed nested QVBoxLayout and QHBoxLayout supporting any depth. min/max/preferred sizes are supported and recursively propagated up. See src/core/layouting/examples for how to use just this layouting engine without any docking. This is pure C++ and doesn't depend on Qt.

Event Filters

Since KDDW works with non-Qt, we can't use Qt event filters directly, so we added an abstraction layer.
Event filters implement EventFilterInterface. For Qt, we have a GlobalEventFilter class, which calls qGuiApp->installEventFilter, then forwards events to all registered EventFilterInterface.

We have the following global event filters:

  • DockRegistry singleton Catches expose events to maintain floating window z-order. Catches clicking on a MDI dock widget, to raise it. For hiding the auto-hide sidebar overlay when clicking elsewhere.

  • FallbackMouseGrabber For platforms that don't support grabbing the mouse. Mostly for QtQuick to workaround bugs.

  • Some wayland code

  • WidgetResizeHandler when used by MDI, or if EGLFS For resizing MDI dock widgets when mouse goes near borders.

mdi raise()

Clicking on a MDI dockwidget will raise it.
This is tested by tst_mdiZorder().
Actual raising is done by DockRegistry::onMouseButtonPress(), which is called by our global event filter.

Roadmap

KDDockWidgets is by now a very mature product.
Future development will be focused on finishing the Flutter frontend and improving Wayland support.
QtQuick API will also mature, as users give feedback.
There's nothing planned for QtWidgets, but feature requests and bug reports will be honoured for the foreseeable future.

Features and bugfixes for maybe 2.x or 3.0

  • QtQuick: Improve API
  • QtQuick: API for specify min/max sizes
  • QtWidgets: Make TitleBar more configurable, so user can inherit from it and customize more
  • Core: Cleanups for button handling, normalize code for all button types.

Get Involved

Bug Reporting

Please submit your issue reports to our GitHub space.

When reporting bugs please make it easy for the maintainer to reproduce it. Use examples/minimal/ or examples/dockwidgets/ for reproducing the problem. If you did modifications to the example in order to reproduce then please attach the patch and not a picture of your changes. You can get a patch by doing git diff > repro.diff at the repo root.

Also state which KDDW sha1, branch or version you're using, and which operating system.

KDAB will happily accept external contributions; however, all contributions require a signed KDAB Copyright Assignment Agreement.

  • Individual contributors (non-employees) are required to electronically agree to the KDAB CLA using the GitHub cla-assistant hook.

  • Employees, representing their company, must email a completed and signed KDAB Copyright Assignment Agreement to info@kdab.com.

This is needed so we can continue to dual-license it.

Contact info@kdab.com for more information.

Thanks to our contributors.

Licensing

KDDockWidgets is © Klarälvdalens Datakonsult AB (KDAB) and is licensed according to the terms of the GPL 2.0 or GPL 3.0.

Contact KDAB at info@kdab.com to inquire about commercial licensing.

About KDAB

KDDockWidgets is supported and maintained by Klarälvdalens Datakonsult AB (KDAB).

The KDAB Group is the global No.1 software consultancy for Qt, C++ and OpenGL applications across desktop, embedded and mobile platforms.

The KDAB Group provides consulting and mentoring for developing Qt applications from scratch and in porting from all popular and legacy frameworks to Qt. We continue to help develop parts of Qt and are one of the major contributors to the Qt Project. We can give advanced or standard trainings anywhere around the globe on Qt as well as C++, OpenGL, 3D and more.

Please visit https://www.kdab.com to meet the people who write code like this.

Stay up-to-date with KDAB product announcements: