ABPeoplePickerView is leaving hidden windows? (OSX) - macos

This is how I discovered the problem:
My app has a small dialog window with an ABPeoplePickerView. This window (or its controller) is correctly deallocated when finished with.
When the app terminates, in applicationShouldTerminate: I iterate through all its windows ([NSApp windows]) and if the window has a delegate and it responds to windowShouldClose: I call that method and if the response is NO, I stop the termination.
Logging each window's title revealed that each time I created my dialog window, two extra hidden windows were created, with titles: "People Picker Debug Info" and "People Picker Preview", and that these windows aren't disposed of when the dialog is closed. You can actually see these windows if you makeKeyAndOrderFront them. The latter is blank. A long run of the app could create a large number of these windows, presumably using up resources. Should I worry? Should I do anything about it? Could I make use of them?
My hunch is to search for these windows by title in my dialog's deallocate method, and close them there. Are there any ARC issues?

The following lines in the window controller's dealloc method have fixed the problem, with no side effects as far as I can tell.
for (NSWindow *w in [NSApp windows]) {
if ([w.title isEqualToString:#"People Picker Debug Info" ]) {
[w setReleasedWhenClosed:YES];
[w close];
}
if ([w.title isEqualToString:#"People Picker Preview" ]) {
[w setReleasedWhenClosed:YES];
[w close];
}
}

Related

OSX - How to identify window under cursor in all spaces including fullscreen

I'm using Window Services' CGWindowListCreate and CGWindowListCreateDescriptionFromArray to get window information. When getting kCGWindowBounds in a regular Space everything works fine (I'm drawing borders around the frontmost window on the 0th level). However, when I use the same method while on a fullscreen application's Space, I get nonsense bounds: (0, 855, 480, 1).
I wouldn't care much about this if there was an easy way to tell if I'm currently at a fullscreen app's Space, because then I'd just draw a border around the screen (well... it would depend if the menu bar is showing...).
Is this a bug, or is there a reason for this behavior?
EDIT:
Figured out my problem. It's a bigger issue than I would have liked. The thing is the API goes through ALL NSWindows, even the ones that aren't, well, normal windows. Chrome's loading bar on the bottom is a window by itself, for example, and Mail also has some window on the top of the app. This is a problem because I have no way to differentiate the window that looks to be frontmost.
For my app, I would like to capture a specific window to intercept mouse events in it. I would have liked to be able to have the user press a hotkey and then click on the desired window to select, but there is no API to get the window under the cursor. I have no clue how to proceed.
Edit 2:
To better help people find a useful answer, changed title from: "Quartz Window Services returning wrong window bounds for fullscreen apps"
Have you got these methods defined for the window delegate?
- (NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize
{
NSRect mainDisplayRect = [[NSScreen mainScreen] frame];
CGSize cgScreenSize = CGSizeMake(mainDisplayRect.size.width, mainDisplayRect.size.height);
return cgScreenSize;
}
- (void)windowWillEnterFullScreen:(NSNotification *)notification
{
}
- (void)windowDidEnterFullScreen:(NSNotification *)notification
{
}
- (void)windowWillExitFullScreen:(NSNotification *)notification
{
}
I proceeded by going through the description dictionaries and checking if the current cursor position was inside the bounds of the windows. The first window to satisfy this would be the window right under the cursor, which is exactly what I needed.
Separately, to find the current top-most window, I used the iChat Apple example of the Accessibility API to register ApplicationActivatedNotification and MainWindowDidChangeNotifications. Both notifications combined would let me keep track of the main window of the active app (top-most). To get the bounds in this case, I just got the main window's position and size using the Accessibility API.

Mac App Store Dialogs vs Full Screen Window

My app got rejected because the dialogs to handle in-app purchases are behind my transparent full screen window. You can still click them, but it's not user-friendly.
How would I handle this? Is there a way to alter the way these dialogs are presented, or should I change the properties of my own window?
I'm talking about these dialogs (the grid is what's drawn on my main window) :
You can set the window level to a lower value so the dialogs appear on top when starting the store request and reset it to it's previous value after the request completes. Or you could exit full screen mode to make the store request. They may be more annoyed by the transparent window which can be confusing more than the window order.
This works for me
#interface FullscreenWindow : NSWindow
#end
#implementation FullscreenWindow
-(id) init
{
// some init code here...
[self setLevel:NSMainMenuWindowLevel+1];
return self;
}
#end

NSStatusWindowLevel disabled when presenting window sheet

I'm using an NSWindow and set it's level to NSStatusWindowLevel :
[aWindow setLevel:NSStatusWindowLevel];
Now, when I present a sheet (self is my sheet window)
modalAnswer = 0;
[NSApp beginSheet:self modalForWindow:aWindow modalDelegate:self didEndSelector:NULL contextInfo:nil];
[self makeKeyAndOrderFront:nil];
then the window doesn't show up above the dock, it hides underneath (meaning that NSStatusWindowLevel doesn't work anymore).
I've tried changing the level of the sheet window, but it won't work.
What's causing this issue?
I asked for technical support and they found it was a silly mistake : sheets normally are modal, but I was making it modal myself too.
The combination of beginModalSessionForWindow and runModalSession is the issue here.
It appears to be servicing the default run loop which is causing the menu bar and Dock to appear over your window.
I'm a bit confused as to why you are calling beginSheet:modalForWindow, and then using NSApp's beginModalSessionForWindow. Why do you manually add a modal session? Sheets are automatically modal to whatever window it is attached to. I am used to seeing the use of "beginModalSessionForWindow" without sheets on top of them.

Cocoa screen saver config panel floating freely

I'm writing a screen saver using Cocoa's ScreenSaver API. It's compiled for 64-bit arch and I'm running it on Lion.
In order to enable configuration, I have added the following to the main view:
- (BOOL)hasConfigureSheet
{
return YES;
}
- (NSWindow*)configureSheet
{
if (configureSheet == nil) {
if (![NSBundle loadNibNamed: #"WTConfigureSheet" owner: self]) {
NSLog(#"Failed to load config sheet");
return nil;
}
}
ScreenSaverDefaults *defaults =
[ScreenSaverDefaults defaultsForModuleWithName: WTModuleName];
backgroundColorWell.color = [defaults objectForKey: #"BackgroundColor"];
lightLetterColorWell.color = [defaults objectForKey: #"LightLetterColor"];
darkLetterColorWell.color = [defaults objectForKey: #"DarkLetterColor"];
return configureSheet;
}
After installing the saver freshly, clicking "Options" makes the config sheet appear not as a sheet, but floating freely on the screen, without a border. Otherwise, it works correctly and disappears after being dismissed.
When I click "Options" a second time, the config sheet appears again, this time correctly as a sheet of the preferences window. It then immediately freezes, so that I can't click any of its controls.
Does anyone have an idea what causes this behavior?
I had the same problem as you today and it took me quite some time to figure this one out, so here's my solution:
I discovered that the NSWindow appears as soon as you call loadNibNamed:owner:. So there had to be some sort of mechanism to automatically open windows from nibs.
So I re-checked the nib and saw that there is an option called "Visible At Launch" on the attribute inspector pane which is checked by default.
The solution is very simple: just uncheck that checkbox and it works as expected.
I find it easy to overlook since you expect the window to open, but it actually opens twice (once automatically and a second time because System Preferences.app shows it as a sheet) which leads to the glitches.
Another problem that could happen, depending on how you defined the ivar / property on your class is that after the first close and re-open of the window it just freezes.
This is because per default the window releases itself when closed.
So be sure to also uncheck "Release When Closed" in interface builder.
For this code to work as written, you need to create an IBOutlet of type NSWindow* named configureSheet in your main view's header file, save that file so Interface Builder can see the change, then load WTConfigureSheet.xib in Interface Builder and connect up the toplevel window component to Files Owner -> configureSheet.

Closing an NSWindow

I have a NSWindow that hosts a WebView that Ive hooked up to a script handler.
Now, when the user clicks a button on a control on the WebView it calls a Objective C method on my object.
In this specific case, the action of the button is to try and close the window hosting the WebView
[[webView window] close];
This usually works, but sometimes i get a SEGFAULT or some other access violation as a result of the event loop trying to dispatcha mouse message to the now destroyed view.
The callstack is horrible when I try to close the window, the even loop has called the window has called the webView, has called my script delegate when I try and close the window. Destruction of an object from a callback from that object is generally, well, dangerous, but I can't figure out how windows should safely be closed as a result of users interacting with views on them.
Istead of closing, can't you try out the API
- (void)orderOut:(id)sender
just check whether your window is visible and orderout that window
if([[webView window] isVisible])
[[webView window] orderOut:self];
The callstack is horrible when I try to close the window, the even loop has called the window has called the webView, has called my script delegate when I try and close the window. Destruction of an object from a callback from that object is generally, well, dangerous, but I can't figure out how windows should safely be closed as a result of users interacting with views on them.
You can use performSelector:withObject:afterDelay: to put off closing the window until 0.0 seconds after the button hit.
In this specific case, the action of the button is to try and close the window hosting the WebView
[[webView window] close];
This usually works, but sometimes i get a SEGFAULT or some other access violation as a result of the event loop trying to dispatcha mouse message to the now destroyed view.
That's not likely. The event loop will only dispatch an event for a window that exists; if you have closed and thereby destroyed a window, no event can arrive at that window, nor at any view that may once have been in it.
It would help if you would edit your question to include the stack trace for that crash.
I know this is an old question, but I'm having a similar issue and I suspect the accepted answer is missing the point. I believe the window hosting the WebView is still one or more of the delegates of the WebView, and delegate methods are being called after the WebView finishes loading, which is after the window is closed.
I was looking for the right way to resolve this… I'll keep looking. :-)

Resources