4

When a SwiftUI app is minimized and the dock icon is clicked. The app won't be deminimized and put to the front just like other apps do.

import SwiftUI

@main
struct MyApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            MainView()
        }
    }
}

class AppDelegate: NSObject, NSApplicationDelegate {
    func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
        // THIS IS NEVER CALLED!!!
        if !flag {
            for window: AnyObject in sender.windows {
                window.makeKeyAndOrderFront(self)
            }
        }
        
        return true
    }
}

Other delegate methods like applicationDidLaunch do get called so its not a linking issue. Does anyone know how to get this to work?

Comment on Asperi enter image description here

Mark
  • 16,906
  • 20
  • 84
  • 117
  • I use Xcode Version 13.3.1, macOS 12.3.1 so about the same. I choose Xcode > File > New Project. Choose macOS tab. App (template). Name the project 'Sample'. Then build and run. When I minimize the app and then click on the App Icon, nothing happens. – Mark Apr 17 '22 at 18:36
  • Sorry I see the window does come to the front just not restored when minimized. I should clarify in my question, my apologies. – Mark Apr 17 '22 at 18:40
  • It may be a bug looking at this report: https://github.com/feedback-assistant/reports/issues/246 – Mark Apr 17 '22 at 18:50

5 Answers5

3

2022

Will display app in case of it is hidden or minimized both!

func applicationDidBecomeActive(_ notification: Notification) {
    NSApp.unhide(self)
    
    if let wnd = NSApp.windows.first {
        wnd.makeKeyAndOrderFront(self)
        wnd.setIsVisible(true)
    }
}
Andrew_STOP_RU_WAR_IN_UA
  • 9,318
  • 5
  • 65
  • 101
1

Use did become active callback, tested as worked with Xcode 13.3 / macOS 12.2.1

Like,

func applicationDidBecomeActive(_ notification: Notification) {
    if NSApp.windows.compactMap({ $0.isVisible ? Optional(true) : nil }).isEmpty {
         NSApp.windows.first?.makeKeyAndOrderFront(self)
    }
}

Test module in project is here

Note: in case of active application the only application(Will/Did)Update are called in click Dock icon.

Asperi
  • 228,894
  • 20
  • 464
  • 690
  • Hi Asperi. If it works on your computer it might be a bug in MacOS Monterey 12.3.1 (21E258) or Xcode Version 13.3.1 (13E500a), because I run the exact code you shared and it did not work. Unfortunately I am not able to share the image in the comment so I placed it in my question. Please take a look. When I click on the app icon it does not get deminimized as you can see. – Mark Apr 24 '22 at 09:30
  • Hmm... I might imagined different scenario, because as I see you don't switch app after window minimised. Try instead with `applicationDidUpdate` callback. – Asperi Apr 24 '22 at 09:36
  • applicationDidUpdate will fire constantly meaning it will never deminimize. What did work was with the delegate method `applicationDidBecomeActive`. But the app needed to resign first in order for it to work so it's not optimal, but at least a start. – Mark Apr 25 '22 at 09:18
  • I just encountered this bug, how fancy of Apple. – Klajd Deda Aug 04 '22 at 15:09
  • rdar://FB11057969 filed – Klajd Deda Aug 04 '22 at 15:31
1

In delegate methods that get called when clicking on the dock icon try calling

NSApp.activate(ignoringOtherApps: true)

This should bring your app to the foreground

Suyash Medhavi
  • 1,135
  • 6
  • 18
  • Did this not solve my problem. I tried every app delegate and none is called when pressing on the dock icon, but even when I put this on a method which get called in other situations this won't put the window in front. Thanks for your comment tho. – Mark Apr 25 '22 at 09:16
0

This is a temporary work around that works for me

class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
    // disable tabs ...
    NSWindow.allowsAutomaticWindowTabbing = false
}

// Quit if the main window is closed
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
    BzLogger[Self.self].info("")
    return true
}

func applicationDidUpdate(_ notification: Notification) {
    if NSApplication.shared.mainWindow == nil,
       let event = NSApplication.shared.currentEvent {
        if event.type == .systemDefined {
            // FIX-ME: kdeda
            // This is hack since Apple broke this whole thing on macOS
            
            // BzLogger[Self.self].info("NSApplication.shared.currentEvent: \(event)")
            // BzLogger[Self.self].info("NSApplication.shared.currentEvent: \(event.subtype)")
            // BzLogger[Self.self].info("NSApplication.shared.pressedMouseButtons: \(NSEvent.pressedMouseButtons)")
            // BzLogger[Self.self].info("NSApplication.shared.isActive: \(NSApplication.shared.isActive)")
            if NSEvent.pressedMouseButtons == 1 {
                // mouse down, maybe there is a better way
                if NSApp.windows.compactMap({ $0.isVisible ? Optional(true) : nil }).isEmpty {
                    NSApp.windows.first?.makeKeyAndOrderFront(self)
                }
            }
        }
    }
}

}

Klajd Deda
  • 355
  • 2
  • 7
0

I found this solution.

In your @main entry class App add this property:

@NSApplicationDelegateAdaptor var appDelegate: AppDelegate

It now should looks like this:

import SwiftUI

@main
struct TestApp: App {
    @NSApplicationDelegateAdaptor var appDelegate: AppDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

Now, create the AppDelegate class (you can create a new separate AppDelegate.swift file or just continue typing after the App struct closed:

class AppDelegate: NSObject, NSApplicationDelegate {
    func applicationDidChangeOcclusionState(_ notification: Notification) {
        if let window = NSApp.windows.first, window.isMiniaturized {
            NSApp.hide(self)
        }
    }
    
    func applicationDidBecomeActive(_ notification: Notification) {
        NSApp.windows.first?.makeKeyAndOrderFront(self)
    }
}

Now it is minimizing, maximizing, closing and reopening again as normal as other apps (ex. Safari, Mail, etc.).

This works perfectly on Monterey 12.4.

PowerBSD
  • 1
  • 1