Consider the following scenario. I have an app with two windows:
the main window which contains all of the app's functionality;
and an auxiliary window that can be invoked using a global shortcut or by clicking app's status bar icon. It looks like this:
It's a simple window for quickly adding data to the application without bringing up the main window — possibly changing spaces and disrupting user's workflow.
The window floats above everything else (it's on NSModalPanelWindowLevel) and can join all spaces (NSWindowCollectionBehaviorCanJoinAllSpaces)
Here's the problem: when the quick-add window is ordered out (the X button or Esc is pressed), the main window is made key and ordered front (provided that it's somewhere on the window list in the current space).
This isn't the behavior I want. Normally, when an app's window is closed, yes, you want the app's window below to be activated, but not here — this is a "helper" window that should work more-or-less independently from the app itself. When I'm in Safari and invoke the quick-add window, I only want to add some data, click Return, and I want it to go away — I want the previous window (Safari) to be key and on top, not the main window of my app (unless of course the main window of my app was key before invoking quick-add).
So, how to close an NSWindow without activating the window below?
I can't figure this out. The only idea I had is that maybe you could make a helper application that would display this auxiliary window — but that sounds like a lot of work (sending data back and forth between processes, all that…). There must be a simpler way!
i don't think this can be (usefully) done with an NSWindow.
As in this answer, i would recommend trying to use an NSPanel with the style NSNonactivatingPanelMask instead of creating an NSWindow.
Related
Is it possible to create a NSWindow that will not only is above all other windows (including other applications) but also able to block windows from going "into" that window. Basically I would like to extend the system's menu bar by having another bar below it, but it stops the user from resizing other windows to occupy that space.
For instance, if the user was to maximize a window, it would only be able to have a height of the screen size minus the system status bar minus my application's window.
I was thinking it may be possible by listening to some sort of window resizing notification and if the user tries to set the frame of that other window to a size that would go inside of my application's window then I would resize the other window, but method seems like such a pain.
I also acknowledge that this may not be possible, but was curious if it is!
Thanks in advance!
It is totally possible to make a window which is above all other windows, just set It's level to NSMainMenuWindowLevel.
But preventing other windows from resizing beyond It, I don't think so.
Even if there is a system API to limit window resizing (I don't think there is), some apps use custom code to control window resizing and would completely ignore the presence of your "special" window. I've seen apps which simply hardcode 22 (the height of the menu bar) when calculating window resizing stuff.
I have two NSWindows. Window A with level 0, and Window B with level 1. I'm using B as a floating window.
This works as expected until I put A as a modal window (i.e., send runModalForWindow:A message to NSApplication). Then B is always behind A.
Is there a way that I can have B above A, even when A is running as a modal window?
Much appreciated for the help.
To put your floating window in front, use [myfloater setLevel: NSModalPanelWindowLevel+1].
Other people are telling you that you will have trouble interacting with the floater, but I've done it and it worked for me. (My floater uses NSPanel of "Utility Panel" style rather than plain NSWindow, but I'm not sure if that's important. You may also need to say [myPanel setWorksWhenModal: YES].)
AFAIK that is not possible.
From the Apple class reference:
NSApplication runModalForWindow:
This method runs a modal event loop for the specified window
synchronously. It displays the specified window, makes it key, starts
the run loop, and processes events for that window. (You do not need
to show the window yourself.) While the application is in that loop,
it does not respond to any other events (including mouse, keyboard, or
window-close events) unless they are associated with the window. It
also does not perform any tasks (such as firing timers) that are not
associated with the modal run loop. In other words, this method
consumes only enough CPU time to process events and dispatch them to
the action methods associated with the modal window.
Given this, your Window A will become the key window and will always be shown on top of any other window of your app. I think this is how modal windows are supposed to work.
As an alternative you can consider using an NSPopover which has a clear presence to the user but does not force your application into a modal state.
Check out this page from the Apple docs on guidelines re various options available to you.
I think if you set the window level to NSScreenSaverWindowLevel, it will always be on top.
You can use orderFront:, orderFrontRegardless, or orderFront:relativeTo:, to have B moved in front of A. However not sure how many tasks can you do in B, as due to the fact that A is modal, you won't be able to interact with B.
In my Cocoa/Objective-C application I have a utility panel floating "always on top" to be accessible even when my application is not active. I am trying to disable the "switching to my application when a user clicks on that panel".
The behaviour I would like to achieve is similar to OSX's Keyboard Viewer, (which is also a never activating panel), so that some other application remained active after clicking on my app's panel. i.e. Safari stays active when typing an address using Keyboard Viewer. Even third-party onscreen keyboards have this functionality (for example the one from CORALLO Software), which means this behavior is not reserved system-only.
I was messing around with NSApplicationActivationPolicy, but without positive results. In which direction should I go?
You should take a look at the canBecomeKeyWindow and canBecomeMainWindow methods on NSWindow. It sounds like you want your window to maintain key status while not being able to be the main window. Here are some resources to help you:
Window Programming Guide - Explains the difference between main and key windows
NSWindow class reference - Jump to the sections on canBecomeKeyWindow and canBecomeMainWindow
Is there a way to have my app's window receive keyboard and/or mouse events (i.e. user clicking on window's buttons) while still retaining focus to another, unrelated app?
I've tried configuring my window at different levels, including [myWindow setLevel:NSPopUpMenuWindowLevel] to no avail.
You should be able to handle mouse clicks without ordering your window front by making your views (at least the ones that handle mouse clicks) respond to acceptsFirstMouse: messages by sending NSApp a preventWindowOrdering message and then returning YES.
You should not make your app handle typing without ordering itself front. The user might not realize where their typing is going if the field where it's appearing is obscured by another window.
Found it. Simple, yet elusive.
Use NSPanel and make sure panel style is Non Activating (NSNonactivatingPanelMask) or tick the same option in IB's inspector.
I am trying to write a program that requires to know if a window is being dragged (moved around). The catch is that it's not the program's window, but rather any window in the OS (eg. Safari, iTunes, Adium, TextMate, etc.), and what program it belongs to
I was thinking AppleScript would be a potential way to do this, but there doesn't seem to be anyway to know whether it's being dragged.
Any ideas?
On window will resize handler or window will move handler. I'm not sure if those are the exact names but you can find them in the Window section of the Applescript section in the inspect window in Interface Builder.