We could just pass a data offset as part of server requests that affect or query current desktop.
This implies the existence of some shared memory that encompasses such desktops, where each desktop can be located at some "data offset."
This leads to four[^5th] sub-problems, which IMHO have minimal impact in my original proposal of "ref-counted mappings:"
1. What's the scope of the shared memory?
1. **The scope of the shared memory is Winstation-wide:** This sounds like the most intuitive choice to me, since a desktop has exactly one parent Winstation at any time. Handling `SetProcessWindowStation` will need to get a little more complicated, though.
2. **The scope of the shared memory is wineprefix-wide:** This will make the shared memory management more straightforward, but may end up bloating the shared memory for *all* processes whenever some sandbox-based application tries to create a new station.
2. How many desktops can fit in the initial size of the shared memory?
1. **Just one:** This is the least bloated choice, since most applications (including the `wineboot` dialog) needs just one desktop.
2. **More than one:** This will allow us to delay the 3rd and 4th problem when handling multiple desktops, but will lead to more bloat.
3. Can the shared memory be resized after creation?
1. **The size is fixed:** This means that we cannot use the desktop shared memory when the number of desktops exceed the certain threshold. The CreateDesktop[^createdesktop] documentation states that the "number of desktops that can be created is limited by the size of the system desktop heap," although I'm not sure if the heap is Winstation-wide or system-wide.
2. **The size is variable:** This allows us to delay the 4th problem until when we run out of the host memory.
4. What if we run out of shared memory space?
1. **Fail desktop creation:** Simplest solution, but may lead to regression in existing apps (e.g., Win32 sandboxed apps) if the shared memory is fixed and limited in size (e.g., just one desktop).
2. **Don't fail desktop creation:** This way, we'll have to retain the current desktop-related querying server calls for fallback, which may be additional maintenance burden.
Ref-counted mappings avoid these problems entirely, by making each mapping local to the specific desktop object.
And yes, there is an argument to use a different mapping for more-or-less thread-specific data,
Meanwhile, ref-counted mappings do not rely on thread-specific mappings; multiple threads can share the same mapping (the refcount merely has to be incremented).
but desktops are global objects.
I believe that the ambiguity of the word _global_ was the source of confusion. "Global" can mean two things:
1. The object being described is associated with some *broader* scope that subsumes the *immediate* scope in context. This matches the dictionary definition. For example, a C global variable is associated with the *program* scope, which subsumes the *scope of a translation unit* it is defined in.
2. The object is part of some ambient, implicit environment. For example, [ambient authority] is used for Unix/NT APIs that need to check for access permissions, and thread-local variables can be used as implicit parameters to functions.
I guess that the meaning was not easily disambiguated since the notion of "broader" and "immediate" scope were not clearly agreed (or thought to be agreed) upon, and the latter does not imply the former. I could be wrong, though, so please ignore it if it was not the case.
[^5th]: There's actually the 5th problem, which is a bit theoretical: a process that is given access to the entire shared memory can read the state of a desktop that the process has no access to. Wine is not a security boundary, so let's ignore it. [^createdesktop]: [CreateDesktopA function (winuser.h) - Win32 apps | Microsoft Learn](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-creat...)
[ambient authority]: https://en.wikipedia.org/wiki/Ambient_authority