ValveSoftware / gamescope

SteamOS session compositing window manager
Other
3.12k stars 211 forks source link

Origin achievment popups steal focus from game #87

Closed Plagman closed 3 years ago

Plagman commented 4 years ago

Output when running focus debug mode:

e481fd4bd0)
determine_and_apply_focus focus 35651622

xwininfo: Window id: 0x2200026 "Origin"

Absolute upper-left X:  803
Absolute upper-left Y:  550
Relative upper-left X:  803
Relative upper-left Y:  550
Width: 475
Height: 170
Depth: 32
Visual: 0x55
Visual Class: TrueColor
Border width: 0
Class: InputOutput
Colormap: 0x2200025 (not installed)
Bit Gravity State: NorthWestGravity
Window Gravity State: NorthWestGravity
Backing Store State: NotUseful
Save Under State: yes
Map State: IsViewable
Override Redirect State: no
Corners:  +803+550  -2+550  -2-0  +803-0
-geometry 475x170-2-0

_NET_WM_BYPASS_COMPOSITOR(CARDINAL) = 0
_NET_WM_STATE(ATOM) = _NET_WM_STATE_ABOVE, _NET_WM_STATE_SKIP_PAGER, _NET_WM_STATE_SKIP_TASKBAR
_NET_WM_ICON(CARDINAL) =        Icon (32 x 32):

░░                 
░░                  
░░░░                  
░░░░░░░░               
░░░░░░░░░░░░            
░░░░░░░░░░░░░░          
░░░░░░░░░░░░░░░░         
░░░░░░░░░░░░░░░░░░        
░░░░░░░░░░░░░░░░░░░       
░░░░░░░░░░░░░░░░░░░░░      
░░░░░░░░░░░░░░░░░░░░░░      
░░░░░░░░░     ░░░░░░░░      
░░░░░░░░       ░░░░░░░░     
░░░░░░░        ░░░░░░░░     
░░░░░░░         ░░░░░░░     
▒▒▒▒▒▒░         ▒▒▒▒▒▒░     
▒▒▒▒▒▒░        ░▒▒▒▒▒▒░     
▒▒▒▒▒▒▒░       ░▒▒▒▒▒▒░     
░▒▒▒▒▒▒░      ░▒▒▒▒▒▒▒░     
░▒▒▒▒▒▒▒▒░░░░░▒▒▒▒▒▒▒▒      
░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░      
░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░       
░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░       
░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░        
░▒▒▒▒▒▒▒▒▒▒▒▒▒░         
░▒▒▒▒▒▒▒▒▒▒▒          
░░░░░▒▒▒▒░          
░▒▒▒            
░▒░             
▒░              
░                

Icon (16 x 16):

░         
░░░░░       
░░░░░░░     
░░░░░░░░░    
░░░░░░░░░░░   
░░░░   ░░░░   
░░░     ░░░   
▒▒▒     ▒▒▒   
▒▒▒░   ░▒▒▒   
░▒▒▒░░░▒▒▒░   
▒▒▒▒▒▒▒▒▒    
▒▒▒▒▒▒▒░    
░░▒▒▒░     
░░      
░       

_NET_WM_NAME(UTF8_STRING) = "Origin"
WM_ICON_NAME(STRING) = "Origin"
WM_NAME(STRING) = "Origin"
WM_HINTS(WM_HINTS):
Client accepts input or input focus: True
Initial state is Normal State.
bitmap id # to use for icon: 0x3200e37
bitmap id # of mask for icon: 0x3200e39
window id # of group leader: 0x2200026
_NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_NORMAL
_MOTIF_WM_HINTS(_MOTIF_WM_HINTS) = 0x3, 0x24, 0x0, 0x0, 0x0
WM_NORMAL_HINTS(WM_SIZE_HINTS):
program specified location: 803, 550
program specified minimum size: 475 by 170
program specified maximum size: 475 by 170
window gravity: Static
_NET_WM_USER_TIME_WINDOW(WINDOW): window id # 0x3200010
XdndAware(ATOM) = BITMAP
_NET_WM_PID(CARDINAL) = 359077
WM_LOCALE_NAME(STRING) = "en_US.UTF-8"
WM_CLIENT_MACHINE(STRING) = "redcore"
WM_CLASS(STRING) = "origin.exe", "steam_app_1182480"
WM_PROTOCOLS(ATOM): protocols  WM_DELETE_WINDOW, _NET_WM_PING

xwininfo: Window id: 0x522 (the root window) (has no name)

Root window id: 0x522 (the root window) (has no name)
Parent window id: 0x0 (none)
104 children:
0x2200026 "Origin": ("origin.exe" "steam_app_1182480")  475x170+803+550  +803+550
0x3c00003 "Titanfall 2": ("titanfall2.exe" "steam_app_1237970")  1280x720+0+0  +0+0
1 child:
0x360005d (has no name): ()  1280x720+0+0  +0+0
0x3c00004 "Default IME": ("titanfall2.exe" "steam_app_1237970")  1x1+0+0  +0+0
0x3600038 (has no name): ()  1x1+-1+-1  +-1+-1
0x360002f (has no name): ()  1x1+-1+-1  +-1+-1
0x220001e "Origin": ("origin.exe" "steam_app_1182480")  1065x700+0+0  +0+0
1 child:
0x3200d58 (has no name): ()  160x24+0+0  +0+0
0x2200020 "Origin": ("origin.exe" "steam_app_1182480")  112x27+0+0  +0+0
1 child:
0x3200d23 (has no name): ()  112x27+0+0  +0+0
0x220001d "Origin": ("origin.exe" "steam_app_1182480")  229x425+320+120  +320+120
0x220001c "Origin": ("origin.exe" "steam_app_1182480")  112x27+0+0  +0+0
1 child:
0x3200bef (has no name): ()  112x27+0+0  +0+0
0x220001a "Origin": ("origin.exe" "steam_app_1182480")  112x100+590+310  +590+310
0x2200019 "Origin": ("origin.exe" "steam_app_1182480")  153x27+320+120  +320+120
0x2200018 "Origin": ("origin.exe" "steam_app_1182480")  640x480+320+120  +320+120
0x2200017 "Origin": ("origin.exe" "steam_app_1182480")  112x35+320+120  +320+120
0x2200016 "Origin": ("origin.exe" "steam_app_1182480")  640x480+320+120  +320+120
0x2200015 "Origin": ("origin.exe" "steam_app_1182480")  173x62+320+120  +320+120
0x2200014 "Origin": ("origin.exe" "steam_app_1182480")  173x62+553+329  +553+329
0x2200013 "Origin": ("origin.exe" "steam_app_1182480")  112x34+320+120  +320+120
0x2200012 "Origin": ("origin.exe" "steam_app_1182480")  640x480+320+120  +320+120
0x2200011 "Origin": ("origin.exe" "steam_app_1182480")  132x76+320+120  +320+120
0x2200010 "Origin": ("origin.exe" "steam_app_1182480")  127x71+576+324  +576+324
0x2200007 (has no name): ("origin.exe" "steam_app_1182480")  960x540+0+0  +0+0
0x2200006 (has no name): ("origin.exe" "steam_app_1182480")  112x27+0+0  +0+0
0x2200005 (has no name): ("origin.exe" "steam_app_1182480")  1x1+0+0  +0+0
0x2400008 "Wine System Tray": ("explorer.exe" "steam_app_1237970")  160x27+0+0  +0+0
0x2400009 (has no name): ("explorer.exe" "steam_app_1237970")  1x1+0+0  +0+0
0x2200004 "QTrayIconMessageWindow": ("origin.exe" "steam_app_1182480")  960x540+0+0  +0+0
0x2e00001 (has no name): ("originclientservice.exe" "steam_app_1182480")  1x1+0+0  +0+0
0x2e00002 "Default IME": ("originclientservice.exe" "steam_app_1182480")  1x1+0+0  +0+0
0x2c0000a (has no name): ()  1x1+-1+-1  +-1+-1
0x3200025 (has no name): ()  1x1+-1+-1  +-1+-1
0x2200001 (has no name): ("origin.exe" "steam_app_1182480")  1x1+0+0  +0+0
0x2200002 "Default IME": ("origin.exe" "steam_app_1182480")  1x1+0+0  +0+0
0x3200010 (has no name): ()  1x1+-1+-1  +-1+-1
0x2a00001 "Steam": ("steam.exe" "steam_app_1237970")  400x300+40+40  +40+40
0x2a00002 "Default IME": ("steam.exe" "steam_app_1237970")  1x1+0+0  +0+0
0x2800008 (has no name): ()  1x1+-1+-1  +-1+-1
0x2400007 (has no name): ("explorer.exe" "steam_app_1237970")  1x1+0+0  +0+0
0x2400006 (has no name): ("explorer.exe" "steam_app_1237970")  1x1+0+0  +0+0
0x2400005 (has no name): ("explorer.exe" "steam_app_1237970")  1x1+0+0  +0+0
0x2400004 (has no name): ("explorer.exe" "steam_app_1237970")  1x1+0+0  +0+0
0x2400002 (has no name): ("explorer.exe" "steam_app_1237970")  1x1+1280+720  +1280+720
0x2400003 "Default IME": ("explorer.exe" "steam_app_1237970")  1x1+0+0  +0+0
0x2000014 (has no name): ()  1x1+-1+-1  +-1+-1
0x2600001 (has no name): ()  1x1+0+0  +0+0
0x2400001 (has no name): ()  1280x720+0+0  +0+0
0x1600014 "Steam": ("steam" "steam")  1280x720+0+0  +0+0
0x160002d "SteamOverlay": ("steam" "steam")  650x200+0+0  +0+0
0x1600027 "SteamOverlay": ("steam" "steam")  1920x1080+0+0  +0+0
0x1600021 "SteamOverlay": ("steam" "steam")  1920x1080+0+0  +0+0
0x600074 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600072 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600070 "Screenshot Uploader": ("Steam" "Steam")  64x24+0+0  +0+0
0x60006e (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60006c (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60006a (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600068 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600066 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600064 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600062 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600060 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60005e (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60005c (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60005a (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600058 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600056 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600054 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600052 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600050 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60004e (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60004c (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60004a (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600048 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600046 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600044 "Servers": ("Steam" "Steam")  64x24+0+0  +0+0
0x600042 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600040 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60003e (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60003c (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60003a (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600038 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600036 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600034 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600032 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600030 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60002e (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60002c (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60002a (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600028 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600026 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600024 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600022 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600020 "Steam": ("Steam" "Steam")  64x24+0+0  +0+0
0x60001e (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60001c (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60001a (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x600018 "Friends": ("Steam" "Steam")  64x24+0+0  +0+0
0x600016 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60000f (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60000d (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x60000b "Web Chat Container": ("Steam" "Steam")  64x24+0+0  +0+0
0xe0000a (has no name): ()  1x1+0+0  +0+0
0x600005 (has no name): ("Steam" "Steam")  64x24+0+0  +0+0
0x800001 "steam": ("steam" "Steam")  10x10+10+10  +10+10
1 child:
0x800002 (has no name): ()  1x1+-1+-1  +9+9
0x200001 "steamcompmgr": ()  1x1+0+0  +0+0

Unhandled client message: WM_CHANGE_STATE
Plagman commented 4 years ago

Probably shouldn't focus any of these things as primary if there's an alternative: _NET_WM_STATE_ABOVE, _NET_WM_STATE_SKIP_PAGER, _NET_WM_STATE_SKIP_TASKBAR

Plagman commented 4 years ago

I think a good first step would just be a commit that tracks the three states above from _NET_WM_STATE and keeps them as Bools in the window structures.

emersion commented 4 years ago

wlroots code deciding whether an override-redirect window wants focus:

https://github.com/swaywm/wlroots/blob/b0144c7ded2b655085eb8e7e9b64908dc9420d60/xwayland/xwm.c#L1942

emersion commented 4 years ago

Hmm. Looks like we completely overwrite _NET_WM_STATE: https://github.com/Plagman/gamescope/blob/cd31090733c0517ce786bcb32574d42daa81130f/src/steamcompmgr.cpp#L552

Plagman commented 4 years ago

Ah whoops - probably wasn't a problem before we started wanting to care about it. This was more definitely intended to OR the hidden bit into the current window state.

emersion commented 4 years ago

This line might be responsible for the focus stealing:

https://github.com/Plagman/gamescope/blob/6cc28f8d7be5dfaefd0370462a1a294dbd97db52/src/steamcompmgr.cpp#L1666

emersion commented 4 years ago

All of this probably happens because the Windows client sets WS_EX_NOACTIVATE:

    if (ex_style & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE))
        new_state |= (1 << NET_WM_STATE_SKIP_TASKBAR) | (1 << NET_WM_STATE_SKIP_PAGER);

Wine will try to re-focus the parent window (then falling back to the currently active window, then falling back to the last focused window) when a WS_EX_NOACTIVATE window gets focus:

        /* try to find some other window to give the focus to */
        hwnd = GetFocus();
        if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
        if (!hwnd) hwnd = GetActiveWindow();
        if (!hwnd) hwnd = last_focus;
        if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time );
Plagman commented 3 years ago

Trying to summarize offline discussion: should winex11 set an 'extension' property for the WM indicating WS_EX_NOACTIVATE, given there's no strict equivalent on the Linux side? I'm guessing other WMs could actually make use of it too. That would let us to 'the right thing' and ignore it for input focus when it comes in, and not try to do a heuristic based on other attributes it might have.

emersion commented 3 years ago

Okay, I just had another idea: maybe we should listen to focus changes requested by the client and bump the focus priority based on that? So basically, if the client manually focuses a window, set a requestFocus field and use this in determine_and_apply_focus.

emersion commented 3 years ago

Hmm. Actually Wine should just change the focus behind the XWM's back when getting FocusIn for the achievement popup. gamescope doesn't listen to FocusIn events, so shouldn't interfere with the focus change. So I'm not sure why this bug happens.

Some WINEDEBUG=trace+x11drv,trace+event (plus gamescope -F) logs would be helpful.