source: trunk/Cocoa/Pester/Source/PSVolumeController.m @ 584

Last change on this file since 584 was 584, checked in by Nicholas Riley, 10 years ago

Better solution for volume popup in 10.6: use a menu.

File size: 3.7 KB
Line 
1//
2//  PSVolumeController.m
3//  Pester
4//
5//  Created by Nicholas Riley on Tue Apr 08 2003.
6//  Copyright (c) 2003 Nicholas Riley. All rights reserved.
7//
8
9#import "PSVolumeController.h"
10#import "NJRSoundManager.h"
11#import "NJRNonCenteringWindow.h"
12
13@interface NSMenu (SnowLeopardAdditions)
14- (BOOL)popUpMenuPositioningItem:(NSMenuItem *)item atLocation:(NSPoint)location inView:(NSView *)view;
15- (void)setAllowsContextMenuPlugIns:(BOOL)allows;
16- (void)cancelTracking;
17@end
18
19@interface NSMenuItem (SnowLeopardAdditions)
20- (void)setView:(NSView *)view;
21@end
22
23@implementation PSVolumeController
24
25+ (PSVolumeController *)controllerWithVolume:(float)volume delegate:(id)aDelegate;
26{
27    return [[self alloc] initWithVolume: volume delegate: aDelegate];
28}
29
30- (id)initWithVolume:(float)volume delegate:(id)aDelegate;
31{
32    if ( (self = [self initWithWindowNibName: @"Volume"]) != nil) {
33        [self window]; // connect outlets
34
35        if ([NJRSoundManager volumeIsNotMutedOrInvalid: volume])
36            [volumeSlider setFloatValue: volume];
37
38        delegate = [aDelegate retain];
39
40        NSView *view = [aDelegate volumeControllerLaunchingView: self];
41
42        // In 10.6, we can no longer force the modal session to work by "seeding" the slider with a mouse-down event.
43        // Instead, use a menu.  (This should mostly work on 10.5 too, but is currently untested.)
44        if ([NSMenu instancesRespondToSelector: @selector(popUpMenuPositioningItem:atLocation:inView:)]) {
45            menu = [[NSMenu alloc] initWithTitle: @""];
46            NSMenuItem *menuItem = [[NSMenuItem alloc] init];
47            [menuItem setView: contentView];
48            [menu addItem: menuItem];
49            [menuItem release];
50            NSPoint point;
51            if (view != nil) {
52                NSSize size = [view bounds].size;
53                point = [view isFlipped] ? NSMakePoint(0, size.height) : NSZeroPoint;
54            } else {
55                point = [NSEvent mouseLocation];
56            }
57            [menu setAllowsContextMenuPlugIns: NO];
58            [menu popUpMenuPositioningItem: nil atLocation: point inView: view];
59            [menu release];
60        } else {
61            NSWindow *window = [[NJRNonCenteringWindow alloc] initWithContentRect: [contentView bounds] styleMask: NSBorderlessWindowMask backing: NSBackingStoreBuffered defer: NO];
62            [window setContentView: contentView];
63            [window setOpaque: NO];
64            [window setBackgroundColor: [NSColor colorWithCalibratedWhite: 0.81f alpha: 0.9f]];
65            [window setHasShadow: YES];
66            [window setOneShot: YES];
67            [window setDelegate: self];
68
69            if (view != nil) {
70                NSRect rect = [view convertRect: [view bounds] toView: nil];
71                NSWindow *parentWindow = [view window];
72                rect.origin = [parentWindow convertBaseToScreen: rect.origin];
73                rect.origin.x -= [window frame].size.width - rect.size.width + 1;
74                [window setFrameTopLeftPoint: rect.origin];
75                NSRect visibleFrame = [[parentWindow screen] visibleFrame];
76                if (!NSContainsRect(visibleFrame, [window frame])) {
77                    NSPoint viewTopLeft = { rect.origin.x, rect.origin.y + rect.size.height };
78                    [window setFrameOrigin: viewTopLeft];
79                }
80            }
81            // -[NSApplication beginModalSessionForWindow:] shows and centers the window; we use NJRNonCenteringWindow to prevent the repositioning from succeeding
82            NSModalSession session = [NSApp beginModalSessionForWindow: window];
83            [volumeSlider mouseDown: [NSApp currentEvent]];
84            [NSApp runModalSession: session];
85            [NSApp endModalSession: session];
86            [window close];
87        }
88
89        [self autorelease];
90    }
91    return self;
92}
93
94- (void)dealloc;
95{
96    [delegate release];
97    [super dealloc];
98}
99
100- (IBAction)volumeSet:(NSSlider *)sender;
101{
102    [delegate volumeController: self didSetVolume: [sender floatValue]];
103    if (NSEventMaskFromType([[NSApp currentEvent] type]) & (NSLeftMouseUpMask | NSRightMouseUpMask | NSOtherMouseUpMask))
104        [menu cancelTracking];
105}
106
107@end
Note: See TracBrowser for help on using the repository browser.