Index: chimera/src/application/MainController.mm =================================================================== RCS file: /cvsroot/mozilla/chimera/src/application/MainController.mm,v retrieving revision 1.59.2.48 diff -U5 -r1.59.2.48 MainController.mm --- chimera/src/application/MainController.mm 6 Feb 2003 02:58:03 -0000 1.59.2.48 +++ chimera/src/application/MainController.mm 21 Feb 2003 20:09:34 -0000 @@ -260,10 +260,14 @@ } // load up the charset dictionary with keys and menu titles. NSString* charsetPath = [NSBundle pathForResource:@"Charset" ofType:@"dict" inDirectory:[[NSBundle mainBundle] bundlePath]]; mCharsets = [[NSDictionary dictionaryWithContentsOfFile:charsetPath] retain]; + + // Force use of vector fonts at all sizes + SetOutlinePreferred( true ); + printf("SIMON: MainController: init: SetOutlinePreferred done.\n"); } - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { return [[ProgressDlgController sharedDownloadController] allowTerminate]; Index: widget/src/cocoa/nsChildView.h =================================================================== RCS file: /cvsroot/mozilla/widget/src/cocoa/nsChildView.h,v retrieving revision 1.12.2.1.16.5 diff -U5 -r1.12.2.1.16.5 nsChildView.h --- widget/src/cocoa/nsChildView.h 26 Nov 2002 03:19:30 -0000 1.12.2.1.16.5 +++ widget/src/cocoa/nsChildView.h 21 Feb 2003 20:12:38 -0000 @@ -42,10 +42,11 @@ #include "nsISupports.h" #include "nsBaseWidget.h" #include "nsIPluginWidget.h" #include "nsDeleteObserver.h" #include "nsIEventSink.h" +#include "nsIScrollableView.h" #include "nsIWidget.h" #include "nsIKBStateControl.h" #include "nsIAppShell.h" @@ -91,10 +92,24 @@ // needed for NSTextInput implementation NSRange mMarkedRange; NSRange mSelectedRange; BOOL mInComposition; + + BOOL mInHandScroll; // true for as long as we are hand scrolling + + // hand scroll locations + NSPoint mHandScrollStartMouseLoc; + nscoord mHandScrollStartScrollX, mHandScrollStartScrollY; + + nsIScrollableView* mScrollableView; // related gecko scrollable view + + // Click/Hold context menu + NSTimer * clickHoldTimer; + NSMethodSignature * sig; //needed for timer + NSInvocation * invoc; //needed for timer + BOOL inClickHoldMenu; //true when the click/hold menu is visible } @end @@ -289,11 +304,12 @@ PRPackedBool mLiveResizeInProgress; PRPackedBool mPluginDrawing; nsPluginPort* mPluginPort; RgnHandle mVisRgn; - + float mTwipsToPixels; + float mPixelsToTwips; }; #if DEBUG #define WIDGET_SET_CLASSNAME(n) gInstanceClassName = (n) Index: widget/src/cocoa/nsChildView.mm =================================================================== RCS file: /cvsroot/mozilla/widget/src/cocoa/nsChildView.mm,v retrieving revision 1.33.2.1.16.22 diff -U5 -r1.33.2.1.16.22 nsChildView.mm --- widget/src/cocoa/nsChildView.mm 29 Jan 2003 00:57:44 -0000 1.33.2.1.16.22 +++ widget/src/cocoa/nsChildView.mm 21 Feb 2003 20:12:46 -0000 @@ -52,10 +52,11 @@ #include "nsplugindefs.h" #include "nsMacResources.h" #include "nsRegionMac.h" #include "nsIRollupListener.h" #include "nsIEventSink.h" +#include "nsIScrollableView.h" #include "nsCarbonHelpers.h" #include "nsGfxUtils.h" #if PINK_PROFILING @@ -322,11 +323,17 @@ nsWidgetInitData *aInitData, nsNativeWidget aNativeParent) { mBounds = aRect; -// CalcWindowRegions(); + mContext = aContext; + if (mContext) { + mContext->GetAppUnitsToDevUnits(mTwipsToPixels); + mContext->GetDevUnitsToAppUnits(mPixelsToTwips); + } + + // CalcWindowRegions(); BaseCreate(aParent, aRect, aHandleEventFunction, aContext, aAppShell, aToolkit, aInitData); // inherit things from the parent view and create our parallel @@ -2276,10 +2283,12 @@ mMarkedRange.length = 0; mSelectedRange.location = NSNotFound; mSelectedRange.length = 0; mInComposition = NO; + inClickHoldMenu = NO; + return self; } - (NSWindow*) getNativeWindow { @@ -2300,20 +2309,78 @@ [super dealloc]; // this sets the current port to _savePort SetPort(NULL); // this is safe on OS X; it will set the port to // an empty fallback port. } +// set the closed hand cursor and record the starting scroll positions +- (void) startHandScroll:(NSEvent*)theEvent +{ + mHandScrollStartMouseLoc = [[self window] convertBaseToScreen: [theEvent locationInWindow]]; + + // we have to loop up through superviews in case the view that received the + // mouseDown is in fact a plugin view with no scrollbars + ChildView* currView = self; + while (!mScrollableView && currView && + [currView isMemberOfClass:[ChildView class]]) { + + // This is a hack I learned in nsView::GetViewFor(nsIWidget* aWidget) + // that I'm not sure is kosher. If anyone knows a better way to get + // the view for a widget, I'd love to hear it. --Nathan + + void* clientData; + [currView widget]->GetClientData(clientData); + + nsISupports* data = (nsISupports*)clientData; + data->QueryInterface(NS_GET_IID(nsIScrollableView), (void **)&mScrollableView); + + currView = [currView superview]; + } + + // if we succeeded in getting the mScrollableView + if (mScrollableView) { + mScrollableView->GetScrollPosition(mHandScrollStartScrollX, mHandScrollStartScrollY); + mGeckoChild->SetCursor(eCursor_grabbing); + mInHandScroll = TRUE; + } +} +// update the scroll position based on the new mouse coordinates +- (void) updateHandScroll:(NSEvent*)theEvent { + NSPoint newMouseLoc = [[self window] convertBaseToScreen: [theEvent locationInWindow]]; + + PRInt32 deltaX = (PRInt32)(mHandScrollStartMouseLoc.x - newMouseLoc.x); + PRInt32 deltaY = (PRInt32)(newMouseLoc.y - mHandScrollStartMouseLoc.y); + + // convert to the nsIView coordinates + nscoord newX = mHandScrollStartScrollX + + NSIntPixelsToTwips(deltaX, mGeckoChild->mPixelsToTwips); + nscoord newY = mHandScrollStartScrollY + + NSIntPixelsToTwips(deltaY, mGeckoChild->mPixelsToTwips); + mScrollableView->ScrollTo(newX, newY, NS_VMREFRESH_IMMEDIATE); +} + +// reset the scrool flag and cursor +- (void) stopHandScroll:(NSEvent*)theEvent { + mInHandScroll = FALSE; + + // calling flagsChanged will set the cursor appropriately + [self flagsChanged:theEvent]; +} // // -setFrame // // Override in order to keep our mouse enter/exit tracking rect in sync with // the frame of the view // - (void)setFrame:(NSRect)frameRect { [super setFrame:frameRect]; + if (mMouseEnterExitTag) + [self removeTrackingRect:mMouseEnterExitTag]; + + mMouseEnterExitTag = [self addTrackingRect:[self bounds] owner:self + userData:nil assumeInside: YES]; } // // -isFlipped @@ -2372,16 +2439,21 @@ - (void)viewWillMoveToWindow:(NSWindow *)newWindow { if (mGeckoChild && !newWindow) mGeckoChild->RemovedFromWindow(); + if (mMouseEnterExitTag) + [self removeTrackingRect:mMouseEnterExitTag]; } - (void)viewDidMoveToWindow { if (mGeckoChild && [self window]) mGeckoChild->AddedToWindow(); + + mMouseEnterExitTag = [self addTrackingRect:[self bounds] owner:self + userData:nil assumeInside: YES]; } - (void)viewWillStartLiveResize { if (mGeckoChild && mIsPluginView) @@ -2418,12 +2490,66 @@ ConvertCocoaToGeckoRect(aRect, r); nsCOMPtr rendContext = getter_AddRefs(mGeckoChild->GetRenderingContext()); mGeckoChild->UpdateWidget(r, rendContext); } +#pragma mark - + +// Method called by the Click/Hold Timer +// Spoof a NSRightMouseDown message to make chimera think that +// the right mouse button was clicked, thus creating a context +// menu. +- (void)clickHoldTimerFired:(id)theEvent; +{ + NSBeep(); + clickHoldTimer = nil; // memleak? + NSEvent * newEvent = [NSEvent mouseEventWithType:NSRightMouseDown + location:[theEvent locationInWindow] + modifierFlags:[theEvent modifierFlags] + timestamp:[theEvent timestamp] + windowNumber:[theEvent windowNumber] + context:[theEvent context] + eventNumber:[theEvent eventNumber] + clickCount:[theEvent clickCount] + pressure:[theEvent pressure]]; + printf("SIMON: clickHoldTimerFired\n"); + inClickHoldMenu = YES; // needed to handle drags + [self rightMouseDown:newEvent]; // should trigger popup menu +} + - (void)mouseDown:(NSEvent *)theEvent { + // if the command and alt keys are held down, initiate hand scrolling + if ([theEvent modifierFlags] == (NSCommandKeyMask | NSAlternateKeyMask)) { + [self startHandScroll: theEvent]; + return; // do not pass this mousedown event to gecko + } + // initiate click/hold handling + if( clickHoldTimer ) { + // first make sure there's not a timer hanging around due to some mishap + printf("SIMON: mouseDown: invalidate\n"); + [clickHoldTimer invalidate]; + clickHoldTimer = nil; + } + inClickHoldMenu = NO; // true when the click/hold (context) menu is visible + SEL sel = @selector(clickHoldTimerFired:); + if( [self respondsToSelector:sel] ) + { + // Create a timer. If the timer fires before it gets invalidated, + // the user is clicking and holding. + sig = [[self methodSignatureForSelector:sel] retain]; + invoc = [[NSInvocation invocationWithMethodSignature:sig] retain]; + [invoc setSelector:sel]; + [invoc setTarget:self]; + [invoc setArgument:&theEvent atIndex:2]; //maybe need to retain theEvent first + clickHoldTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 + invocation:invoc + repeats:NO]; + } else { + printf("Chimera: nsChildView: mouseDown: Self doesn't respond to clickHoldTimerFired!!!!\n"); // should never happen + } + nsMouseEvent geckoEvent; geckoEvent.eventStructType = NS_MOUSE_EVENT; geckoEvent.nativeMsg = nsnull; [self convert:theEvent message:NS_MOUSE_LEFT_BUTTON_DOWN toGeckoEvent:&geckoEvent]; geckoEvent.clickCount = [theEvent clickCount]; @@ -2447,10 +2573,36 @@ } // mouseDown - (void)mouseUp:(NSEvent *)theEvent { + if (mInHandScroll) { + [self updateHandScroll:theEvent]; + [self stopHandScroll:theEvent]; + return; + } + // invalidate any Click/Hold timer that may be hanging around + if( clickHoldTimer ) { + printf("SIMON: mouseUp: invalidate\n"); + [clickHoldTimer invalidate]; + clickHoldTimer = nil; + } + // If we've created a Click/Hold menu, morph this into an NSRightMouseUp + if( inClickHoldMenu ) { + NSEvent * newEvent = [NSEvent mouseEventWithType:NSRightMouseUp + location:[theEvent locationInWindow] + modifierFlags:[theEvent modifierFlags] + timestamp:[theEvent timestamp] + windowNumber:[theEvent windowNumber] + context:[theEvent context] + eventNumber:[theEvent eventNumber] + clickCount:[theEvent clickCount] + pressure:[theEvent pressure]]; + inClickHoldMenu = NO; + [self rightMouseUp:newEvent]; + return; // and stop ;-) + } nsMouseEvent geckoEvent; geckoEvent.eventStructType = NS_MOUSE_EVENT; geckoEvent.nativeMsg = nsnull; [self convert:theEvent message:NS_MOUSE_LEFT_BUTTON_UP toGeckoEvent:&geckoEvent]; @@ -2478,11 +2630,16 @@ if (view != (NSView*)self) { // We shouldn't handle this. Send it to the right view. [view mouseMoved: theEvent]; return; } - + // check if we are in a hand scroll or if the user + // has command and alt held down; if so, we do not want + // gecko messing with the cursor. + if ([theEvent modifierFlags] == (NSCommandKeyMask | NSAlternateKeyMask)) { + return; + } nsMouseEvent geckoEvent; geckoEvent.eventStructType = NS_MOUSE_EVENT; geckoEvent.nativeMsg = nsnull; [self convert:theEvent message:NS_MOUSE_MOVE toGeckoEvent:&geckoEvent]; @@ -2503,10 +2660,22 @@ mGeckoChild->DispatchMouseEvent(geckoEvent); } - (void)mouseDragged:(NSEvent*)theEvent { + // if the handscroll flag is set, steal this event + if (mInHandScroll) { + [self updateHandScroll:theEvent]; + return; + } + // invalidate any Click/Hold timer that may be hanging around + if( clickHoldTimer ) { + printf("SIMON: mouseDragged: invalidate\n"); + [clickHoldTimer invalidate]; + clickHoldTimer = nil; //memleak? + printf("SIMON: mouseDragged: invalidate done.\n"); + } nsMouseEvent geckoEvent; geckoEvent.eventStructType = NS_MOUSE_EVENT; geckoEvent.nativeMsg = nsnull; [self convert:theEvent message:NS_MOUSE_MOVE toGeckoEvent:&geckoEvent]; @@ -2524,20 +2693,23 @@ mGeckoChild->DispatchMouseEvent(geckoEvent); } - (void)mouseEntered:(NSEvent*)theEvent { - // printf("got mouse ENTERED view\n"); + // checks to see if we should change to the hand cursor + [self flagsChanged:theEvent]; } - (void)mouseExited:(NSEvent*)theEvent { - // printf("got mouse EXIT view\n"); + // checks to see if we should change from the hand cursor + [self flagsChanged:theEvent]; } - (void)rightMouseDown:(NSEvent *)theEvent { + NSBeep(); // The right mouse went down. Fire off a right mouse down and // then send the context menu event. nsMouseEvent geckoEvent; geckoEvent.eventStructType = NS_MOUSE_EVENT; geckoEvent.nativeMsg = nsnull; @@ -2559,10 +2731,15 @@ [super rightMouseDown:theEvent]; // let the superview do context menu stuff } - (void)rightMouseUp:(NSEvent *)theEvent { + // if the command and alt keys are held down, initiate hand scrolling + if ([theEvent modifierFlags] == (NSCommandKeyMask | NSAlternateKeyMask)) { + [self startHandScroll: theEvent]; + return; // do not pass this mousedown event to gecko + } nsMouseEvent geckoEvent; geckoEvent.eventStructType = NS_MOUSE_EVENT; geckoEvent.nativeMsg = nsnull; [self convert: theEvent message: NS_MOUSE_RIGHT_BUTTON_UP toGeckoEvent:&geckoEvent]; @@ -2582,10 +2759,15 @@ [super rightMouseUp:theEvent]; } - (void)otherMouseDown:(NSEvent *)theEvent { + if (mInHandScroll) { + [self updateHandScroll:theEvent]; + [self stopHandScroll:theEvent]; + return; + } nsMouseEvent geckoEvent; geckoEvent.eventStructType = NS_MOUSE_EVENT; geckoEvent.nativeMsg = nsnull; [self convert:theEvent message:NS_MOUSE_MIDDLE_BUTTON_DOWN toGeckoEvent:&geckoEvent]; geckoEvent.clickCount = [theEvent clickCount]; @@ -2649,10 +2831,12 @@ // send event into Gecko by going directly to the // the widget. mGeckoChild->DispatchWindowEvent(geckoEvent); } +#pragma mark - + // // -convert:message:toGeckoEvent: // // convert from one event system to the other for event dispatching // @@ -3187,10 +3371,36 @@ EventRecord macEvent; ConvertCocoaKeyEventToMacEvent(theEvent, macEvent); geckoEvent.nativeMsg = &macEvent; mGeckoChild->DispatchWindowEvent(geckoEvent); +} + +// look for the user's pressing of command and alt so that we can display +// the hand scroll cursor +- (void)flagsChanged:(NSEvent*)theEvent +{ + BOOL inMouseView = NO; + // check to see if the user has command and alt held down; if so, + // find out if the cursor is in an ChildView + if ([theEvent modifierFlags] == (NSCommandKeyMask | NSAlternateKeyMask)) { + NSPoint pointInWindow = [[self window] mouseLocationOutsideOfEventStream]; + + NSView* mouseView = [[[self window] contentView] hitTest:pointInWindow]; + inMouseView = (mouseView != nil && [mouseView isMemberOfClass:[ChildView class]]); + } + if (inMouseView) { + mGeckoChild->SetCursor(eCursor_grab); + } else { + nsCursor cursor = mGeckoChild->GetCursor(); + if (!mInHandScroll) { + if (cursor == eCursor_grab || cursor == eCursor_grabbing) + mGeckoChild->SetCursor(eCursor_standard); + // pass on the event since we are not using it + [super flagsChanged:theEvent]; + } + } } // This method is called when we are about to be focused. - (BOOL)becomeFirstResponder {