Skip to content
This repository has been archived by the owner on Nov 1, 2021. It is now read-only.

Enhance wlr-layer-shell keyboard_interactivity #32

Closed
ammen99 opened this issue Dec 15, 2018 · 29 comments
Closed

Enhance wlr-layer-shell keyboard_interactivity #32

ammen99 opened this issue Dec 15, 2018 · 29 comments

Comments

@ammen99
Copy link
Member

ammen99 commented Dec 15, 2018

The current keyboard_interactivity allows clients to only notify the compositor they want exclusive keyboard access. It would make much more sense to allow clients to specify they want one of the following:

  1. No keyboard interaction - backgrounds, some docks, etc
  2. keyboard-focus-on-click - such could be panels that have a search field or that can be navigated with they keyboard, but don't want to lock focus to their layer
  3. exclusive keyboard focus - like the current 1 value - can be used for ex. by lockscreens

Note that adding this doesn't have to break existing clients - the protocol currently says what happens when the value is 1 (and afaik it is implicitly understood the only other reasonable value is 0). We can just specify what happens when the value is 2 (focus-on-click)

@ddevault
Copy link
Contributor

Can you elaborate more on some of the clients in the second group?

@ammen99
Copy link
Member Author

ammen99 commented Dec 15, 2018

Can you elaborate more on some of the clients in the second group?

I'm imagining something like a panel which has a search field (search for applications, files, whatever you want). Kind of what Windows has, although there the search field is inside the "popup". So, one may click on the panel's search field, and if he/she wants to dismiss it, can still click on the other normal apps.

Another use-case I thought of but as emersion pointed out it can be done via xdg-popup grab: navigating a popup menu with the keyboard.

And last but not least (a dirty hack, I agree) would be this: have a panel which can activate its menu from the terminal, via dbus or whatever. You can register this as a keybinding, then the panel first sets exclusive interactivity (stealing focus) then sets normal interactivity. At this point, the panel can be navigated with the keyboard, but it can also be dismissed when clicking on another window.

There aren't any clients that require this and that I know of, but I still think that differentiating between those 3 different cases is something that might help in the future.

@emersion
Copy link
Member

keyboard-focus-on-click

Thought about it for a while and I'm not sure it fixes the issue. If you have a panel with a search field, you want the panel to receive focus when the user clicks on the search field but you don't want to receive focus when the user clicks anywhere else on the panel.

Maybe that can be fixed by adding a request to start a grab on the layer surface.

@ammen99
Copy link
Member Author

ammen99 commented Dec 15, 2018

Maybe that can be fixed by adding a request to start a grab on the layer surface.

Ok, that is also a good idea. But I think that anyway we need to clarify what happens with layer surfaces without keyboard interactivity - they shouldn't get keyboard focus at all, except by this grab request?

@emersion
Copy link
Member

Yeah. IIRC this was left out as an implementation detail, but it's probably better to clearly specify the behaviour so that we don't get clients that work in a compositor and don't work in another.

@emersion
Copy link
Member

emersion commented Jan 8, 2019

Another use-case for a "keyboard-focus-on-click" kind of thing would be to be able to interact with swaynag with the keyboard.

@AdrianVovk
Copy link

My panel client uses the focus-on-click provided by wf-shell, and it works quite well for stealing/returning focus to apps as necessary. I do the whole dance with EXCLUSIVE->CLICK to get focus, and then NONE->CLICK to give up focus. I can open my menus via DBus and I need to steal keyboard focus but keep acting sanely (click away = defocus the window). When the panels are closed, I should be able to continue typing in the app that I stole focus from.

@ammen99
Copy link
Member Author

ammen99 commented Apr 28, 2019

After some recent discussions I no longer think we need the focus-on-click mode, at least for the original problem I was trying to solve. If a panel has a search field, it can just request exclusive focus when the user clicks in the search field, and drop it when clicking outside, achieving something similar to how xdg-shell grabs work. This would also ensure that such panels can work on more types of compositors, for ex. on focus-on-hover compositors.

I am not sure about

Another use-case for a "keyboard-focus-on-click" kind of thing would be to be able to interact with swaynag with the keyboard.

so I am leaving the issue open. Feel free to close it if there is no actual use case for the click-to-focus mode.

@AdrianVovk
Copy link

I've been messing around with GTK-layer-shell demo apps and I see a few issues with the way layer-shell handles it now.

Everything my panel needs can be boiled down to two functions: Steal focus and continue being treated normally, and give up focus and continue being treated normally. Right now, layer-shell has Steal focus and do not give it up again to anything else, and give up focus and do not give focus to me.

Maybe, instead of having a boolean keyboard mode, there could be enums + signals. For example:

enum KeyboardMode {
    EXCLUSIVE, // Steal focus and don't give up
    BORROWED, // Steal focus but give up normally
    NORMAL, // Give up focus but allow it to be taken normally
    NONE // Don't allow focus
}

signal keyboard_mode_changed(KeyboardMode new_mode) {
   if (new_mode == NORMAL || new_mode == NONE) close_popup_menus();
}

on_popup_menus_open() {
   set_keyboard_mode(BORROWED);
}

on_popup_menus_close() {
    set_keyboard_mode(NORMAL);
}

Thoughts?

@emersion
Copy link
Member

  1. This seems complicated. Adding grab semantics would probably be better.
  2. I don't like the idea of changing keyboard interactivity like this (here when popups are opened/closed). Popups have a keyboard grab anyway, I don't see why this is needed.

@AdrianVovk
Copy link

@emersion My popups don't have grabs, because users would have to click twice to switch from one popup to the next (click once to close the currently-open popup, and then a second time to open the next). Maybe this is just how GTK implements it, but I have to do this by manually to make it sane.

@emersion
Copy link
Member

I'm not sure I understand. Popups have grabs and you cannot really do anything about it.

Can you explain your exact use-case?

@AdrianVovk
Copy link

AdrianVovk commented May 20, 2019

I'm not sure I understand. Popups have grabs and you cannot really do anything about it.

I'm using GtkPopover, which allows me to make it act pretty much like a regular window. I can skip gtk_add_grab and it only opens/closes when I manually tell it to

Can you explain your exact use-case?
Pretty much exactly like Windows does popups for battery or wifi settings. I want the panel to be able to focus itself but not change anything else about how the compositor treats its focus. Same with defocus.

Using the mode with grabs doesn't allow the user to have the battery menu open and then click on the notifications icon and have that open. GTK grabs don't let me interact with any other UI outside of the popover, and that's no good for my panel

@AdrianVovk
Copy link

@emersion Does this mean that "the top-most layer must always have focus" or "only the top-most layer should ever have focus"?

If it's the latter, this keyboard issue can be resolved easily: When a client requests exclusive keyboard mode, the compositor gives it focus. The client can still be defocused, but nothing else can get focused. When the client gets defocused, it can detect this and drop exclusive focus, and the top-most regular window gets focused by the compositor. If a client wants to always have focus, it can detect defocus and re-request exclusive focus.

In other words, if exclusive focus mode means "only this client or nothing gets focus", then this issue can be closed

@AdrianVovk
Copy link

@emersion Ping. I'm unsure if you got the last comment

@emersion
Copy link
Member

emersion commented Jun 1, 2019

Using the mode with grabs doesn't allow the user to have the battery menu open and then click on the notifications icon and have that open. GTK grabs don't let me interact with any other UI outside of the popover, and that's no good for my panel

Most panels I've seen switch the menu when the user hovers another item. Open the popup by clicking on "battery", then hover "notifications icon" and it gets activated.

Does this mean that "the top-most layer must always have focus" or "only the top-most layer should ever have focus"?

Well. "the top-most layer which has keyboard interactivity set to true".

In other words:

  • If no surface has keyboard interactivity set to 1, business as usual, normal focus semantics apply for toplevels, and layer surfaces don't get keyboard focus
  • If one layer surface has keyboard interactivity set to 1, it gets keyboard focus, unconditionally, and focus cannot be changed
  • If more than one layer surface has keyboard interactivity set to 1, the top-most one gets focus (with the same semantics as above)

@AdrianVovk
Copy link

@emersion Gah, so that solution doesn't work

@ammen99
Copy link
Member Author

ammen99 commented Jun 1, 2019

@emersion So, if we have an interactive surface in the top layer, the compositor can't decide to unfocus it (without focusing anything else of course)?

@emersion
Copy link
Member

emersion commented Jun 2, 2019

Gah, so that solution doesn't work

Have you considered doing like GNOME and switching popup on mouseover?

So, if we have an interactive surface in the top layer, the compositor can't decide to unfocus it (without focusing anything else of course)?

To clarify, what I explained above was what the client should expect. The compositor has the final word and can decide to focus something else.

@AdrianVovk
Copy link

@emersion My issue has nothing to do about hovering on other items/clicking to switch popovers.

My issue is simple:

  • I need to be told when the user interacts with anything outside of my panel (so I can close all of my popovers)
  • I need to be able to steal focus from a view
  • I need to be able to return focus to a view

The idea is to implement point 1 through focusing/defocusing the panel. This is the way the wf-shell proto does it. A client can steal focus, then go into "treat me normally" mode to steal focus and still be told about defocus, and then it can go into "don't focus" followed by "treat me normally" to give up focus and still behave as expected

Now that I've laid it out like this, however, all layer-shell really needs is a "clicked outside of this client" signal. The steal/give back focus is done by the keyboard focus mode boolean. So:

User interacts with panel -> panel steals keyboard focus
User opens a popover through keyboard shortcut -> panel steals focus
User clicks outside of panel -> panel closes all popovers -> panel gives up keyboard focus
User closes a popover through keyboard shortcut -> panel gives up focus

Are you against adding in such an event?

@emersion
Copy link
Member

emersion commented Jun 3, 2019

It looks like you're trying to describe protocol-level mechanisms instead of what you really want from an UX point-of-view. Before going into "requests"/"events" details, I'd like to understand what's your exact use-case?

@AdrianVovk
Copy link

AdrianVovk commented Jun 3, 2019

@emersion I want my popovers to close when the user clicks on something that isn't my panel. I want to be able to steal focus for when the user opens my popovers with a keyboard shortcut, and return focus to the previous app when the user closes my popovers with a keyboard shortcut

Exact use case: My app launcher popover includes a spotlight-esque search feature. If the user presses Super, the menu toggles. If the user starts typing while the menu is open, it starts a search. If the menu is closed for any reason, the focus should go right back to the previous program. For example, user could be in a browser, press super, type 'e^5', see the answer, then click onto a text box in the browser (at which point the popover closes) and type into it.

Basically: Behave like the start menu on Windows

@emersion
Copy link
Member

emersion commented Jun 3, 2019

Seems to me like layer shell popups are exactly what you want. No need for keyboard interactivity.

@ammen99
Copy link
Member Author

ammen99 commented Jun 3, 2019

@emersion The compositor would never give focus to the popup/layer surface if it doesn't have keyboard interactivity?

Also problematic is that GTK uses subsurfaces in much more cases than it should (in this particular case subsurfaces are used)

@emersion
Copy link
Member

emersion commented Jun 3, 2019

The popup gets an implicit grab when opened. It means it gets all input events, including keyboard events, even if the parent surface doesn't have keyboard focus.

Also problematic is that GTK uses subsurfaces in much more cases than it should (in this particular case subsurfaces are used)

gtk-layer-shell probably helps here.

(But in any case this is a GTK issue, not a layer-shell one)

@dkondor
Copy link
Contributor

dkondor commented Nov 22, 2020

Hi,
I've just come across this. One more use-case where this is relevant is a layer-shell surface that cares about pressed keyboard modifiers with clicks.
E.g. cairo-dock has the function that shift + click on the icon of an already running application starts a new instance. This is something that I believe would work with "normal" keyboard focus semantics, but seems impossible to achieve currently. I agree with @ammen99 's original comment that this could be implemented without breaking current behavior by turning the argument of set_keyboard_interactivity() into an enum.

@emersion
Copy link
Member

This is something that I believe would work with "normal" keyboard focus semantics, but seems impossible to achieve currently.

Then this is a bug in the implementation, not in the protocol itself.

@ammen99
Copy link
Member Author

ammen99 commented Nov 23, 2020

This is something that I believe would work with "normal" keyboard focus semantics, but seems impossible to achieve currently.

Then this is a bug in the implementation, not in the protocol itself.

Would you say that cairo-dock needs to set keyboard interactivity to true when clicked on, wait to get the modifiers, then when it gets the modifiers, unset its keyboard interactivity?

@emersion
Copy link
Member

Oh, please disregard my comment. I forgot that layer surfaces didn't receive any keyboard input by default.

emersion pushed a commit to dkondor/wlr-protocols that referenced this issue Jan 6, 2021
Currently only background and bottom layers can have surfaces with
normal focus semantics. Allow top and overlay layers to have these
semantics too (instead of exclusive).

Closes: swaywm#32
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

No branches or pull requests

5 participants