| Index: ui/views/cocoa/cocoa_window_move_loop.mm
 | 
| diff --git a/ui/views/cocoa/cocoa_window_move_loop.mm b/ui/views/cocoa/cocoa_window_move_loop.mm
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..a306f9cfb5ced21e0dc7c8d259cb515015eac09a
 | 
| --- /dev/null
 | 
| +++ b/ui/views/cocoa/cocoa_window_move_loop.mm
 | 
| @@ -0,0 +1,127 @@
 | 
| +// Copyright 2016 The Chromium Authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +#include "ui/views/cocoa/cocoa_window_move_loop.h"
 | 
| +
 | 
| +#include "base/run_loop.h"
 | 
| +#include "ui/display/screen.h"
 | 
| +#import "ui/gfx/mac/coordinate_conversion.h"
 | 
| +#import "ui/views/cocoa/bridged_native_widget.h"
 | 
| +
 | 
| +// When event monitors process the events the full list of monitors is cached,
 | 
| +// and if we unregister the event monitor that's at the end of the list while
 | 
| +// processing the first monitor's handler -- the callback for the unregistered
 | 
| +// monitor will still be called even though it's unregistered. This will result
 | 
| +// in dereferencing an invalid pointer.
 | 
| +//
 | 
| +// WeakCocoaWindowMoveLoop is retained by the event monitor and stores weak
 | 
| +// pointer for the CocoaWindowMoveLoop, so there will be no invalid memory
 | 
| +// access.
 | 
| +@interface WeakCocoaWindowMoveLoop : NSObject {
 | 
| + @private
 | 
| +  base::WeakPtr<views::CocoaWindowMoveLoop> weak_;
 | 
| +}
 | 
| +@end
 | 
| +
 | 
| +@implementation WeakCocoaWindowMoveLoop
 | 
| +- (id)initWithWeakPtr:(const base::WeakPtr<views::CocoaWindowMoveLoop>&)weak {
 | 
| +  if ((self = [super init])) {
 | 
| +    weak_ = weak;
 | 
| +  }
 | 
| +  return self;
 | 
| +}
 | 
| +
 | 
| +- (base::WeakPtr<views::CocoaWindowMoveLoop>&)weak {
 | 
| +  return weak_;
 | 
| +}
 | 
| +@end
 | 
| +
 | 
| +namespace views {
 | 
| +
 | 
| +CocoaWindowMoveLoop::CocoaWindowMoveLoop(
 | 
| +    BridgedNativeWidget* owner,
 | 
| +    const NSPoint& initial_mouse_in_screen)
 | 
| +    : owner_(owner),
 | 
| +      initial_mouse_in_screen_(initial_mouse_in_screen),
 | 
| +      weak_factory_(this) {
 | 
| +}
 | 
| +
 | 
| +CocoaWindowMoveLoop::~CocoaWindowMoveLoop() {
 | 
| +  // Handle the pathological case, where |this| is destroyed while running.
 | 
| +  if (exit_reason_ref_) {
 | 
| +    *exit_reason_ref_ = WINDOW_DESTROYED;
 | 
| +    quit_closure_.Run();
 | 
| +  }
 | 
| +
 | 
| +  owner_ = nullptr;
 | 
| +}
 | 
| +
 | 
| +Widget::MoveLoopResult CocoaWindowMoveLoop::Run() {
 | 
| +  LoopExitReason exit_reason = ENDED_EXTERNALLY;
 | 
| +  exit_reason_ref_ = &exit_reason;
 | 
| +  NSWindow* window = owner_->ns_window();
 | 
| +  const NSRect initial_frame = [window frame];
 | 
| +
 | 
| +  base::RunLoop run_loop;
 | 
| +  quit_closure_ = run_loop.QuitClosure();
 | 
| +
 | 
| +  // Will be retained by the monitor handler block.
 | 
| +  WeakCocoaWindowMoveLoop* weak_cocoa_window_move_loop =
 | 
| +      [[[WeakCocoaWindowMoveLoop alloc]
 | 
| +          initWithWeakPtr:weak_factory_.GetWeakPtr()] autorelease];
 | 
| +
 | 
| +  // Esc keypress is handled by EscapeTracker, which is installed by
 | 
| +  // TabDragController.
 | 
| +  NSEventMask mask = NSLeftMouseUpMask | NSLeftMouseDraggedMask;
 | 
| +  auto handler = ^NSEvent*(NSEvent* event) {
 | 
| +    CocoaWindowMoveLoop* strong = [weak_cocoa_window_move_loop weak].get();
 | 
| +    if (!strong || !strong->exit_reason_ref_) {
 | 
| +      // By this point CocoaWindowMoveLoop was deleted while processing this
 | 
| +      // same event, and this event monitor was not unregistered in time. See
 | 
| +      // the WeakCocoaWindowMoveLoop comment above.
 | 
| +      // Continue processing the event.
 | 
| +      return event;
 | 
| +    }
 | 
| +
 | 
| +    if ([event type] == NSLeftMouseDragged) {
 | 
| +      const NSPoint mouse_in_screen = [NSEvent mouseLocation];
 | 
| +
 | 
| +      const NSRect ns_frame = NSOffsetRect(
 | 
| +          initial_frame, mouse_in_screen.x - initial_mouse_in_screen_.x,
 | 
| +          mouse_in_screen.y - initial_mouse_in_screen_.y);
 | 
| +      [window setFrame:ns_frame display:NO animate:NO];
 | 
| +
 | 
| +      return event;
 | 
| +    }
 | 
| +
 | 
| +    DCHECK_EQ([event type], NSLeftMouseUp);
 | 
| +    *strong->exit_reason_ref_ = MOUSE_UP;
 | 
| +    strong->quit_closure_.Run();
 | 
| +    return event;  // Process the MouseUp.
 | 
| +  };
 | 
| +  id monitor =
 | 
| +      [NSEvent addLocalMonitorForEventsMatchingMask:mask handler:handler];
 | 
| +
 | 
| +  run_loop.Run();
 | 
| +  [NSEvent removeMonitor:monitor];
 | 
| +
 | 
| +  if (exit_reason != WINDOW_DESTROYED && exit_reason != ENDED_EXTERNALLY) {
 | 
| +    exit_reason_ref_ = nullptr;  // Ensure End() doesn't replace the reason.
 | 
| +    owner_->EndMoveLoop();       // Deletes |this|.
 | 
| +  }
 | 
| +
 | 
| +  return exit_reason != MOUSE_UP ? Widget::MOVE_LOOP_CANCELED
 | 
| +                                 : Widget::MOVE_LOOP_SUCCESSFUL;
 | 
| +}
 | 
| +
 | 
| +void CocoaWindowMoveLoop::End() {
 | 
| +  if (exit_reason_ref_) {
 | 
| +    DCHECK_EQ(*exit_reason_ref_, ENDED_EXTERNALLY);
 | 
| +    // Ensure the destructor doesn't replace the reason.
 | 
| +    exit_reason_ref_ = nullptr;
 | 
| +    quit_closure_.Run();
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +}  // namespace views
 | 
| 
 |