OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ui/views/cocoa/bridged_native_widget.h" | 5 #import "ui/views/cocoa/bridged_native_widget.h" |
6 | 6 |
7 #import <objc/runtime.h> | 7 #import <objc/runtime.h> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/mac/mac_util.h" | 10 #include "base/mac/mac_util.h" |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]); | 80 [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]); |
81 } | 81 } |
82 | 82 |
83 BridgedNativeWidget::~BridgedNativeWidget() { | 83 BridgedNativeWidget::~BridgedNativeWidget() { |
84 RemoveOrDestroyChildren(); | 84 RemoveOrDestroyChildren(); |
85 DCHECK(child_windows_.empty()); | 85 DCHECK(child_windows_.empty()); |
86 SetFocusManager(NULL); | 86 SetFocusManager(NULL); |
87 SetRootView(NULL); | 87 SetRootView(NULL); |
88 DestroyCompositor(); | 88 DestroyCompositor(); |
89 if ([window_ delegate]) { | 89 if ([window_ delegate]) { |
| 90 // If the delegate is still set on a modal dialog, it means it was not |
| 91 // closed via [NSApplication endSheet:]. This is probably OK if the widget |
| 92 // was never shown. But Cocoa ignores close() calls on open sheets. Calling |
| 93 // endSheet: here would work, but it messes up assumptions elsewhere. E.g. |
| 94 // DialogClientView assumes its delegate is alive when closing, which isn't |
| 95 // true after endSheet: synchronously calls OnNativeWidgetDestroyed(). |
| 96 // So ban it. Modal dialogs should be closed via Widget::Close(). |
| 97 DCHECK(!native_widget_mac_->GetWidget()->IsModal()); |
| 98 |
90 // If the delegate is still set, it means OnWindowWillClose has not been | 99 // If the delegate is still set, it means OnWindowWillClose has not been |
91 // called and the window is still open. Calling -[NSWindow close] will | 100 // called and the window is still open. Calling -[NSWindow close] will |
92 // synchronously call OnWindowWillClose and notify NativeWidgetMac. | 101 // synchronously call OnWindowWillClose and notify NativeWidgetMac. |
93 [window_ close]; | 102 [window_ close]; |
94 } | 103 } |
95 DCHECK(![window_ delegate]); | 104 DCHECK(![window_ delegate]); |
96 } | 105 } |
97 | 106 |
98 void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window, | 107 void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window, |
99 const Widget::InitParams& params) { | 108 const Widget::InitParams& params) { |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 focus_manager->AddFocusChangeListener(this); | 182 focus_manager->AddFocusChangeListener(this); |
174 | 183 |
175 focus_manager_ = focus_manager; | 184 focus_manager_ = focus_manager; |
176 } | 185 } |
177 | 186 |
178 void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds) { | 187 void BridgedNativeWidget::SetBounds(const gfx::Rect& new_bounds) { |
179 // A contentRect with zero width or height is a banned practice in ChromeMac, | 188 // A contentRect with zero width or height is a banned practice in ChromeMac, |
180 // due to unpredictable OSX treatment. | 189 // due to unpredictable OSX treatment. |
181 DCHECK(!new_bounds.IsEmpty()) << "Zero-sized windows not supported on Mac"; | 190 DCHECK(!new_bounds.IsEmpty()) << "Zero-sized windows not supported on Mac"; |
182 | 191 |
| 192 if (native_widget_mac_->GetWidget()->IsModal()) { |
| 193 // Modal dialogs are positioned by Cocoa. Just update the size. |
| 194 [window_ |
| 195 setContentSize:NSMakeSize(new_bounds.width(), new_bounds.height())]; |
| 196 return; |
| 197 } |
| 198 |
183 gfx::Rect actual_new_bounds(new_bounds); | 199 gfx::Rect actual_new_bounds(new_bounds); |
184 | 200 |
185 if (parent_ && | 201 if (parent_ && |
186 !PositionWindowInScreenCoordinates(native_widget_mac_->GetWidget(), | 202 !PositionWindowInScreenCoordinates(native_widget_mac_->GetWidget(), |
187 widget_type_)) | 203 widget_type_)) |
188 actual_new_bounds.Offset(parent_->GetRestoredBounds().OffsetFromOrigin()); | 204 actual_new_bounds.Offset(parent_->GetRestoredBounds().OffsetFromOrigin()); |
189 | 205 |
190 [window_ setFrame:gfx::ScreenRectToNSRect(actual_new_bounds) | 206 [window_ setFrame:gfx::ScreenRectToNSRect(actual_new_bounds) |
191 display:YES | 207 display:YES |
192 animate:NO]; | 208 animate:NO]; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 DCHECK(wants_to_be_visible_); | 248 DCHECK(wants_to_be_visible_); |
233 | 249 |
234 // If there's a hidden ancestor, return and wait for it to become visible. | 250 // If there's a hidden ancestor, return and wait for it to become visible. |
235 for (BridgedNativeWidget* ancestor = parent(); | 251 for (BridgedNativeWidget* ancestor = parent(); |
236 ancestor; | 252 ancestor; |
237 ancestor = ancestor->parent()) { | 253 ancestor = ancestor->parent()) { |
238 if (!ancestor->window_visible_) | 254 if (!ancestor->window_visible_) |
239 return; | 255 return; |
240 } | 256 } |
241 | 257 |
| 258 if (native_widget_mac_->GetWidget()->IsModal()) { |
| 259 NSWindow* parent_window = parent_->ns_window(); |
| 260 DCHECK(parent_window); |
| 261 |
| 262 [NSApp beginSheet:window_ |
| 263 modalForWindow:parent_window |
| 264 modalDelegate:[window_ delegate] |
| 265 didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) |
| 266 contextInfo:nullptr]; |
| 267 return; |
| 268 } |
| 269 |
242 if (new_state == SHOW_AND_ACTIVATE_WINDOW) { | 270 if (new_state == SHOW_AND_ACTIVATE_WINDOW) { |
243 [window_ makeKeyAndOrderFront:nil]; | 271 [window_ makeKeyAndOrderFront:nil]; |
244 [NSApp activateIgnoringOtherApps:YES]; | 272 [NSApp activateIgnoringOtherApps:YES]; |
245 } else { | 273 } else { |
246 // ui::SHOW_STATE_INACTIVE is typically used to avoid stealing focus from a | 274 // ui::SHOW_STATE_INACTIVE is typically used to avoid stealing focus from a |
247 // parent window. So, if there's a parent, order above that. Otherwise, this | 275 // parent window. So, if there's a parent, order above that. Otherwise, this |
248 // will order above all windows at the same level. | 276 // will order above all windows at the same level. |
249 NSInteger parent_window_number = 0; | 277 NSInteger parent_window_number = 0; |
250 if (parent()) | 278 if (parent()) |
251 parent_window_number = [parent()->ns_window() windowNumber]; | 279 parent_window_number = [parent()->ns_window() windowNumber]; |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 if (layer()) | 471 if (layer()) |
444 UpdateLayerProperties(); | 472 UpdateLayerProperties(); |
445 } | 473 } |
446 | 474 |
447 void BridgedNativeWidget::OnWindowKeyStatusChangedTo(bool is_key) { | 475 void BridgedNativeWidget::OnWindowKeyStatusChangedTo(bool is_key) { |
448 Widget* widget = native_widget_mac()->GetWidget(); | 476 Widget* widget = native_widget_mac()->GetWidget(); |
449 widget->OnNativeWidgetActivationChanged(is_key); | 477 widget->OnNativeWidgetActivationChanged(is_key); |
450 // The contentView is the BridgedContentView hosting the views::RootView. The | 478 // The contentView is the BridgedContentView hosting the views::RootView. The |
451 // focus manager will already know if a native subview has focus. | 479 // focus manager will already know if a native subview has focus. |
452 if ([window_ contentView] == [window_ firstResponder]) { | 480 if ([window_ contentView] == [window_ firstResponder]) { |
453 if (is_key) | 481 if (is_key) { |
| 482 widget->OnNativeFocus(); |
454 widget->GetFocusManager()->RestoreFocusedView(); | 483 widget->GetFocusManager()->RestoreFocusedView(); |
455 else | 484 } else { |
| 485 widget->OnNativeBlur(); |
456 widget->GetFocusManager()->StoreFocusedView(true); | 486 widget->GetFocusManager()->StoreFocusedView(true); |
| 487 } |
457 } | 488 } |
458 } | 489 } |
459 | 490 |
460 InputMethod* BridgedNativeWidget::CreateInputMethod() { | 491 InputMethod* BridgedNativeWidget::CreateInputMethod() { |
461 if (switches::IsTextInputFocusManagerEnabled()) | 492 if (switches::IsTextInputFocusManagerEnabled()) |
462 return new NullInputMethod(); | 493 return new NullInputMethod(); |
463 | 494 |
464 return new InputMethodBridge(this, GetHostInputMethod(), true); | 495 return new InputMethodBridge(this, GetHostInputMethod(), true); |
465 } | 496 } |
466 | 497 |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
753 window_, &kWindowPropertiesKey); | 784 window_, &kWindowPropertiesKey); |
754 if (!properties) { | 785 if (!properties) { |
755 properties = [NSMutableDictionary dictionary]; | 786 properties = [NSMutableDictionary dictionary]; |
756 objc_setAssociatedObject(window_, &kWindowPropertiesKey, | 787 objc_setAssociatedObject(window_, &kWindowPropertiesKey, |
757 properties, OBJC_ASSOCIATION_RETAIN); | 788 properties, OBJC_ASSOCIATION_RETAIN); |
758 } | 789 } |
759 return properties; | 790 return properties; |
760 } | 791 } |
761 | 792 |
762 } // namespace views | 793 } // namespace views |
OLD | NEW |