Sort unlaunched apps on app list start page by apps grid order.
[chromium-blink-merge.git] / ui / views / widget / native_widget_mac.mm
blob564494ea26fba075aee81fde8c97f24b38dba5aa
1 // Copyright 2014 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.
5 #include "ui/views/widget/native_widget_mac.h"
7 #import <Cocoa/Cocoa.h>
9 #include "base/mac/foundation_util.h"
10 #include "base/mac/scoped_nsobject.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "ui/gfx/font_list.h"
13 #import "ui/gfx/mac/coordinate_conversion.h"
14 #include "ui/native_theme/native_theme.h"
15 #import "ui/views/cocoa/bridged_content_view.h"
16 #import "ui/views/cocoa/bridged_native_widget.h"
17 #import "ui/views/cocoa/native_widget_mac_nswindow.h"
18 #import "ui/views/cocoa/views_nswindow_delegate.h"
19 #include "ui/views/window/native_frame_view.h"
21 namespace views {
22 namespace {
24 NSInteger StyleMaskForParams(const Widget::InitParams& params) {
25   // TODO(tapted): Determine better masks when there are use cases for it.
26   if (params.remove_standard_frame)
27     return NSBorderlessWindowMask;
29   if (params.type == Widget::InitParams::TYPE_WINDOW) {
30     return NSTitledWindowMask | NSClosableWindowMask |
31            NSMiniaturizableWindowMask | NSResizableWindowMask;
32   }
33   return NSBorderlessWindowMask;
36 NSRect ValidateContentRect(NSRect content_rect) {
37   // A contentRect with zero width or height is a banned practice in Chrome, due
38   // to unpredictable OSX treatment. For now, silently give a minimum dimension.
39   // TODO(tapted): Add a DCHECK, or add emulation logic (e.g. to auto-hide).
40   if (NSWidth(content_rect) == 0)
41     content_rect.size.width = 1;
43   if (NSHeight(content_rect) == 0)
44     content_rect.size.height = 1;
46   return content_rect;
49 gfx::Size WindowSizeForClientAreaSize(NSWindow* window, const gfx::Size& size) {
50   NSRect content_rect = NSMakeRect(0, 0, size.width(), size.height());
51   NSRect frame_rect = [window frameRectForContentRect:content_rect];
52   return gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect));
55 }  // namespace
57 ////////////////////////////////////////////////////////////////////////////////
58 // NativeWidgetMac, public:
60 NativeWidgetMac::NativeWidgetMac(internal::NativeWidgetDelegate* delegate)
61     : delegate_(delegate),
62       bridge_(new BridgedNativeWidget(this)),
63       ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET) {
66 NativeWidgetMac::~NativeWidgetMac() {
67   if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
68     delete delegate_;
69   else
70     CloseNow();
73 // static
74 BridgedNativeWidget* NativeWidgetMac::GetBridgeForNativeWindow(
75     gfx::NativeWindow window) {
76   id<NSWindowDelegate> window_delegate = [window delegate];
77   if ([window_delegate respondsToSelector:@selector(nativeWidgetMac)]) {
78     ViewsNSWindowDelegate* delegate =
79         base::mac::ObjCCastStrict<ViewsNSWindowDelegate>(window_delegate);
80     return [delegate nativeWidgetMac]->bridge_.get();
81   }
82   return nullptr;  // Not created by NativeWidgetMac.
85 void NativeWidgetMac::OnWindowWillClose() {
86   delegate_->OnNativeWidgetDestroying();
87   // Note: If closed via CloseNow(), |bridge_| will already be reset. If closed
88   // by the user, or via Close() and a RunLoop, this will reset it.
89   bridge_.reset();
90   delegate_->OnNativeWidgetDestroyed();
91   if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
92     delete this;
95 ////////////////////////////////////////////////////////////////////////////////
96 // NativeWidgetMac, internal::NativeWidgetPrivate implementation:
98 void NativeWidgetMac::InitNativeWidget(const Widget::InitParams& params) {
99   ownership_ = params.ownership;
101   NSInteger style_mask = StyleMaskForParams(params);
102   NSRect content_rect = ValidateContentRect(
103       [NSWindow contentRectForFrameRect:gfx::ScreenRectToNSRect(params.bounds)
104                               styleMask:style_mask]);
106   base::scoped_nsobject<NSWindow> window([[NativeWidgetMacNSWindow alloc]
107       initWithContentRect:content_rect
108                 styleMask:style_mask
109                   backing:NSBackingStoreBuffered
110                     defer:YES]);
111   [window setReleasedWhenClosed:NO];  // Owned by scoped_nsobject.
112   bridge_->Init(window, params);
114   delegate_->OnNativeWidgetCreated(true);
116   bridge_->SetFocusManager(GetWidget()->GetFocusManager());
118   DCHECK(GetWidget()->GetRootView());
119   bridge_->SetRootView(GetWidget()->GetRootView());
121   // "Infer" must be handled by ViewsDelegate::OnBeforeWidgetInit().
122   DCHECK_NE(Widget::InitParams::INFER_OPACITY, params.opacity);
123   bool translucent = params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW;
124   switch (params.layer_type) {
125     case aura::WINDOW_LAYER_NONE:
126       break;
127     case aura::WINDOW_LAYER_TEXTURED:
128       bridge_->CreateLayer(ui::LAYER_TEXTURED, translucent);
129       break;
130     case aura::WINDOW_LAYER_NOT_DRAWN:
131       bridge_->CreateLayer(ui::LAYER_NOT_DRAWN, translucent);
132       break;
133     case aura::WINDOW_LAYER_SOLID_COLOR:
134       bridge_->CreateLayer(ui::LAYER_SOLID_COLOR, translucent);
135       break;
136   }
139 NonClientFrameView* NativeWidgetMac::CreateNonClientFrameView() {
140   return new NativeFrameView(GetWidget());
143 bool NativeWidgetMac::ShouldUseNativeFrame() const {
144   return true;
147 bool NativeWidgetMac::ShouldWindowContentsBeTransparent() const {
148   // On Windows, this returns false when DWM is unavailable (e.g. XP, RDP or
149   // classic mode). OSX always has a compositing window manager.
150   return true;
153 void NativeWidgetMac::FrameTypeChanged() {
154   NOTIMPLEMENTED();
157 Widget* NativeWidgetMac::GetWidget() {
158   return delegate_->AsWidget();
161 const Widget* NativeWidgetMac::GetWidget() const {
162   return delegate_->AsWidget();
165 gfx::NativeView NativeWidgetMac::GetNativeView() const {
166   // Returns a BridgedContentView, unless there is no views::RootView set.
167   return [GetNativeWindow() contentView];
170 gfx::NativeWindow NativeWidgetMac::GetNativeWindow() const {
171   return bridge_ ? bridge_->ns_window() : nil;
174 Widget* NativeWidgetMac::GetTopLevelWidget() {
175   NativeWidgetPrivate* native_widget = GetTopLevelNativeWidget(GetNativeView());
176   return native_widget ? native_widget->GetWidget() : NULL;
179 const ui::Compositor* NativeWidgetMac::GetCompositor() const {
180   return bridge_ && bridge_->layer() ? bridge_->layer()->GetCompositor()
181                                      : nullptr;
184 const ui::Layer* NativeWidgetMac::GetLayer() const {
185   return bridge_ ? bridge_->layer() : nullptr;
188 void NativeWidgetMac::ReorderNativeViews() {
189   if (bridge_)
190     bridge_->SetRootView(GetWidget()->GetRootView());
193 void NativeWidgetMac::ViewRemoved(View* view) {
194   NOTIMPLEMENTED();
197 void NativeWidgetMac::SetNativeWindowProperty(const char* name, void* value) {
198   if (bridge_)
199     bridge_->SetNativeWindowProperty(name, value);
202 void* NativeWidgetMac::GetNativeWindowProperty(const char* name) const {
203   if (bridge_)
204     return bridge_->GetNativeWindowProperty(name);
206   return nullptr;
209 TooltipManager* NativeWidgetMac::GetTooltipManager() const {
210   NOTIMPLEMENTED();
211   return NULL;
214 void NativeWidgetMac::SetCapture() {
215   if (bridge_ && !bridge_->HasCapture())
216     bridge_->AcquireCapture();
219 void NativeWidgetMac::ReleaseCapture() {
220   if (bridge_)
221     bridge_->ReleaseCapture();
224 bool NativeWidgetMac::HasCapture() const {
225   return bridge_ && bridge_->HasCapture();
228 InputMethod* NativeWidgetMac::CreateInputMethod() {
229   return bridge_ ? bridge_->CreateInputMethod() : NULL;
232 internal::InputMethodDelegate* NativeWidgetMac::GetInputMethodDelegate() {
233   return bridge_.get();
236 ui::InputMethod* NativeWidgetMac::GetHostInputMethod() {
237   return bridge_ ? bridge_->GetHostInputMethod() : NULL;
240 void NativeWidgetMac::CenterWindow(const gfx::Size& size) {
241   SetSize(WindowSizeForClientAreaSize(GetNativeWindow(), size));
242   // Note that this is not the precise center of screen, but it is the standard
243   // location for windows like dialogs to appear on screen for Mac.
244   // TODO(tapted): If there is a parent window, center in that instead.
245   [GetNativeWindow() center];
248 void NativeWidgetMac::GetWindowPlacement(gfx::Rect* bounds,
249                                          ui::WindowShowState* maximized) const {
250   NOTIMPLEMENTED();
253 bool NativeWidgetMac::SetWindowTitle(const base::string16& title) {
254   NSWindow* window = GetNativeWindow();
255   NSString* current_title = [window title];
256   NSString* new_title = SysUTF16ToNSString(title);
257   if ([current_title isEqualToString:new_title])
258     return false;
260   [window setTitle:new_title];
261   return true;
264 void NativeWidgetMac::SetWindowIcons(const gfx::ImageSkia& window_icon,
265                                      const gfx::ImageSkia& app_icon) {
266   NOTIMPLEMENTED();
269 void NativeWidgetMac::InitModalType(ui::ModalType modal_type) {
270   NOTIMPLEMENTED();
273 gfx::Rect NativeWidgetMac::GetWindowBoundsInScreen() const {
274   return gfx::ScreenRectFromNSRect([GetNativeWindow() frame]);
277 gfx::Rect NativeWidgetMac::GetClientAreaBoundsInScreen() const {
278   NSWindow* window = GetNativeWindow();
279   return gfx::ScreenRectFromNSRect(
280       [window contentRectForFrameRect:[window frame]]);
283 gfx::Rect NativeWidgetMac::GetRestoredBounds() const {
284   return bridge_ ? bridge_->GetRestoredBounds() : gfx::Rect();
287 void NativeWidgetMac::SetBounds(const gfx::Rect& bounds) {
288   if (bridge_)
289     bridge_->SetBounds(bounds);
292 void NativeWidgetMac::SetSize(const gfx::Size& size) {
293   // Ensure the top-left corner stays in-place (rather than the bottom-left,
294   // which -[NSWindow setContentSize:] would do).
295   SetBounds(gfx::Rect(GetWindowBoundsInScreen().origin(), size));
298 void NativeWidgetMac::StackAbove(gfx::NativeView native_view) {
299   NOTIMPLEMENTED();
302 void NativeWidgetMac::StackAtTop() {
303   NOTIMPLEMENTED();
306 void NativeWidgetMac::StackBelow(gfx::NativeView native_view) {
307   NOTIMPLEMENTED();
310 void NativeWidgetMac::SetShape(gfx::NativeRegion shape) {
311   NOTIMPLEMENTED();
314 void NativeWidgetMac::Close() {
315   if (!bridge_)
316     return;
318   // Clear the view early to suppress repaints.
319   bridge_->SetRootView(NULL);
321   NSWindow* window = GetNativeWindow();
322   // Calling performClose: will momentarily highlight the close button, but
323   // AppKit will reject it if there is no close button.
324   SEL close_selector = ([window styleMask] & NSClosableWindowMask)
325                            ? @selector(performClose:)
326                            : @selector(close);
327   [window performSelector:close_selector withObject:nil afterDelay:0];
330 void NativeWidgetMac::CloseNow() {
331   // Reset |bridge_| to NULL before destroying it.
332   scoped_ptr<BridgedNativeWidget> bridge(bridge_.Pass());
335 void NativeWidgetMac::Show() {
336   ShowWithWindowState(ui::SHOW_STATE_NORMAL);
339 void NativeWidgetMac::Hide() {
340   if (!bridge_)
341     return;
343   bridge_->SetVisibilityState(BridgedNativeWidget::HIDE_WINDOW);
346 void NativeWidgetMac::ShowMaximizedWithBounds(
347     const gfx::Rect& restored_bounds) {
348   NOTIMPLEMENTED();
351 void NativeWidgetMac::ShowWithWindowState(ui::WindowShowState state) {
352   if (!bridge_)
353     return;
355   switch (state) {
356     case ui::SHOW_STATE_DEFAULT:
357     case ui::SHOW_STATE_NORMAL:
358     case ui::SHOW_STATE_INACTIVE:
359       break;
360     case ui::SHOW_STATE_MINIMIZED:
361     case ui::SHOW_STATE_MAXIMIZED:
362     case ui::SHOW_STATE_FULLSCREEN:
363       NOTIMPLEMENTED();
364       break;
365     case ui::SHOW_STATE_END:
366       NOTREACHED();
367       break;
368   }
369   bridge_->SetVisibilityState(state == ui::SHOW_STATE_INACTIVE
370       ? BridgedNativeWidget::SHOW_INACTIVE
371       : BridgedNativeWidget::SHOW_AND_ACTIVATE_WINDOW);
374 bool NativeWidgetMac::IsVisible() const {
375   return bridge_ && bridge_->window_visible();
378 void NativeWidgetMac::Activate() {
379   if (!bridge_)
380     return;
382   bridge_->SetVisibilityState(BridgedNativeWidget::SHOW_AND_ACTIVATE_WINDOW);
385 void NativeWidgetMac::Deactivate() {
386   NOTIMPLEMENTED();
389 bool NativeWidgetMac::IsActive() const {
390   return [GetNativeWindow() isKeyWindow];
393 void NativeWidgetMac::SetAlwaysOnTop(bool always_on_top) {
394   NOTIMPLEMENTED();
397 bool NativeWidgetMac::IsAlwaysOnTop() const {
398   NOTIMPLEMENTED();
399   return false;
402 void NativeWidgetMac::SetVisibleOnAllWorkspaces(bool always_visible) {
403   NOTIMPLEMENTED();
406 void NativeWidgetMac::Maximize() {
407   NOTIMPLEMENTED();  // See IsMaximized().
410 void NativeWidgetMac::Minimize() {
411   NSWindow* window = GetNativeWindow();
412   // Calling performMiniaturize: will momentarily highlight the button, but
413   // AppKit will reject it if there is no miniaturize button.
414   if ([window styleMask] & NSMiniaturizableWindowMask)
415     [window performMiniaturize:nil];
416   else
417     [window miniaturize:nil];
420 bool NativeWidgetMac::IsMaximized() const {
421   // The window frame isn't altered on Mac unless going fullscreen. The green
422   // "+" button just makes the window bigger. So, always false.
423   return false;
426 bool NativeWidgetMac::IsMinimized() const {
427   return [GetNativeWindow() isMiniaturized];
430 void NativeWidgetMac::Restore() {
431   [GetNativeWindow() deminiaturize:nil];
434 void NativeWidgetMac::SetFullscreen(bool fullscreen) {
435   if (!bridge_ || fullscreen == IsFullscreen())
436     return;
438   bridge_->ToggleDesiredFullscreenState();
441 bool NativeWidgetMac::IsFullscreen() const {
442   return bridge_ && bridge_->target_fullscreen_state();
445 void NativeWidgetMac::SetOpacity(unsigned char opacity) {
446   NOTIMPLEMENTED();
449 void NativeWidgetMac::SetUseDragFrame(bool use_drag_frame) {
450   NOTIMPLEMENTED();
453 void NativeWidgetMac::FlashFrame(bool flash_frame) {
454   NOTIMPLEMENTED();
457 void NativeWidgetMac::RunShellDrag(View* view,
458                                    const ui::OSExchangeData& data,
459                                    const gfx::Point& location,
460                                    int operation,
461                                    ui::DragDropTypes::DragEventSource source) {
462   NOTIMPLEMENTED();
465 void NativeWidgetMac::SchedulePaintInRect(const gfx::Rect& rect) {
466   // TODO(tapted): This should use setNeedsDisplayInRect:, once the coordinate
467   // system of |rect| has been converted.
468   [GetNativeView() setNeedsDisplay:YES];
469   if (bridge_ && bridge_->layer())
470     bridge_->layer()->SchedulePaint(rect);
473 void NativeWidgetMac::SetCursor(gfx::NativeCursor cursor) {
474   if (bridge_)
475     bridge_->SetCursor(cursor);
478 bool NativeWidgetMac::IsMouseEventsEnabled() const {
479   NOTIMPLEMENTED();
480   return true;
483 void NativeWidgetMac::ClearNativeFocus() {
484   // To quote DesktopWindowTreeHostX11, "This method is weird and misnamed."
485   // The goal is to set focus to the content window, thereby removing focus from
486   // any NSView in the window that doesn't belong to toolkit-views.
487   [GetNativeWindow() makeFirstResponder:GetNativeView()];
490 gfx::Rect NativeWidgetMac::GetWorkAreaBoundsInScreen() const {
491   NOTIMPLEMENTED();
492   return gfx::Rect();
495 Widget::MoveLoopResult NativeWidgetMac::RunMoveLoop(
496     const gfx::Vector2d& drag_offset,
497     Widget::MoveLoopSource source,
498     Widget::MoveLoopEscapeBehavior escape_behavior) {
499   NOTIMPLEMENTED();
500   return Widget::MOVE_LOOP_CANCELED;
503 void NativeWidgetMac::EndMoveLoop() {
504   NOTIMPLEMENTED();
507 void NativeWidgetMac::SetVisibilityChangedAnimationsEnabled(bool value) {
508   NOTIMPLEMENTED();
511 void NativeWidgetMac::SetVisibilityAnimationDuration(
512     const base::TimeDelta& duration) {
513   NOTIMPLEMENTED();
516 void NativeWidgetMac::SetVisibilityAnimationTransition(
517     Widget::VisibilityTransition transition) {
518   NOTIMPLEMENTED();
521 ui::NativeTheme* NativeWidgetMac::GetNativeTheme() const {
522   return ui::NativeTheme::instance();
525 void NativeWidgetMac::OnRootViewLayout() {
526   NOTIMPLEMENTED();
529 bool NativeWidgetMac::IsTranslucentWindowOpacitySupported() const {
530   return false;
533 void NativeWidgetMac::OnSizeConstraintsChanged() {
534   NOTIMPLEMENTED();
537 void NativeWidgetMac::RepostNativeEvent(gfx::NativeEvent native_event) {
538   NOTIMPLEMENTED();
541 ////////////////////////////////////////////////////////////////////////////////
542 // Widget, public:
544 bool Widget::ConvertRect(const Widget* source,
545                          const Widget* target,
546                          gfx::Rect* rect) {
547   return false;
550 namespace internal {
552 ////////////////////////////////////////////////////////////////////////////////
553 // internal::NativeWidgetPrivate, public:
555 // static
556 NativeWidgetPrivate* NativeWidgetPrivate::CreateNativeWidget(
557     internal::NativeWidgetDelegate* delegate) {
558   return new NativeWidgetMac(delegate);
561 // static
562 NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeView(
563     gfx::NativeView native_view) {
564   return GetNativeWidgetForNativeWindow([native_view window]);
567 // static
568 NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeWindow(
569     gfx::NativeWindow native_window) {
570   id<NSWindowDelegate> window_delegate = [native_window delegate];
571   if ([window_delegate respondsToSelector:@selector(nativeWidgetMac)]) {
572     ViewsNSWindowDelegate* delegate =
573         base::mac::ObjCCastStrict<ViewsNSWindowDelegate>(window_delegate);
574     return [delegate nativeWidgetMac];
575   }
576   return NULL;  // Not created by NativeWidgetMac.
579 // static
580 NativeWidgetPrivate* NativeWidgetPrivate::GetTopLevelNativeWidget(
581     gfx::NativeView native_view) {
582   BridgedNativeWidget* bridge =
583       NativeWidgetMac::GetBridgeForNativeWindow([native_view window]);
584   if (!bridge)
585     return NULL;
587   for (BridgedNativeWidget* parent;
588        (parent = bridge->parent());
589        bridge = parent) {
590   }
591   return bridge->native_widget_mac();
594 // static
595 void NativeWidgetPrivate::GetAllChildWidgets(gfx::NativeView native_view,
596                                              Widget::Widgets* children) {
597   BridgedNativeWidget* bridge =
598       NativeWidgetMac::GetBridgeForNativeWindow([native_view window]);
599   if (!bridge)
600     return;
602   // If |native_view| is a subview of the contentView, it will share an
603   // NSWindow, but will itself be a native child of the Widget. That is, adding
604   // bridge->..->GetWidget() to |children| would be adding the _parent_ of
605   // |native_view|, not the Widget for |native_view|. |native_view| doesn't have
606   // a corresponding Widget of its own in this case (and so can't have Widget
607   // children of its own on Mac).
608   if (bridge->ns_view() != native_view)
609     return;
611   // Code expects widget for |native_view| to be added to |children|.
612   if (bridge->native_widget_mac()->GetWidget())
613     children->insert(bridge->native_widget_mac()->GetWidget());
615   for (BridgedNativeWidget* child : bridge->child_windows())
616     GetAllChildWidgets(child->ns_view(), children);
619 // static
620 void NativeWidgetPrivate::GetAllOwnedWidgets(gfx::NativeView native_view,
621                                              Widget::Widgets* owned) {
622   NOTIMPLEMENTED();
625 // static
626 void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view,
627                                              gfx::NativeView new_parent) {
628   NOTIMPLEMENTED();
631 // static
632 bool NativeWidgetPrivate::IsMouseButtonDown() {
633   return [NSEvent pressedMouseButtons] != 0;
636 // static
637 gfx::FontList NativeWidgetPrivate::GetWindowTitleFontList() {
638   NOTIMPLEMENTED();
639   return gfx::FontList();
642 }  // namespace internal
643 }  // namespace views