title: Cocoa AppKit - Dismissing a modal window (i.e. popup or contextual menu) and pressing the button currently hovered above
body: <p>Basically I want to create the effect of that provided in the system's menu bar. A user presses on one of the menu headings, and as he moves across the different headings, the menus open up automatically.</p>
  
  <p>The snag is that if I open a pop-up menu for a button, the user has to click again to dismiss it. The entire runloop is on hold as I believe the pop-up menu is modal. How do I go about being able to send a [somePopUpMenu cancelTracking] when the user moves to the next button?</p>
  
  <p>Here's code I'm currently trying out in my NSWindow subclass. The point is that once the mouse exits a button, the mouse is automatically clicked (leftdown/leftup) on the next button, the timer is invalidated and the popup menu is cancelled.</p>
  
  <p>Assuming a popup menu is open and the mouse exists, the leftdown/leftup events are fired (I know this works as I log them in NSLog's for mouseDown and mouseUp), the timer is invalidated, but the pop up menu is still showing, and the other button "clicked" on by the fake events doesn't show anything. Also, the whole thing gets into a loop and there's frantic mouseDown/mouseUp being sent for some reason.</p>
  
  <p>Worth noting the the popup menu is created in another object, though the hookToMenu has a proper reference to it (I confirmed via debug/stepping through).</p>
  
  <p>Dunno if I'm borking the event tracking timer or doing it the wrong way. I did try it via a window controller as well but got the same results.</p>
  
  <p>Any help on this would be appreciated. </p>
  
  <pre><code>-(void)stopTimer
  {
      [timer invalidate];
      [hookToMenu cancelTracking]; //hookToMenu is NSMenu*
  }
  
  -startFireDateTimer
  {
      NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:0];
      timer = [[NSTimer alloc] initWithFireDate:nil interval:0 target:self selector:@selector(targetMethod)      userInfo:nil  repeats:YES];
  
      NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
      [runLoop addTimer:timer forMode:NSEventTrackingRunLoopMode];
      [timer release];
  }
  
  -(void)targetMethod
  {
      NSEvent *newEvent;
  
      newEvent=[NSApp nextEventMatchingMask:NSMouseExitedMask untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:NO];
  
      if ([newEvent type]==NSMouseExited)
      {
          NSPoint mouseLoc;
  
          mouseLoc=[newEvent locationInWindow];
  
          int type=NSLeftMouseDown;
          int type2=NSLeftMouseUp;
          int windowNumber=[self windowNumber];
  
          id fakeMouseUpEvent=[NSEvent mouseEventWithType:type
                                                 location:mouseLoc
                                            modifierFlags:nil 
                                                timestamp:[NSDate timeIntervalSinceReferenceDate]
                                             windowNumber:windowNumber 
                                                  context:nil
                                              eventNumber:nil 
                                               clickCount:1 
                                                 pressure:1];
  
          id fakeMouseUpEvent2=[NSEvent mouseEventWithType:type2
                                                  location:mouseLoc
                                             modifierFlags:nil 
                                                 timestamp:[NSDate timeIntervalSinceReferenceDate]
                                              windowNumber:windowNumber 
                                                   context:nil
                                               eventNumber:nil 
                                                clickCount:1 
                                                  pressure:1];
  
          [NSApp sendEvent:fakeMouseUpEvent];
          [NSApp sendEvent:fakeMouseUpEvent2];
  
          [self stopTimer];
      }
  }
  
  -(void)mouseDown:(NSEvent *)theEvent
  {    
      [self startFireDateTimer];
  
      NSLog(@"WINDOW: mouse down in window!");
  
      [super mouseDown:theEvent];
  }
  
  -(void)mouseUp:(NSEvent *)theEvent
  {    
      NSLog(@"WINDOW: mouse up in window!");
  
      [super mouseUp:theEvent];
  }
  </code></pre>