layer-shell: strange behavior if keyboard interactivity is set before showing the view
Describe the bug If keyboard interactivity is set before initially showing (mapping) a layer-shell view, it takes effect, but is not fully updated the next time.
To Reproduce Steps to reproduce the behavior (Python example below):
- Create a layer-shell view without showing
- set keyboard interactivity to ON_DEMAND
- show the view (it will have keyboard focus which is expected)
- set keyboard interactivity to NONE
- the layer shell view retains keyboard focus (and takes keyboard input) until clicked outside or until keyboard interactivity is set again to ON_DEMAND -> NONE (i.e. it works the second time)
Expected behavior Keyboard focus is lost immediately.
If steps #2 and #3 are swapped, it works as expected.
Wayfire version git: 44e1fa9c62e1f8c9f35cedbf3e86c6a0247e0b79
Simple example Use the buttons to switch keyboard interactivity settings:
#!/usr/bin/env python3
import os
import sys
import gi
import wayfire_socket as ws
gi.require_version('Gtk', '3.0')
gi.require_version('GtkLayerShell', '0.1')
from gi.repository import Gtk, GtkLayerShell
class KBWindow(Gtk.Window):
def __init__(self):
self.timeout_id = 0
Gtk.Window.__init__(self)
GtkLayerShell.init_for_window(self)
GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.ON_DEMAND)
lbl = Gtk.Label('Set keyboard mode')
btn1 = Gtk.Button.new_with_label('None')
btn1.connect("clicked", self.kb_none)
btn2 = Gtk.Button.new_with_label('On demand')
btn2.connect("clicked", self.kb_ondemand)
btn3 = Gtk.Button.new_with_label('Exclusive')
btn3.connect("clicked", self.kb_excl)
btn4 = Gtk.Button.new_with_label('Quit')
btn4.connect("clicked", Gtk.main_quit)
entry = Gtk.Entry()
box = Gtk.Box(orientation = Gtk.Orientation.VERTICAL)
box.add(lbl)
box.add(btn1)
box.add(btn2)
box.add(btn3)
box.add(entry)
box.add(btn4)
self.add(box)
self.connect('destroy', Gtk.main_quit)
self.show_all()
# GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.ON_DEMAND)
def kb_none(self, btn):
GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.NONE)
def kb_ondemand(self, btn):
GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.ON_DEMAND)
def kb_excl(self, btn):
GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.EXCLUSIVE)
def main(args):
win1 = KBWindow()
Gtk.main()
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
Nice catch. After setting the keyboard mode to NONE, it only works as intended after focusing on another view, excluding the dialog. The issue is that the input still retains keyboard focus, and the update only occurs after a keyboard focus change.
it's up to gtk to disable the keyboard input on the fly
#!/usr/bin/env python3
import os
import sys
import gi
#pip install wayfire
from wayfire import WayfireSocket as ws
gi.require_version('Gtk', '3.0')
gi.require_version('GtkLayerShell', '0.1')
from gi.repository import Gtk, GtkLayerShell
class KBWindow(Gtk.Window):
def __init__(self):
self.timeout_id = 0
Gtk.Window.__init__(self)
GtkLayerShell.init_for_window(self)
GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.ON_DEMAND)
lbl = Gtk.Label(label='Set keyboard mode')
btn1 = Gtk.Button.new_with_label('None')
btn1.connect("clicked", self.kb_none)
btn2 = Gtk.Button.new_with_label('On demand')
btn2.connect("clicked", self.kb_ondemand)
btn3 = Gtk.Button.new_with_label('Exclusive')
btn3.connect("clicked", self.kb_excl)
btn4 = Gtk.Button.new_with_label('Quit')
btn4.connect("clicked", Gtk.main_quit)
self.entry = Gtk.Entry()
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
box.add(lbl)
box.add(btn1)
box.add(btn2)
box.add(btn3)
box.add(self.entry)
box.add(btn4)
self.add(box)
self.connect('destroy', Gtk.main_quit)
self.show_all()
def kb_none(self, btn):
GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.NONE)
# Make the input field non-editable
self.entry.set_sensitive(False)
def kb_ondemand(self, btn):
GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.ON_DEMAND)
# Make the input field editable again
self.entry.set_sensitive(True)
def kb_excl(self, btn):
GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.EXCLUSIVE)
# Make the input field editable again
self.entry.set_sensitive(True)
def main(args):
win1 = KBWindow()
Gtk.main()
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
The following seems to fix this issue for me (although I'm unsure if it would have additional side-effects, related to the other elements in prev_state, so I'm not creating a PR for it):
diff --git a/src/view/layer-shell/layer-shell.cpp b/src/view/layer-shell/layer-shell.cpp
index a85ca8a3..1c9f45cc 100644
--- a/src/view/layer-shell/layer-shell.cpp
+++ b/src/view/layer-shell/layer-shell.cpp
@@ -440,6 +440,9 @@ std::shared_ptr<wayfire_layer_shell_view> wayfire_layer_shell_view::create(wlr_l
lsurface->output = self->get_output()->handle;
+ // Initial state
+ self->prev_state = lsurface->current;
+
// Initial configure
self->on_commit_unmapped.emit(NULL);