Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layer-shell: strange behavior if keyboard interactivity is set before showing the view #2449

Open
dkondor opened this issue Aug 24, 2024 · 3 comments
Labels
Milestone

Comments

@dkondor
Copy link
Contributor

dkondor commented Aug 24, 2024

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):

  1. Create a layer-shell view without showing
  2. set keyboard interactivity to ON_DEMAND
  3. show the view (it will have keyboard focus which is expected)
  4. set keyboard interactivity to NONE
  5. 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: 44e1fa9

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:]))
@dkondor dkondor added the bug label Aug 24, 2024
@killown
Copy link
Contributor

killown commented Aug 24, 2024

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.

@killown
Copy link
Contributor

killown commented Aug 24, 2024

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:]))

@ammen99 ammen99 added this to the 0.10 milestone Aug 25, 2024
@dkondor
Copy link
Contributor Author

dkondor commented Aug 25, 2024

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);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants