Styling Kirigami applications wtih custom QtQuickControls Style

Hi !

I’m currently trying to write a QtQuickControls style based on org.kde.desktop that more closely integrates the Oxygen QStyle to QML and Kirigami applications.

I’m having a couple of issues:

  • ApplicationWindow’s background work with bare QML applications, but not with Kirigami
  • MenuItem style applies on Kirigami menus… but not with bare QML applications

Both can be shown in the following screenshots:

Kirigami application. The menu style applies entirely, but the application window’s background doesn’t use my style’s background. When I pop a menuBar, my style’s background does appear on the bar: it seems like something from either Kirigami or the org.kde.desktop style has a non-transparent background, which draws over the window’s background. I just can’t figure out what: I’ve replaced the backgrounds of Page, Pane, ToolBar, MenuBar, Drawer with transparent rectangles, and it only worked for the MenuBar. Any hint on how to move forward from here would help !

Plain QML application. Here, my gradient background does show. However, the MenuItem don’t use the style from the MenuItem template. The reason it happens is because I’m describing the menu using Actions rather than MenuItem, which is something I believe became possible with Qt6… but with other styles (like Material), the style applies in both cases. Is there something I’m doing wrong ?

The way it works is, I’m trying to inherit as much as possible from org.kde.desktop (which I know isn’t designed to just reproduce oxygen, but any QStyle in general, but it saves me time for the most Oxygen elements, which already render as expected).

So the basis for all my elements is something like this:

import QtQuick
import org.kde.desktop as Style

Style.Page {
  background: Rectangle {
    color: "transparent"
  }
}

For most elements, it works as I would expect. I do have issues with scrollbars and tooltips. They do not render as they would with the org.kde.desktop style: instead, it looks more like org.kde.breeze, with slightly different colors. It’s a bit puzzling, but it probably won’t be too hard to reimplement those from scratch anyway.

I’m also wondering if there could be a way to swap the QT_QUICK_CONTROLS_STYLE environment varibable on a global level, with systemsettings, when changing the application style. Could the QStyle commuicate that there’s a custom QtQuickControls style that should be use along with them (like with Breeze, and hopefully one day with Oxygen if I can complete this work) ?

Any thoughts, and any help would be very welcome !

3 Likes

ApplicationWindow’s background work with bare QML applications, but not with Kirigami

Are you certain it’s the ApplicationWindow that doesn’t have the correct background? I think it’s more likely because Kirigami.Page sets a custom background:

In the words of Moliere: and so that is why your daughter is mute. It is indeed the Kirigami.Page that does this. I can see my gradient background if I make the Page background transparent.

I think it’s a weird choice to force a background on the Page. Why not just let the QtQuickControls style Page template background apply ? I am able to fix the issue, but the solution is not exactly orthodox:

import QtQuick                                                                                                     
import org.kde.desktop as Style                                                                                    
                                                                                                                   
Style.Page {                                                                                                       
  Component.onCompleted: {                                                                                         
    background = realBackground                                                                                   
  }                                                                                                                
                                                                                                                   
  Rectangle {                                                                                                      
    id: realBackground                                                                                             
    color: "transparent"                                                                                           
  }                                                                                                                
}

And that’s not a good idea either… while I don’t see any reason why Kirigami should force its own background, applications themselves might have a good reason to do so, and my solution would break that for such applications.

The toolbar still has its own background, and that solution doesn’t work for the Toolbar element. But it has to be something similar: I’ll figure it out. Thanks !

1 Like

Unfortunately I do not know why the page has a custom background, and the commit message isn’t helpful either. I agree it should be the style that provides that. You could perhaps ask on the Matrix channel or open an issue / bug report and hopefully someone with more knowledge than me can help.

2 Likes

I have been wanting this for so long! Awesome work - Oxygen is my favorite widget style ever, but many new KDE programs sadly don’t use it much due to being based on Kirigami or QML. How can I try this? :smiley:

1 Like

I hope you can find a good solution, and get it merged into upstream Kirigami! And also, I do like Breeze but damn, Oxygen still rocks so hard after all these years.

Hopefully the outcome of the whole Union theming infrastructure project will be to make Oxygen declarative and easy enough to maintain going forward. In a certain way, it sort of remains the pinnacle of what theming was able to achieve on Linux desktops.

2 Likes

My current progress is available on my github at the following link:

I’ve done some unconventional things, there’s probably some stuff that should be moved to a private module. And it would probably make sense to move some stuff from the KStyle to the liboxygen, to better support some of the settings. It’s a LOT of work, and I don’t know that I’ll ever have the time to do all that.

Plus, it only works when an environment variable is set:

export QT_QUICK_CONTROLS_STYLE=org.kde.oxygen

That’s not very practical. There might be a way to fix that shortcoming using KSharedConfig and kdeglobals. I’ll have to look it up. I’d first need to find out if there’s a hook somewhere that runs when a KStyle gets configured/unconfigured.

Important note: it doesn’t work with Qt5. The project should build (I don’t think I’ve made any change that would break Qt5 compatibility), but it will build without the QtQuickControls style.

Progresses

I’ve made some progresses with the background gradient, but it’s not quite there yet. The decoration and the qtquick window don’t completely blend yet. I have the linear and radial gradient setup, it’s probably just a matter of finding the proper values.

I managed to fix the issues with the scrollbars and the menu items. The menu items do not look very good right now, due to Rectangle being pretty basic in terms of drawing borders. I’ll have to rewrite it with Shape instead.

Most importantly, I think I found out why Kirigami overwrites the background set by the style. When Pages are left with a transparent backgrounds, there are issues with some of the transitions, in which you can momentarily see both views when one pops over the other. I don’t have any ideas as to how I could fix this issue with a background gradient. Bummer.

Lovely job!

I hope this won’t be needed after Union becomes a thing, but since that day is yet to come, this is a worthwhile replacement!

I wouldn’t hold my breath. I’m pretty eager to see Union bring consistent styling back to KDE, but I really don’t see how that would work with Oxygen. Porting a GTK4 theme to both QtWidgets and QtQuick ? That seems reasonable, considering the input is just stylesheets and images. But when the input is code, that sounds a lot more tedious, if possible at all.

So, if we were to resurrect Oxygen after Union becomes a thing, we’d probably need to start again from scratch anyway. Then again, if we ever want Oxygen to support GTK4, we can’t use anything of what already exists, since the oxygen-gtk themes are mostly code, and GTK styling is stylesheet-only nowadays. Even the oxygen-gtk3 theme needs some serious update: it is very much broken. Who has time for that ? Not even me.

But hey, this wasn’t so much work, and I’m pretty glad with the result. I think these Kirigami apps look gorgeous like that:

4 Likes

That’s just plain AWESOME! The gradients are correctly aligned!

I think this totally should totally make it into Plasma itself, replacing what’s currently there for QML/QtQuick/Kirigami Oxygen.

1 Like

Maybe we’ll actually get there ! I think it’s still a little bit too hacky for that now.

I do have one major issue: Flatpaks may crash when this style is set. They might not if they use QQuickStyle::setFallbackStyle, but since the style isn’t packed with the Flatpak, the program won’t find it, and without a fallback style, it just fails to launch.

We also need a less hacky way to set the QtQuick style globally. I have something that works, but it requires you to restart the Plasma session for your style change to take effect.

I’m hopeful Union will create a need to find solutions for both these issues.

1 Like

Is this change to Kirigami merge-worthy? Eliminating the use of hardcoded colors is something we need to do for Union anyway, so your work on that would be appreciated.

1 Like

I didn’t change anything in Kirigami. I wanted to avoid changing existing stuff, so I went for something hackish instead. Definitely not merge worthy.

I believe the actual fix isn’t going to be obvious: removing the color is going to break some Kirigami transitions (when opening those inline popups, the kind that triggers when you open a page with pageStack.layers.push). For a brief moment, both views are rendered one over the other, and for the page rendered on top, having a transparent background makes it look glitchy.

I’ve thought of many potential ways to fix the issue, but none of them is either fool proof or trivial.

Best idea I came up with for now: during the popping transitions, we manually append an Item on the background of the Page that’s in transition. That Item will have a layer effect using a shader: the shader needs access to the texture of the ApplicationWindow, and to the texture of the Page popping in or out. For each pixel of the latter that’s transparent, we draw the corresponding ApplicationWindow pixel instead. It should preserve both backgrounds, from the new page, and the window, all while concealing the page below.

However, I don’t know if that’ll be efficient. Definitely not nearly as much as how it currently works, with plain backgrounds. I don’t have the experience to evaluate that, but I’m worried that might be a tad bit too expensive for some hardware on mobile devices.

But if we’re going to need that anyway at some point, I can at least try to implement it.

1 Like

I took the morning to start an implementation of that shader effect, and here’s what I came up with for the moment:

It’s not done yet. I’m almost there but not quite: it currently works more or less as I want it to when the Page does not have a background. But some themes and application might set a background on the Page, and then it needs to blend: I’m still having issues with that.

Bad news is, it seems like the solution is not very efficient still. The window background texture must be shifted when the Page is being translated on the Y axis, and that happens too slowly.

The YAnimators used in PageRow.qml don’t seem to trigger the yChanged event, so I had to add a backgroundYShift property on pages, and a NumberAnimation on the StackView transitions.

I don’t know exactly if it’s because the NumberAnimation doesn’t update the property often enough to match the YAnimator speed, or because of something else, but the background being drawn under the transitionning Page kinda lags behind.

1 Like

There is a third-party oxygen-like theme at Making sure you're not a bot!

Oh, this one I don’t know. I need to take a look how it compares to oxygen-gnome (Gnome-Look, GitLab) which I am currently using and Oxygen SCSS (KDE Store, GitLab).

qqc2-oxygen-style is available for RHEL and Fedora in my copr. If you also want the new oxygen style, you need to install plasma-oxygen-Plaristote too. Beware that the latter conflicts with plasma-oxygen, therefore the --allowerasing flag needs to be used if you have that installed.

1 Like

Just a few nitpicks:

  • There is no Kirigami platform theme in the qqc2 style. Both qqc2-desktop-style and qqc2-breeze-style have one, Union also has a WIP one.
  • When the qqc2 style is set as an environment variable system-wide, libplasma dialogs are broken. They don’t show Apply, Ok, Cancel buttons in the bottom.
  • Spectacle is broken, so I can’t take screenshots.
  • Is there any plan to port this to pure QML, similar to qqc2-breeze-style?

I confirm, I reported that a few days ago.

About Kirigami : the deed is done, or at least I think it is.

I added a test : it shows an AppliationWindow with a custom background and a button at the center. Clicking the button pushes a new layer, with a Page having a background that’s half transparent, and half semi-transparent.

On current Kirigami, the button will be visible during the new page layer transition. On patched Kirigami, as the Page slides up, the button will be hidden by the Page’s background, which blends its own background with the ApplicationWindow’s one.

@hazelbunny In response to your remarks :

  • I wasn’t aware about Kirigami platform theme. I assume the proper course would be for this style to just re-use the one provided by qqc2-desktop-style.
  • I don’t think I’m having the same issue with libplasma dialog, though I might not be looking at the right places. Can you give me an exemple of a dialog that breaks ?
  • I also noticed the issue with Spectacle. You can technically take the screenshot, but the preview does not show. Very impractical. I have no clue how it relates to the changes I’ve done, I’ll have to look into Spectacle specifically.
  • There’s no plan to port this to pure QML. I had considered that at the beginning, but it’s just not realistic in terms of how much work I’d have to put in. There’s a lot of code involved, and styling in QtWidgets is not nearly as intuitive as QML styling: biggest issue is, when I look at QtWidget styling, I have no clue what I’m looking at 90% of the time :smiley: ! It’s not just Oxygen (though it does have a lot of code), I’m also trying to do the same thing with the IaOra style, and I’m having the same issue.
1 Like