Index: chrome/browser/ui/cocoa/browser_window_controller.mm |
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm |
index e1d8109199c0f37b0dae5e53b03e584bb728429c..06cbcfb82db28b2abe29e50b32616fdcfaaa5118 100644 |
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm |
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm |
@@ -5,6 +5,7 @@ |
#import "chrome/browser/ui/cocoa/browser_window_controller.h" |
#include <Carbon/Carbon.h> |
+#include <numeric> |
#include "base/command_line.h" |
#include "base/mac/mac_util.h" |
@@ -141,7 +142,6 @@ |
// longer indicate that the window is shrinking from an apparent zoomed state) |
// and if it's set we continue to constrain the resize. |
- |
@interface NSWindow (NSPrivateApis) |
// Note: These functions are private, use -[NSObject respondsToSelector:] |
// before calling them. |
@@ -152,6 +152,33 @@ |
@end |
+// Forward-declare symbols that are part of the 10.6 SDK. |
+#if !defined(MAC_OS_X_VERSION_10_6) || \ |
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 |
+ |
+enum { |
+ NSTouchPhaseBegan = 1U << 0, |
+ NSTouchPhaseMoved = 1U << 1, |
+ NSTouchPhaseStationary = 1U << 2, |
+ NSTouchPhaseEnded = 1U << 3, |
+ NSTouchPhaseCancelled = 1U << 4, |
+ NSTouchPhaseTouching = NSTouchPhaseBegan | NSTouchPhaseMoved | |
+ NSTouchPhaseStationary, |
+ NSTouchPhaseAny = NSUIntegerMax |
+}; |
+typedef NSUInteger NSTouchPhase; |
+ |
+@interface NSEvent (SnowLeopardDeclarations) |
+- (NSSet*)touchesMatchingPhase:(NSTouchPhase)phase inView:(NSView*)view; |
+@end |
+ |
+@interface NSTouch : NSObject |
+- (NSPoint)normalizedPosition; |
+- (id<NSObject, NSCopying>)identity; |
+@end |
+ |
+#endif // MAC_OS_X_VERSION_10_6 |
+ |
// Provide the forward-declarations of new 10.7 SDK symbols so they can be |
// called when building with the 10.5 SDK. |
#if !defined(MAC_OS_X_VERSION_10_7) || \ |
@@ -1705,6 +1732,71 @@ typedef NSInteger NSWindowAnimationBehavior; |
- (void)beginGestureWithEvent:(NSEvent*)event { |
totalMagnifyGestureAmount_ = 0; |
currentZoomStepDelta_ = 0; |
+ |
+ // On Lion, there's support controlled by a System Preference for two- and |
+ // three-finger navigational gestures. If set to allow three-finger gestures, |
+ // the system gesture recognizer will automatically call |-swipeWithEvent:| |
+ // and that will be handled as it would be on Snow Leopard. The two-finger |
+ // gesture does not do this, so it must be manually recognized. See the note |
+ // inside |-recognizeTwoFingerGestures| for detailed information on the |
+ // interaction of the different preferences. |
+ NSSet* touches = [event touchesMatchingPhase:NSTouchPhaseAny |
+ inView:nil]; |
+ if ([self recognizeTwoFingerGestures] && [touches count] >= 2) { |
+ twoFingerGestureTouches_.reset([[NSMutableDictionary alloc] init]); |
+ for (NSTouch* touch in touches) { |
+ [twoFingerGestureTouches_ setObject:touch forKey:touch.identity]; |
+ } |
+ } |
+} |
+ |
+- (void)endGestureWithEvent:(NSEvent*)event { |
+ // This method only needs to process gesture events for two-finger navigation. |
+ if (!twoFingerGestureTouches_.get()) |
+ return; |
+ |
+ // When a multi-touch gesture ends, only one touch will be in the "End" phase. |
+ // Other touches will be in "Moved" or "Unknown" phases. So long as one is |
+ // ended, which it is by virtue of this method being called, the gesture can |
+ // be committed so long as the magnitude is great enough. |
+ NSSet* touches = [event touchesMatchingPhase:NSTouchPhaseAny |
+ inView:nil]; |
+ |
+ // Store the touch data locally and reset the ivar so that new gestures can |
+ // begin. |
+ scoped_nsobject<NSDictionary> beginTouches( |
+ twoFingerGestureTouches_.release()); |
+ |
+ // Construct a vector of magnitudes. Since gesture events do not have the |
+ // |-deltaX| property set, this creates the X magnitude for each finger. |
+ std::vector<CGFloat> magnitudes; |
+ for (NSTouch* touch in touches) { |
+ NSTouch* beginTouch = [beginTouches objectForKey:touch.identity]; |
+ if (!beginTouch) |
+ continue; |
+ |
+ // The |normalizedPosition| is scaled from (0,1). |
+ magnitudes.push_back(touch.normalizedPosition.x - |
+ beginTouch.normalizedPosition.x); |
+ } |
+ |
+ // Need at least two points to gesture. |
+ if (magnitudes.size() < 2) |
+ return; |
+ |
+ CGFloat sum = std::accumulate(magnitudes.begin(), magnitudes.end(), 0.0f); |
+ int command_id = 0; |
+ if (sum > 0.3) |
+ command_id = IDC_FORWARD; |
+ else if (sum < -0.3) |
+ command_id = IDC_BACK; |
+ else |
+ return; |
+ |
+ if (browser_->command_updater()->IsCommandEnabled(command_id)) { |
+ browser_->ExecuteCommandWithDisposition(command_id, |
+ event_utils::WindowOpenDispositionFromNSEvent(event)); |
+ } |
} |
// Delegate method called when window is resized. |