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!
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!
This technique won't fit in a comment, but I might suggest getting up-close-and-personal with DTrace. I suggested in the comments above to subclass NSWindow and put NSLog statements in the -orderOut:, etc. methods. However, using DTrace for this would likely be far more effective - although, as you will see, it will still be useful to know the address of the objects you will be observing - the upside is that you won't litter your code with a bunch of NSLog statements.
The simplest script might be:
#pragma D option quiet
objc$target:NSWindow:-orderOut?:entry
{
printf( "%30s %10s %x %x\n", probemod, probefunc, arg0, arg1 );
}
and would be called with the process id of the application by doing something like:
sudo dtrace -s dtrace_window.d -p9434
In this particular case, arg0 will contain the address of the window. Unfortunately, it is apparently non-trivial to obtain the title of the window or even the contents of a NSString from within DTrace, but may be worth the effort. I do have a question here and here to see if anyone knows to do either one of these things. (If you can get the title of window, you can set up a map from the address of the window to a string.)
It would be easy to attach probes to any and all methods, functions, etc. you think might be involved so you can try to "follow the event" to resolve this problem.
So, ultimately, I would suggest to just keep adding DTrace probes until something provides the required hint resolve this problem.
Related
Title quite much says it all.
In VB6, and in VBA/Access it was possible to hit break key, and jump into debug mode when using the msgbox() command.
Is there a way to do this in vb.net (desktop/winforms) applications?
Often, some code will toss up a dialog box, and it is rather nice then to jump into debug mode as a result of that message box having been displayed.
Edit
Ok, hitting pause button in most applications work, but in this application, when I hit pause, then I get this:
Edit two:
Ok, I have discovered the reason for this behavior. I have the application Frame work box un-checked. The reason for this is I did't want to specify the main application form as startup form, and I desired additional control over what occurs if the main startup form (that I don't specify) is closed. Thus, my main application form is launched via application.Run(my form)
It thus seems that due to starting the main form as a new separate application thread (which is the result of using application.Run(), then you can't use ctrl-break, or more common use/hit the pause button in the IDE to halt the code. Hitting pause will thus display that the application is running a main app thread, which indeed is the case since I use applicaiton.Run() to launch the main form from the classic and traditional Sub Main().
Edit 3
A way to fix this, and enable the pause key to work is to un-check in tools->debugging the [ ] Enable Just My Code. This will thus allow debug mode of the other "main" application thread.
Hmm. [CTRL][BREAK] clears the dialog box. However, clicking the pause button in the IDE will do what you want.
Alternatively, select Debug > Break All from the menu.
I'm working on a NSMenuBar application and another NSMenuBar app seems to influence the display behaviour of my application!? More precisely: Adobe's Creative Cloud Application. When I click on that (creative cloud) Icon, the popup-view appears. Afterwards, when I click on my StatusBar Icon, my Menu appears, BUT, all the NSMenuItem's that should be Enabled are suddenly Disabled, and not interactive anymore.
Some observations:
When I log the enabled-state of the NSMenuItem, it logs correctly as being Enabled, but it is clearly not displaying as enabled (see screenshot), and clicking on it simply closes the Menu without performing the associated action. I do the logging with the following code:
-(void)menuWillOpen:(NSMenu *)menu
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC),
dispatch_get_main_queue(),
^{
NSLog(#"preferences menu-item is enabled: %hhd",[self.preferenceMenuItem isEnabled]);
});
}
The NSMenu I use is set to setAutoenablesItems:NO.
Also, Adobe's Creative Cloud uses a popup-view. And when it is opened, It clearly hovers over the screen-real-estate that my NSMenu is using.
When I try to reproduce this with other NSMenuBar applications (e.g. Apple's Wifi or Bluetooth) it all works. No problem. Then again, those applications don't use Popover-views, and they don't completely overlap the space of my app.
Please see these screenshots as illustration:
Before
Malicious Creative Cloud
After
What Am I missing here? Apps should not be influencing each other like this right? I'm slowly but surely losing my mind over this. Any help MUCH appreciated! Thnx!!
I have found the solution to my own problem. So I hope I will help anybody else struggling with this.
I was using my main xib file menu (with the status-bar) and referenced that menu to open when clicking on the statusbar icon. This caused the app to get in focus and to display two times the same menu (although not open at the same time), one under the statusbar-icon as intended, and one on the left side next to the apple symbol. Whenever the statusbar-menu was somehow getting deactivated, the left menu was still working, as if the focus was shifted to that one.
For me the solution was to decouple my referenced menu from the xib's menu, by dragging it outside the parent-menu. It's weird because somehow it's not visible anymore in InterfaceBuilder, but it's definitely still there. See screenshots:
BEFORE:
AFTER:
I am learning Objective-C and programming applications for OS X. I want to write myself a simple notifier, which should work this way:
connect to website and check, if there is new content (I have that covered)
display window with action buttons like "ignore", "visit website" (this is also easy)
I thought, that I will add my app to startup and if there are no changes on the website - just terminate it. But the window with action buttons will pop up before application checks, if there is a new content and window will flash quickly. How do I prevent that?
Is there a better way to create something like this? For example instead of running my application during startup - running a daemon, that will check the website every 24 hours and then display the window? How can I do that?
Recently, I read Start Developing Mac Apps Today, so I might be still missing something obvious.
Select NSWindow and just turn off Visible At Launch.
If you want to show the window, do it manually as follows.
- (void)applicationWillFinishLaunching:(NSNotification *)notification {
/* Do whatever necessary before the window appears */
[window setIsVisible:YES];
}
Personally, I never have the Visible-At-Launch switch on.
I'm working on wrapping some Cocoa functionality in an Objective-C library that will be called from a cross-platform C library. One of my goals is to provide someone who does development in C on Linux with the ability to deploy to OSX without having to get into XCode, nib files, etc. I want them to be able to compile and link their code on OSX using the command line tools, and end up with a regular resizeable main window with the usual buttons and so on, an application menu and a dock icon that looks and behaves as expected, etc.
I'm working on OSX 10.8.5. I have XCode 5.0 installed. Here's my gcc --version output:
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.0 (clang-500.2.76) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix
I've figured out how to present a main window, how to set up the application menu, and various other things, programmatically, without using XCode or any nib or plist, but I've run into a problem with the dock icon.
I set a custom dock icon image by calling:
[NSApp setApplicationIconImage:dockImage];
When the user quits the app, the dock icon image reverts to something else (some kind of default application icon or view), briefly, before going away. How can I prevent that from happening without using XCode to create a nib or a plist?
I've tried setting the activation policy of NSApp to prohibitted in the app delegate's applicationShouldTerminate method, to try to hide the dock icon before this switch back occurs. That didn't help, it does hide the window and the dock icon, but the dock icon still switches back to the default icon, briefly, as part of the process of hiding. I confirmed this by returning NSTerminateLator, and confirming that setting the activation policy to prohibited does cause the dock and the icon to hide even though the app is not terminating, and not setting it leaves it unhidden.
I've tried subclassing NSApplication and overriding the setApplicationIconImage call. I have confirmed that it is being called a second time, by something other than my code (well, or not directly by my code, anyway), just before the program exits. I've tried preventing the second call to it from working by calling the super function the first time, but not the second time, and I've confirmed that code in that function can prevent my code from changing the application icon, but that didn't fix the problem. It still happens anyway, somehow.
I've also tried removing the application badge, like this:
[[window dockTile] setShowsApplicationBadge: NO];
just in case it was something to do with that, but that didn't work. The docs say that app badges are no longer relevant as of 10.6, but I was grasping at straws.
Being stumped on the programmatic front, I'm now trying to find out how to package an .app from scratch,without using XCode, and see if maybe I can create a plist from scratch that has a reference to application image in it. But a programmatic solution would be preferable, as I'd really like to minimize what goes into the OSX-specific packaging of a deployment.
Another possibility might be to use XCode once, to produce a very generic, bare-bones .app that my deployment scripts copy and alter.
Please don't shoot my question down as being "too broad" or "not constructive" or something like that. I realize I'm reinventing wheels that already exist in various forms, but there's no law against trying to build a better mouse trap, or just a different or even a worse one, for that matter. I realize I'm trying to fix a problem that a lot of people would consider inconsequential, but XCode-produced apps don't have this problem, and I really don't want the tools I'm creating to produce any user-visible artifacts like that. I'm not intending to diss Apple's tool chain or invite debate about whether or not what I'm pursuing should be pursued. I have a specific, technical problem that I'm looking for solution to that is within the constraints of my goals.
I'm writing a simple Cocoa Application, no core data or multiple document support. Running on a Mac Pro, OS X 10.6.6, Xcode 3.2.3.
I have reduced my application to the following code in my AppDelegate class:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
[openPanel runModal];
return;
}
From within the debugger, I will run my application. As expected a somewhat not-to-useful OpenPanel will appear. I will click Cancel and it will disappear. All this is as expected. When I click [Command + Q] to Quit the application, the UI will go away but the debugger will indicate that the application is still running (as does the console output).
Based upon all the information I'm reading, I should not have to do anything else in order for this to run right. I've downloaded several examples on the Open Panel's usage but most use the deprecated methods of opening modal giving additional information as parameters. FWIW, I tried those methods and am still seeing the same result.
One last item, when the Open dialog appears, just for an instant I see a message box asking me something to the extent if I want my application to receive incoming connections. The dialog quickly disappears. I don't know if that is part of my problem or not. [Update - this deals with my Firewall being turned on.]
Yes, I'm fairly new at Objective C but not at programming in general. Any words of wisdom is greatly appreciated!
2011.02.07 - Update:
I have walked the debugger line by line without incident. There is no indication of any program failure in the console window.
I say that the debugger is still active after [Command + Q] because the Stop Process toolbar button is still enabled as is the Break button. Further the console indicates that after I tell the application to terminate (either via the menu or key command) that it is still running. The following is the Complete console output from start of run to after I Quit the application.
Program loaded.
run
[Switching to process 62370]
Running...
The Activity Monitor (system tool) will show my application terminating (no longer shows up as a process) but the Debugger will still not transition to "edit" mode - if I tell Xcode to run the debugger again, it will ask me if it's OK to Stop the current debugging session. If I was in Windows I would start looking for background threads keeping the process alive but as far as I know, NSOpenPanel should not be doing something like that.
I have further simplified the program to nothing more than creating a brand new Cocoa application and inserting the code snippet above - no other additions to the template project or updates in any way.
And lastly, when the application is run under the Leaks Performance Tool, everything runs fine when the panel is created but never used. When created and actually used though, at the end of the run I will get the following message in the tool "insufficient task_for_pid privileges (leakagent64)". Googling this hurts. If I read it right, the debugger does not have sufficient permissions to fully kill the target process ??? Now that sounds stupid but ... It does not make sense!
Another update - I just downloaded and ran FunHouse, one of the SDK sample applications that also uses NSOpenPanel. Well don't I feel special. It exhibits the same exact behavior. So from this I conclude either Apple has a bug in their code, my machine is special and messed up, and finally, it is Not my code that is at fault. That being the best part. Tomorrow, I will use a friends Mac and see if the same behavior is exhibited on his box.
This is just too weird.
I rebooted my box, took it to work and found it worked like a charm! I will assume this is fixed and has nothing to do with any other connected devices at home as compared to at work.
If it re-exhibits at home, then it is a network/device issue. Thanks all for your inputs and suggestions! Very much appreciated.
What, specifically, does the debugger say? It's possible that your program crashed, so the debugger is showing you information about the crash.
What if you omit any attempt to run an Open panel?