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