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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
|
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/mac_util.h"
#include "base/sys_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h" // IDC_*
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#import "chrome/browser/cocoa/bookmark_bar_controller.h"
#import "chrome/browser/cocoa/browser_window_cocoa.h"
#import "chrome/browser/cocoa/browser_window_controller.h"
#import "chrome/browser/cocoa/find_bar_cocoa_controller.h"
#include "chrome/browser/cocoa/find_bar_bridge.h"
#import "chrome/browser/cocoa/status_bubble_mac.h"
#import "chrome/browser/cocoa/tab_strip_model_observer_bridge.h"
#import "chrome/browser/cocoa/tab_strip_view.h"
#import "chrome/browser/cocoa/tab_strip_controller.h"
#import "chrome/browser/cocoa/tab_view.h"
#import "chrome/browser/cocoa/toolbar_controller.h"
#include "chrome/common/pref_service.h"
namespace {
// Size of the gradient. Empirically determined so that the gradient looks
// like what the heuristic does when there are just a few tabs.
const int kWindowGradientHeight = 24;
}
@interface BrowserWindowController(Private)
- (void)positionToolbar;
// Leopard's gradient heuristic gets confused by our tabs and makes the title
// gradient jump when creating a tab that is less than a tab width from the
// right side of the screen. This function disables Leopard's gradient
// heuristic.
- (void)fixWindowGradient;
// Called by the Notification Center whenever the tabContentArea's
// frame changes. Re-positions the bookmark bar and the find bar.
- (void)tabContentAreaFrameChanged:(id)sender;
// Saves the window's position in the local state preferences.
- (void)saveWindowPositionIfNeeded;
// Saves the window's position to the given pref service.
- (void)saveWindowPositionToPrefs:(PrefService*)prefs;
// We need to adjust where sheets come out of the window, as by default they
// erupt from the omnibox, which is rather weird.
- (NSRect)window:(NSWindow *)window
willPositionSheet:(NSWindow *)sheet
usingRect:(NSRect)defaultSheetRect;
@end
@implementation BrowserWindowController
// Load the browser window nib and do any Cocoa-specific initialization.
// Takes ownership of |browser|. Note that the nib also sets this controller
// up as the window's delegate.
- (id)initWithBrowser:(Browser*)browser {
return [self initWithBrowser:browser takeOwnership:YES];
}
// Private (TestingAPI) init routine with testing options.
- (id)initWithBrowser:(Browser*)browser takeOwnership:(BOOL)ownIt {
// Use initWithWindowNibPath:: instead of initWithWindowNibName: so we
// can override it in a unit test.
NSString *nibpath = [mac_util::MainAppBundle()
pathForResource:@"BrowserWindow"
ofType:@"nib"];
if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
DCHECK(browser);
browser_.reset(browser);
ownsBrowser_ = ownIt;
tabObserver_.reset(
new TabStripModelObserverBridge(browser->tabstrip_model(), self));
windowShim_.reset(new BrowserWindowCocoa(browser, self, [self window]));
// The window is now fully realized and |-windowDidLoad:| has been
// called. We shouldn't do much in wDL because |windowShim_| won't yet
// be initialized (as it's called in response to |[self window]| above).
// Retain it per the comment in the header.
window_.reset([[self window] retain]);
// Since we don't have a standard resize control, Cocoa won't enable the
// zoom (green) button on the titlebar for us. Grab it and enable it
// manually. Note that when launched from XCode, the doesn't work for the
// first window (and only the first window). There's some activation
// wonkiness there, since XCode stays active and the menus don't switch
// either. It always works when launched from the Finder.
NSButton* zoomButton =
[[self window] standardWindowButton:NSWindowZoomButton];
[zoomButton setEnabled:YES];
// Register ourselves for frame changed notifications from the
// tabContentArea.
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(tabContentAreaFrameChanged:)
name:nil
object:[self tabContentArea]];
// Get the most appropriate size for the window. The window shim will handle
// flipping the coordinates for us so we can use it to save some code.
gfx::Rect windowRect = browser_->GetSavedWindowBounds();
windowShim_->SetBounds(windowRect);
// Create a controller for the tab strip, giving it the model object for
// this window's Browser and the tab strip view. The controller will handle
// registering for the appropriate tab notifications from the back-end and
// managing the creation of new tabs.
tabStripController_.reset([[TabStripController alloc]
initWithView:[self tabStripView]
switchView:[self tabContentArea]
model:browser_->tabstrip_model()]);
// Create a controller for the toolbar, giving it the toolbar model object
// and the toolbar view from the nib. The controller will handle
// registering for the appropriate command state changes from the back-end.
toolbarController_.reset([[ToolbarController alloc]
initWithModel:browser->toolbar_model()
commands:browser->command_updater()
profile:browser->profile()]);
[self positionToolbar];
// After we've adjusted the toolbar, create a controller for the bookmark
// bar. It will show/hide itself based on the global preference and handle
// positioning itself (if visible) above the content area, which is why
// we need to do it after we've placed the toolbar.
bookmarkController_.reset([[BookmarkBarController alloc]
initWithProfile:browser_->profile()
contentArea:[self tabContentArea]]);
[self fixWindowGradient];
// Create the bridge for the status bubble.
statusBubble_.reset(new StatusBubbleMac([self window]));
}
return self;
}
- (void)dealloc {
browser_->CloseAllTabs();
// Under certain testing configurations we may not actually own the browser.
if (ownsBrowser_ == NO)
browser_.release();
[super dealloc];
}
// Access the C++ bridge between the NSWindow and the rest of Chromium
- (BrowserWindow*)browserWindow {
return windowShim_.get();
}
- (void)destroyBrowser {
[NSApp removeWindowsItem:[self window]];
// We need the window to go away now.
[self autorelease];
}
// Called when the window meets the criteria to be closed (ie,
// |-windowShoudlClose:| returns YES). We must be careful to preserve the
// semantics of BrowserWindow::Close() and not call the Browser's dtor directly
// from this method.
- (void)windowWillClose:(NSNotification *)notification {
DCHECK(!browser_->tabstrip_model()->count());
// We can't actually use |-autorelease| here because there's an embedded
// run loop in the |-performClose:| which contains its own autorelease pool.
// Instead we use call it after a zero-length delay, which gets us back
// to the main event loop.
[self performSelector:@selector(autorelease)
withObject:nil
afterDelay:0];
}
// Called when the user wants to close a window or from the shutdown process.
// The Browser object is in control of whether or not we're allowed to close. It
// may defer closing due to several states, such as onUnload handlers needing to
// be fired. If closing is deferred, the Browser will handle the processing
// required to get us to the closing state and (by watching for all the tabs
// going away) will again call to close the window when it's finally ready.
- (BOOL)windowShouldClose:(id)sender {
// Give beforeunload handlers the chance to cancel the close before we hide
// the window below.
if (!browser_->ShouldCloseWindow())
return NO;
// saveWindowPositionIfNeeded: only works if we are the last active
// window, but orderOut: ends up activating another window, so we
// have to save the window position before we call orderOut:.
[self saveWindowPositionIfNeeded];
if (!browser_->tabstrip_model()->empty()) {
// Tab strip isn't empty. Hide the frame (so it appears to have closed
// immediately) and close all the tabs, allowing the renderers to shut
// down. When the tab strip is empty we'll be called back again.
[[self window] orderOut:self];
browser_->OnWindowClosing();
return NO;
}
// the tab strip is empty, it's ok to close the window
return YES;
}
// Called right after our window became the main window.
- (void)windowDidBecomeMain:(NSNotification *)notification {
BrowserList::SetLastActive(browser_.get());
[self saveWindowPositionIfNeeded];
}
// Called when the user clicks the zoom button (or selects it from the Window
// menu). Zoom to the appropriate size based on the content. Make sure we
// enforce a minimum width to ensure websites with small intrinsic widths
// (such as google.com) don't end up with a wee window. Enforce a max width
// that leaves room for icons on the right side. Use the full (usable) height
// regardless.
- (NSRect)windowWillUseStandardFrame:(NSWindow*)window
defaultFrame:(NSRect)frame {
const int kMinimumIntrinsicWidth = 700;
const int kScrollbarWidth = 16;
const int kSpaceForIcons = 50;
const NSSize screenSize = [[window screen] visibleFrame].size;
// Always leave room on the right for icons.
const int kMaxWidth = screenSize.width - kSpaceForIcons;
TabContents* contents = browser_->tabstrip_model()->GetSelectedTabContents();
if (contents) {
int intrinsicWidth = contents->view()->preferred_width() + kScrollbarWidth;
int tempWidth = std::max(intrinsicWidth, kMinimumIntrinsicWidth);
frame.size.width = std::min(tempWidth, kMaxWidth);
frame.size.height = screenSize.height;
}
return frame;
}
// Update a toggle state for an NSMenuItem if modified.
// Take care to insure |item| looks like a NSMenuItem.
// Called by validateUserInterfaceItem:.
- (void)updateToggleStateWithTag:(NSInteger)tag forItem:(id)item {
if (![item respondsToSelector:@selector(state)] ||
![item respondsToSelector:@selector(setState:)])
return;
// On Windows this logic happens in bookmark_bar_view.cc. On the
// Mac we're a lot more MVC happy so we've moved it into a
// controller. To be clear, this simply updates the menu item; it
// does not display the bookmark bar itself.
if (tag == IDC_SHOW_BOOKMARK_BAR) {
bool toggled = windowShim_->IsBookmarkBarVisible();
NSInteger oldState = [item state];
NSInteger newState = toggled ? NSOnState : NSOffState;
if (oldState != newState)
[item setState:newState];
}
}
// Called to validate menu and toolbar items when this window is key. All the
// items we care about have been set with the |commandDispatch:| action and
// a target of FirstResponder in IB. If it's not one of those, let it
// continue up the responder chain to be handled elsewhere. We pull out the
// tag as the cross-platform constant to differentiate and dispatch the
// various commands.
// NOTE: we might have to handle state for app-wide menu items,
// although we could cheat and directly ask the app controller if our
// command_updater doesn't support the command. This may or may not be an issue,
// too early to tell.
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
SEL action = [item action];
BOOL enable = NO;
if (action == @selector(commandDispatch:)) {
NSInteger tag = [item tag];
if (browser_->command_updater()->SupportsCommand(tag)) {
// Generate return value (enabled state)
enable = browser_->command_updater()->IsCommandEnabled(tag) ? YES : NO;
// If the item is toggleable, find it's toggle state and
// try to update it. This is a little awkward, but the alternative is
// to check after a commandDispatch, which seems worse.
[self updateToggleStateWithTag:tag forItem:item];
}
}
return enable;
}
// Called when the user picks a menu or toolbar item when this window is key.
// Calls through to the browser object to execute the command. This assumes that
// the command is supported and doesn't check, otherwise it would have been
// disabled in the UI in validateUserInterfaceItem:.
- (void)commandDispatch:(id)sender {
NSInteger tag = [sender tag];
browser_->ExecuteCommand(tag);
}
- (LocationBar*)locationBar {
return [toolbarController_ locationBar];
}
- (StatusBubble*)statusBubble {
return statusBubble_.get();
}
- (void)updateToolbarWithContents:(TabContents*)tab
shouldRestoreState:(BOOL)shouldRestore {
[toolbarController_ updateToolbarWithContents:tab
shouldRestoreState:shouldRestore];
}
- (void)setStarredState:(BOOL)isStarred {
[toolbarController_ setStarredState:isStarred];
}
// Return the rect, in WebKit coordinates (flipped), of the window's grow box
// in the coordinate system of the content area of the currently selected tab.
// |windowGrowBox| needs to be in the window's coordinate system.
- (NSRect)selectedTabGrowBoxRect {
return [tabStripController_ selectedTabGrowBoxRect];
}
// Move a given tab view to the location of the current placeholder. If there is
// no placeholder, it will go at the end. |controller| is the window controller
// of a tab being dropped from a different window. It will be nil if the drag is
// within the window, otherwise the tab is removed from that window before being
// placed into this one. The implementation will call |-removePlaceholder| since
// the drag is now complete. This also calls |-layoutTabs| internally so
// clients do not need to call it again.
- (void)moveTabView:(NSView*)view
fromController:(TabWindowController*)dragController {
if (dragController) {
// Moving between windows. Figure out the TabContents to drop into our tab
// model from the source window's model.
BOOL isBrowser =
[dragController isKindOfClass:[BrowserWindowController class]];
DCHECK(isBrowser);
if (!isBrowser) return;
BrowserWindowController* dragBWC = (BrowserWindowController*)dragController;
int index = [dragBWC->tabStripController_ indexForTabView:view];
TabContents* contents =
dragBWC->browser_->tabstrip_model()->GetTabContentsAt(index);
// Now that we have enough information about the tab, we can remove it from
// the dragging window. We need to do this *before* we add it to the new
// window as this will removes the TabContents' delegate.
[dragController detachTabView:view];
// Deposit it into our model at the appropriate location (it already knows
// where it should go from tracking the drag). Doing this sets the tab's
// delegate to be the Browser.
[tabStripController_ dropTabContents:contents];
} else {
// Moving within a window.
int index = [tabStripController_ indexForTabView:view];
[tabStripController_ moveTabFromIndex:index];
}
// Remove the placeholder since the drag is now complete.
[self removePlaceholder];
}
// Tells the tab strip to forget about this tab in preparation for it being
// put into a different tab strip, such as during a drop on another window.
- (void)detachTabView:(NSView*)view {
int index = [tabStripController_ indexForTabView:view];
browser_->tabstrip_model()->DetachTabContentsAt(index);
}
- (NSView *)selectedTabView {
return [tabStripController_ selectedTabView];
}
- (void)setIsLoading:(BOOL)isLoading {
[toolbarController_ setIsLoading:isLoading];
}
// Called to start/stop the loading animations.
- (void)updateLoadingAnimations:(BOOL)animate {
if (animate) {
// TODO(pinkerton): determine what throbber animation is necessary and
// start a timer to periodically update. Windows tells the tab strip to
// do this. It uses a single timer to coalesce the multiple things that
// could be updating. http://crbug.com/8281
} else {
// TODO(pinkerton): stop the timer.
}
}
// Make the location bar the first responder, if possible.
- (void)focusLocationBar {
[toolbarController_ focusLocationBar];
}
- (void)layoutTabs {
[tabStripController_ layoutTabs];
}
- (TabWindowController*)detachTabToNewWindow:(TabView*)tabView {
// Fetch the tab contents for the tab being dragged
int index = [tabStripController_ indexForTabView:tabView];
TabContents* contents = browser_->tabstrip_model()->GetTabContentsAt(index);
// Set the window size. Need to do this before we detach the tab so it's
// still in the window. We have to flip the coordinates as that's what
// is expected by the Browser code.
NSWindow* sourceWindow = [tabView window];
NSRect windowRect = [sourceWindow frame];
NSScreen* screen = [sourceWindow screen];
windowRect.origin.y =
[screen frame].size.height - windowRect.size.height -
windowRect.origin.y;
gfx::Rect browserRect(windowRect.origin.x, windowRect.origin.y,
windowRect.size.width, windowRect.size.height);
NSRect tabRect = [tabView frame];
// Detach it from the source window, which just updates the model without
// deleting the tab contents. This needs to come before creating the new
// Browser because it clears the TabContents' delegate, which gets hooked
// up during creation of the new window.
browser_->tabstrip_model()->DetachTabContentsAt(index);
// Create the new window with a single tab in its model, the one being
// dragged.
DockInfo dockInfo;
Browser* newBrowser =
browser_->tabstrip_model()->TearOffTabContents(contents,
browserRect,
dockInfo);
// Get the new controller by asking the new window for its delegate.
TabWindowController* controller =
[newBrowser->window()->GetNativeHandle() delegate];
DCHECK(controller && [controller isKindOfClass:[TabWindowController class]]);
// Force the added tab to the right size (remove stretching)
tabRect.size.height = [TabStripController defaultTabHeight];
NSView *newTabView = [controller selectedTabView];
[newTabView setFrame:tabRect];
return controller;
}
- (void)insertPlaceholderForTab:(TabView*)tab
frame:(NSRect)frame
yStretchiness:(CGFloat)yStretchiness {
[tabStripController_ insertPlaceholderForTab:tab
frame:frame
yStretchiness:yStretchiness];
}
- (void)removePlaceholder {
[tabStripController_ insertPlaceholderForTab:nil
frame:NSZeroRect
yStretchiness:0];
}
- (BOOL)isBookmarkBarVisible {
return [bookmarkController_ isBookmarkBarVisible];
}
- (void)toggleBookmarkBar {
[bookmarkController_ toggleBookmarkBar];
}
- (void)addFindBar:(FindBarCocoaController*)findBarCocoaController {
// Shouldn't call addFindBar twice.
DCHECK(!findBarCocoaController_.get());
// Create a controller for the findbar.
findBarCocoaController_.reset([findBarCocoaController retain]);
[[[self window] contentView] addSubview:[findBarCocoaController_ view]];
[findBarCocoaController_ positionFindBarView:[self tabContentArea]];
}
- (NSInteger)numberOfTabs {
return browser_->tabstrip_model()->count();
}
- (NSString*)selectedTabTitle {
TabContents* contents = browser_->tabstrip_model()->GetSelectedTabContents();
return base::SysUTF16ToNSString(contents->GetTitle());
}
- (void)selectTabWithContents:(TabContents*)newContents
previousContents:(TabContents*)oldContents
atIndex:(NSInteger)index
userGesture:(bool)wasUserGesture {
DCHECK(oldContents != newContents);
// Update various elements that are interested in knowing the current
// TabContents.
#if 0
// TODO(pinkerton):Update as more things become window-specific
infobar_container_->ChangeTabContents(new_contents);
contents_container_->SetTabContents(new_contents);
#endif
newContents->DidBecomeSelected();
// Change the entry in the Window menu to match the title of the
// currently selected tab. This will create an entry if one does
// not already exist.
[NSApp changeWindowsItem:[self window]
title:base::SysUTF16ToNSString(newContents->GetTitle())
filename:NO];
#if 0
// TODO(pinkerton):Update as more things become window-specific
// Update all the UI bits.
UpdateTitleBar();
toolbar_->SetProfile(new_contents->profile());
UpdateToolbar(new_contents, true);
UpdateUIForContents(new_contents);
#endif
}
- (void)tabChangedWithContents:(TabContents*)contents
atIndex:(NSInteger)index
loadingOnly:(BOOL)loading {
// Change the entry in the Window menu to match the new title of the tab,
// but only if this is the currently selected tab.
if (index == browser_->tabstrip_model()->selected_index()) {
[NSApp changeWindowsItem:[self window]
title:base::SysUTF16ToNSString(contents->GetTitle())
filename:NO];
}
}
@end
@interface NSWindow (NSPrivateApis)
// Note: These functions are private, use -[NSObject respondsToSelector:]
// before calling them.
- (void)setAutorecalculatesContentBorderThickness:(BOOL)b
forEdge:(NSRectEdge)e;
- (void)setContentBorderThickness:(CGFloat)b forEdge:(NSRectEdge)e;
@end
@implementation BrowserWindowController (Private)
// Position |toolbarView_| below the tab strip, but not as a sibling. The
// toolbar is part of the window's contentView, mainly because we want the
// opacity during drags to be the same as the web content.
- (void)positionToolbar {
NSView* contentView = [self tabContentArea];
NSRect contentFrame = [contentView frame];
NSView* toolbarView = [toolbarController_ view];
NSRect toolbarFrame = [toolbarView frame];
// Shrink the content area by the height of the toolbar.
contentFrame.size.height -= toolbarFrame.size.height;
[contentView setFrame:contentFrame];
// Move the toolbar above the content area, within the window's content view
// (as opposed to the tab strip, which is a sibling).
toolbarFrame.origin.y = NSMaxY(contentFrame);
toolbarFrame.origin.x = 0;
toolbarFrame.size.width = contentFrame.size.width;
[toolbarView setFrame:toolbarFrame];
[[[self window] contentView] addSubview:toolbarView];
}
- (void)fixWindowGradient {
NSWindow* win = [self window];
if ([win respondsToSelector:@selector(
setAutorecalculatesContentBorderThickness:forEdge:)] &&
[win respondsToSelector:@selector(
setContentBorderThickness:forEdge:)]) {
[win setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
[win setContentBorderThickness:kWindowGradientHeight forEdge:NSMaxYEdge];
}
}
- (void)tabContentAreaFrameChanged:(id)sender {
// TODO(rohitrao): This is triggered by window resizes also. Make
// sure we aren't doing anything wasteful in those cases.
[bookmarkController_ resizeBookmarkBar];
if (findBarCocoaController_.get()) {
[findBarCocoaController_ positionFindBarView:[self tabContentArea]];
}
}
- (void)saveWindowPositionIfNeeded {
if (browser_ != BrowserList::GetLastActive())
return;
if (!g_browser_process || !g_browser_process->local_state() ||
!browser_->ShouldSaveWindowPlacement())
return;
[self saveWindowPositionToPrefs:g_browser_process->local_state()];
}
- (void)saveWindowPositionToPrefs:(PrefService*)prefs {
// Window placements are stored relative to the work area bounds,
// not the monitor bounds.
NSRect workFrame = [[[self window] screen] visibleFrame];
// Start with the window's frame, which is in virtual coordinates.
// Subtract the origin of the visibleFrame to get the window frame
// relative to the work area.
gfx::Rect bounds(NSRectToCGRect([[self window] frame]));
bounds.Offset(-workFrame.origin.x, -workFrame.origin.y);
// Do some y twiddling to flip the coordinate system.
bounds.set_y(workFrame.size.height - bounds.y() - bounds.height());
DictionaryValue* windowPreferences = prefs->GetMutableDictionary(
browser_->GetWindowPlacementKey().c_str());
windowPreferences->SetInteger(L"left", bounds.x());
windowPreferences->SetInteger(L"top", bounds.y());
windowPreferences->SetInteger(L"right", bounds.right());
windowPreferences->SetInteger(L"bottom", bounds.bottom());
windowPreferences->SetBoolean(L"maximized", false);
windowPreferences->SetBoolean(L"always_on_top", false);
}
- (NSRect)window:(NSWindow *)window
willPositionSheet:(NSWindow *)sheet
usingRect:(NSRect)defaultSheetRect {
NSRect windowFrame = [window frame];
defaultSheetRect.origin.y = windowFrame.size.height - 10;
return defaultSheetRect;
}
// In addition to the tab strip and content area, which the superview's impl
// takes care of, we need to add the toolbar and bookmark bar to the
// overlay so they draw correctly when dragging out a new window.
- (NSArray*)viewsToMoveToOverlay {
NSArray* views = [super viewsToMoveToOverlay];
NSArray* browserViews =
[NSArray arrayWithObjects:[toolbarController_ view],
[bookmarkController_ view],
nil];
return [views arrayByAddingObjectsFromArray:browserViews];
}
@end
|