Skip to content

Conversation

@titouv
Copy link

@titouv titouv commented Jul 8, 2025

Goal

The default app switcher with Command + Space in macOS 26 Tahoe uses a liquid look that matches the rest of the interface

This PR is here to convert the UI to use the new Liquid Glass design system of macOS 26 Tahoe

Here are the docs from Apple for Adopting Liquid Glass

Todo

  • Support build with conditional Liquid Glass use, with fallback to the previous behavior on previous macOS versions
  • Adapt the rest of the interface settings, windows, menu bar, etc., to support Liquid Glass

Note

I saw that you were looking for someone to take over this project, I think I can help. Maybe this PR can be kind of a test

Images

Here are some images comparing versions in white and dark mode:

Current look
dark-preview-og
white-preview-og

Liquid Glass support look (this version of the PR, look may change)
dark-preview
white-preview

Comparison
dark-compare
white-compare

) != nil
// ScreenCaptureKit is the only method to check screen recording permissions from macOS 12.0 onwards.
// This function is only called if macOS 12.0 or later, based on the `detectScreenRecordingIsGranted` check.
let semaphore = DispatchSemaphore(value: 0)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why we use a semaphore here. This method is always called from the main thread, with non-concurrent calls, isn't it? Also, even if the calls were concurrent, is there an issue calling SCShareableContent.getWithCompletionHandler concurrently?

private static func detectScreenRecordingIsGranted() -> PermissionStatus {
if #available(macOS 10.15, *) {
// ScreenCaptureKit is available from macOS 12.0
if #available(macOS 12.0, *) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably have this change to the Screen Sharing permission check, in a separate Merge Request. It is unrelated to the goal of this current MR: Adopting Liquid Glass.

class RunningApplicationsEvents {
private static var appsObserver: NSKeyValueObservation!
private static var previousValueOfRunningApps: Set<NSRunningApplication>!
private static let appsQueue = DispatchQueue(label: "RunningApplicationsEvents.appsQueue")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused by the changes in this file. What is the issue being addressed here?

class PreviewPanel: NSPanel {
private let previewView = LightImageView()
private let borderView = BorderView()
private let visualEffectView: NSView = {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure to understand why the Preview Panel is changed by this MR. Preview Panel shows a 1-to-1 screenshot of the window to preview. There is no blurry background like the main panel for example

makeKeyAndOrderFront(nil)
MouseEvents.toggle(true)
thumbnailsView.scrollView.flashScrollers()
// thumbnailsView.scrollView.flashScrollers()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to remove this? I can't find the connection to the MR's goal

if #available(macOS 11.0, *) { toolbarStyle = .preference }
toolbar!.displayMode = .iconAndLabel
toolbar!.showsBaselineSeparator = true
// toolbar!.showsBaselineSeparator = true
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to remove this? I can't find the connection to the MR's goal

item.image = NSImage.initCopy(id)
item.image!.isTemplate = true
item.maxSize = NSSize(width: 22, height: 22)
// Removed the line: item.maxSize = NSSize(width: 22, height: 22)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to remove this? I can't find the connection to the MR's goal

@lwouis
Copy link
Owner

lwouis commented Jul 10, 2025

Hi,

Thank you for sharing this MR. Tahoe is due this fall. Until then, we won't be able to change anything. It's common for Apple to make many changes during the Beta. We always wait for the Betas to end to make any change to AltTab. Once things are clear, and API changes are stable.

Let's revisit this MR then. I'll have to get familiar with the API changes. I see many changes. It's a bit scary to see so many changes, that could break the experience for users on older macOS, and in specific situations like Dark Mode, etc. Lots of QA is required to not break things with such an MR. We have to be very cautious.

Thank you

@titouv
Copy link
Author

titouv commented Jul 16, 2025

Hi,

I have modified the PR to include only the changes necessary for its goal. I apologize for the unnecessary changes you had to review while I was exploring how to achieve the PR goal.

The only unrelated changes I couldn't remove while implementing these changes in Xcode 26 were in alt-tab-macos.xcodeproj/project.pbxproj (which blocked compilation).

This PR adds a conditional change that uses the new NSGlassEffectView on macOS version 26 and later. It falls back to the current app-switcher version in AltTab for older macOS versions (which uses NSVisualEffectView).

And of course, this PR includes proposed changes that I didn't expect you to approve until the full release of macOS Tahoe. It's just proposed changes

Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants