How to scan if Mac is in background / foreground - objective-c

Is there any posible way to know if a Mac is in background or foreground?
In iOS we have the following methods:
applicationWillEnterForeground
applicationWillenterBackground
But is there any way to know if a Mac is active or inactive?

It depends on your application layout, but in general use an NSApplication delegate and implement:
- (void)applicationWillBecomeActive:(NSNotification *)aNotification
as well as its counterpart
- (void)applicationWillResignActive:(NSNotification *)aNotification
There are other notifications as well. See the linked document above. Also note that OS X allows real multitasking and thus background/foreground usually refer to having focus or not having focus.

Related

Accessing NSWindow.level for all applications windows on screen

I am trying to manipulate the windows of macOS. I have found the following URLs:
Move other windows on Mac OS X using Accessibility API
Getting Window Number through OSX Accessibility API (Core Graphics)
set the size and position of all windows on the screen in swift
How to set an external application always being frontmost on OS X? (Unanswered)
How to convert a Carbon AXUIElementRef to Cocoa NSWindow (Unanswered)
Setting the window level over Accessibility (Unanswered)
How to create an AXUIElementRef from an NSView or NSWindow? (Unanswered)
The links allow for accessing the various windows of an application via the Accessibility API of macOS; more specifically, they use the AXUIElementRef element to re-position windows.
When creating an app for macOS, I have successfully used the following code ...
#implementation CustomWindow
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation
{
self = [super initWithContentRect:contentRect styleMask:windowStyle backing:bufferingType defer:deferCreation];
if(self)
{
[self setLevel:kCGDesktopWindowLevel - 1];
[self setCollectionBehavior:
(NSWindowCollectionBehaviorCanJoinAllSpaces |
NSWindowCollectionBehaviorStationary |
NSWindowCollectionBehaviorIgnoresCycle)];
}
return self;
}
// ...
#end
... to put a window on the Desktop level of the screen. What I am looking for is a way to manipulate the same Window level property or the like via a custom Windows Manager application. In other words, I would like to code a windows manager that can manipulate the levels the windows of other applications on screen.
Am, I correct in my findings that this can't be done? Can it be done via Core Graphics?
In addition, I want to change the application that is key and in focus, but I think this can be done.
You can't really manipulate the CGWindowLevel of a window (all normal windows are kCGNormalWindowLevel, for example) but if you're looking to change the order of a normal-level window relative to others then you're probably looking for Accessibility's kAXRaiseAction, which you can see in action here.
If you're just looking to see what all the windows on the system are (and their CGWindowLevels, then CGWindowListCopyWindowInfo will give you that information.

Is There A Lost Focus Window Event in Objective C?

Coming from a .NET background I'm used to events getting fired so trapping a lost focus event is easy but I'm not sure how to do this in Obj-C. Basically I want my app to know when another application has gotten focus and it no longer has it so it can perform some actions.
Can you please tell me how I can implement this kind of functionality in Obj-C for an OSX app?
Have a look at the NSWindow notifications. Specifically, you're interested in NSWindowDidBecomeKeyNotification and NSWindowDidResignKeyNotification. You can also create a delegate for the window and implement its windowDidBecomeKey: and windowDidResignKey: methods, as noted in the NSWindowDelegate protocol documentation.
Or, if you just wanted to know when the application (not a window) has gained focus, you can subscribe to the NSApplicationDidBecomeActiveNotification. Likewise, NSApplicationDidResignActiveNotification will notify you when your app loses focus. These notifications are discussed more here. You can also implement applicationWillBecomeActive: and applicationWillResignActive: in the application delegate.
It's unclear if you want notification of a single window losing focus or notification of your entire app losing focus. My answer here provides notification for the entire application losing focus. (See mipadi's answer if you just want to know when one of your app's window loses focus.)
Observe the appropriate notification:
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
selector:#selector(appDeactivated:)
name:NSWorkspaceDidDeactivateApplicationNotification
object:nil];
Then add the handler method:
-(void) appDeactivated:(NSNotification *)notification
{
NSRunningApplication* app = [notification.userInfo objectForKey:#"NSWorkspaceApplicationKey"];
if (app == [NSRunningApplication currentApplication]) {
// your cleanup code here
}
}

Cocoa App - Get Keyboard Events When Application Not Focused

I'm writing a Cocoa app that needs to be able to capture keyboard events even when not focused. (It's controlling another app via the Apple Scripting Bridge).
I have tried the solution here: OSX: Detect system-wide keyDown events?
It compiles fine, but doesn't actually do anything. I'm putting the code in my init method.
I also can't get CGEventTap to work either. Any suggestions?
Here's my code:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSEvent addGlobalMonitorForEventsMatchingMask:(NSKeyDownMask) handler:^(NSEvent *event){
NSLog(#"test");
}];
}
Also, I'm aware that assistive devices needs turned on. Unfortunately when I go into the settings it only lists specific apps. Mine isn't one of them.
Use AXIsProcessTrustedWithOptions to request access. Then you'll show up in System Preferences.

How to activate a custom screensaver preview in Cocoa/Obj-C?

I have created a fairly simple screensaver that runs on Mac OS 10.6.5 without issue.
The configuration screen has accumulated quite a few different options and I'm trying to implement my own preview on the configureSheet window so the user (just me, currently) can immediately see the effect of a change without having to OK and Test each change.
I've added an NSView to the configureSheet and set the custom class in Interface Builder to my ScreenSaverView subclass. I know that drawRect: is firing, because I can remove the condition for clearing the view to black, and my custom preview no longer appears with the black background.
Here is that function (based on several fine tutorials on the Internet):
- (void)drawRect:(NSRect)rect
{
if ( shouldDrawBackground )
{
[super drawRect:rect];
shouldDrawBackground = NO;
}
if (pausing == NO)
[spiroForm drawForm];
}
The spiroForm class simply draws itself into the ScreenSaverView frame using NSBezierPath and, as mentioned, is not problematical for the actual screensaver or the built-in System Preferences preview. The custom preview (configureView) frame is passed into the init method for, um, itself (since its custom class is my ScreenSaverView subclass.) The -initWithFrame method is called in configureSheet before returning the configureSheet object to the OS:
[configureView initWithFrame:[configureView bounds] isPreview:YES];
Maybe I don't have to do that? It was just something I tried to see if it was required for drawing.
I eventually added a delegate to the configureSheet to try triggering the startAnimation and stopAnimation functions of my preview via windowWillBeginSheet and windowWillEndSheet notifications, but those don't appear to be getting called for some reason. The delegate is declared as NSObject <NSWindowDelegate> and I set the delegate in the configureSheet method before returning the configureSheet object.
I've been working on this for days, but haven't been able to find anything about how the OS manages the ScreenSaverView objects (which I think is what I'm trying to emulate by running my own copy.)
Does anybody have any suggestions on how to manage this or if Apple documents it somewhere that I haven't found? This isn't really required for the screensaver to work, I just think it would be fun (I also looked for a way to use the OS preview, but it's blocked while the configureSheet is activated.)
OK, there are a couple of 'duh' moments involved with the solution:
First of all, I was setting the delegate for the sheet notifications to the sheet itself. The window that the sheet belongs to gets the notifications.
Secondly, that very window that the sheet belongs to is owned by System Preferences, I don't see any way to set my delegate class as a delegate to that window, so the whole delegate thing doesn't appear to be a viable solution.
I ended up subclassing NSWindow for the configureSheet so that I could start and stop animation on my preview by over-riding the makeKeyWindow and close methods.
- (void) makeKeyWindow
{
if (myPreview != nil)
if ( ! [myPreview isAnimating])
{
[myPreview startAnimation];
}
[super makeKeyWindow];
}
I also had to add an IBOutlet for my preview object itself and connect it in Interface Builder.
Still working out a couple of issues, but now when I click on my screensaver Options button, my configureSheet drops down and displays its own preview while you set options. Sheesh. The hoops I jump through for these little niceties. Anyway, I like it. Onward and upward.

Closing child windows in Cocoa when the main window is closed

I'm a Cocoa newbie so it is likely that my approach is wrong but ..
I have an app which opens several child windows (after the main/parent window has been loaded) using NSWindowController and initNibWIthName:. This works fine.
But when I close the parent window (using the red x) these remain open and prevent the app from closing until they are closed as well. This makes sense as I am not shutting them anywhere.
But how do I do this? There must be an event that is called at this point but I can't find what it is anywhere.
Notifications such as applicationWillTerminate (and so on) are only called when the application actually is terminating not when the close button has been pressed.
I guess I'm looking for something similar to the Windows WM_CLOSE type messages.
The closest equivalent you'll find is the NSWindowWillCloseNotification posted by the window prior to its closing. You can probably get the child windows to close themselves when the parent window closes using:
NSWindow *parentWindow;
NSArray *childWindows;
NSNotificationCenter *noteCenter = [NSNotificationCenter defaultCenter];
for (NSWindow *childWindow in childWindows) {
[noteCenter
addObserver:childWindow selector:#selector(close)
name:NSWindowWillCloseNotification object:parentWindow];
}
If the child window will be deallocated before its parent, be sure to unregister it for notifications before that happens.
The delegate method mentioned by Mark is a convenience method for the delegate that saves them the trouble of registering for a notification they'll likely want anyway. You don't need to create a window controller just to receive that message; simply sending the window [window setDelegate:myObject] will cause myObject to receive the -windowWillClose: message if it responds to the method.
By the way, what Cocoa calls "child windows" differs from what you're thinking of. They're not addressed in the Window Programming Guide, but if you look at the documentation for the related methods on NSWindow, you'll see that they basically track the movements of their parent window, so that they move with it.
If you're coming to Cocoa from Win32 programming, you might find Apple's Porting to Mac OS X from Windows Win32 API helpful to highlight conceptual differences between Win32 and Cocoa.
windowWillClose:
Apple developer docs NSWindowDelegate
Windows and applications are not the same thing in Mac OS X.
If you have a single-window interface, with a main window and no others except for About, Preferences, etc., then you should implement applicationShouldTerminateAfterLastWindowClosed: in your application delegate and return YES. This is the only way (aside from you doing it manually) that closing a window causes the application to quit.
If you have a multiple-window interface (as in a typical document-based application), then you should make all of those windows peers to one another. Windows such as Inspectors and tool palettes should be floating panels, not regular windows. And closing the last window should never, ever quit such an app.