Index: trunk/Cocoa/Pester/Source/PSVolumeController.m
===================================================================
--- trunk/Cocoa/Pester/Source/PSVolumeController.m	(revision 583)
+++ trunk/Cocoa/Pester/Source/PSVolumeController.m	(revision 584)
@@ -11,4 +11,14 @@
 #import "NJRNonCenteringWindow.h"
 
+@interface NSMenu (SnowLeopardAdditions)
+- (BOOL)popUpMenuPositioningItem:(NSMenuItem *)item atLocation:(NSPoint)location inView:(NSView *)view;
+- (void)setAllowsContextMenuPlugIns:(BOOL)allows;
+- (void)cancelTracking;
+@end
+
+@interface NSMenuItem (SnowLeopardAdditions)
+- (void)setView:(NSView *)view;
+@end
+
 @implementation PSVolumeController
 
@@ -22,58 +32,60 @@
     if ( (self = [self initWithWindowNibName: @"Volume"]) != nil) {
         [self window]; // connect outlets
-        NSWindow *window = [[NJRNonCenteringWindow alloc] initWithContentRect: [contentView bounds] styleMask: NSBorderlessWindowMask backing: NSBackingStoreBuffered defer: NO];
 
-        if ([NJRSoundManager volumeIsNotMutedOrInvalid: volume])
+	if ([NJRSoundManager volumeIsNotMutedOrInvalid: volume])
             [volumeSlider setFloatValue: volume];
 
         delegate = [aDelegate retain];
 
-        [window setContentView: contentView];
-	[window setInitialFirstResponder: volumeSlider];
-	[window makeFirstResponder: volumeSlider];
-        [window setOpaque: NO];
-        [window setBackgroundColor: [NSColor colorWithCalibratedWhite: 0.81f alpha: 0.9f]];
-        [window setHasShadow: YES];
-        [window setOneShot: YES];
-        [window setDelegate: self];
-        NSView *view = [aDelegate volumeControllerLaunchingView: self];
-        if (view != nil) {
-            NSRect rect = [view convertRect: [view bounds] toView: nil];
-            NSWindow *parentWindow = [view window];
-            rect.origin = [parentWindow convertBaseToScreen: rect.origin];
-            rect.origin.x -= [window frame].size.width - rect.size.width + 1;
-            [window setFrameTopLeftPoint: rect.origin];
-            NSRect visibleFrame = [[parentWindow screen] visibleFrame];
-            if (!NSContainsRect(visibleFrame, [window frame])) {
-                NSPoint viewTopLeft = { rect.origin.x, rect.origin.y + rect.size.height };
-                [window setFrameOrigin: viewTopLeft];
-            }
-        }
+	NSView *view = [aDelegate volumeControllerLaunchingView: self];
 
-        // -[NSApplication beginModalSessionForWindow:] shows and centers the window; we use NJRNonCenteringWindow to prevent the repositioning from succeeding
-        NSModalSession session = [NSApp beginModalSessionForWindow: window];
 	// In 10.6, we can no longer force the modal session to work by "seeding" the slider with a mouse-down event.
-	// Instead, we stop the modal session on a volume change.
-	while ([NSApp runModalSession: session] == NSRunContinuesResponse) {
-	    // Any mouse click events that do not change the slider value should abort.
-	    NSEvent *event = [NSApp currentEvent];
-	    unsigned int eventTypeMask = NSEventMaskFromType([event type]);
-	    if (eventTypeMask & (NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask)) {
-		[NSApp preventWindowOrdering];
-		[NSApp discardEventsMatchingMask: NSAnyEventMask beforeEvent: event];
-		break;
+	// Instead, use a menu.  (This should mostly work on 10.5 too, but is currently untested.)
+	if ([NSMenu instancesRespondToSelector: @selector(popUpMenuPositioningItem:atLocation:inView:)]) {
+	    menu = [[NSMenu alloc] initWithTitle: @""];
+	    NSMenuItem *menuItem = [[NSMenuItem alloc] init];
+	    [menuItem setView: contentView];
+	    [menu addItem: menuItem];
+	    [menuItem release];
+	    NSPoint point;
+	    if (view != nil) {
+		NSSize size = [view bounds].size;
+		point = [view isFlipped] ? NSMakePoint(0, size.height) : NSZeroPoint;
+	    } else {
+		point = [NSEvent mouseLocation];
 	    }
-	    if (eventTypeMask & (NSKeyDownMask | NSKeyUpMask)) {
-		unsigned short keyCode = [event keyCode];
-		if (keyCode == 53 || keyCode == 36 || keyCode == 76) { // escape, return, enter
-		    [NSApp discardEventsMatchingMask: NSAnyEventMask beforeEvent: event];
-		    break;
+	    [menu setAllowsContextMenuPlugIns: NO];
+	    [menu popUpMenuPositioningItem: nil atLocation: point inView: view];
+	    [menu release];
+	} else {
+	    NSWindow *window = [[NJRNonCenteringWindow alloc] initWithContentRect: [contentView bounds] styleMask: NSBorderlessWindowMask backing: NSBackingStoreBuffered defer: NO];
+	    [window setContentView: contentView];
+	    [window setOpaque: NO];
+	    [window setBackgroundColor: [NSColor colorWithCalibratedWhite: 0.81f alpha: 0.9f]];
+	    [window setHasShadow: YES];
+	    [window setOneShot: YES];
+	    [window setDelegate: self];
+
+	    if (view != nil) {
+		NSRect rect = [view convertRect: [view bounds] toView: nil];
+		NSWindow *parentWindow = [view window];
+		rect.origin = [parentWindow convertBaseToScreen: rect.origin];
+		rect.origin.x -= [window frame].size.width - rect.size.width + 1;
+		[window setFrameTopLeftPoint: rect.origin];
+		NSRect visibleFrame = [[parentWindow screen] visibleFrame];
+		if (!NSContainsRect(visibleFrame, [window frame])) {
+		    NSPoint viewTopLeft = { rect.origin.x, rect.origin.y + rect.size.height };
+		    [window setFrameOrigin: viewTopLeft];
 		}
 	    }
+	    // -[NSApplication beginModalSessionForWindow:] shows and centers the window; we use NJRNonCenteringWindow to prevent the repositioning from succeeding
+	    NSModalSession session = [NSApp beginModalSessionForWindow: window];
+	    [volumeSlider mouseDown: [NSApp currentEvent]];
+	    [NSApp runModalSession: session];
+	    [NSApp endModalSession: session];
+	    [window close];
 	}
-        [NSApp endModalSession: session];
-        [window close];
+
         [self autorelease];
-        // XXX make sure window and self are released
     }
     return self;
@@ -89,5 +101,6 @@
 {
     [delegate volumeController: self didSetVolume: [sender floatValue]];
-    [NSApp stopModal];
+    if (NSEventMaskFromType([[NSApp currentEvent] type]) & (NSLeftMouseUpMask | NSRightMouseUpMask | NSOtherMouseUpMask))
+	[menu cancelTracking];
 }
 
