> So, our problem is to harmonize it all.
OK, I'm looking more at this, to try and get it all resolved. The
amount of time I spend looking and thinking seems inversely
proportional to how easily and neatly it all seems to be resolvable.
Yay. So, the goal here is to check my understanding and see what
sorta end state we can get to[0]. At significant length, naturally.
There are several different parts, and several different signaling
mechanisms, that we need to consider in the EWMH bits. There is a
property (actually, several) which is set on a window when we first
see it, that tells us something about how it should initially be
handled. There is a message sent to us that tells us something to
change at arbitrary times during its life. And there's also a return
path where we [re]set the property on the window; this tells the
app[4] something about what we're doing, and also feeds back into the
first step here when e.g. restarting ctwm[5].
Firstly, the simplest case. We read the _NET_WM_WINDOW_TYPE when we
first see a window, and have defined OTP levels for Desktop, Dock, and
[everything else]. If we don't have a defined OTP for the window
otherwise[1], we use that as the initial seed instead. It never
changes after a window initially shows up. Done.
The remaining cases relate to the _NET_WM_STATE bits. The window
sends a STATE_FULLSCREEN message to tell us to fullscreen it, which we
handle by basically pretending f.fullscreenzoom was called. We then
(currently don't exactly[2]) set it in the property so the app can
tell we're doing that. And we follow the EWMH ruling that _FULLSCREEN
windows with focus get jacked up to the top OTP layer, and returned
back to its normal home when un-_FULLSCREEN'd. Also done. Yay, we've
got simple, clean, and pretty easy to declare "correct" answers.
So that just leaves the _STATE_{ABOVE,BELOW} pieces. And here is
where interpretation gets tougher, as EWMH doesn't really seem to
contemplate the ability to have windows in layers by other mechanisms.
EWMH says that _STATE_BELOW means it's below everything (except
_DESKTOP), and _STATE_ABOVE means it's alongside _DOCK[3] and above
everything else (except _FULLSCREEN). Now, as an _initial_ state when
we first see the window, these could be treated just like we do
desktop/dock above; we use them as defaults if the config doesn't tell
us something more specific.
But it's complicated by how these can also be set arbitrarily during
the window's lifetime; we can get a message at any time saying the
window should be (or not be) _ABOVE or _BELOW. What semantics could
that imply?
1) We could ignore it, unless the window is already sitting in 0
(x-ref [1]). That seems wrong; if we're gonna claim to support the
message, we should do something with it, since getting it means
we're supposed to change something.
2) We could use them as a "set priority" sort of statement. This can
have the odd effect that a window setting _ABOVE could _lower_ it,
or _BELOW could _raise_ it, depending on where it was previously.
That can't be right.
3) We could use them as a "change priority" sort of statement, so when
we see _ABOVE we shift it up from where it otherwise was, etc.
This leads to things that contradict the spec; e.g., a window was
at -3, we define _ABOVE -> "+= 2"; now the window is _ABOVE, but is
_not_ stacked above "normal" windows since it's still at an
effective -1.
4) We could try and do some weird combination of changing unless we'd
have to set to get in the right place, like _ABOVE ->
"min(1,prev+2)" and so on. That's awful special magic, which is
bad for code and bad for predictability.
I rule out (4) pretty quickly and certainly. And I tend to do so to
(1) as well. So that leaves (2) and (3) as useful options. Either of
them require us to break _some_ expectation and consistency, and they
seem exhaustive; I don't see a 5th choice to add to the list.
Currently I lean slightly (3).
There's the further complication that we do (and should) also set
_ABOVE/_BELOW in the property on the window to signal to the
app[4] where it is. We currently do that via essentially "(pri >
0) ? _ABOVE : _BELOW", which is sensible. Except, now we're in
tricky double-apply territory, because that message we send to the
application can also be taken as a message the application is
sending to _US_ when e.g. restarting ctwm. I take a window and
config it to a priority of 1. Since it's above the middle, we set
_ABOVE in its property, which lets the application know it's above
the middle. Then we restart, it gets config'd to 1 like normal,
except now we also see _ABOVE in its property, which we take to
mean "+2", so now it winds up at 3!
So we have to come up with extra magic to be able to tell the
difference between "has _ABOVE set because at some point the app
asked to be _ABOVE" and "has _ABOVE set because config/user action
set OTP to something positive and so we set it to inform the app"
(and similarly for _BELOW). Ugh. Gremlins. [5]
So far I'm on a regular schedule; about every half hour of thinking
and trying scenarios, I change my mind on what the least bad choices
are. I think I have at least twice just in writing this email. I'm
hoping somebody has a good clean answer...
[0] Statements of the We Do X form should generally be read as
aspirational (what we should be/be moving to doing) rather than
explanatory (what we're doing now). The lack of doing things as
described now is why we're here in the first place :)
[1] We can't see the difference between "no priority requested, so set
to <default>" and "priority explicitly set to <default>". I'm
intending to continue ignoring it until it comes up.
[2] Bug. I think. There are a few nearby related ones too. I think.
[3] Further tricksy; the spec says "_DOCK (unless they have state
_BELOW)", which means if something is both _DOCK and _BELOW it
doesn't go in the _DOCK level. It doesn't say whether that means
"_DOCK and _BELOW cancel each other out, so it's <normal>", or
"_BELOW always goes in the _BELOW level, whether or not _DOCK is
there too"; the latter seems the most self-consistent reading,
considering how it seems like what it wants you to do if _DOCK and
_ABOVE are both set too.
[4] Well, actually, to the app itself, or other things like external
minimaps or $DEITY knows what else, that use EWMH-specified
properties to understand how the desktop is setup. That's what
EWMH is for, after all.
[5] I sorta feel like this is a bug in EWMH, conflating the app->WM
signaling mechanism with the WM->app(s) one...