Cast NSWindow to NSPanel - objective-c

I am accessing a Virtual keyboard (external application - in Adobe Flex).
I want that keyboard should be non focusable. So I have to apply
styleMask:NSNonactivatingPanelMask
But am accessing the keyboard as
NSWindow *myMainWindow = [[[NSApplication sharedApplication] windows] objectAtIndex:0];
as NSNonactivatingPanelMask can only be applied to the NSPanel only
If I can type cast the NSWindow to NSPanel (?) then it possible.
----------My Previous question------------
Return focus to Editor after clicking a button in floating window of MAC

An NSPanel is an NSWindow, the reverse is not true - inheritance doesn't work both ways!
Furthermore casting an object reference from one type to another does not change the actual type of the reference object, so even if you cast an A * to a B * then invoking a method gets you exactly the same method as without the cast - the cast serves to inform the compiler that you know the actual object referenced is a different type and so quietens the compiler when you invoke a B method.
Even if you could get past all that, you state you want the keyboard to be non-focusable, which is not the same as non-activating - the former is about being an applications main window, the latter is about accepting input without activating an application.
The main window of an application is the one which is focussed, its frame highlighted in some way, etc. The key window of an application is the one which is accepting user input. They are often the same window, but need not be. It sounds like you want your keyboard to by the key window without being the main window - i.e. behave like a panel.
NSWindow has methods canBecomeMainWindow and canBecomeKeyWindow which determine whether a window can become main or key respectively. While you cannot change what these return for an NSWindow instance you can subclass NSWindow and override these methods - this is what NSPanel does - see the NSWindow documentation for these methods. So if you, say, define KeyboardWindow as an NSWindow subclass and override canBecomeMainWindow to return NO. Do this and you have a window which will not become main (focussed) but can accept input.
HTH

AS provided by #ashirbad
NSWindow *mainWindow = [[NSApp windows] objectAtIndex: 0];
NSView *mainContentView = [mainWindow contentView];
NSPanel *mainPanel = [[NSPanel alloc] initWithContentRect:[mainContentView frame]
styleMask:NSBorderlessWindowMask | NSNonactivatingPanelMask
backing:NSBackingStoreBuffered defer:YES];
[mainPanel setContentView:mainContentView];
[mainPanel setLevel:NSScreenSaverWindowLevel];
[mainPanel makeKeyAndOrderFront:nil];
[mainContentView orderOut:nil]; //error
This solved my problem.
But I'm getting an error orderOut is not defined in NSView.
If the top app is a Mac application then it's ok But if it is a flex app (in this case). The application not responding at this line.
[mainPanel setContentView:mainContentView];

Related

How do you make an NSWindow visible and in focus that was declared in Interface Builder?

I have an NSWindow designed in Interface Builder, and I want this window to be appear programmatically and be given focus. In my case the window appears, allows itself to be configured with titles, but the window stubbornly refuses to take focus, refuses to resize, and refuses to respond to any kind of input, from pressing the button, to moving the vertical slider, to allowing the window to close.
The NSWindowController is defined as follows:
#interface SignTextTab : NSWindowController <NSWindowDelegate>
- (id)processMessage:(id)message messageUuid:(id)messageUuid messageId:(id)messageId;
#end
and is instantiated as follows:
tab = [[SignTextTab alloc] init];
The NSWindowController loads the NIB as follows:
- (id) init
{
return [super initWithWindowNibName:#"SignTextTab" owner:self];
}
and the window is made visible as follows:
self.window.level = NSModalPanelWindowLevel;
[self.window makeKeyAndOrderFront:self];
Querying the status of the NSWindow directly after the calls above leads to this:
NSWindowStyleMask styleMask = self.window.styleMask;
BOOL isKey = self.window.isKeyWindow;
BOOL canKey = self.window.canBecomeKeyWindow;
The variable isKey is NO, because makeKeyAndOrderFront did not appear to do anything. The variable canKey is YES.
The styleMask is as follows:
NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable
The application is a Safari Web Extension.
Many people have asked the question, but none of these have answers that translate into concrete actions relevant in Xcode 13.
How do I open an NSWindow and have the window selected and in focus?
Connect Window Controller Outlet to Window
How to give focus to NSWindow loaded from NIB?
The file's owner is configured as follows.
Does anyone know what concrete steps need to be taken to make sure the NSWindow can gain focus, and provide concrete screenshots of what Interface Builder is supposed to look like when it is configured correctly?

Added NSWindow as child of another window, but not persisting

My goal is to position an NSWindow relative to another NSWindow, such that when the parent is dragged around, the child moves along with it.
When I poke around with the debugger, I can see the NSWindow parenting relationship getting established correctly. However, in a later part of my code, that same NSWindow returns nil when I try to fetch the parent. I figured only an explicit call to removeChildWindow would eliminate the parenting, unless there's something else going on here like I'm setting up the parenting incorrectly. Are there other ways for an NSWindow to lose its parent/child relationship?
someFunction(NSWindow* parentWindow) {
NSWindow* wnd = [[NSWindow alloc] initWithContentRect:frame
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
[parentWindow addChildWindow:wnd ordered:NSWindowAbove];
}
later:
anotherFunction(NSWindow* window) {
NSWindow* parentWindow = [window parentWindow]; // debugger shows nil
}
It seems I had a call to change the window visibility to false:
[wnd setIsVisible:false];
And when I tried reading its parent again, that ends up being nil. Who would have guessed it, this doesn't appear to be documented.

keyDown: Not Called on NSClipView Subclass

My app is not document based, and its sole window is managed by a custom, xib-based NSWindowController subclass that I instantiate within the app delegate code:
- (void) applicationDidFinishLaunching:(NSNotification*) aNotification
{
_mainWindowController = [MainWindowController new];
// (stored in ivar just to prevent deallocation)
//[_mainWindowController showWindow:self];
// ↕︎ Not sure about the difference between these two... both seem to work.
[[_mainWindowController window] makeKeyAndOrderFront:self];
}
I have subclassed NSClipView to "center content inside a scroll view" (instead of having it pegged to the lower left corner) when it is zoomed to a size smaller than the clip view, and also implement custom functionality on mouse drag etc.
My window does have a title bar.
My window isn't borderless (I think), so I am not subclassing NSWindow.
I have overriden -acceptsFirstResponder, -canBecomeKeyView and -becomeFirstResponder in my NSClipview subclass (all return YES).
The drag events do trigger -mouseDown: etc., and if I set a breakpoint there, the first responder at that point is the same as the window hosting my clip view: [self.window firstResponder] and [self window] give the same memory address.
What am I missing?
Update
I put together a minimal project reproducing my setup.
I discovered that if my custom view is the window's main view, -keyDown: is called without problems. But if I place a scroll view and replace its clip view by my custom view (to do that, I need to change the base class from NSView to NSClipView, of course!), -keyDown: is no longer triggered.
I assume it has something to do with how NSScrollView manages events (however, as I said before, -mouseDown:, -mouseDragged: etc. seem to be unaffected).
I also discovered that I can override -keyDown: in my window controller, and that seems to work, so I have decided to do just that (still open to an answer, though). Also, since I'm trying to detect the shift key alone (not as a modifier of another key), I'd rather use:
- (void) flagsChanged:(NSEvent *) event
{
if ([event modifierFlags] & NSShiftKeyMask) {
// Shift key is DOWN
}
else{
// Shift key is UP
}
}
...instead of -keyDown: / -keyUp: (taken from this answer).

How to detect when a NSPanel closes as a result of losing focus? E.g. A user clicking outside of the NSPanel (Window?)

I have a generic NSPanel window that I am using as a preferences window in my app. I have a selector that I call every time the window closes. The purpose of that selector is to save the state of the users chosen preferences (there is no "save" button).
I have an NSButton ("CLOSE") which I easily setup to call my closing selector.
I set it up so that my selector is also called when the user clicks the RED X in the top left corner of the NSPanel by doing:
NSButton *closeButton = [[self window] standardWindowButton:NSWindowCloseButton];
[closeButton setTarget:self];
[closeButton setAction:#selector(myCloseSelector:)];
This works perfectly. My problem though? The window also closes if the user clicks outside of the NSPanel. E.g. If they take their mouse and click on their browser window below the NSPanel that popped up. This also closes the window.
How do I catch my NSPanel losing focus and closing ? I need to ensure that when this happens I also get my selector called.
Thanks!
Made my NSWindowController a delegate for NSWindowDelegate.
myWindowController.h
#interface myWindowController : NSWindowController <NSWindowDelegate>
and then set myWindowController as the delegate for my NSPanel.
Now I can implement:
- (void) windowDidResignKey:(NSNotification *)notification {
NSLog(#"Houston...we lost a panel.");
}
and everything works swimmingly!

How to change title of NSPanel at runtime?

Maybe I'm missing something really simple here (I hope so), but is there a trick to changing the title of an NSPanel at runtime? The obvious [panel setTitle:#"New title"] doesn't seem to be working.
I'm trying to display a regular panel which contains a WebView, and I want to the title of the panel to reflect the title of the HTML content.
I subclassed NSWindowController and called initWithWindowNibName. I changed the class in the nib from NSWindow to NSPanel, and everything seems to be working okay. In my window controller, I did this:
- (void)windowDidLoad {
[super windowDidLoad];
[[self window] setTitle:#"My New Title"];
}
(I will actually be setting the title in a webView:didReceiveTitle:forFrame delegate, but this is simpler to show).
I verified that the code is getting called, and there are no errors reported, but the title never changes. Any ideas?
In the nib file that contains the panel, make sure that the File’s Owner’s class has been set to your NSWindowController subclass and that the window outlet from File’s Owner has been connected to the panel. Otherwise, the window controller won’t know which window it should be managing and [self window] returns nil.
You're setting the title, but you're not telling the window to display itself again.