Why would my application fail to "unhide" (show)

cocoa, macos, objective-c

Solution

After working with Apple Engineers in AppKit, a solution has been found.

In our application, we "flush" the event queue for various reasons via this method:

NSEvent* lastEvent = [NSEvent otherEventWithType:NSPeriodic
                                            location:NSMakePoint(0.0, 0.0)
                                            modifierFlags:0
                                           timestamp:[NSDate timeIntervalSinceReferenceDate]
                                        windowNumber:1
                                             context:NULL
                                             subtype:0
                                               data1:0
                                               data2:0];

    [[NSApplication sharedApplication] discardEventsMatchingMask:NSAnyEventMask beforeEvent:lastEvent];

The Mac OS X systems sends a "Show" event to the application on launch. Our flush function, which is called upon launch, effectively removes that event from the queue, but the core process part of Mac OS X has its own internal queue that keeps track of show and hide and other types of event types so that it doesn't send repeated messages. (I'll be investigating if this flush is really necessary)

The problem is that when `discardEventsMatchingMask:NSAnyEventMask` is called on every event, it clears out the events for the application, but doesn't respond to the core process's show event and so core process thinks that it doesn't need to send the show event again.

The solution to this particular problem is to be more selective in which events are cleared. With my new implementation, I do not clear events that will be sent by core process.

/* a bug in Apple's Core Process group forces me to isolate which events should be cleared as
        show|hide|activate|deactivate messages get sent by Core Process, but are not _marked_ as
     handled and so Core Process thinks that the "Show" event is still pending and will not send
     another */

    NSEvent* lastEvent = [NSEvent otherEventWithType:NSPeriodic
                                            location:NSMakePoint(0.0, 0.0)
                                            modifierFlags:0
                                           timestamp:[NSDate timeIntervalSinceReferenceDate]
                                        windowNumber:1
                                             context:NULL
                                             subtype:0
                                               data1:0
                                               data2:0];


    NSEventMask maskForEventsToDiscard = (NSPeriodic |
                                          NSLeftMouseDown |
                                          NSLeftMouseUp |
                                          NSMouseMoved |
                                          NSLeftMouseDragged |
                                          NSRightMouseDragged |
                                          NSMouseEntered |
                                          NSMouseExited |
                                          NSKeyDown |
                                          NSOtherMouseDown |
                                          NSOtherMouseUp |
                                          NSOtherMouseDragged);

    [[NSApplication sharedApplication] discardEventsMatchingMask:maskForEventsToDiscard
                                                     beforeEvent:lastEvent];

As the "show" event is not cleared on launch, show and hide work now!

A special thanks to KF of Apple!

Problem

I'm investigating an issue on Mac OS X 10.8, and I am at the end of my wits. I'm not sure what to do next. The application is 32 bit and has some Carbon calls in it. Here is the problem: when I right-click the application icon in the dock, select the menu item "Hide", then, after the application has hidden, I select the "Show" menu item from the dock, and the problem occurs: the main document window does not appear (the palettes and menu do appear). At this point, the "Show" menu item does not change to "Hide" even though the palettes have become visible. I expect that the main document window becomes visible when I select "Show" from the application dock menu. Just like other Mac applications. When it fails, I can make the main document window visible again if I use the App Exposé gesture on the Trackpad to show the document windows and select the main document window. It works fine if I launch the application from the Terminal or from Xcode. The document window shows and the dock menu item for my application changes to "Hide" as expected. I launch the app from the terminal by navigating to the parent directory of the *.app, and typing `./MyApp.app/Contents/MacOS/MyApp`. It fails when I have launched by double-clicking the application icon in the Finder. My log messages from the application delegate's unhide functions appear when the application is launched from the Terminal and Xcode, but not when launched from the Finder. ``` – applicationWillUnhide: – applicationDidUnhide: ``` I have looked in the Console.app for any exceptions thrown (or any other messages). There are none. Update: To try and debug this, I launched from the Finder, and used Xcode to attach to the process. I had suspected that an exception was being thrown and when I tested it using Xcode's "Exception Breakpoint" as well as putting a breakpoint on objc_exception_throw (just in case), it dd not break when I hide or "show" the application. I then thought that I needed to prove that the `NSApplicationWillUnhideNotification` and `NSApplicationDidUnhideNotification` were being sent out. They are when I launch from Xcode or from the Terminal, but if I launch from the Finder, they are not. I verified this by, after attaching Xcode to the application, putting a breakpoint via "Add Symbolic Breakpoint" for: ``` -[NSNotificationCenter postNotificationName:object:userInfo] ``` And then, I added a Debugger Command: "po * (id*) ($esp+12)" to print out the first parameter to that selector (the notification name). Which I found in an answer posted here, in StackOverflow. Using that, I can see the notifications that are posted after I choose the "Show" menu item. When I launch from Xcode/Terminal, I see the following notifications posted: ``` NSApplicationWillUpdateNotification, NSWindowDidUpdateNotification, NSApplicationDidUpdateNotification, ** NSApplicationWillUnhideNotification **, ..., ** NSApplicationDidUnhideNotification **, ..., NSApplicationWillBecomeActiveNotification, ... ``` `NSApplicationWillUnhideNotification` is posted in this situation. When I launch from the Finder, I see the following notifications are posted: ``` NSApplicationWillUpdateNotification, NSWindowDidUpdateNotification, NSApplicationDidUpdateNotification, NSApplicationWillBecomeActiveNotification, ... ``` It does not send the `NSApplicationWillUnhideNotification`. Also, when I select "Show" from the Xcode-launched version, I see `-[NSApplication _doUnhideWithoutActivation]` in the backtrace. Putting a breakpoint for that function when I attach to the Finder-launched version does not result in a break when I select "Show". Then, I thought to myself, perhaps the application thinks that it is not hidden. I have a idle event handler, so from there I printed out the value of `[[NSApplication sharedApplicaton] isHidden]` while I Hide and "Show" the application. For the problem situation, when the application is not hidden, it prints out `NO` for `isHidden`. When the application becomes hidden, it prints out `YES` for `isHidden`. When I select "Show" from the dock menu, it continues to print out `NO` for `isHidden`. It knows that it is hidden, but part of the application has been activated: the `NSPanels` and the `NSMenuBar` appear. I can see the document window by entering into the application Exposé mode, and clicking the document window will make the window appear, but the dock menu item is still "Show" and `isHidden` is still `YES`. The unhide mechanism works fine for a sample application, so I'm pretty sure that our code is doing something to shut this off. I wonder what would be different between an application launched from the Terminal compared to an application launched from the Finder? I had the application log the environment variables using `[[NSProcessInfo processInfo] environment]` and the only real difference I could see is that PWD exists in the variables for the Terminal application: I cannot see anything in our code that makes use of that. I had the application log the command-line arguments via `[[NSProcessInfo processInfo] arguments]`, and I do see something different in the Finder-launched version. Both the Terminal and Finder launched versions list the path of the binary as the first argument; the Finder also lists a second paramter, "-psn_0_89445704". I have read online that it is something that Mac OS X adds to command-line arguments for GUI applications and I see it added to the command-line arguments for other applications that Hide and Show properly from the Dock menu. Do you have any other thoughts that may lead me further towards solving this mystery? Thanks for any help or suggestions!

Original source

Related problems