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: setting keyboard-interactivity to ON_DEMAND always grabs the focus #2450

Open
dkondor opened this issue Aug 25, 2024 · 1 comment
Labels

Comments

@dkondor
Copy link
Contributor

dkondor commented Aug 25, 2024

Describe the bug
Per here, this is not intended.

To Reproduce
See Python code below. It creates a layer-shell view with buttons to toggle keyboard-interactivity + a separate button below the text entry ("Release keyboard") which tries to "lose" keyboard interactivity by (1) switching to NONE; (2) waiting 500 ms (to make what's happening more visible); and (3) switching back to ON_DEMAND

In any case when keyboard-interactivity is switched to ON_DEMAND, the layer-shell surface grabs keyboard focus.

Expected behavior
When clicking on "Release keyboard", the layer-shell surface should stay unfocused.

(Note: I'm unsure what should happen when clicking the "On demand" button; on the one hand, a mouse click should lead to keyboard focus; on the other hand, even in this case, switching to ON_DEMAND happens after the mouse click finished. In any case, this is not relevant to my use case and I'm fine with any behavior)

Use case
Primarily, I use ON_DEMAND to be able to register modifier + click on a layer-shell surface (while using standard GTK API). This requires ON_DEMAND to be the default state. I do want to "lose" the keyboard focus in specific cases: (1) when a menu is closed (e.g. by ESC or wf-shell::toggle_menu); (2) when triggering scale via IPC (e.g. see here).

Wayfire version
git 44e1fa9

Test code

#!/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, GLib


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.new('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)
		btn5 = Gtk.Button.new_with_label('Release keyboard')
		btn5.connect("clicked", self.release_kb)
		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(btn5)
		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 reset_keyboard(self):
		GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.ON_DEMAND)
		self.timeout_id = 0
		return False

	def release_kb(self, btn):
		# we set keyboard mode to NONE first to lose keyboard focus
		GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.NONE)
		if self.timeout_id == 0:
			# we wait 500 ms before setting it back to ON_DEMAND to see if focus really changes
			self.timeout_id = GLib.timeout_add(500, self.reset_keyboard)
	
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 25, 2024
@dkondor
Copy link
Contributor Author

dkondor commented Aug 25, 2024

The following fixes the issue for me:

diff --git a/src/view/layer-shell/layer-shell.cpp b/src/view/layer-shell/layer-shell.cpp
index a85ca8a3..c243868e 100644
--- a/src/view/layer-shell/layer-shell.cpp
+++ b/src/view/layer-shell/layer-shell.cpp
@@ -565,10 +565,10 @@ void wayfire_layer_shell_view::commit()
 
         if (prev_state.keyboard_interactive != state->keyboard_interactive)
         {
-            if ((state->keyboard_interactive >= 1) && (state->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP))
+            if ((state->keyboard_interactive == 1) && (state->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP))
             {
                 wf::get_core().seat->focus_view(self());
-            } else
+            } else if (state->keyboard_interactive == 0)
             {
                 wf::get_core().seat->refocus();
             }

So far I've only tested with my Python example and gtk-layer-demo. Since it avoids calling refocus in a lot of cases, it can have further, unintended consequences. One thing to note is that this results in clicking the "On demand" button also not grabbing focus which can be counter-intuitive in some cases.

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

1 participant