Chromium Code Reviews| 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 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <stdint.h> | 9 #include <stdint.h> |
| 10 | 10 |
| (...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 346 in_fullscreen_transition_(false), | 346 in_fullscreen_transition_(false), |
| 347 window_visible_(false), | 347 window_visible_(false), |
| 348 wants_to_be_visible_(false) { | 348 wants_to_be_visible_(false) { |
| 349 SetupDragEventMonitor(); | 349 SetupDragEventMonitor(); |
| 350 DCHECK(parent); | 350 DCHECK(parent); |
| 351 window_delegate_.reset( | 351 window_delegate_.reset( |
| 352 [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]); | 352 [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]); |
| 353 } | 353 } |
| 354 | 354 |
| 355 BridgedNativeWidget::~BridgedNativeWidget() { | 355 BridgedNativeWidget::~BridgedNativeWidget() { |
| 356 bool close_window = false; | 356 // The delegate should be cleared already. Note this enforces the precondition |
| 357 if ([window_ delegate]) { | 357 // that the hosted NSWindow is closed before the destructor is called. |
|
karandeepb
2016/10/18 10:00:29
Technically, the window hasn't closed yet right? W
tapted
2016/10/19 06:20:25
Done.
| |
| 358 // If the delegate is still set on a modal dialog, it means it was not | 358 DCHECK(![window_ delegate]); |
| 359 // closed via [NSApplication endSheet:]. This is probably OK if the widget | |
| 360 // was never shown. But Cocoa ignores close() calls on open sheets. Calling | |
| 361 // endSheet: here would work, but it messes up assumptions elsewhere. E.g. | |
| 362 // DialogClientView assumes its delegate is alive when closing, which isn't | |
| 363 // true after endSheet: synchronously calls OnNativeWidgetDestroyed(). | |
| 364 // So ban it. Modal dialogs should be closed via Widget::Close(). | |
| 365 DCHECK(!native_widget_mac_->IsWindowModalSheet()); | |
| 366 | |
| 367 // If the delegate is still set, it means OnWindowWillClose() has not been | |
| 368 // called and the window is still open. Usually, -[NSWindow close] would | |
| 369 // synchronously call OnWindowWillClose() which removes the delegate and | |
| 370 // notifies NativeWidgetMac, which then calls this with a nil delegate. | |
| 371 // For other teardown flows (e.g. Widget::WIDGET_OWNS_NATIVE_WIDGET or | |
| 372 // Widget::CloseNow()) the delegate must first be cleared to avoid AppKit | |
| 373 // calling back into the bridge. This means OnWindowWillClose() needs to be | |
| 374 // invoked manually, which is done below. | |
| 375 // Note that if the window has children it can't be closed until the | |
| 376 // children are gone, but removing child windows calls into AppKit for the | |
| 377 // parent window, so the delegate must be cleared first. | |
| 378 [window_ setDelegate:nil]; | |
| 379 close_window = true; | |
| 380 } | |
| 381 | 359 |
| 382 RemoveOrDestroyChildren(); | 360 RemoveOrDestroyChildren(); |
| 383 DCHECK(child_windows_.empty()); | 361 DCHECK(child_windows_.empty()); |
| 384 SetFocusManager(nullptr); | 362 SetFocusManager(nullptr); |
| 385 SetRootView(nullptr); | 363 SetRootView(nullptr); |
| 386 DestroyCompositor(); | 364 DestroyCompositor(); |
| 387 | |
| 388 if (close_window) { | |
| 389 OnWindowWillClose(); | |
| 390 [window_ close]; | |
| 391 } | |
| 392 } | 365 } |
| 393 | 366 |
| 394 void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window, | 367 void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window, |
| 395 const Widget::InitParams& params) { | 368 const Widget::InitParams& params) { |
| 396 widget_type_ = params.type; | 369 widget_type_ = params.type; |
| 397 | 370 |
| 398 DCHECK(!window_); | 371 DCHECK(!window_); |
| 399 window_.swap(window); | 372 window_.swap(window); |
| 400 [window_ setDelegate:window_delegate_]; | 373 [window_ setDelegate:window_delegate_]; |
| 401 | 374 |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 699 void* BridgedNativeWidget::GetNativeWindowProperty(const char* name) const { | 672 void* BridgedNativeWidget::GetNativeWindowProperty(const char* name) const { |
| 700 NSString* key = [NSString stringWithUTF8String:name]; | 673 NSString* key = [NSString stringWithUTF8String:name]; |
| 701 return [[GetWindowProperties() objectForKey:key] pointerValue]; | 674 return [[GetWindowProperties() objectForKey:key] pointerValue]; |
| 702 } | 675 } |
| 703 | 676 |
| 704 void BridgedNativeWidget::SetCursor(NSCursor* cursor) { | 677 void BridgedNativeWidget::SetCursor(NSCursor* cursor) { |
| 705 [window_delegate_ setCursor:cursor]; | 678 [window_delegate_ setCursor:cursor]; |
| 706 } | 679 } |
| 707 | 680 |
| 708 void BridgedNativeWidget::OnWindowWillClose() { | 681 void BridgedNativeWidget::OnWindowWillClose() { |
| 682 native_widget_mac_->GetWidget()->OnNativeWidgetDestroying(); | |
| 683 | |
| 709 // Ensure BridgedNativeWidget does not have capture, otherwise | 684 // Ensure BridgedNativeWidget does not have capture, otherwise |
| 710 // OnMouseCaptureLost() may reference a deleted |native_widget_mac_| when | 685 // OnMouseCaptureLost() may reference a deleted |native_widget_mac_| when |
| 711 // called via ~CocoaMouseCapture() upon the destruction of |mouse_capture_|. | 686 // called via ~CocoaMouseCapture() upon the destruction of |mouse_capture_|. |
| 712 // See crbug.com/622201. Also we do this before setting the delegate to nil, | 687 // See crbug.com/622201. Also we do this before setting the delegate to nil, |
| 713 // because this may lead to callbacks to bridge which rely on a valid | 688 // because this may lead to callbacks to bridge which rely on a valid |
| 714 // delegate. | 689 // delegate. |
| 715 ReleaseCapture(); | 690 ReleaseCapture(); |
| 716 | 691 |
| 717 if (parent_) { | 692 if (parent_) { |
| 718 parent_->RemoveChildWindow(this); | 693 parent_->RemoveChildWindow(this); |
| 719 parent_ = nullptr; | 694 parent_ = nullptr; |
| 720 } | 695 } |
| 721 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; | 696 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; |
| 722 // Note this also clears the NSWindow delegate, after informing Widget | 697 [window_ setDelegate:nil]; |
| 723 // delegates about the closure. NativeWidgetMac then deletes |this| before | 698 native_widget_mac_->OnWindowDestroyed(); |
| 724 // returning. | 699 // Note: |this| is deleted here. |
| 725 native_widget_mac_->OnWindowWillClose(); | |
| 726 } | 700 } |
| 727 | 701 |
| 728 void BridgedNativeWidget::OnFullscreenTransitionStart( | 702 void BridgedNativeWidget::OnFullscreenTransitionStart( |
| 729 bool target_fullscreen_state) { | 703 bool target_fullscreen_state) { |
| 730 // Note: This can fail for fullscreen changes started externally, but a user | 704 // Note: This can fail for fullscreen changes started externally, but a user |
| 731 // shouldn't be able to do that if the window is invisible to begin with. | 705 // shouldn't be able to do that if the window is invisible to begin with. |
| 732 DCHECK(window_visible_); | 706 DCHECK(window_visible_); |
| 733 | 707 |
| 734 DCHECK_NE(target_fullscreen_state, target_fullscreen_state_); | 708 DCHECK_NE(target_fullscreen_state, target_fullscreen_state_); |
| 735 target_fullscreen_state_ = target_fullscreen_state; | 709 target_fullscreen_state_ = target_fullscreen_state; |
| (...skipping 666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1402 [bridged_view_ setMouseDownCanMoveWindow:draggable]; | 1376 [bridged_view_ setMouseDownCanMoveWindow:draggable]; |
| 1403 // AppKit will not update its cache of mouseDownCanMoveWindow unless something | 1377 // AppKit will not update its cache of mouseDownCanMoveWindow unless something |
| 1404 // changes. Previously we tried adding an NSView and removing it, but for some | 1378 // changes. Previously we tried adding an NSView and removing it, but for some |
| 1405 // reason it required reposting the mouse-down event, and didn't always work. | 1379 // reason it required reposting the mouse-down event, and didn't always work. |
| 1406 // Calling the below seems to be an effective solution. | 1380 // Calling the below seems to be an effective solution. |
| 1407 [window_ setMovableByWindowBackground:NO]; | 1381 [window_ setMovableByWindowBackground:NO]; |
| 1408 [window_ setMovableByWindowBackground:YES]; | 1382 [window_ setMovableByWindowBackground:YES]; |
| 1409 } | 1383 } |
| 1410 | 1384 |
| 1411 } // namespace views | 1385 } // namespace views |
| OLD | NEW |