Skip to content
This repository
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 105 lines (80 sloc) 3.405 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
//
// ToggleBluetoothAction.m
// ControlPlane
//
// Created by David Symonds on 1/05/07.
//

#import "ToggleBluetoothAction.h"
#import <IOBluetooth/objc/IOBluetoothHostController.h>

// requires IOBluetooth.framework
int IOBluetoothPreferenceGetControllerPowerState(void);
void IOBluetoothPreferenceSetControllerPowerState(int);


@implementation ToggleBluetoothAction

- (NSString *)description
{
if (turnOn)
return NSLocalizedString(@"Turning Bluetooth on.", @"");
else
return NSLocalizedString(@"Turning Bluetooth off.", @"");
}

// IOBluetooth.framework is not thread-safe, so all IOBluetooth calls need to be done in the main thread.
- (void)setPowerState
{
IOBluetoothPreferenceSetControllerPowerState(turnOn ? 1 : 0);

}

- (BOOL)execute:(NSString **)errorString
{
int state = (turnOn ? 1 : 0);
    int i = 0;
    IOBluetoothHostController *hostController = [IOBluetoothHostController defaultController];

    
    // IOBluetoothPreferenceGetControllerPowerState but
    // there definitely needs to be some amount of time between
    // when the bluetooth controller is enabled or disabled
    // to when you attempt to get the bluetooth conroller's power state
    // ControlPlane attempts to sleep here for 5 seconds to give bluetooth
    // some time to settle. This check was originally done on the main thread
    // but ControlPlane shouldn't block the main thread for that long
    // so it was moved here, hopefully it doesn't cause harm.
    
    // this and more is "documented" at http://dmaclach.blogspot.com/2010/10/its-dead-jim.html
    // and https://github.com/dustinrue/ControlPlane/issues/11, thanks to David Jennes for finding
    // this tip. This will still cause an error should the bluetooth controller take more than
// the mentioned 5 seconds to switch, generating a delayed error notification (Growl)

    
    // It's been reported more than once that BT will fail to enable or disable under certain
    // circumstances. In an attempt to make this a bit more reliable while simulaneously putting
    // in the least amount of effort, ControlPlane simply tries to get the Bluetooth
    // host controller into the desired state a few times.
    
    
    setState = -1;
    
    // try 5 times to change the bluetooth controller state
    while (state != setState && i < 5) {
        [self performSelectorOnMainThread:@selector(setPowerState) withObject:nil waitUntilDone:YES];
        [NSThread sleepForTimeInterval:2];
        setState = hostController.powerState;
        i++;
    }
    
    
if (state != setState) {
if (turnOn)
*errorString = NSLocalizedString(@"Failed turning Bluetooth on.", @"");
else
*errorString = NSLocalizedString(@"Failed turning Bluetooth off.", @"");
return NO;
}

    
    NSLog(@"Successfully toggled bluetooth after %d %@", i, (i > 1) ? @"tries":@"try");
return YES;
}

+ (NSString *)helpText
{
return NSLocalizedString(@"The parameter for ToggleBluetooth actions is either \"1\" "
"or \"0\", depending on whether you want your Bluetooth controller's power "
"turned on or off.", @"");
}

+ (NSString *)creationHelpText
{
return NSLocalizedString(@"Turn Bluetooth", @"Will be followed by 'on' or 'off'");
}

+ (NSString *) friendlyName {
    return NSLocalizedString(@"Toggle Bluetooth", @"");
}

+ (NSString *)menuCategory {
    return NSLocalizedString(@"System Preferences", @"");
}
@end
Something went wrong with that request. Please try again.