diff --git a/AppKit/CPResponder.j b/AppKit/CPResponder.j index 92a6dff9b..9e268e40f 100644 --- a/AppKit/CPResponder.j +++ b/AppKit/CPResponder.j @@ -152,6 +152,15 @@ CPDownArrowKeyCode = 40; [_nextResponder performSelector:_cmd withObject:anEvent]; } +/*! + Notifies the receiver that the user has clicked the right mouse down in its area. + @param anEvent contains information about the right click +*/ +- (void)rightMouseDown:(CPEvent)anEvent +{ + [_nextResponder performSelector:_cmd withObject:anEvent]; +} + /*! Notifies the receiver that the user has initiated a drag over it. A drag is a mouse movement while the left button is down. @@ -171,6 +180,15 @@ CPDownArrowKeyCode = 40; [_nextResponder performSelector:_cmd withObject:anEvent]; } +/*! + Notifies the receiver that the user has released the right mouse button. + @param anEvent contains information about the release +*/ +- (void)rightMouseUp:(CPEvent)anEvent +{ + [_nextResponder performSelector:_cmd withObject:anEvent]; +} + /*! Notifies the receiver that the user has moved the mouse (with no buttons down). @param anEvent contains information about the movement diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 318c45357..c3b2499b8 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -243,6 +243,11 @@ var CPViewFlags = { }, return [CPSet setWithObjects:@"boundsOrigin", @"boundsSize"]; } ++ (CPMenu)defaultMenu +{ + return nil; +} + - (id)init { return [self initWithFrame:CGRectMakeZero()]; @@ -1309,6 +1314,22 @@ var CPViewFlags = { }, [super mouseDown:anEvent]; } +- (void)rightMouseDown:(CPEvent)anEvent +{ + var menu = [self menuForEvent:anEvent]; + if (menu) + [CPMenu popUpContextMenu:menu withEvent:anEvent forView:self]; + else if ([[self nextResponder] isKindOfClass:CPView]) + [super rightMouseDown:anEvent]; + else + [[[anEvent window] platformWindow] _propagateContextMenuDOMEvent:YES]; +} + +- (CPMenu)menuForEvent:(CPEvent)anEvent +{ + return [self menu] || [[self class] defaultMenu]; +} + /*! Sets the background color of the receiver. @param aColor the new color for the receiver's background diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index cfb98a5f5..7a916d9eb 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -1347,44 +1347,58 @@ CPTexturedBackgroundWindowMask case CPScrollWheel: return [[_windowView hitTest:point] scrollWheel:anEvent]; - case CPLeftMouseUp: if (!_leftMouseDownView) - return [[_windowView hitTest:point] mouseUp:anEvent]; + case CPLeftMouseUp: + case CPRightMouseUp: var hitTestedView = _leftMouseDownView, + selector = type == CPRightMouseUp ? @selector(rightMouseUp:) : @selector(mouseUp:); - [_leftMouseDownView mouseUp:anEvent] + if (!hitTestedView) + hitTestedView = [_windowView hitTest:point]; + + [hitTestedView performSelector:selector withObject:anEvent]; _leftMouseDownView = nil; return; - case CPLeftMouseDown: _leftMouseDownView = [_windowView hitTest:point]; + case CPLeftMouseDown: + case CPRightMouseDown: _leftMouseDownView = [_windowView hitTest:point]; if (_leftMouseDownView != _firstResponder && [_leftMouseDownView acceptsFirstResponder]) [self makeFirstResponder:_leftMouseDownView]; [CPApp activateIgnoringOtherApps:YES]; - var theWindow = [anEvent window]; + var theWindow = [anEvent window], + selector = type == CPRightMouseDown ? @selector(rightMouseDown:) : @selector(mouseDown:); if ([theWindow isKeyWindow] || [theWindow becomesKeyOnlyIfNeeded] && ![_leftMouseDownView needsPanelToBecomeKey]) - return [_leftMouseDownView mouseDown:anEvent]; + return [_leftMouseDownView performSelector:selector withObject:anEvent]; else { // FIXME: delayed ordering? [self makeKeyAndOrderFront:self]; if ([_leftMouseDownView acceptsFirstMouse:anEvent]) - return [_leftMouseDownView mouseDown:anEvent] + return [_leftMouseDownView performSelector:selector withObject:anEvent]; } break; - case CPLeftMouseDragged: if (!_leftMouseDownView) + + case CPLeftMouseDragged: + case CPRightMouseDragged: if (!_leftMouseDownView) return [[_windowView hitTest:point] mouseDragged:anEvent]; - return [_leftMouseDownView mouseDragged:anEvent]; - - case CPRightMouseUp: return [_rightMouseDownView mouseUp:anEvent]; - case CPRightMouseDown: _rightMouseDownView = [_windowView hitTest:point]; - return [_rightMouseDownView mouseDown:anEvent]; - case CPRightMouseDragged: return [_rightMouseDownView mouseDragged:anEvent]; - + var selector; + if (type == CPRightMouseDragged) + { + selector = @selector(rightMouseDragged:) + if (![_leftMouseDownView respondsToSelector:selector]) + selector = nil; + } + + if (!selector) + selector = @selector(mouseDragged:) + + return [_leftMouseDownView performSelector:selector withObject:anEvent]; + case CPMouseMoved: if (!_acceptsMouseMovedEvents) return; diff --git a/AppKit/Platform/CPPlatformWindow.j b/AppKit/Platform/CPPlatformWindow.j index 3f253aeac..4ebfa8f81 100644 --- a/AppKit/Platform/CPPlatformWindow.j +++ b/AppKit/Platform/CPPlatformWindow.j @@ -46,6 +46,7 @@ var PrimaryPlatformWindow = NULL; CPDictionary _windowLayers; BOOL _mouseIsDown; + BOOL _mouseDownIsRightClick; CPWindow _mouseDownWindow; CPTimeInterval _lastMouseUp; CPTimeInterval _lastMouseDown; diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index 2048a5ace..30f560581 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -127,7 +127,8 @@ var PlatformWindows = [CPSet set]; // Define up here so compressor knows about em. var CPDOMEventGetClickCount, CPDOMEventStop, - StopDOMEventPropagation; + StopDOMEventPropagation, + StopContextMenuDOMEventPropagation; var _DOMEventGuard; @@ -312,6 +313,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; mouseEventImplementation = class_getMethodImplementation(theClass, mouseEventSelector), mouseEventCallback = function (anEvent) { mouseEventImplementation(self, nil, anEvent); }, + contextMenuEventSelector = @selector(contextMenuEvent:), + contextMenuEventImplementation = class_getMethodImplementation(theClass, contextMenuEventSelector), + contextMenuEventCallback = function (anEvent) { return contextMenuEventImplementation(self, nil, anEvent); }, + scrollEventSelector = @selector(scrollEvent:), scrollEventImplementation = class_getMethodImplementation(theClass, scrollEventSelector), scrollEventCallback = function (anEvent) { scrollEventImplementation(self, nil, anEvent); }, @@ -335,6 +340,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; theDocument.addEventListener("mouseup", mouseEventCallback, NO); theDocument.addEventListener("mousedown", mouseEventCallback, NO); theDocument.addEventListener("mousemove", mouseEventCallback, NO); + theDocument.addEventListener("contextmenu", contextMenuEventCallback, NO); theDocument.addEventListener("beforecopy", copyEventCallback, NO); theDocument.addEventListener("beforecut", copyEventCallback, NO); @@ -362,6 +368,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; theDocument.removeEventListener("mouseup", mouseEventCallback, NO); theDocument.removeEventListener("mousedown", mouseEventCallback, NO); theDocument.removeEventListener("mousemove", mouseEventCallback, NO); + theDocument.removeEventListener("contextmenu", contextMenuEventCallback, NO); theDocument.removeEventListener("keyup", keyEventCallback, NO); theDocument.removeEventListener("keydown", keyEventCallback, NO); @@ -394,6 +401,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; theDocument.attachEvent("onmousedown", mouseEventCallback); theDocument.attachEvent("onmousemove", mouseEventCallback); theDocument.attachEvent("ondblclick", mouseEventCallback); + theDocument.attachEvent("oncontextmenu", contextMenuEventCallback); theDocument.attachEvent("onkeyup", keyEventCallback); theDocument.attachEvent("onkeydown", keyEventCallback); @@ -416,6 +424,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; theDocument.detachEvent("onmousedown", mouseEventCallback); theDocument.detachEvent("onmousemove", mouseEventCallback); theDocument.detachEvent("ondblclick", mouseEventCallback); + theDocument.detachEvent("oncontextmenu", contextMenuEventCallback); theDocument.detachEvent("onkeyup", keyEventCallback); theDocument.detachEvent("onkeydown", keyEventCallback); @@ -1046,11 +1055,12 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; { if(_mouseIsDown) { - event = _CPEventFromNativeMouseEvent(aDOMEvent, CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0); + event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseUp : CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0); _mouseIsDown = NO; _lastMouseUp = event; _mouseDownWindow = nil; + _mouseDownIsRightClick = NO; } if(_DOMEventMode) @@ -1090,8 +1100,13 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; _DOMBodyElement.style["-khtml-user-drag"] = "element"; } - event = _CPEventFromNativeMouseEvent(aDOMEvent, CPLeftMouseDown, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseDown, timestamp, location), 0); - + var button = aDOMEvent.button; + _mouseDownIsRightClick = button == 2 || (button == 0 && modifierFlags & CPControlKeyMask); + + StopContextMenuDOMEventPropagation = YES; + + event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseDown : CPLeftMouseDown, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseDown, timestamp, location), 0); + _mouseIsDown = YES; _lastMouseDown = event; } @@ -1101,7 +1116,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (_DOMEventMode) return; - event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseIsDown ? CPLeftMouseDragged : CPMouseMoved, location, modifierFlags, timestamp, windowNumber, nil, -1, 1, 0); + event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseIsDown ? (_mouseDownIsRightClick ? CPRightMouseDragged : CPLeftMouseDragged) : CPMouseMoved, location, modifierFlags, timestamp, windowNumber, nil, -1, 1, 0); } var isDragging = [[CPDragServer sharedDragServer] isDragging]; @@ -1122,6 +1137,14 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; } +- (void)contextMenuEvent:(DOMEvent)aDOMEvent +{ + if (StopContextMenuDOMEventPropagation) + CPDOMEventStop(aDOMEvent, self); + + return !StopContextMenuDOMEventPropagation; +} + - (CPArray)orderedWindowsAtLevel:(int)aLevel { var layer = [self layerAtLevel:aLevel create:NO]; @@ -1263,6 +1286,19 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; return !StopDOMEventPropagation; } +- (void)_propagateContextMenuDOMEvent:(BOOL)aFlag +{ + if (aFlag && CPBrowserIsEngine(CPGeckoBrowserEngine)) + StopDOMEventPropagation = !aFlag; + + StopContextMenuDOMEventPropagation = !aFlag; +} + +- (BOOL)_willPropagateContextMenuDOMEvent +{ + return StopContextMenuDOMEventPropagation; +} + - (CPWindow)hitTest:(CPPoint)location { if (self._only)