1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #import <Cocoa/Cocoa.h> 6 7 #import "chrome/browser/ui/cocoa/window_size_autosaver.h" 8 9 #include "chrome/browser/prefs/pref_service.h" 10 #include "chrome/browser/prefs/scoped_user_pref_update.h" 11 12 // If the window width stored in the prefs is smaller than this, the size is 13 // not restored but instead cleared from the profile -- to protect users from 14 // accidentally making their windows very small and then not finding them again. 15 const int kMinWindowWidth = 101; 16 17 // Minimum restored window height, see |kMinWindowWidth|. 18 const int kMinWindowHeight = 17; 19 20 @interface WindowSizeAutosaver (Private) 21 - (void)save:(NSNotification*)notification; 22 - (void)restore; 23 @end 24 25 @implementation WindowSizeAutosaver 26 27 - (id)initWithWindow:(NSWindow*)window 28 prefService:(PrefService*)prefs 29 path:(const char*)path { 30 if ((self = [super init])) { 31 window_ = window; 32 prefService_ = prefs; 33 path_ = path; 34 35 [self restore]; 36 [[NSNotificationCenter defaultCenter] 37 addObserver:self 38 selector:@selector(save:) 39 name:NSWindowDidMoveNotification 40 object:window_]; 41 [[NSNotificationCenter defaultCenter] 42 addObserver:self 43 selector:@selector(save:) 44 name:NSWindowDidResizeNotification 45 object:window_]; 46 } 47 return self; 48 } 49 50 - (void)dealloc { 51 [[NSNotificationCenter defaultCenter] removeObserver:self]; 52 [super dealloc]; 53 } 54 55 - (void)save:(NSNotification*)notification { 56 DictionaryPrefUpdate update(prefService_, path_); 57 DictionaryValue* windowPrefs = update.Get(); 58 NSRect frame = [window_ frame]; 59 if ([window_ styleMask] & NSResizableWindowMask) { 60 // Save the origin of the window. 61 windowPrefs->SetInteger("left", NSMinX(frame)); 62 windowPrefs->SetInteger("right", NSMaxX(frame)); 63 // windows's and linux's profiles have top < bottom due to having their 64 // screen origin in the upper left, while cocoa's is in the lower left. To 65 // keep the top < bottom invariant, store top in bottom and vice versa. 66 windowPrefs->SetInteger("top", NSMinY(frame)); 67 windowPrefs->SetInteger("bottom", NSMaxY(frame)); 68 } else { 69 // Save the origin of the window. 70 windowPrefs->SetInteger("x", frame.origin.x); 71 windowPrefs->SetInteger("y", frame.origin.y); 72 } 73 } 74 75 - (void)restore { 76 // Get the positioning information. 77 const DictionaryValue* windowPrefs = prefService_->GetDictionary(path_); 78 if ([window_ styleMask] & NSResizableWindowMask) { 79 int x1, x2, y1, y2; 80 if (!windowPrefs->GetInteger("left", &x1) || 81 !windowPrefs->GetInteger("right", &x2) || 82 !windowPrefs->GetInteger("top", &y1) || 83 !windowPrefs->GetInteger("bottom", &y2)) { 84 return; 85 } 86 if (x2 - x1 < kMinWindowWidth || y2 - y1 < kMinWindowHeight) { 87 // Windows should never be very small. 88 DictionaryPrefUpdate update(prefService_, path_); 89 DictionaryValue* mutableWindowPrefs = update.Get(); 90 mutableWindowPrefs->Remove("left", NULL); 91 mutableWindowPrefs->Remove("right", NULL); 92 mutableWindowPrefs->Remove("top", NULL); 93 mutableWindowPrefs->Remove("bottom", NULL); 94 } else { 95 [window_ setFrame:NSMakeRect(x1, y1, x2 - x1, y2 - y1) display:YES]; 96 97 // Make sure the window is on-screen. 98 [window_ cascadeTopLeftFromPoint:NSZeroPoint]; 99 } 100 } else { 101 int x, y; 102 if (!windowPrefs->GetInteger("x", &x) || 103 !windowPrefs->GetInteger("y", &y)) 104 return; // Nothing stored. 105 // Turn the origin (lower-left) into an upper-left window point. 106 NSPoint upperLeft = NSMakePoint(x, y + NSHeight([window_ frame])); 107 [window_ cascadeTopLeftFromPoint:upperLeft]; 108 } 109 } 110 111 @end 112 113