Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(489)

Side by Side Diff: chrome/browser/ui/cocoa/extensions/native_app_window_cocoa.mm

Issue 21344002: Move native_app_window code to apps areas (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase to after mac app shim fix Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 "chrome/browser/ui/cocoa/extensions/native_app_window_cocoa.h"
6
7 #include "base/command_line.h"
8 #include "base/mac/mac_util.h"
9 #include "base/strings/sys_string_conversions.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/cocoa/browser_window_utils.h"
12 #import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
13 #include "chrome/browser/ui/cocoa/extensions/extension_keybinding_registry_cocoa .h"
14 #include "chrome/browser/ui/cocoa/extensions/extension_view_mac.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/common/extensions/extension.h"
17 #include "content/public/browser/native_web_keyboard_event.h"
18 #include "content/public/browser/notification_source.h"
19 #include "content/public/browser/notification_types.h"
20 #include "content/public/browser/render_widget_host_view.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/browser/web_contents_view.h"
23 #include "third_party/skia/include/core/SkRegion.h"
24
25 using apps::ShellWindow;
26
27 @interface NSWindow (NSPrivateApis)
28 - (void)setBottomCornerRounded:(BOOL)rounded;
29 @end
30
31 // Replicate specific 10.7 SDK declarations for building with prior SDKs.
32 #if !defined(MAC_OS_X_VERSION_10_7) || \
33 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
34
35 @interface NSWindow (LionSDKDeclarations)
36 - (void)toggleFullScreen:(id)sender;
37 @end
38
39 enum {
40 NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7
41 };
42
43 #endif // MAC_OS_X_VERSION_10_7
44
45 @implementation NativeAppWindowController
46
47 @synthesize appWindow = appWindow_;
48
49 - (void)windowWillClose:(NSNotification*)notification {
50 if (appWindow_)
51 appWindow_->WindowWillClose();
52 }
53
54 - (void)windowDidBecomeKey:(NSNotification*)notification {
55 if (appWindow_)
56 appWindow_->WindowDidBecomeKey();
57 }
58
59 - (void)windowDidResignKey:(NSNotification*)notification {
60 if (appWindow_)
61 appWindow_->WindowDidResignKey();
62 }
63
64 - (void)windowDidResize:(NSNotification*)notification {
65 if (appWindow_)
66 appWindow_->WindowDidResize();
67 }
68
69 - (void)windowDidMove:(NSNotification*)notification {
70 if (appWindow_)
71 appWindow_->WindowDidMove();
72 }
73
74 - (void)windowDidMiniaturize:(NSNotification*)notification {
75 if (appWindow_)
76 appWindow_->WindowDidMiniaturize();
77 }
78
79 - (void)windowDidDeminiaturize:(NSNotification*)notification {
80 if (appWindow_)
81 appWindow_->WindowDidDeminiaturize();
82 }
83
84 - (BOOL)windowShouldZoom:(NSWindow*)window
85 toFrame:(NSRect)newFrame {
86 if (appWindow_)
87 appWindow_->WindowWillZoom();
88 return YES;
89 }
90
91 // Allow non resizable windows (without NSResizableWindowMask) to enter
92 // fullscreen by passing through the full size in willUseFullScreenContentSize.
93 - (NSSize)window:(NSWindow *)window
94 willUseFullScreenContentSize:(NSSize)proposedSize {
95 return proposedSize;
96 }
97
98 - (void)executeCommand:(int)command {
99 // No-op, swallow the event.
100 }
101
102 - (BOOL)handledByExtensionCommand:(NSEvent*)event {
103 if (appWindow_)
104 return appWindow_->HandledByExtensionCommand(event);
105 return NO;
106 }
107
108 @end
109
110 // This is really a method on NSGrayFrame, so it should only be called on the
111 // view passed into -[NSWindow drawCustomFrameRect:forView:].
112 @interface NSView (PrivateMethods)
113 - (CGFloat)roundedCornerRadius;
114 @end
115
116 @interface ShellNSWindow : ChromeEventProcessingWindow
117 @end
118 @implementation ShellNSWindow
119 @end
120
121 @interface ShellCustomFrameNSWindow : ShellNSWindow
122
123 - (void)drawCustomFrameRect:(NSRect)rect forView:(NSView*)view;
124
125 @end
126
127 @implementation ShellCustomFrameNSWindow
128
129 - (void)drawCustomFrameRect:(NSRect)rect forView:(NSView*)view {
130 [[NSBezierPath bezierPathWithRect:rect] addClip];
131 [[NSColor clearColor] set];
132 NSRectFill(rect);
133
134 // Set up our clip.
135 CGFloat cornerRadius = 4.0;
136 if ([view respondsToSelector:@selector(roundedCornerRadius)])
137 cornerRadius = [view roundedCornerRadius];
138 [[NSBezierPath bezierPathWithRoundedRect:[view bounds]
139 xRadius:cornerRadius
140 yRadius:cornerRadius] addClip];
141 [[NSColor whiteColor] set];
142 NSRectFill(rect);
143 }
144
145 @end
146
147 @interface ShellFramelessNSWindow : ShellCustomFrameNSWindow
148
149 @end
150
151 @implementation ShellFramelessNSWindow
152
153 + (NSRect)frameRectForContentRect:(NSRect)contentRect
154 styleMask:(NSUInteger)mask {
155 return contentRect;
156 }
157
158 + (NSRect)contentRectForFrameRect:(NSRect)frameRect
159 styleMask:(NSUInteger)mask {
160 return frameRect;
161 }
162
163 - (NSRect)frameRectForContentRect:(NSRect)contentRect {
164 return contentRect;
165 }
166
167 - (NSRect)contentRectForFrameRect:(NSRect)frameRect {
168 return frameRect;
169 }
170
171 @end
172
173 @interface ControlRegionView : NSView {
174 @private
175 NativeAppWindowCocoa* appWindow_; // Weak; owns self.
176 }
177
178 @end
179
180 @implementation ControlRegionView
181
182 - (id)initWithAppWindow:(NativeAppWindowCocoa*)appWindow {
183 if ((self = [super init]))
184 appWindow_ = appWindow;
185 return self;
186 }
187
188 - (BOOL)mouseDownCanMoveWindow {
189 return NO;
190 }
191
192 - (NSView*)hitTest:(NSPoint)aPoint {
193 if (appWindow_->use_system_drag() ||
194 !appWindow_->IsWithinDraggableRegion(aPoint)) {
195 return nil;
196 }
197 return self;
198 }
199
200 - (void)mouseDown:(NSEvent*)event {
201 appWindow_->HandleMouseEvent(event);
202 }
203
204 - (void)mouseDragged:(NSEvent*)event {
205 appWindow_->HandleMouseEvent(event);
206 }
207
208 @end
209
210 @interface NSView (WebContentsView)
211 - (void)setMouseDownCanMoveWindow:(BOOL)can_move;
212 @end
213
214 NativeAppWindowCocoa::NativeAppWindowCocoa(
215 ShellWindow* shell_window,
216 const ShellWindow::CreateParams& params)
217 : shell_window_(shell_window),
218 has_frame_(params.frame == ShellWindow::FRAME_CHROME),
219 is_maximized_(false),
220 is_fullscreen_(false),
221 attention_request_id_(0),
222 use_system_drag_(true) {
223 // Flip coordinates based on the primary screen.
224 NSRect main_screen_rect = [[[NSScreen screens] objectAtIndex:0] frame];
225 NSRect cocoa_bounds = NSMakeRect(params.bounds.x(),
226 NSHeight(main_screen_rect) - params.bounds.y() - params.bounds.height(),
227 params.bounds.width(), params.bounds.height());
228
229 // If coordinates are < 0, center window on primary screen
230 if (params.bounds.x() == INT_MIN) {
231 cocoa_bounds.origin.x =
232 floor((NSWidth(main_screen_rect) - NSWidth(cocoa_bounds)) / 2);
233 }
234 if (params.bounds.y() == INT_MIN) {
235 cocoa_bounds.origin.y =
236 floor((NSHeight(main_screen_rect) - NSHeight(cocoa_bounds)) / 2);
237 }
238
239 resizable_ = params.resizable;
240 base::scoped_nsobject<NSWindow> window;
241 Class window_class;
242 if (has_frame_) {
243 bool should_use_native_frame =
244 CommandLine::ForCurrentProcess()->HasSwitch(
245 switches::kAppsUseNativeFrame);
246 window_class = should_use_native_frame ?
247 [ShellNSWindow class] : [ShellCustomFrameNSWindow class];
248 } else {
249 window_class = [ShellFramelessNSWindow class];
250 }
251 window.reset([[window_class alloc]
252 initWithContentRect:cocoa_bounds
253 styleMask:GetWindowStyleMask()
254 backing:NSBackingStoreBuffered
255 defer:NO]);
256 [window setTitle:base::SysUTF8ToNSString(extension()->name())];
257 min_size_ = params.minimum_size;
258 if (min_size_.width() || min_size_.height()) {
259 [window setContentMinSize:
260 NSMakeSize(min_size_.width(), min_size_.height())];
261 }
262 max_size_ = params.maximum_size;
263 if (max_size_.width() || max_size_.height()) {
264 CGFloat max_width = max_size_.width() ? max_size_.width() : CGFLOAT_MAX;
265 CGFloat max_height = max_size_.height() ? max_size_.height() : CGFLOAT_MAX;
266 [window setContentMaxSize:NSMakeSize(max_width, max_height)];
267 }
268
269 if (base::mac::IsOSSnowLeopard() &&
270 [window respondsToSelector:@selector(setBottomCornerRounded:)])
271 [window setBottomCornerRounded:NO];
272
273 // Set the window to participate in Lion Fullscreen mode. Setting this flag
274 // has no effect on Snow Leopard or earlier. Packaged apps don't show the
275 // fullscreen button on their window decorations.
276 NSWindowCollectionBehavior behavior = [window collectionBehavior];
277 behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
278 [window setCollectionBehavior:behavior];
279
280 window_controller_.reset(
281 [[NativeAppWindowController alloc] initWithWindow:window.release()]);
282
283 NSView* view = web_contents()->GetView()->GetNativeView();
284 [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
285
286 // By default, the whole frameless window is not draggable.
287 if (!has_frame_) {
288 gfx::Rect window_bounds(
289 0, 0, NSWidth(cocoa_bounds), NSHeight(cocoa_bounds));
290 system_drag_exclude_areas_.push_back(window_bounds);
291 }
292
293 InstallView();
294
295 [[window_controller_ window] setDelegate:window_controller_];
296 [window_controller_ setAppWindow:this];
297
298 extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryCocoa(
299 shell_window_->profile(),
300 window,
301 extensions::ExtensionKeybindingRegistry::PLATFORM_APPS_ONLY,
302 shell_window));
303 }
304
305 NSUInteger NativeAppWindowCocoa::GetWindowStyleMask() const {
306 NSUInteger style_mask = NSTitledWindowMask | NSClosableWindowMask |
307 NSMiniaturizableWindowMask;
308 if (resizable_)
309 style_mask |= NSResizableWindowMask;
310 if (!has_frame_ ||
311 !CommandLine::ForCurrentProcess()->HasSwitch(
312 switches::kAppsUseNativeFrame)) {
313 style_mask |= NSTexturedBackgroundWindowMask;
314 }
315 return style_mask;
316 }
317
318 void NativeAppWindowCocoa::InstallView() {
319 NSView* view = web_contents()->GetView()->GetNativeView();
320 if (has_frame_) {
321 [view setFrame:[[window() contentView] bounds]];
322 [[window() contentView] addSubview:view];
323 if (!max_size_.IsEmpty() && min_size_ == max_size_) {
324 [[window() standardWindowButton:NSWindowZoomButton] setEnabled:NO];
325 [window() setShowsResizeIndicator:NO];
326 }
327 } else {
328 // TODO(jeremya): find a cleaner way to send this information to the
329 // WebContentsViewCocoa view.
330 DCHECK([view
331 respondsToSelector:@selector(setMouseDownCanMoveWindow:)]);
332 [view setMouseDownCanMoveWindow:YES];
333
334 NSView* frameView = [[window() contentView] superview];
335 [view setFrame:[frameView bounds]];
336 [frameView addSubview:view];
337
338 [[window() standardWindowButton:NSWindowZoomButton] setHidden:YES];
339 [[window() standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
340 [[window() standardWindowButton:NSWindowCloseButton] setHidden:YES];
341
342 // Some third-party OS X utilities check the zoom button's enabled state to
343 // determine whether to show custom UI on hover, so we disable it here to
344 // prevent them from doing so in a frameless app window.
345 [[window() standardWindowButton:NSWindowZoomButton] setEnabled:NO];
346
347 InstallDraggableRegionViews();
348 }
349 }
350
351 void NativeAppWindowCocoa::UninstallView() {
352 NSView* view = web_contents()->GetView()->GetNativeView();
353 [view removeFromSuperview];
354 }
355
356 bool NativeAppWindowCocoa::IsActive() const {
357 return [window() isKeyWindow];
358 }
359
360 bool NativeAppWindowCocoa::IsMaximized() const {
361 return is_maximized_;
362 }
363
364 bool NativeAppWindowCocoa::IsMinimized() const {
365 return [window() isMiniaturized];
366 }
367
368 bool NativeAppWindowCocoa::IsFullscreen() const {
369 return is_fullscreen_;
370 }
371
372 void NativeAppWindowCocoa::SetFullscreen(bool fullscreen) {
373 if (fullscreen == is_fullscreen_)
374 return;
375 is_fullscreen_ = fullscreen;
376
377 if (base::mac::IsOSLionOrLater()) {
378 [window() toggleFullScreen:nil];
379 return;
380 }
381
382 DCHECK(base::mac::IsOSSnowLeopard());
383
384 // Fade to black.
385 const CGDisplayReservationInterval kFadeDurationSeconds = 0.6;
386 bool did_fade_out = false;
387 CGDisplayFadeReservationToken token;
388 if (CGAcquireDisplayFadeReservation(kFadeDurationSeconds, &token) ==
389 kCGErrorSuccess) {
390 did_fade_out = true;
391 CGDisplayFade(token, kFadeDurationSeconds / 2, kCGDisplayBlendNormal,
392 kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, /*synchronous=*/true);
393 }
394
395 // Since frameless windows insert the WebContentsView into the NSThemeFrame
396 // ([[window contentView] superview]), and since that NSThemeFrame is
397 // destroyed and recreated when we change the styleMask of the window, we
398 // need to remove the view from the window when we change the style, and
399 // add it back afterwards.
400 UninstallView();
401 if (fullscreen) {
402 restored_bounds_ = [window() frame];
403 [window() setStyleMask:NSBorderlessWindowMask];
404 [window() setFrame:[window()
405 frameRectForContentRect:[[window() screen] frame]]
406 display:YES];
407 base::mac::RequestFullScreen(base::mac::kFullScreenModeAutoHideAll);
408 } else {
409 base::mac::ReleaseFullScreen(base::mac::kFullScreenModeAutoHideAll);
410 [window() setStyleMask:GetWindowStyleMask()];
411 [window() setFrame:restored_bounds_ display:YES];
412 }
413 InstallView();
414
415 // Fade back in.
416 if (did_fade_out) {
417 CGDisplayFade(token, kFadeDurationSeconds / 2, kCGDisplayBlendSolidColor,
418 kCGDisplayBlendNormal, 0.0, 0.0, 0.0, /*synchronous=*/false);
419 CGReleaseDisplayFadeReservation(token);
420 }
421 }
422
423 bool NativeAppWindowCocoa::IsFullscreenOrPending() const {
424 return is_fullscreen_;
425 }
426
427 bool NativeAppWindowCocoa::IsDetached() const {
428 return false;
429 }
430
431 gfx::NativeWindow NativeAppWindowCocoa::GetNativeWindow() {
432 return window();
433 }
434
435 gfx::Rect NativeAppWindowCocoa::GetRestoredBounds() const {
436 // Flip coordinates based on the primary screen.
437 NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
438 NSRect frame = [window() frame];
439 gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame));
440 bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame));
441 return bounds;
442 }
443
444 ui::WindowShowState NativeAppWindowCocoa::GetRestoredState() const {
445 if (IsMaximized())
446 return ui::SHOW_STATE_MAXIMIZED;
447 return ui::SHOW_STATE_NORMAL;
448 }
449
450 gfx::Rect NativeAppWindowCocoa::GetBounds() const {
451 return GetRestoredBounds();
452 }
453
454 void NativeAppWindowCocoa::Show() {
455 [window_controller_ showWindow:nil];
456 [window() makeKeyAndOrderFront:window_controller_];
457 }
458
459 void NativeAppWindowCocoa::ShowInactive() {
460 [window() orderFront:window_controller_];
461 }
462
463 void NativeAppWindowCocoa::Hide() {
464 [window() orderOut:window_controller_];
465 }
466
467 void NativeAppWindowCocoa::Close() {
468 [window() performClose:nil];
469 }
470
471 void NativeAppWindowCocoa::Activate() {
472 [BrowserWindowUtils activateWindowForController:window_controller_];
473 }
474
475 void NativeAppWindowCocoa::Deactivate() {
476 // TODO(jcivelli): http://crbug.com/51364 Implement me.
477 NOTIMPLEMENTED();
478 }
479
480 void NativeAppWindowCocoa::Maximize() {
481 // Zoom toggles so only call if not already maximized.
482 if (![window() isZoomed])
483 [window() zoom:window_controller_];
484 is_maximized_ = true;
485 }
486
487 void NativeAppWindowCocoa::Minimize() {
488 [window() miniaturize:window_controller_];
489 }
490
491 void NativeAppWindowCocoa::Restore() {
492 if ([window() isZoomed])
493 [window() zoom:window_controller_]; // Toggles zoom mode.
494 else if (IsMinimized())
495 [window() deminiaturize:window_controller_];
496 is_maximized_ = false;
497 }
498
499 void NativeAppWindowCocoa::SetBounds(const gfx::Rect& bounds) {
500 // Enforce minimum/maximum bounds.
501 gfx::Rect checked_bounds = bounds;
502
503 NSSize min_size = [window() minSize];
504 if (bounds.width() < min_size.width)
505 checked_bounds.set_width(min_size.width);
506 if (bounds.height() < min_size.height)
507 checked_bounds.set_height(min_size.height);
508 NSSize max_size = [window() maxSize];
509 if (checked_bounds.width() > max_size.width)
510 checked_bounds.set_width(max_size.width);
511 if (checked_bounds.height() > max_size.height)
512 checked_bounds.set_height(max_size.height);
513
514 NSRect cocoa_bounds = NSMakeRect(checked_bounds.x(), 0,
515 checked_bounds.width(),
516 checked_bounds.height());
517 // Flip coordinates based on the primary screen.
518 NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
519 cocoa_bounds.origin.y = NSHeight([screen frame]) - checked_bounds.bottom();
520
521 [window() setFrame:cocoa_bounds display:YES];
522 }
523
524 void NativeAppWindowCocoa::UpdateWindowIcon() {
525 // TODO(junmin): implement.
526 }
527
528 void NativeAppWindowCocoa::UpdateWindowTitle() {
529 string16 title = shell_window_->GetTitle();
530 [window() setTitle:base::SysUTF16ToNSString(title)];
531 }
532
533 void NativeAppWindowCocoa::UpdateDraggableRegions(
534 const std::vector<extensions::DraggableRegion>& regions) {
535 // Draggable region is not supported for non-frameless window.
536 if (has_frame_)
537 return;
538
539 // To use system drag, the window has to be marked as draggable with
540 // non-draggable areas being excluded via overlapping views.
541 // 1) If no draggable area is provided, the window is not draggable at all.
542 // 2) If only one draggable area is given, as this is the most common
543 // case, use the system drag. The non-draggable areas that are opposite of
544 // the draggable area are computed.
545 // 3) Otherwise, use the custom drag. As such, we lose the capability to
546 // support some features like snapping into other space.
547
548 // Determine how to perform the drag by counting the number of draggable
549 // areas.
550 const extensions::DraggableRegion* draggable_area = NULL;
551 use_system_drag_ = true;
552 for (std::vector<extensions::DraggableRegion>::const_iterator iter =
553 regions.begin();
554 iter != regions.end();
555 ++iter) {
556 if (iter->draggable) {
557 // If more than one draggable area is found, use custom drag.
558 if (draggable_area) {
559 use_system_drag_ = false;
560 break;
561 }
562 draggable_area = &(*iter);
563 }
564 }
565
566 if (use_system_drag_)
567 UpdateDraggableRegionsForSystemDrag(regions, draggable_area);
568 else
569 UpdateDraggableRegionsForCustomDrag(regions);
570
571 InstallDraggableRegionViews();
572 }
573
574 void NativeAppWindowCocoa::UpdateDraggableRegionsForSystemDrag(
575 const std::vector<extensions::DraggableRegion>& regions,
576 const extensions::DraggableRegion* draggable_area) {
577 NSView* web_view = web_contents()->GetView()->GetNativeView();
578 NSInteger web_view_width = NSWidth([web_view bounds]);
579 NSInteger web_view_height = NSHeight([web_view bounds]);
580
581 system_drag_exclude_areas_.clear();
582
583 // The whole window is not draggable if no draggable area is given.
584 if (!draggable_area) {
585 gfx::Rect window_bounds(0, 0, web_view_width, web_view_height);
586 system_drag_exclude_areas_.push_back(window_bounds);
587 return;
588 }
589
590 // Otherwise, there is only one draggable area. Compute non-draggable areas
591 // that are the opposite of the given draggable area, combined with the
592 // remaining provided non-draggable areas.
593
594 // Copy all given non-draggable areas.
595 for (std::vector<extensions::DraggableRegion>::const_iterator iter =
596 regions.begin();
597 iter != regions.end();
598 ++iter) {
599 if (!iter->draggable)
600 system_drag_exclude_areas_.push_back(iter->bounds);
601 }
602
603 gfx::Rect draggable_bounds = draggable_area->bounds;
604 gfx::Rect non_draggable_bounds;
605
606 // Add the non-draggable area above the given draggable area.
607 if (draggable_bounds.y() > 0) {
608 non_draggable_bounds.SetRect(0,
609 0,
610 web_view_width,
611 draggable_bounds.y() - 1);
612 system_drag_exclude_areas_.push_back(non_draggable_bounds);
613 }
614
615 // Add the non-draggable area below the given draggable area.
616 if (draggable_bounds.bottom() < web_view_height) {
617 non_draggable_bounds.SetRect(0,
618 draggable_bounds.bottom() + 1,
619 web_view_width,
620 web_view_height - draggable_bounds.bottom());
621 system_drag_exclude_areas_.push_back(non_draggable_bounds);
622 }
623
624 // Add the non-draggable area to the left of the given draggable area.
625 if (draggable_bounds.x() > 0) {
626 non_draggable_bounds.SetRect(0,
627 draggable_bounds.y(),
628 draggable_bounds.x() - 1,
629 draggable_bounds.height());
630 system_drag_exclude_areas_.push_back(non_draggable_bounds);
631 }
632
633 // Add the non-draggable area to the right of the given draggable area.
634 if (draggable_bounds.right() < web_view_width) {
635 non_draggable_bounds.SetRect(draggable_bounds.right() + 1,
636 draggable_bounds.y(),
637 web_view_width - draggable_bounds.right(),
638 draggable_bounds.height());
639 system_drag_exclude_areas_.push_back(non_draggable_bounds);
640 }
641 }
642
643 void NativeAppWindowCocoa::UpdateDraggableRegionsForCustomDrag(
644 const std::vector<extensions::DraggableRegion>& regions) {
645 // We still need one ControlRegionView to cover the whole window such that
646 // mouse events could be captured.
647 NSView* web_view = web_contents()->GetView()->GetNativeView();
648 gfx::Rect window_bounds(
649 0, 0, NSWidth([web_view bounds]), NSHeight([web_view bounds]));
650 system_drag_exclude_areas_.clear();
651 system_drag_exclude_areas_.push_back(window_bounds);
652
653 // Aggregate the draggable areas and non-draggable areas such that hit test
654 // could be performed easily.
655 draggable_region_.reset(ShellWindow::RawDraggableRegionsToSkRegion(regions));
656 }
657
658 void NativeAppWindowCocoa::HandleKeyboardEvent(
659 const content::NativeWebKeyboardEvent& event) {
660 if (event.skip_in_browser ||
661 event.type == content::NativeWebKeyboardEvent::Char) {
662 return;
663 }
664 [window() redispatchKeyEvent:event.os_event];
665 }
666
667 void NativeAppWindowCocoa::InstallDraggableRegionViews() {
668 DCHECK(!has_frame_);
669
670 // All ControlRegionViews should be added as children of the WebContentsView,
671 // because WebContentsView will be removed and re-added when entering and
672 // leaving fullscreen mode.
673 NSView* webView = web_contents()->GetView()->GetNativeView();
674 NSInteger webViewHeight = NSHeight([webView bounds]);
675
676 // Remove all ControlRegionViews that are added last time.
677 // Note that [webView subviews] returns the view's mutable internal array and
678 // it should be copied to avoid mutating the original array while enumerating
679 // it.
680 base::scoped_nsobject<NSArray> subviews([[webView subviews] copy]);
681 for (NSView* subview in subviews.get())
682 if ([subview isKindOfClass:[ControlRegionView class]])
683 [subview removeFromSuperview];
684
685 // Create and add ControlRegionView for each region that needs to be excluded
686 // from the dragging.
687 for (std::vector<gfx::Rect>::const_iterator iter =
688 system_drag_exclude_areas_.begin();
689 iter != system_drag_exclude_areas_.end();
690 ++iter) {
691 base::scoped_nsobject<NSView> controlRegion(
692 [[ControlRegionView alloc] initWithAppWindow:this]);
693 [controlRegion setFrame:NSMakeRect(iter->x(),
694 webViewHeight - iter->bottom(),
695 iter->width(),
696 iter->height())];
697 [controlRegion setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
698 [webView addSubview:controlRegion];
699 }
700 }
701
702 void NativeAppWindowCocoa::FlashFrame(bool flash) {
703 if (flash) {
704 attention_request_id_ = [NSApp requestUserAttention:NSInformationalRequest];
705 } else {
706 [NSApp cancelUserAttentionRequest:attention_request_id_];
707 attention_request_id_ = 0;
708 }
709 }
710
711 bool NativeAppWindowCocoa::IsAlwaysOnTop() const {
712 return false;
713 }
714
715 void NativeAppWindowCocoa::RenderViewHostChanged() {
716 web_contents()->GetView()->Focus();
717 }
718
719 gfx::Insets NativeAppWindowCocoa::GetFrameInsets() const {
720 if (!has_frame_)
721 return gfx::Insets();
722
723 // Flip the coordinates based on the main screen.
724 NSInteger screen_height =
725 NSHeight([[[NSScreen screens] objectAtIndex:0] frame]);
726
727 NSRect frame_nsrect = [window() frame];
728 gfx::Rect frame_rect(NSRectToCGRect(frame_nsrect));
729 frame_rect.set_y(screen_height - NSMaxY(frame_nsrect));
730
731 NSRect content_nsrect = [window() contentRectForFrameRect:frame_nsrect];
732 gfx::Rect content_rect(NSRectToCGRect(content_nsrect));
733 content_rect.set_y(screen_height - NSMaxY(content_nsrect));
734
735 return frame_rect.InsetsFrom(content_rect);
736 }
737
738 gfx::NativeView NativeAppWindowCocoa::GetHostView() const {
739 NOTIMPLEMENTED();
740 return NULL;
741 }
742
743 gfx::Point NativeAppWindowCocoa::GetDialogPosition(const gfx::Size& size) {
744 NOTIMPLEMENTED();
745 return gfx::Point();
746 }
747
748 void NativeAppWindowCocoa::AddObserver(
749 web_modal::WebContentsModalDialogHostObserver* observer) {
750 NOTIMPLEMENTED();
751 }
752
753 void NativeAppWindowCocoa::RemoveObserver(
754 web_modal::WebContentsModalDialogHostObserver* observer) {
755 NOTIMPLEMENTED();
756 }
757
758 void NativeAppWindowCocoa::WindowWillClose() {
759 [window_controller_ setAppWindow:NULL];
760 shell_window_->OnNativeWindowChanged();
761 shell_window_->OnNativeClose();
762 }
763
764 void NativeAppWindowCocoa::WindowDidBecomeKey() {
765 content::RenderWidgetHostView* rwhv =
766 web_contents()->GetRenderWidgetHostView();
767 if (rwhv)
768 rwhv->SetActive(true);
769 shell_window_->OnNativeWindowActivated();
770 }
771
772 void NativeAppWindowCocoa::WindowDidResignKey() {
773 // If our app is still active and we're still the key window, ignore this
774 // message, since it just means that a menu extra (on the "system status bar")
775 // was activated; we'll get another |-windowDidResignKey| if we ever really
776 // lose key window status.
777 if ([NSApp isActive] && ([NSApp keyWindow] == window()))
778 return;
779
780 content::RenderWidgetHostView* rwhv =
781 web_contents()->GetRenderWidgetHostView();
782 if (rwhv)
783 rwhv->SetActive(false);
784 }
785
786 void NativeAppWindowCocoa::WindowDidResize() {
787 shell_window_->OnNativeWindowChanged();
788 }
789
790 void NativeAppWindowCocoa::WindowDidMove() {
791 shell_window_->OnNativeWindowChanged();
792 }
793
794 void NativeAppWindowCocoa::WindowDidMiniaturize() {
795 shell_window_->OnNativeWindowChanged();
796 }
797
798 void NativeAppWindowCocoa::WindowDidDeminiaturize() {
799 shell_window_->OnNativeWindowChanged();
800 }
801
802 void NativeAppWindowCocoa::WindowWillZoom() {
803 is_maximized_ = ![window() isZoomed];
804 }
805
806 bool NativeAppWindowCocoa::HandledByExtensionCommand(NSEvent* event) {
807 return extension_keybinding_registry_->ProcessKeyEvent(
808 content::NativeWebKeyboardEvent(event));
809 }
810
811 void NativeAppWindowCocoa::HandleMouseEvent(NSEvent* event) {
812 if ([event type] == NSLeftMouseDown) {
813 last_mouse_location_ =
814 [window() convertBaseToScreen:[event locationInWindow]];
815 } else if ([event type] == NSLeftMouseDragged) {
816 NSPoint current_mouse_location =
817 [window() convertBaseToScreen:[event locationInWindow]];
818 NSPoint frame_origin = [window() frame].origin;
819 frame_origin.x += current_mouse_location.x - last_mouse_location_.x;
820 frame_origin.y += current_mouse_location.y - last_mouse_location_.y;
821 [window() setFrameOrigin:frame_origin];
822 last_mouse_location_ = current_mouse_location;
823 }
824 }
825
826 bool NativeAppWindowCocoa::IsWithinDraggableRegion(NSPoint point) const {
827 if (!draggable_region_)
828 return false;
829 NSView* webView = web_contents()->GetView()->GetNativeView();
830 NSInteger webViewHeight = NSHeight([webView bounds]);
831 // |draggable_region_| is stored in local platform-indepdent coordiate system
832 // while |point| is in local Cocoa coordinate system. Do the conversion
833 // to match these two.
834 return draggable_region_->contains(point.x, webViewHeight - point.y);
835 }
836
837 NativeAppWindowCocoa::~NativeAppWindowCocoa() {
838 }
839
840 ShellNSWindow* NativeAppWindowCocoa::window() const {
841 NSWindow* window = [window_controller_ window];
842 CHECK(!window || [window isKindOfClass:[ShellNSWindow class]]);
843 return static_cast<ShellNSWindow*>(window);
844 }
845
846 // static
847 NativeAppWindow* NativeAppWindow::Create(
848 ShellWindow* shell_window,
849 const ShellWindow::CreateParams& params) {
850 return new NativeAppWindowCocoa(shell_window, params);
851 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/cocoa/extensions/native_app_window_cocoa.h ('k') | chrome/browser/ui/extensions/native_app_window.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698