How to prevent displaying window on application startup osx - objective-c

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.

Related

Objective-C bring app to front on key press

I am trying trying to bring an application that is in the background to the foreground by binding to a key-press from the user even when the application does not have focus.
The affect I want is exactly like Quicksilver / Alfred / Spotlight.
Is it possible to do this without having the user mess with any Settings inside Accessibility?
Or is this functionality prevented for security reasons? It seems some people have managed to get around this
Thanks!
PS: I am working off the example from apple with rounded window / transparency:
https://developer.apple.com/library/mac/samplecode/RoundTransparentWindow/Introduction/Intro.html
Registering a Global Event Listener is what you're looking for.
You can then read global key presses and call [NSApp activateIgnoringOtherApps:YES]; on the desired key press.
If you also want the user to be able to customise that shortcut, use MASShortcut.

Keep my app as responder while calling activateWithOptions:NSApplicationActivateIgnoringOtherApps

I am making a vim-style "window manager" that takes text input, much like Alfred or Spotlight in Mavericks (in a floating panel).
The problem I'm having is when I call activateWithOptions: on a running application it steals focus from my window. I was hoping the problem would be solved by simply bring my app to the foreground again, however it seems the activation is running on a separate thread, and I end up activating my app before the original app gets activated.
I have tried reactivating when I receive NSWorkspaceDidActivateApplicationNotification, but that doesn't work either.
Ideally I'd like to pause execution until the application is focused for multiple reasons, since that would be the window I manipulate further.
Does anyone have any suggestions?

Add button to OSX lock screen

Is it possible to alter the existing OSX lock screen ? For example if I wanted to add a button above the users profile image that says "Hello World" on click.. is this possible?
The goal is to run an AppleScript when the button is clicked.
EDIT -
/System/Library/PrivateFrameworks/LoginUIKit.framework
Inside here you have the ability to change the login screen images and such, but also it contains several compiled nib files abbreviated with 'LUI' which I am assuming stands for 'Locked User Interface'. I'm about to set up parallels and try to open them in Snow Leopard with xcode 3.2.6, and see if I can edit the nibs. If I'm able to accomplish this, would editing such files be in violation of their TOS?
Another possibility was running a window above it. On screen lock I can get the window above the screensaver simply by saying
[window setLevel:NSScreenSaverLevel]
but still, that doesn't overlay the login screen.
I feel like this shouldn't even be possible, but I seen something similar on the Knock to Unlock app.
Did you try to use the following line?
[window setLevel:CGShieldingWindowLevel()+1];
I'm using it to do the same as KnockToUnlock and it works like a charm. I see my window above the login screen either if I come on the login screen from the sleep mode or the screensaver.
Hope this helps.

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

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.

How to order a window to front if you are not in the Application in Objective-C

Is there a way to make a "makeKeyAndOrderToFront" without beeing in the Application?
If I am in Safari and in the Menu Bar there is a MenuItem to my App, after I press this, i want to show a window of my App in the Front (makeKeyAndOrderToFront makes this just if you are in the Application).
Which way can I use? And how can I animate this Window (like Tweeties Add new Tweet -> atebits.com).
Thank you!
As you've discovered, changing the window order within your application does not have any impact on which application is active. You can bring your application to the foreground by activating it:
[NSApp activateIgnoringOtherApps:YES];
If your application had a dock icon the behavior would be similar to the user clicking on it.
Applescript would be a trivially easy way to make your app frontmost. It won't be doing any animation, though.
tell application "System Events" to set frontmost of process "My Application" to true
Perhaps the best way to accomplish what you want, if I understand the question correctly, is to have your application respond to an Apple event which you send to it after your menu item is selected which will bring your application and desired window to the front.
Provided your application has a connection to the window server (which it will if it's using AppKit or Carbon), you can use the Core Services function SetFrontProcess() to bring it to the fore. SetFrontProcessWithOptions() can be used to bring only the frontmost non-floating window of your app to the fore. These functions appear to be available to 64-bit applications, but if you're targeting 10.6+, you're likely better off using the NSRunningApplication class. Something like
[[[NSRunningApplication
runningApplicationsWithBundleIdentifier:ident] lastObject]
activateWithOptions:0]
should do the trick.