mafulechka
mafulechkaMarch 18, 2020, 6:01 a.m.

Custom client side window decorations in Qt 5.15

This is fresh news about a new feature in Qt 5.15 that is very exciting.

Traditionally, window treatments have been a pretty boring thing. Title, Limit, Minimize, Maximize, Resize, Exit... and that's it.


However, more and more applications have recently included an application specific UI and themes. A couple of screenshots to explain what is being said here:

MacOS has been doing this for quite some time.

... and Chrome, and any other web browser.

Embedding menus in your design can save a lot of screen space.

...or it might be important for branding or design.
Unfortunately, things like this were not previously possible with Qt.
However, it was possible to remove the decoration from the window, i.e.:

Window {
    flags: Qt.FramelessWindowHint
}

But that just left you with an undecorated window. So it couldn't be moved or changed. If you then tried to move the window or resize it by grabbing the mouse and manually setting the size and position of the window, you would quickly find that it didn't work very well. Window managers tend to have very specific behavior when moving or resizing windows. Common actions are dragging up to maximize, dragging left/right on a tile, snapping to other windows or the taskbar, resizing two windows at the same time if they are next to each other, and so on.

To be fair, one helper was previously provided - QSizeGrip. It allows you to resize any given window corner, but only works on corners, not window borders, and is only available for widget applications.

Qt 5.15 added two new methods to QWindow: startSystemMove and startSystemResize. These methods ask the window manager to take over and start its own resize or move operation. This means that snapping, tiling, and so on should work like magic, and the implementation of the header in QML becomes almost a one-liner:

DragHandler {
    onActiveChanged: if (active) window.startSystemMove();
    target: null
}

By placing this code snippet in a QtQuick element, all drag operation triggers will call the native window's move operation.
startSystemResize works similarly, except it takes a Qt::Edges argument, which is a bitfield of the window borders you captured, i.e. for the bottom right corner, you would call:

startSystemResize(Qt.RightEdge | Qt.BottomEdge)

It's also very handy, as you can easily have one handler for all four window borders and just create the borders argument like this:

DragHandler {
    id: resizeHandler
    grabPermissions: TapHandler.TakeOverForbidden
    target: null
    onActiveChanged: if (active) {
        const p = resizeHandler.centroid.position;
        let e = 0;
        if (p.x < border) e |= Qt.LeftEdge;
        if (p.x >= width - border) e |= Qt.RightEdge;
        if (p.y < border) e |= Qt.TopEdge;
        if (p.y >= height - border) e |= Qt.BottomEdge;
        window.startSystemResize(e);
    }
}

If you'd like a complete example of how this can be used, a web browser mockup has been made using the new API.

Please note that while this is a cross-platform API, not all platforms support it. startSystemMove is currently supported on Wayland, X11, macOS, and Windows, while startSystemResize, on the other hand, is supported on Wayland, X11, and Windows, but not on macOS.

To deal with this, both methods return a boolean value that indicates whether the operation was supported or not. This means that if you want to implement resizing on macOS as well, you will have to check the return value of startSystemResize and try your best to implement a fallback in case of failure, i.e.:

if (!window.startSystemResize(edges)) {
    // your fallback code for setting window.width/height manually
}

Further work in Qt will be to provide fallbacks or abstractions that do the work for you, but at least nothing should stop you from doing it yourself.

Another area of improvement is agreeing with the window manager on whether to use client-side or server-side styling. Some applications may want to support both modes and let the window manager decide, but this is currently not possible. Once FramelessWindowHint is set, there will be no server-side styling.

The third area is the window shadow. At least on Wayland, the shadow must be drawn as part of the window decoration. And while it is possible to draw shadows with QtQuick, there is currently no way to tell the QPA plugin which part of the surface is the shadow and which part is the window frame, which means that if you try to draw shadows, the window manager will currently consider the shadow part. windows, and this will mess up the tiling and snapping with other windows. On other platforms, the window manager usually draws shadows, even for client-side-decorated windows, so this is a difficult problem to solve.

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

Comments

Only authorized users can post comments.
Please, Log in or Sign up
AD

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:50points,
  • Rating points-4
m

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:80points,
  • Rating points4
m

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:20points,
  • Rating points-10
Last comments
ИМ
Игорь МаксимовNov. 22, 2024, 10:51 p.m.
Django - Tutorial 017. Customize the login page to Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii LegotckoiNov. 1, 2024, 12:37 a.m.
Django - Lesson 064. How to write a Python Markdown extension Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEOct. 19, 2024, 6:19 p.m.
Fb3 file reader on Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовOct. 5, 2024, 5:51 p.m.
Django - Lesson 064. How to write a Python Markdown extension Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5July 5, 2024, 9:02 p.m.
QML - Lesson 016. SQLite database and the working with it in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Now discuss on the forum
Evgenii Legotckoi
Evgenii LegotckoiJune 25, 2024, 1:11 a.m.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Nov. 15, 2024, 5:04 p.m.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectJune 4, 2022, 1:49 p.m.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9AnonimOct. 25, 2024, 7:10 p.m.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Follow us in social networks