alt-tab-macos icon indicating copy to clipboard operation
alt-tab-macos copied to clipboard

Starting with macOS 12.2, AltTab only grabs windows in active spaces

Open skyzyx opened this issue 3 years ago • 39 comments

Describe the bug

  • I work with 2 monitors
  • I work almost exclusively in full-screen mode

I updated to macOS 12.2 Beta (21D5039d) this morning, and since then, AltTab only grabs the front-most full-screen app window from each of my displays — ignoring the full-screen windows that are not front-most.

I know that the full-screen support is buggy because this app has to use private APIs, etc., but I wanted to bring this situation to the attention of the developers as a known issue.

Usually when AltTab is missing windows, I can quit and re-launch the app to get it to pick up the current state of my environment. However, even this action no longer works as of this morning's macOS beta update.

Screenshots / video

http://s3.ryanparman.com.s3.amazonaws.com/alttab-bug-1.mp4

skyzyx avatar Jan 13 '22 19:01 skyzyx

Seeing the same on macOS 12.2 (21D49), the production version of macOS 12.2.

dnivi3 avatar Jan 28 '22 10:01 dnivi3

likely related to https://github.com/kasper/phoenix/issues/289 and https://github.com/ianyh/Amethyst/issues/1192

kaatt avatar Jan 29 '22 18:01 kaatt

~~Looks like Amethyst has fixed this in https://github.com/ianyh/Amethyst/pull/1184~~

dnivi3 avatar Feb 02 '22 15:02 dnivi3

@dnivi3 the code change you linked to is this:

image

Changing the order remove -> add to add -> remove. AltTab already does add -> remove:

image

lwouis avatar Feb 02 '22 23:02 lwouis

@lwouis yeah, I realised my layman non-technical understanding of this isn't helpful. Is there any I can help or contribute towards this getting fixed?

dnivi3 avatar Feb 03 '22 16:02 dnivi3

@dnivi3 i'm afraid only code contributions would help. Please see https://github.com/lwouis/alt-tab-macos/issues/1179

lwouis avatar Feb 03 '22 16:02 lwouis

Related: #1351

lwouis avatar Feb 04 '22 14:02 lwouis

Just to add the datapoint, the issue persists in the newly released macOS 12.3.

stevetodd avatar Mar 14 '22 21:03 stevetodd

This behaviour is repeatable. I have 3 desktops. When restarting alt-tab, windows from the active one get detected correctly, the switcher works just as expected, while on the other desktops only the active window is shown in the switcher. Restarting the apps/reopening the windows causes them to be shown in the switcher. Macos 12.3.1 here.

radaczynski avatar Apr 09 '22 06:04 radaczynski

Allowing screen recording permissions to the app should fix this.

kaatt avatar Apr 09 '22 07:04 kaatt

@kaatt - were you refering to my comment? It does not fix this issue - AltTab had the permission to record screen all the time. Windows from the current desktop are detected just fine after restart of AltTab, but on other desktops only one window is detected (+ all the windows that are created after AltTab is launched).

radaczynski avatar Apr 09 '22 10:04 radaczynski

It seems that we could simply replace the call to CGSAddWindowsToSpaces with a call to CGSMoveWindowsToManagedSpace.

Can anyone confirm this would work?

lwouis avatar Apr 28 '22 17:04 lwouis

I experimented with replacing CGSAddWindowsToSpaces with CGSMoveWindowsToManagedSpace. It's not a 1-to-1 replacement. It doesn't move fullscreen windows. It successfully moves regular windows, and moves them back, but it doesn't do anything for fullscreen windows, thus AltTab doesn't see them.

lwouis avatar May 07 '22 07:05 lwouis

@lwouis glad to hear it solves for regular windows, but shame with fullscreen ones. Selfishly, this solves for my use cases. Is there a branch I can build from to test this?

dnivi3 avatar May 07 '22 18:05 dnivi3

Is there a branch I can build from to test this?

i'm sorry, there isn't

lwouis avatar May 08 '22 01:05 lwouis

Interesting data point: https://github.com/lwouis/alt-tab-macos/issues/1088#issuecomment-1054595185

i wonder if HS works on macOS 12.3+. If it can still work it means they have a robust trick to deal with windows in other Spaces

lwouis avatar May 21 '22 06:05 lwouis

Interesting data point: #1088 (comment)

i wonder if HS works on macOS 12.3+. If it can still work it means they have a robust trick to deal with windows in other Spaces

@lwouis I can confirm that HyperSwitch works just fine on macOS Monterey 12.4 (21F79) and is grabbing any and all windows, including in other spaces. This is with the caveat that the window previews sometime just return blank, but that is a problem that HS has had for a long time.

dnivi3 avatar May 24 '22 07:05 dnivi3

Today I wanted to decompile the Skylight framework on 12.4. I went in my 12.4 VM, and got surprised that I couldn't find it at /System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight:

image

Furthermore, I thought "how can AltTab work if Skylight is missing?". I tried to run AltTab, and it seems to work fine.

But as I was testing AltTab, I noticed that the Spaces at the top of the screen, in Mission Control, look different from my main machine which is still on macOS 10.15:

10.15 12.4
image image

Anyone knows what's going on here? Why is Skylight not at the usual path, and did Apple change the UI for Mission Control?

lwouis avatar May 28 '22 06:05 lwouis

@lwouis

Why is Skylight not at the usual path

From the Big Sur release notes:

New in macOS Big Sur 11.0.1, the system ships with a built-in dynamic linker cache of all system-provided libraries. As part of this change, copies of dynamic libraries are no longer present on the filesystem. Code that attempts to check for dynamic library presence by looking for a file at a path or enumerating a directory will fail. Instead, check for library presence by attempting to dlopen() the path, which will correctly check for the library in the cache.

Hopper has a function to read from the DYLD shared cache.

did Apple change the UI for Mission Control

Not to my knowledge. On your screenshot, it looks like the transparency was disabled.

decodism avatar May 28 '22 14:05 decodism

Hopper has a function to read from the DYLD shared cache.

I googled that, and it's a pretty new feature in Hopper apparently. My version didn't support it for instance. I'm constantly amazed at how fast things get deprecated these days. Constant march forward :/

On your screenshot, it looks like the transparency was disabled

But also, the Spaces "thumbnails" at the top are squarish now instead of rectangles. And they don't show the windows in each Space. Is that just on that VM, or it's like this now?

lwouis avatar May 28 '22 15:05 lwouis

My version didn't support it for instance

It seems that there are third party tools to extract from the cache.

the Spaces "thumbnails" at the top are squarish now instead of rectangles

It looks like they are the same aspect ratio as your screenshot.

they don't show the windows in each Space

It's your VM.

decodism avatar May 28 '22 20:05 decodism

@decodism you seem to be knowledgeable with decompiling. Could you please help me? I would like to investigate what happened to CGSAddWindowsToSpaces on macOS 12.2+, and why it stopped working.

macOS 10.15

On macOS 10.15, I see this proc, and it seems to lead to a mach message, to WindowServer I imagine? So there is not much implementation, it's just messaging. Maybe I'm not reading it correctly though?

image image image

macOS 12.4

On macOS 12.4, I used the new Hopper feature for DYLD shared cache. But that only shows me strings which match, not procs. I don't know how to dig further with these things.

image image image

I have investigated a lot of alternative APIs to replace CGSAddWindowsToSpaces. Nothing seems to cut it and be a good replacement. I don't think any other big projects in the community which relied on it has found a successful replacement yet.

I was hoping maybe that if I could look into the internal of CGSAddWindowsToSpaces, I could bypass calling it, and instead maybe call a sub-function, or maybe even directly send raw mach messages to the WindowServer to emulate the old behavior. We already use this approach to focus windows.

Any help would be amazing here, and I'm quite out of my expertise zone, and I feel sad thinking that AltTab is broken for users of macOS 12.2+

lwouis avatar May 29 '22 10:05 lwouis

@lwouis CGS* functions are in SkyLight; they’ve been renamed from CGS* to SLS* (the CGS variants still work)

CGSConnectionRef contains a mach port; SLS functions communicate with some service (likely WindowServer) over the mach port, sending raw payloads. Payload kind is determined by DWORD at msg_hdr[0x14] (likely msgh_id).

WindowServer is itself implemented in SkyLight: WindowServer binary merely executes SLXServer entrypoint, which checks flags and re-spawns WindowServer as a daemon (in classic Unix style; no launchd involvement).

SLXServer seems to be a massive loop, it’s a switch statement with 383 cases.

Also, Objective-See has some RE work on WindowServer/SLS: https://objective-see.com/blog/blog_0x2C.html

You'll not be able to send raw mach messages to WindowServer because of entitlements - Apple has Skylight entitlements too only issued to official binaries.

I'm opening /System/Library/dyld/dyld_shared_cache_arm64e → Skylight in Hopper Screen Shot 2022-05-29 at 4 16 48 PM

and see transaction methods:

Screen Shot 2022-05-29 at 4 17 19 PM

Transaction methods may work but I've incorrect/partial headers for them:

#import <AppKit/AppKit.h>
typedef NSObject SLSTransaction;
typedef int SLSConnectionID;
typedef size_t SLSSpaceID;

int SLSMainConnectionID(void);

// SLSTransactionCreate returns <SLSTransaction [0x600002300ac0] cid: 493239, data: 0x109664000, size: 0, capacity: 16384, valid>
SLSTransaction* SLSTransactionCreate(SLSConnectionID cid);
int SLSTransactionCommit(SLSTransaction* txID, int unknown);

int SLSTransactionAddWindowToSpace(SLSTransaction* txID, CGWindowID window, SLSSpaceID space);
int SLSTransactionRemoveWindowFromSpace(SLSTransaction* txID, CGWindowID window, SLSSpaceID space);
int SLSTransactionRemoveWindowFromSpaces(SLSTransaction* txID, CGWindowID window, CFArrayRef spaces);
int SLSTransactionMoveWindowsToManagedSpace(SLSTransaction* txID, CFArrayRef windows, SLSSpaceID space);
int SLSTransactionAddWindowToSpaceAndRemoveFromSpaces(SLSTransaction* txID, CGWindowID window_id, SLSSpaceID add_space_id, CFArrayRef remove_space_ids);

kaatt avatar May 29 '22 10:05 kaatt

SLS functions are the user-facing API of the WindowServer; they are essentially helper functions. The actual implementation is also in the SkyLight framework, with an X prefix, which is what the server ends up executing upon receiving a mach_msg of said type.

Screenshot 2022-05-29 at 15 56 51

I've tested some of the transaction related functions mentioned above before, and they work fine, but not sure if they can get around the issue that the non-transactional-version have in 12.2 and newer.

koekeishiya avatar May 29 '22 14:05 koekeishiya

What headers/call incantation did you try for the transaction functions? I can test out on 12.3+

kaatt avatar May 29 '22 14:05 kaatt

extern CFTypeRef SLSTransactionCreate(int cid);
extern CGError SLSTransactionCommit(CFTypeRef transaction, int unknown); // passed 0 as unknown
extern CGError SLSTransactionMoveWindowsToManagedSpace(CFTypeRef transaction, CFArrayRef window_list, uint64_t sid);
extern CGError SLSTransactionAddWindowToSpace(CFTypeRef transaction, uint32_t wid, uint64_t sid);
extern CGError SLSTransactionRemoveWindowFromSpace(CFTypeRef transaction, uint32_t wid, uint64_t sid);

koekeishiya avatar May 29 '22 14:05 koekeishiya

@kaatt I didn't get the path from the search matches in Hopper, to getting the list of methods here:

image

How did the search in Hopper reveal to you the existence of SLSTransactionAddWindowToSpace for instance?

@koekeishiya

On macOS 10.15, in the __XAddWindowsToSpaces function you mentioned, it seems to call a function called _PKGSpacesAddWindowsWithConnection internally to do the work:

image

This one has the PKG prefix instead of CGS/SLS. Have you investigated around that? Maybe that PKG function is still preserved on 12.2+ as it's more internal? Maybe there is generally interesting features within the PKG functions family?

And also, how do you investigate on macOS 12.2+? There is no __XAddWindowsToSpaces there, so it seems they make big changes to the SLS internals.

lwouis avatar May 29 '22 14:05 lwouis

How did the search in Hopper reveal to you the existence of SLSTransactionAddWindowToSpace for instance?

I was probably searching for SLSTransaction. I also looked into /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/System/Library/PrivateFrameworks/SkyLight.framework/SkyLight.tbd

@koekeishiya your headers look similar to mine. Doesn't look like any SLSTransaction methods are working for me on 12.4. Even tried SLSTransactionMoveWindowsToManagedSpace since SLSMoveWindowsToManagedSpace is working:

typedef CFTypeRef SLSTransaction;

SLSTransaction* SLSTransactionCreate(SLSConnectionID cid);
int SLSTransactionCommit(SLSTransaction* txID, int unknown);
int SLSTransactionMoveWindowsToManagedSpace(SLSTransaction* txID, CFArrayRef window_list, SLSSpaceID sid);

tx = SLSTransactionCreate(connection)
SLSTransactionMoveWindowsToManagedSpace(tx, [fromSpace], toSpace)
SLSTransactionCommit(tx, 0)

kaatt avatar May 29 '22 14:05 kaatt

This one has the PKG prefix instead of CGS/SLS. Have you investigated around that? Maybe that PKG function is still preserved on 12.2+ as it's more internal? Maybe there is generally interesting features within the PKG functions family?

I found this string inside SkyLight.framework: SkyLight/Server/Packages/PKGSpace.c. So it seems they created packages inside SkyLight, and PKG may just be the way they are separating those packages. Here PKGSpace may be where they deal with Spaces.

Furthermore, inside the PKG call I mentioned above, they call ___WSWorkspacesAddWindowsWithConnection_block_invoke which is probably WS = WindowServer

lwouis avatar May 30 '22 16:05 lwouis

@lwouis

you seem to be knowledgeable with decompiling

Sorry but I am not.

decodism avatar May 31 '22 12:05 decodism