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.
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.
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.
I've created a simple Cocoa-Application in XCode 4.6 with an NSPanel instead of the default NSWindow. When I enable the Non-Activating
option and start the application everything works fine:
The panel is displayed in front of everything else and when
the mouse cursor hovers over the panel's edges it changes from a normal
arrow-cursor to the appropriate resize-cursor, so the user knows that he can resize
the panel.
This works fine as longs as I don't click on any other application
as for example Safari or Finder.
From the moment I once give focus to another application,
I can click on and hover over my panel as much as I want, the
cursor style will not change anymore - it always stays an arrow and it's not possible to return to the normal behavior.
The panel stays selectable and in the front, you still can move and resize it,
but the mouse cursor stays an arrow all the time. You then cannot even change it
manually using something like: [[NSCursor crosshairCursor] set].
So I need to find a way to create a NSPanel that keeps the normal
automatic-change-cursorstyle-when-hovering-over-panel-edges-behaviour
even when you give focus to another application.
I have already tried to use an customized NSPanel-class,
where I have overwritten the canBecomeKeyWindow and
canBecomeMainWindow methods, so that they return YES
but even when I make my Panel KeyWindow and MainWindow...
[myPanel makeKeyAndOrderFront:self];
[myPanel makeMainWindow];
...it doesn't solve the cursor issue.
Would be great if someone could help me here :)
PS.: the Base SDK and the Deployment Target are set to 10.8 in my project
So I found out that the described issue has nothing to to with the panel's window-state. It really doesn't matter if it is set to key or to main, instead the cursor-problem (stays arrow all the time)is related to the application's activation state.
Everything works fine as long as the application that owns the panel is active but if you click on another application my application is deactivated and does not get activated again - even if you click on the panel - because the "non-activating"-option is enabled.
The problem is that i need the "non activating"-option because I am creating a status-bar-screen-capturing app that should be displayed and operate in front of everything else but without deactivating any running application. I could solve the cursor problem by
[NSApp activateIgnoringOtherApps];
but then taking a screenshot of a fullscreen video running in Safari would deactivate Safari and minimize the video, which I don't want.
I don’t think it’s possible through normal APIs to change the cursor when your app isn’t active. I’m pretty sure the window system doesn’t allow it: it’d be a violation of the boundaries between apps—if you try to set a cursor from the background, and the foreground app also tries to set a cursor, who would win?
Of course the system can do it (like when you take a screenshot with ⌘⇧4), because that’s in the window system itself.
i'm looking for a way to have a NSWindow, which is able to block other NSWindows, like the menubar does. I mean: It is not possible to drag a Window over the menubar.
Is that kind of behavior realizable for my own NSWindow?
Thanks in advance
Bijan
NSWindow's dragging behavior automatically keeps windows from going under the menu bar — because they aren't supposed to. If you have some special case, you can override the standard dragging behavior. But think carefully before throwing away standard functionality prescribed by the HIG.
Also, it isn't possible to drag a window over the menu bar (rather than under) unless it's also over everything else, because the menu bar is normally above every other window.
I just stumbled on this question. There they say it is possible to move other windows using the Accessibility API or the Quartz Window Services.
Can't I just read out the other window's positions and move them, so that they do not collide with my window? Maybe triggered by a 0.1 sec. timer?
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.