Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(561)

Side by Side Diff: ui/views/cocoa/bridged_native_widget.mm

Issue 1747803003: MacViews: Implement Tab Dragging (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/debug/stack_trace.h"
11 #include "base/logging.h" 12 #include "base/logging.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"
16 #include "base/run_loop.h"
15 #include "base/thread_task_runner_handle.h" 17 #include "base/thread_task_runner_handle.h"
16 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h" 18 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
17 #import "ui/base/cocoa/constrained_window/constrained_window_animation.h" 19 #import "ui/base/cocoa/constrained_window/constrained_window_animation.h"
18 #include "ui/base/hit_test.h" 20 #include "ui/base/hit_test.h"
19 #include "ui/base/ime/input_method.h" 21 #include "ui/base/ime/input_method.h"
20 #include "ui/base/ime/input_method_factory.h" 22 #include "ui/base/ime/input_method_factory.h"
21 #include "ui/gfx/display.h" 23 #include "ui/gfx/display.h"
22 #include "ui/gfx/geometry/dip_util.h" 24 #include "ui/gfx/geometry/dip_util.h"
23 #import "ui/gfx/mac/coordinate_conversion.h" 25 #import "ui/gfx/mac/coordinate_conversion.h"
24 #import "ui/gfx/mac/nswindow_frame_controls.h" 26 #import "ui/gfx/mac/nswindow_frame_controls.h"
25 #include "ui/gfx/screen.h" 27 #include "ui/gfx/screen.h"
26 #import "ui/views/cocoa/bridged_content_view.h" 28 #import "ui/views/cocoa/bridged_content_view.h"
27 #import "ui/views/cocoa/cocoa_mouse_capture.h" 29 #import "ui/views/cocoa/cocoa_mouse_capture.h"
28 #include "ui/views/cocoa/tooltip_manager_mac.h" 30 #include "ui/views/cocoa/tooltip_manager_mac.h"
29 #import "ui/views/cocoa/views_nswindow_delegate.h" 31 #import "ui/views/cocoa/views_nswindow_delegate.h"
30 #import "ui/views/cocoa/widget_owner_nswindow_adapter.h" 32 #import "ui/views/cocoa/widget_owner_nswindow_adapter.h"
31 #include "ui/views/view.h" 33 #include "ui/views/view.h"
32 #include "ui/views/views_delegate.h" 34 #include "ui/views/views_delegate.h"
33 #include "ui/views/widget/native_widget_mac.h" 35 #include "ui/views/widget/native_widget_mac.h"
34 #include "ui/views/widget/widget.h" 36 #include "ui/views/widget/widget.h"
35 #include "ui/views/widget/widget_aura_utils.h" 37 #include "ui/views/widget/widget_aura_utils.h"
36 #include "ui/views/widget/widget_delegate.h" 38 #include "ui/views/widget/widget_delegate.h"
37 39
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 40 // 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 41 // window but is not hittable so that accessibility hit tests always go to the
50 // BridgedContentView. 42 // BridgedContentView.
51 @interface ViewsCompositorSuperview : NSView 43 @interface ViewsCompositorSuperview : NSView
52 @end 44 @end
53 45
54 @implementation ViewsCompositorSuperview 46 @implementation ViewsCompositorSuperview
55 - (NSView*)hitTest:(NSPoint)aPoint { 47 - (NSView*)hitTest:(NSPoint)aPoint {
56 return nil; 48 return nil;
57 } 49 }
(...skipping 29 matching lines...) Expand all
87 const CGFloat kYosemiteMenuOpacity = 194.0 / 255.0; 79 const CGFloat kYosemiteMenuOpacity = 194.0 / 255.0;
88 const int kYosemiteMenuBlur = 80; 80 const int kYosemiteMenuBlur = 80;
89 81
90 // Margin at edge and corners of the window that trigger resizing. These match 82 // Margin at edge and corners of the window that trigger resizing. These match
91 // actual Cocoa resize margins. 83 // actual Cocoa resize margins.
92 const int kResizeAreaEdgeSize = 3; 84 const int kResizeAreaEdgeSize = 3;
93 const int kResizeAreaCornerSize = 12; 85 const int kResizeAreaCornerSize = 12;
94 86
95 int kWindowPropertiesKey; 87 int kWindowPropertiesKey;
96 88
89 bool g_ignore_next_mouse_down_for_draggable_regions = false;
90
97 float GetDeviceScaleFactorFromView(NSView* view) { 91 float GetDeviceScaleFactorFromView(NSView* view) {
98 gfx::Display display = 92 gfx::Display display =
99 gfx::Screen::GetScreen()->GetDisplayNearestWindow(view); 93 gfx::Screen::GetScreen()->GetDisplayNearestWindow(view);
100 DCHECK(display.is_valid()); 94 DCHECK(display.is_valid());
101 return display.device_scale_factor(); 95 return display.device_scale_factor();
102 } 96 }
103 97
104 // Returns true if bounds passed to window in SetBounds should be treated as 98 // Returns true if bounds passed to window in SetBounds should be treated as
105 // though they are in screen coordinates. 99 // though they are in screen coordinates.
106 bool PositionWindowInScreenCoordinates(views::Widget* widget, 100 bool PositionWindowInScreenCoordinates(views::Widget* widget,
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 NSInteger event_number = [ns_event eventNumber]; 178 NSInteger event_number = [ns_event eventNumber];
185 179
186 // The logic here is a bit convoluted because we want to mitigate race 180 // The logic here is a bit convoluted because we want to mitigate race
187 // conditions if somehow a different mouse-down occurs between reposts. 181 // conditions if somehow a different mouse-down occurs between reposts.
188 // Specifically, we want to avoid: 182 // Specifically, we want to avoid:
189 // - BridgedNativeWidget's draggability getting out of sync (e.g. if it is 183 // - BridgedNativeWidget's draggability getting out of sync (e.g. if it is
190 // draggable outside of a repost cycle), 184 // draggable outside of a repost cycle),
191 // - any repost loop. 185 // - any repost loop.
192 186
193 if (repost_state == NONE) { 187 if (repost_state == NONE) {
188 if (g_ignore_next_mouse_down_for_draggable_regions) {
189 g_ignore_next_mouse_down_for_draggable_regions = false;
190 return ns_event;
191 }
192
194 if (WindowWantsMouseDownReposted(ns_event)) { 193 if (WindowWantsMouseDownReposted(ns_event)) {
195 repost_state = EXPECTING_REPOST; 194 repost_state = EXPECTING_REPOST;
196 reposted_event_number = event_number; 195 reposted_event_number = event_number;
196 DLOG(INFO) << "Reposting event for window drag";
197 CGEventPost(kCGSessionEventTap, [ns_event CGEvent]); 197 CGEventPost(kCGSessionEventTap, [ns_event CGEvent]);
198 return nil; 198 return nil;
199 } 199 }
200 200
201 return ns_event; 201 return ns_event;
202 } 202 }
203 203
204 if (repost_state == EXPECTING_REPOST) { 204 if (repost_state == EXPECTING_REPOST) {
205 // Call through so that the window is made non-draggable again. 205 // Call through so that the window is made non-draggable again.
206 WindowWantsMouseDownReposted(ns_event); 206 WindowWantsMouseDownReposted(ns_event);
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 // resize operations to coordinate with frames provided by the GPU process. 256 // resize operations to coordinate with frames provided by the GPU process.
257 scoped_refptr<base::SingleThreadTaskRunner> GetCompositorTaskRunner() { 257 scoped_refptr<base::SingleThreadTaskRunner> GetCompositorTaskRunner() {
258 // If the WindowResizeHelper's pumpable task runner is set, it means the GPU 258 // If the WindowResizeHelper's pumpable task runner is set, it means the GPU
259 // process is directing messages there, and the compositor can synchronize 259 // process is directing messages there, and the compositor can synchronize
260 // with it. Otherwise, just use the UI thread. 260 // with it. Otherwise, just use the UI thread.
261 scoped_refptr<base::SingleThreadTaskRunner> task_runner = 261 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
262 ui::WindowResizeHelperMac::Get()->task_runner(); 262 ui::WindowResizeHelperMac::Get()->task_runner();
263 return task_runner ? task_runner : base::ThreadTaskRunnerHandle::Get(); 263 return task_runner ? task_runner : base::ThreadTaskRunnerHandle::Get();
264 } 264 }
265 265
266 CGPoint GetCGMousePosition() {
267 return CGEventGetLocation(
268 base::ScopedCFTypeRef<CGEventRef>(CGEventCreate(nullptr)));
269 }
270
271 void SendCustomLeftMouseEvent(CGEventType type) {
272 base::ScopedCFTypeRef<CGEventRef> event(
273 CGEventCreateMouseEvent(
274 nullptr, type, GetCGMousePosition(),
275 kCGMouseButtonLeft));
276 CGEventSetIntegerValueField(event, kCGEventSourceUserData, 1);
277 CGEventPost(kCGSessionEventTap, event);
278 }
279
266 } // namespace 280 } // namespace
267 281
282 extern "C" {
283
284 typedef int32_t CGSConnection;
285 CGSConnection _CGSDefaultConnection();
286 CGError CGSSetWindowBackgroundBlurRadius(CGSConnection connection,
287 NSInteger windowNumber,
288 int radius);
289
290 }
291
268 namespace views { 292 namespace views {
269 293
294 class CocoaWindowMoveLoop {
295 public:
296 explicit CocoaWindowMoveLoop(BridgedNativeWidget* owner)
297 : owner_(owner),
298 run_loop_(new base::RunLoop),
299 quit_closure_(run_loop_->QuitClosure()) {
300 // AppKit continues to send mouse events to the window, but toolkit-views
301 // goes berserk if it gets them during RunMoveLoop().
302 [owner_->ns_view() setIgnoreMouseEvents:YES];
303 owner_->SetDraggable(true);
304 }
305
306 ~CocoaWindowMoveLoop() {
307 owner_->SetDraggable(false);
308 // Note the crafted events in Run() should not make their way through to
309 // toolkit-views, but regular events after that should be. So stop ignoring.
310 [owner_->ns_view() setIgnoreMouseEvents:NO];
311
312 // Handle the pathological case, where |this| is destroyed while running.
313 if (exit_reason_ref_) {
314 *exit_reason_ref_ = WINDOW_DESTROYED;
315 quit_closure_.Run();
316 }
317
318 // Handle Run() never being called.
319 if (monitor_) {
320 [NSEvent removeMonitor:monitor_];
321 monitor_ = nil;
322 }
323 owner_ = nullptr;
324 }
325
326 Widget::MoveLoopResult Run() {
327 LoopExitReason exit_reason = ENDED_EXTERNALLY;
328 exit_reason_ref_ = &exit_reason;
329
330 // Move the RunLoop to the stack so our destructor can be called while it is
331 // running.
332 scoped_ptr<base::RunLoop> run_loop(std::move(run_loop_));
333
334 // A new window may have just been created, so post an event at the session
335 // tap level to initiate a window drag.
336 // TODO(tapted): Move this "inside" the window or stuff breaks when dragging
337 // the last tab/s off a browser.
338 SendCustomLeftMouseEvent(kCGEventLeftMouseDown);
339
340 NSEventMask mask =
341 NSLeftMouseUpMask | NSKeyDownMask | NSLeftMouseDraggedMask;
342 monitor_ = [NSEvent addLocalMonitorForEventsMatchingMask:mask
343 handler:^NSEvent*(NSEvent* event) {
344 DLOG(INFO) << "Saw a thing: " << this;
345 if ([event type] == NSLeftMouseDragged) {
346 DLOG(INFO) << "drag";
347 // AppKit doesn't supply position updates during a drag, so post a
348 // task to notify observers once AppKit has moved the window.
349 base::MessageLoop::current()->PostTask(
350 FROM_HERE, base::Bind(&BridgedNativeWidget::OnPositionChanged,
351 base::Unretained(owner_)));
352 return event;
353 }
354 DLOG(INFO) << "Quitting due to event in " << this;
355 quit_closure_.Run();
356 if ([event type] == NSLeftMouseUp) {
357 DLOG(INFO) << "mouseup";
358 *exit_reason_ref_ = MOUSE_UP;
359 return event; // Process the MouseUp.
360 }
361 *exit_reason_ref_ = ESCAPE_PRESSED;
362 DLOG(INFO) << "key";
363 return nil; // Swallow the keypress.
364 }];
365
366 // NSKeyDownMask doesn't work inside addLocalMonitorForEventsMatchingMask:
367 // the event is swallowed by the window move loop before it gets to -[NSApp
368 // sendEvent:]. To see an escape keypress, hook in an event tap lower.
369
370 run_loop->Run();
371
372 if (exit_reason != WINDOW_DESTROYED && exit_reason != ENDED_EXTERNALLY) {
373 exit_reason_ref_ = nullptr; // Ensure End() doesn't replace the reason.
374 DLOG(INFO) << "Calling own EndMoveLoop in " << this;
375 owner_->EndMoveLoop(); // Deletes |this|.
376 }
377
378 if (exit_reason != MOUSE_UP) {
379 // Tell AppKit to stop moving the window. Otherwise, AppKit will refuse to
380 // start a new window drag. Note the window being dragged is going away in
381 // this case, so it doesn't really matter where the event is located.
382 SendCustomLeftMouseEvent(kCGEventLeftMouseUp);
383
384 if (exit_reason == ENDED_EXTERNALLY) {
385 // When not canceled, the non-moving drag in the original window must
386 // resume. To do this, AppKit needs to see a mouseDown so that it sends
387 // the correct events. Ideally, it also needs to be at the original
388 // offset, so that it hits a non-draggable region of the original
389 // window: The tab being dragged may move some distance from the cursor
390 // when it "snaps in", so the cursor may not be over a tab. Sadly, this
391 // method doesn't know which window that is. But all that really needs
392 // to be done is to prevent a custom-dragging area from starting a
393 // window-drag. So hook into the logic in RepostEventIfHandledByWindow()
394 // by setting a flag here. Note this assumes the custom mouseDown event
395 // is guaranteed to hit another BridgedNativeWidget when it gets to the
396 // front of the event queue.
397 // TODO(tapted): A better fix would be to keep the temporary window
398 // around and never call EndMoveLoop() on Mac, making this block of code
399 // obsolete.
400 g_ignore_next_mouse_down_for_draggable_regions = true;
401 SendCustomLeftMouseEvent(kCGEventLeftMouseDown);
402 }
403 }
404
405 return exit_reason == ESCAPE_PRESSED
406 ? Widget::MOVE_LOOP_CANCELED : Widget::MOVE_LOOP_SUCCESSFUL;
407 }
408
409 void End() {
410 DLOG(INFO) << "In End() for " << this
411 << " reason_ref = " << exit_reason_ref_;
412 if (exit_reason_ref_) {
413 DCHECK_EQ(*exit_reason_ref_, ENDED_EXTERNALLY);
414 // Ensure the destructor doesn't replace the reason.
415 exit_reason_ref_ = nullptr;
416 quit_closure_.Run();
417 }
418 }
419
420 static CGEventRef EscapeKeypressMonitor(CGEventTapProxy proxy,
421 CGEventType type,
422 CGEventRef event,
423 void* refcon) {
424 CocoaWindowMoveLoop* self = static_cast<CocoaWindowMoveLoop*>(refcon);
425 (void)self;
426 return event;
427 }
428
429 private:
430 enum LoopExitReason {
431 ENDED_EXTERNALLY,
432 ESCAPE_PRESSED,
433 MOUSE_UP,
434 WINDOW_DESTROYED,
435 };
436
437 BridgedNativeWidget* owner_; // Weak. Owns this.
438 scoped_ptr<base::RunLoop> run_loop_;
439 id monitor_ = nil;
440
441 // Pointer to a stack variable holding the exit reason.
442 LoopExitReason* exit_reason_ref_ = nullptr;
443 base::Closure quit_closure_;
444
445 DISALLOW_COPY_AND_ASSIGN(CocoaWindowMoveLoop);
446 };
447
270 // static 448 // static
271 gfx::Size BridgedNativeWidget::GetWindowSizeForClientSize( 449 gfx::Size BridgedNativeWidget::GetWindowSizeForClientSize(
272 NSWindow* window, 450 NSWindow* window,
273 const gfx::Size& content_size) { 451 const gfx::Size& content_size) {
274 NSRect content_rect = 452 NSRect content_rect =
275 NSMakeRect(0, 0, content_size.width(), content_size.height()); 453 NSMakeRect(0, 0, content_size.width(), content_size.height());
276 NSRect frame_rect = [window frameRectForContentRect:content_rect]; 454 NSRect frame_rect = [window frameRectForContentRect:content_rect];
277 return gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect)); 455 return gfx::Size(NSWidth(frame_rect), NSHeight(frame_rect));
278 } 456 }
279 457
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 display:YES 642 display:YES
465 animate:NO]; 643 animate:NO];
466 } 644 }
467 645
468 void BridgedNativeWidget::SetRootView(views::View* view) { 646 void BridgedNativeWidget::SetRootView(views::View* view) {
469 if (view == [bridged_view_ hostedView]) 647 if (view == [bridged_view_ hostedView])
470 return; 648 return;
471 649
472 // If this is ever false, the compositor will need to be properly torn down 650 // If this is ever false, the compositor will need to be properly torn down
473 // and replaced, pointing at the new view. 651 // and replaced, pointing at the new view.
652 if (view && compositor_widget_) {
653 DLOG(INFO) << "Gonna die: view=" << view
654 << " compositor_widget=" << compositor_widget_;
655 }
474 DCHECK(!view || !compositor_widget_); 656 DCHECK(!view || !compositor_widget_);
475 657
476 [bridged_view_ clearView]; 658 [bridged_view_ clearView];
477 bridged_view_.reset(); 659 bridged_view_.reset();
478 // Note that there can still be references to the old |bridged_view_| 660 // Note that there can still be references to the old |bridged_view_|
479 // floating around in Cocoa libraries at this point. However, references to 661 // floating around in Cocoa libraries at this point. However, references to
480 // the old views::View will be gone, so any method calls will become no-ops. 662 // the old views::View will be gone, so any method calls will become no-ops.
481 663
482 if (view) { 664 if (view) {
483 bridged_view_.reset([[BridgedContentView alloc] initWithView:view]); 665 bridged_view_.reset([[BridgedContentView alloc] initWithView:view]);
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 // hasn't yet received a frame from the compositor at this stage, so it is 721 // hasn't yet received a frame from the compositor at this stage, so it is
540 // fully transparent until the GPU sends a frame swap IPC. For the blocking 722 // fully transparent until the GPU sends a frame swap IPC. For the blocking
541 // option, the animation needs to wait until AcceleratedWidgetSwapCompleted 723 // option, the animation needs to wait until AcceleratedWidgetSwapCompleted
542 // has been called at least once, otherwise it will animate nothing. 724 // has been called at least once, otherwise it will animate nothing.
543 [show_animation setAnimationBlockingMode:NSAnimationNonblocking]; 725 [show_animation setAnimationBlockingMode:NSAnimationNonblocking];
544 [show_animation startAnimation]; 726 [show_animation startAnimation];
545 } 727 }
546 } 728 }
547 729
548 void BridgedNativeWidget::AcquireCapture() { 730 void BridgedNativeWidget::AcquireCapture() {
731 base::debug::StackTrace().Print();
732 DLOG(INFO) << "AcquireCapture: " << this;
549 DCHECK(!HasCapture()); 733 DCHECK(!HasCapture());
550 if (!window_visible_) 734 if (!window_visible_)
551 return; // Capture on hidden windows is disallowed. 735 return; // Capture on hidden windows is disallowed.
552 736
553 mouse_capture_.reset(new CocoaMouseCapture(this)); 737 mouse_capture_.reset(new CocoaMouseCapture(this));
554 738
555 // Initiating global event capture with addGlobalMonitorForEventsMatchingMask: 739 // Initiating global event capture with addGlobalMonitorForEventsMatchingMask:
556 // will reset the mouse cursor to an arrow. Asking the window for an update 740 // will reset the mouse cursor to an arrow. Asking the window for an update
557 // here will restore what we want. However, it can sometimes cause the cursor 741 // here will restore what we want. However, it can sometimes cause the cursor
558 // to flicker, once, on the initial mouseDown. 742 // to flicker, once, on the initial mouseDown.
559 // TOOD(tapted): Make this unnecessary by only asking for global mouse capture 743 // TOOD(tapted): Make this unnecessary by only asking for global mouse capture
560 // for the cases that need it (e.g. menus, but not drag and drop). 744 // for the cases that need it (e.g. menus, but not drag and drop).
561 [window_ cursorUpdate:[NSApp currentEvent]]; 745 [window_ cursorUpdate:[NSApp currentEvent]];
562 } 746 }
563 747
564 void BridgedNativeWidget::ReleaseCapture() { 748 void BridgedNativeWidget::ReleaseCapture() {
749 base::debug::StackTrace().Print();
750 DLOG(INFO) << "ReleaseCapture: " << this << " drag_loop=" << drag_run_loop_;
565 mouse_capture_.reset(); 751 mouse_capture_.reset();
752 //if (drag_run_loop_) {
753 // drag_run_loop_->Quit();
754 // drag_run_loop_ = nullptr;
755 //}
566 } 756 }
567 757
568 bool BridgedNativeWidget::HasCapture() { 758 bool BridgedNativeWidget::HasCapture() {
569 return mouse_capture_ && mouse_capture_->IsActive(); 759 return mouse_capture_ && mouse_capture_->IsActive();
570 } 760 }
571 761
762 Widget::MoveLoopResult BridgedNativeWidget::RunMoveLoop(
763 const gfx::Vector2d& drag_offset) {
764 base::debug::StackTrace().Print();
765 DLOG(INFO) << "RunMoveLoop(): " << this << " drag_loop=" << drag_run_loop_;
766
767 DCHECK(!HasCapture());
768 DCHECK(!window_move_loop_);
769
770 // First, position the window in the right place. The point |drag_offset|
771 // away from the top-left corner needs to be positioned under the mouse.
772 // TODO(tapted): Figure out why the toolkit-views drag controller doesn't get
773 // this right when it first initializes the Widget.
774 NSPoint mouse_in_screen = gfx::ScreenPointToNSPoint(
775 gfx::Screen::GetScreen()->GetCursorScreenPoint());
776 NSRect frame = [window_ frame];
777 frame.origin.x = mouse_in_screen.x - drag_offset.x();
778 frame.origin.y = mouse_in_screen.y - NSHeight(frame) + drag_offset.y();
779 NSLog(@"mouse, frame, offset -> frame: %@, %@, %s, %@",
780 NSStringFromRect([window_ frame]),
781 NSStringFromPoint(mouse_in_screen),
782 drag_offset.ToString().c_str(),
783 NSStringFromRect(frame));
784
785 // After setting the frame to correct the initial offset, the drag controller
786 // may immediately want to quit when it's notified of the new bounds. So the
787 // MoveLoop must be set up before the call to setFrame.
788 window_move_loop_.reset(new CocoaWindowMoveLoop(this));
789
790 // Animating may provide a less janky UX, but something custom would be
791 // required so that it follows updates to the mouse position.
792 [window_ setFrame:frame display:YES animate:NO];
793
794 // Setting the frame will call OnWidgetBoundsChanged(), which could result in
795 // a call to EndMoveLoop().
796 if (!window_move_loop_)
797 return Widget::MOVE_LOOP_SUCCESSFUL;
798
799 return window_move_loop_->Run();
800
801 // |this| may be destroyed during the RunLoop, causing it to exit early.
802 // Even if that doesn't happen, CocoaWindowMoveLoop will clean itself up by
803 // calling EndMoveLoop(). So window_move_loop_ will always be null before the
804 // function returns. But don't DCHECK since |this| might not be valid.
805 }
806
807 void BridgedNativeWidget::EndMoveLoop() {
808 DCHECK(window_move_loop_);
809 DLOG(INFO) << "Quitting due to EndMoveLoop for " << window_move_loop_.get();
810 window_move_loop_->End();
811 DLOG(INFO) << "Resetting: " << window_move_loop_.get();
812 window_move_loop_.reset();
813 }
814
572 void BridgedNativeWidget::SetNativeWindowProperty(const char* name, 815 void BridgedNativeWidget::SetNativeWindowProperty(const char* name,
573 void* value) { 816 void* value) {
574 NSString* key = [NSString stringWithUTF8String:name]; 817 NSString* key = [NSString stringWithUTF8String:name];
575 if (value) { 818 if (value) {
576 [GetWindowProperties() setObject:[NSValue valueWithPointer:value] 819 [GetWindowProperties() setObject:[NSValue valueWithPointer:value]
577 forKey:key]; 820 forKey:key];
578 } else { 821 } else {
579 [GetWindowProperties() removeObjectForKey:key]; 822 [GetWindowProperties() removeObjectForKey:key];
580 } 823 }
581 } 824 }
582 825
583 void* BridgedNativeWidget::GetNativeWindowProperty(const char* name) const { 826 void* BridgedNativeWidget::GetNativeWindowProperty(const char* name) const {
584 NSString* key = [NSString stringWithUTF8String:name]; 827 NSString* key = [NSString stringWithUTF8String:name];
585 return [[GetWindowProperties() objectForKey:key] pointerValue]; 828 return [[GetWindowProperties() objectForKey:key] pointerValue];
586 } 829 }
587 830
588 void BridgedNativeWidget::SetCursor(NSCursor* cursor) { 831 void BridgedNativeWidget::SetCursor(NSCursor* cursor) {
589 [window_delegate_ setCursor:cursor]; 832 [window_delegate_ setCursor:cursor];
590 } 833 }
591 834
592 void BridgedNativeWidget::OnWindowWillClose() { 835 void BridgedNativeWidget::OnWindowWillClose() {
836 DCHECK(!drag_run_loop_);
593 if (parent_) { 837 if (parent_) {
594 parent_->RemoveChildWindow(this); 838 parent_->RemoveChildWindow(this);
595 parent_ = nullptr; 839 parent_ = nullptr;
596 } 840 }
597 [window_ setDelegate:nil]; 841 [window_ setDelegate:nil];
598 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; 842 [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_];
599 native_widget_mac_->OnWindowWillClose(); 843 native_widget_mac_->OnWindowWillClose();
600 } 844 }
601 845
602 void BridgedNativeWidget::OnFullscreenTransitionStart( 846 void BridgedNativeWidget::OnFullscreenTransitionStart(
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
685 929
686 // 10.9 is unable to generate a window shadow from the composited CALayer, so 930 // 10.9 is unable to generate a window shadow from the composited CALayer, so
687 // use Quartz. 931 // use Quartz.
688 // We don't update the window mask during a live resize, instead it is done 932 // We don't update the window mask during a live resize, instead it is done
689 // after the resize is completed in viewDidEndLiveResize: in 933 // after the resize is completed in viewDidEndLiveResize: in
690 // BridgedContentView. 934 // BridgedContentView.
691 if (base::mac::IsOSMavericksOrEarlier() && ![window_ inLiveResize]) 935 if (base::mac::IsOSMavericksOrEarlier() && ![window_ inLiveResize])
692 [bridged_view_ updateWindowMask]; 936 [bridged_view_ updateWindowMask];
693 } 937 }
694 938
939 void BridgedNativeWidget::OnPositionChanged() {
940 native_widget_mac_->GetWidget()->OnNativeWidgetMove();
941 }
942
695 void BridgedNativeWidget::OnVisibilityChanged() { 943 void BridgedNativeWidget::OnVisibilityChanged() {
696 OnVisibilityChangedTo([window_ isVisible]); 944 OnVisibilityChangedTo([window_ isVisible]);
697 } 945 }
698 946
699 void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) { 947 void BridgedNativeWidget::OnVisibilityChangedTo(bool new_visibility) {
700 if (window_visible_ == new_visibility) 948 if (window_visible_ == new_visibility)
701 return; 949 return;
702 950
703 window_visible_ = new_visibility; 951 window_visible_ = new_visibility;
704 952
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after
1238 [bridged_view_ setMouseDownCanMoveWindow:draggable]; 1486 [bridged_view_ setMouseDownCanMoveWindow:draggable];
1239 // AppKit will not update its cache of mouseDownCanMoveWindow unless something 1487 // AppKit will not update its cache of mouseDownCanMoveWindow unless something
1240 // changes. Previously we tried adding an NSView and removing it, but for some 1488 // 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. 1489 // reason it required reposting the mouse-down event, and didn't always work.
1242 // Calling the below seems to be an effective solution. 1490 // Calling the below seems to be an effective solution.
1243 [window_ setMovableByWindowBackground:NO]; 1491 [window_ setMovableByWindowBackground:NO];
1244 [window_ setMovableByWindowBackground:YES]; 1492 [window_ setMovableByWindowBackground:YES];
1245 } 1493 }
1246 1494
1247 } // namespace views 1495 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698