Introduction
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
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 thelibclang.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 theSDKROOT
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
-
Flutter >= 3.13 && Dart 3.1
-
CMake, Ninja
-
KDDW (git clone https://github.com/KDAB/KDDockWidgets.git)
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 ofadd_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 widgetsTitleBar
Group
, a group of tabbed dock widgets with a titlebarTabBar
, similar concept to QTabBarStack
, similar concept to QTabWidget.Separator
, allows resizing dock widgets inside a layoutRubberBand
, indicates the drop location when draggingSideBar
, the sidebar when using the "auto hide feature"ClassicDropIndicatorOverlay
, the drop indicatorsSegmentedDropIndicatorOverlay
, 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 QQuickItem
s, 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.
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.
Copyright Assignment
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: