Adium

Changeset 21764

Show
Ignore:
Timestamp:
12/01/2007 01:07:31 AM (1 year ago)
Author:
boredzo
Message:

Burninated the Carbon Event implementation of AISmoothTooltipTracker, because it didn't work. We now use NSTrackingArea instead. Refs #1156.

Next will be a Tiger-compatible substitute, which I've (creatively) named AITrackingArea. We'll use this until either we drop Tiger and go Leopard-only or we find a bug in NSTrackingArea that we can't work around.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/tooltip-fixes/Frameworks/AIUtilities Framework/Source/AISmoothTooltipTracker.h

    r21762 r21764  
    4646 
    4747        NSPoint                         lastMouseLocation;                              //Last known location of the mouse, used for movement tracking 
    48         NSTimer                         *tooltipMouseLocationTimer;             //Checks for mouse movement 
    4948        NSPoint                         tooltipLocation;                                //Last tooltip location we told our delegate about 
    50     NSTrackingRectTag  tooltipTrackingTag;                             //Tag for our tracking rec
     49    NSTrackingArea             *trackingArea;                                  //Tracking area to watch the view for mouse entry, movement, and exi
    5150    NSTimer                             *tooltipDelayTimer;                             //Used to determine how long before a tooltip appears 
    52  
    53         void                            *mouseMovedHandlerUPP;                  //By void *, I mean EventHandlerUPP. 
    54         void                            *mouseMovedHandler;                             //Carbon Event handler for mouse-moved events; only exists during tracking. By void *, I mean EventHandlerRef. 
    5551} 
    5652 
  • branches/tooltip-fixes/Frameworks/AIUtilities Framework/Source/AISmoothTooltipTracker.m

    r21763 r21764  
    2727- (void)resetCursorTracking; 
    2828 
    29 - (void)_startTrackingMouse; 
    30 - (void)_stopTrackingMouse; 
    3129- (void)_hideTooltip; 
    3230 
    33 //10.4: We use these to access our instance variables from the Carbon Event handler without making them @public. When we switch to NSTrackingArea, they should go away along with the handler. 
    34 - (void)getPrivateVariablesTooltipDelayTimer:(out NSTimer **)outTooltipDelayTimer 
    35                                                    lastMouseLocation:(out NSPoint *)outLastMouseLocation 
    36                                                          tooltipLocation:(out NSPoint *)outTooltipLocation 
    37                                                                         delegate:(out id *)outDelegate; 
    38 - (void)setPrivateVariablesLastMouseLocation:(NSPoint)newLastMouseLocation 
    39                                                          tooltipLocation:(NSPoint)newTooltipLocation 
    40                                                                         delegate:(id)newDelegate; 
     31- (void)mouseEntered:(NSEvent *)event; 
     32- (void)mouseMoved:(NSEvent *)event; 
     33- (void)mouseExited:(NSEvent *)event; 
     34 
    4135@end 
    42  
    43 //10.4: This handler responds to kEventMouseMoved. For Leopard-only, switch to NSTrackingArea. 
    44 static OSStatus handleMouseMovedCarbonEvent(EventHandlerCallRef nextHandler, EventRef event, void *refcon); 
    4536 
    4637@implementation AISmoothTooltipTracker 
     
    5647                view = [inView retain]; 
    5748                delegate = inDelegate; 
    58                 tooltipTrackingTag = -1; 
    5949                tooltipLocation = NSZeroPoint; 
    6050 
     
    7060 
    7161                [self installCursorRect]; 
    72  
    73                 mouseMovedHandlerUPP = NewEventHandlerUPP(handleMouseMovedCarbonEvent); 
    7462        } 
    7563 
     
    8371#endif 
    8472 
    85         RemoveEventHandler(mouseMovedHandler); 
    86         DisposeEventHandlerUPP(mouseMovedHandlerUPP); 
    87  
    8873        [[NSNotificationCenter defaultCenter] removeObserver:self]; 
    8974 
    9075        [self removeCursorRect]; 
    91         [self _stopTrackingMouse]; 
    9276 
    9377        [view release]; view = nil; 
     
    9983{ 
    10084        if (delegate != inDelegate) { 
    101                 [self _stopTrackingMouse]; 
    102  
    10385                delegate = inDelegate; 
    10486        } 
     
    122104 
    123105        [self removeCursorRect]; 
    124         [self _stopTrackingMouse]; 
    125106} 
    126107 
     
    143124- (void)installCursorRect 
    144125{ 
    145         if (tooltipTrackingTag == -1) { 
     126        if (!trackingArea) { 
    146127                NSRect                  trackingRect; 
     128                NSPoint                 mouseLocation = [[view window] mouseLocationOutsideOfEventStream]; 
    147129                BOOL                    mouseInside; 
    148130 
     
    151133                trackingRect.origin = NSMakePoint(0,0); 
    152134 
    153                 mouseInside = NSPointInRect([view convertPoint:[[view window] mouseLocationOutsideOfEventStream] fromView:[[view window] contentView]], 
     135                mouseInside = NSPointInRect([view convertPoint:mouseLocation fromView:[[view window] contentView]], 
    154136                                                                        trackingRect); 
     137 
     138                trackingArea = [[NSTrackingArea alloc] initWithRect:trackingRect 
     139                                                                                                        options:(NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved) | NSTrackingActiveAlways | NSTrackingInVisibleRect 
     140                                                                                                          owner:self 
     141                                                                                                   userInfo:nil]; 
     142                [view addTrackingArea:trackingArea]; 
     143 
    155144#if LOG_TRACKING_INFO 
    156145                NSLog(@"%s: mouse location: %@; trackingRect: %@; mouseInside: %@", __PRETTY_FUNCTION__, NSStringFromPoint([view convertPoint:[[view window] mouseLocationOutsideOfEventStream] fromView:[[view window] contentView]]), NSStringFromRect(trackingRect), mouseInside ? @"YES" : @"NO"); 
    157146#endif 
    158                 tooltipTrackingTag = [view addTrackingRect:trackingRect owner:self userData:nil assumeInside:mouseInside]; 
    159  
    160 #if LOG_TRACKING_INFO 
    161                 NSLog(@"[%@ installCursorRect] addTrackingRect %@ on %@ in %@: tag = %i",self,NSStringFromRect(trackingRect),view,[view window],tooltipTrackingTag); 
    162 #endif 
    163                 //If the mouse is already inside, begin tracking the mouse immediately 
    164                 if ([[view window] isVisible] && mouseInside) [self _startTrackingMouse]; 
     147 
     148                //If the mouse is already inside, NSTrackingArea won't send us a mouse-entered event, so we need to forge one. 
     149                if ([[view window] isVisible] && mouseInside) { 
     150                        struct UnsignedWide microsecondsSinceStartup; 
     151                        Microseconds(&microsecondsSinceStartup); 
     152                         
     153                        NSEvent *event = [NSEvent mouseEventWithType:NSMouseEntered 
     154                                                                                                location:mouseLocation 
     155                                                                                   modifierFlags:0 
     156                                                                                           timestamp:UnsignedWideToUInt64(microsecondsSinceStartup) 
     157                                                                                        windowNumber:[[view window] windowNumber] 
     158                                                                                                 context:[NSGraphicsContext currentContext] 
     159                                                                                         eventNumber:0 
     160                                                                                          clickCount:0 
     161                                                                                                pressure:0.0f]; 
     162                        [self mouseEntered:event]; 
     163                } 
    165164        } 
    166165} 
     
    170169{ 
    171170#if LOG_TRACKING_INFO 
    172         if (tooltipTrackingTag != -1) { 
    173                 NSLog(@"[%@ removeCursorRect] Remove rect from %@ in %@ : tag = %i",self,view,[view window],tooltipTrackingTag); 
     171        if (trackingArea) { 
     172                NSLog(@"[%@ removeCursorRect] Remove rect from %@ in %@ : tracking area = %i",self,view,[view window], trackingArea); 
    174173        } else { 
    175174                NSLog(@"[%@ removeCursorRect] No rect to remove",self); 
     
    177176#endif 
    178177 
    179         if (tooltipTrackingTag != -1) { 
    180                 [view removeTrackingRect:tooltipTrackingTag]; 
    181                 tooltipTrackingTag = -1; 
    182                 [self _stopTrackingMouse]; 
     178        if (trackingArea) { 
     179                [view removeTrackingArea:trackingArea]; 
     180                trackingArea = nil; 
    183181        } 
    184182} 
     
    201199// - mouseMoved: events do not work when Adium is in the background 
    202200#pragma mark Tooltips (Cursor movement) 
    203 //Mouse entered our list, begin tracking it's movement 
     201 
     202//Mouse entered our list. Start the delay timer that will show the tooltip. 
    204203- (void)mouseEntered:(NSEvent *)theEvent 
    205204{ 
     
    207206        NSLog(@"+++ [%@: mouseEntered]", self); 
    208207#endif 
    209         [self _startTrackingMouse]; 
    210 
    211  
    212 //Mouse left our list, cease tracking 
    213 - (void)mouseExited:(NSEvent *)theEvent 
    214 
    215 #if LOG_TRACKING_INFO 
    216         NSLog(@"--- [%@: mouseExited]", self); 
    217 #endif 
    218         [self _stopTrackingMouse]; 
    219 
    220  
    221 //Start tracking mouse movement 
    222 - (void)_startTrackingMouse 
    223 
    224 #if LOG_TRACKING_INFO 
    225         NSLog(@"%s called; mouseMovedHandler is %p", __PRETTY_FUNCTION__, mouseMovedHandler); 
    226 #endif 
    227  
    228         if (!mouseMovedHandler) { 
    229                 enum { numTypeSpecs = 1 }; 
    230                 struct EventTypeSpec typeSpecs[numTypeSpecs] = { 
    231                         { kEventClassMouse, kEventMouseMoved } 
    232                 }; 
    233                 WindowRef theWindow = [[view window] windowRef]; 
    234  
    235                 OSStatus err = InstallWindowEventHandler(theWindow, mouseMovedHandlerUPP, numTypeSpecs, typeSpecs, /*refcon*/ (void *)self, (EventHandlerRef *)&mouseMovedHandler); 
    236                 NSAssert3(err == noErr, @"%s: InstallWindowEventHandler returned %i (%s)", __PRETTY_FUNCTION__, err, GetMacOSStatusCommentString(err)); 
    237 #if LOG_TRACKING_INFO 
    238                 NSLog(@"%s: Installed window event handler on %p (%p)", __PRETTY_FUNCTION__, theWindow, [[view window] windowRef]); 
    239 #endif 
    240  
    241                 NSValue *initialMouseLocation = [NSValue valueWithPoint:[NSEvent mouseLocation]]; 
    242                 tooltipDelayTimer = [[NSTimer scheduledTimerWithTimeInterval:TOOL_TIP_DELAY 
    243                                                                                                                           target:self 
    244                                                                                                                         selector:@selector(delayedShowTooltip:) 
    245                                                                                                                         userInfo:[NSMutableDictionary dictionaryWithObject:initialMouseLocation forKey:MOUSE_LOCATION_KEY] 
    246                                                                                                                          repeats:NO] retain]; 
    247 #if LOG_TRACKING_INFO 
    248                 NSLog(@"%s: Scheduled timer %@ for %f seconds from now", __PRETTY_FUNCTION__, tooltipDelayTimer, TOOL_TIP_DELAY); 
    249 #endif 
    250         } 
    251 
    252  
    253 //Stop tracking mouse movement 
    254 - (void)_stopTrackingMouse 
    255 
    256 #if LOG_TRACKING_INFO 
    257         NSLog(@"%s called; mouseMovedHandler is %p", __PRETTY_FUNCTION__, mouseMovedHandler); 
    258 #endif 
    259  
    260         //Invalidate tracking 
    261         if (mouseMovedHandler) { 
    262 #if LOG_TRACKING_INFO 
    263                 NSLog(@"%s: Hiding tooltip! delegate is %@", __PRETTY_FUNCTION__, delegate); 
    264 #endif 
    265                 //Hide the tooltip before releasing the timer, as the timer may be the last object retaining self 
    266                 //and we want to communicate with the delegate before a potential call to dealloc. 
    267                 [self _hideTooltip]; 
    268  
    269 #if LOG_TRACKING_INFO 
    270                 NSLog(@"%s: Removing event handler!", __PRETTY_FUNCTION__); 
    271 #endif 
    272                 RemoveEventHandler((EventHandlerRef)mouseMovedHandler); 
    273  
    274 #if LOG_TRACKING_INFO 
    275                 NSLog(@"%s: Invalidating and releasing tooltip delay timer %@!", __PRETTY_FUNCTION__, tooltipDelayTimer); 
    276 #endif 
    277                 [tooltipDelayTimer invalidate]; 
    278                 [tooltipDelayTimer release]; 
    279                 tooltipDelayTimer = nil; 
    280  
    281 #if LOG_TRACKING_INFO 
    282                 NSLog(@"%s: Using up surplus exclamation marks!", __PRETTY_FUNCTION__); 
    283 #endif 
    284         } 
    285 
    286  
    287 - (void)delayedShowTooltip:(NSTimer *)timer 
    288 
    289 #if LOG_TRACKING_INFO 
    290         NSLog(@"%s: Timer fired! Showing tooltip at %@", __PRETTY_FUNCTION__, NSStringFromPoint([[[timer userInfo] objectForKey:MOUSE_LOCATION_KEY] pointValue])); 
    291 #endif 
    292         [delegate showTooltipAtPoint:[[[timer userInfo] objectForKey:MOUSE_LOCATION_KEY] pointValue]]; 
    293  
    294         /* 
    295 #if LOG_TRACKING_INFO 
    296         NSLog(@"%s: Removing event handler %p", __PRETTY_FUNCTION__, mouseMovedHandler); 
    297 #endif 
    298         RemoveEventHandler((EventHandlerRef)mouseMovedHandler); 
    299          */ 
    300  
    301 #if LOG_TRACKING_INFO 
    302         NSLog(@"%s: Invalidating and releasing timer %@", __PRETTY_FUNCTION__, tooltipDelayTimer); 
    303 #endif 
    304         [tooltipDelayTimer invalidate]; 
    305         [tooltipDelayTimer release]; 
    306         tooltipDelayTimer = nil; 
    307 
    308  
    309 - (void)_hideTooltip 
    310 
    311 #if LOG_TRACKING_INFO 
    312         NSLog(@"%s: tooltipLocation is %@; delegate is %@", __PRETTY_FUNCTION__, NSStringFromPoint(tooltipLocation), delegate); 
    313 #endif 
    314         //If the tooltip was being shown before, hide it 
    315         if (!NSEqualPoints(tooltipLocation,NSZeroPoint)) { 
    316                 lastMouseLocation = NSZeroPoint; 
    317                 tooltipLocation = NSZeroPoint; 
    318  
    319                 //Hide tooltip 
    320                 [delegate hideTooltip]; 
    321         } 
    322 
    323  
    324 - (void)getPrivateVariablesTooltipDelayTimer:(out NSTimer **)outTooltipDelayTimer 
    325                                                    lastMouseLocation:(out NSPoint *)outLastMouseLocation 
    326                                                          tooltipLocation:(out NSPoint *)outTooltipLocation 
    327                                                                         delegate:(out id *)outDelegate 
    328 
    329         if (outTooltipDelayTimer) *outTooltipDelayTimer = tooltipDelayTimer; 
    330         if (outLastMouseLocation) *outLastMouseLocation = lastMouseLocation; 
    331         if (outTooltipLocation)   *outTooltipLocation   = tooltipLocation; 
    332         if (outDelegate)          *outDelegate          = delegate; 
    333 
    334 - (void)setPrivateVariablesLastMouseLocation:(NSPoint)newLastMouseLocation 
    335                                                          tooltipLocation:(NSPoint)newTooltipLocation 
    336                                                                         delegate:(id)newDelegate 
    337 
    338         lastMouseLocation = newLastMouseLocation; 
    339         tooltipLocation = newTooltipLocation; 
    340         delegate = newDelegate; 
    341 
    342  
    343 @end 
    344  
    345 static OSStatus handleMouseMovedCarbonEvent(EventHandlerCallRef nextHandler, EventRef event, void *refcon) { 
    346 #if LOG_TRACKING_INFO 
    347         NSLog(@"%s called!", __PRETTY_FUNCTION__); 
    348 #endif 
    349         OSStatus err; 
    350  
    351         AISmoothTooltipTracker *self = (id)refcon; 
    352         NSView *view = [self view]; 
    353         NSWindow *theWindow = [view window]; 
    354  
    355         id delegate; 
    356     NSTimer *tooltipDelayTimer; 
    357         NSPoint lastMouseLocation; 
    358         NSPoint tooltipLocation; 
    359         [self getPrivateVariablesTooltipDelayTimer:&tooltipDelayTimer 
    360                                                          lastMouseLocation:&lastMouseLocation 
    361                                                            tooltipLocation:&tooltipLocation 
    362                                                                           delegate:&delegate]; 
    363  
    364         //Check whether kEventParamWindowRef is the window we're tracking. 
    365         WindowRef eventWindow = NULL; 
    366         err = GetEventParameter(event, kEventParamWindowRef, typeWindowRef, /*outActualType*/ NULL, sizeof(eventWindow), /*outActualSize*/ NULL, &eventWindow); 
    367 #if LOG_TRACKING_INFO 
    368         NSLog(@"%s: GetEventParameter, for kEventParamWindowRef, returned window %p and error %i (%s)", __PRETTY_FUNCTION__, eventWindow, err, GetMacOSStatusCommentString(err)); 
    369 #endif 
    370         NSCAssert3(err == noErr, @"%s: GetEventParameter, retrieving kEventParamWindowRef, returned error %i (%s)", __PRETTY_FUNCTION__, err, GetMacOSStatusCommentString(err)); 
    371         if (eventWindow != [theWindow windowRef]) { 
    372                 return eventNotHandledErr; 
    373         } 
    374  
    375         //Check whether kEventParamWindowMouseLocation is within the frame of the view we're tracking. 
    376         HIPoint mouseLocationInWindow; 
    377         err = GetEventParameter(event, kEventParamWindowMouseLocation, typeHIPoint, /*outActualType*/ NULL, sizeof(mouseLocationInWindow), /*outActualSize*/ NULL, &mouseLocationInWindow); 
    378 #if LOG_TRACKING_INFO 
    379         NSLog(@"%s: GetEventParameter, for kEventParamWindowMouseLocation, returned point %@ and error %i (%s)", __PRETTY_FUNCTION__, NSStringFromPoint(NSPointFromCGPoint(mouseLocationInWindow)), err, GetMacOSStatusCommentString(err)); 
    380 #endif 
    381         NSCAssert3(err == noErr, @"%s: GetEventParameter, retrieving kEventParamWindowMouseLocation, returned error %i (%s)", __PRETTY_FUNCTION__, err, GetMacOSStatusCommentString(err)); 
    382  
    383         //Convert from HIToolbox's top-left origin to Cocoa's bottom-left origin. 
    384         NSPoint mouseLocation = { mouseLocationInWindow.x, (mouseLocationInWindow.y + [theWindow frame].size.height) * -1.0 }; 
    385  
    386 #if LOG_TRACKING_INFO 
    387         NSLog(@"%@: Visible: %i ; Point %@ in %@ = %i", self, 
    388                   [theWindow isVisible], 
    389                   NSStringFromPoint(mouseLocation), 
    390                   NSStringFromRect([view frame]), 
    391                   NSPointInRect(mouseLocation, [view frame])); 
    392 #endif 
    393  
     208 
     209        NSValue *initialMouseLocation = [NSValue valueWithPoint:[NSEvent mouseLocation]]; 
     210        tooltipDelayTimer = [[NSTimer scheduledTimerWithTimeInterval:TOOL_TIP_DELAY 
     211                                                                                                                  target:self 
     212                                                                                                                selector:@selector(delayedShowTooltip:) 
     213                                                                                                                userInfo:[NSMutableDictionary dictionaryWithObject:initialMouseLocation forKey:MOUSE_LOCATION_KEY] 
     214                                                                                                                 repeats:NO] retain]; 
     215#if LOG_TRACKING_INFO 
     216        NSLog(@"%s: Scheduled timer %@ for %f seconds from now", __PRETTY_FUNCTION__, tooltipDelayTimer, TOOL_TIP_DELAY); 
     217#endif 
     218
     219 
     220- (void)mouseMoved:(NSEvent *)event 
     221
     222        NSPoint mouseLocation = [event locationInWindow]; 
     223        NSWindow *theWindow = [event window]; 
     224 
     225#warning Assumes that (a) view is the content view of this window and (b) content-relative co-ordinates are the same as frame-relative co-ordinates. 
    394226        if ([theWindow isVisible] && 
    395227                NSPointInRect(mouseLocation, [view frame]) 
    396228        ) { 
     229                //Convert our mouse location from window-relative (for comparison) to screen-relative (for real use). 
     230                mouseLocation = [theWindow convertBaseToScreen:mouseLocation]; 
     231 
    397232                //If the tooltip is not yet on screen, and the mouse has moved, then reset the delay. 
    398233                if (tooltipDelayTimer) { 
     
    427262                [self _hideTooltip]; 
    428263        } 
    429  
    430         [self setPrivateVariablesLastMouseLocation:lastMouseLocation 
    431                                                            tooltipLocation:tooltipLocation 
    432                                                                           delegate:delegate]; 
    433  
    434         return err; 
    435 
     264
     265 
     266//Mouse left our list. Hide the tooltip. 
     267- (void)mouseExited:(NSEvent *)theEvent 
     268
     269#if LOG_TRACKING_INFO 
     270        NSLog(@"--- [%@: mouseExited]", self); 
     271#endif 
     272 
     273        [self _hideTooltip]; 
     274
     275 
     276- (void)delayedShowTooltip:(NSTimer *)timer 
     277
     278#if LOG_TRACKING_INFO 
     279        NSLog(@"%s: Timer fired! Showing tooltip at %@", __PRETTY_FUNCTION__, NSStringFromPoint([[[timer userInfo] objectForKey:MOUSE_LOCATION_KEY] pointValue])); 
     280#endif 
     281        [delegate showTooltipAtPoint:[[[timer userInfo] objectForKey:MOUSE_LOCATION_KEY] pointValue]]; 
     282 
     283        /* 
     284#if LOG_TRACKING_INFO 
     285        NSLog(@"%s: Removing event handler %p", __PRETTY_FUNCTION__, mouseMovedHandler); 
     286#endif 
     287        RemoveEventHandler((EventHandlerRef)mouseMovedHandler); 
     288         */ 
     289 
     290#if LOG_TRACKING_INFO 
     291        NSLog(@"%s: Invalidating and releasing timer %@", __PRETTY_FUNCTION__, tooltipDelayTimer); 
     292#endif 
     293        [tooltipDelayTimer invalidate]; 
     294        [tooltipDelayTimer release]; 
     295        tooltipDelayTimer = nil; 
     296
     297 
     298- (void)_hideTooltip 
     299
     300#if LOG_TRACKING_INFO 
     301        NSLog(@"%s: tooltipLocation is %@; delegate is %@", __PRETTY_FUNCTION__, NSStringFromPoint(tooltipLocation), delegate); 
     302#endif 
     303        //If the tooltip was being shown before, hide it 
     304        if (!NSEqualPoints(tooltipLocation,NSZeroPoint)) { 
     305                lastMouseLocation = NSZeroPoint; 
     306                tooltipLocation = NSZeroPoint; 
     307 
     308                //Hide tooltip 
     309                [delegate hideTooltip]; 
     310        } 
     311
     312 
     313@end