Open gfgit opened 6 months ago
Nice! Taskbar under kwin_wayland works again I see.
NOTE: panel auto-hide is not working yet
It does here :) (had always worked on this branch).
Something has gone wrong I think, I recompiled the changes this afternoon and taskbar is gone again.
Taskbar is back here now I see, and crash on clicking showdesktop is avoided too.
Just noticed a different behavior here compared to wlroots and X11 (any WM): the taskbar buttons only activates windows, but don't toggle minimize/restore.
From my tests it looks that export XDG_SESSION_DESKTOP="KDE
in the startscript is not needed (anymore).
Another remaining issue is the "Maximize" item in menu which is always greyed out.
NOTE: panel auto-hide is not working yet
Is this not implemented yet, or, the implementation gives some problems?
Edit:
// Emulate auto-hide on Wayland // NOTE: we cannot move window out of screen so we make it smaller // NOTE: a cleaner approach would be to use screen edge protocol // but it's specific to KWin
From the code it seems to me that you have problems about how. With layer-shell, we can set the margin to a negative value. For a bottom panel, setting the bottom margin to -PANEL_HEIGHT
would mean that the panel is effectively hidden.
However, the issue of how to show the panel becomes a problem. With wayfire, we can use wayfire-shell or wayfire-desktop-shell, both of which provide an equivalent of screen-edge protocol.
But in general, we can partially hide the panel, instead of resizing the panel. For example, set the bottom margin to -PANEL_HEIGHT + PANEL_HIDE_SIZE
. This would leave a few pixels sticking out. If the mouse pointer enters the panel, then it can be revealed completely. In place of QPropertyAnimation
, you can apply QVariantAnimation
and change the bottom margin value from -PANEL_HEIGHT + PANEL_HIDE_SIZE
to 0 and other way around.
Are negative margin value allowed by layer shell? Didn't know about it! Current implementation sort of works but on my setup it triggers auto-show even if cursor is not yet at screen edge. This makes it impossible to click for example statusbar of applications or other UI elements near screen edge because panel shows first and you end up click the panel instead. It may be a bug in kwin mouse logic
Well... It's not specifically, disallowed. On wayfire, we simply use negative margins. I've not tested on other compositors, though.
Negative layershell margins may end up on other outputs or don't receive frame / configure events anymore because the surface is not actually visible (which revealed a bug in the GTK layershell wrapper in the past), depending on the compositor. (Although I'd actually categorize the shows-up-on-other-output as a compositor bug). AFAIR a discussion in the ext-layershell protocol MR concluded to not allow negative margins at all (but memory is a bit fuzzy there).
Another option that should always work is hiding the panel and replacing it with a transparent hitbox without exclusive zone. On mouse movement on the hitbox that one is hidden and the panel is shown again.
The variant also has the benefit that rather than just having a transparent non-exclusive hitbox, one could also anchor the replacement surface to e.g. the bottom-left edge and show a small button instead which - when triggered - hides the replacement surface and restores the panel one. That replacement surface would then be non-exclusive, only be the width of the button and using the top layer so its always visible on top of usual windows.
Current implementation sort of works but on my setup it triggers auto-show even if cursor is not yet at screen edge. This makes it impossible to click for example statusbar of applications or other UI elements near screen edge because panel shows first and you end up click the panel instead. It may be a bug in kwin mouse logic
I didn't notice that as I don't really use it, but it's on all compositors the same, getting triggered at panel height and not screen border.
Current implementation sort of works but on my setup it triggers auto-show even if cursor is not yet at screen edge. This makes it impossible to click for example statusbar of applications or other UI elements near screen edge because panel shows first and you end up click the panel instead. It may be a bug in kwin mouse logic
I didn't notice that as I don't really use it, but it's on all compositors the same, getting triggered at panel height and not screen border.
That could also be solved by using the transparent replacement surface, either via the button-only variant or by defining a 1px or 2px height of the surface (added a commented out call to the GTK example above).
Under X11, the panel is moved out of the screen appropriately, such that only 4 pixels (PANEL_HIDE_SIZE) of its height or width remain visible, depending on whether it's horizontal or vertical. Then its opacity is made zero. Those invisible 4 pixels serve to show the panel on mouse-over.
Since the panel is never positioned between screens, this method works fine. Of course, there are other details/options, like animation and auto-hiding on overlapping windows.
Btw what about lxqt/lxqt#2531 (comment) ?
I'm ok for extracting layer shell code and make a new PR
Code is inspired by libtaskmanager/waylandtasksmodel.cpp
Awesome that the code works for you but in this case the inspiration seems was rather strong and seems to include copied code from Plasma in multiple files as the commented out lines still references the original class and the general structure of the code (for example org_kde_plasma_window_icon_changed
). We do not mind this as it's free software after all but would appreciate it if the original license headers could be preserved, thanks!
The original license headers are the two SPDX- lines at the top of the file, e.g. SPDX-License-Identifier: LGPL-2.1-only. Since lxqt is LGPL v2.1, you can specifically choose to re-use the code from KDE under the LGPL v2.1.
seems to include copied code from Plasma in multiple files
In that case, the original codes should be referenced by comments like "Adapted from...".
@Sodivad Hi, I've updated the license headers. Is it ok like that?
Rebased on current master
I notice 2 regressions now: desktop switch is the "n.d" one (not supported on this platform: wayland) and showdesktop doesn't work too anymore.
@gfgit @stefonarch @tsujan A request.
This PR introduces support for plasma wayland based taskbar and pager. However, before this can reviewed don't you think it's better to discuss how we will introduce support for wlroots-based taskbar too? Otherwise, we will unnecessarily have to refactor the code.
One of the ways we can go ahead is via modules - basically plugins for the taskbar plugin. The wayland backend code will load the suitable plugin based on the compositor and user's choice. We can use the ILXQtTaskbarAbstractBackend
class as to develop the plugin interface. Then, the backends for all other platforms can be easily developed.
The biggest advantage in this approach is that we can easily change the backend code without affecting the rest of the project. Secondly, we can add support for different compositors based on their strengths - sway, wayfire, hyprland can use IPC, others can use what they provide. If nothing is available, the generic wlroots backend can be used.
If we introduce these modules (the framework for modules) before we review this PR, then we can refactor the plasma code into a module rather than merge this and ten go for a refactor later.
I think that makes sense. Labwc (generic wlroots backend), kwin and wayfire will be the priority atm as both qterminal dropdown and lxqt-runner are unusable on sway and hyprland is on a quite weird way probably afaik ("As we’re in the middle of slowly but surely moving off of depending on wlroots for our backend(s),").
As we’re in the middle of slowly but surely moving off of depending on wlroots for our backend(s),").
What does that mean? Who's moving away from wlr for the backends?
Even if we directly move away from wlroots, we still need the modules-based approach.
The wayland backend code will load the suitable plugin based on the compositor....
@marcusbritanicus, yes, a modular approach is the best way, considering the fact that LXQt is and will remain modular, as far as possible.
As @stefonarch mentioned, with the current state of affairs, supporting LabWC, Wayfire and kwin_wayland is our priority.
Who's moving away from wlr for the backends?
I'm also curious to know the source of that quotation, but I think it's about hyprland
;) If so, it's none of our concern....
I'm also curious to know the source of that quotation, but I think it's about hyprland ;) If so, it's none of our concern....
@marcusbritanicus I very much agree on plugin system. We could somewhat reuse the technique of LXQt panel plugins.
Also I think we should drop "Taskbar" from class name, as not it's used in other parts of the code not related to taskbar plugin itself.
I suggest ILXQtAbstractWMInterface
.
I like the sound of ILXQtAbstractWMInterface
.
As they say, no good deed goes unpunished, and you (@gfgit) have done a fantastic job on lxqt-panel thus far. So, I think it is only fitting that you should develop the plugin interface for this as well. Will you please do the honours?
Until the first draft of the interface is ready, we have a few things to mull about:
I suggest ILXQtAbstractWMInterface.
I agree.
@gfgit @marcusbritanicus Any updates on this?
@gfgit @marcusbritanicus Any updates on this?
I am waiting for @gfgit to do this. He is much much better at it, than I am. Once the framework is developed, I will port wlroots to this.
I will port wlroots to this.
I'm looking forward to that. Currently I use a slightly changed version of your old branch to have task-bar under labwc and wayfire.
So, we're all waiting for @gfgit ;)
Hello everyone. I'm a bit busy currently. In 2 weeks I'll make a draft. I was thinking about the overall structure. How do we choose the right plugin to load? If the detection is in the plugin itself it means we have to load them all and query each, then choose the best and unload the rest. This is quite heavy, maybe we can cache the result for next startup and do it again in case plugin gives different scire than cached.
How does Qt choose the backend on startup? We migth take inspirations
How do we choose the right plugin to load?
I think @marcusbritanicus has already done it in his PR; hasn't he?
In 2 weeks I'll make a draft.
There may be a misunderstanding here (perhaps mine): We're waiting for the problem(s) of this PR to be fixed, such that we could merge it and @marcusbritanicus could do the rest. Am I the only one who got that impression?
Do we add support for xdg-toplevel-icon protocol?
This protocol is used to get the icons for each window, as set by the client. A fallback will be using app-id if this is not set. This will be soon supported by Qt, Plasma (6.2) and Wlroots. GTK, I know not.
Just to chime in, this protocol is between compositor and app. the taskbar shouldn't need to concern itself with it. If a client sets a custom icon, it will be available via plasma-window-managment.
There may be a misunderstanding here (perhaps mine): We're waiting for the problem(s) of this PR to be fixed, such that we could merge it and @marcusbritanicus could do the rest. Am I the only one who got that impression?
I understood that the general approach should be changed to a plugin architecture, and then all should be ported there.
How do we choose the right plugin to load?
I've to admit that I've no idea how actually backends are chosen. If we think about the panel being part of lxqt-session
we could go under wayland for values in XDG_CURRENT_DESKTOP
(example XDG_CURRENT_DESKTOP=LXQt:labwc:wlroots
) as we will set this. Otherwise we'd to scan for compositors in user applications - this could be also a fallback for users who just run lxqt-panel
in whatever compositor.
choose the right plugin['s backend] to load
I know nothing about Wayland, but it seems like lxqt-panel should have a global function that determines what actual compositor is running, by querying supported protcols or... - then that value is passed to the plugin loader to startup each plugin in that mode.
EDIT: A caveat is if the Wayland plugin and X11 plugin are separated, i.e. plugin-taskbar/
plugin-taskbar-wlroots/
, then you'd need the plugin loader to select the proper plugin for the determined mode.
I understood we wanted to implement a plugin structure before merging this and the rebase all wayland related PRs on top of plugins.
Also current logic as done by Marcus is hardcoded in executable. This would defeat the advantages of plugins. We want to let user develop an independent plugin for an exotic WM and it will be selected in some way at runtime. We then provide "official" plugins for a small number of compositors.
So the logic must be inside the plugin itself or maybe in some attached JSON info file describing how to check if plugin is eligible without having to load it, but this maybe is too complex.
We want to let user develop an independent plugin for an exotic WM and it will be selected in some way at runtime.
That sounds too ambitious to me, especially because Wayland WMs come and go and there's no guarantee that they're shell-compatible, but if you and @marcusbritanicus could execute this plan with a reasonable amount of code and without extra dependencies, who am I to disagree? ;)
because Wayland WMs come and go and there's no guarantee that they're shell-compatible
Or they can have issues like sway with the runner (doesn't get focus). Tried just now river which closes all popups in the panel before executing the click. But we can assume that labwc, sway, wayfire and also Hyprland will stay around for good, not to mention kwin.
And it is ambitious, yes, but could really make LXQt unique in the wayland world, providing a modular DE to the WMs.
Do we add support for xdg-toplevel-icon protocol? This protocol is used to get the icons for each window, as set by the client. A fallback will be using app-id if this is not set. This will be soon supported by Qt, Plasma (6.2) and Wlroots. GTK, I know not.
Just to chime in, this protocol is between compositor and app. the taskbar shouldn't need to concern itself with it. If a client sets a custom icon, it will be available via plasma-window-managment.
@Sodivad We have to support all compositors, and not just plasma/kwin. This means, we will need to add support for all compositors which are not kwin, and that needs to be done manually.
@Sodivad We have to support all compositors, and not just plasma/kwin. This means, we will need to add support for all compositors which are not kwin, and that needs to be done manually. Yes I understand. But it doesn't change that the taskbar doesnt have to implement it and it wouldn't work to get custom icons of windows that way.
We want to let user develop an independent plugin for an exotic WM and it will be selected in some way at runtime.
That sounds too ambitious to me, especially because Wayland WMs come and go and there's no guarantee that they're shell-compatible, but if you and @marcusbritanicus could execute this plan with a reasonable amount of code and without extra dependencies, who am I to disagree? ;)
I think Qt first checks QT_QPA_PLATFORM
, then it checks XDG_SESSION_TYPE
and something else. As far as I have seen, LXQt does not use env vars for most works.
We can use a mix of hard-coded values (majority) and plugin settings.
XDG_CURRENT_DESKTOP
.TaskBarBackendOverrides = Wayfire:my-wayfire-plugin, Hyprland:some-other-plugin, sway:wlroots, generic:my-wlroots-plugin
Do we add support for xdg-toplevel-icon protocol? This protocol is used to get the icons for each window, as set by the client. A fallback will be using app-id if this is not set. This will be soon supported by Qt, Plasma (6.2) and Wlroots. GTK, I know not.
Just to chime in, this protocol is between compositor and app. the taskbar shouldn't need to concern itself with it. If a client sets a custom icon, it will be available via plasma-window-managment.
@Sodivad We have to support all compositors, and not just plasma/kwin. This means, we will need to add support for all compositors which are not kwin, and that needs to be done manually.
The protocol only allows sharing the icon between the application and the compositor. There is currently no official protocol to tell third party applications like panels about the icon. That is something that should maybe brought up at https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/196.
Ah.. that's a pity. I really thought we could access it the other way round. Well, in that case, we have nothing to do from our side. @Consolatis thanks. @Sodivad Sorry, I misunderstood your comment. Please ignore my reply.
PS: @Consolatis I am done dealing with wayland and/or wlroots protocols. To them I say: You implement something, good. You do not, good.
I see https://github.com/labwc/labwc/pull/1950 and if I get it right using this protocol could alos fix the positioning issues for popups on bottom/right panels like tooltips and bookmarks dialog in fancymenu, not sure. It should fix the seach results in mainmenu.
Rebased on top of #2075
It works fine on x11 but under kwin_wayland I get different errors and coredump based on folder (first Desktop, then home) where I launch it.
[user@archlinux Scrivania]$ lxqt-panel
Backend error: "Failed to extract plugin meta data from '/home/user/Scrivania/computer.desktop': '/home/user/Scrivania/computer.desktop' is not a valid ELF object (invalid signature)"
Backend error: "Failed to extract plugin meta data from '/home/user/Scrivania/featherpad.desktop': '/home/user/Scrivania/featherpad.desktop' is not a valid ELF object (invalid signature)"
Backend error: "Failed to extract plugin meta data from '/home/user/Scrivania/lxqt-config-session.desktop': '/home/user/Scrivania/lxqt-config-session.desktop' is not a valid ELF object (invalid signature)"
Backend error: "Failed to extract plugin meta data from '/home/user/Scrivania/lxqt-leave.desktop': '/home/user/Scrivania/lxqt-leave.desktop' is not a valid ELF object (invalid signature)"
Backend error: "Failed to extract plugin meta data from '/home/user/Scrivania/lxqt-logout.desktop': '/home/user/Scrivania/lxqt-logout.desktop' is not a valid ELF object (invalid signature)"
Backend error: "Failed to extract plugin meta data from '/home/user/Scrivania/network.desktop': '/home/user/Scrivania/network.desktop' is not a valid ELF object (invalid signature)"
Backend error: "Failed to extract plugin meta data from '/home/user/Scrivania/trash-can.desktop': '/home/user/Scrivania/trash-can.desktop' is not a valid ELF object (invalid signature)"
Backend error: "Failed to extract plugin meta data from '/home/user/Scrivania/user-home.desktop': '/home/user/Scrivania/user-home.desktop' is not a valid ELF object (invalid signature)"
Errore di segmentazione (core dump creato)
[user@archlinux Scrivania]$ cd
[user@archlinux ~]$ lxqt-panel
qt.core.plugin.loader: /home/user/file: failed to map to memory: Argomento non valido
Backend error: "Il file '/home/user/file' non è un plugin Qt valido."
Backend error: "Failed to extract plugin meta data from '/home/user/chromium-flags.conf': '/home/user/chromium-flags.conf' is not a valid ELF object (il file è troppo piccolo)"
Errore di segmentazione (core dump creato)
backtrace isn't really helpful, don't attach it.
I think it's a search path issue.
What's your value of macro PLUGIN_DIR
?
Here it points to /usr/local/lib/lxqt-panel
It then has a subfolder backend
which inside has kwin_wayland_backend.so
library
@stefonarch I can reproduce your error. I ran it through GDB. Turns out, lxqt-panel tries to load the xcb plugin. Here is the bt which is a little more sensible:
#0 0x00007ffff64ab32c in ??? () at /usr/lib64/libc.so.6
#1 0x00007ffff645a6c8 in raise () at /usr/lib64/libc.so.6
#2 0x00007ffff64424b8 in abort () at /usr/lib64/libc.so.6
#3 0x00007ffff5e8c6e9 in ??? () at /usr/lib64/libQt6Core.so.6
#4 0x00007ffff5e8ce6f in QMessageLogger::fatal(char const*, ...) const () at /usr/lib64/libQt6Core.so.6
#5 0x00007ffff5e8cf2a in qt_assert_x(char const*, char const*, char const*, int) () at /usr/lib64/libQt6Core.so.6
#6 0x00007fffe101d35e in LXQtWMBackendX11::LXQtWMBackendX11 (this=0x555555bd1410, parent=0x0) at /home/cosmos/Softwares/Projects/LXQt/lxqt-panel/panel/backends/xcb/lxqtwmbackend_x11.cpp:51
x11Application = 0x0
x11Application = <optimized out>
#7 0x00007fffe101fad9 in LXQtWMBackendX11Library::instance (this=0x555555be4240) at /home/cosmos/Softwares/Projects/LXQt/lxqt-panel/panel/backends/xcb/lxqtwmbackend_x11.cpp:700
#8 0x00005555555cd25c in LXQtPanelApplicationPrivate::loadBackend (this=0x555555bf4a90) at /home/cosmos/Softwares/Projects/LXQt/lxqt-panel/panel/lxqtpanelapplication.cpp:160
loader = <incomplete type>
preferredBackend = {d = {d = 0x0, ptr = 0x7ffff622e94e <QString::_empty> u"", size = 0}, static _empty = 0 u'\000'}
plugin = 0x555555be4240
backend = 0x555555be4250
__PRETTY_FUNCTION__ = "void LXQtPanelApplicationPrivate::loadBackend()"
#9 0x00005555555cd8f8 in LXQtPanelApplication::LXQtPanelApplication (this=0x7fffffffdd10, argc=@0x7fffffffdd0c: 1, argv=0x7fffffffde88) at /home/cosmos/Softwares/Projects/LXQt/lxqt-panel/panel/lxqtpanelapplication.cpp:212
VERINFO = {d = {d = 0x0, ptr = 0x5555556f4a60 u"2.0.1\nliblxqt 2.0.0\nQt 6.7.2", size = 37}, static _empty = 0 u'\000'}
configFile = {d = {d = 0x0, ptr = 0x0, size = 0}, static _empty = 0 u'\000'}
allScreens = {<QListSpecialMethods<QScreen*>> = {<QListSpecialMethodsBase<QScreen*>> = {<No data fields>}, <No data fields>}, d = {d = 0x0, ptr = 0x0, size = 0}}
d = 0x555555bf4a90
parser = {d = 0x555555be73f0}
configFileOption = {d = {d = 0x555555c025b0}}
panels = {<QListSpecialMethods<QString>> = {<QListSpecialMethodsBase<QString>> = {<No data fields>}, <No data fields>}, d = {d = 0x0, ptr = 0x0, size = 0}}
iconTheme = {d = {d = 0x555555c02420, ptr = 0x555555c02430 u"Use alternate configuration file.", size = 33}, static _empty = 0 u'\000'}
d = <optimized out>
VERINFO = {d = {d = <optimized out>, ptr = <optimized out>, size = <optimized out>}, static _empty = 0 u'\000'}
parser = {d = <optimized out>}
configFileOption = {d = {d = <optimized out>}}
configFile = {d = {d = <optimized out>, ptr = <optimized out>, size = <optimized out>}, static _empty = 0 u'\000'}
allScreens = {<QListSpecialMethods<QScreen*>> = {<QListSpecialMethodsBase<QScreen*>> = {<No data fields>}, <No data fields>}, d = {d = <optimized out>, ptr = <optimized out>, size = <optimized out>}}
panels = {<QListSpecialMethods<QString>> = {<QListSpecialMethodsBase<QString>> = {<No data fields>}, <No data fields>}, d = {d = <optimized out>, ptr = <optimized out>, size = <optimized out>}}
iconTheme = {d = {d = <optimized out>, ptr = <optimized out>, size = <optimized out>}, static _empty = 0 u'\000'}
screen = <optimized out>
__for_range = <optimized out>
__for_begin = {i = <optimized out>}
__for_end = {i = <optimized out>}
i = <optimized out>
__for_range = <optimized out>
__for_begin = {i = <optimized out>}
__for_end = {i = <optimized out>}
#10 0x00005555555a9e4d in main (argc=1, argv=0x7fffffffde88) at /home/cosmos/Softwares/Projects/LXQt/lxqt-panel/panel/main.cpp:39
app = {<LXQt::Application> = {<No data fields>}, static staticMetaObject = {d = {superdata = {direct = 0x7ffff7e4e2c0 <LXQt::Application::staticMetaObject>}, stringdata = 0x5555556f1080 <(anonymous namespace)::qt_meta_stringdata_CLASSLXQtPanelApplicationENDCLASS>, data = 0x5555556f11c0 <qt_meta_data_CLASSLXQtPanelApplicationENDCLASS>, static_metacall = 0x5555555a53b4 <LXQtPanelApplication::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)>, relatedMetaObjects = 0x0, metaTypes = 0x55555578a4a0 <qt_incomplete_metaTypeArray<(anonymous namespace)::qt_meta_stringdata_CLASSLXQtPanelApplicationENDCLASS_t, QtPrivate::TypeAndForceComplete<LXQtPanelApplication, std::integral_constant<bool, true> >, QtPrivate::TypeAndForceComplete<void, std::integral_constant<bool, false> >, QtPrivate::TypeAndForceComplete<void, std::integral_constant<bool, false> >, QtPrivate::TypeAndForceComplete<void, std::integral_constant<bool, false> >, QtPrivate::TypeAndForceComplete<void, std::integral_constant<bool, false> >, QtPrivate::TypeAndForceComplete<LXQtPanel*, std::integral_constant<bool, false> >, QtPrivate::TypeAndForceComplete<void, std::integral_constant<bool, false> >, QtPrivate::TypeAndForceComplete<QScreen*, std::integral_constant<bool, false> >, QtPrivate::TypeAndForceComplete<void, std::integral_constant<bool, false> >, QtPrivate::TypeAndForceComplete<QObject*, std::integral_constant<bool, false> >, QtPrivate::TypeAndForceComplete<void, std::integral_constant<bool, false> >, QtPrivate::TypeAndForceComplete<void, std::integral_constant<bool, false> > >>, extradata = 0x0}}, mPanels = {<QListSpecialMethods<LXQtPanel*>> = {<QListSpecialMethodsBase<LXQtPanel*>> = {<No data fields>}, <No data fields>}, d = {d = 0x0, ptr = 0x0, size = 0}}, mGlobalIconTheme = {d = {d = 0x0, ptr = 0x0, size = 0}}, d_ptr = 0x555555bf4a90}
What's your value of macro
PLUGIN_DIR
?
How can I check that?
EDIT:it looks like there is no other backend than xcb
Depends on #2041 (WM abstraction) Replaces #2031
This is an experimental implementation on taskbar, desktopswitch and showdesktop functionality for KWin Wayland compositor. It uses following protocols:
org-kde-plasma-virtual-desktop
plasma-window-management
(Taken from plasma-wayland-protocols repository)
Code is inspired by libtaskmanager/waylandtasksmodel.cpp
Ideally the Wayland backend should have sub-backends targeting specific compositors when no standard protocol is available.
It also uses layer shell protocol to place panel on screen edge.
NOTE: panel auto-hide is not working yet