File: mouse_drag_controller.mm

package info (click to toggle)
chromium-browser 41.0.2272.118-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie-kfreebsd
  • size: 2,189,132 kB
  • sloc: cpp: 9,691,462; ansic: 3,341,451; python: 712,689; asm: 518,779; xml: 208,926; java: 169,820; sh: 119,353; perl: 68,907; makefile: 28,311; yacc: 13,305; objc: 11,385; tcl: 3,186; cs: 2,225; sql: 2,217; lex: 2,215; lisp: 1,349; pascal: 1,256; awk: 407; ruby: 155; sed: 53; php: 14; exp: 11
file content (145 lines) | stat: -rw-r--r-- 4,364 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright (c) 2012 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 "chrome/browser/ui/cocoa/panels/mouse_drag_controller.h"

#include <Carbon/Carbon.h>  // kVK_Escape
#import <Cocoa/Cocoa.h>

#include "base/logging.h"
#include "base/mac/scoped_nsautorelease_pool.h"

// The distance the user has to move the mouse while keeping the left button
// down before panel resizing operation actually starts.
const double kDragThreshold = 3.0;

@implementation MouseDragController

- (NSView<MouseDragControllerClient>*)client {
  return client_;
}

- (NSPoint)initialMouseLocation {
  return initialMouseLocation_;
}

- (BOOL)exceedsDragThreshold:(NSPoint)mouseLocation {
  float deltaX = fabs(initialMouseLocation_.x - mouseLocation.x);
  float deltaY = fabs(initialMouseLocation_.y - mouseLocation.y);
  return deltaX > kDragThreshold || deltaY > kDragThreshold;
}

- (BOOL)tryStartDrag:(NSEvent*)event {
  DCHECK(dragState_ == PANEL_DRAG_CAN_START);
  NSPoint mouseLocation = [event locationInWindow];
  if (![self exceedsDragThreshold:mouseLocation])
    return NO;

  // Mouse moved over threshold, start drag.
  dragState_ = PANEL_DRAG_IN_PROGRESS;
  [client_ dragStarted:initialMouseLocation_];
  return YES;
}

- (void)cleanupAfterDrag {
  if (dragState_ == PANEL_DRAG_SUPPRESSED)
    return;
  dragState_ = PANEL_DRAG_SUPPRESSED;
  initialMouseLocation_ = NSZeroPoint;
  [client_ cleanupAfterDrag];
}

- (MouseDragController*)initWithClient:
      (NSView<MouseDragControllerClient>*)client {
  client_ = client;
  dragState_ = PANEL_DRAG_SUPPRESSED;
  return self;
}

- (void)mouseDown:(NSEvent*)event {
  DCHECK(dragState_ == PANEL_DRAG_SUPPRESSED);
  dragState_ = PANEL_DRAG_CAN_START;
  initialMouseLocation_ = [event locationInWindow];
  [client_ prepareForDrag];
}

- (void)mouseDragged:(NSEvent*)event {
  if (dragState_ == PANEL_DRAG_SUPPRESSED)
    return;

  // In addition to events needed to control the drag operation, fetch the right
  // mouse click events and key down events and ignore them, to prevent their
  // accumulation in the queue and "playing out" when the mouse is released.
  const NSUInteger mask =
      NSLeftMouseUpMask | NSLeftMouseDraggedMask | NSKeyUpMask |
      NSRightMouseDownMask | NSKeyDownMask ;

  while (true) {
    base::mac::ScopedNSAutoreleasePool autorelease_pool;
    BOOL keepGoing = YES;

    switch ([event type]) {
      case NSLeftMouseDragged: {
        // If drag didn't start yet, see if mouse moved far enough to start it.
        if (dragState_ == PANEL_DRAG_CAN_START && ![self tryStartDrag:event])
          return;

        DCHECK(dragState_ == PANEL_DRAG_IN_PROGRESS);
        [client_ dragProgress:[event locationInWindow]];
        break;
      }

      case NSKeyUp:
        if ([event keyCode] == kVK_Escape) {
          // The drag might not be started yet because of threshold, so check.
          if (dragState_ == PANEL_DRAG_IN_PROGRESS)
            [client_ dragEnded:YES];
          keepGoing = NO;
        }
        break;

      case NSLeftMouseUp:
        // The drag might not be started yet because of threshold, so check.
        if (dragState_ == PANEL_DRAG_IN_PROGRESS)
          [client_ dragEnded:NO];
        keepGoing = NO;
        break;

      case NSRightMouseDownMask:
        break;

      default:
        // Dequeue and ignore other mouse and key events so the Chrome context
        // menu does not come after right click on a page during Panel
        // resize, or the keystrokes are not 'accumulated' and entered
        // at once when the drag ends.
        break;
    }

    if (!keepGoing)
      break;

    autorelease_pool.Recycle();

    event = [NSApp nextEventMatchingMask:mask
                               untilDate:[NSDate distantFuture]
                                  inMode:NSDefaultRunLoopMode
                                 dequeue:YES];

  }
  [self cleanupAfterDrag];
}


- (void)mouseUp:(NSEvent*)event {
  if (dragState_ == PANEL_DRAG_SUPPRESSED)
    return;
  // The mouseUp while in drag should be processed by nested message loop
  // in mouseDragged: method.
  DCHECK(dragState_ != PANEL_DRAG_IN_PROGRESS);
  // Do cleanup in case the actual drag was not started (because of threshold).
  [self cleanupAfterDrag];
}
@end