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 |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #import "base/mac/foundation_util.h" | 12 #import "base/mac/foundation_util.h" |
| 13 #include "base/mac/mac_util.h" | 13 #include "base/mac/mac_util.h" |
| 14 #import "base/mac/sdk_forward_declarations.h" | 14 #import "base/mac/sdk_forward_declarations.h" |
| 15 #include "base/run_loop.h" | |
| 15 #include "base/thread_task_runner_handle.h" | 16 #include "base/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/gfx/display.h" | 22 #include "ui/gfx/display.h" |
| 22 #include "ui/gfx/geometry/dip_util.h" | 23 #include "ui/gfx/geometry/dip_util.h" |
| 23 #import "ui/gfx/mac/coordinate_conversion.h" | 24 #import "ui/gfx/mac/coordinate_conversion.h" |
| 24 #import "ui/gfx/mac/nswindow_frame_controls.h" | 25 #import "ui/gfx/mac/nswindow_frame_controls.h" |
| 25 #include "ui/gfx/screen.h" | 26 #include "ui/gfx/screen.h" |
| 26 #import "ui/views/cocoa/bridged_content_view.h" | 27 #import "ui/views/cocoa/bridged_content_view.h" |
| 27 #import "ui/views/cocoa/cocoa_mouse_capture.h" | 28 #import "ui/views/cocoa/cocoa_mouse_capture.h" |
| 28 #include "ui/views/cocoa/tooltip_manager_mac.h" | 29 #include "ui/views/cocoa/tooltip_manager_mac.h" |
| 29 #import "ui/views/cocoa/views_nswindow_delegate.h" | 30 #import "ui/views/cocoa/views_nswindow_delegate.h" |
| 30 #import "ui/views/cocoa/widget_owner_nswindow_adapter.h" | 31 #import "ui/views/cocoa/widget_owner_nswindow_adapter.h" |
| 31 #include "ui/views/view.h" | 32 #include "ui/views/view.h" |
| 32 #include "ui/views/views_delegate.h" | 33 #include "ui/views/views_delegate.h" |
| 33 #include "ui/views/widget/native_widget_mac.h" | 34 #include "ui/views/widget/native_widget_mac.h" |
| 34 #include "ui/views/widget/widget.h" | 35 #include "ui/views/widget/widget.h" |
| 35 #include "ui/views/widget/widget_aura_utils.h" | 36 #include "ui/views/widget/widget_aura_utils.h" |
| 36 #include "ui/views/widget/widget_delegate.h" | 37 #include "ui/views/widget/widget_delegate.h" |
| 37 | 38 |
| 38 extern "C" { | |
| 39 | |
| 40 typedef int32_t CGSConnection; | |
| 41 CGSConnection _CGSDefaultConnection(); | |
| 42 CGError CGSSetWindowBackgroundBlurRadius(CGSConnection connection, | |
| 43 NSInteger windowNumber, | |
| 44 int radius); | |
| 45 | |
| 46 } | |
| 47 | |
| 48 // The NSView that hosts the composited CALayer drawing the UI. It fills the | 39 // The NSView that hosts the composited CALayer drawing the UI. It fills the |
| 49 // window but is not hittable so that accessibility hit tests always go to the | 40 // window but is not hittable so that accessibility hit tests always go to the |
| 50 // BridgedContentView. | 41 // BridgedContentView. |
| 51 @interface ViewsCompositorSuperview : NSView | 42 @interface ViewsCompositorSuperview : NSView |
| 52 @end | 43 @end |
| 53 | 44 |
| 54 @implementation ViewsCompositorSuperview | 45 @implementation ViewsCompositorSuperview |
| 55 - (NSView*)hitTest:(NSPoint)aPoint { | 46 - (NSView*)hitTest:(NSPoint)aPoint { |
| 56 return nil; | 47 return nil; |
| 57 } | 48 } |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 87 const CGFloat kYosemiteMenuOpacity = 194.0 / 255.0; | 78 const CGFloat kYosemiteMenuOpacity = 194.0 / 255.0; |
| 88 const int kYosemiteMenuBlur = 80; | 79 const int kYosemiteMenuBlur = 80; |
| 89 | 80 |
| 90 // Margin at edge and corners of the window that trigger resizing. These match | 81 // Margin at edge and corners of the window that trigger resizing. These match |
| 91 // actual Cocoa resize margins. | 82 // actual Cocoa resize margins. |
| 92 const int kResizeAreaEdgeSize = 3; | 83 const int kResizeAreaEdgeSize = 3; |
| 93 const int kResizeAreaCornerSize = 12; | 84 const int kResizeAreaCornerSize = 12; |
| 94 | 85 |
| 95 int kWindowPropertiesKey; | 86 int kWindowPropertiesKey; |
| 96 | 87 |
| 88 bool g_ignore_next_mouse_down_for_draggable_regions = false; | |
| 89 | |
| 97 float GetDeviceScaleFactorFromView(NSView* view) { | 90 float GetDeviceScaleFactorFromView(NSView* view) { |
| 98 gfx::Display display = | 91 gfx::Display display = |
| 99 gfx::Screen::GetScreen()->GetDisplayNearestWindow(view); | 92 gfx::Screen::GetScreen()->GetDisplayNearestWindow(view); |
| 100 DCHECK(display.is_valid()); | 93 DCHECK(display.is_valid()); |
| 101 return display.device_scale_factor(); | 94 return display.device_scale_factor(); |
| 102 } | 95 } |
| 103 | 96 |
| 104 // Returns true if bounds passed to window in SetBounds should be treated as | 97 // Returns true if bounds passed to window in SetBounds should be treated as |
| 105 // though they are in screen coordinates. | 98 // though they are in screen coordinates. |
| 106 bool PositionWindowInScreenCoordinates(views::Widget* widget, | 99 bool PositionWindowInScreenCoordinates(views::Widget* widget, |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 184 NSInteger event_number = [ns_event eventNumber]; | 177 NSInteger event_number = [ns_event eventNumber]; |
| 185 | 178 |
| 186 // The logic here is a bit convoluted because we want to mitigate race | 179 // The logic here is a bit convoluted because we want to mitigate race |
| 187 // conditions if somehow a different mouse-down occurs between reposts. | 180 // conditions if somehow a different mouse-down occurs between reposts. |
| 188 // Specifically, we want to avoid: | 181 // Specifically, we want to avoid: |
| 189 // - BridgedNativeWidget's draggability getting out of sync (e.g. if it is | 182 // - BridgedNativeWidget's draggability getting out of sync (e.g. if it is |
| 190 // draggable outside of a repost cycle), | 183 // draggable outside of a repost cycle), |
| 191 // - any repost loop. | 184 // - any repost loop. |
| 192 | 185 |
| 193 if (repost_state == NONE) { | 186 if (repost_state == NONE) { |
| 187 if (g_ignore_next_mouse_down_for_draggable_regions) { | |
| 188 g_ignore_next_mouse_down_for_draggable_regions = false; | |
| 189 return ns_event; | |
| 190 } | |
| 191 | |
| 194 if (WindowWantsMouseDownReposted(ns_event)) { | 192 if (WindowWantsMouseDownReposted(ns_event)) { |
| 195 repost_state = EXPECTING_REPOST; | 193 repost_state = EXPECTING_REPOST; |
| 196 reposted_event_number = event_number; | 194 reposted_event_number = event_number; |
| 197 CGEventPost(kCGSessionEventTap, [ns_event CGEvent]); | 195 CGEventPost(kCGSessionEventTap, [ns_event CGEvent]); |
| 198 return nil; | 196 return nil; |
| 199 } | 197 } |
| 200 | 198 |
| 201 return ns_event; | 199 return ns_event; |
| 202 } | 200 } |
| 203 | 201 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 256 // resize operations to coordinate with frames provided by the GPU process. | 254 // resize operations to coordinate with frames provided by the GPU process. |
| 257 scoped_refptr<base::SingleThreadTaskRunner> GetCompositorTaskRunner() { | 255 scoped_refptr<base::SingleThreadTaskRunner> GetCompositorTaskRunner() { |
| 258 // If the WindowResizeHelper's pumpable task runner is set, it means the GPU | 256 // If the WindowResizeHelper's pumpable task runner is set, it means the GPU |
| 259 // process is directing messages there, and the compositor can synchronize | 257 // process is directing messages there, and the compositor can synchronize |
| 260 // with it. Otherwise, just use the UI thread. | 258 // with it. Otherwise, just use the UI thread. |
| 261 scoped_refptr<base::SingleThreadTaskRunner> task_runner = | 259 scoped_refptr<base::SingleThreadTaskRunner> task_runner = |
| 262 ui::WindowResizeHelperMac::Get()->task_runner(); | 260 ui::WindowResizeHelperMac::Get()->task_runner(); |
| 263 return task_runner ? task_runner : base::ThreadTaskRunnerHandle::Get(); | 261 return task_runner ? task_runner : base::ThreadTaskRunnerHandle::Get(); |
| 264 } | 262 } |
| 265 | 263 |
| 264 CGPoint GetCGMousePosition() { | |
| 265 return CGEventGetLocation( | |
| 266 base::ScopedCFTypeRef<CGEventRef>(CGEventCreate(nullptr))); | |
| 267 } | |
| 268 | |
| 269 void SendCustomLeftMouseEvent(CGEventType type) { | |
| 270 base::ScopedCFTypeRef<CGEventRef> event( | |
| 271 CGEventCreateMouseEvent( | |
| 272 nullptr, type, GetCGMousePosition(), | |
| 273 kCGMouseButtonLeft)); | |
| 274 CGEventSetIntegerValueField(event, kCGEventSourceUserData, 1); | |
| 275 CGEventPost(kCGSessionEventTap, event); | |
| 276 } | |
| 277 | |
| 266 } // namespace | 278 } // namespace |
| 267 | 279 |
| 280 extern "C" { | |
| 281 | |
| 282 typedef int32_t CGSConnection; | |
| 283 CGSConnection _CGSDefaultConnection(); | |
| 284 CGError CGSSetWindowBackgroundBlurRadius(CGSConnection connection, | |
| 285 NSInteger windowNumber, | |
| 286 int radius); | |
| 287 | |
| 288 } | |
| 289 | |
| 290 // CocoaWindowMoveLoop can be deleted just before its local event monitor is | |
| 291 // processed and in that case it's too late to call removeMonitor: and we have a | |
| 292 // dangling this pointer. Use a proxy Obj-C class to store the weakptr. | |
| 293 @interface WeakCocoaWindowMoveLoop : NSObject { | |
| 294 @private | |
| 295 base::WeakPtr<views::CocoaWindowMoveLoop> weak_; | |
| 296 } | |
| 297 @end | |
| 298 | |
| 299 @implementation WeakCocoaWindowMoveLoop | |
| 300 - (id)initWithWeakPtr:(const base::WeakPtr<views::CocoaWindowMoveLoop>&)weak { | |
| 301 if (self = [super init]) { | |
| 302 weak_ = weak; | |
| 303 } | |
| 304 return self; | |
| 305 } | |
| 306 | |
| 307 - (base::WeakPtr<views::CocoaWindowMoveLoop>&)weak { | |
| 308 return weak_; | |
| 309 } | |
| 310 @end | |
| 311 | |
| 268 namespace views { | 312 namespace views { |
| 269 | 313 |
| 314 class CocoaWindowMoveLoop { | |
|
tapted
2016/03/10 11:51:19
Move this to its own file (with WeakCocoaMoveLoop?
themblsha
2016/03/10 17:18:58
Oh, right, you told me about that and it seems tha
| |
| 315 public: | |
| 316 explicit CocoaWindowMoveLoop(BridgedNativeWidget* owner) | |
| 317 : owner_(owner), | |
| 318 run_loop_(new base::RunLoop), | |
| 319 quit_closure_(run_loop_->QuitClosure()), | |
| 320 weak_factory_(this) { | |
| 321 // AppKit continues to send mouse events to the window, but toolkit-views | |
| 322 // goes berserk if it gets them during RunMoveLoop(). | |
|
tapted
2016/03/10 11:51:19
hehe - I remember writing `berserk`... Perhaps "bu
themblsha
2016/03/10 17:18:58
Done.
| |
| 323 [owner_->ns_view() setIgnoreMouseEvents:YES]; | |
| 324 owner_->SetDraggable(true); | |
| 325 } | |
| 326 | |
| 327 ~CocoaWindowMoveLoop() { | |
| 328 owner_->SetDraggable(false); | |
| 329 // Note the crafted events in Run() should not make their way through to | |
| 330 // toolkit-views, but regular events after that should be. So stop ignoring. | |
| 331 [owner_->ns_view() setIgnoreMouseEvents:NO]; | |
| 332 | |
| 333 // Handle the pathological case, where |this| is destroyed while running. | |
| 334 if (exit_reason_ref_) { | |
| 335 *exit_reason_ref_ = WINDOW_DESTROYED; | |
| 336 quit_closure_.Run(); | |
| 337 } | |
| 338 | |
| 339 // Handle Run() never being called. | |
| 340 if (monitor_) { | |
| 341 [NSEvent removeMonitor:monitor_]; | |
| 342 monitor_ = nil; | |
| 343 } | |
| 344 owner_ = nullptr; | |
| 345 } | |
| 346 | |
| 347 Widget::MoveLoopResult Run() { | |
| 348 LoopExitReason exit_reason = ENDED_EXTERNALLY; | |
| 349 exit_reason_ref_ = &exit_reason; | |
| 350 | |
| 351 // Move the RunLoop to the stack so our destructor can be called while it is | |
| 352 // running. | |
| 353 scoped_ptr<base::RunLoop> run_loop(std::move(run_loop_)); | |
| 354 | |
| 355 // A new window may have just been created, so post an event at the session | |
| 356 // tap level to initiate a window drag. | |
| 357 // TODO(tapted): Move this "inside" the window or stuff breaks when dragging | |
| 358 // the last tab/s off a browser. | |
| 359 SendCustomLeftMouseEvent(kCGEventLeftMouseDown); | |
| 360 | |
| 361 WeakCocoaWindowMoveLoop* proxy_quit_closure = | |
| 362 [[[WeakCocoaWindowMoveLoop alloc] | |
| 363 initWithWeakPtr:weak_factory_.GetWeakPtr()] autorelease]; | |
| 364 | |
| 365 NSEventMask mask = | |
| 366 NSLeftMouseUpMask | NSKeyDownMask | NSLeftMouseDraggedMask; | |
| 367 monitor_ = [NSEvent addLocalMonitorForEventsMatchingMask:mask | |
| 368 handler:^NSEvent*(NSEvent* event) { | |
| 369 if ([event type] == NSLeftMouseDragged) { | |
| 370 // AppKit doesn't supply position updates during a drag, so post a | |
| 371 // task to notify observers once AppKit has moved the window. | |
| 372 base::MessageLoop::current()->PostTask( | |
| 373 FROM_HERE, base::Bind(&BridgedNativeWidget::OnPositionChanged, | |
| 374 base::Unretained(owner_))); | |
| 375 return event; | |
| 376 } | |
| 377 | |
| 378 CocoaWindowMoveLoop* thiss = [proxy_quit_closure weak].get(); | |
| 379 if (!thiss) | |
| 380 return nil; | |
| 381 | |
| 382 thiss->quit_closure_.Run(); | |
| 383 if ([event type] == NSLeftMouseUp) { | |
| 384 *thiss->exit_reason_ref_ = MOUSE_UP; | |
| 385 return event; // Process the MouseUp. | |
| 386 } | |
| 387 *thiss->exit_reason_ref_ = ESCAPE_PRESSED; | |
| 388 return nil; // Swallow the keypress. | |
| 389 }]; | |
| 390 | |
| 391 // NSKeyDownMask doesn't work inside addLocalMonitorForEventsMatchingMask: | |
| 392 // the event is swallowed by the window move loop before it gets to -[NSApp | |
| 393 // sendEvent:]. To see an escape keypress, hook in an event tap lower. | |
| 394 | |
| 395 run_loop->Run(); | |
| 396 | |
| 397 if (exit_reason != WINDOW_DESTROYED && exit_reason != ENDED_EXTERNALLY) { | |
| 398 exit_reason_ref_ = nullptr; // Ensure End() doesn't replace the reason. | |
| 399 owner_->EndMoveLoop(); // Deletes |this|. | |
| 400 } | |
| 401 | |
| 402 if (exit_reason != MOUSE_UP) { | |
| 403 // Tell AppKit to stop moving the window. Otherwise, AppKit will refuse to | |
| 404 // start a new window drag. Note the window being dragged is going away in | |
| 405 // this case, so it doesn't really matter where the event is located. | |
| 406 SendCustomLeftMouseEvent(kCGEventLeftMouseUp); | |
| 407 | |
| 408 if (exit_reason == ENDED_EXTERNALLY) { | |
| 409 // When not canceled, the non-moving drag in the original window must | |
| 410 // resume. To do this, AppKit needs to see a mouseDown so that it sends | |
| 411 // the correct events. Ideally, it also needs to be at the original | |
| 412 // offset, so that it hits a non-draggable region of the original | |
| 413 // window: The tab being dragged may move some distance from the cursor | |
| 414 // when it "snaps in", so the cursor may not be over a tab. Sadly, this | |
| 415 // method doesn't know which window that is. But all that really needs | |
| 416 // to be done is to prevent a custom-dragging area from starting a | |
| 417 // window-drag. So hook into the logic in RepostEventIfHandledByWindow() | |
| 418 // by setting a flag here. Note this assumes the custom mouseDown event | |
| 419 // is guaranteed to hit another BridgedNativeWidget when it gets to the | |
| 420 // front of the event queue. | |
| 421 // TODO(tapted): A better fix would be to keep the temporary window | |
| 422 // around and never call EndMoveLoop() on Mac, making this block of code | |
| 423 // obsolete. | |
| 424 g_ignore_next_mouse_down_for_draggable_regions = true; | |
| 425 SendCustomLeftMouseEvent(kCGEventLeftMouseDown); | |
| 426 } | |
| 427 } | |
| 428 | |
| 429 return exit_reason == ESCAPE_PRESSED | |
| 430 ? Widget::MOVE_LOOP_CANCELED : Widget::MOVE_LOOP_SUCCESSFUL; | |
| 431 } | |
| 432 | |
| 433 void End() { | |
| 434 if (exit_reason_ref_) { | |
| 435 DCHECK_EQ(*exit_reason_ref_, ENDED_EXTERNALLY); | |
| 436 // Ensure the destructor doesn't replace the reason. | |
| 437 exit_reason_ref_ = nullptr; | |
| 438 quit_closure_.Run(); | |
| 439 } | |
| 440 } | |
| 441 | |
| 442 static CGEventRef EscapeKeypressMonitor(CGEventTapProxy proxy, | |
| 443 CGEventType type, | |
| 444 CGEventRef event, | |
| 445 void* refcon) { | |
| 446 CocoaWindowMoveLoop* self = static_cast<CocoaWindowMoveLoop*>(refcon); | |
| 447 (void)self; | |
| 448 return event; | |
| 449 } | |
| 450 | |
| 451 private: | |
| 452 enum LoopExitReason { | |
| 453 ENDED_EXTERNALLY, | |
| 454 ESCAPE_PRESSED, | |
| 455 MOUSE_UP, | |
| 456 WINDOW_DESTROYED, | |
| 457 }; | |
| 458 | |
| 459 BridgedNativeWidget* owner_; // Weak. Owns this. | |
| 460 scoped_ptr<base::RunLoop> run_loop_; | |
| 461 id monitor_ = nil; | |
| 462 | |
| 463 // Pointer to a stack variable holding the exit reason. | |
| 464 LoopExitReason* exit_reason_ref_ = nullptr; | |
| 465 base::Closure quit_closure_; | |
| 466 | |
| 467 // WeakPtrFactory for event monitor safety. | |
| 468 base::WeakPtrFactory<CocoaWindowMoveLoop> weak_factory_; | |
| 469 | |
| 470 DISALLOW_COPY_AND_ASSIGN(CocoaWindowMoveLoop); | |
| 471 }; | |
| 472 | |
| 270 // static | 473 // static |
| 271 gfx::Size BridgedNativeWidget::GetWindowSizeForClientSize( | 474 gfx::Size BridgedNativeWidget::GetWindowSizeForClientSize( |
| 272 NSWindow* window, | 475 NSWindow* window, |
| 273 const gfx::Size& content_size) { | 476 const gfx::Size& content_size) { |
| 274 NSRect content_rect = | 477 NSRect content_rect = |
| 275 NSMakeRect(0, 0, content_size.width(), content_size.height()); | 478 NSMakeRect(0, 0, content_size.width(), content_size.height()); |
| 276 NSRect frame_rect = [window frameRectForContentRect:content_rect]; | 479 NSRect frame_rect = [window frameRectForContentRect:content_rect]; |
| 277 return gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect)); | 480 return gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect)); |
| 278 } | 481 } |
| 279 | 482 |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 562 } | 765 } |
| 563 | 766 |
| 564 void BridgedNativeWidget::ReleaseCapture() { | 767 void BridgedNativeWidget::ReleaseCapture() { |
| 565 mouse_capture_.reset(); | 768 mouse_capture_.reset(); |
| 566 } | 769 } |
| 567 | 770 |
| 568 bool BridgedNativeWidget::HasCapture() { | 771 bool BridgedNativeWidget::HasCapture() { |
| 569 return mouse_capture_ && mouse_capture_->IsActive(); | 772 return mouse_capture_ && mouse_capture_->IsActive(); |
| 570 } | 773 } |
| 571 | 774 |
| 775 Widget::MoveLoopResult BridgedNativeWidget::RunMoveLoop( | |
| 776 const gfx::Vector2d& drag_offset) { | |
| 777 DCHECK(!HasCapture()); | |
| 778 DCHECK(!window_move_loop_); | |
| 779 | |
| 780 // First, position the window in the right place. The point |drag_offset| | |
| 781 // away from the top-left corner needs to be positioned under the mouse. | |
| 782 // TODO(tapted): Figure out why the toolkit-views drag controller doesn't get | |
| 783 // this right when it first initializes the Widget. | |
| 784 NSPoint mouse_in_screen = gfx::ScreenPointToNSPoint( | |
| 785 gfx::Screen::GetScreen()->GetCursorScreenPoint()); | |
| 786 NSRect frame = [window_ frame]; | |
| 787 frame.origin.x = mouse_in_screen.x - drag_offset.x(); | |
| 788 frame.origin.y = mouse_in_screen.y - NSHeight(frame) + drag_offset.y(); | |
| 789 | |
| 790 // After setting the frame to correct the initial offset, the drag controller | |
| 791 // may immediately want to quit when it's notified of the new bounds. So the | |
| 792 // MoveLoop must be set up before the call to setFrame. | |
| 793 window_move_loop_.reset(new CocoaWindowMoveLoop(this)); | |
| 794 | |
| 795 // Animating may provide a less janky UX, but something custom would be | |
| 796 // required so that it follows updates to the mouse position. | |
| 797 [window_ setFrame:frame display:YES animate:NO]; | |
| 798 | |
| 799 // Setting the frame will call OnWidgetBoundsChanged(), which could result in | |
| 800 // a call to EndMoveLoop(). | |
| 801 if (!window_move_loop_) | |
| 802 return Widget::MOVE_LOOP_SUCCESSFUL; | |
| 803 | |
| 804 return window_move_loop_->Run(); | |
| 805 | |
| 806 // |this| may be destroyed during the RunLoop, causing it to exit early. | |
| 807 // Even if that doesn't happen, CocoaWindowMoveLoop will clean itself up by | |
| 808 // calling EndMoveLoop(). So window_move_loop_ will always be null before the | |
| 809 // function returns. But don't DCHECK since |this| might not be valid. | |
| 810 } | |
| 811 | |
| 812 void BridgedNativeWidget::EndMoveLoop() { | |
| 813 DCHECK(window_move_loop_); | |
| 814 window_move_loop_->End(); | |
| 815 window_move_loop_.reset(); | |
| 816 } | |
| 817 | |
| 572 void BridgedNativeWidget::SetNativeWindowProperty(const char* name, | 818 void BridgedNativeWidget::SetNativeWindowProperty(const char* name, |
| 573 void* value) { | 819 void* value) { |
| 574 NSString* key = [NSString stringWithUTF8String:name]; | 820 NSString* key = [NSString stringWithUTF8String:name]; |
| 575 if (value) { | 821 if (value) { |
| 576 [GetWindowProperties() setObject:[NSValue valueWithPointer:value] | 822 [GetWindowProperties() setObject:[NSValue valueWithPointer:value] |
| 577 forKey:key]; | 823 forKey:key]; |
| 578 } else { | 824 } else { |
| 579 [GetWindowProperties() removeObjectForKey:key]; | 825 [GetWindowProperties() removeObjectForKey:key]; |
| 580 } | 826 } |
| 581 } | 827 } |
| 582 | 828 |
| 583 void* BridgedNativeWidget::GetNativeWindowProperty(const char* name) const { | 829 void* BridgedNativeWidget::GetNativeWindowProperty(const char* name) const { |
| 584 NSString* key = [NSString stringWithUTF8String:name]; | 830 NSString* key = [NSString stringWithUTF8String:name]; |
| 585 return [[GetWindowProperties() objectForKey:key] pointerValue]; | 831 return [[GetWindowProperties() objectForKey:key] pointerValue]; |
| 586 } | 832 } |
| 587 | 833 |
| 588 void BridgedNativeWidget::SetCursor(NSCursor* cursor) { | 834 void BridgedNativeWidget::SetCursor(NSCursor* cursor) { |
| 589 [window_delegate_ setCursor:cursor]; | 835 [window_delegate_ setCursor:cursor]; |
| 590 } | 836 } |
| 591 | 837 |
| 592 void BridgedNativeWidget::OnWindowWillClose() { | 838 void BridgedNativeWidget::OnWindowWillClose() { |
| 839 DCHECK(!drag_run_loop_); | |
| 593 if (parent_) { | 840 if (parent_) { |
| 594 parent_->RemoveChildWindow(this); | 841 parent_->RemoveChildWindow(this); |
| 595 parent_ = nullptr; | 842 parent_ = nullptr; |
| 596 } | 843 } |
| 597 [window_ setDelegate:nil]; | 844 [window_ setDelegate:nil]; |
| 598 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; | 845 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; |
| 599 native_widget_mac_->OnWindowWillClose(); | 846 native_widget_mac_->OnWindowWillClose(); |
| 600 } | 847 } |
| 601 | 848 |
| 602 void BridgedNativeWidget::OnFullscreenTransitionStart( | 849 void BridgedNativeWidget::OnFullscreenTransitionStart( |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 685 | 932 |
| 686 // 10.9 is unable to generate a window shadow from the composited CALayer, so | 933 // 10.9 is unable to generate a window shadow from the composited CALayer, so |
| 687 // use Quartz. | 934 // use Quartz. |
| 688 // We don't update the window mask during a live resize, instead it is done | 935 // We don't update the window mask during a live resize, instead it is done |
| 689 // after the resize is completed in viewDidEndLiveResize: in | 936 // after the resize is completed in viewDidEndLiveResize: in |
| 690 // BridgedContentView. | 937 // BridgedContentView. |
| 691 if (base::mac::IsOSMavericksOrEarlier() && ![window_ inLiveResize]) | 938 if (base::mac::IsOSMavericksOrEarlier() && ![window_ inLiveResize]) |
| 692 [bridged_view_ updateWindowMask]; | 939 [bridged_view_ updateWindowMask]; |
| 693 } | 940 } |
| 694 | 941 |
| 942 void BridgedNativeWidget::OnPositionChanged() { | |
| 943 native_widget_mac_->GetWidget()->OnNativeWidgetMove(); | |
| 944 } | |
| 945 | |
| 695 void BridgedNativeWidget::OnVisibilityChanged() { | 946 void BridgedNativeWidget::OnVisibilityChanged() { |
| 696 OnVisibilityChangedTo([window_ isVisible]); | 947 OnVisibilityChangedTo([window_ isVisible]); |
| 697 } | 948 } |
| 698 | 949 |
| 699 void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) { | 950 void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) { |
| 700 if (window_visible_ == new_visibility) | 951 if (window_visible_ == new_visibility) |
| 701 return; | 952 return; |
| 702 | 953 |
| 703 window_visible_ = new_visibility; | 954 window_visible_ = new_visibility; |
| 704 | 955 |
| (...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1238 [bridged_view_ setMouseDownCanMoveWindow:draggable]; | 1489 [bridged_view_ setMouseDownCanMoveWindow:draggable]; |
| 1239 // AppKit will not update its cache of mouseDownCanMoveWindow unless something | 1490 // AppKit will not update its cache of mouseDownCanMoveWindow unless something |
| 1240 // changes. Previously we tried adding an NSView and removing it, but for some | 1491 // changes. Previously we tried adding an NSView and removing it, but for some |
| 1241 // reason it required reposting the mouse-down event, and didn't always work. | 1492 // reason it required reposting the mouse-down event, and didn't always work. |
| 1242 // Calling the below seems to be an effective solution. | 1493 // Calling the below seems to be an effective solution. |
| 1243 [window_ setMovableByWindowBackground:NO]; | 1494 [window_ setMovableByWindowBackground:NO]; |
| 1244 [window_ setMovableByWindowBackground:YES]; | 1495 [window_ setMovableByWindowBackground:YES]; |
| 1245 } | 1496 } |
| 1246 | 1497 |
| 1247 } // namespace views | 1498 } // namespace views |
| OLD | NEW |