NSWindow autosave - position not saved on 2nd monitor

In Yosemite (and possibly earlier), the window frame autosave mechanism does not automatically position windows that have been moved from the primary display to a second monitor, or to any position that overlaps the second monitor.

Instead, the next time it is instantiated, the window is automatically positioned to the previous location (if there was a valid default position recorded) or the default for the window, or in the case of overlapping windows, a position that fits completely on the main screen.

This occurs regardless of whether the autosave name property is set on a window in Interface Builder or through NSWindowController. eg.

-(void)windowDidLoad
{
    [super windowDidLoad];
    [self setShouldCascadeWindows:NO];
    [self setWindowFrameAutosaveName:@"MyWindowAutoSaveName"];
}

      

Does anyone know of a workaround?

+3


source to share


1 answer


I wouldn't be able to restore the autosave for the second monitor. No amount of spanking will make it work. It will restore the first monitor to the same position as the window on the second monitor. To fix the problem, I ditched the autosave API and made my own.

When the window's windowWillClose: method is called, first save a BOOL that indicates whether the window has been enlarged in full screen mode. Then, if the window hasn't been zoomed in (more on that in a second), use NSStringFromRect and save the window rectangle.

-(void)windowWillClose:(NSNotification *)notification
{
  NSString  *mainWindowFrameString;

  [_defaults setObject:[NSNumber numberWithBool:[_flimFlamViewController windowIsFullScreen]] forKey:QUITTING_ZOOM_STATE];

  if ([_flimFlamViewController windowIsFullScreen] == NO) {
    mainWindowFrameString = NSStringFromRect([_ourWindow frame]);
    [_defaults setObject:mainWindowFrameString forKey:MAIN_WINDOW_FRAME];
    }

  [_defaults synchronize];

}

      

Conversely, when the window is created (perhaps in awakeFromNib :) loads a string from NSUserDefaults and uses NSRectFromString to get the bounds. Check frame sizes for zero to see if it was the first time you started the app. If the border is not all zeros, set the window border to this CGRect.

  mainWindowFrameString = [_defaults objectForKey:MAIN_WINDOW_FRAME];       // get the last saved window frame values
  mainWindowFrame = NSRectFromString(mainWindowFrameString);                // convert it to a CGRect

  if ((mainWindowFrame.size.width != 0) && (mainWindowFrame.size.height != 0)) {
    [_ourWindow setFrame:mainWindowFrame display:YES];
    }
  else {
    [_ourWindow center];
    }

      



To handle a full-screen window zoomed in when the window is closed, first save the frame position before it appears in full-screen mode - you will use this later when the window opens to place the window on the appropriate monitor.

-(void)windowWillEnterFullScreen:(NSNotification *)notification
{
  NSString  *mainWindowFrameString;

  // save the frame coordinates before going full screen

  mainWindowFrameString = NSStringFromRect([_ourWindow frame]);
  [_defaults setObject:mainWindowFrameString forKey:MAIN_WINDOW_FRAME];
}

      

Then in viewWillAppear: determine if the window needs to be scaled (the window has already been placed on the corresponding monitor at this point). toggleFullScreen: will result in the full screen of the window.

  lastZoomStateDefault = [_defaults objectForKey:QUITTING_ZOOM_STATE];
  _windowIsFullScreen = [lastZoomStateDefault boolValue];

  if (_windowIsFullScreen == YES) {
    [_window toggleFullScreen:nil];
    }

      

+3


source







All Articles