Extras/HardwareGrowler/AppController.m
author diggory
Mon Jul 07 19:34:48 2008 +0000 (2008-07-07)
changeset 4144 c78b283d2fca
parent 3851 2185cda12bfa
child 4204 2564276c9d5c
permissions -rw-r--r--
HardwareGrowler now shows appropriate icons for Airport and Network events - the older ones no longer exist on more recent systems.
diggory@1255
     1
#import "AppController.h"
ingmarstein@2619
     2
#include <IOKit/IOKitLib.h>
ingmarstein@2619
     3
#include <IOKit/IOMessage.h>
ingmarstein@2619
     4
#include <IOKit/pwr_mgt/IOPMLib.h>
ingmarstein@3141
     5
#include <CFGrowlAdditions.h>
ingmarstein@2619
     6
#include "FireWireNotifier.h"
ingmarstein@2619
     7
#include "USBNotifier.h"
ingmarstein@2619
     8
#include "BluetoothNotifier.h"
ingmarstein@2619
     9
#include "VolumeNotifier.h"
ingmarstein@2619
    10
#include "NetworkNotifier.h"
ingmarstein@2619
    11
#include "SyncNotifier.h"
evands@3121
    12
#include "PowerNotifier.h"
diggory@1255
    13
evands@3780
    14
#define NotifierUSBConnectionNotification				@"USB Device Connected"
evands@3780
    15
#define NotifierUSBDisconnectionNotification			@"USB Device Disconnected"
evands@3780
    16
#define NotifierVolumeMountedNotification				@"Volume Mounted"
evands@3780
    17
#define NotifierVolumeUnmountedNotification				@"Volume Unmounted"
evands@3780
    18
#define NotifierBluetoothConnectionNotification			@"Bluetooth Device Connected"
evands@3780
    19
#define NotifierBluetoothDisconnectionNotification		@"Bluetooth Device Disconnected"
evands@3780
    20
#define NotifierFireWireConnectionNotification			@"FireWire Device Connected"
evands@3780
    21
#define NotifierFireWireDisconnectionNotification		@"FireWire Device Disconnected"
evands@3780
    22
#define NotifierNetworkLinkUpNotification				@"Network Link Up"
evands@3780
    23
#define NotifierNetworkLinkDownNotification				@"Network Link Down"
evands@3780
    24
#define NotifierNetworkIpAcquiredNotification			@"IP Acquired"
evands@3780
    25
#define NotifierNetworkIpReleasedNotification			@"IP Released"
evands@3780
    26
#define NotifierNetworkAirportConnectNotification		@"AirPort Connected"
evands@3780
    27
#define NotifierNetworkAirportDisconnectNotification	@"AirPort Disconnected"
evands@3780
    28
#define NotifierSyncStartedNotification					@"Sync started"
evands@3780
    29
#define NotifierSyncFinishedNotification				@"Sync finished"
evands@3780
    30
#define NotifierPowerOnACNotification					@"Switched to A/C Power"
evands@3780
    31
#define NotifierPowerOnBatteryNotification				@"Switched to Battery Power"
evands@3780
    32
#define NotifierPowerOnUPSNotification					@"Switched to UPS Power"
evands@3780
    33
evands@3780
    34
#define NotifierUSBConnectionHumanReadableDescription				NSLocalizedString(@"USB Device Connected", "")
evands@3780
    35
#define NotifierUSBDisconnectionHumanReadableDescription			NSLocalizedString(@"USB Device Disconnected", "")
evands@3780
    36
#define NotifierVolumeMountedHumanReadableDescription				NSLocalizedString(@"Volume Mounted", "")
evands@3780
    37
#define NotifierVolumeUnmountedHumanReadableDescription				NSLocalizedString(@"Volume Unmounted", "")
evands@3780
    38
#define NotifierBluetoothConnectionHumanReadableDescription			NSLocalizedString(@"Bluetooth Device Connected", "")
evands@3780
    39
#define NotifierBluetoothDisconnectionHumanReadableDescription		NSLocalizedString(@"Bluetooth Device Disconnected", "")
evands@3780
    40
#define NotifierFireWireConnectionHumanReadableDescription			NSLocalizedString(@"FireWire Device Connected", "")
evands@3780
    41
#define NotifierFireWireDisconnectionHumanReadableDescription		NSLocalizedString(@"FireWire Device Disconnected", "")
evands@3780
    42
#define NotifierNetworkLinkUpHumanReadableDescription				NSLocalizedString(@"Network Link Up", "")
evands@3780
    43
#define NotifierNetworkLinkDownHumanReadableDescription				NSLocalizedString(@"Network Link Down", "")
evands@3780
    44
#define NotifierNetworkIpAcquiredHumanReadableDescription			NSLocalizedString(@"IP Acquired", "")
evands@3780
    45
#define NotifierNetworkIpReleasedHumanReadableDescription			NSLocalizedString(@"IP Released", "")
evands@3780
    46
#define NotifierNetworkAirportConnectHumanReadableDescription		NSLocalizedString(@"AirPort Connected", "")
evands@3780
    47
#define NotifierNetworkAirportDisconnectHumanReadableDescription	NSLocalizedString(@"AirPort Disconnected", "")
evands@3780
    48
#define NotifierSyncStartedHumanReadableDescription					NSLocalizedString(@"Sync started", "")
evands@3780
    49
#define NotifierSyncFinishedHumanReadableDescription				NSLocalizedString(@"Sync finished", "")
evands@3780
    50
#define NotifierPowerOnACHumanReadableDescription					NSLocalizedString(@"Switched to A/C Power", "")
evands@3780
    51
#define NotifierPowerOnBatteryHumanReadableDescription				NSLocalizedString(@"Switched to Battery Power", "")
evands@3780
    52
#define NotifierPowerOnUPSHumanReadableDescription					NSLocalizedString(@"Switched to UPS Power", "")
evands@3780
    53
ingmarstein@2623
    54
ingmarstein@2623
    55
#define NotifierFireWireConnectionTitle()				CFCopyLocalizedString(CFSTR("FireWire Connection"), "")
ingmarstein@2623
    56
#define NotifierFireWireDisconnectionTitle()			CFCopyLocalizedString(CFSTR("FireWire Disconnection"), "")
ingmarstein@2623
    57
#define NotifierUSBConnectionTitle()					CFCopyLocalizedString(CFSTR("USB Connection"), "")
ingmarstein@2623
    58
#define NotifierUSBDisconnectionTitle()					CFCopyLocalizedString(CFSTR("USB Disconnection"), "")
ingmarstein@2623
    59
#define NotifierBluetoothConnectionTitle()				CFCopyLocalizedString(CFSTR("Bluetooth Connection"), "")
ingmarstein@2623
    60
#define NotifierBluetoothDisconnectionTitle()			CFCopyLocalizedString(CFSTR("Bluetooth Disconnection"), "")
ingmarstein@2623
    61
#define NotifierVolumeMountedTitle()					CFCopyLocalizedString(CFSTR("Volume Mounted"), "")
ingmarstein@2623
    62
#define NotifierVolumeUnmountedTitle()					CFCopyLocalizedString(CFSTR("Volume Unmounted"), "")
ingmarstein@2623
    63
#define NotifierNetworkAirportConnectTitle()			CFCopyLocalizedString(CFSTR("Airport connected"), "")
ingmarstein@2623
    64
#define NotifierNetworkAirportDisconnectTitle()			CFCopyLocalizedString(CFSTR("Airport disconnected"), "")
ingmarstein@2623
    65
#define NotifierNetworkLinkUpTitle()					CFCopyLocalizedString(CFSTR("Ethernet activated"), "")
ingmarstein@2623
    66
#define NotifierNetworkLinkDownTitle()					CFCopyLocalizedString(CFSTR("Ethernet deactivated"), "")
ingmarstein@2623
    67
#define NotifierNetworkIpAcquiredTitle()				CFCopyLocalizedString(CFSTR("IP address acquired"), "")
ingmarstein@2623
    68
#define NotifierNetworkIpReleasedTitle()				CFCopyLocalizedString(CFSTR("IP address released"), "")
ingmarstein@2623
    69
#define NotifierSyncStartedTitle()						CFCopyLocalizedString(CFSTR("Sync started"), "")
ingmarstein@2623
    70
#define NotifierSyncFinishedTitle()						CFCopyLocalizedString(CFSTR("Sync finished"), "")
ingmarstein@2623
    71
ingmarstein@2623
    72
#define NotifierNetworkAirportDisconnectDescription()	CFCopyLocalizedString(CFSTR("Left network %@."), "")
ingmarstein@3139
    73
#define NotifierNetworkIpAcquiredDescription()			CFCopyLocalizedString(CFSTR("New primary IP: %@ (%@)"), "")
ingmarstein@2623
    74
#define NotifierNetworkIpReleasedDescription()			CFCopyLocalizedString(CFSTR("No IP address now"), "")
ingmarstein@2394
    75
ingmarstein@2619
    76
static io_connect_t			powerConnection;
ingmarstein@2619
    77
static io_object_t			powerNotifier;
ingmarstein@2619
    78
static CFRunLoopSourceRef	powerRunLoopSource;
ingmarstein@2619
    79
static BOOL					sleeping;
ingmarstein@2608
    80
ingmarstein@3141
    81
#pragma mark Icons
ingmarstein@3141
    82
ingmarstein@3141
    83
static CFDataRef firewireLogo(void)
ingmarstein@3141
    84
{
ingmarstein@3141
    85
	static CFDataRef firewireLogoData = NULL;
ingmarstein@3141
    86
	char imagePath[PATH_MAX];
ingmarstein@3141
    87
ingmarstein@3141
    88
	if (!firewireLogoData) {
ingmarstein@3141
    89
		CFURLRef imageURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
ingmarstein@3141
    90
												 CFSTR("FireWireLogo"),
ingmarstein@3141
    91
												 CFSTR("png"),
ingmarstein@3141
    92
												 /*subDirName*/ NULL);
ingmarstein@3141
    93
		if (CFURLGetFileSystemRepresentation(imageURL, false, (UInt8 *)imagePath, sizeof(imagePath)))
ingmarstein@3141
    94
			firewireLogoData = (CFDataRef)readFile(imagePath);
ingmarstein@3141
    95
		CFRelease(imageURL);
ingmarstein@3141
    96
	}
ingmarstein@3141
    97
ingmarstein@3141
    98
	return firewireLogoData;
ingmarstein@3141
    99
}
ingmarstein@3141
   100
ingmarstein@3141
   101
static CFDataRef usbLogo(void)
ingmarstein@3141
   102
{
ingmarstein@3141
   103
	static CFDataRef usbLogoData = NULL;
ingmarstein@3141
   104
	char imagePath[PATH_MAX];
ingmarstein@3141
   105
ingmarstein@3141
   106
	if (!usbLogoData) {
ingmarstein@3141
   107
		CFURLRef imageURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
ingmarstein@3141
   108
													CFSTR("usbLogoWhite"),
ingmarstein@3141
   109
													CFSTR("png"),
ingmarstein@3141
   110
													/*subDirName*/ NULL);
ingmarstein@3141
   111
		if (CFURLGetFileSystemRepresentation(imageURL, false, (UInt8 *)imagePath, sizeof(imagePath)))
ingmarstein@3141
   112
			usbLogoData = (CFDataRef)readFile(imagePath);
ingmarstein@3141
   113
		CFRelease(imageURL);
ingmarstein@3141
   114
	}
ingmarstein@3141
   115
ingmarstein@3141
   116
	return usbLogoData;
ingmarstein@3141
   117
}
ingmarstein@3141
   118
ingmarstein@3141
   119
static CFDataRef bluetoothLogo(void)
ingmarstein@3141
   120
{
ingmarstein@3141
   121
	static CFDataRef bluetoothLogoData = NULL;
ingmarstein@3141
   122
	char imagePath[PATH_MAX];
ingmarstein@3141
   123
ingmarstein@3141
   124
	if (!bluetoothLogoData) {
ingmarstein@3141
   125
		CFURLRef imageURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
ingmarstein@3141
   126
													CFSTR("BluetoothLogo"),
ingmarstein@3141
   127
													CFSTR("png"),
ingmarstein@3141
   128
													/*subDirName*/ NULL);
ingmarstein@3141
   129
		if (CFURLGetFileSystemRepresentation(imageURL, false, (UInt8 *)imagePath, sizeof(imagePath)))
ingmarstein@3141
   130
			bluetoothLogoData = (CFDataRef)readFile(imagePath);
ingmarstein@3141
   131
		CFRelease(imageURL);
ingmarstein@3141
   132
	}
ingmarstein@3141
   133
ingmarstein@3141
   134
	return bluetoothLogoData;
ingmarstein@3141
   135
}
ingmarstein@3141
   136
ingmarstein@3141
   137
static CFDataRef airportIcon(void)
ingmarstein@3141
   138
{
ingmarstein@3141
   139
	static CFDataRef airportIconData = NULL;
ingmarstein@3141
   140
ingmarstein@3141
   141
	if (!airportIconData) {
diggory@4144
   142
		CFURLRef appURL = (CFURLRef)copyURLForApplication(@"Airport Utility.app");
ingmarstein@3141
   143
		if (appURL) {
ingmarstein@3141
   144
			airportIconData = (CFDataRef)copyIconDataForURL((NSURL *)appURL);
ingmarstein@3141
   145
			CFRelease(appURL);
diggory@4144
   146
		} else {
diggory@4144
   147
			appURL = (CFURLRef)copyURLForApplication(@"Airport Admin Utility.app");
diggory@4144
   148
			if (appURL) {
diggory@4144
   149
				airportIconData = (CFDataRef)copyIconDataForURL((NSURL *)appURL);
diggory@4144
   150
				CFRelease(appURL);
diggory@4144
   151
			}			
ingmarstein@3141
   152
		}
ingmarstein@3141
   153
	}
ingmarstein@3141
   154
ingmarstein@3141
   155
	return airportIconData;
ingmarstein@3141
   156
}
ingmarstein@3141
   157
ingmarstein@3141
   158
static CFDataRef ipIcon(void)
ingmarstein@3141
   159
{
ingmarstein@3141
   160
	static CFDataRef ipIconData = NULL;
ingmarstein@3141
   161
ingmarstein@3141
   162
	if (!ipIconData) {
diggory@4144
   163
		CFURLRef appURL = (CFURLRef)copyURLForApplication(@"Network Utility.app");
ingmarstein@3141
   164
		if (appURL) {
ingmarstein@3141
   165
			ipIconData = (CFDataRef)copyIconDataForURL((NSURL *)appURL);
ingmarstein@3141
   166
			CFRelease(appURL);
ingmarstein@3141
   167
		}
ingmarstein@3141
   168
	}
ingmarstein@3141
   169
ingmarstein@3141
   170
	return ipIconData;
ingmarstein@3141
   171
}
ingmarstein@3141
   172
ingmarstein@3141
   173
static CFDataRef iSyncIcon(void)
ingmarstein@3141
   174
{
ingmarstein@3141
   175
	static CFDataRef iSyncIconData = NULL;
ingmarstein@3141
   176
ingmarstein@3141
   177
	if (!iSyncIconData) {
ingmarstein@3141
   178
		CFURLRef appURL = (CFURLRef)copyURLForApplication(@"iSync.app");
ingmarstein@3141
   179
		if (appURL) {
ingmarstein@3141
   180
			iSyncIconData = (CFDataRef)copyIconDataForURL((NSURL *)appURL);
ingmarstein@3141
   181
			CFRelease(appURL);
ingmarstein@3141
   182
		}
ingmarstein@3141
   183
	}
ingmarstein@3141
   184
ingmarstein@3141
   185
	return iSyncIconData;
ingmarstein@3141
   186
}
ingmarstein@3141
   187
evands@3121
   188
#pragma mark Firewire
evands@3121
   189
ingmarstein@2624
   190
void AppController_fwDidConnect(CFStringRef deviceName) {
ingmarstein@2623
   191
//	NSLog(@"FireWire Connect: %@", deviceName);
ingmarstein@2623
   192
ingmarstein@2623
   193
	CFStringRef title = NotifierFireWireConnectionTitle();
ingmarstein@2623
   194
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
ingmarstein@2608
   195
							description:(NSString *)deviceName
ingmarstein@2623
   196
							notificationName:(NSString *)NotifierFireWireConnectionNotification
ingmarstein@3141
   197
							iconData:(NSData *)firewireLogo()
ingmarstein@2608
   198
							priority:0
ingmarstein@2608
   199
							isSticky:NO
ingmarstein@2608
   200
							clickContext:nil];
ingmarstein@2623
   201
	CFRelease(title);
ingmarstein@2608
   202
}
ingmarstein@2608
   203
ingmarstein@2624
   204
void AppController_fwDidDisconnect(CFStringRef deviceName) {
ingmarstein@2623
   205
//	NSLog(@"FireWire Disconnect: %@", deviceName);
ingmarstein@2623
   206
ingmarstein@2623
   207
	CFStringRef title = NotifierFireWireDisconnectionTitle();
ingmarstein@2623
   208
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
ingmarstein@2608
   209
							description:(NSString *)deviceName
ingmarstein@2623
   210
							notificationName:(NSString *)NotifierFireWireDisconnectionNotification
ingmarstein@3141
   211
							iconData:(NSData *)firewireLogo()
evands@3121
   212
							priority:0
evands@3121
   213
							isSticky:NO
evands@3121
   214
							clickContext:nil];
evands@3121
   215
	CFRelease(title);
evands@3121
   216
}
evands@3121
   217
evands@3121
   218
#pragma mark USB
ingmarstein@2608
   219
ingmarstein@2624
   220
void AppController_usbDidConnect(CFStringRef deviceName) {
ingmarstein@2623
   221
//	NSLog(@"USB Connect: %@", deviceName);
ingmarstein@2623
   222
	CFStringRef title = NotifierUSBConnectionTitle();
ingmarstein@2623
   223
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
ingmarstein@2608
   224
							description:(NSString *)deviceName
ingmarstein@2623
   225
							notificationName:(NSString *)NotifierUSBConnectionNotification
ingmarstein@3141
   226
							iconData:(NSData *)usbLogo()
ingmarstein@2608
   227
							priority:0
ingmarstein@2608
   228
							isSticky:NO
ingmarstein@2608
   229
							clickContext:nil];
ingmarstein@2623
   230
	CFRelease(title);
ingmarstein@2608
   231
}
ingmarstein@2608
   232
ingmarstein@2624
   233
void AppController_usbDidDisconnect(CFStringRef deviceName) {
ingmarstein@2623
   234
//	NSLog(@"USB Disconnect: %@", deviceName);
ingmarstein@2623
   235
	CFStringRef title = NotifierUSBDisconnectionTitle();
ingmarstein@2623
   236
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
ingmarstein@2608
   237
							description:(NSString *)deviceName
ingmarstein@2623
   238
							notificationName:(NSString *)NotifierUSBDisconnectionNotification
ingmarstein@3141
   239
							iconData:(NSData *)usbLogo()
evands@3121
   240
							priority:0
evands@3121
   241
							isSticky:NO
evands@3121
   242
							clickContext:nil];
evands@3121
   243
	CFRelease(title);
evands@3121
   244
}
evands@3121
   245
evands@3121
   246
#pragma mark Bluetooth
ingmarstein@2608
   247
ingmarstein@2624
   248
void AppController_bluetoothDidConnect(CFStringRef device) {
ingmarstein@2623
   249
//	NSLog(@"Bluetooth Connect: %@", device);
ingmarstein@2623
   250
	CFStringRef title = NotifierBluetoothConnectionTitle();
ingmarstein@2623
   251
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
ingmarstein@2608
   252
							description:(NSString *)device
ingmarstein@2623
   253
							notificationName:(NSString *)NotifierBluetoothConnectionNotification
ingmarstein@3141
   254
							iconData:(NSData *)bluetoothLogo()
ingmarstein@2608
   255
							priority:0
ingmarstein@2608
   256
							isSticky:NO
ingmarstein@2608
   257
							clickContext:nil];
ingmarstein@2623
   258
	CFRelease(title);
ingmarstein@2608
   259
}
ingmarstein@2608
   260
ingmarstein@2624
   261
void AppController_bluetoothDidDisconnect(CFStringRef device) {
ingmarstein@2623
   262
//	NSLog(@"Bluetooth Disconnect: %@", device);
ingmarstein@2623
   263
	CFStringRef title = NotifierBluetoothDisconnectionTitle();
ingmarstein@2623
   264
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
ingmarstein@2608
   265
							description:(NSString *)device
ingmarstein@2623
   266
							notificationName:(NSString *)NotifierBluetoothDisconnectionNotification
ingmarstein@3141
   267
							iconData:(NSData *)bluetoothLogo()
evands@3121
   268
							priority:0
evands@3121
   269
							isSticky:NO
evands@3121
   270
							clickContext:nil];
evands@3121
   271
	CFRelease(title);
evands@3121
   272
}
evands@3121
   273
evands@3121
   274
#pragma mark Volumes
ingmarstein@2608
   275
boredzo@3657
   276
void AppController_volumeDidMount(VolumeInfo *info) {
boredzo@3657
   277
//	NSLog(@"volume Mount: %@", info);
ingmarstein@2608
   278
ingmarstein@2623
   279
	CFStringRef title = NotifierVolumeMountedTitle();
boredzo@3633
   280
	NSDictionary *context = nil;
boredzo@3633
   281
	
boredzo@3657
   282
	if ([info path]) {
boredzo@3633
   283
		context = [NSDictionary dictionaryWithObjectsAndKeys:
boredzo@3633
   284
								(NSString *)NotifierVolumeMountedNotification, @"notification",
boredzo@3657
   285
								[info path], @"path",
boredzo@3633
   286
								nil];
boredzo@3633
   287
	}
boredzo@3633
   288
	
boredzo@3633
   289
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
boredzo@3657
   290
							description:[info name]
ingmarstein@2623
   291
							notificationName:(NSString *)NotifierVolumeMountedNotification
boredzo@3657
   292
							iconData:[info iconData]
ingmarstein@2608
   293
							priority:0
ingmarstein@2608
   294
							isSticky:NO
boredzo@3633
   295
							clickContext:context];
boredzo@3633
   296
	CFRelease(title);
boredzo@3633
   297
}
boredzo@3633
   298
boredzo@3657
   299
void AppController_volumeDidUnmount(VolumeInfo *info) {
boredzo@3657
   300
//	NSLog(@"volume Unmount: %@", info);
ingmarstein@2608
   301
ingmarstein@2623
   302
	CFStringRef title = NotifierVolumeUnmountedTitle();
boredzo@3657
   303
boredzo@3657
   304
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
boredzo@3657
   305
							description:[info name]
ingmarstein@2623
   306
							notificationName:(NSString *)NotifierVolumeUnmountedNotification
boredzo@3657
   307
							iconData:[info iconData]
evands@3121
   308
							priority:0
evands@3121
   309
							isSticky:NO
evands@3121
   310
							clickContext:nil];
evands@3121
   311
	CFRelease(title);
evands@3121
   312
}
evands@3121
   313
evands@3121
   314
#pragma mark Network
ingmarstein@2623
   315
ingmarstein@2624
   316
void AppController_airportConnect(CFStringRef networkName, const unsigned char *bssidBytes) {
ingmarstein@2608
   317
	//NSLog(@"AirPort connect: %@", description);
ingmarstein@2608
   318
ingmarstein@2608
   319
	if (sleeping)
ingmarstein@2608
   320
		return;
ingmarstein@2608
   321
ingmarstein@2623
   322
	CFStringRef title = NotifierNetworkAirportConnectTitle();
evands@3789
   323
	
evands@3789
   324
	NSString *bssid = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X",
evands@3789
   325
					   bssidBytes[0],
evands@3789
   326
					   bssidBytes[1],
evands@3789
   327
					   bssidBytes[2],
evands@3789
   328
					   bssidBytes[3],
evands@3789
   329
					   bssidBytes[4],
evands@3789
   330
					   bssidBytes[5]];
evands@3810
   331
	NSString *description = [NSString stringWithFormat:NSLocalizedString(@"Joined network.\nSSID:\t\t%@\nBSSID:\t%@", ""),
evands@3789
   332
							 networkName,
evands@3789
   333
							 bssid];
evands@3789
   334
evands@3789
   335
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
evands@3789
   336
								description:description
ingmarstein@2623
   337
						   notificationName:(NSString *)NotifierNetworkAirportConnectNotification
ingmarstein@3141
   338
								   iconData:(NSData *)airportIcon()
ingmarstein@2608
   339
								   priority:0
ingmarstein@2608
   340
								   isSticky:NO
ingmarstein@2608
   341
							   clickContext:nil];
evands@3789
   342
	CFRelease(title);
ingmarstein@2623
   343
}
ingmarstein@2623
   344
ingmarstein@2624
   345
void AppController_airportDisconnect(CFStringRef networkName) {
ingmarstein@2608
   346
	//NSLog(@"AirPort disconnect: %@", description);
ingmarstein@2608
   347
ingmarstein@2608
   348
	if (sleeping)
ingmarstein@2608
   349
		return;
ingmarstein@2608
   350
ingmarstein@2623
   351
	CFStringRef title = NotifierNetworkAirportDisconnectTitle();
ingmarstein@2623
   352
	CFStringRef format = NotifierNetworkAirportDisconnectDescription();
ingmarstein@2623
   353
	CFStringRef description = CFStringCreateWithFormat(kCFAllocatorDefault,
ingmarstein@2625
   354
													   NULL,
ingmarstein@2623
   355
													   format,
ingmarstein@2623
   356
													   networkName);
ingmarstein@2623
   357
	CFRelease(format);
ingmarstein@3125
   358
ingmarstein@2623
   359
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
ingmarstein@2623
   360
								description:(NSString *)description
ingmarstein@2623
   361
						   notificationName:(NSString *)NotifierNetworkAirportDisconnectNotification
ingmarstein@3141
   362
								   iconData:(NSData *)airportIcon()
ingmarstein@2608
   363
								   priority:0
ingmarstein@2608
   364
								   isSticky:NO
ingmarstein@2608
   365
							   clickContext:nil];
ingmarstein@2623
   366
ingmarstein@2623
   367
	CFRelease(title);
ingmarstein@2623
   368
	CFRelease(description);
ingmarstein@2608
   369
}
ingmarstein@2608
   370
ingmarstein@2624
   371
void AppController_linkUp(CFStringRef description) {
ingmarstein@2608
   372
	//NSLog(@"Link up: %@", description);
ingmarstein@2608
   373
ingmarstein@2608
   374
	if (sleeping)
ingmarstein@2608
   375
		return;
ingmarstein@2608
   376
ingmarstein@2623
   377
	CFStringRef title = NotifierNetworkLinkUpTitle();
ingmarstein@2623
   378
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
ingmarstein@2623
   379
								description:(NSString *)description
ingmarstein@2623
   380
						   notificationName:(NSString *)NotifierNetworkLinkUpNotification
ingmarstein@3141
   381
								   iconData:(NSData *)ipIcon()
ingmarstein@2608
   382
								   priority:0
ingmarstein@2608
   383
								   isSticky:NO
ingmarstein@2608
   384
							   clickContext:nil];
ingmarstein@2623
   385
	CFRelease(title);
ingmarstein@2608
   386
}
ingmarstein@2608
   387
ingmarstein@2624
   388
void AppController_linkDown(CFStringRef description) {
ingmarstein@2608
   389
	//NSLog(@"Link down: %@", description);
ingmarstein@2608
   390
ingmarstein@2608
   391
	if (sleeping)
ingmarstein@2608
   392
		return;
ingmarstein@2608
   393
ingmarstein@2623
   394
	CFStringRef title = NotifierNetworkLinkDownTitle();
ingmarstein@2623
   395
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
ingmarstein@2623
   396
								description:(NSString *)description
ingmarstein@2623
   397
						   notificationName:(NSString *)NotifierNetworkLinkDownNotification
ingmarstein@3141
   398
								   iconData:(NSData *)ipIcon()
ingmarstein@2608
   399
								   priority:0
ingmarstein@2608
   400
								   isSticky:NO
ingmarstein@2608
   401
							   clickContext:nil];
ingmarstein@2623
   402
	CFRelease(title);
ingmarstein@2608
   403
}
ingmarstein@2608
   404
ingmarstein@3139
   405
void AppController_ipAcquired(CFStringRef ip, CFStringRef type) {
ingmarstein@2608
   406
	//NSLog(@"IP acquired: %@", ip);
ingmarstein@2608
   407
ingmarstein@2608
   408
	if (sleeping)
ingmarstein@2608
   409
		return;
ingmarstein@2608
   410
ingmarstein@2623
   411
	CFStringRef title = NotifierNetworkIpAcquiredTitle();
ingmarstein@2623
   412
	CFStringRef format = NotifierNetworkIpAcquiredDescription();
ingmarstein@2623
   413
	CFStringRef description = CFStringCreateWithFormat(kCFAllocatorDefault,
ingmarstein@2625
   414
													   NULL,
ingmarstein@2623
   415
													   format,
ingmarstein@3139
   416
													   ip,
evands@3760
   417
													   type);
ingmarstein@2623
   418
	CFRelease(format);
ingmarstein@2623
   419
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
ingmarstein@2623
   420
								description:(NSString *)description
ingmarstein@2623
   421
						   notificationName:(NSString *)NotifierNetworkIpAcquiredNotification
ingmarstein@3141
   422
								   iconData:(NSData *)ipIcon()
ingmarstein@2608
   423
								   priority:0
ingmarstein@2608
   424
								   isSticky:NO
ingmarstein@2608
   425
							   clickContext:nil];
ingmarstein@2623
   426
	CFRelease(title);
ingmarstein@2623
   427
	CFRelease(description);
ingmarstein@2608
   428
}
ingmarstein@2608
   429
ingmarstein@2624
   430
void AppController_ipReleased(void) {
ingmarstein@2608
   431
	//NSLog(@"IP released");
ingmarstein@2608
   432
ingmarstein@2608
   433
	if (sleeping)
ingmarstein@2608
   434
		return;
ingmarstein@2608
   435
ingmarstein@2623
   436
	CFStringRef title = NotifierNetworkIpReleasedTitle();
ingmarstein@2623
   437
	CFStringRef description = NotifierNetworkIpReleasedDescription();
ingmarstein@2623
   438
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
ingmarstein@2623
   439
								description:(NSString *)description
ingmarstein@2623
   440
						   notificationName:(NSString *)NotifierNetworkIpReleasedNotification
ingmarstein@3141
   441
								   iconData:(NSData *)ipIcon()
ingmarstein@2608
   442
								   priority:0
ingmarstein@2608
   443
								   isSticky:NO
ingmarstein@2608
   444
							   clickContext:nil];
ingmarstein@2623
   445
	CFRelease(title);
ingmarstein@2623
   446
	CFRelease(description);
ingmarstein@2608
   447
}
ingmarstein@2608
   448
evands@3121
   449
#pragma mark Sync
evands@3121
   450
ingmarstein@2624
   451
void AppController_syncStarted(void) {
ingmarstein@2608
   452
	//NSLog(@"Sync started");
ingmarstein@2608
   453
ingmarstein@2623
   454
	CFStringRef title = NotifierSyncStartedTitle();
ingmarstein@2623
   455
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
ingmarstein@2623
   456
								description:(NSString *)title
ingmarstein@2623
   457
						   notificationName:(NSString *)NotifierSyncStartedNotification
ingmarstein@3141
   458
								   iconData:(NSData *)iSyncIcon()
ingmarstein@2608
   459
								   priority:0
ingmarstein@2608
   460
								   isSticky:NO
ingmarstein@2608
   461
							   clickContext:nil];
ingmarstein@2623
   462
	CFRelease(title);
ingmarstein@2608
   463
}
ingmarstein@2608
   464
ingmarstein@2624
   465
void AppController_syncFinished(void) {
ingmarstein@2608
   466
	//NSLog(@"Sync finished");
ingmarstein@2608
   467
ingmarstein@2623
   468
	CFStringRef title = NotifierSyncFinishedTitle();
ingmarstein@2623
   469
	[GrowlApplicationBridge notifyWithTitle:(NSString *)title
ingmarstein@2623
   470
								description:(NSString *)title
ingmarstein@2623
   471
						   notificationName:(NSString *)NotifierSyncFinishedNotification
ingmarstein@3141
   472
								   iconData:(NSData *)iSyncIcon()
evands@3121
   473
								   priority:0
evands@3121
   474
								   isSticky:NO
evands@3121
   475
							   clickContext:nil];
evands@3121
   476
	CFRelease(title);
evands@3121
   477
}
evands@3121
   478
evands@3121
   479
#pragma mark Power
evands@3121
   480
void AppController_powerSwitched(HGPowerSource powerSource, CFBooleanRef isCharging,
evands@3121
   481
								 int batteryTime, int batteryPercentage)
evands@3121
   482
{
evands@3121
   483
	NSString		*title = nil;
evands@3121
   484
	NSMutableString *description = [NSMutableString string];
evands@3121
   485
	NSString		*notificationName = nil;
ingmarstein@3141
   486
	CFDataRef		imageData = iSyncIcon();
evands@3121
   487
evands@3121
   488
	BOOL		haveBatteryTime = (batteryTime != -1);
ingmarstein@3170
   489
	BOOL		haveBatteryPercentage = (batteryPercentage != -1);
ingmarstein@3125
   490
evands@3121
   491
	if (powerSource == HGACPower) {
evands@3121
   492
		title = NSLocalizedString(@"On A/C power", nil);
evands@3121
   493
evands@3121
   494
		if (isCharging == kCFBooleanTrue) {
evands@3121
   495
			[description appendString:NSLocalizedString(@"Battery charging...", nil)];
ingmarstein@3170
   496
			if (haveBatteryTime || haveBatteryPercentage) [description appendString:@"\n"];
evands@3121
   497
			if (haveBatteryTime) [description appendFormat:NSLocalizedString(@"Time to charge: %i", nil), batteryTime];
ingmarstein@3170
   498
			if (haveBatteryTime && haveBatteryPercentage) [description appendString:@"\n"];
ingmarstein@3170
   499
			if (haveBatteryPercentage) [description appendFormat:NSLocalizedString(@"Current charge: %d%%", nil), batteryPercentage];
evands@3121
   500
		}
evands@3121
   501
evands@3121
   502
		notificationName = (NSString *)NotifierPowerOnACNotification;
evands@3121
   503
evands@3121
   504
	} else if (powerSource == HGBatteryPower) {
evands@3121
   505
		title = NSLocalizedString(@"On battery power", nil);
ingmarstein@3125
   506
evands@3121
   507
		if (haveBatteryTime) [description appendFormat:NSLocalizedString(@"Time remaining: %i minutes", nil), batteryTime];
ingmarstein@3170
   508
		if (haveBatteryTime && haveBatteryPercentage) [description appendString:@"\n"];
ingmarstein@3170
   509
		if (haveBatteryPercentage) [description appendFormat:NSLocalizedString(@"Current charge: %d%%", nil), batteryPercentage];
ingmarstein@3125
   510
evands@3121
   511
		notificationName = (NSString *)NotifierPowerOnBatteryNotification;
evands@3121
   512
evands@3121
   513
	} else if (powerSource == HGUPSPower) {
evands@3121
   514
		title = NSLocalizedString(@"On UPS power", nil);
ingmarstein@3125
   515
evands@3121
   516
		notificationName = (NSString *)NotifierPowerOnUPSNotification;
evands@3121
   517
	}
evands@3121
   518
ingmarstein@3125
   519
	if (notificationName)
evands@3121
   520
		[GrowlApplicationBridge notifyWithTitle:title
evands@3121
   521
									description:description
evands@3121
   522
							   notificationName:notificationName
ingmarstein@3141
   523
									   iconData:(NSData *)imageData
evands@3121
   524
									   priority:0
evands@3121
   525
									   isSticky:NO
evands@3121
   526
								   clickContext:nil];
ingmarstein@2623
   527
}
ingmarstein@2608
   528
ingmarstein@2619
   529
static void powerCallback(void *refcon, io_service_t service, natural_t messageType, void *messageArgument) {
ingmarstein@2619
   530
#pragma unused(refcon,service)
ingmarstein@2619
   531
	switch (messageType) {
ingmarstein@2619
   532
		case kIOMessageSystemWillRestart:
ingmarstein@2619
   533
		case kIOMessageSystemWillPowerOff:
ingmarstein@2619
   534
		case kIOMessageSystemWillSleep:
ingmarstein@2619
   535
		case kIOMessageDeviceWillPowerOff:
ingmarstein@2619
   536
			sleeping = YES;
ingmarstein@2619
   537
			IOAllowPowerChange(powerConnection, (long)messageArgument);
ingmarstein@2619
   538
			break;
ingmarstein@2619
   539
		case kIOMessageCanSystemPowerOff:
ingmarstein@2619
   540
		case kIOMessageCanSystemSleep:
ingmarstein@2619
   541
		case kIOMessageCanDevicePowerOff:
ingmarstein@2619
   542
			IOAllowPowerChange(powerConnection, (long)messageArgument);
ingmarstein@2619
   543
			break;
ingmarstein@2619
   544
		case kIOMessageSystemWillNotSleep:
ingmarstein@2619
   545
		case kIOMessageSystemWillNotPowerOff:
ingmarstein@2619
   546
		case kIOMessageSystemHasPoweredOn:
ingmarstein@2619
   547
		case kIOMessageDeviceWillNotPowerOff:
ingmarstein@2619
   548
		case kIOMessageDeviceHasPoweredOn:
ingmarstein@2619
   549
			sleeping = NO;
ingmarstein@2619
   550
		default:
ingmarstein@2619
   551
			break;
ingmarstein@2619
   552
	}
ingmarstein@2619
   553
}
ingmarstein@2619
   554
diggory@1255
   555
@implementation AppController
diggory@1255
   556
ingmarstein@2165
   557
- (void) awakeFromNib {
ingmarstein@2619
   558
	// Register ourselves as a Growl delegate for registration purposes
rudy@1257
   559
	[GrowlApplicationBridge setGrowlDelegate:self];
ingmarstein@1358
   560
evands@3121
   561
	// Register for sleep and wake notifications so we can suppress various notifications during sleep
ingmarstein@2619
   562
	IONotificationPortRef ioNotificationPort;
ingmarstein@2619
   563
	powerConnection = IORegisterForSystemPower(NULL, &ioNotificationPort, powerCallback, &powerNotifier);
ingmarstein@2619
   564
	if (powerConnection) {
ingmarstein@2619
   565
		powerRunLoopSource = IONotificationPortGetRunLoopSource(ioNotificationPort);
ingmarstein@2619
   566
		CFRunLoopAddSource(CFRunLoopGetCurrent(), powerRunLoopSource, kCFRunLoopDefaultMode);
ingmarstein@2619
   567
	}
ingmarstein@1358
   568
ingmarstein@2624
   569
	FireWireNotifier_init();
ingmarstein@2624
   570
	USBNotifier_init();
ingmarstein@2624
   571
	VolumeNotifier_init();
ingmarstein@2624
   572
	SyncNotifier_init();
ingmarstein@2624
   573
	BluetoothNotifier_init();
evands@3760
   574
	networkNotifier = [[NetworkNotifier alloc] init];
evands@3121
   575
	PowerNotifier_init();
ingmarstein@1572
   576
}
ingmarstein@1572
   577
ingmarstein@2165
   578
- (void) dealloc {
ingmarstein@2608
   579
	FireWireNotifier_dealloc();
ingmarstein@2608
   580
	USBNotifier_dealloc();
ingmarstein@2608
   581
	VolumeNotifier_dealloc();
ingmarstein@2608
   582
	SyncNotifier_dealloc();
ingmarstein@2608
   583
	BluetoothNotifier_dealloc();
evands@3760
   584
	[networkNotifier release];
ingmarstein@1358
   585
ingmarstein@2619
   586
	if (powerConnection) {
ingmarstein@2619
   587
		CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerRunLoopSource, kCFRunLoopDefaultMode);
ingmarstein@2619
   588
		IODeregisterForSystemPower(&powerNotifier);
ingmarstein@2619
   589
	}
ingmarstein@1358
   590
rudy@1257
   591
	[super dealloc];
rudy@1257
   592
}
rudy@1257
   593
ingmarstein@1572
   594
- (NSString *) applicationNameForGrowl {
ingmarstein@1316
   595
	return @"HardwareGrowler";
rudy@1257
   596
}
ingmarstein@1289
   597
ingmarstein@1572
   598
- (NSDictionary *) registrationDictionaryForGrowl {
evands@3780
   599
	NSDictionary *notificationsWithDescriptions = [NSDictionary dictionaryWithObjectsAndKeys:
evands@3780
   600
	 NotifierUSBConnectionHumanReadableDescription, NotifierUSBConnectionNotification,			
evands@3780
   601
	 NotifierUSBDisconnectionHumanReadableDescription, NotifierUSBDisconnectionNotification,		
evands@3780
   602
	 NotifierVolumeMountedHumanReadableDescription, NotifierVolumeMountedNotification,			
evands@3780
   603
	 NotifierVolumeUnmountedHumanReadableDescription, NotifierVolumeUnmountedNotification,			
evands@3780
   604
	 NotifierBluetoothConnectionHumanReadableDescription, NotifierBluetoothConnectionNotification,		
evands@3780
   605
	 NotifierBluetoothDisconnectionHumanReadableDescription, NotifierBluetoothDisconnectionNotification,	
evands@3780
   606
	 NotifierFireWireConnectionHumanReadableDescription, NotifierFireWireConnectionNotification,		
evands@3780
   607
	 NotifierFireWireDisconnectionHumanReadableDescription, NotifierFireWireDisconnectionNotification,	
evands@3780
   608
	 NotifierNetworkLinkUpHumanReadableDescription, NotifierNetworkLinkUpNotification,			
evands@3780
   609
	 NotifierNetworkLinkDownHumanReadableDescription, NotifierNetworkLinkDownNotification,			
evands@3780
   610
	 NotifierNetworkIpAcquiredHumanReadableDescription, NotifierNetworkIpAcquiredNotification,		
evands@3780
   611
	 NotifierNetworkIpReleasedHumanReadableDescription, NotifierNetworkIpReleasedNotification,		
evands@3780
   612
	 NotifierNetworkAirportConnectHumanReadableDescription, NotifierNetworkAirportConnectNotification,	
evands@3780
   613
	 NotifierNetworkAirportDisconnectHumanReadableDescription, NotifierNetworkAirportDisconnectNotification,
evands@3780
   614
	 NotifierSyncStartedHumanReadableDescription, NotifierSyncStartedNotification,				
evands@3780
   615
	 NotifierSyncFinishedHumanReadableDescription, NotifierSyncFinishedNotification,			
evands@3780
   616
	 NotifierPowerOnACHumanReadableDescription, NotifierPowerOnACNotification,				
evands@3780
   617
	 NotifierPowerOnBatteryHumanReadableDescription, NotifierPowerOnBatteryNotification,			
evands@3780
   618
	 NotifierPowerOnUPSHumanReadableDescription, NotifierPowerOnUPSNotification,				
evands@3780
   619
	 nil];
evands@3780
   620
evands@3851
   621
	NSArray *allNotifications = [notificationsWithDescriptions allKeys];
evands@3851
   622
	
evands@3851
   623
	//Don't turn the sync notiifications on by default; they're noisy and not all that interesting.
evands@3851
   624
	NSMutableArray *defaultNotifications = [allNotifications mutableCopy];
evands@3851
   625
	[defaultNotifications removeObject:NotifierSyncStartedNotification];
evands@3851
   626
	[defaultNotifications removeObject:NotifierSyncFinishedNotification];
evands@3851
   627
	
ingmarstein@1289
   628
	NSDictionary *regDict = [NSDictionary dictionaryWithObjectsAndKeys:
evands@3780
   629
							 @"HardwareGrowler", GROWL_APP_NAME,
evands@3851
   630
							 allNotifications, GROWL_NOTIFICATIONS_ALL,
evands@3851
   631
							 defaultNotifications,	GROWL_NOTIFICATIONS_DEFAULT,
evands@3780
   632
							 notificationsWithDescriptions,	GROWL_NOTIFICATIONS_HUMAN_READABLE_NAMES,
evands@3780
   633
							 nil];
ingmarstein@2472
   634
evands@3851
   635
	[defaultNotifications release];
evands@3851
   636
rudy@1257
   637
	return regDict;
rudy@1257
   638
}
diggory@1255
   639
boredzo@3633
   640
- (void) growlNotificationWasClicked:(id)clickContext {
boredzo@3633
   641
	if ([[clickContext objectForKey:@"notification"] isEqualToString:(NSString *)NotifierVolumeMountedNotification])
boredzo@3633
   642
		[[NSWorkspace sharedWorkspace] openFile:[clickContext objectForKey:@"path"]];
boredzo@3633
   643
}
boredzo@3633
   644
ingmarstein@2623
   645
- (IBAction) doSimpleHelp:(id)sender {
ingmarstein@3186
   646
#pragma unused(sender)
ingmarstein@1905
   647
	[[NSWorkspace sharedWorkspace] openFile:[[NSBundle mainBundle] pathForResource:@"readme" ofType:@"txt"]];
ingmarstein@1308
   648
}
diggory@1307
   649
ingmarstein@1261
   650
@end