OLD | NEW |
| (Empty) |
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 #include "content/shell/shell.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/logging.h" | |
10 #import "base/mac/scoped_nsobject.h" | |
11 #include "base/strings/string_piece.h" | |
12 #include "base/strings/sys_string_conversions.h" | |
13 #include "content/public/browser/native_web_keyboard_event.h" | |
14 #include "content/public/browser/web_contents.h" | |
15 #include "content/public/browser/web_contents_view.h" | |
16 #include "content/shell/app/resource.h" | |
17 #import "ui/base/cocoa/underlay_opengl_hosting_window.h" | |
18 #include "url/gurl.h" | |
19 | |
20 #if !defined(MAC_OS_X_VERSION_10_7) || \ | |
21 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 | |
22 | |
23 enum { | |
24 NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7, | |
25 NSWindowCollectionBehaviorFullScreenAuxiliary = 1 << 8 | |
26 }; | |
27 | |
28 #endif // MAC_OS_X_VERSION_10_7 | |
29 | |
30 // Receives notification that the window is closing so that it can start the | |
31 // tear-down process. Is responsible for deleting itself when done. | |
32 @interface ContentShellWindowDelegate : NSObject<NSWindowDelegate> { | |
33 @private | |
34 content::Shell* shell_; | |
35 } | |
36 - (id)initWithShell:(content::Shell*)shell; | |
37 @end | |
38 | |
39 @implementation ContentShellWindowDelegate | |
40 | |
41 - (id)initWithShell:(content::Shell*)shell { | |
42 if ((self = [super init])) { | |
43 shell_ = shell; | |
44 } | |
45 return self; | |
46 } | |
47 | |
48 // Called when the window is about to close. Perform the self-destruction | |
49 // sequence by getting rid of the shell and removing it and the window from | |
50 // the various global lists. By returning YES, we allow the window to be | |
51 // removed from the screen. | |
52 - (BOOL)windowShouldClose:(id)window { | |
53 [window autorelease]; | |
54 delete shell_; | |
55 [self release]; | |
56 | |
57 return YES; | |
58 } | |
59 | |
60 - (void)performAction:(id)sender { | |
61 shell_->ActionPerformed([sender tag]); | |
62 } | |
63 | |
64 - (void)takeURLStringValueFrom:(id)sender { | |
65 shell_->URLEntered(base::SysNSStringToUTF8([sender stringValue])); | |
66 } | |
67 | |
68 @end | |
69 | |
70 @interface CrShellWindow : UnderlayOpenGLHostingWindow { | |
71 @private | |
72 content::Shell* shell_; | |
73 } | |
74 - (void)setShell:(content::Shell*)shell; | |
75 - (void)showDevTools:(id)sender; | |
76 @end | |
77 | |
78 @implementation CrShellWindow | |
79 | |
80 - (void)setShell:(content::Shell*)shell { | |
81 shell_ = shell; | |
82 } | |
83 | |
84 - (void)showDevTools:(id)sender { | |
85 shell_->ShowDevTools(); | |
86 } | |
87 | |
88 @end | |
89 | |
90 namespace { | |
91 | |
92 NSString* kWindowTitle = @"Content Shell"; | |
93 | |
94 // Layout constants (in view coordinates) | |
95 const CGFloat kButtonWidth = 72; | |
96 const CGFloat kURLBarHeight = 24; | |
97 | |
98 // The minimum size of the window's content (in view coordinates) | |
99 const CGFloat kMinimumWindowWidth = 400; | |
100 const CGFloat kMinimumWindowHeight = 300; | |
101 | |
102 void MakeShellButton(NSRect* rect, | |
103 NSString* title, | |
104 NSView* parent, | |
105 int control, | |
106 NSView* target, | |
107 NSString* key, | |
108 NSUInteger modifier) { | |
109 base::scoped_nsobject<NSButton> button( | |
110 [[NSButton alloc] initWithFrame:*rect]); | |
111 [button setTitle:title]; | |
112 [button setBezelStyle:NSSmallSquareBezelStyle]; | |
113 [button setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)]; | |
114 [button setTarget:target]; | |
115 [button setAction:@selector(performAction:)]; | |
116 [button setTag:control]; | |
117 [button setKeyEquivalent:key]; | |
118 [button setKeyEquivalentModifierMask:modifier]; | |
119 [parent addSubview:button]; | |
120 rect->origin.x += kButtonWidth; | |
121 } | |
122 | |
123 } // namespace | |
124 | |
125 namespace content { | |
126 | |
127 void Shell::PlatformInitialize(const gfx::Size& default_window_size) { | |
128 } | |
129 | |
130 void Shell::PlatformCleanUp() { | |
131 } | |
132 | |
133 void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) { | |
134 if (headless_) | |
135 return; | |
136 | |
137 int id; | |
138 switch (control) { | |
139 case BACK_BUTTON: | |
140 id = IDC_NAV_BACK; | |
141 break; | |
142 case FORWARD_BUTTON: | |
143 id = IDC_NAV_FORWARD; | |
144 break; | |
145 case STOP_BUTTON: | |
146 id = IDC_NAV_STOP; | |
147 break; | |
148 default: | |
149 NOTREACHED() << "Unknown UI control"; | |
150 return; | |
151 } | |
152 [[[window_ contentView] viewWithTag:id] setEnabled:is_enabled]; | |
153 } | |
154 | |
155 void Shell::PlatformSetAddressBarURL(const GURL& url) { | |
156 if (headless_) | |
157 return; | |
158 | |
159 NSString* url_string = base::SysUTF8ToNSString(url.spec()); | |
160 [url_edit_view_ setStringValue:url_string]; | |
161 } | |
162 | |
163 void Shell::PlatformSetIsLoading(bool loading) { | |
164 } | |
165 | |
166 void Shell::PlatformCreateWindow(int width, int height) { | |
167 if (headless_) { | |
168 content_width_ = width; | |
169 content_height_ = height; | |
170 return; | |
171 } | |
172 | |
173 NSRect initial_window_bounds = | |
174 NSMakeRect(0, 0, width, height + kURLBarHeight); | |
175 NSRect content_rect = initial_window_bounds; | |
176 NSUInteger style_mask = NSTitledWindowMask | | |
177 NSClosableWindowMask | | |
178 NSMiniaturizableWindowMask | | |
179 NSResizableWindowMask; | |
180 CrShellWindow* window = | |
181 [[CrShellWindow alloc] initWithContentRect:content_rect | |
182 styleMask:style_mask | |
183 backing:NSBackingStoreBuffered | |
184 defer:NO]; | |
185 window_ = window; | |
186 [window setShell:this]; | |
187 [window_ setTitle:kWindowTitle]; | |
188 NSView* content = [window_ contentView]; | |
189 | |
190 // If the window is allowed to get too small, it will wreck the view bindings. | |
191 NSSize min_size = NSMakeSize(kMinimumWindowWidth, kMinimumWindowHeight); | |
192 min_size = [content convertSize:min_size toView:nil]; | |
193 // Note that this takes window coordinates. | |
194 [window_ setContentMinSize:min_size]; | |
195 | |
196 // Set the shell window to participate in Lion Fullscreen mode. Set | |
197 // Setting this flag has no effect on Snow Leopard or earlier. | |
198 NSUInteger collectionBehavior = [window_ collectionBehavior]; | |
199 collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary; | |
200 [window_ setCollectionBehavior:collectionBehavior]; | |
201 | |
202 // Rely on the window delegate to clean us up rather than immediately | |
203 // releasing when the window gets closed. We use the delegate to do | |
204 // everything from the autorelease pool so the shell isn't on the stack | |
205 // during cleanup (ie, a window close from javascript). | |
206 [window_ setReleasedWhenClosed:NO]; | |
207 | |
208 // Create a window delegate to watch for when it's asked to go away. It will | |
209 // clean itself up so we don't need to hold a reference. | |
210 ContentShellWindowDelegate* delegate = | |
211 [[ContentShellWindowDelegate alloc] initWithShell:this]; | |
212 [window_ setDelegate:delegate]; | |
213 | |
214 NSRect button_frame = | |
215 NSMakeRect(0, NSMaxY(initial_window_bounds) - kURLBarHeight, | |
216 kButtonWidth, kURLBarHeight); | |
217 | |
218 MakeShellButton(&button_frame, @"Back", content, IDC_NAV_BACK, | |
219 (NSView*)delegate, @"[", NSCommandKeyMask); | |
220 MakeShellButton(&button_frame, @"Forward", content, IDC_NAV_FORWARD, | |
221 (NSView*)delegate, @"]", NSCommandKeyMask); | |
222 MakeShellButton(&button_frame, @"Reload", content, IDC_NAV_RELOAD, | |
223 (NSView*)delegate, @"r", NSCommandKeyMask); | |
224 MakeShellButton(&button_frame, @"Stop", content, IDC_NAV_STOP, | |
225 (NSView*)delegate, @".", NSCommandKeyMask); | |
226 | |
227 button_frame.size.width = | |
228 NSWidth(initial_window_bounds) - NSMinX(button_frame); | |
229 base::scoped_nsobject<NSTextField> url_edit_view( | |
230 [[NSTextField alloc] initWithFrame:button_frame]); | |
231 [content addSubview:url_edit_view]; | |
232 [url_edit_view setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)]; | |
233 [url_edit_view setTarget:delegate]; | |
234 [url_edit_view setAction:@selector(takeURLStringValueFrom:)]; | |
235 [[url_edit_view cell] setWraps:NO]; | |
236 [[url_edit_view cell] setScrollable:YES]; | |
237 url_edit_view_ = url_edit_view.get(); | |
238 | |
239 // show the window | |
240 [window_ makeKeyAndOrderFront:nil]; | |
241 } | |
242 | |
243 void Shell::PlatformSetContents() { | |
244 NSView* web_view = web_contents_->GetView()->GetNativeView(); | |
245 [web_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; | |
246 | |
247 if (headless_) { | |
248 SizeTo(content_width_, content_height_); | |
249 return; | |
250 } | |
251 | |
252 NSView* content = [window_ contentView]; | |
253 [content addSubview:web_view]; | |
254 | |
255 NSRect frame = [content bounds]; | |
256 frame.size.height -= kURLBarHeight; | |
257 [web_view setFrame:frame]; | |
258 [web_view setNeedsDisplay:YES]; | |
259 } | |
260 | |
261 void Shell::SizeTo(int width, int height) { | |
262 if (!headless_) { | |
263 NOTREACHED(); | |
264 return; | |
265 } | |
266 NSView* web_view = web_contents_->GetView()->GetNativeView(); | |
267 NSRect frame = NSMakeRect(0, 0, width, height); | |
268 [web_view setFrame:frame]; | |
269 } | |
270 | |
271 void Shell::PlatformResizeSubViews() { | |
272 // Not needed; subviews are bound. | |
273 } | |
274 | |
275 void Shell::PlatformSetTitle(const string16& title) { | |
276 if (headless_) | |
277 return; | |
278 | |
279 NSString* title_string = base::SysUTF16ToNSString(title); | |
280 [window_ setTitle:title_string]; | |
281 } | |
282 | |
283 void Shell::Close() { | |
284 if (headless_) | |
285 delete this; | |
286 else | |
287 [window_ performClose:nil]; | |
288 } | |
289 | |
290 void Shell::ActionPerformed(int control) { | |
291 switch (control) { | |
292 case IDC_NAV_BACK: | |
293 GoBackOrForward(-1); | |
294 break; | |
295 case IDC_NAV_FORWARD: | |
296 GoBackOrForward(1); | |
297 break; | |
298 case IDC_NAV_RELOAD: | |
299 Reload(); | |
300 break; | |
301 case IDC_NAV_STOP: | |
302 Stop(); | |
303 break; | |
304 } | |
305 } | |
306 | |
307 void Shell::URLEntered(std::string url_string) { | |
308 if (!url_string.empty()) { | |
309 GURL url(url_string); | |
310 if (!url.has_scheme()) | |
311 url = GURL("http://" + url_string); | |
312 LoadURL(url); | |
313 } | |
314 } | |
315 | |
316 void Shell::HandleKeyboardEvent(WebContents* source, | |
317 const NativeWebKeyboardEvent& event) { | |
318 if (event.skip_in_browser) | |
319 return; | |
320 | |
321 // The event handling to get this strictly right is a tangle; cheat here a bit | |
322 // by just letting the menus have a chance at it. | |
323 if ([event.os_event type] == NSKeyDown) { | |
324 if (([event.os_event modifierFlags] & NSCommandKeyMask) && | |
325 [[event.os_event characters] isEqual:@"l"]) { | |
326 [window_ makeFirstResponder:url_edit_view_]; | |
327 return; | |
328 } | |
329 | |
330 [[NSApp mainMenu] performKeyEquivalent:event.os_event]; | |
331 } | |
332 } | |
333 | |
334 } // namespace content | |
OLD | NEW |