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

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

Issue 1747803003: MacViews: Implement Tab Dragging (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove CGEvent-generating code from ui_controls_mac.mm Created 4 years, 6 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
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/views/cocoa/cocoa_window_move_loop.h"
6
7 #import <Cocoa/Cocoa.h>
8
9 #include "base/run_loop.h"
10 #include "ui/display/screen.h"
11 #import "ui/gfx/mac/coordinate_conversion.mm"
12 #import "ui/views/cocoa/bridged_native_widget.h"
13
14 // When event monitors process the events the full list of monitors is cached,
15 // and if we unregister the event monitor that's at the end of the list while
16 // processing the first monitor's handler -- the callback for the unregistered
17 // monitor will still be called even though it's unregistered. This will result
18 // in dereferencing an invalid pointer.
19 //
20 // WeakCocoaWindowMoveLoop is retained by the event monitor and stores weak
21 // pointer for the CocoaWindowMoveLoop, so there will be no invalid memory
22 // access.
23 @interface WeakCocoaWindowMoveLoop : NSObject {
24 @private
25 base::WeakPtr<views::CocoaWindowMoveLoop> weak_;
26 }
27 @end
28
29 @implementation WeakCocoaWindowMoveLoop
30 - (id)initWithWeakPtr:(const base::WeakPtr<views::CocoaWindowMoveLoop>&)weak {
31 if ((self = [super init])) {
32 weak_ = weak;
33 }
34 return self;
35 }
36
37 - (base::WeakPtr<views::CocoaWindowMoveLoop>&)weak {
38 return weak_;
39 }
40 @end
41
42 namespace views {
43
44 CocoaWindowMoveLoop::CocoaWindowMoveLoop(
45 BridgedNativeWidget* owner,
46 const gfx::Point& initial_mouse_in_screen)
47 : owner_(owner),
48 initial_mouse_in_screen_(initial_mouse_in_screen),
tapted 2016/06/01 11:29:56 use gfx::ScreenRectToNSRect() here
themblsha 2016/06/03 17:42:08 Done.
49 weak_factory_(this) {
50 owner_->SetDraggable(true);
51 }
52
53 CocoaWindowMoveLoop::~CocoaWindowMoveLoop() {
54 owner_->SetDraggable(false);
55
56 // Handle the pathological case, where |this| is destroyed while running.
57 if (exit_reason_ref_) {
58 *exit_reason_ref_ = WINDOW_DESTROYED;
59 quit_closure_.Run();
60 }
61
62 owner_ = nullptr;
63 }
64
65 Widget::MoveLoopResult CocoaWindowMoveLoop::Run() {
66 LoopExitReason exit_reason = ENDED_EXTERNALLY;
67 exit_reason_ref_ = &exit_reason;
68 NSWindow* window = owner_->ns_window();
69 const NSRect initial_frame = [window frame];
70
71 base::RunLoop run_loop;
72 quit_closure_ = run_loop.QuitClosure();
73
74 // Will be retained by the monitor handler block.
75 WeakCocoaWindowMoveLoop* weak_cocoa_window_move_loop =
76 [[[WeakCocoaWindowMoveLoop alloc]
77 initWithWeakPtr:weak_factory_.GetWeakPtr()] autorelease];
78
79 // Esc keypress is handled by EscapeTracker, which is installed by
80 // TabDragController.
81 NSEventMask mask = NSLeftMouseUpMask | NSLeftMouseDraggedMask;
82 auto handler = ^NSEvent*(NSEvent* event) {
83 CocoaWindowMoveLoop* strong = [weak_cocoa_window_move_loop weak].get();
84 if (!strong || !strong->exit_reason_ref_) {
85 // By this point CocoaWindowMoveLoop was deleted while processing this
86 // same event, and this event monitor was not unregistered in time. See
87 // the WeakCocoaWindowMoveLoop comment above.
88 // Continue processing the event.
89 return event;
90 }
91
92 if ([event type] == NSLeftMouseDragged) {
93 const gfx::Point mouse_in_screen =
94 display::Screen::GetScreen()->GetCursorScreenPoint();
tapted 2016/06/01 11:29:56 (per earlier comment, use [NSEvent mouseLocation]
themblsha 2016/06/03 17:42:08 Done.
95
96 const NSRect ns_frame = NSOffsetRect(
97 initial_frame, mouse_in_screen.x() - initial_mouse_in_screen_.x(),
98 -(mouse_in_screen.y() - initial_mouse_in_screen_.y()));
99 [window setFrame:ns_frame display:NO animate:NO];
100
101 return event;
102 }
103
104 DCHECK_EQ([event type], NSLeftMouseUp);
105 *strong->exit_reason_ref_ = MOUSE_UP;
106 strong->quit_closure_.Run();
107 return event; // Process the MouseUp.
108 };
109 id monitor =
110 [NSEvent addLocalMonitorForEventsMatchingMask:mask handler:handler];
111
112 run_loop.Run();
113 [NSEvent removeMonitor:monitor];
114
115 if (exit_reason != WINDOW_DESTROYED && exit_reason != ENDED_EXTERNALLY) {
116 exit_reason_ref_ = nullptr; // Ensure End() doesn't replace the reason.
117 owner_->EndMoveLoop(); // Deletes |this|.
118 }
119
120 return exit_reason != MOUSE_UP ? Widget::MOVE_LOOP_CANCELED
121 : Widget::MOVE_LOOP_SUCCESSFUL;
122 }
123
124 void CocoaWindowMoveLoop::End() {
125 if (exit_reason_ref_) {
126 DCHECK_EQ(*exit_reason_ref_, ENDED_EXTERNALLY);
127 // Ensure the destructor doesn't replace the reason.
128 exit_reason_ref_ = nullptr;
129 quit_closure_.Run();
130 }
131 }
132
133 void CocoaWindowMoveLoop::OnPositionChanged() {
134 return owner_->OnPositionChanged();
135 }
136
137 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698