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 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 335 in_fullscreen_transition_(false), | 335 in_fullscreen_transition_(false), |
| 336 window_visible_(false), | 336 window_visible_(false), |
| 337 wants_to_be_visible_(false) { | 337 wants_to_be_visible_(false) { |
| 338 SetupDragEventMonitor(); | 338 SetupDragEventMonitor(); |
| 339 DCHECK(parent); | 339 DCHECK(parent); |
| 340 window_delegate_.reset( | 340 window_delegate_.reset( |
| 341 [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]); | 341 [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]); |
| 342 } | 342 } |
| 343 | 343 |
| 344 BridgedNativeWidget::~BridgedNativeWidget() { | 344 BridgedNativeWidget::~BridgedNativeWidget() { |
| 345 bool close_window = false; | 345 // If the delegate is still set on a modal dialog, it means it was not |
| 346 if ([window_ delegate]) { | 346 // closed via [NSApplication endSheet:]. This is probably OK if the widget |
| 347 // If the delegate is still set on a modal dialog, it means it was not | 347 // was never shown. But Cocoa ignores close() calls on open sheets. Calling |
| 348 // closed via [NSApplication endSheet:]. This is probably OK if the widget | 348 // endSheet: here would work, but it messes up assumptions elsewhere. E.g. |
| 349 // was never shown. But Cocoa ignores close() calls on open sheets. Calling | 349 // DialogClientView assumes its delegate is alive when closing, which isn't |
| 350 // endSheet: here would work, but it messes up assumptions elsewhere. E.g. | 350 // true after endSheet: synchronously calls OnNativeWidgetDestroyed(). |
| 351 // DialogClientView assumes its delegate is alive when closing, which isn't | 351 // So ban it. Modal dialogs should be closed via Widget::Close(). |
| 352 // true after endSheet: synchronously calls OnNativeWidgetDestroyed(). | 352 DCHECK(!close_window_ || !native_widget_mac_->IsWindowModalSheet()); |
| 353 // So ban it. Modal dialogs should be closed via Widget::Close(). | |
| 354 DCHECK(!native_widget_mac_->IsWindowModalSheet()); | |
| 355 | 353 |
| 356 // If the delegate is still set, it means OnWindowWillClose() has not been | 354 [window_ setDelegate:nil]; |
| 357 // called and the window is still open. Usually, -[NSWindow close] would | |
| 358 // synchronously call OnWindowWillClose() which removes the delegate and | |
| 359 // notifies NativeWidgetMac, which then calls this with a nil delegate. | |
| 360 // For other teardown flows (e.g. Widget::WIDGET_OWNS_NATIVE_WIDGET or | |
| 361 // Widget::CloseNow()) the delegate must first be cleared to avoid AppKit | |
| 362 // calling back into the bridge. This means OnWindowWillClose() needs to be | |
| 363 // invoked manually, which is done below. | |
| 364 // Note that if the window has children it can't be closed until the | |
| 365 // children are gone, but removing child windows calls into AppKit for the | |
| 366 // parent window, so the delegate must be cleared first. | |
| 367 [window_ setDelegate:nil]; | |
| 368 close_window = true; | |
| 369 } | |
| 370 | |
| 371 RemoveOrDestroyChildren(); | 355 RemoveOrDestroyChildren(); |
| 372 DCHECK(child_windows_.empty()); | 356 DCHECK(child_windows_.empty()); |
| 373 SetFocusManager(nullptr); | 357 SetFocusManager(nullptr); |
| 374 SetRootView(nullptr); | 358 SetRootView(nullptr); |
| 375 DestroyCompositor(); | 359 DestroyCompositor(); |
| 376 | 360 |
| 377 if (close_window) { | 361 if (close_window_) { |
| 378 OnWindowWillClose(); | 362 OnWindowWillClose(); |
| 379 [window_ close]; | 363 [window_ close]; |
| 380 } | 364 } |
| 381 } | 365 } |
| 382 | 366 |
| 383 void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window, | 367 void BridgedNativeWidget::Init(base::scoped_nsobject<NSWindow> window, |
| 384 const Widget::InitParams& params) { | 368 const Widget::InitParams& params) { |
| 385 widget_type_ = params.type; | 369 widget_type_ = params.type; |
| 386 | 370 |
| 387 DCHECK(!window_); | 371 DCHECK(!window_); |
| (...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 700 // called via ~CocoaMouseCapture() upon the destruction of |mouse_capture_|. | 684 // called via ~CocoaMouseCapture() upon the destruction of |mouse_capture_|. |
| 701 // See crbug.com/622201. Also we do this before setting the delegate to nil, | 685 // See crbug.com/622201. Also we do this before setting the delegate to nil, |
| 702 // because this may lead to callbacks to bridge which rely on a valid | 686 // because this may lead to callbacks to bridge which rely on a valid |
| 703 // delegate. | 687 // delegate. |
| 704 ReleaseCapture(); | 688 ReleaseCapture(); |
| 705 | 689 |
| 706 if (parent_) { | 690 if (parent_) { |
| 707 parent_->RemoveChildWindow(this); | 691 parent_->RemoveChildWindow(this); |
| 708 parent_ = nullptr; | 692 parent_ = nullptr; |
| 709 } | 693 } |
| 710 [window_ setDelegate:nil]; | 694 close_window_ = false; |
| 711 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; | 695 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; |
| 712 native_widget_mac_->OnWindowWillClose(); | 696 native_widget_mac_->OnWindowWillClose(); |
|
tapted
2016/10/05 08:38:18
Is the problem just that NativeWidgetMac::OnWindow
| |
| 713 } | 697 } |
| 714 | 698 |
| 715 void BridgedNativeWidget::OnFullscreenTransitionStart( | 699 void BridgedNativeWidget::OnFullscreenTransitionStart( |
| 716 bool target_fullscreen_state) { | 700 bool target_fullscreen_state) { |
| 717 // Note: This can fail for fullscreen changes started externally, but a user | 701 // Note: This can fail for fullscreen changes started externally, but a user |
| 718 // shouldn't be able to do that if the window is invisible to begin with. | 702 // shouldn't be able to do that if the window is invisible to begin with. |
| 719 DCHECK(window_visible_); | 703 DCHECK(window_visible_); |
| 720 | 704 |
| 721 DCHECK_NE(target_fullscreen_state, target_fullscreen_state_); | 705 DCHECK_NE(target_fullscreen_state, target_fullscreen_state_); |
| 722 target_fullscreen_state_ = target_fullscreen_state; | 706 target_fullscreen_state_ = target_fullscreen_state; |
| (...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1390 [bridged_view_ setMouseDownCanMoveWindow:draggable]; | 1374 [bridged_view_ setMouseDownCanMoveWindow:draggable]; |
| 1391 // AppKit will not update its cache of mouseDownCanMoveWindow unless something | 1375 // AppKit will not update its cache of mouseDownCanMoveWindow unless something |
| 1392 // changes. Previously we tried adding an NSView and removing it, but for some | 1376 // changes. Previously we tried adding an NSView and removing it, but for some |
| 1393 // reason it required reposting the mouse-down event, and didn't always work. | 1377 // reason it required reposting the mouse-down event, and didn't always work. |
| 1394 // Calling the below seems to be an effective solution. | 1378 // Calling the below seems to be an effective solution. |
| 1395 [window_ setMovableByWindowBackground:NO]; | 1379 [window_ setMovableByWindowBackground:NO]; |
| 1396 [window_ setMovableByWindowBackground:YES]; | 1380 [window_ setMovableByWindowBackground:YES]; |
| 1397 } | 1381 } |
| 1398 | 1382 |
| 1399 } // namespace views | 1383 } // namespace views |
| OLD | NEW |