Search code examples
objective-cmacoscocoa

Is it possible to change behavior and attributes of the window of an NSPopover?


I am sorry - I do not understand what is missing in my question. I think it is fully loaded with all the needed details - but I'll try to appease the moderator here with more info.

  1. MacOS Cocoa app written solely in Objective-C.

  2. The app is a "Status Item" app. With tiny visual footprint as an icon on the menu-bar (NSStatusItem), which opens an NSMenu One of the NSMenuItem objects in this NSMenu shows/hides a popover. Here is the IBAction called.

    -(IBAction)showPreventionStatus:(id)sender { if (self.statusPopover.isShown) { // hide it [self.statusPopover performClose:self]; [(NSMenuItem *)sender setTitle:@"Show Prevention State"]; } else { [self.statusPopover showRelativeToRect:[self.statusItem.button bounds] ofView:self.statusItem.button preferredEdge:NSMaxYEdge]; [(NSMenuItem *)sender setTitle:@"Hide Prevention State"]; } }

Where

@property (strong) IBOutlet NSPopover *statusPopover;

is defined in my XIB and connected to this property of my AppDelegate.

  1. Almost all of the UI is defined in a single .XIB, including the NSPopover, its NSPopoverController, and the NSView hierarchy presented by this NSPopover. Most objects are connected to my AppDelegate.m which contains all the IBActions etc.

enter image description here

When open, The popover looks like this (removed some of the details):

Popover window, sans text

This NSPopover (configured to be transient) can be torn off, and then it looks like a floating window/panel. The popover displays an NSView which is defined and attached to the popover in a normal .xib file (see screenshot above)

I can obtain the underlying window object from the NSPopover like this:

NSWindow *statusWindow = [self.statusIconView window];

where self.statusIconView can be ANY NSView in the view hierarchy of the pop-over.

The statusWindow looks like a normal NSWindow - but any attempt to change its attributes (I'm trying to make it resizable for instance) is ignored.

I tried to inspect it in the debugger - and found out that its class is special:

NSPopoeverWindow : NSPanel : NSWindow

NSPopoeverWindow seems to be a private Cocoa class, since I can't find it in the AppKit headers. However, it subclasses NSPanel which in turn is a subclass of NSWindow. I suspect this special class overrides and ignores much of the NSWindow functionality and behavior.

I tried to manipulate this window object in many of the NSPopover delegate methods (before and after it is shown, before and after it is detached etc.) to no avail. It simply ignores everything I do to it.

After applying change/modification to any of its properties/attribuges, if I "get" its new state - I see the proprtyu/attribute unchanged. My calls were NOT applied.

Now my question:

Is there a way to force it to "behave" the way I want?

  1. I want it resizable.
  2. I want it to become "key" and some of its elements/controls to become first-responders. E.g. currently an editable text field inside the view can't be edited, refuses keyboard commands (for copy/paste/select-all)

I did NOT create this window, and I did not anywhere in my code determine its class. It's NSPopover (or maybe NSPopoverController) who do this.

my code is Obj-C but I don't think that matters here.

Any idea will be greatly appreciated.


Solution

  • Sounds like you need to implement -[NSPopoverDelegate detachableWindowForPopover:] and provide a window of the kind you want.