Hello. I am fairly new to GTK development and I am planning to build a launcher-like application using GTK 4 and rust.
I need my application window to always open on top of other windows and in the center of the current monitor.
In gtk3 you could use the “set_keep_above” method on GtkWindow object to achieve that but that seems to have been removed from GTK4. After reading some posts I understood some of the reasons being this decision, but still, I am thinking this is a very common use case to have a launcher on top of other windows like Ulauncher, Albert, Rofi etc.
What would be the best way to do this with GTK 4? Maybe using Hints like _NET_WM_ACTION_ABOVE ??
I would prefer to have a solution that works in X11 and Wayland, but if not possible, I am not seeing using Wayland myself in the next few years and this is mostly a personal tool, so no problem if I have to use X11 APIs directly.
Note that this will be also my first Rust project, so if you can provide with some examples, It would be nice.
Hello, welcome to the Discourse, that’s a great question. Unfortunately there is no way to do that in a fully cross-platform manner so it was removed from GTK4. On X11 you will have to get the XID with gdk::X11Surface::xid and manually set the _NET_WM_STATE_ABOVE hint.
For Wayland, there is no standard API for this because it is an inherently insecure operation and it is known by now that the X11 policy of letting any window set these hints at will is not desired. If targeting GNOME, the most effective way to do it would probably be to make a GNOME extension that moves the window when it appears and set the above flag. That would work on both X11 and Wayland and be more secure than using the X11 hints. If targeting other Wayland implementations, there may be other things to use like the layer-shell extension which is intended for launchers and panels and such. If you want to do things like this in a secure way I would definitely suggest getting away from X11 as soon as possible.
Hey @brpaz I hope you can pull it off or at least learn something in the process. I tried to implement a prototype launcher in Rust also, but got stuck very early. Ulauncher heavily relies on GTK3 with X11 or Xwayland now.
You also can’t center a window in GTK4, and you need a Gnome extension if you want to implement “raise or run” to work on both X11 and Wayland. And additionally if you want to set a hotkey to show the launcher, you kind of need a Gnome extension for that also unless you leave it up to your users to handle the keybinding (which I guess is reasonable).
And I think that’s not all of it. I sort of got to the conclusion that I probably want to write the whole GUI as a Gnome shell extension, but with a daemon to handle the search database and extensions in Rust. Then Pop OS implemented their launcher exactly like that, so you might want to check that out. The shell extension is their whole cosmic desktop though, so it does a lot of other things also. And they have big ambitions to rewrite that layer to a fully independent DE.
It’s mostly out of their control, because they want Gtk to be fully Wayland compatible. Wayland doesn’t implement any protocol for these things, and there is no other protocol than X11 that does.
Gnome can implement it for extensions, because with Gnome they control the window manager, and can implement these things in that layer, but GTK can’t make assumptions about the window manager used.
I would love to see more standardization so we could get these behaviors back though.
There never was any “standardization” or “common operations” as far as X11 is concerned. It was implemented using property hints which are just that: hints that the window manager may or may not implement. Some window managers ignore them. So nothing has really changed there from the GTK side. You can think of Wayland as being more explicit about not supporting these hints.
For the “center” positioning, it wasn’t even X11 hints: GTK used the global coordinates to position the window itself, something that just cannot be done with Wayland.
Right, and that was done using XMoveWindow and some attempt to calculate what the correct coordinates are which also may not even work depending on the window manager or how it decides to implement things like workspaces… Another reminder why X11 is really not the model anyone wants to copy
I think that would be nearly optimal, assuming there was a reason to opt out (like doing a tiling wm) rather than “it’s not a standard, so we don’t have to implement it”
There is no feedback to the programmer whether the operation is supported or not or whether it failed
Some WMs might ignore them only in some circumstances, e.g. when a window is being dragged, or when a window is offscreen, or when a window is fullscreen or tiled, or in GNOME when the activities overview or app grid is open, etc etc. Again, no feedback to the programmer this is happening
Some users might think this is a bad behavior and configure the WM to disable it for all windows (a valid thing to do in X11 in any WM, not just tiling WMs)
There is no reason to do this from an unprivileged hints API anyway, the only thing that will use these types of APIs are launchers and panels, i.e. things that are considered privileged components of the shell and really need to be aware of all those special cases mentioned above, which are WM-specific
Maybe someone could design some kind of specialized API for desktop components that handles this and is really a superset of all situations that all window managers would end up in, but then you are looking at taking lots of pieces out of a GNOME extension and putting them in a generic form, along with everything else that every other window manager does.
If that sounds like a lot of effort, then one might have to accept that making a custom self-contained shell component is not something you can just bolt onto a random WM and have it work.
In most of these cases failing silently was not something I considered an issue. We did what we could to support these features, and when the WM didn’t implement them it was out of our hands. And it was probably the expected behavior for users who choose to use window managers which didn’t support the hints.
If that sounds like a lot of effort, then one might have to accept that making a custom self-contained shell component is not something you can just bolt onto a random WM and have it work.
That’s the hard pill to swallow for people used to these type of app launchers, but I recently came to a similar conclusions, so thanks for the confirmation
At least for me, after many decades of dealing with X11, it seems that it is not possible to have both a generic window management API available to clients, and a situation where the window manager can do whatever it wants. Those two things are completely opposing forces, but X11 tries to provide both and makes it so you have to cross your fingers and hope it works sometimes when the window manager feels like it. So that is why Wayland doesn’t have a window management API available to clients.
If one considers it appropriate to tell users “sorry your window manager is broken because it does not support feature XYZ, get used to it or use another one” then the Wayland situation is about the same…
Haven´t thought about the gnome extension route. I wanted to build a small launcher-like application for a very specific use case. But I also don´t want to be weeks dealing with GTK and Gnome shenanigans. I want to build this app quickly.
IMO the fastest way to build a launcher quickly (for GNOME) is to just make it entirely as a GNOME extension. Likewise for KDE you would just make a Plasma Widget. Once you start trying to build it as an external application in Rust or C or something and you plan to support multiple shells and window managers, it gets very complicated very quickly. For other desktops, I don’t know much about Pop Shell or Cinnamon or XFCE or anything like that, I heard they were making their own plugin systems.