bakkeby/patches

problem with fullscreen apps under wine when switching tags [question]

ltsdw opened this issue · 42 comments

ltsdw commented

Firstly thank you for your patches.

This seems to be a known issue, where you start an app in fullscreen mode, it works properly until you switch to another tag and back to the app, then it will be stuck (sound and commands still works, but the screen will be black).

This isn't an issue with your patches, but since you seem to know a lot about the dwm project I thought about asking you if you know something about an workaround, patch, or anything else.

This user on reddit said it solved it's issue with the fullscreen patch.

I tried the fullscreen patch (now I'm using dwm-fullscreen-compilation-6.2.diff) but still experiencing the problem.

I presume you are referring specifically to games here. Just the "actual" fullscreen may potentially work for things running under wine, but it won't be a catch all thing.

I don't know if it is a proton thing or a steam thing, but it seems that when you leave a steam game to view another tag the game internally goes into some form of weird state that is not advertised via the x properties. If you run xprop on the window it should say that it is in normal state.

The only fix or workaround I have found so far is to force set the state to NormalState when switching back to the window (in function setfocus).

You can try adding this one line here to your build and see if that fixes it for you:
https://github.com/bakkeby/patches/blob/master/dwm/dwm-steam-6.2.diff#L66

The if statement as part of that patch is just to avoid needlessly setting the state every time any window receives focus. It is not really important and you don't need to worry about that just to see if it solves the issue or not.

ltsdw commented

I don't know if it is a proton thing or a steam thing, but it seems that when you leave a steam game to view another tag the game internally goes into some form of weird state that is not advertised via the x properties. If you run xprop on the window it should say that it is in normal state.

as I think it happens with steam games, it's happening on any application that has a true fullscreen mode (not only games), it works normally with false fullscreen (also known as borderless mode).

I think the patch you mentioned only works with steam right? as this line set issteam.

I'm testing with three games all of them non-steam games.

you mentioned xprop, now I noticed something strange is happening.

here is xprop output to a game launched with fullscreen before I switch tag:

WM_STATE(WM_STATE):
		window state: Normal
		icon window: 0x0
_NET_WM_BYPASS_COMPOSITOR(CARDINAL) = 1
_NET_WM_STATE(ATOM) = _NET_WM_STATE_FULLSCREEN
_NET_WM_NAME(UTF8_STRING) = "Nova Ragnarok"
WM_ICON_NAME(STRING) = "Nova Ragnarok"
WM_NAME(STRING) = "Nova Ragnarok"
WM_HINTS(WM_HINTS):
		Client accepts input or input focus: False
		Initial state is Normal State.
		bitmap id # to use for icon: 0x1e00063
		bitmap id # of mask for icon: 0x1e00065
		window id # of group leader: 0x200000b
_NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_NORMAL
_MOTIF_WM_HINTS(_MOTIF_WM_HINTS) = 0x3, 0x26, 0x0, 0x0, 0x0
WM_NORMAL_HINTS(WM_SIZE_HINTS):
		window gravity: Static
_NET_WM_USER_TIME_WINDOW(WINDOW): window id # 0x1e00018
XdndAware(ATOM) = BITMAP
_NET_WM_PID(CARDINAL) = 123645
WM_LOCALE_NAME(STRING) = "pt_BR.UTF-8"

and here after I switch tag:

_NET_ACTIVE_WINDOW(WINDOW): window id # 0x100000f
_NET_CLIENT_LIST(WINDOW): window id # 0x1400214, 0x1400136, 0x180000f, 0x120000f, 0x100000f, 0x200000b
XFree86_DDC_EDID1_RAWDATA(INTEGER) = 0, -1, -1, -1, -1, -1, -1, 0, 13, -82, -54, 21, 0, 0, 0, 0, 34, 24, 1, 4, -107, 34, 19, 120, 2, -61, -59, -111, 85, 84, -108, 40, 36, 80, 84, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -38, 29, 86, -30, 80, 0, 32, 48, 68, 45, 71, 0, 88, -63, 16, 0, 0, 24, 0, 0, 0, -2, 0, 78, 49, 53, 54, 66, 71, 69, 45, 69, 52, 50, 10, 32, 0, 0, 0, -2, 0, 67, 77, 78, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, -2, 0, 78, 49, 53, 54, 66, 71, 69, 45, 69, 52, 50, 10, 32, 0, 85
GDK_VISUALS(INTEGER) = 1194, 1612
WM_NAME(STRING) = "\00161ºCã\302\200± \002036 028 029 030ã\302\200± \003RAM:3428/SWAP:0ã\302\200± \004â\302\207\302\205 0000 / 0000 kbpsã\302\200± \0050002 msã\302\200± \00666% - JBL TUNE110BTã\302\200± \007qui-07/10/21-14:37ã\302\200± \010[100] "
_NET_DESKTOP_VIEWPORT(CARDINAL) = 0, 0
_NET_DESKTOP_NAMES(UTF8_STRING) = "一", "二", "三", "四", "ウェブ", "ゲーム", "暗記", "マインクラフト", "開発"
_NET_CURRENT_DESKTOP(CARDINAL) = 5
_NET_NUMBER_OF_DESKTOPS(CARDINAL) = 9
_NET_SUPPORTED(ATOM) = _NET_SUPPORTED, _NET_WM_NAME, _NET_WM_STATE, _NET_SUPPORTING_WM_CHECK, _NET_WM_STATE_FULLSCREEN, _NET_ACTIVE_WINDOW, _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DESKTOP, _NET_WM_WINDOW_TYPE_DIALOG, _NET_CLIENT_LIST, _NET_DESKTOP_NAMES, _NET_DESKTOP_VIEWPORT, _NET_NUMBER_OF_DESKTOPS, _NET_CURRENT_DESKTOP
_NET_SUPPORTING_WM_CHECK(WINDOW): window id # 0x800015
XIM_SERVERS(ATOM) = @server=fcitx
RESOURCE_MANAGER(STRING) = "*.background:\t#191f21\n*.color0:\t#000000\n*.color1:\t#a8fff2\n*.color10:\t#fff700\n*.color11:\t#48605f\n*.color12:\t#5974ff\n*.color13:\t#38bab5\n*.color14:\t#29bc1d\n*.color15:\t#fd97ff\n*.color2:\t#01f539\n*.color3:\t#48a58c\n*.color4:\t#9D0101\n*.color5:\t#AE008B\n*.color6:\t#67807f\n*.color7:\t#0073ff\n*.color8:\t#52a84f\n*.color9:\t#2d98ee\n*.cursorColor:\t#00f2e4\n*.foreground:\t#f394ff\n*multiClickTime:\t5000\n"
_XKB_RULES_NAMES(STRING) = "evdev", "abnt2", "br", "", ""
XFree86_has_VT(INTEGER) = 1
XFree86_VT(INTEGER) = 1

It seems it's not showing the info about the game, but instead the window manager itself. Look there's the tags name, scripts that I'm using for the status bar, etc.

Could it be some patch that I applied?

The patch is specifically for steam yes, but the issue apparently affects wine and other platforms. The one line I referred to addresses the black screen issue that can occur when changing tags while a game window is in fullscreen, at least in the cases I have encountered.

If you could name some non-game applications where this happens then that would be useful. I'd like to be able to replicate this myself.

I could have a look at your build if you have that available somewhere.

ltsdw commented

If you could name some non-game applications where this happens then that would be useful. I'd like to be able to replicate this myself.

Sadly I can't think of any right now the only applications that I have right now is these 3 non-steam games, my thought was anything that can go fullscreen and change the resolution while doing this will trigger it.

I could have a look at your build if you have that available somewhere.

these are some of the patches that I have applied, since some of them will not apply because of incompatibility, I made some changes to some of them.

dwm-00-alpha-6.2.diff                      dwm-01-barpadding-6.2.diff
dwm-02-floatrules.diff                      dwm-03-hide_vacant_tags-6.2.diff
dwm-04-fullgaps-6.2.diff                  dwm-05-pertag-6.2.diff
dwm-06-regex-rules.diff                   dwm-07-alwayscenter.diff
dwm-08-desktop_icons-6.2.diff       dwm-09-fullscreen-compilation-6.2.diff
dwm-10-ewmhtags-6.2.diff              dwm-11-desktop-6.2.diff
dwm-12-statuscmd.diff                    dwm-13-unused-function-warning.diff

but to be reproducible at your end, I thought about trying dwm without any changes, patches or changes to config.h, just grabbed the source code and compiled, still the problem was there.

I take it that all three games run under wine?

ltsdw commented

I take it that all three games run under wine?

yes.

I tried with one game where the game/wine caused the monitor resolution to be changed. In this particular case the game crashed and the resolution stayed as is at 576x432 or something like that, but under normal circumstances I'd kind of expect wine to restore the original resolution when exiting.

If that actually happens I am not entirely sure of after finding these:

dwm does not actually manage the monitor / screen / resolution, but it will react if it receives a configure notify event and the root window size has changed. So if you change tags while the game is running the resolution will stay the same (e.g. 576x432 in my case) and the experience is less than stellar of course.

I tried another game and that did restore the resolution when I exited so perhaps it depends on the game or the situation.

But your question was not about the resolution change, but about the black screen issue.

So when I was in fullscreen in the game running via wine and I change tags then what happens is that the game window loses focus and wine wants the window to be minimized (go into iconic state).

When I restore a window from iconic state then it comes back fine (no black screen), which is the same basis for the steam patch adding the one line of setclientstate(c, NormalState); in the setfocus function. It could be that you need to use keybindings to be able to focus on the window though for this to come into effect.

What you can try is to add the awesomebar patch to your build and see if that makes any difference for you.

It shows all window titles in the bar, but more importantly it adds some support for the IconicState. At least with this you can test if explicitly hiding and unhiding a game window will fix the black screen issue.

If that works then I can show you how to handle state changes via client messages.

ltsdw commented

I tried with one game where the game/wine caused the monitor resolution to be changed. In this particular case the game crashed and the resolution stayed as is at 576x432 or something like that, but under normal circumstances I'd kind of expect wine to restore the original resolution when exiting.

Ah yes, it does it sometimes, generally 41-valve_proton_fullscreen_hack-staging-tkg.patch solves it, I think.

So when I was in fullscreen in the game running via wine and I change tags then what happens is that the game window loses focus and wine wants the window to be minimized (go into iconic state).

When I restore a window from iconic state then it comes back fine (no black screen), which is the same basis for the steam patch adding the one line of setclientstate(c, NormalState); in the setfocus function. It could be that you need to use keybindings to be able to focus on the window though for this to come into effect.

What you can try is to add the awesomebar patch to your build and see if that makes any difference for you.

About that I had major incompatibilities trying to apply the patch, but I think I did good adapting it, as everything seems to be working, MOD+h (hides it), MOD+s (unhide), MOD+k, MOD+j, MOD+SHIFT+j and MOD+SHIFT+k also working as it suppose to (cycling through/hiding/unhiding windows).

But it seems to not be working with the games I tried with (it worked for you?), once pressing MOD+h the window goes black (as related above with switching tags, also tried switching tags instead of hiding with MOD+h, but still), MOD+s doesn't seem to work/bring the window back, everything keeps black, and MOD+SHIFT+j/k actually crashes the Xorg session/dwm I don't know (only happens when I try with the games, everything else it hide/unhide the windows as it supposed to).

ltsdw commented

actually I'll try to apply the patch on plain dwm, without the others patches to see if it still crashes with MOD+SHIFT+j/k

So Nova Ragnarok is one game you are having issues with, what are the other two?

ltsdw commented

every game that has fullscreen mode (true fullscreen), nova ragnarok, gta-sa, PoE (in the past TESO, TS4 and LoL, but I don't have them right now to test again, so only the first three).

ltsdw commented

Ok, adapted the patch again, applied a top of dwm source without any other patch, now mod+shift+j/k seems to be working and not crashing the whole thing anymore. Still, the game isn't drawing the window back when trying to unhide after switching tag (or hiding).

I guess I'll have to try a few more games to reproduce this issue.

Given that you are able to replicate this consistently you are welcome to try out my build provided you promise not to look at the code. It has some more extensive EWMH integration, but nothing that makes me think "oh yes that change would have fixed the black screen issue in wine".

ltsdw commented

pretty cool build huh, but still :(

lala

ltsdw commented

also I don't know if matters, but using the wine's option 'emulate a virtual desktop' at winecfg, with the resolution of the monitor doesn't trigger it, I guess because wine draws the window similar to the 'borderless' option of the game.

Hmm, yes.

Unchecking the Allow the window manager to control the windows tickbox will also prevent you from doing e.g. Super+3 to change tags. That is actually not true because it will still change tags in the background and if I open up a new terminal and do Super+f to make it fullscreen then it is above the game running fullscreen (which is quite a cool effect I find).

I am wondering if the black screen issue might be related to the graphics drivers.

ltsdw commented

I am wondering if the black screen issue might be related to the graphics drivers.

I don't know, maybe. I'm using an Intel HD Graphics 5500.

Did you couldn't reproduce the issue on your end? That's strange. You tested with what game? Maybe I can test here too.

ltsdw commented

I was thinking trying out that steam patch you mentioned, but making a change to it, instead of issteam I'll adapt it to isexe (or something like that) and match it with title/class that ends with .exe. Just to see if it makes any change, as I don't have steam installed right now.

You don't need the whole steam patch, just the one line I referred to earlier.

I was testing with Anachronox which is a very old game and using OpenGL. I have been trying a few others but to be honest I am generally struggling to get them to run. Maybe I need to download some from GoG as they are often better supported.

ltsdw commented

Sadly it didn't worked neither.

One thing I noticed, as I said above, after switching tag and using xprop it was showing the info about the dwm itself, it is because it isn't the window of the game that is there when using xprop, to make the window of the game comes to front I have to press MOD+f. But only a fraction of the window will draw at the superior left corner of the display.

imageedit_2_8132523650

Sadly it didn't worked neither.

Yes not surprising given that the awesomebar patch didn't help either with hiding / unhiding the window.

Do you know if this works fine in i3, qtile or xmonad?

ltsdw commented

Yup, it does. Didn't tested with qtile though, but it works with i3 and xmonad.

That's good.

When you move to another tag in dwm the windows are moved to a negative x position, and when you move back to a tag the windows are moved from the negative x position to their designated place.

It is guesswork on my part but it could be that the graphics driver somehow does not like the window being moved to a negative x position. One thing we can try out is to swap out the mechanism that hides and shows windows (in the showhide function in dwm.c) with code that iconifies and unmaps and sets normal state and maps windows instead.

There is an example of doing this in @jzbor's MoonWM (fork / build of dwm). Not sure how easy it is to get running, you'll need wmcommons as well as the project is split (for some odd reason :)).

The main logic we are after are ref.

ltsdw commented

well... the same result with moonwm :(

Well at least we can rule out that it has something to do with moving the window to a negative x position.

It is an interesting issue.

Do you know how to capture standard error when you run dwm? It might be worth having a look at the property notifications and configure requests that comes in when you reproduce the issue. This you can add to your build using fprintf statements, or you can try my build with debug enabled.

ltsdw commented

I went with your build.

I thought it would be more verbose, I don't know if I did right though. Look:

sáb 09 out 2021 16:54:13 -03: Starting dusk
manage --> client st
manage <-- (st)
[282 16:54:25.837693] Ignoring unknown config key: cursorColor
manage --> client kitty
manage <-- (kitty)
[282 16:54:26.025809] Failed to enable transparency. This happens when your desktop environment does not support compositing.
erresc: unknown csi ESC[22;0t
erresc: invalid color j=258, p=?
erresc: unknown csi ESC[23;0t
erresc: unknown csi ESC[22;0t
erresc: invalid color j=258, p=?
erresc: unknown csi ESC[23;0t
erresc: unknown csi ESC[22;0t
erresc: invalid color j=258, p=?
erresc: unknown csi ESC[23;0t
hidews called for ws 1
manage --> client Nova Ragnarok
manage <-- (Nova Ragnarok)
hidews called for ws 2
hidews called for ws 1
hidews called for ws 2
erresc: unknown csi ESC[22;0t
erresc: invalid color j=258, p=?
hidews called for ws 1
manage --> client Nova Ragnarok
manage <-- (Nova Ragnarok)
hidews called for ws 2
erresc: unknown csi ESC[23;0t
erresc: unknown csi ESC[22;0t
erresc: invalid color j=258, p=?
erresc: unknown csi ESC[23;0t
erresc: unknown csi ESC[22;0t
erresc: invalid color j=258, p=?
ATTENTION: default value of option mesa_glthread overridden by environment.
ATTENTION: option value of option mesa_glthread ignored.

As I think it is piping all errors it finds there's some noise there I think that's erresc is from nvim, you can ignore it, the attention is from wine and there's some other stuff from the kitty itself.

Interesting that we get a mapping request for the game twice, like it has been unmapped somehow or there are actually two separate windows.

The last bit about mesa_glthread is also curious.

In config.h under the functionality setting you can uncomment the debug option to get more information on property notifications and configure requests.

https://github.com/bakkeby/dusk/blob/6cc8ad6aac7edf32dad91ebc33dfa8fd5c0897ed/config.def.h#L82

ltsdw commented

The last bit about mesa_glthread is also curious.

my bad, that was my fault, actually that is from firefox (that was a bug where it would crash at start with mesa_glthread=true (that's my case it's true system wide for every application), so I had to set it to false, it's was fixed already I can remove that envar before launching firefox).

In config.h under the functionality setting you can uncomment the debug option to get more information on property notifications and configure requests.

https://github.com/bakkeby/dusk/blob/6cc8ad6aac7edf32dad91ebc33dfa8fd5c0897ed/config.def.h#L82

Ok, let me try again.

ltsdw commented

You mentioned config.h and referenced the config.def.h xd I was wondering why wasn't working, had to uncomment at the config.h. btw pretty neat of yours having a debug option.

EDIT:

that was too much info to paste here, so put it on a file.

dusklog.txt

Thanks @ltsdw, that's very helpful.

The only thing that sticks out for me is this when the window is first shown:

configurerequest: received event 15 for client Nova Ragnarok
    - x = 0, y = 0, w = 1366, h = 768

and this when the window is hidden:

configurerequest: received event 15 for client Nova Ragnarok
    - x = -32000, y = -32000, w = 160, h = 24

For some reason it changes size to 160x24, which most likely explains why it only showed a fraction of the window in the top left corner.

Possibly something interferes which prevents wine from restoring the size of the window afterwards.

Can you try adding the following rule in the clientrules array in config.h for dusk and see if that makes any difference?

{ .class = "novaro.exe", .flags = IgnoreCfgReqPos|IgnoreCfgReqSize },

The idea being to see if disrespecting the client's wish to resize to 160x24 has an impact. This may however interfere with setting the initial size of 1366x768.

If that is problematic then we can try to only respect configure requests to resize the window if the window position is not negative.

E.g. for dwm:

diff --git a/dwm.c b/dwm.c
index 5e4d494..c33f0e5 100644
--- a/dwm.c
+++ b/dwm.c
@@ -597,11 +597,11 @@ configurerequest(XEvent *e)
                                c->oldy = c->y;
                                c->y = m->my + ev->y;
                        }
-                       if (ev->value_mask & CWWidth) {
+                       if (c->x >= 0 && (ev->value_mask & CWWidth)) {
                                c->oldw = c->w;
                                c->w = ev->width;
                        }
-                       if (ev->value_mask & CWHeight) {
+                       if (c->y >= 0 && (ev->value_mask & CWHeight)) {
                                c->oldh = c->h;
                                c->h = ev->height;
                        }
ltsdw commented

hmm, it doesn't seem to be working, yet, I noticed that it still at log:

configurerequest: received event 15 for client Nova Ragnarok
    - x = -32000, y = -32000, w = 160, h = 24

dusklog2.txt

The debug logging would still log the fact that it received such a request (even if it may not respect it). It is a bit disappointing that it didn't work though.

ltsdw commented

Yup was a bit disappointing :(

I have some updates to make though. Like I got your steam patch and made some little changes to it, and when I tested with PoE and GTA SA, in fact the window redraw itself after focusing, with some caveat of course.

this is your steam patch using regex to pattern match.

diff --git a/config.def.h b/config.def.h
index 861b566..05e679c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -41,6 +41,9 @@ static const Rule rules[] = {
 	{ "Firefox",  NULL,       NULL,       1 << 8,       0,           -1 },
 };
 
+/*regex patterns to match class window with*/
+static const char* regex_classes[] = { "\\.exe", "steam_proton", "Steam", "steam_app_" };
+
 /* layout(s) */
 static const float mfact     = 0.55; /* factor of master area size [0.05..0.95] */
 static const int nmaster     = 1;    /* number of clients in master area */
diff --git a/dwm.c b/dwm.c
index 5d9e565..7cf761d 100644
--- a/dwm.c
+++ b/dwm.c
@@ -98,6 +98,7 @@ struct Client {
 	int bw, oldbw;
 	unsigned int tags;
 	int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+	int iswine;
 	int fakefullscreen;
 	Client *next;
 	Client *snext;
@@ -318,6 +319,8 @@ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
 
 static regex_t regexcache[LENGTH(rules)][3];
 
+static regex_t regexwine[LENGTH(regex_classes)];
+
 /* function implementations */
 void
 applyrules(Client *c)
@@ -335,6 +338,13 @@ applyrules(Client *c)
 	class    = ch.res_class ? ch.res_class : broken;
 	instance = ch.res_name  ? ch.res_name  : broken;
 
+	for (i = 0; i < LENGTH(regexwine); i++) {
+		if (!regexec(&regexwine[i], class, 0, NULL, 0)) {
+			c->iswine = 1;
+			break;
+		}
+	}
+
 	for (i = 0; i < LENGTH(rules); i++) {
 		r = &rules[i];
 		if((!r->title || !regexec(&regexcache[i][2], c->name, 0, NULL, 0)) &&
@@ -603,6 +613,10 @@ compileregexes(void)
 	int i;
 	int status;
 	const Rule *r;
+
+	for (i = 0; i < LENGTH(regex_classes); ++i)
+		regcomp(&regexwine[i], regex_classes[i], REG_NOSUB);
+
 	for(i = 0; i < LENGTH(rules); i++) {
 		r = &rules[i];
 		if (r->class) {
@@ -686,13 +700,15 @@ configurerequest(XEvent *e)
 			c->bw = ev->border_width;
 		else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
 			m = c->mon;
-			if (ev->value_mask & CWX) {
-				c->oldx = c->x;
-				c->x = m->mx + ev->x;
-			}
-			if (ev->value_mask & CWY) {
-				c->oldy = c->y;
-				c->y = m->my + ev->y;
+			if (!c->iswine) {
+				if (ev->value_mask & CWX) {
+					c->oldx = c->x;
+					c->x = m->mx + ev->x;
+				}
+				if (ev->value_mask & CWY) {
+					c->oldy = c->y;
+					c->y = m->my + ev->y;
+				}
 			}
 			if (ev->value_mask & CWWidth) {
 				c->oldw = c->w;
@@ -1670,6 +1686,10 @@ setfocus(Client *c)
 			XA_WINDOW, 32, PropModeReplace,
 			(unsigned char *) &(c->win), 1);
 	}
+
+	if (c->iswine)
+		setclientstate(c, NormalState);
+
 	sendevent(c, wmatom[WMTakeFocus]);
 }

about the gta-sa:

  • if I change tag a black window will redraw at that window (is the game window, but it doesn't show nothing, it's black, this window maybe it's appearing because the logic of my changes to your patch, I don't know), so I have to change to another tag to this window disappear.
  • switching back to game tag,sometimes there will be that rectangle that I mentioned above, hovering the mouse over this rectangle will bring the game window to front (not black, the actual game window, which it's good, in fact, this solved a really annoying problem where the camera would spin forever even when using the wine's virtual desktop option).

PoE is the same as I described above.

Nova RO though will not bring the window of the game back :(, actually about the thing I described above, where switching tag will draw a black screen to the tag I switched, novaro actually will draw that little square I mentioned, not the entire screen as the other two games, it seems to ignore completely the screen size, or the size of the window before it 'hide' itself, I don't know.

what these lines does exactly?

				if (ev->value_mask & CWX) {
					c->oldx = c->x;
					c->x = m->mx + ev->x;
				}
				if (ev->value_mask & CWY) {
					c->oldy = c->y;
					c->y = m->my + ev->y;
				}

btw may I let this issue opened a little bit more? maybe I'll test with some other things, eventually I'll close it.

ltsdw commented

I also tried applying what you suggested with the patch above:

diff --git a/dwm.c b/dwm.c
index 5e4d494..c33f0e5 100644
--- a/dwm.c
+++ b/dwm.c
@@ -597,11 +597,11 @@ configurerequest(XEvent *e)
                                c->oldy = c->y;
                                c->y = m->my + ev->y;
                        }
-                       if (ev->value_mask & CWWidth) {
+                       if (c->x >= 0 && (ev->value_mask & CWWidth)) {
                                c->oldw = c->w;
                                c->w = ev->width;
                        }
-                       if (ev->value_mask & CWHeight) {
+                       if (c->y >= 0 && (ev->value_mask & CWHeight)) {
                                c->oldh = c->h;
                                c->h = ev->height;
                        }

but as it didn't change anything (atleast I din't see nothing different) I let it out of the patch.

btw may I let this issue opened a little bit more?

Of course. I don't use wine personally but I am as interested as you in finding out the cause of these black windows and what other window managers does differently in this respect to make it work. I know many people come across this and it would be good to have solution to this. I just wanted to say thanks for your persistence and for bearing with me.

We can also move this to the discussion section, but I'm fine with leaving it here.

what these lines does exactly?

				if (ev->value_mask & CWX) {
					c->oldx = c->x;
					c->x = m->mx + ev->x;
				}
				if (ev->value_mask & CWY) {
					c->oldy = c->y;
					c->y = m->my + ev->y;
				}

When the window manager receives a configure request event then that event can contain information about the window coordinates (x and y position) and/or the window size (height and width).

The value mask contains flags indicating which values were provided as part of the configure request event. In the first if statement it checks whether the x coordinate was present in the event, and if so then it sets the new position. Same with the y value.

I also tried applying what you suggested with the patch above but as it didn't change anything

Yes so in your modified steam patch you wrapped the positional data in an if (!c->iswine) { clause, hence the configure request would no longer result in the c->x and c->y being set to -32000, thus the size would still be resized to 160x24. You can try wrapping both position and size within the if clause to see if that helps, but I kind of doubt it given that the rule in #39 (comment) didn't help. Then again that rule was specifically for Nova Ragnarok which behaves differently compared to the other two games.

What you may also want to try is to resize the game window, either using the mouse or by opening a new tiled terminal next to it. If that makes a difference let me know.

switching back to game tag,sometimes there will be that rectangle that I mentioned above, hovering the mouse over this rectangle will bring the game window to front (not black, the actual game window, which it's good, in fact, this solved a really annoying problem where the camera would spin forever even when using the wine's virtual desktop option).

From dwm's side the only thing that happens here is that it receives an enter notify event from the X server and this triggers the eventnotify function which ultimately calls focus(c); on the client window.

If you tail the dusk debug output (or if you add debug print statements to your own build) while doing this then I suspect that you'll find that another configure request comes in to resize the window. Potentially what triggers this is that the window receives input focus.

if I change tag a black window will redraw at that window (is the game window, but it doesn't show nothing, it's black, this window maybe it's appearing because the logic of my changes to your patch, I don't know), so I have to change to another tag to this window disappear.

I think is likely a side effect of the steam patch where the if (!c->iswine) { statement added to the configurerequest function prevents wine from moving the window away via configure requests.


Overall my impression is that these issues mainly come from that wine tries to act like a window manager to manage the game window and that this interferes with how the window manager manages the window, or vice versa.

The bit about it sending a configure request to move the window to x and y position of -32000 I still find curious. Maybe wine has logic such that it depends on finding the window at those coordinates?

I checked out the wine source code from https://wiki.winehq.org/Source_Code and it looks like it does depend on it as well as the iconic state.

$ grep -rn -- -32000 wine | grep -v '/tests/'
wine/dlls/user32/winpos.c:1138:        else if (IsIconic( hwnd ) && (newPos.left != -32000 || newPos.top != -32000))
wine/dlls/user32/winpos.c:1140:            OffsetRect( &newPos, -32000 - newPos.left, -32000 - newPos.top );
wine/dlls/user32/winpos.c:1772:             wndPtr->window_rect.left <= -32000 && wndPtr->window_rect.top <= -32000 &&
wine/dlls/user32/winpos.c:1775:            pWinpos->x = -32000;
wine/dlls/user32/winpos.c:1776:            pWinpos->y = -32000;
wine/dlls/wineandroid.drv/window.c:1391:    if (rect->left != -32000 || rect->top != -32000)
wine/dlls/wineandroid.drv/window.c:1393:        OffsetRect( rect, -32000 - rect->left, -32000 - rect->top );
wine/dlls/winex11.drv/window.c:2566:        if (((rect->left != -32000 || rect->top != -32000)) && hide_icon( data ))
wine/dlls/winex11.drv/window.c:2568:            OffsetRect( rect, -32000 - rect->left, -32000 - rect->top );
wine/dlls/winemac.drv/window.c:1803:        if (rect->left != -32000 || rect->top != -32000)
wine/dlls/winemac.drv/window.c:1805:            OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);

It should be noted that configure requests that change position of the window are ignored by dwm if the window is not shown. Refer to this if statement in the configurerequest function:

            if (ISVISIBLE(c))
                XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);

There is a patch called autoresize that works with this in that the window will be moved later on when it is displayed again.

I don't think that is exactly what we are after though.

I am thinking we could try something like this to allow wine to move the window to those coordinates. Note that you'll want to remove the if (!c->iswine) { from before which prevents wine from changing the position of the window.

            if (ISVISIBLE(c) || c->x < 0)
                XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
ltsdw commented

I just wanted to say thanks for your persistence and for bearing with me.

And thank you for helping me out :)

We can also move this to the discussion section, but I'm fine with leaving it here.

For me that would be fine too, whichever you think it's better.

What you may also want to try is to resize the game window, either using the mouse or by opening a new tiled terminal next to it. If that makes a difference let me know.

That will not work neither, the little rectangle of the game will not move neither. It will on accept move when I do something like, mod+f which will cover the entire window in black (including the bar), then mod+f again to return to normal the 160x24 rectangle, then I will be able to move that little window, but not resize it, it still ignore any request to resize it.

I think is likely a side effect of the steam patch where the if (!c->iswine) { statement added to the configurerequest function prevents wine from moving the window away via configure requests.

I tried removing that, still it draws a black window to the tag I switched to, actually PoE will draw a window with borders, the GTA will simple cover the entire window in black (I think because gta doesn't have a fullscreen-with-borders option, only fullscreen).

There is a patch called autoresize that works with this in that the window will be moved later on when it is displayed again.

I'll try that out and see if changes something.

I am thinking we could try something like this to allow wine to move the window to those coordinates. Note that you'll want to remove the if (!c->iswine) { from before which prevents wine from changing the position of the window.

            if (ISVISIBLE(c) || c->x < 0)
                XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);

So I tried that out, but it doesn't seem to change much. The only difference that I noticed now is that Nova RO will draw a black window that covers the entire window to the tag I switched to (like the other two), but if I go to the tag of the game it'll have nothing there, neither that rectangle 160x24.

diff --git a/dwm.c b/dwm.c
index 544bc1c..f1997c4 100644
--- a/dwm.c
+++ b/dwm.c
@@ -700,16 +700,14 @@ configurerequest(XEvent *e)
 			c->bw = ev->border_width;
 		else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
 			m = c->mon;
-			if (!c->iswine) {
-				if (ev->value_mask & CWX) {
-					c->oldx = c->x;
-					c->x = m->mx + ev->x;
-				}
-				if (ev->value_mask & CWY) {
-					c->oldy = c->y;
-					c->y = m->my + ev->y;
-				}
-			}
+            if (ev->value_mask & CWX) {
+                c->oldx = c->x;
+                c->x = m->mx + ev->x;
+            }
+            if (ev->value_mask & CWY) {
+                c->oldy = c->y;
+                c->y = m->my + ev->y;
+            }
 			if (ev->value_mask & CWWidth) {
 				c->oldw = c->w;
 				c->w = ev->width;
@@ -724,8 +722,8 @@ configurerequest(XEvent *e)
 				c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
 			if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
 				configure(c);
-			if (ISVISIBLE(c))
-				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
+			if (ISVISIBLE(c) || c->x < 0)
+				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
 		} else
 			configure(c);
 	} else {
ltsdw commented

nvm it does resize, I wasn't seeing because the rectangle would still showing part of the last window visible before switching back. But didn't change anything, still black (except the part 160x24 that still showing part of the last visible window, but that is because I'm not compositing, if I enable composition the window will be entire black).

Its more easy to see if I enable compositing.

I have to press mod+f to this rectangle appear, otherwise it would be hided.

Screenshot-12-10-2021_17-32-20

resizing didn't work neither.

Screenshot-12-10-2021_17-32-41

Also tested the autoresize patch, didn't see any change neither.

At least 2 of 3 is working :).

I remember I had problems with some gfxbench tests too in the past, but since I can't test right now because of expired certified or something like that I can't tell if it solves the problem there too or was something else.

ltsdw commented

another update.

You mentioned that when you unchecked the wine's option 'allow the window manager to control the windows' it would be like you couldn't switch tags (but as you mentioned in fact it switchs tags, you couldn't see because the game window would cover the entire screen). With the Nova RO it happens the same thing but as the game always 'minimize' itself when it lose the focus, it will resize itself to 160x24, but instead of being black it shows part of the game, and click that little rectangle brings the game to front, though it's not possible to do much with the window, you can't send it to another tag, resize it, move it, kill it with mod+q (mod+c in my case), etc (well that's what we told wine to do so it's expected).

But as the window is not black anymore it's possible to play the thing. That's basically a workaround I think, if someone doesn't want to use the virtual desktop feature of wine, or the game doesn't have a borderless option or the person can't apply the steam patch. In my opinion though the better one is the virtual desktop.

that's a cool feature as you mentioned.

OK, I tried installing NovaRO directly via the .exe file but ran into an issue where I could not save the settings because of a missing .ini file or something like that.

So I tried again using Lutris and that worked.

The main things I noticed was that:

  • wine sends a configure notify event for the root window to change dimensions
  • wine sends configure requests for all other windows sending them to a negative x position
  • when the window loses focus it minimizes or goes into iconic state
  • the window manager is spammed with configure requests for the NovaRO Patcher

One problem with the configure requests (for Steam as well) is that the X and Y positions are absolute whereas in dwm the values are treated as relative to the monitor.

            if (ev->value_mask & CWX) {
                c->oldx = c->x;
                c->x = m->mx + ev->x;
            }
            if (ev->value_mask & CWY) {
                c->oldy = c->y;
                c->y = m->my + ev->y;
            }

This is not a problem if you have a single monitor, but if you have multiple and at different Y levels then windows may be placed out of view if you don't take the monitor x and y into account.

Maybe I will try letting programs (like wine) have full control and respect all configure requests and see if that makes a difference, but in principle that kind of sounds like a bad idea for a tiling window manager :)

Have you tried using Lutris for managing your games?

If you go into Lutris, right-click on a game > Configure > System options > Switch resolution to
then you can have Lutris handle the resolution switching, which to my surprise actually worked and NovoRO did not end up with a black screen or anything like that when moving to another tag and back. I still had to sort out the resolution when the game exited, but that can be sorted out relatively easy by running an xrandr command.

Lutris actually have a quite a few tricks up its sleeve to make games work, but also here I found that using a virtual desktop was the best solution to get NovoRO to behave simply because it doesn't change resolution and I can have it as a floating window or in full screen. This may depend on the game of course.

ltsdw commented

OK, I tried installing NovaRO directly via the .exe file but ran into an issue where I could not save the settings because of a missing .ini file or something like that.

Ah yes, you supposed to run Setup.exe before launching the you would probably need to run NovaWine.exe too, it kinda sort it out the anti-cheat or something like that, I don't know it works, @phaicm wrote it for the linux players.

If you would configure it manually this guide would help: NovaRO Wine Tutorial - Linux

So I tried again using Lutris and that worked.

generally that it's more easy.

* the window manager is spammed with configure requests for the NovaRO Patcher

I think that only happens when you launch the game through the "Nova Patcher.exe". Because it still opened while the game runs. Running through NovaRO.exe I think you would only see requests from the game.

One problem with the configure requests (for Steam as well) is that the X and Y positions are absolute whereas in dwm the values are treated as relative to the monitor.

            if (ev->value_mask & CWX) {
                c->oldx = c->x;
                c->x = m->mx + ev->x;
            }
            if (ev->value_mask & CWY) {
                c->oldy = c->y;
                c->y = m->my + ev->y;
            }

This is not a problem if you have a single monitor, but if you have multiple and at different Y levels then windows may be placed out of view if you don't take the monitor x and y into account.

Maybe I will try letting programs (like wine) have full control and respect all configure requests and see if that makes a difference, but in principle that kind of sounds like a bad idea for a tiling window manager :)

Yeah, I was thinking with myself if something like that wouldn't be possible.

Have you tried using Lutris for managing your games?

If you go into Lutris, right-click on a game > Configure > System options > Switch resolution to then you can have Lutris handle the resolution switching, which to my surprise actually worked and NovoRO did not end up with a black screen or anything like that when moving to another tag and back. I still had to sort out the resolution when the game exited, but that can be sorted out relatively easy by running an xrandr command.

Yes, I used to use Lutris for all my games, only after I needed to change my HDD and reinstall all things again that I got lazy and started running all through simple scripts.

ltsdw commented

As none of the other things I tested so far behaved as the NovaRO, I think it's a game specific thing.

I'll be closing this one now. Also thank you so much for your time and effort helping me out whit this ❤️.