smithay icon indicating copy to clipboard operation
smithay copied to clipboard

Steam big picture gets no keyboard input

Open trigg opened this issue 4 years ago • 7 comments

Testing on Anvil on all backends available.

If you launch steam as steam -tenfoot or launch normally and switch to big-picture mode the window doesn't accept any keypresses.

Log shows keys are registered by Anvil and all other apps tested work as expected

trigg avatar Nov 09 '21 22:11 trigg

Per this issue https://github.com/ValveSoftware/steam-for-linux/issues/4924, this is probably an issue with XWayland?

i509VCB avatar Nov 20 '21 03:11 i509VCB

This issue is not across all XWayland, does not happen on wayfire via XWayland.

trigg avatar Nov 24 '21 13:11 trigg

This issue is not across all XWayland, does not happen on wayfire via XWayland.

XWayland in this case means the smithay integration with XWayland if it was a little confusing :)

i509VCB avatar Nov 24 '21 16:11 i509VCB

I can confirm this is an issue, recorded anvil using obs in the x11 backend

https://user-images.githubusercontent.com/30619168/143513205-4da486cc-f714-4f1c-92a2-3a147dc2f447.mp4

I try typing into the big picture browser at 1 min, there are also a few other bugs I find on the path to get into big picture by just trying to do things.

@psychon probably understands xwayland in smithay a lot better than I do.

i509VCB avatar Nov 26 '21 01:11 i509VCB

Well, the code in anvil/src/xwayland/mod.rs basically "does not do anything". For this case: Nothing ever does anything with the x11 input focus, so things end up in the default focus-follows-mouse mode. I do not know specifically why this case doesn't work with steam and I am not going to install steam to try to figure this out (could someone run xprop in a terminal, click on the steam fullscreen window and fetch the xprop output? Any long _NET_WM_ICON output can be skipped. I am specifically curious about WM_HINTS and WM_PROTOCOLS. (No idea how to run something in a terminal while another window is fullscreen. sleep 10 ; xprop?))

X11 being x11, there are four different "input models", where two of them expect help from the WM to get the input focus: https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.7 [At first I typed an explanation of the four models here, but then deleted it again because no one cares]

(Oh and: Nothing ever does anything with the stacking order, so it could happen that another window is "on top" in X11 than what anvil actually renders on top).

Basically: Something needs to do/be an actual window manager for lots of things to work properly. I can do the X11 parts (or help someone in filling them in), but sadly I do not really have the time to do much. The current WM in anvil doesn't even keep any state, so it does not know which windows exist! And AFAIR the user cannot move/resize windows.

psychon avatar Nov 28 '21 07:11 psychon

_NET_WM_USER_TIME(CARDINAL) = 630306
STEAM_BIGPICTURE(CARDINAL) = 1
_NET_WM_ICON(CARDINAL) = 	Icon (48 x 48):
	(not shown)

_NET_WM_STATE(ATOM) = _NET_WM_STATE_FULLSCREEN, _NET_WM_STATE_FOCUSED
WM_STATE(WM_STATE):
		window state: Normal
		icon window: 0x0
XdndAware(ATOM) = BITMAP
_NET_WM_NAME(UTF8_STRING) = "Steam"
WM_NAME(UTF8_STRING) = "Steam"
WM_PROTOCOLS(ATOM): protocols  WM_DELETE_WINDOW, WM_TAKE_FOCUS, _NET_WM_PING
_NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_NORMAL
_NET_WM_PID(CARDINAL) = 8677
WM_LOCALE_NAME(STRING) = "en_US.UTF-8"
WM_CLASS(STRING) = "steam", "steam"
WM_HINTS(WM_HINTS):
		Client accepts input or input focus: True
		window id # of group leader: 0x57e77205
WM_NORMAL_HINTS(WM_SIZE_HINTS):
		program specified minimum aspect ratio: 1066/600
		program specified maximum aspect ratio: 1066/600
WM_CLIENT_MACHINE(STRING) = "triggtop"
_MOTIF_WM_HINTS(_MOTIF_WM_HINTS) = 0x2, 0x0, 0x0, 0x0, 0x0

(Oh and: Nothing ever does anything with the stacking order, so it could happen that another window is "on top" in X11 than what anvil actually renders on top).

In my case this shouldn't be the problem as I only ever draw the first window in the list,

but sadly I do not really have the time to do much

I completely understand that and thanks for looking into this!

trigg avatar Nov 28 '21 08:11 trigg

WM_PROTOCOLS(ATOM): protocols WM_DELETE_WINDOW, WM_TAKE_FOCUS, _NET_WM_PING

Yup, this window expects a WM_TAKE_FOCUS message from the WM to get the input focus.

WM_HINTS(WM_HINTS): Client accepts input or input focus: True

It also expects the WM to focus the window "by itself". This part might actually already work (more or less) through the default "focus follows mouse" mode, but this will likely break as sooner or later (as soon as something actually sets the input focus and WM_TAKE_FOCUS allows clients to do this).

The WM_TAKE_FOCUS part "just" needs a call similar to this: https://github.com/psychon/x11rb/blob/d661b0ca04033b806dcb1f38619776ad34f281df/examples/simple_window_manager.rs#L359-L366 (Plus, in the context of anvil, a conn.flush()? afterwards might be necessary.)

But instead of using WM_DELETE_WINDOW, this part of ICCCM needs to be implemented: https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.7

Windows with the atom WM_TAKE_FOCUS in their WM_PROTOCOLS property may receive a ClientMessage event from the window manager (as described in section 4.2.8) with WM_TAKE_FOCUS in its data[0] field and a valid timestamp (i.e. not CurrentTime ) in its data[1] field.

I know that the spec forbids CurrentTime, but for a first draft, just using CurrentTime aka x11rb::CURRENT_TIME aka 0 might actually be enough. Doing this properly is a tiny bit more complicated, because "time" is more like "monotonic counter that the X11 server manages and that has nothing to do with actual time".

So, untested draft that just needs someone to figure out how to find the right X11 window id for the call (aka "the hard part is missing" since anvil's WM does not keep any state about windows currently):

let wm_protocols = conn.intern_atom(false, b"WM_PROTOCOLS")?.reply()?.atom;
let wm_delete_window = conn.intern_atom(false, b"WM_DELETE_WINDOW")?.reply()?.atom;
let event = ClientMessageEvent::new(32, window, wm_protocols, [wm_delete_window, 0, 0, 0, 0]);
conn.send_event(false, window, EventMask::NO_EVENT, &event)?;
conn.flush();

For doing this properly, I would recommend using https://docs.rs/x11rb/0.9.0/x11rb/macro.atom_manager.html instead of doing needless round-trips for interning these atoms when they are needed, but for a first draft the above would be enough.

The proper way to find the window to focus, would be to keep some map between Wayland surface ID and X11 window ID and use that. A quick first hack might be to just focus the window that was opened last. And to send it a WM_TAKE_FOCUS unconditionally, no matter what input mode it actually has. That would be done here (after mapping the window): https://github.com/Smithay/smithay/blob/a8bc2f4a50eebbd95fa5578aa92510f6ea884825/anvil/src/xwayland/mod.rs#L163

Edit: And if someone wants to actually check whether a window has WM_TAKE_FOCUS in its WM_PROTOCOLS property, a quick hack would be something like this condition that checks whether WM_TAKE_FOCUS appears in WM_PROTOCOLS:

conn
    .get_property(false, window, the_atom_for_WM_PROTOCOLS, x11rb::protocol::xproto::AtomEnum::ATOM, 0, 1234)?
    .reply()?
    .value32()
    .map(|iter| iter.any(|atom| atom == the_atom_for_WM_TAKE_FOCUS)) == Ok(true)

(Edit: Perhaps better u32::max instead of 1234? Doesn't really matter..)

psychon avatar Nov 28 '21 09:11 psychon

should this issue be closed? all prs addressing the issue are closed or merged. (I could be wrong, though)

anoraktrend avatar Feb 19 '23 14:02 anoraktrend

My apologies I've not been keeping up with my bug reports lately.

This works in all my tests. Thanks!

trigg avatar Feb 19 '23 15:02 trigg