1735 lines
55 KiB
Objective-C
1735 lines
55 KiB
Objective-C
//
|
|
// AppDelegate.m
|
|
// iTunes Volume Control
|
|
//
|
|
// Created by Andrea Alberti on 25.12.12.
|
|
// Copyright (c) 2012 Andrea Alberti. All rights reserved.
|
|
//
|
|
|
|
#import "AppDelegate.h"
|
|
#import <IOKit/hidsystem/ev_keymap.h>
|
|
#import <Sparkle/SUUpdater.h>
|
|
#import "StatusItemView.h"
|
|
//#import "IntroWindowController.h"
|
|
//#import "MyNSVisualEffectView.h"
|
|
|
|
#import <IOKit/hidsystem/ev_keymap.h>
|
|
|
|
#import "SystemVolume.h"
|
|
|
|
#import "AccessibilityDialog.h"
|
|
|
|
//#import "BezelServices.h"
|
|
#import "OSD.h"
|
|
|
|
// #include <dlfcn.h>
|
|
|
|
//This will handle signals for us, specifically SIGTERM.
|
|
void handleSIGTERM(int sig) {
|
|
[NSApp terminate:nil];
|
|
}
|
|
|
|
#pragma mark - Tapping key stroke events
|
|
|
|
//static void displayPreferencesChanged(CGDirectDisplayID displayID, CGDisplayChangeSummaryFlags flags, void *userInfo) {
|
|
// [[NSNotificationCenter defaultCenter] postNotificationName:@"displayResolutionHasChanged" object:NULL];
|
|
//}
|
|
|
|
CGEventRef event_tap_callback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
|
|
{
|
|
static int previousKeyCode = 0;
|
|
static bool muteDown = false;
|
|
NSEvent * sysEvent;
|
|
|
|
if (type == kCGEventTapDisabledByTimeout) {
|
|
// NSAlert *alert = [NSAlert alertWithMessageText:@"iTunes Volume Control" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"Event Taps Disabled! Re-enabling."];
|
|
// [alert runModal];
|
|
//
|
|
// NSLog(@"Event Taps Disabled! Re-enabling");
|
|
[(__bridge AppDelegate *)(refcon) resetEventTap];
|
|
return event;
|
|
}
|
|
|
|
// No event we care for? return ASAP
|
|
if (type != NX_SYSDEFINED) return event;
|
|
|
|
sysEvent = [NSEvent eventWithCGEvent:event];
|
|
// No need to test event type, we know it is NSSystemDefined, becuase that is the same as NX_SYSDEFINED
|
|
// if ([sysEvent subtype] != NX_SUBTYPE_AUX_CONTROL_BUTTONS && [sysEvent subtype] != NX_SUBTYPE_AUX_MOUSE_BUTTONS) return event;
|
|
if ([sysEvent subtype] != NX_SUBTYPE_AUX_CONTROL_BUTTONS) return event;
|
|
|
|
int keyFlags = ([sysEvent data1] & 0x0000FFFF);
|
|
int keyCode = (([sysEvent data1] & 0xFFFF0000) >> 16);
|
|
int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
|
|
CGEventFlags keyModifier = [sysEvent modifierFlags]|0xFFFF;
|
|
AppDelegate* app=(__bridge AppDelegate *)(refcon);
|
|
bool keyIsRepeat = (keyFlags & 0x1);
|
|
//bool musicProgramRunning=[app->musicProgramPnt isRunning];
|
|
|
|
// store whether Apple CMD modifier has been pressed or not
|
|
[app setAppleCMDModifierPressed:(keyModifier&NX_COMMANDMASK)==NX_COMMANDMASK];
|
|
|
|
switch( keyCode )
|
|
{
|
|
case NX_KEYTYPE_MUTE:
|
|
|
|
if(previousKeyCode!=keyCode && app->timer)
|
|
{
|
|
[app stopTimer];
|
|
#ifdef OWN_WINDOW
|
|
if(!app->timerImgSpeaker&&!app->fadeInAnimationReady){
|
|
app->timerImgSpeaker=[NSTimer scheduledTimerWithTimeInterval:app->waitOverlayPanel target:app selector:@selector(hideSpeakerImg:) userInfo:nil repeats:NO];
|
|
[[NSRunLoop mainRunLoop] addTimer:app->timerImgSpeaker forMode:NSRunLoopCommonModes];
|
|
}
|
|
#endif
|
|
}
|
|
previousKeyCode=keyCode;
|
|
|
|
if( keyState == 1 )
|
|
{
|
|
muteDown = true;
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"MuteITunesVolume" object:NULL];
|
|
}
|
|
else
|
|
{
|
|
muteDown = false;
|
|
}
|
|
return NULL;
|
|
break;
|
|
case NX_KEYTYPE_SOUND_UP:
|
|
case NX_KEYTYPE_SOUND_DOWN:
|
|
// NSLog(@"Subtype %d",[sysEvent subtype]);
|
|
// NSLog(@"keyCode %d",keyCode);
|
|
// NSLog(@"keyState %d",keyState);
|
|
// NSLog(@"keyIsRepeat %d",keyIsRepeat);
|
|
|
|
if(!muteDown)
|
|
{
|
|
if(previousKeyCode!=keyCode && app->timer)
|
|
{
|
|
[app stopTimer];
|
|
#ifdef OWN_WINDOW
|
|
if(!app->timerImgSpeaker&&!app->fadeInAnimationReady){
|
|
app->timerImgSpeaker=[NSTimer scheduledTimerWithTimeInterval:app->waitOverlayPanel target:app selector:@selector(hideSpeakerImg:) userInfo:nil repeats:NO];
|
|
[[NSRunLoop mainRunLoop] addTimer:app->timerImgSpeaker forMode:NSRunLoopCommonModes];
|
|
}
|
|
#endif
|
|
}
|
|
previousKeyCode=keyCode;
|
|
|
|
if( keyState == 1 )
|
|
{
|
|
if( !app->timer )
|
|
{
|
|
if( keyCode == NX_KEYTYPE_SOUND_UP )
|
|
{
|
|
[[NSNotificationCenter defaultCenter]
|
|
postNotificationName:(keyIsRepeat?@"IncreaseITunesVolumeRamp":@"IncreaseITunesVolume") object:NULL];
|
|
}
|
|
else
|
|
{
|
|
[[NSNotificationCenter defaultCenter]
|
|
postNotificationName:(keyIsRepeat?@"DecreaseITunesVolumeRamp":@"DecreaseITunesVolume") object:NULL];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(app->timer)
|
|
{
|
|
[app stopTimer];
|
|
#ifdef OWN_WINDOW
|
|
if(!app->timerImgSpeaker&&!app->fadeInAnimationReady){
|
|
app->timerImgSpeaker=[NSTimer scheduledTimerWithTimeInterval:app->waitOverlayPanel target:app selector:@selector(hideSpeakerImg:) userInfo:nil repeats:NO];
|
|
[[NSRunLoop mainRunLoop] addTimer:app->timerImgSpeaker forMode:NSRunLoopCommonModes];
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
return event;
|
|
}
|
|
|
|
#pragma mark - Class extension for status menu
|
|
|
|
@interface AppDelegate () <NSMenuDelegate>
|
|
{
|
|
StatusItemView* _statusBarItemView;
|
|
NSTimer* _statusBarHideTimer;
|
|
NSPopover* _hideFromStatusBarHintPopover;
|
|
NSTextField* _hideFromStatusBarHintLabel;
|
|
NSTimer *_hideFromStatusBarHintPopoverUpdateTimer;
|
|
|
|
NSView* _hintView;
|
|
NSViewController* _hintVC;
|
|
}
|
|
|
|
@end
|
|
|
|
#pragma mark - Extention music applications
|
|
|
|
@implementation PlayerApplication
|
|
|
|
@synthesize currentVolume = _currentVolume;
|
|
|
|
- (void) setCurrentVolume:(double)currentVolume
|
|
{
|
|
[self setDoubleVolume:currentVolume];
|
|
|
|
[musicPlayer setSoundVolume:round(currentVolume)];
|
|
}
|
|
|
|
- (double) currentVolume
|
|
{
|
|
double vol = [musicPlayer soundVolume];
|
|
|
|
if (fabs(vol-[self doubleVolume])<1)
|
|
{
|
|
vol = [self doubleVolume];
|
|
}
|
|
|
|
return vol;
|
|
}
|
|
|
|
- (void) nextTrack
|
|
{
|
|
return [musicPlayer nextTrack];
|
|
}
|
|
|
|
- (void) previousTrack
|
|
{
|
|
return [musicPlayer previousTrack];
|
|
}
|
|
|
|
- (void) playPause
|
|
{
|
|
return [musicPlayer playPause];
|
|
}
|
|
|
|
- (BOOL) isRunning
|
|
{
|
|
return [musicPlayer isRunning];
|
|
}
|
|
|
|
- (iTunesEPlS) playerState
|
|
{
|
|
return [musicPlayer playerState];
|
|
}
|
|
|
|
-(id)initWithBundleIdentifier:(NSString*) bundleIdentifier {
|
|
if (self = [super init]) {
|
|
[self setCurrentVolume: -100];
|
|
[self setOldVolume: -1];
|
|
musicPlayer = [SBApplication applicationWithBundleIdentifier:bundleIdentifier];
|
|
|
|
}
|
|
return self;
|
|
}
|
|
|
|
@end
|
|
|
|
/*
|
|
#pragma mark - Class extension for NSString
|
|
|
|
@implementation NSString (NSString_Extended)
|
|
|
|
- (NSString *)urlencode {
|
|
NSMutableString *output = [NSMutableString string];
|
|
const unsigned char *source = (const unsigned char *)[self UTF8String];
|
|
unsigned long int sourceLen = strlen((const char *)source);
|
|
for (int i = 0; i < sourceLen; ++i) {
|
|
const unsigned char thisChar = source[i];
|
|
if (thisChar == ' '){
|
|
[output appendString:@"+"];
|
|
} else if (thisChar == '.' || thisChar == '-' || thisChar == '_' || thisChar == '~' ||
|
|
(thisChar >= 'a' && thisChar <= 'z') ||
|
|
(thisChar >= 'A' && thisChar <= 'Z') ||
|
|
(thisChar >= '0' && thisChar <= '9')) {
|
|
[output appendFormat:@"%c", thisChar];
|
|
} else {
|
|
[output appendFormat:@"%%%02X", thisChar];
|
|
}
|
|
}
|
|
return output;
|
|
}
|
|
|
|
@end
|
|
*/
|
|
|
|
#ifdef OWN_WINDOW
|
|
#pragma mark - Extending NSView
|
|
|
|
//#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
|
|
|
|
@implementation NSView (HS)
|
|
|
|
-(instancetype)insertVibrancyViewBlendingMode:(NSVisualEffectBlendingMode)mode
|
|
{
|
|
Class vibrantClass=NSClassFromString(@"NSVisualEffectView");
|
|
if (vibrantClass)
|
|
{
|
|
NSVisualEffectView *vibrant=[[vibrantClass alloc] initWithFrame:self.bounds];
|
|
|
|
[vibrant setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
|
|
[vibrant setBlendingMode:mode];
|
|
|
|
//[vibrant setMaterial:NSVisualEffectMaterialLight];
|
|
//[vibrant setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]];
|
|
[vibrant setState:NSVisualEffectStateActive];
|
|
|
|
[vibrant setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]];
|
|
[vibrant setMaterial:0x1a]; // NSVisualEffectMaterialDark
|
|
|
|
[self addSubview:vibrant positioned:NSWindowAbove relativeTo:nil];
|
|
|
|
return vibrant;
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
@end
|
|
|
|
//#endif
|
|
|
|
#endif
|
|
|
|
#pragma mark - Implementation AppDelegate
|
|
|
|
@implementation AppDelegate
|
|
|
|
// @synthesize AppleRemoteConnected=_AppleRemoteConnected;
|
|
@synthesize StartAtLogin=_StartAtLogin;
|
|
@synthesize Tapping=_Tapping;
|
|
@synthesize UseAppleCMDModifier=_UseAppleCMDModifier;
|
|
@synthesize AppleCMDModifierPressed=_AppleCMDModifierPressed;
|
|
@synthesize AutomaticUpdates=_AutomaticUpdates;
|
|
@synthesize hideFromStatusBar = _hideFromStatusBar;
|
|
@synthesize hideVolumeWindow = _hideVolumeWindow;
|
|
@synthesize loadIntroAtStart = _loadIntroAtStart;
|
|
@synthesize statusBar = _statusBar;
|
|
|
|
@synthesize iTunesBtn = _iTunesBtn;
|
|
@synthesize spotifyBtn = _spotifyBtn;
|
|
@synthesize systemBtn = _systemBtn;
|
|
|
|
@synthesize iTunesPerc = _iTunesPerc;
|
|
@synthesize spotifyPerc = _spotifyPerc;
|
|
@synthesize systemPerc = _systemPerc;
|
|
|
|
@synthesize statusMenu = _statusMenu;
|
|
@synthesize volumeWindow = _volumeWindow;
|
|
|
|
#ifdef OWN_WINDOW
|
|
static CFTimeInterval fadeInDuration=0.1;
|
|
static CFTimeInterval fadeOutDuration=0.7;
|
|
#endif
|
|
|
|
static NSTimeInterval volumeRampTimeInterval=0.01;
|
|
static NSTimeInterval statusBarHideDelay=10;
|
|
|
|
/*
|
|
// El Capitan and probably older systems
|
|
void *(*_BSDoGraphicWithMeterAndTimeout)(CGDirectDisplayID arg0, BSGraphic arg1, int arg2, float v, int timeout) = NULL;
|
|
|
|
- (BOOL)_loadBezelServices
|
|
{
|
|
// Load BezelServices framework
|
|
void *handle = dlopen("/System/Library/PrivateFrameworks/BezelServices.framework/Versions/A/BezelServices", RTLD_GLOBAL);
|
|
if (!handle) {
|
|
NSLog(@"Error opening framework");
|
|
return NO;
|
|
}
|
|
else {
|
|
_BSDoGraphicWithMeterAndTimeout = dlsym(handle, "BSDoGraphicWithMeterAndTimeout");
|
|
return _BSDoGraphicWithMeterAndTimeout != NULL;
|
|
}
|
|
}
|
|
*/
|
|
|
|
-(void) sendMediaKey: (int)key {
|
|
// create and send down key event
|
|
NSEvent* key_event;
|
|
|
|
key_event = [NSEvent otherEventWithType:NSEventTypeSystemDefined location:CGPointZero modifierFlags:0xa00 timestamp:0 windowNumber:0 context:0 subtype:8 data1:((key << 16) | (0xa << 8)) data2:-1];
|
|
CGEventPost(0, key_event.CGEvent);
|
|
// NSLog(@"%d keycode (down) sent",key);
|
|
|
|
// create and send up key event
|
|
key_event = [NSEvent otherEventWithType:NSEventTypeSystemDefined location:CGPointZero modifierFlags:0xb00 timestamp:0 windowNumber:0 context:0 subtype:8 data1:((key << 16) | (0xb << 8)) data2:-1];
|
|
CGEventPost(0, key_event.CGEvent);
|
|
// NSLog(@"%d keycode (up) sent",key);
|
|
}
|
|
|
|
|
|
/*
|
|
- (PrivacyConsentState)checkSIPforAppIdentifier:(NSString *)bundleIdentifier promptIfNeeded:(BOOL)promptIfNeeded
|
|
{
|
|
PrivacyConsentState result;
|
|
if (@available(macOS 10.14, *)) {
|
|
AEAddressDesc addressDesc;
|
|
// We need a C string here, not an NSString
|
|
const char *bundleIdentifierCString = [bundleIdentifier cStringUsingEncoding:NSUTF8StringEncoding];
|
|
if( AECreateDesc(typeApplicationBundleID, bundleIdentifierCString, strlen(bundleIdentifierCString), &addressDesc) == noErr )
|
|
{
|
|
OSStatus appleScriptPermission = AEDeterminePermissionToAutomateTarget(&addressDesc, typeWildCard, typeWildCard, promptIfNeeded);
|
|
|
|
AEDisposeDesc(&addressDesc);
|
|
|
|
switch (appleScriptPermission) {
|
|
case errAEEventWouldRequireUserConsent:
|
|
NSLog(@"Automation consent not yet granted for %@, would require user consent.", bundleIdentifier);
|
|
result = PrivacyConsentStateUnknown;
|
|
break;
|
|
case noErr:
|
|
NSLog(@"Automation permitted for %@.", bundleIdentifier);
|
|
result = PrivacyConsentStateGranted;
|
|
break;
|
|
case errAEEventNotPermitted:
|
|
NSLog(@"Automation of %@ not permitted.", bundleIdentifier);
|
|
result = PrivacyConsentStateDenied;
|
|
break;
|
|
case procNotFound:
|
|
NSLog(@"%@ not running, automation consent unknown.", bundleIdentifier);
|
|
result = PrivacyConsentStateUnknown;
|
|
break;
|
|
default:
|
|
NSLog(@"%s switch statement fell through: %@ %d", __PRETTY_FUNCTION__, bundleIdentifier, appleScriptPermission);
|
|
result = PrivacyConsentStateUnknown;
|
|
}
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
NSLog(@"%s error executing AECreateDesc.", __PRETTY_FUNCTION__);
|
|
return PrivacyConsentStateDenied;
|
|
}
|
|
}
|
|
else {
|
|
return PrivacyConsentStateGranted;
|
|
}
|
|
|
|
}
|
|
*/
|
|
|
|
- (IBAction)terminate:(id)sender
|
|
{
|
|
if(CFMachPortIsValid(eventTap)) {
|
|
CFMachPortInvalidate(eventTap);
|
|
CFRunLoopSourceInvalidate(runLoopSource);
|
|
CFRelease(eventTap);
|
|
CFRelease(runLoopSource);
|
|
}
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
[[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
|
|
|
|
// [remote stopListening:self];
|
|
// remote=nil;
|
|
|
|
systemAudio = nil;
|
|
iTunes = nil;
|
|
spotify = nil;
|
|
|
|
_statusBar = nil;
|
|
|
|
accessibilityDialog = nil;
|
|
introWindowController = nil;
|
|
|
|
[timer invalidate];
|
|
timer = nil;
|
|
|
|
[timerImgSpeaker invalidate];
|
|
timerImgSpeaker = nil;
|
|
|
|
preferences = nil;
|
|
|
|
[NSApp terminate:nil];
|
|
}
|
|
|
|
- (bool) StartAtLogin
|
|
{
|
|
NSURL *appURL=[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
|
|
|
|
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
|
|
|
|
bool found=false;
|
|
|
|
if (loginItems) {
|
|
UInt32 seedValue;
|
|
//Retrieve the list of Login Items and cast them to a NSArray so that it will be easier to iterate.
|
|
NSArray *loginItemsArray = (__bridge NSArray *)LSSharedFileListCopySnapshot(loginItems, &seedValue);
|
|
|
|
for(int i=0; i<[loginItemsArray count]; i++)
|
|
{
|
|
LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)[loginItemsArray objectAtIndex:i];
|
|
//Resolve the item with URL
|
|
CFURLRef url = NULL;
|
|
|
|
// LSSharedFileListItemResolve is deprecated in Mac OS X 10.10
|
|
// Switch to LSSharedFileListItemCopyResolvedURL if possible
|
|
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000 // MAC_OS_X_VERSION_10_10
|
|
LSSharedFileListItemResolve(itemRef, 0, &url, NULL);
|
|
#else
|
|
url = LSSharedFileListItemCopyResolvedURL(itemRef, 0, NULL);
|
|
#endif
|
|
|
|
if ( url ) {
|
|
if ( CFEqual(url, (__bridge CFTypeRef)(appURL)) ) // found it
|
|
{
|
|
found=true;
|
|
}
|
|
CFRelease(url);
|
|
}
|
|
|
|
if(found)break;
|
|
}
|
|
|
|
CFRelease((__bridge CFTypeRef)(loginItemsArray));
|
|
CFRelease(loginItems);
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
- (void)introWindowWillClose:(NSNotification *)aNotification{
|
|
introWindowController = nil;
|
|
}
|
|
|
|
- (void)setStartAtLogin:(bool)enabled savePreferences:(bool)savePreferences
|
|
{
|
|
NSMenuItem* menuItem=[_statusMenu itemWithTag:4];
|
|
[menuItem setState:enabled];
|
|
|
|
if(savePreferences)
|
|
{
|
|
NSURL *appURL=[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
|
|
|
|
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
|
|
|
|
if (loginItems) {
|
|
if(enabled)
|
|
{
|
|
// Insert the item at the bottom of Login Items list.
|
|
LSSharedFileListItemRef loginItemRef = LSSharedFileListInsertItemURL(loginItems,
|
|
kLSSharedFileListItemLast,
|
|
NULL,
|
|
NULL,
|
|
(__bridge CFURLRef)appURL,
|
|
NULL,
|
|
NULL);
|
|
if (loginItemRef) {
|
|
CFRelease(loginItemRef);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UInt32 seedValue;
|
|
//Retrieve the list of Login Items and cast them to a NSArray so that it will be easier to iterate.
|
|
NSArray *loginItemsArray = (__bridge NSArray *)LSSharedFileListCopySnapshot(loginItems, &seedValue);
|
|
for(int i=0; i<[loginItemsArray count]; i++)
|
|
{
|
|
LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)[loginItemsArray objectAtIndex:i];
|
|
//Resolve the item with URL
|
|
CFURLRef URL = NULL;
|
|
|
|
// LSSharedFileListItemResolve is deprecated in Mac OS X 10.10
|
|
// Switch to LSSharedFileListItemCopyResolvedURL if possible
|
|
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000 // MAC_OS_X_VERSION_10_10
|
|
LSSharedFileListItemResolve(itemRef, 0, &URL, NULL);
|
|
#else
|
|
URL = LSSharedFileListItemCopyResolvedURL(itemRef, 0, NULL);
|
|
#endif
|
|
|
|
if ( URL ) {
|
|
if ( CFEqual(URL, (__bridge CFTypeRef)(appURL)) ) // found it
|
|
{
|
|
LSSharedFileListItemRemove(loginItems,itemRef);
|
|
}
|
|
CFRelease(URL);
|
|
}
|
|
}
|
|
CFRelease((__bridge CFTypeRef)(loginItemsArray));
|
|
}
|
|
CFRelease(loginItems);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)stopTimer
|
|
{
|
|
[timer invalidate];
|
|
timer=nil;
|
|
}
|
|
|
|
- (void)rampVolumeUp:(NSTimer*)theTimer
|
|
{
|
|
[self changeVol:true];
|
|
}
|
|
|
|
- (void)rampVolumeDown:(NSTimer*)theTimer
|
|
{
|
|
[self changeVol:false];
|
|
}
|
|
|
|
- (void)wasAuthorized
|
|
{
|
|
[accessibilityDialog close];
|
|
accessibilityDialog = nil;
|
|
|
|
[self completeInitialization];
|
|
}
|
|
|
|
- (bool)createEventTap
|
|
{
|
|
if(eventTap != nil && CFMachPortIsValid(eventTap)) {
|
|
CFMachPortInvalidate(eventTap);
|
|
CFRunLoopSourceInvalidate(runLoopSource);
|
|
CFRelease(eventTap);
|
|
CFRelease(runLoopSource);
|
|
}
|
|
|
|
CGEventMask eventMask = (/*(1 << kCGEventKeyDown) | (1 << kCGEventKeyUp) |*/CGEventMaskBit(NX_SYSDEFINED));
|
|
eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault,
|
|
eventMask, event_tap_callback, (__bridge void *)self); // Create an event tap. We are interested in SYS key presses.
|
|
|
|
if(eventTap != nil)
|
|
{
|
|
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0); // Create a run loop source.
|
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes); // Add to the current run loop.
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
// Apple remote
|
|
- (void) appleRemoteInit
|
|
{
|
|
remote = [[AppleRemote alloc] init];
|
|
[remote setDelegate:self];
|
|
}
|
|
*/
|
|
|
|
- (void)playPauseITunes:(NSNotification *)aNotification
|
|
{
|
|
[self sendMediaKey:NX_KEYTYPE_PLAY];
|
|
|
|
// id musicPlayerPnt = [self runningPlayer];
|
|
//
|
|
// // check if iTunes is running (Q1)
|
|
// [musicPlayerPnt playpause];
|
|
}
|
|
|
|
- (void)nextTrackITunes:(NSNotification *)aNotification
|
|
{
|
|
[self sendMediaKey:NX_KEYTYPE_NEXT];
|
|
// id musicPlayerPnt = [self runningPlayer];
|
|
//
|
|
// if ([musicPlayerPnt isRunning])
|
|
// {
|
|
// [musicPlayerPnt nextTrack];
|
|
// }
|
|
}
|
|
|
|
- (void)previousTrackITunes:(NSNotification *)aNotification
|
|
{
|
|
[self sendMediaKey:NX_KEYTYPE_PREVIOUS];
|
|
|
|
// id musicPlayerPnt = [self runningPlayer];
|
|
//
|
|
// if ([musicPlayerPnt isRunning])
|
|
// {
|
|
// [musicPlayerPnt previousTrack];
|
|
// }
|
|
}
|
|
|
|
- (void)muteITunesVolume:(NSNotification *)aNotification
|
|
{
|
|
#ifdef OWN_WINDOW
|
|
[self displayVolumeBar];
|
|
#endif
|
|
|
|
id musicPlayerPnt = [self runningPlayer];
|
|
|
|
if (musicPlayerPnt != nil)
|
|
{
|
|
if([musicPlayerPnt oldVolume]<0)
|
|
{
|
|
[musicPlayerPnt setOldVolume:[musicPlayerPnt currentVolume]];
|
|
[musicPlayerPnt setCurrentVolume:0];
|
|
|
|
if(!_hideVolumeWindow)
|
|
[[self->OSDManager sharedManager] showImage:OSDGraphicSpeakerMute onDisplayID:CGSMainDisplayID() priority:OSDPriorityDefault msecUntilFade:1000 filledChiclets:0 totalChiclets:(unsigned int)100 locked:NO];
|
|
|
|
//[self refreshVolumeBar:0];
|
|
}
|
|
else
|
|
{
|
|
[musicPlayerPnt setCurrentVolume:[musicPlayerPnt oldVolume]];
|
|
[volumeImageLayer setContents:imgVolOn];
|
|
|
|
if(!_hideVolumeWindow)
|
|
[[self->OSDManager sharedManager] showImage:OSDGraphicSpeaker onDisplayID:CGSMainDisplayID() priority:OSDPriorityDefault msecUntilFade:1000 filledChiclets:(unsigned int)[musicPlayerPnt oldVolume] totalChiclets:(unsigned int)100 locked:NO];
|
|
|
|
//[self refreshVolumeBar:oldVolumeSetting];
|
|
[musicPlayerPnt setOldVolume:-1];
|
|
}
|
|
|
|
if([_statusBarItemView menuIsVisible])
|
|
{
|
|
if( musicPlayerPnt == iTunes)
|
|
[self setItunesVolume:[musicPlayerPnt currentVolume]];
|
|
else if( musicPlayerPnt == spotify)
|
|
[self setSpotifyVolume:[musicPlayerPnt currentVolume]];
|
|
else if( musicPlayerPnt == systemAudio)
|
|
[self setSystemVolume:[musicPlayerPnt currentVolume]];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)increaseITunesVolume:(NSNotification *)aNotification
|
|
{
|
|
#ifdef OWN_WINDOW
|
|
[self displayVolumeBar];
|
|
#endif
|
|
|
|
if( [[aNotification name] isEqualToString:@"IncreaseITunesVolumeRamp"] )
|
|
{
|
|
timer=[NSTimer scheduledTimerWithTimeInterval:volumeRampTimeInterval*(NSTimeInterval)increment target:self selector:@selector(rampVolumeUp:) userInfo:nil repeats:YES];
|
|
|
|
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
|
|
|
|
if(timerImgSpeaker) {[timerImgSpeaker invalidate]; timerImgSpeaker=nil;}
|
|
}
|
|
else
|
|
{
|
|
[self changeVol:true];
|
|
}
|
|
}
|
|
|
|
- (void)decreaseITunesVolume:(NSNotification *)aNotification
|
|
{
|
|
#ifdef OWN_WINDOW
|
|
[self displayVolumeBar];
|
|
#endif
|
|
|
|
if( [[aNotification name] isEqualToString:@"DecreaseITunesVolumeRamp"] )
|
|
{
|
|
timer=[NSTimer scheduledTimerWithTimeInterval:volumeRampTimeInterval*(NSTimeInterval)increment target:self selector:@selector(rampVolumeDown:) userInfo:nil repeats:YES];
|
|
|
|
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
|
|
|
|
if(timerImgSpeaker) {[timerImgSpeaker invalidate]; timerImgSpeaker=nil;}
|
|
}
|
|
else
|
|
{
|
|
[self changeVol:false];
|
|
}
|
|
}
|
|
|
|
/*
|
|
// Apple remote
|
|
- (void) appleRemoteButton: (AppleRemoteEventIdentifier)buttonIdentifier pressedDown: (BOOL) pressedDown clickCount: (unsigned int) count {
|
|
|
|
switch (buttonIdentifier)
|
|
{
|
|
case kRemoteButtonVolume_Plus_Hold:
|
|
if(timer)
|
|
{
|
|
[self stopTimer];
|
|
|
|
// if(!timerImgSpeaker&&!fadeInAnimationReady) {
|
|
// timerImgSpeaker=[NSTimer scheduledTimerWithTimeInterval:waitOverlayPanel target:self selector:@selector(hideSpeakerImg:) userInfo:nil repeats:NO];
|
|
// [[NSRunLoop mainRunLoop] addTimer:timerImgSpeaker forMode:NSRunLoopCommonModes];
|
|
// }
|
|
}
|
|
else
|
|
{
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"IncreaseITunesVolumeRamp" object:NULL];
|
|
}
|
|
break;
|
|
case kRemoteButtonVolume_Plus:
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"IncreaseITunesVolume" object:NULL];
|
|
break;
|
|
|
|
case kRemoteButtonVolume_Minus_Hold:
|
|
if(timer)
|
|
{
|
|
[self stopTimer];
|
|
|
|
// if(!timerImgSpeaker&&!fadeInAnimationReady){
|
|
// timerImgSpeaker=[NSTimer scheduledTimerWithTimeInterval:waitOverlayPanel target:self selector:@selector(hideSpeakerImg:) userInfo:nil repeats:NO];
|
|
// [[NSRunLoop mainRunLoop] addTimer:timerImgSpeaker forMode:NSRunLoopCommonModes];
|
|
// }
|
|
}
|
|
else
|
|
{
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"DecreaseITunesVolumeRamp" object:NULL];
|
|
}
|
|
break;
|
|
case kRemoteButtonVolume_Minus:
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"DecreaseITunesVolume" object:NULL];
|
|
break;
|
|
|
|
case k2009RemoteButtonFullscreen:
|
|
break;
|
|
|
|
case k2009RemoteButtonPlay:
|
|
case kRemoteButtonPlay:
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"PlayPauseITunes" object:NULL];
|
|
break;
|
|
|
|
case kRemoteButtonLeft_Hold:
|
|
case kRemoteButtonLeft:
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"PreviousTrackITunes" object:NULL];
|
|
break;
|
|
|
|
case kRemoteButtonRight_Hold:
|
|
case kRemoteButtonRight:
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"NextTrackITunes" object:NULL];
|
|
break;
|
|
|
|
case kRemoteButtonMenu_Hold:
|
|
case kRemoteButtonMenu:
|
|
break;
|
|
|
|
case kRemoteButtonPlay_Sleep:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
*/
|
|
|
|
- (id)init
|
|
{
|
|
self = [super init];
|
|
if(self)
|
|
{
|
|
self->eventTap = nil;
|
|
|
|
#ifdef OWN_WINDOW
|
|
fadeOutAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
|
|
[fadeOutAnimation setDuration:fadeOutDuration];
|
|
[fadeOutAnimation setRemovedOnCompletion:NO];
|
|
[fadeOutAnimation setFillMode:kCAFillModeForwards];
|
|
[fadeOutAnimation setFromValue:[NSNumber numberWithFloat:1.0f]];
|
|
[fadeOutAnimation setToValue:[NSNumber numberWithFloat:0.0f]];
|
|
// [fadeOutAnimation setDelegate:self];
|
|
|
|
fadeInAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
|
|
[fadeInAnimation setDuration:fadeInDuration];
|
|
[fadeInAnimation setRemovedOnCompletion:NO];
|
|
[fadeInAnimation setFillMode:kCAFillModeForwards];
|
|
[fadeInAnimation setFromValue:[NSNumber numberWithFloat:0.0f]];
|
|
[fadeInAnimation setToValue:[NSNumber numberWithFloat:1.0f]];
|
|
// [fadeInAnimation setDelegate:self];
|
|
|
|
fadeInAnimationReady=true;
|
|
|
|
waitOverlayPanel=1.0;
|
|
#endif
|
|
|
|
|
|
if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_6) {
|
|
//10.6.x or earlier systems
|
|
osxVersion = 106;
|
|
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_7) {
|
|
/* On a 10.7 - 10.7.x system */
|
|
osxVersion = 107;
|
|
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_8) {
|
|
/* On a 10.8 - 10.8.x system */
|
|
osxVersion = 108;
|
|
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_9) {
|
|
/* On a 10.9 - 10.9.x system */
|
|
osxVersion = 109;
|
|
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_10) {
|
|
/* On a 10.10 - 10.10.x system */
|
|
osxVersion = 110;
|
|
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_11) {
|
|
/* On a 10.11 - 10.11.x system */
|
|
osxVersion = 111;
|
|
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_12) {
|
|
/* On a 10.12 - 10.12.x system */
|
|
osxVersion = 112;
|
|
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_13) {
|
|
/* On a 10.13 - 10.13.x system */
|
|
osxVersion = 113;
|
|
} else if (floor(NSAppKitVersionNumber) <= 1671) {
|
|
/* On a 10.14 - 10.14.x system */
|
|
osxVersion = 114;
|
|
}
|
|
else if (floor(NSAppKitVersionNumber) <= 1894) {
|
|
/* On a 10.15 - 10.15.x system */
|
|
osxVersion = 115;
|
|
}
|
|
else
|
|
{
|
|
osxVersion = 115;
|
|
}
|
|
|
|
|
|
}
|
|
return self;
|
|
}
|
|
|
|
#ifdef OWN_WINDOW
|
|
-(void)awakeFromNibb
|
|
{
|
|
|
|
NSRect screenFrame = [[NSScreen mainScreen] frame];
|
|
|
|
[_volumeWindow setFrame:(osxVersion<110? CGRectMake(round((screenFrame.size.width-210)/2),139,210,206) : CGRectMake(round((screenFrame.size.width-200)/2)+200,140,200,200)) display:NO animate:NO];
|
|
|
|
// NSVisualEffectView* view = [[_volumeWindow contentView] insertVibrancyViewBlendingMode:NSVisualEffectBlendingModeBehindWindow];
|
|
[[_volumeWindow contentView] insertVibrancyViewBlendingMode:NSVisualEffectBlendingModeBehindWindow];
|
|
|
|
NSView* volumeView = [_volumeWindow contentView];
|
|
|
|
[volumeView setWantsLayer:YES];
|
|
|
|
mainLayer = [volumeView layer];
|
|
CGColorRef backgroundColor=CGColorCreateGenericGray(0.00f, 0.00f);
|
|
[mainLayer setBackgroundColor:backgroundColor];
|
|
CFRelease(backgroundColor);
|
|
|
|
[mainLayer setCornerRadius:18];
|
|
[mainLayer setShouldRasterize:false];
|
|
[mainLayer setEdgeAntialiasingMask: kCALayerLeftEdge | kCALayerRightEdge | kCALayerBottomEdge | kCALayerTopEdge];
|
|
|
|
[mainLayer setOpacity:0.0f];
|
|
|
|
imgVolOn=[NSImage imageNamed:@"volume"];
|
|
imgVolOff=[NSImage imageNamed:@"volume-off"];
|
|
|
|
NSRect rect = NSZeroRect;
|
|
rect.size = [imgVolOff size];
|
|
|
|
volumeImageLayer = [CALayer layer];
|
|
[volumeImageLayer setFrame:NSRectToCGRect(rect)];
|
|
[volumeImageLayer setPosition:CGPointMake([volumeView frame].size.width/2, [volumeView frame].size.height/2+12)];
|
|
[volumeImageLayer setContents:imgVolOn];
|
|
|
|
iTunesIcon=[NSImage imageNamed:@"iTunes"];
|
|
|
|
rect = NSZeroRect;
|
|
rect.size = [iTunesIcon size];
|
|
|
|
iconLayer = [CALayer layer];
|
|
[iconLayer setFrame:NSRectToCGRect(rect)];
|
|
[iconLayer setPosition:CGPointMake([volumeImageLayer frame].size.width/2-26, [volumeImageLayer frame].size.height/2)];
|
|
//[iconLayer setPosition:CGPointMake([volumeView frame].size.width/2, [volumeView frame].size.height/2+12)];
|
|
[iconLayer setContents:iTunesIcon];
|
|
|
|
[volumeImageLayer addSublayer:iconLayer];
|
|
[mainLayer addSublayer:volumeImageLayer];
|
|
|
|
[self createVolumeBar];
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
-(void)awakeFromNib
|
|
{
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
-(void)completeInitialization
|
|
{
|
|
NSDictionary* infoDict = [[NSBundle mainBundle] infoDictionary];
|
|
NSString* version = [infoDict objectForKey:@"CFBundleShortVersionString"];
|
|
NSString * operatingSystemVersionString = [[NSProcessInfo processInfo] operatingSystemVersionString];
|
|
|
|
//[[SUUpdater sharedUpdater] setFeedURL:[NSURL URLWithString:[NSString stringWithFormat: @"http://quantum-technologies.iap.uni-bonn.de/alberti/iTunesVolumeControl/iTunesVolumeControlCast.xml.php?version=%@&osxversion=%@",version,[operatingSystemVersionString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]]]];
|
|
|
|
[[SUUpdater sharedUpdater] setFeedURL:[NSURL URLWithString:[NSString stringWithFormat: @"http://quantum-technologies.iap.uni-bonn.de/alberti/iTunesVolumeControl/VolumeControlCast.xml.php?version=%@&osxversion=%@",version,[operatingSystemVersionString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]]]];
|
|
|
|
|
|
[[SUUpdater sharedUpdater] setUpdateCheckInterval:60*60*24*7]; // look for new updates every 7 days
|
|
|
|
#ifdef OWN_WINDOW
|
|
[_volumeWindow orderOut:self];
|
|
// [_volumeWindow setLevel:NSFloatingWindowLevel];
|
|
[_volumeWindow setLevel:0x7d5];
|
|
#endif
|
|
|
|
// [self _loadBezelServices]; // El Capitan and probably older systems
|
|
[[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/OSD.framework"] load];
|
|
self->OSDManager = NSClassFromString(@"OSDManager");
|
|
|
|
//[self checkSIPforAppIdentifier:@"com.apple.iTunes" promptIfNeeded:YES];
|
|
//[self checkSIPforAppIdentifier:@"com.spotify.client" promptIfNeeded:YES];
|
|
|
|
if(osxVersion >= 115)
|
|
iTunes = [[PlayerApplication alloc] initWithBundleIdentifier:@"com.apple.Music"];
|
|
else
|
|
iTunes = [[PlayerApplication alloc] initWithBundleIdentifier:@"com.apple.iTunes"];
|
|
|
|
spotify = [[PlayerApplication alloc] initWithBundleIdentifier:@"com.spotify.client"];
|
|
|
|
// Force MacOS to ask for authorization to AppleEvents if this was not already given
|
|
if([iTunes isRunning])
|
|
[iTunes currentVolume];
|
|
if([spotify isRunning])
|
|
[spotify currentVolume];
|
|
|
|
systemAudio = [[SystemApplication alloc] initWithVersion:osxVersion];
|
|
|
|
[self showInStatusBar]; // Install icon into the menu bar
|
|
|
|
// NSString* iTunesVersion = [[NSString alloc] initWithString:[iTunes version]];
|
|
// NSString* spotifyVersion = [[NSString alloc] initWithString:[spotify version]];
|
|
|
|
// CGDisplayRegisterReconfigurationCallback(displayPreferencesChanged, NULL);
|
|
|
|
// Apple remote
|
|
// [self appleRemoteInit];
|
|
|
|
[self initializePreferences];
|
|
|
|
[self setStartAtLogin:[self StartAtLogin] savePreferences:false];
|
|
|
|
// if([self loadIntroAtStart])
|
|
// [self showIntroWindow:nil];
|
|
}
|
|
|
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
|
{
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(increaseITunesVolume:) name:@"IncreaseITunesVolume" object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(increaseITunesVolume:) name:@"IncreaseITunesVolumeRamp" object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(decreaseITunesVolume:) name:@"DecreaseITunesVolume" object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(decreaseITunesVolume:) name:@"DecreaseITunesVolumeRamp" object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(muteITunesVolume:) name:@"MuteITunesVolume" object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playPauseITunes:) name:@"PlayPauseITunes" object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(nextTrackITunes:) name:@"NextTrackITunes" object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(previousTrackITunes:) name:@"PreviousTrackITunes" object:nil];
|
|
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(displayResolutionChanged:) name:@"displayResolutionHasChanged" object:nil];
|
|
|
|
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
|
|
selector: @selector(receiveWakeNote:)
|
|
name: NSWorkspaceDidWakeNotification object: NULL];
|
|
|
|
signal(SIGTERM, handleSIGTERM);
|
|
|
|
extern CFStringRef kAXTrustedCheckOptionPrompt __attribute__((weak_import));
|
|
|
|
|
|
if( AXIsProcessTrustedWithOptions((__bridge CFDictionaryRef)@{(__bridge id)kAXTrustedCheckOptionPrompt: @NO}) && [self createEventTap] )
|
|
{
|
|
[self completeInitialization];
|
|
}
|
|
else
|
|
{
|
|
accessibilityDialog = [[AccessibilityDialog alloc] initWithWindowNibName:@"AccessibilityDialog"];
|
|
|
|
[accessibilityDialog showWindow:self];
|
|
}
|
|
}
|
|
|
|
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
|
|
{
|
|
[self showInStatusBar];
|
|
[self setHideFromStatusBar:[self hideFromStatusBar]];
|
|
if ([self hideFromStatusBar])
|
|
{
|
|
[self showHideFromStatusBarHintPopover];
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
- (void)showInStatusBar
|
|
{
|
|
if (![self statusBar])
|
|
{
|
|
// the status bar item needs a custom view so that we can show a NSPopover for the hide-from-status-bar hint
|
|
// the view now reacts to the mouseDown event to show the menu
|
|
|
|
_statusBar = [[NSStatusBar systemStatusBar] statusItemWithLength:26];
|
|
[_statusBar setMenu:_statusMenu];
|
|
}
|
|
|
|
if (!_statusBarItemView)
|
|
{
|
|
_statusBarItemView = [[StatusItemView alloc] initWithStatusItem:_statusBar];
|
|
}
|
|
|
|
[_statusBar setView:_statusBarItemView];
|
|
}
|
|
|
|
- (void)initializePreferences
|
|
{
|
|
preferences = [NSUserDefaults standardUserDefaults];
|
|
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
[NSNumber numberWithInt:2], @"volumeIncrement",
|
|
[NSNumber numberWithBool:true] , @"TappingEnabled",
|
|
//[NSNumber numberWithBool:false], @"AppleRemoteConnected",
|
|
[NSNumber numberWithBool:false], @"UseAppleCMDModifier",
|
|
[NSNumber numberWithBool:true], @"AutomaticUpdates",
|
|
[NSNumber numberWithBool:false], @"hideFromStatusBarPreference",
|
|
[NSNumber numberWithBool:false], @"hideVolumeWindowPreference",
|
|
[NSNumber numberWithBool:true], @"iTunesControl",
|
|
[NSNumber numberWithBool:true], @"spotifyControl",
|
|
[NSNumber numberWithBool:true], @"systemControl",
|
|
[NSNumber numberWithBool:true], @"loadIntroAtStart",
|
|
nil ]; // terminate the list
|
|
[preferences registerDefaults:dict];
|
|
|
|
// [self setAppleRemoteConnected:[preferences boolForKey: @"AppleRemoteConnected"]];
|
|
[self setTapping:[preferences boolForKey: @"TappingEnabled"]];
|
|
[self setUseAppleCMDModifier:[preferences boolForKey: @"UseAppleCMDModifier"]];
|
|
[self setAutomaticUpdates:[preferences boolForKey: @"AutomaticUpdates"]];
|
|
[self setHideFromStatusBar:[preferences boolForKey: @"hideFromStatusBarPreference"]];
|
|
[self setHideVolumeWindow:[preferences boolForKey: @"hideVolumeWindowPreference"]];
|
|
[[self iTunesBtn] setState:[preferences boolForKey: @"iTunesControl"]];
|
|
if(osxVersion >= 115)
|
|
{
|
|
[[self iTunesBtn] setTitle:@"Music"];
|
|
}
|
|
[[self iTunesBtn] setState:[preferences boolForKey: @"iTunesControl"]];
|
|
|
|
[[self spotifyBtn] setState:[preferences boolForKey: @"spotifyControl"]];
|
|
[[self systemBtn] setState:[preferences boolForKey: @"systemControl"]];
|
|
[self setLoadIntroAtStart:[preferences boolForKey: @"loadIntroAtStart"]];
|
|
|
|
NSInteger volumeIncSetting = [preferences integerForKey:@"volumeIncrement"];
|
|
[self setVolumeInc:volumeIncSetting];
|
|
|
|
[[self volumeIncrementsSlider] setIntegerValue: volumeIncSetting];
|
|
}
|
|
|
|
- (IBAction)toggleAutomaticUpdates:(id)sender
|
|
{
|
|
[self setAutomaticUpdates:![self AutomaticUpdates]];
|
|
}
|
|
|
|
- (void) setAutomaticUpdates:(bool)enabled
|
|
{
|
|
NSMenuItem* menuItem=[_statusMenu itemWithTag:6];
|
|
[menuItem setState:enabled];
|
|
|
|
[preferences setBool:enabled forKey:@"AutomaticUpdates"];
|
|
[preferences synchronize];
|
|
|
|
_AutomaticUpdates=enabled;
|
|
|
|
[[SUUpdater sharedUpdater] setAutomaticallyChecksForUpdates:enabled];
|
|
}
|
|
|
|
- (IBAction)toggleStartAtLogin:(id)sender
|
|
{
|
|
[self setStartAtLogin:![self StartAtLogin] savePreferences:true];
|
|
}
|
|
|
|
- (IBAction)toggleIntroAtStart:(id)sender
|
|
{
|
|
[self setLoadIntroAtStart:![self loadIntroAtStart]];
|
|
}
|
|
|
|
- (void)setLoadIntroAtStart:(bool)enabled
|
|
{
|
|
[preferences setBool:enabled forKey:@"loadIntroAtStart"];
|
|
[preferences synchronize];
|
|
|
|
_loadIntroAtStart=enabled;
|
|
}
|
|
|
|
// Appleremote
|
|
/*
|
|
- (void)setAppleRemoteConnected:(bool)enabled
|
|
{
|
|
NSMenuItem* menuItem=[_statusMenu itemWithTag:2];
|
|
[menuItem setState:enabled];
|
|
|
|
if(enabled && _Tapping)
|
|
{
|
|
[remote startListening:self];
|
|
}
|
|
else
|
|
{
|
|
[remote stopListening:self];
|
|
}
|
|
|
|
[preferences setBool:enabled forKey:@"AppleRemoteConnected"];
|
|
[preferences synchronize];
|
|
|
|
_AppleRemoteConnected=enabled;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
- (IBAction)toggleAppleRemote:(id)sender
|
|
{
|
|
[self setAppleRemoteConnected:![self AppleRemoteConnected]];
|
|
}
|
|
*/
|
|
|
|
- (void) setUseAppleCMDModifier:(bool)enabled
|
|
{
|
|
NSMenuItem* menuItem=[_statusMenu itemWithTag:3];
|
|
[menuItem setState:enabled];
|
|
|
|
[preferences setBool:enabled forKey:@"UseAppleCMDModifier"];
|
|
[preferences synchronize];
|
|
|
|
_UseAppleCMDModifier=enabled;
|
|
}
|
|
|
|
- (IBAction)toggleUseAppleCMDModifier:(id)sender
|
|
{
|
|
[self setUseAppleCMDModifier:![self UseAppleCMDModifier]];
|
|
}
|
|
|
|
- (void) setTapping:(bool)enabled
|
|
{
|
|
NSMenuItem* menuItem=[_statusMenu itemWithTag:1];
|
|
[menuItem setState:enabled];
|
|
|
|
CGEventTapEnable(eventTap, enabled);
|
|
|
|
if(enabled)
|
|
{
|
|
[_statusBarItemView setIconStatusBarIsGrayed:NO];
|
|
// Appleremote
|
|
// if([self AppleRemoteConnected]) [remote startListening:self];
|
|
}
|
|
else
|
|
{
|
|
[_statusBarItemView setIconStatusBarIsGrayed:YES];
|
|
// Appleremote
|
|
// [remote stopListening:self];
|
|
}
|
|
|
|
[preferences setBool:enabled forKey:@"TappingEnabled"];
|
|
[preferences synchronize];
|
|
|
|
_Tapping=enabled;
|
|
}
|
|
|
|
- (IBAction)toggleTapping:(id)sender
|
|
{
|
|
[self setTapping:![self Tapping]];
|
|
}
|
|
|
|
/*
|
|
- (IBAction)showIntroWindow:(id)sender
|
|
{
|
|
if(!introWindowController)
|
|
{
|
|
introWindowController = [[IntroWindowController alloc] initWithWindowNibName:@"IntroWindow"];
|
|
}
|
|
|
|
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
|
[introWindowController showWindow:self];
|
|
[[introWindowController window] makeKeyAndOrderFront:self];
|
|
}
|
|
*/
|
|
|
|
- (IBAction)sliderValueChanged:(NSSliderCell*)slider
|
|
{
|
|
NSInteger volumeIncSetting = [[self volumeIncrementsSlider] integerValue];
|
|
|
|
[self setVolumeInc:volumeIncSetting];
|
|
|
|
[preferences setInteger:volumeIncSetting forKey:@"volumeIncrement"];
|
|
[preferences synchronize];
|
|
|
|
}
|
|
|
|
- (void) setVolumeInc:(NSInteger)volumeIncSetting
|
|
{
|
|
switch(volumeIncSetting)
|
|
{
|
|
case 5:
|
|
increment = 25;
|
|
break;
|
|
case 4:
|
|
increment = 12.5;
|
|
break;
|
|
case 3:
|
|
increment = 6.25;
|
|
break;
|
|
case 2:
|
|
increment = 3.125;
|
|
break;
|
|
case 1:
|
|
default:
|
|
increment = 1.5625;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
- (IBAction)aboutPanel:(id)sender
|
|
{
|
|
NSDictionary* infoDict = [[NSBundle mainBundle] infoDictionary];
|
|
NSString* version = [infoDict objectForKey:@"CFBundleVersion"];
|
|
NSRange range=[version rangeOfString:@"." options:NSBackwardsSearch];
|
|
if(version>0) version=[version substringFromIndex:range.location+1];
|
|
|
|
infoDict = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
version,@"Version",
|
|
nil ]; // terminate the list
|
|
|
|
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
|
[[NSApplication sharedApplication] orderFrontStandardAboutPanelWithOptions:infoDict];
|
|
}
|
|
|
|
|
|
/*
|
|
- (void) displayResolutionChanged: (NSNotification*) note
|
|
{
|
|
// TODO test with the old operating system and check it is triggered when res is changed
|
|
NSRect screenFrame = [[NSScreen mainScreen] frame];
|
|
[_volumeWindow setFrame:(osxVersion<110? CGRectMake(round((screenFrame.size.width-210)/2),139,210,206) : CGRectMake(round((screenFrame.size.width-200)/2),140,200,200)) display:NO animate:NO];
|
|
}
|
|
*/
|
|
|
|
- (void) receiveWakeNote: (NSNotification*) note
|
|
{
|
|
[self setTapping:[self Tapping]];
|
|
[_statusBarItemView setAppropriateColorScheme];
|
|
|
|
// Apple remote
|
|
// [self setAppleRemoteConnected:[self AppleRemoteConnected]];
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
|
|
}
|
|
|
|
#ifdef OWN_WINDOW
|
|
|
|
- (void) showSpeakerImg:(NSTimer*)theTimer
|
|
{
|
|
[_volumeWindow orderFront:self];
|
|
|
|
fadeInAnimationReady=false;
|
|
[mainLayer addAnimation:fadeInAnimation forKey:@"increaseOpacity"];
|
|
}
|
|
|
|
- (void) hideSpeakerImg:(NSTimer*)theTimer
|
|
{
|
|
[CATransaction begin]; {
|
|
[CATransaction setCompletionBlock:^{
|
|
[self->_volumeWindow orderOut:self];
|
|
self->fadeInAnimationReady=true;
|
|
}];
|
|
[mainLayer addAnimation:fadeOutAnimation forKey:@"decreaseOpacity"];
|
|
} [CATransaction commit];
|
|
}
|
|
|
|
#endif
|
|
|
|
-(void)resetEventTap
|
|
{
|
|
CGEventTapEnable(eventTap, _Tapping);
|
|
}
|
|
|
|
- (IBAction)increaseVol:(id)sender
|
|
{
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"IncreaseITunesVolume" object:NULL];
|
|
|
|
}
|
|
|
|
- (id)runningPlayer
|
|
{
|
|
id musicPlayerPnt = nil;
|
|
|
|
if(_AppleCMDModifierPressed == _UseAppleCMDModifier)
|
|
{
|
|
if([_iTunesBtn state] && [iTunes isRunning] && [iTunes playerState] == iTunesEPlSPlaying)
|
|
{
|
|
musicPlayerPnt = iTunes;
|
|
}
|
|
else if([_spotifyBtn state] && [spotify isRunning] && [spotify playerState] == SpotifyEPlSPlaying)
|
|
{
|
|
musicPlayerPnt = spotify;
|
|
}
|
|
else if([_systemBtn state])
|
|
{
|
|
musicPlayerPnt = systemAudio;
|
|
}
|
|
}
|
|
else
|
|
musicPlayerPnt = systemAudio;
|
|
|
|
return musicPlayerPnt;
|
|
}
|
|
|
|
- (void)changeVol:(bool)increase
|
|
{
|
|
id musicPlayerPnt = [self runningPlayer];
|
|
|
|
if (musicPlayerPnt != nil)
|
|
{
|
|
double volume = [musicPlayerPnt currentVolume];
|
|
|
|
if([musicPlayerPnt oldVolume]<0) // if it was not mute
|
|
{
|
|
//volume=[musicProgramPnt soundVolume]+_volumeInc*(increase?1:-1);
|
|
volume += (increase?1:-1)*increment;
|
|
}
|
|
else // if it was mute
|
|
{
|
|
// [volumeImageLayer setContents:imgVolOn]; // restore the image of the speaker from mute speaker
|
|
volume=[musicPlayerPnt oldVolume];
|
|
[musicPlayerPnt setOldVolume:-1]; // this says that it is not mute
|
|
}
|
|
if (volume<0) volume=0;
|
|
if (volume>100) volume=100;
|
|
|
|
/*
|
|
NSInteger i = 0;
|
|
double diff1 = abs(100);
|
|
double diff2;
|
|
|
|
for (NSInteger j = 1; j < numPos; j++ ) {
|
|
diff2 = fabs(volume - (double)positions[j]);
|
|
if ( diff2<diff1 )
|
|
{
|
|
diff1 = diff2;
|
|
i = j;
|
|
}
|
|
}
|
|
*/
|
|
|
|
OSDGraphic image = (volume > 0)? OSDGraphicSpeaker : OSDGraphicSpeakerMute;
|
|
|
|
NSInteger numFullBlks = floor(volume/6.25);
|
|
NSInteger numQrtsBlks = round((volume-(double)numFullBlks*6.25)/1.5625);
|
|
|
|
//NSLog(@"%d %d",(int)numFullBlks,(int)numQrtsBlks);
|
|
|
|
if(!_hideVolumeWindow)
|
|
[[self->OSDManager sharedManager] showImage:image onDisplayID:CGSMainDisplayID() priority:OSDPriorityDefault msecUntilFade:1000 filledChiclets:(unsigned int)(round(((numFullBlks*4+numQrtsBlks)*1.5625)*100)) totalChiclets:(unsigned int)10000 locked:NO];
|
|
|
|
[musicPlayerPnt setCurrentVolume:volume];
|
|
|
|
if([_statusBarItemView menuIsVisible])
|
|
{
|
|
if( musicPlayerPnt == iTunes)
|
|
[self setItunesVolume:volume];
|
|
else if( musicPlayerPnt == spotify)
|
|
[self setSpotifyVolume:volume];
|
|
else if( musicPlayerPnt == systemAudio)
|
|
[self setSystemVolume:volume];
|
|
}
|
|
[self refreshVolumeBar:(int)volume];
|
|
}
|
|
}
|
|
|
|
- (void) setItunesVolume:(NSInteger)volume
|
|
{
|
|
if (volume == -1)
|
|
[[self iTunesPerc] setHidden:YES];
|
|
else
|
|
{
|
|
[[self iTunesPerc] setHidden:NO];
|
|
[[self iTunesPerc] setStringValue:[NSString stringWithFormat:@"(%d%%)",(int)volume]];
|
|
}
|
|
}
|
|
|
|
- (void) setSpotifyVolume:(NSInteger)volume
|
|
{
|
|
if (volume == -1)
|
|
[[self spotifyPerc] setHidden:YES];
|
|
else
|
|
{
|
|
[[self spotifyPerc] setHidden:NO];
|
|
[[self spotifyPerc] setStringValue:[NSString stringWithFormat:@"(%d%%)",(int)volume]];
|
|
}
|
|
}
|
|
|
|
- (void) setSystemVolume:(NSInteger)volume
|
|
{
|
|
if (volume == -1)
|
|
[[self systemPerc] setHidden:YES];
|
|
else
|
|
{
|
|
[[self systemPerc] setHidden:NO];
|
|
[[self systemPerc] setStringValue:[NSString stringWithFormat:@"(%d%%)",(int)volume]];
|
|
}
|
|
|
|
}
|
|
|
|
- (void) updatePercentages
|
|
{
|
|
if([iTunes isRunning])
|
|
[self setItunesVolume:[iTunes currentVolume]];
|
|
else
|
|
[self setItunesVolume:-1];
|
|
|
|
if([spotify isRunning])
|
|
[self setSpotifyVolume:[spotify currentVolume]];
|
|
else
|
|
[self setSpotifyVolume:-1];
|
|
|
|
[self setSystemVolume:[systemAudio currentVolume]];
|
|
}
|
|
|
|
- (void) createVolumeBar
|
|
{
|
|
|
|
CALayer* background;
|
|
int i;
|
|
|
|
/*
|
|
for(i=0; i<16; i++)
|
|
{
|
|
background = [CALayer layer];
|
|
[background setFrame:CGRectMake(9*i+32, 29.0, 7.0, 9.0)];
|
|
[background setBackgroundColor:CGColorCreateGenericRGB(0.f, 0.f, 0.f, 0.5f)];
|
|
|
|
[mainLayer addSublayer:background];
|
|
}
|
|
|
|
*/
|
|
|
|
background = [CALayer layer];
|
|
[background setFrame:CGRectMake(20.0, 20, 160.0, 8.0)];
|
|
[background setBackgroundColor:CGColorCreateGenericRGB(0.f, 0.f, 0.f, 0.5f)];
|
|
|
|
[mainLayer addSublayer:background];
|
|
|
|
for(i=0; i<16; i++)
|
|
{
|
|
volumeBar[i] = [CALayer layer];
|
|
[volumeBar[i] setFrame:CGRectMake(10*i+21, 21.0, 9.0, 6.0)];
|
|
[volumeBar[i] setBackgroundColor:CGColorCreateGenericRGB(1.0f, 1.0f, 1.0f, 1.0f)];
|
|
|
|
/*
|
|
[volumeBar[i] setShadowOffset:CGSizeMake(-1, -1)];
|
|
[volumeBar[i] setShadowRadius:1.0];
|
|
[volumeBar[i] setShadowColor:CGColorCreateGenericRGB(0.f, 0.f, 0.f, 1.0f)];
|
|
[volumeBar[i] setShadowOpacity:0.5];
|
|
*/
|
|
|
|
[volumeBar[i] setHidden:YES];
|
|
|
|
[mainLayer addSublayer:volumeBar[i]];
|
|
}
|
|
|
|
}
|
|
|
|
- (void) refreshVolumeBar:(NSInteger)volume
|
|
{
|
|
NSInteger doubleFullRectangles = (NSInteger)round(32.0f * volume / 100.0f);
|
|
NSInteger fullRectangles=doubleFullRectangles>>1;
|
|
|
|
[CATransaction begin];
|
|
[CATransaction setAnimationDuration: 0.0];
|
|
[CATransaction setDisableActions: TRUE];
|
|
|
|
if(volume==0)
|
|
{
|
|
[volumeImageLayer setContents:imgVolOff];
|
|
}
|
|
else
|
|
{
|
|
[volumeImageLayer setContents:imgVolOn];
|
|
}
|
|
|
|
CGRect frame;
|
|
|
|
for(NSInteger i=0; i<fullRectangles; i++)
|
|
{
|
|
frame = [volumeBar[i] frame];
|
|
frame.size.width=9;
|
|
[volumeBar[i] setFrame:frame];
|
|
|
|
[volumeBar[i] setHidden:NO];
|
|
}
|
|
for(NSInteger i=fullRectangles; i<16; i++)
|
|
{
|
|
frame = [volumeBar[i] frame];
|
|
frame.size.width=9;
|
|
[volumeBar[i] setFrame:frame];
|
|
|
|
[volumeBar[i] setHidden:YES];
|
|
}
|
|
|
|
if(fullRectangles*2 != doubleFullRectangles)
|
|
{
|
|
|
|
frame = [volumeBar[fullRectangles] frame];
|
|
frame.size.width=5;
|
|
|
|
[volumeBar[fullRectangles] setFrame:frame];
|
|
[volumeBar[fullRectangles] setHidden:NO];
|
|
}
|
|
|
|
[CATransaction commit];
|
|
}
|
|
|
|
#ifdef OWN_WINDOW
|
|
- (void) displayVolumeBar
|
|
{
|
|
if(fadeInAnimationReady) [self showSpeakerImg:nil];
|
|
if(timerImgSpeaker) {[timerImgSpeaker invalidate]; timerImgSpeaker=nil;}
|
|
timerImgSpeaker=[NSTimer scheduledTimerWithTimeInterval:waitOverlayPanel target:self selector:@selector(hideSpeakerImg:) userInfo:nil repeats:NO];
|
|
[[NSRunLoop mainRunLoop] addTimer:timerImgSpeaker forMode:NSRunLoopCommonModes];
|
|
}
|
|
#endif
|
|
|
|
|
|
#pragma mark - Hide From Status Bar
|
|
|
|
- (IBAction)toggleHideFromStatusBar:(id)sender
|
|
{
|
|
[self setHideFromStatusBar:![self hideFromStatusBar]];
|
|
if ([self hideFromStatusBar])
|
|
[self showHideFromStatusBarHintPopover];
|
|
}
|
|
|
|
- (void)setHideFromStatusBar:(bool)enabled
|
|
{
|
|
_hideFromStatusBar=enabled;
|
|
|
|
NSMenuItem* menuItem=[_statusMenu itemWithTag:5];
|
|
[menuItem setState:[self hideFromStatusBar]];
|
|
|
|
[preferences setBool:enabled forKey:@"hideFromStatusBarPreference"];
|
|
[preferences synchronize];
|
|
|
|
if(enabled)
|
|
{
|
|
if (![_statusBarHideTimer isValid] && [self statusBar])
|
|
{
|
|
[self setHideFromStatusBarHintLabelWithSeconds:statusBarHideDelay];
|
|
_statusBarHideTimer = [NSTimer scheduledTimerWithTimeInterval:statusBarHideDelay target:self selector:@selector(doHideFromStatusBar:) userInfo:nil repeats:NO];
|
|
[[NSRunLoop mainRunLoop] addTimer:_statusBarHideTimer forMode:NSRunLoopCommonModes];
|
|
_hideFromStatusBarHintPopoverUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateHideFromStatusBarHintPopover:) userInfo:nil repeats:YES];
|
|
[[NSRunLoop mainRunLoop] addTimer:_hideFromStatusBarHintPopoverUpdateTimer forMode:NSRunLoopCommonModes];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
[_hideFromStatusBarHintPopover close];
|
|
[_statusBarHideTimer invalidate];
|
|
_statusBarHideTimer = nil;
|
|
[_hideFromStatusBarHintPopoverUpdateTimer invalidate];
|
|
_hideFromStatusBarHintPopoverUpdateTimer = nil;
|
|
}
|
|
}
|
|
|
|
- (void)doHideFromStatusBar:(NSTimer*)aTimer
|
|
{
|
|
[_hideFromStatusBarHintPopoverUpdateTimer invalidate];
|
|
_hideFromStatusBarHintPopoverUpdateTimer = nil;
|
|
_statusBarHideTimer = nil;
|
|
[_hideFromStatusBarHintPopover close];
|
|
[[NSStatusBar systemStatusBar] removeStatusItem:[self statusBar]];
|
|
_statusBar = nil;
|
|
|
|
[self setHideFromStatusBar:true];
|
|
}
|
|
|
|
- (void)showHideFromStatusBarHintPopover
|
|
{
|
|
if ([_hideFromStatusBarHintPopover isShown]) return;
|
|
|
|
if (! _hideFromStatusBarHintPopover)
|
|
{
|
|
CGRect popoverRect = (CGRect) {
|
|
.size.width = 225,
|
|
.size.height = 50
|
|
};
|
|
|
|
_hideFromStatusBarHintLabel = [[NSTextField alloc] initWithFrame:CGRectInset(popoverRect, 10, 10)];
|
|
[_hideFromStatusBarHintLabel setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
|
|
[_hideFromStatusBarHintLabel setEditable:false];
|
|
[_hideFromStatusBarHintLabel setSelectable:false];
|
|
[_hideFromStatusBarHintLabel setBezeled:false];
|
|
[_hideFromStatusBarHintLabel setBackgroundColor:[NSColor clearColor]];
|
|
[_hideFromStatusBarHintLabel setAlignment:NSTextAlignmentCenter];
|
|
|
|
_hintView = [[NSView alloc] initWithFrame:popoverRect];
|
|
[_hintView addSubview:_hideFromStatusBarHintLabel];
|
|
|
|
_hintVC = [[NSViewController alloc] init];
|
|
[_hintVC setView:_hintView];
|
|
|
|
_hideFromStatusBarHintPopover = [[NSPopover alloc] init];
|
|
[_hideFromStatusBarHintPopover setContentViewController:_hintVC];
|
|
}
|
|
|
|
[_hideFromStatusBarHintPopover showRelativeToRect:[_statusBarItemView frame] ofView:_statusBarItemView preferredEdge:NSMinYEdge];
|
|
}
|
|
|
|
- (void)updateHideFromStatusBarHintPopover:(NSTimer*)aTimer
|
|
{
|
|
NSDate* now = [NSDate date];
|
|
[self setHideFromStatusBarHintLabelWithSeconds:[[_statusBarHideTimer fireDate] timeIntervalSinceDate:now]];
|
|
}
|
|
|
|
- (void)setHideFromStatusBarHintLabelWithSeconds:(NSUInteger)seconds
|
|
{
|
|
[_hideFromStatusBarHintLabel setStringValue:[NSString stringWithFormat:@"iTunes Volume Control will hide after %ld seconds.\n\nLaunch it again to re-show the icon.",seconds]];
|
|
}
|
|
|
|
#pragma mark - Music players
|
|
|
|
- (IBAction)toggleMusicPlayer:(id)sender
|
|
{
|
|
if (sender == _iTunesBtn) {
|
|
[preferences setBool:[sender state] forKey:@"iTunesControl"];
|
|
}
|
|
else if (sender == _spotifyBtn)
|
|
{
|
|
[preferences setBool:[sender state] forKey:@"spotifyControl"];
|
|
}
|
|
else if (sender == _systemBtn)
|
|
{
|
|
[preferences setBool:[sender state] forKey:@"systemControl"];
|
|
}
|
|
[preferences synchronize];
|
|
}
|
|
|
|
#pragma mark - NSMenuDelegate
|
|
|
|
- (IBAction)toggleHideVolumeWindow:(id)sender
|
|
{
|
|
[self setHideVolumeWindow:![self hideVolumeWindow]];
|
|
}
|
|
|
|
- (void)setHideVolumeWindow:(bool)enabled
|
|
{
|
|
_hideVolumeWindow=enabled;
|
|
|
|
NSMenuItem* menuItem=[_statusMenu itemWithTag:6];
|
|
[menuItem setState:[self hideVolumeWindow]];
|
|
|
|
[preferences setBool:enabled forKey:@"hideVolumeWindowPreference"];
|
|
[preferences synchronize];
|
|
}
|
|
|
|
|
|
- (void)menuWillOpen:(NSMenu *)menu
|
|
{
|
|
[_statusBarItemView setMenuIsVisible:true];
|
|
[_hideFromStatusBarHintPopover close];
|
|
}
|
|
|
|
- (void)menuDidClose:(NSMenu *)menu
|
|
{
|
|
[_statusBarItemView setMenuIsVisible:false];
|
|
if ([self hideFromStatusBar])
|
|
[self showHideFromStatusBarHintPopover];
|
|
}
|
|
|
|
@end
|