Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / tabs / tab_window_controller.mm
1 // Copyright (c) 2012 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 "chrome/browser/ui/cocoa/tabs/tab_window_controller.h"
6
7 #include "base/logging.h"
8 #import "chrome/browser/ui/cocoa/browser_window_layout.h"
9 #import "chrome/browser/ui/cocoa/fast_resize_view.h"
10 #import "chrome/browser/ui/cocoa/framed_browser_window.h"
11 #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
12 #import "chrome/browser/ui/cocoa/themed_window.h"
13 #import "chrome/browser/ui/cocoa/version_independent_window.h"
14 #import "ui/base/cocoa/focus_tracker.h"
15 #include "ui/base/theme_provider.h"
16
17 @interface TabWindowController(PRIVATE)
18 - (void)setUseOverlay:(BOOL)useOverlay;
19 @end
20
21 @interface TabWindowOverlayWindow : NSWindow
22 @end
23
24 @implementation TabWindowOverlayWindow
25
26 - (ui::ThemeProvider*)themeProvider {
27   if ([self parentWindow])
28     return [[[self parentWindow] windowController] themeProvider];
29   return NULL;
30 }
31
32 - (ThemedWindowStyle)themedWindowStyle {
33   if ([self parentWindow])
34     return [[[self parentWindow] windowController] themedWindowStyle];
35   return NO;
36 }
37
38 - (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment {
39   if ([self parentWindow]) {
40     return [[[self parentWindow] windowController]
41         themeImagePositionForAlignment:alignment];
42   }
43   return NSZeroPoint;
44 }
45
46 @end
47
48 @implementation TabWindowController
49
50 - (id)initTabWindowControllerWithTabStrip:(BOOL)hasTabStrip {
51   NSRect contentRect = NSMakeRect(60, 229, 750, 600);
52   base::scoped_nsobject<FramedBrowserWindow> window(
53       [[FramedBrowserWindow alloc] initWithContentRect:contentRect
54                                            hasTabStrip:hasTabStrip]);
55   [self moveContentViewToBack:[window contentView]];
56   [window setReleasedWhenClosed:YES];
57   [window setAutorecalculatesKeyViewLoop:YES];
58
59   if ((self = [super initWithWindow:window])) {
60     [[self window] setDelegate:self];
61
62     tabContentArea_.reset([[FastResizeView alloc] initWithFrame:
63         NSMakeRect(0, 0, 750, 600)]);
64     [tabContentArea_ setAutoresizingMask:NSViewWidthSizable |
65                                          NSViewHeightSizable];
66     [[[self window] contentView] addSubview:tabContentArea_];
67
68     tabStripView_.reset([[TabStripView alloc]
69         initWithFrame:NSMakeRect(0, 0, 750, chrome::kTabStripHeight)]);
70     [tabStripView_ setAutoresizingMask:NSViewWidthSizable |
71                                        NSViewMinYMargin];
72     if (hasTabStrip)
73       [self insertTabStripView:tabStripView_ intoWindow:[self window]];
74   }
75   return self;
76 }
77
78 - (TabStripView*)tabStripView {
79   return tabStripView_;
80 }
81
82 - (FastResizeView*)tabContentArea {
83   return tabContentArea_;
84 }
85
86 - (void)removeOverlay {
87   [self setUseOverlay:NO];
88   if (closeDeferred_) {
89     // See comment in BrowserWindowCocoa::Close() about orderOut:.
90     [[self window] orderOut:self];
91     [[self window] performClose:self];  // Autoreleases the controller.
92   }
93 }
94
95 - (void)showOverlay {
96   [self setUseOverlay:YES];
97 }
98
99 // If |useOverlay| is YES, creates a new overlay window and puts the tab strip
100 // and the content area inside of it. This allows it to have a different opacity
101 // from the title bar. If NO, returns everything to the previous state and
102 // destroys the overlay window until it's needed again. The tab strip and window
103 // contents are returned to the original window.
104 - (void)setUseOverlay:(BOOL)useOverlay {
105   [NSObject cancelPreviousPerformRequestsWithTarget:self
106                                            selector:@selector(removeOverlay)
107                                              object:nil];
108   NSWindow* window = [self window];
109   if (useOverlay && !overlayWindow_) {
110     DCHECK(!originalContentView_);
111
112     overlayWindow_ = [[TabWindowOverlayWindow alloc]
113                          initWithContentRect:[window frame]
114                                    styleMask:NSBorderlessWindowMask
115                                      backing:NSBackingStoreBuffered
116                                        defer:YES];
117     [overlayWindow_ setTitle:@"overlay"];
118     [overlayWindow_ setBackgroundColor:[NSColor clearColor]];
119     [overlayWindow_ setOpaque:NO];
120     [overlayWindow_ setDelegate:self];
121
122     originalContentView_ = [window contentView];
123     [window addChildWindow:overlayWindow_ ordered:NSWindowAbove];
124
125     // Explicitly set the responder to be nil here (for restoring later).
126     // If the first responder were to be left non-nil here then
127     // [RenderWidgethostViewCocoa resignFirstResponder] would be called,
128     // followed by RenderWidgetHost::Blur(), which would result in an unexpected
129     // loss of focus.
130     focusBeforeOverlay_.reset([[FocusTracker alloc] initWithWindow:window]);
131     [window makeFirstResponder:nil];
132
133     // Move the original window's tab strip view and content view to the overlay
134     // window. The content view is added as a subview of the overlay window's
135     // content view (rather than using setContentView:) because the overlay
136     // window has a different content size (due to it being borderless).
137     [[overlayWindow_ cr_windowView] addSubview:[self tabStripView]];
138     [[overlayWindow_ contentView] addSubview:originalContentView_];
139
140     [overlayWindow_ orderFront:nil];
141   } else if (!useOverlay && overlayWindow_) {
142     DCHECK(originalContentView_);
143
144     // Return the original window's tab strip view and content view to their
145     // places. The TabStripView always needs to be in front of the window's
146     // content view and therefore it should always be added after the content
147     // view is set.
148     [window setContentView:originalContentView_];
149     [self moveContentViewToBack:originalContentView_];
150     [self insertTabStripView:[self tabStripView] intoWindow:window];
151     [[window cr_windowView] updateTrackingAreas];
152
153     [focusBeforeOverlay_ restoreFocusInWindow:window];
154     focusBeforeOverlay_.reset();
155
156     [window display];
157     [window removeChildWindow:overlayWindow_];
158
159     [overlayWindow_ orderOut:nil];
160     [overlayWindow_ release];
161     overlayWindow_ = nil;
162     originalContentView_ = nil;
163   } else {
164     NOTREACHED();
165   }
166 }
167
168 - (NSWindow*)overlayWindow {
169   return overlayWindow_;
170 }
171
172 - (BOOL)shouldConstrainFrameRect {
173   // If we currently have an overlay window, do not attempt to change the
174   // window's size, as our overlay window doesn't know how to resize properly.
175   return overlayWindow_ == nil;
176 }
177
178 - (BOOL)canReceiveFrom:(TabWindowController*)source {
179   // subclass must implement
180   NOTIMPLEMENTED();
181   return NO;
182 }
183
184 - (void)moveTabViews:(NSArray*)views
185       fromController:(TabWindowController*)dragController {
186   NOTIMPLEMENTED();
187 }
188
189 - (NSArray*)tabViews {
190   NOTIMPLEMENTED();
191   return nil;
192 }
193
194 - (NSView*)activeTabView {
195   NOTIMPLEMENTED();
196   return nil;
197 }
198
199 - (void)layoutTabs {
200   // subclass must implement
201   NOTIMPLEMENTED();
202 }
203
204 - (TabWindowController*)detachTabsToNewWindow:(NSArray*)tabViews
205                                    draggedTab:(NSView*)draggedTab {
206   // subclass must implement
207   NOTIMPLEMENTED();
208   return NULL;
209 }
210
211 - (void)insertPlaceholderForTab:(TabView*)tab frame:(NSRect)frame {
212   [self showNewTabButton:NO];
213 }
214
215 - (void)removePlaceholder {
216   [self showNewTabButton:YES];
217 }
218
219 - (BOOL)isDragSessionActive {
220   NOTIMPLEMENTED();
221   return NO;
222 }
223
224 - (BOOL)tabDraggingAllowed {
225   return YES;
226 }
227
228 - (BOOL)tabTearingAllowed {
229   return YES;
230 }
231
232 - (BOOL)windowMovementAllowed {
233   return YES;
234 }
235
236 - (BOOL)isTabFullyVisible:(TabView*)tab {
237   // Subclasses should implement this, but it's not necessary.
238   return YES;
239 }
240
241 - (void)showNewTabButton:(BOOL)show {
242   // subclass must implement
243   NOTIMPLEMENTED();
244 }
245
246 - (void)detachTabView:(NSView*)view {
247   // subclass must implement
248   NOTIMPLEMENTED();
249 }
250
251 - (NSInteger)numberOfTabs {
252   // subclass must implement
253   NOTIMPLEMENTED();
254   return 0;
255 }
256
257 - (BOOL)hasLiveTabs {
258   // subclass must implement
259   NOTIMPLEMENTED();
260   return NO;
261 }
262
263 - (NSString*)activeTabTitle {
264   // subclass must implement
265   NOTIMPLEMENTED();
266   return @"";
267 }
268
269 - (BOOL)hasTabStrip {
270   // Subclasses should implement this.
271   NOTIMPLEMENTED();
272   return YES;
273 }
274
275 - (BOOL)isTabDraggable:(NSView*)tabView {
276   // Subclasses should implement this.
277   NOTIMPLEMENTED();
278   return YES;
279 }
280
281 // Tell the window that it needs to call performClose: as soon as the current
282 // drag is complete. This prevents a window (and its overlay) from going away
283 // during a drag.
284 - (void)deferPerformClose {
285   closeDeferred_ = YES;
286 }
287
288 - (void)moveContentViewToBack:(NSView*)cv {
289   base::scoped_nsobject<NSView> contentView([cv retain]);
290   NSView* superview = [contentView superview];
291   [contentView removeFromSuperview];
292   [superview addSubview:contentView positioned:NSWindowBelow relativeTo:nil];
293 }
294
295 - (void)insertTabStripView:(NSView*)tabStripView intoWindow:(NSWindow*)window {
296   NSView* contentParent = [window cr_windowView];
297   if (contentParent == [[window contentView] superview]) {
298     // Add the tab strip directly above the content view, if they are siblings.
299     [contentParent addSubview:tabStripView
300                    positioned:NSWindowAbove
301                    relativeTo:[window contentView]];
302   } else {
303     [contentParent addSubview:tabStripView];
304   }
305 }
306
307 // Called when the size of the window content area has changed. Override to
308 // position specific views. Base class implementation does nothing.
309 - (void)layoutSubviews {
310   NOTIMPLEMENTED();
311 }
312
313 @end