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 |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #import "base/mac/bind_objc_block.h" |
12 #import "base/mac/foundation_util.h" | 13 #import "base/mac/foundation_util.h" |
13 #include "base/mac/mac_util.h" | 14 #include "base/mac/mac_util.h" |
14 #import "base/mac/sdk_forward_declarations.h" | 15 #import "base/mac/sdk_forward_declarations.h" |
15 #include "base/threading/thread_task_runner_handle.h" | 16 #include "base/threading/thread_task_runner_handle.h" |
16 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h" | 17 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h" |
17 #import "ui/base/cocoa/constrained_window/constrained_window_animation.h" | 18 #import "ui/base/cocoa/constrained_window/constrained_window_animation.h" |
18 #include "ui/base/hit_test.h" | 19 #include "ui/base/hit_test.h" |
19 #include "ui/base/ime/input_method.h" | 20 #include "ui/base/ime/input_method.h" |
20 #include "ui/base/ime/input_method_factory.h" | 21 #include "ui/base/ime/input_method_factory.h" |
21 #include "ui/display/display.h" | 22 #include "ui/display/display.h" |
22 #include "ui/display/screen.h" | 23 #include "ui/display/screen.h" |
23 #include "ui/gfx/geometry/dip_util.h" | 24 #include "ui/gfx/geometry/dip_util.h" |
24 #import "ui/gfx/mac/coordinate_conversion.h" | 25 #import "ui/gfx/mac/coordinate_conversion.h" |
25 #import "ui/gfx/mac/nswindow_frame_controls.h" | 26 #import "ui/gfx/mac/nswindow_frame_controls.h" |
26 #import "ui/views/cocoa/bridged_content_view.h" | 27 #import "ui/views/cocoa/bridged_content_view.h" |
27 #import "ui/views/cocoa/drag_drop_client_mac.h" | 28 #import "ui/views/cocoa/drag_drop_client_mac.h" |
28 #import "ui/views/cocoa/cocoa_mouse_capture.h" | 29 #import "ui/views/cocoa/cocoa_mouse_capture.h" |
29 #import "ui/views/cocoa/cocoa_window_move_loop.h" | 30 #import "ui/views/cocoa/cocoa_window_move_loop.h" |
30 #include "ui/views/cocoa/tooltip_manager_mac.h" | 31 #include "ui/views/cocoa/tooltip_manager_mac.h" |
| 32 #import "ui/views/cocoa/views_nswindow_close_animator.h" |
31 #import "ui/views/cocoa/views_nswindow_delegate.h" | 33 #import "ui/views/cocoa/views_nswindow_delegate.h" |
32 #import "ui/views/cocoa/widget_owner_nswindow_adapter.h" | 34 #import "ui/views/cocoa/widget_owner_nswindow_adapter.h" |
33 #include "ui/views/view.h" | 35 #include "ui/views/view.h" |
34 #include "ui/views/views_delegate.h" | 36 #include "ui/views/views_delegate.h" |
35 #include "ui/views/widget/native_widget_mac.h" | 37 #include "ui/views/widget/native_widget_mac.h" |
36 #include "ui/views/widget/widget.h" | 38 #include "ui/views/widget/widget.h" |
37 #include "ui/views/widget/widget_aura_utils.h" | 39 #include "ui/views/widget/widget_aura_utils.h" |
38 #include "ui/views/widget/widget_delegate.h" | 40 #include "ui/views/widget/widget_delegate.h" |
39 | 41 |
40 extern "C" { | 42 extern "C" { |
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
343 BridgedNativeWidget::~BridgedNativeWidget() { | 345 BridgedNativeWidget::~BridgedNativeWidget() { |
344 bool close_window = false; | 346 bool close_window = false; |
345 if ([window_ delegate]) { | 347 if ([window_ delegate]) { |
346 // If the delegate is still set on a modal dialog, it means it was not | 348 // If the delegate is still set on a modal dialog, it means it was not |
347 // closed via [NSApplication endSheet:]. This is probably OK if the widget | 349 // closed via [NSApplication endSheet:]. This is probably OK if the widget |
348 // was never shown. But Cocoa ignores close() calls on open sheets. Calling | 350 // was never shown. But Cocoa ignores close() calls on open sheets. Calling |
349 // endSheet: here would work, but it messes up assumptions elsewhere. E.g. | 351 // endSheet: here would work, but it messes up assumptions elsewhere. E.g. |
350 // DialogClientView assumes its delegate is alive when closing, which isn't | 352 // DialogClientView assumes its delegate is alive when closing, which isn't |
351 // true after endSheet: synchronously calls OnNativeWidgetDestroyed(). | 353 // true after endSheet: synchronously calls OnNativeWidgetDestroyed(). |
352 // So ban it. Modal dialogs should be closed via Widget::Close(). | 354 // So ban it. Modal dialogs should be closed via Widget::Close(). |
353 DCHECK(!native_widget_mac_->IsWindowModalSheet()); | 355 DCHECK(!IsWindowModalSheet()); |
354 | 356 |
355 // If the delegate is still set, it means OnWindowWillClose() has not been | 357 // If the delegate is still set, it means OnWindowWillClose() has not been |
356 // called and the window is still open. Usually, -[NSWindow close] would | 358 // called and the window is still open. Usually, -[NSWindow close] would |
357 // synchronously call OnWindowWillClose() which removes the delegate and | 359 // synchronously call OnWindowWillClose() which removes the delegate and |
358 // notifies NativeWidgetMac, which then calls this with a nil delegate. | 360 // notifies NativeWidgetMac, which then calls this with a nil delegate. |
359 // For other teardown flows (e.g. Widget::WIDGET_OWNS_NATIVE_WIDGET or | 361 // For other teardown flows (e.g. Widget::WIDGET_OWNS_NATIVE_WIDGET or |
360 // Widget::CloseNow()) the delegate must first be cleared to avoid AppKit | 362 // Widget::CloseNow()) the delegate must first be cleared to avoid AppKit |
361 // calling back into the bridge. This means OnWindowWillClose() needs to be | 363 // calling back into the bridge. This means OnWindowWillClose() needs to be |
362 // invoked manually, which is done below. | 364 // invoked manually, which is done below. |
363 // Note that if the window has children it can't be closed until the | 365 // Note that if the window has children it can't be closed until the |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
487 // no check for maximum size (consistent with aura::Window::SetBounds()). | 489 // no check for maximum size (consistent with aura::Window::SetBounds()). |
488 gfx::Size clamped_content_size = | 490 gfx::Size clamped_content_size = |
489 GetClientSizeForWindowSize(window_, new_bounds.size()); | 491 GetClientSizeForWindowSize(window_, new_bounds.size()); |
490 clamped_content_size.SetToMax(widget->GetMinimumSize()); | 492 clamped_content_size.SetToMax(widget->GetMinimumSize()); |
491 | 493 |
492 // A contentRect with zero width or height is a banned practice in ChromeMac, | 494 // A contentRect with zero width or height is a banned practice in ChromeMac, |
493 // due to unpredictable OSX treatment. | 495 // due to unpredictable OSX treatment. |
494 DCHECK(!clamped_content_size.IsEmpty()) | 496 DCHECK(!clamped_content_size.IsEmpty()) |
495 << "Zero-sized windows not supported on Mac"; | 497 << "Zero-sized windows not supported on Mac"; |
496 | 498 |
497 if (!window_visible_ && native_widget_mac_->IsWindowModalSheet()) { | 499 if (!window_visible_ && IsWindowModalSheet()) { |
498 // Window-Modal dialogs (i.e. sheets) are positioned by Cocoa when shown for | 500 // Window-Modal dialogs (i.e. sheets) are positioned by Cocoa when shown for |
499 // the first time. They also have no frame, so just update the content size. | 501 // the first time. They also have no frame, so just update the content size. |
500 [window_ setContentSize:NSMakeSize(clamped_content_size.width(), | 502 [window_ setContentSize:NSMakeSize(clamped_content_size.width(), |
501 clamped_content_size.height())]; | 503 clamped_content_size.height())]; |
502 return; | 504 return; |
503 } | 505 } |
504 gfx::Rect actual_new_bounds( | 506 gfx::Rect actual_new_bounds( |
505 new_bounds.origin(), | 507 new_bounds.origin(), |
506 GetWindowSizeForClientSize(window_, clamped_content_size)); | 508 GetWindowSizeForClientSize(window_, clamped_content_size)); |
507 | 509 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
552 DCHECK(!window_visible_); | 554 DCHECK(!window_visible_); |
553 return; | 555 return; |
554 } | 556 } |
555 | 557 |
556 DCHECK(wants_to_be_visible_); | 558 DCHECK(wants_to_be_visible_); |
557 // If the parent (or an ancestor) is hidden, return and wait for it to become | 559 // If the parent (or an ancestor) is hidden, return and wait for it to become |
558 // visible. | 560 // visible. |
559 if (parent() && !parent()->IsVisibleParent()) | 561 if (parent() && !parent()->IsVisibleParent()) |
560 return; | 562 return; |
561 | 563 |
562 if (native_widget_mac_->IsWindowModalSheet()) { | 564 if (IsWindowModalSheet()) { |
563 ShowAsModalSheet(); | 565 ShowAsModalSheet(); |
564 return; | 566 return; |
565 } | 567 } |
566 | 568 |
567 if (new_state == SHOW_AND_ACTIVATE_WINDOW) { | 569 if (new_state == SHOW_AND_ACTIVATE_WINDOW) { |
568 [window_ makeKeyAndOrderFront:nil]; | 570 [window_ makeKeyAndOrderFront:nil]; |
569 [NSApp activateIgnoringOtherApps:YES]; | 571 [NSApp activateIgnoringOtherApps:YES]; |
570 } else { | 572 } else { |
571 // ui::SHOW_STATE_INACTIVE is typically used to avoid stealing focus from a | 573 // ui::SHOW_STATE_INACTIVE is typically used to avoid stealing focus from a |
572 // parent window. So, if there's a parent, order above that. Otherwise, this | 574 // parent window. So, if there's a parent, order above that. Otherwise, this |
(...skipping 16 matching lines...) Expand all Loading... |
589 // duration of the animation, but would keep it smooth. The window also | 591 // duration of the animation, but would keep it smooth. The window also |
590 // hasn't yet received a frame from the compositor at this stage, so it is | 592 // hasn't yet received a frame from the compositor at this stage, so it is |
591 // fully transparent until the GPU sends a frame swap IPC. For the blocking | 593 // fully transparent until the GPU sends a frame swap IPC. For the blocking |
592 // option, the animation needs to wait until AcceleratedWidgetSwapCompleted | 594 // option, the animation needs to wait until AcceleratedWidgetSwapCompleted |
593 // has been called at least once, otherwise it will animate nothing. | 595 // has been called at least once, otherwise it will animate nothing. |
594 [show_animation setAnimationBlockingMode:NSAnimationNonblocking]; | 596 [show_animation setAnimationBlockingMode:NSAnimationNonblocking]; |
595 [show_animation startAnimation]; | 597 [show_animation startAnimation]; |
596 } | 598 } |
597 } | 599 } |
598 | 600 |
| 601 void BridgedNativeWidget::CloseAsynchronously() { |
| 602 // In a past life, the window would be synchronously hidden for the non-modal |
| 603 // case. AppKit UI could do funny things before an asynchronous close finished |
| 604 // (see http://crbug.com/156101). But that shouldn't be needed with toolkit- |
| 605 // views. But a synchronous hide would have released capture, so do it now. |
| 606 ReleaseCapture(); |
| 607 |
| 608 if (IsWindowModalSheet()) { |
| 609 // Sheets can't be closed normally. This starts the sheet closing. Once the |
| 610 // sheet has finished animating, it will call sheetDidEnd: on the parent |
| 611 // window's delegate. Note it still needs to be asynchronous, since code |
| 612 // calling Widget::Close() doesn't expect things to be deleted upon return. |
| 613 [NSApp performSelector:@selector(endSheet:) |
| 614 withObject:window_ |
| 615 afterDelay:0]; |
| 616 return; |
| 617 } |
| 618 |
| 619 // For other modal types, animate the close. |
| 620 if (native_widget_mac_->GetWidget()->IsModal()) { |
| 621 CloseNativeWindowWithAnimation(window_); |
| 622 return; |
| 623 } |
| 624 |
| 625 // Clear the view early to suppress repaints. |
| 626 SetRootView(nullptr); |
| 627 |
| 628 // Widget::Close() ensures [Non]ClientView::CanClose() returns true, so there |
| 629 // is no need to call the NSWindow or its delegate's -windowShouldClose: |
| 630 // implementation in the manner of -[NSWindow performClose:]. |
| 631 |
| 632 // Many tests assume that base::RunLoop().RunUntilIdle() is always sufficient |
| 633 // to execute a close. However, in rare cases, -performSelector:..afterDelay:0 |
| 634 // does not do this. So post a regular task. |
| 635 NSWindow* window = window_; // Ensure the block retains the window. |
| 636 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindBlock(^{ |
| 637 [window close]; |
| 638 })); |
| 639 } |
| 640 |
599 void BridgedNativeWidget::AcquireCapture() { | 641 void BridgedNativeWidget::AcquireCapture() { |
600 DCHECK(!HasCapture()); | 642 DCHECK(!HasCapture()); |
601 if (!window_visible_) | 643 if (!window_visible_) |
602 return; // Capture on hidden windows is disallowed. | 644 return; // Capture on hidden windows is disallowed. |
603 | 645 |
604 mouse_capture_.reset(new CocoaMouseCapture(this)); | 646 mouse_capture_.reset(new CocoaMouseCapture(this)); |
605 | 647 |
606 // Initiating global event capture with addGlobalMonitorForEventsMatchingMask: | 648 // Initiating global event capture with addGlobalMonitorForEventsMatchingMask: |
607 // will reset the mouse cursor to an arrow. Asking the window for an update | 649 // will reset the mouse cursor to an arrow. Asking the window for an update |
608 // here will restore what we want. However, it can sometimes cause the cursor | 650 // here will restore what we want. However, it can sometimes cause the cursor |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
802 } else { | 844 } else { |
803 ReleaseCapture(); // Capture on hidden windows is not permitted. | 845 ReleaseCapture(); // Capture on hidden windows is not permitted. |
804 | 846 |
805 // When becoming invisible, remove the entry in any parent's childWindow | 847 // When becoming invisible, remove the entry in any parent's childWindow |
806 // list. Cocoa's childWindow management breaks down when child windows are | 848 // list. Cocoa's childWindow management breaks down when child windows are |
807 // hidden. | 849 // hidden. |
808 if (parent_) | 850 if (parent_) |
809 [parent_->GetNSWindow() removeChildWindow:window_]; | 851 [parent_->GetNSWindow() removeChildWindow:window_]; |
810 } | 852 } |
811 | 853 |
| 854 NotifyVisibilityChangeDown(); |
| 855 |
| 856 // Toolkit-views suppresses redraws while not visible. To prevent Cocoa asking |
| 857 // for an "empty" draw, disable auto-display while hidden. For example, this |
| 858 // prevents Cocoa drawing just *after* a minimize, resulting in a blank window |
| 859 // represented in the deminiaturize animation. |
| 860 [window_ setAutodisplay:window_visible_]; |
| 861 |
| 862 // |bridged_view_| is null when an asynchronous close is pending. Don't |
| 863 // propagate the change further. Note it's not possible to block window |
| 864 // visibility changes coming from native messages, so the bookkeeping above |
| 865 // should still be done. |
| 866 if (!bridged_view_) |
| 867 return; |
| 868 |
812 // TODO(tapted): Investigate whether we want this for Mac. This is what Aura | 869 // TODO(tapted): Investigate whether we want this for Mac. This is what Aura |
813 // does, and it is what tests expect. However, because layer drawing is | 870 // does, and it is what tests expect. However, because layer drawing is |
814 // asynchronous (and things like deminiaturize in AppKit are not), it can | 871 // asynchronous (and things like deminiaturize in AppKit are not), it can |
815 // result in a CALayer appearing on screen before it has been redrawn in the | 872 // result in a CALayer appearing on screen before it has been redrawn in the |
816 // GPU process. This is a general problem. In content, a helper class, | 873 // GPU process. This is a general problem. In content, a helper class, |
817 // RenderWidgetResizeHelper, blocks the UI thread in -[NSView setFrameSize:] | 874 // RenderWidgetResizeHelper, blocks the UI thread in -[NSView setFrameSize:] |
818 // and RenderWidgetHostView::Show() until a frame is ready. | 875 // and RenderWidgetHostView::Show() until a frame is ready. |
819 if (layer()) { | 876 if (layer()) { |
820 layer()->SetVisible(window_visible_); | 877 layer()->SetVisible(window_visible_); |
821 layer()->SchedulePaint(gfx::Rect(GetClientAreaSize())); | 878 layer()->SchedulePaint(gfx::Rect(GetClientAreaSize())); |
822 } | 879 } |
823 | 880 |
824 NotifyVisibilityChangeDown(); | |
825 | |
826 native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged( | 881 native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged( |
827 window_visible_); | 882 window_visible_); |
828 | |
829 // Toolkit-views suppresses redraws while not visible. To prevent Cocoa asking | |
830 // for an "empty" draw, disable auto-display while hidden. For example, this | |
831 // prevents Cocoa drawing just *after* a minimize, resulting in a blank window | |
832 // represented in the deminiaturize animation. | |
833 [window_ setAutodisplay:window_visible_]; | |
834 } | 883 } |
835 | 884 |
836 void BridgedNativeWidget::OnBackingPropertiesChanged() { | 885 void BridgedNativeWidget::OnBackingPropertiesChanged() { |
837 if (layer()) | 886 if (layer()) |
838 UpdateLayerProperties(); | 887 UpdateLayerProperties(); |
839 } | 888 } |
840 | 889 |
841 void BridgedNativeWidget::OnWindowKeyStatusChangedTo(bool is_key) { | 890 void BridgedNativeWidget::OnWindowKeyStatusChangedTo(bool is_key) { |
842 Widget* widget = native_widget_mac()->GetWidget(); | 891 Widget* widget = native_widget_mac()->GetWidget(); |
843 widget->OnNativeWidgetActivationChanged(is_key); | 892 widget->OnNativeWidgetActivationChanged(is_key); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
955 // Transparent window support. | 1004 // Transparent window support. |
956 layer()->GetCompositor()->SetHostHasTransparentBackground(translucent); | 1005 layer()->GetCompositor()->SetHostHasTransparentBackground(translucent); |
957 layer()->SetFillsBoundsOpaquely(!translucent); | 1006 layer()->SetFillsBoundsOpaquely(!translucent); |
958 | 1007 |
959 // Use the regular window background for window modal sheets. The layer() will | 1008 // Use the regular window background for window modal sheets. The layer() will |
960 // still paint over most of it, but the native -[NSApp beginSheet:] animation | 1009 // still paint over most of it, but the native -[NSApp beginSheet:] animation |
961 // blocks the UI thread, so there's no way to invalidate the shadow to match | 1010 // blocks the UI thread, so there's no way to invalidate the shadow to match |
962 // the composited layer. This assumes the native window shape is a good match | 1011 // the composited layer. This assumes the native window shape is a good match |
963 // for the composited NonClientFrameView, which should be the case since the | 1012 // for the composited NonClientFrameView, which should be the case since the |
964 // native shape is what's most appropriate for displaying sheets on Mac. | 1013 // native shape is what's most appropriate for displaying sheets on Mac. |
965 if (translucent && !native_widget_mac_->IsWindowModalSheet()) { | 1014 if (translucent && !IsWindowModalSheet()) { |
966 [window_ setOpaque:NO]; | 1015 [window_ setOpaque:NO]; |
967 // For Mac OS versions earlier than Yosemite, the Window server isn't able | 1016 // For Mac OS versions earlier than Yosemite, the Window server isn't able |
968 // to generate a window shadow from the composited CALayer. To get around | 1017 // to generate a window shadow from the composited CALayer. To get around |
969 // this, let the window background remain opaque and clip the window | 1018 // this, let the window background remain opaque and clip the window |
970 // boundary in drawRect method of BridgedContentView. See crbug.com/543671. | 1019 // boundary in drawRect method of BridgedContentView. See crbug.com/543671. |
971 if (base::mac::IsOSYosemiteOrLater()) | 1020 if (base::mac::IsOSYosemiteOrLater()) |
972 [window_ setBackgroundColor:[NSColor clearColor]]; | 1021 [window_ setBackgroundColor:[NSColor clearColor]]; |
973 } | 1022 } |
974 | 1023 |
975 UpdateLayerProperties(); | 1024 UpdateLayerProperties(); |
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1313 if (!resize_helper->WaitForSingleTaskToRun(timeout_time - now)) | 1362 if (!resize_helper->WaitForSingleTaskToRun(timeout_time - now)) |
1314 return; // Timeout. | 1363 return; // Timeout. |
1315 | 1364 |
1316 // Since the UI thread is blocked, the size shouldn't change. | 1365 // Since the UI thread is blocked, the size shouldn't change. |
1317 DCHECK(size_in_dip == GetClientAreaSize()); | 1366 DCHECK(size_in_dip == GetClientAreaSize()); |
1318 if (compositor_widget_->HasFrameOfSize(size_in_dip)) | 1367 if (compositor_widget_->HasFrameOfSize(size_in_dip)) |
1319 return; // Frame arrived. | 1368 return; // Frame arrived. |
1320 } | 1369 } |
1321 } | 1370 } |
1322 | 1371 |
| 1372 bool BridgedNativeWidget::IsWindowModalSheet() const { |
| 1373 return native_widget_mac_->GetWidget()->widget_delegate()->GetModalType() == |
| 1374 ui::MODAL_TYPE_WINDOW; |
| 1375 } |
| 1376 |
1323 void BridgedNativeWidget::ShowAsModalSheet() { | 1377 void BridgedNativeWidget::ShowAsModalSheet() { |
1324 // -[NSApp beginSheet:] will block the UI thread while the animation runs. | 1378 // -[NSApp beginSheet:] will block the UI thread while the animation runs. |
1325 // So that it doesn't animate a fully transparent window, first wait for a | 1379 // So that it doesn't animate a fully transparent window, first wait for a |
1326 // frame. The first step is to pretend that the window is already visible. | 1380 // frame. The first step is to pretend that the window is already visible. |
1327 window_visible_ = true; | 1381 window_visible_ = true; |
1328 layer()->SetVisible(true); | 1382 layer()->SetVisible(true); |
1329 native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged(true); | 1383 native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged(true); |
1330 MaybeWaitForFrame(GetClientAreaSize()); | 1384 MaybeWaitForFrame(GetClientAreaSize()); |
1331 | 1385 |
1332 NSWindow* parent_window = parent_->GetNSWindow(); | 1386 NSWindow* parent_window = parent_->GetNSWindow(); |
(...skipping 21 matching lines...) Expand all Loading... |
1354 [bridged_view_ setMouseDownCanMoveWindow:draggable]; | 1408 [bridged_view_ setMouseDownCanMoveWindow:draggable]; |
1355 // AppKit will not update its cache of mouseDownCanMoveWindow unless something | 1409 // AppKit will not update its cache of mouseDownCanMoveWindow unless something |
1356 // changes. Previously we tried adding an NSView and removing it, but for some | 1410 // changes. Previously we tried adding an NSView and removing it, but for some |
1357 // reason it required reposting the mouse-down event, and didn't always work. | 1411 // reason it required reposting the mouse-down event, and didn't always work. |
1358 // Calling the below seems to be an effective solution. | 1412 // Calling the below seems to be an effective solution. |
1359 [window_ setMovableByWindowBackground:NO]; | 1413 [window_ setMovableByWindowBackground:NO]; |
1360 [window_ setMovableByWindowBackground:YES]; | 1414 [window_ setMovableByWindowBackground:YES]; |
1361 } | 1415 } |
1362 | 1416 |
1363 } // namespace views | 1417 } // namespace views |
OLD | NEW |