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 #import "base/mac/foundation_util.h" | 10 #import "base/mac/foundation_util.h" |
11 #include "base/mac/mac_util.h" | 11 #include "base/mac/mac_util.h" |
12 #import "base/mac/sdk_forward_declarations.h" | 12 #import "base/mac/sdk_forward_declarations.h" |
13 #include "base/thread_task_runner_handle.h" | 13 #include "base/thread_task_runner_handle.h" |
| 14 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h" |
14 #import "ui/base/cocoa/constrained_window/constrained_window_animation.h" | 15 #import "ui/base/cocoa/constrained_window/constrained_window_animation.h" |
15 #include "ui/base/hit_test.h" | 16 #include "ui/base/hit_test.h" |
16 #include "ui/base/ime/input_method.h" | 17 #include "ui/base/ime/input_method.h" |
17 #include "ui/base/ime/input_method_factory.h" | 18 #include "ui/base/ime/input_method_factory.h" |
18 #include "ui/gfx/display.h" | 19 #include "ui/gfx/display.h" |
19 #include "ui/gfx/geometry/dip_util.h" | 20 #include "ui/gfx/geometry/dip_util.h" |
20 #import "ui/gfx/mac/coordinate_conversion.h" | 21 #import "ui/gfx/mac/coordinate_conversion.h" |
21 #import "ui/gfx/mac/nswindow_frame_controls.h" | 22 #import "ui/gfx/mac/nswindow_frame_controls.h" |
22 #include "ui/gfx/screen.h" | 23 #include "ui/gfx/screen.h" |
23 #import "ui/views/cocoa/bridged_content_view.h" | 24 #import "ui/views/cocoa/bridged_content_view.h" |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 if (monitor) | 207 if (monitor) |
207 return; | 208 return; |
208 | 209 |
209 monitor = [NSEvent | 210 monitor = [NSEvent |
210 addLocalMonitorForEventsMatchingMask:NSLeftMouseDownMask | 211 addLocalMonitorForEventsMatchingMask:NSLeftMouseDownMask |
211 handler:^NSEvent*(NSEvent* ns_event) { | 212 handler:^NSEvent*(NSEvent* ns_event) { |
212 return RepostEventIfHandledByWindow(ns_event); | 213 return RepostEventIfHandledByWindow(ns_event); |
213 }]; | 214 }]; |
214 } | 215 } |
215 | 216 |
| 217 // Returns a task runner for creating a ui::Compositor. This allows compositor |
| 218 // tasks to be funneled through ui::WindowResizeHelper's task runner to allow |
| 219 // resize operations to coordinate with frames provided by the GPU process. |
| 220 scoped_refptr<base::SingleThreadTaskRunner> GetCompositorTaskRunner() { |
| 221 // If the WindowResizeHelper's pumpable task runner is set, it means the GPU |
| 222 // process is directing messages there, and the compositor can synchronize |
| 223 // with it. Otherwise, just use the UI thread. |
| 224 scoped_refptr<base::SingleThreadTaskRunner> task_runner = |
| 225 ui::WindowResizeHelperMac::Get()->task_runner(); |
| 226 return task_runner ? task_runner : base::ThreadTaskRunnerHandle::Get(); |
| 227 } |
| 228 |
216 } // namespace | 229 } // namespace |
217 | 230 |
218 namespace views { | 231 namespace views { |
219 | 232 |
220 // static | 233 // static |
221 gfx::Size BridgedNativeWidget::GetWindowSizeForClientSize( | 234 gfx::Size BridgedNativeWidget::GetWindowSizeForClientSize( |
222 NSWindow* window, | 235 NSWindow* window, |
223 const gfx::Size& content_size) { | 236 const gfx::Size& content_size) { |
224 NSRect content_rect = | 237 NSRect content_rect = |
225 NSMakeRect(0, 0, content_size.width(), content_size.height()); | 238 NSMakeRect(0, 0, content_size.width(), content_size.height()); |
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
612 // 2: the fullscreen button must be enabled so the user can leave fullscreen. | 625 // 2: the fullscreen button must be enabled so the user can leave fullscreen. |
613 // This will be reset when a transition out of fullscreen completes. | 626 // This will be reset when a transition out of fullscreen completes. |
614 gfx::SetNSWindowCanFullscreen(window_, true); | 627 gfx::SetNSWindowCanFullscreen(window_, true); |
615 | 628 |
616 [window_ toggleFullScreen:nil]; | 629 [window_ toggleFullScreen:nil]; |
617 } | 630 } |
618 | 631 |
619 void BridgedNativeWidget::OnSizeChanged() { | 632 void BridgedNativeWidget::OnSizeChanged() { |
620 gfx::Size new_size = GetClientAreaSize(); | 633 gfx::Size new_size = GetClientAreaSize(); |
621 native_widget_mac_->GetWidget()->OnNativeWidgetSizeChanged(new_size); | 634 native_widget_mac_->GetWidget()->OnNativeWidgetSizeChanged(new_size); |
622 if (layer()) | 635 if (layer()) { |
623 UpdateLayerProperties(); | 636 UpdateLayerProperties(); |
| 637 if ([window_ inLiveResize]) |
| 638 MaybeWaitForFrame(new_size); |
| 639 } |
624 } | 640 } |
625 | 641 |
626 void BridgedNativeWidget::OnVisibilityChanged() { | 642 void BridgedNativeWidget::OnVisibilityChanged() { |
627 OnVisibilityChangedTo([window_ isVisible]); | 643 OnVisibilityChangedTo([window_ isVisible]); |
628 } | 644 } |
629 | 645 |
630 void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) { | 646 void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) { |
631 if (window_visible_ == new_visibility) | 647 if (window_visible_ == new_visibility) |
632 return; | 648 return; |
633 | 649 |
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1005 DCHECK(context_factory); | 1021 DCHECK(context_factory); |
1006 | 1022 |
1007 AddCompositorSuperview(); | 1023 AddCompositorSuperview(); |
1008 | 1024 |
1009 // TODO(tapted): Get this value from GpuDataManagerImpl via ViewsDelegate. | 1025 // TODO(tapted): Get this value from GpuDataManagerImpl via ViewsDelegate. |
1010 bool needs_gl_finish_workaround = false; | 1026 bool needs_gl_finish_workaround = false; |
1011 | 1027 |
1012 compositor_widget_.reset( | 1028 compositor_widget_.reset( |
1013 new ui::AcceleratedWidgetMac(needs_gl_finish_workaround)); | 1029 new ui::AcceleratedWidgetMac(needs_gl_finish_workaround)); |
1014 compositor_.reset( | 1030 compositor_.reset( |
1015 new ui::Compositor(context_factory, base::ThreadTaskRunnerHandle::Get())); | 1031 new ui::Compositor(context_factory, GetCompositorTaskRunner())); |
1016 compositor_->SetAcceleratedWidgetAndStartCompositor( | 1032 compositor_->SetAcceleratedWidgetAndStartCompositor( |
1017 compositor_widget_->accelerated_widget()); | 1033 compositor_widget_->accelerated_widget()); |
1018 compositor_widget_->SetNSView(this); | 1034 compositor_widget_->SetNSView(this); |
1019 } | 1035 } |
1020 | 1036 |
1021 void BridgedNativeWidget::InitCompositor() { | 1037 void BridgedNativeWidget::InitCompositor() { |
1022 DCHECK(layer()); | 1038 DCHECK(layer()); |
1023 float scale_factor = GetDeviceScaleFactorFromView(compositor_superview_); | 1039 float scale_factor = GetDeviceScaleFactorFromView(compositor_superview_); |
1024 gfx::Size size_in_dip = GetClientAreaSize(); | 1040 gfx::Size size_in_dip = GetClientAreaSize(); |
1025 compositor_->SetScaleAndSize(scale_factor, | 1041 compositor_->SetScaleAndSize(scale_factor, |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1102 float scale_factor = GetDeviceScaleFactorFromView(compositor_superview_); | 1118 float scale_factor = GetDeviceScaleFactorFromView(compositor_superview_); |
1103 compositor_->SetScaleAndSize(scale_factor, | 1119 compositor_->SetScaleAndSize(scale_factor, |
1104 ConvertSizeToPixel(scale_factor, size_in_dip)); | 1120 ConvertSizeToPixel(scale_factor, size_in_dip)); |
1105 | 1121 |
1106 // For a translucent window, the shadow calculation needs to be carried out | 1122 // For a translucent window, the shadow calculation needs to be carried out |
1107 // after the frame from the compositor arrives. | 1123 // after the frame from the compositor arrives. |
1108 if (![window_ isOpaque]) | 1124 if (![window_ isOpaque]) |
1109 invalidate_shadow_on_frame_swap_ = true; | 1125 invalidate_shadow_on_frame_swap_ = true; |
1110 } | 1126 } |
1111 | 1127 |
| 1128 void BridgedNativeWidget::MaybeWaitForFrame(const gfx::Size& size_in_dip) { |
| 1129 if (!layer()->IsDrawn() || compositor_widget_->HasFrameOfSize(size_in_dip)) |
| 1130 return; |
| 1131 |
| 1132 const int kPaintMsgTimeoutMS = 50; |
| 1133 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 1134 const base::TimeTicks timeout_time = |
| 1135 start_time + base::TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS); |
| 1136 |
| 1137 ui::WindowResizeHelperMac* resize_helper = ui::WindowResizeHelperMac::Get(); |
| 1138 for (base::TimeTicks now = start_time; now < timeout_time; |
| 1139 now = base::TimeTicks::Now()) { |
| 1140 if (!resize_helper->WaitForSingleTaskToRun(timeout_time - now)) |
| 1141 return; // Timeout. |
| 1142 |
| 1143 // Since the UI thread is blocked, the size shouldn't change. |
| 1144 DCHECK(size_in_dip == GetClientAreaSize()); |
| 1145 if (compositor_widget_->HasFrameOfSize(size_in_dip)) |
| 1146 return; // Frame arrived. |
| 1147 } |
| 1148 } |
| 1149 |
1112 NSMutableDictionary* BridgedNativeWidget::GetWindowProperties() const { | 1150 NSMutableDictionary* BridgedNativeWidget::GetWindowProperties() const { |
1113 NSMutableDictionary* properties = objc_getAssociatedObject( | 1151 NSMutableDictionary* properties = objc_getAssociatedObject( |
1114 window_, &kWindowPropertiesKey); | 1152 window_, &kWindowPropertiesKey); |
1115 if (!properties) { | 1153 if (!properties) { |
1116 properties = [NSMutableDictionary dictionary]; | 1154 properties = [NSMutableDictionary dictionary]; |
1117 objc_setAssociatedObject(window_, &kWindowPropertiesKey, | 1155 objc_setAssociatedObject(window_, &kWindowPropertiesKey, |
1118 properties, OBJC_ASSOCIATION_RETAIN); | 1156 properties, OBJC_ASSOCIATION_RETAIN); |
1119 } | 1157 } |
1120 return properties; | 1158 return properties; |
1121 } | 1159 } |
1122 | 1160 |
1123 void BridgedNativeWidget::SetDraggable(bool draggable) { | 1161 void BridgedNativeWidget::SetDraggable(bool draggable) { |
1124 [bridged_view_ setMouseDownCanMoveWindow:draggable]; | 1162 [bridged_view_ setMouseDownCanMoveWindow:draggable]; |
1125 // AppKit will not update its cache of mouseDownCanMoveWindow unless something | 1163 // AppKit will not update its cache of mouseDownCanMoveWindow unless something |
1126 // changes. Previously we tried adding an NSView and removing it, but for some | 1164 // changes. Previously we tried adding an NSView and removing it, but for some |
1127 // reason it required reposting the mouse-down event, and didn't always work. | 1165 // reason it required reposting the mouse-down event, and didn't always work. |
1128 // Calling the below seems to be an effective solution. | 1166 // Calling the below seems to be an effective solution. |
1129 [window_ setMovableByWindowBackground:NO]; | 1167 [window_ setMovableByWindowBackground:NO]; |
1130 [window_ setMovableByWindowBackground:YES]; | 1168 [window_ setMovableByWindowBackground:YES]; |
1131 } | 1169 } |
1132 | 1170 |
1133 } // namespace views | 1171 } // namespace views |
OLD | NEW |