2 // GrowlDefinesInternal.h
5 // Created by Karl Adam on Mon May 17 2004.
6 // Copyright (c) 2004 the Growl Project. All rights reserved.
9 #ifndef _GROWL_GROWLDEFINESINTERNAL_H
10 #define _GROWL_GROWLDEFINESINTERNAL_H
12 #include <CoreFoundation/CoreFoundation.h>
13 #include <sys/types.h>
22 /*! @header GrowlDefinesInternal.h
23 * @abstract Defines internal Growl macros and types.
24 * @ignore ATTRIBUTE_PACKED
25 * @discussion These constants are used both by GrowlHelperApp and by plug-ins.
27 * Notification keys (used in GrowlHelperApp, in GrowlApplicationBridge, and
28 * by applications that don't use GrowlApplicationBridge) are defined in
32 /*! @defined GROWL_TCP_PORT
33 * @abstract The TCP listen port for Growl notification servers.
35 #define GROWL_TCP_PORT 23052
37 /*! @defined GROWL_UDP_PORT
38 * @abstract The UDP listen port for Growl notification servers.
40 #define GROWL_UDP_PORT 9887
42 /*! @defined GROWL_PROTOCOL_VERSION
43 * @abstract The current version of the Growl network-notifications protocol (without encryption).
45 #define GROWL_PROTOCOL_VERSION 1
47 /*! @defined GROWL_PROTOCOL_VERSION_AES128
48 * @abstract The current version of the Growl network-notifications protocol (with AES-128 encryption).
50 #define GROWL_PROTOCOL_VERSION_AES128 2
52 /*! @defined GROWL_TYPE_REGISTRATION
53 * @abstract The packet type of registration packets with MD5 authentication.
55 #define GROWL_TYPE_REGISTRATION 0
56 /*! @defined GROWL_TYPE_NOTIFICATION
57 * @abstract The packet type of notification packets with MD5 authentication.
59 #define GROWL_TYPE_NOTIFICATION 1
60 /*! @defined GROWL_TYPE_REGISTRATION_SHA256
61 * @abstract The packet type of registration packets with SHA-256 authentication.
63 #define GROWL_TYPE_REGISTRATION_SHA256 2
64 /*! @defined GROWL_TYPE_NOTIFICATION_SHA256
65 * @abstract The packet type of notification packets with SHA-256 authentication.
67 #define GROWL_TYPE_NOTIFICATION_SHA256 3
68 /*! @defined GROWL_TYPE_REGISTRATION_NOAUTH
69 * @abstract The packet type of registration packets without authentication.
71 #define GROWL_TYPE_REGISTRATION_NOAUTH 4
72 /*! @defined GROWL_TYPE_NOTIFICATION_NOAUTH
73 * @abstract The packet type of notification packets without authentication.
75 #define GROWL_TYPE_NOTIFICATION_NOAUTH 5
77 #define ATTRIBUTE_PACKED __attribute((packed))
79 /*! @struct GrowlNetworkPacket
80 * @abstract This struct is a header common to all incoming Growl network
81 * packets which identifies the type and version of the packet.
83 struct GrowlNetworkPacket {
84 unsigned char version;
89 * @struct GrowlNetworkRegistration
90 * @abstract The format of a registration packet.
91 * @discussion A Growl client that wants to register with a Growl server sends
92 * a packet in this format.
93 * @field common The Growl packet header.
94 * @field appNameLen The name of the application that is registering.
95 * @field numAllNotifications The number of notifications in the list.
96 * @field numDefaultNotifications The number of notifications in the list that are enabled by default.
97 * @field data Variable-sized data.
99 struct GrowlNetworkRegistration {
100 struct GrowlNetworkPacket common;
101 /* This name is used both internally and in the Growl
104 * The application name should remain stable between different versions
105 * and incarnations of your application.
106 * For example, "SurfWriter" is a good app name, whereas "SurfWriter 2.0"
107 * and "SurfWriter Lite" are not.
109 * In addition to being unsigned, the application name length is in
110 * network byte order.
112 unsigned short appNameLen;
113 /* These names are used both internally and in the Growl
114 * preferences. For this reason, they should be human-readable.
116 unsigned char numAllNotifications;
118 unsigned char numDefaultNotifications;
119 /* The variable-sized data of a registration is:
120 * - The application name, in UTF-8 encoding, for appNameLen bytes.
121 * - The list of all notification names.
122 * - The list of default notifications, as 8-bit unsigned indices into the list of all notifications.
123 * - The MD5/SHA256 checksum of all the data preceding the checksum.
125 * Each notification name is encoded as:
126 * - Length: two bytes, unsigned, network byte order.
127 * - Name: As many bytes of UTF-8-encoded text as the length says.
128 * And there are numAllNotifications of these.
130 unsigned char data[];
134 * @struct GrowlNetworkNotification
135 * @abstract The format of a notification packet.
136 * @discussion A Growl client that wants to post a notification to a Growl
137 * server sends a packet in this format.
138 * @field common The Growl packet header.
139 * @field flags The priority number and the sticky bit.
140 * @field nameLen The length of the notification name.
141 * @field titleLen The length of the notification title.
142 * @field descriptionLen The length of the notification description.
143 * @field appNameLen The length of the application name.
144 * @field data Variable-sized data.
146 struct GrowlNetworkNotification {
147 struct GrowlNetworkPacket common;
149 * @struct GrowlNetworkNotificationFlags
150 * @abstract Various flags.
151 * @discussion This 16-bit packed structure contains the priority as a
152 * signed 3-bit integer from -2 to +2, and the sticky flag as a single bit.
153 * The high 12 bits of the structure are reserved for future use.
154 * @field reserved reserved for future use.
155 * @field priority the priority as a signed 3-bit integer from -2 to +2.
156 * @field sticky the sticky flag.
158 struct GrowlNetworkNotificationFlags {
159 #ifdef __BIG_ENDIAN__
160 unsigned reserved: 12;
166 unsigned reserved: 12;
168 } ATTRIBUTE_PACKED flags; //size = 16 (12 + 3 + 1)
170 /* In addition to being unsigned, the notification name length
171 * is in network byte order.
173 unsigned short nameLen;
174 /* @discussion In addition to being unsigned, the title length is in
175 * network byte order.
177 unsigned short titleLen;
178 /* In addition to being unsigned, the description length is in
179 * network byte order.
181 unsigned short descriptionLen;
182 /* In addition to being unsigned, the application name length
183 * is in network byte order.
185 unsigned short appNameLen;
186 /* The variable-sized data of a notification is:
187 * - Notification name, in UTF-8 encoding, for nameLen bytes.
188 * - Title, in UTF-8 encoding, for titleLen bytes.
189 * - Description, in UTF-8 encoding, for descriptionLen bytes.
190 * - Application name, in UTF-8 encoding, for appNameLen bytes.
191 * - The MD5/SHA256 checksum of all the data preceding the checksum.
193 unsigned char data[];
196 /*! @defined GrowlEnabledKey
197 * @abstract Preference key controlling whether Growl is enabled.
198 * @discussion If this is false, then when GrowlHelperApp is launched to open
199 * a Growl registration dictionary file, GrowlHelperApp will quit when it has
200 * finished processing the file instead of listening for notifications.
202 #define GrowlEnabledKey XSTR("GrowlEnabled")
204 /*! @defined GROWL_SCREENSHOT_MODE
205 * @abstract Preference and notification key controlling whether to save a screenshot of the notification.
206 * @discussion This is for GHA's private usage. If your application puts this
207 * key into a notification dictionary, GHA will clobber it. This key is only
208 * allowed in the notification dictionaries GHA passes to displays.
210 * If this key contains an object whose boolValue is not NO, the display is
211 * asked to save a screenshot of the notification to
212 * ~/Library/Application\ Support/Growl/Screenshots.
214 #define GROWL_SCREENSHOT_MODE XSTR("ScreenshotMode")
216 /*! @defined GROWL_APP_LOCATION
217 * @abstract The location of this application.
218 * @discussion Contains either the POSIX path to the application, or a file-data dictionary (as used by the Dock).
219 * contains the file's alias record and its pathname.
221 #define GROWL_APP_LOCATION XSTR("AppLocation")
223 /*! @defined GROWL_REMOTE_ADDRESS
224 * @abstract The address of the host who sent this notification/registration.
225 * @discussion Contains an NSData with the address of the remote host who
226 * sent this notification/registration.
228 #define GROWL_REMOTE_ADDRESS XSTR("RemoteAddress")
231 * @defined GROWL_PREFPANE_BUNDLE_IDENTIFIER
232 * @discussion The bundle identifier for the Growl preference pane.
234 #define GROWL_PREFPANE_BUNDLE_IDENTIFIER XSTR("com.growl.prefpanel")
236 * @defined GROWL_HELPERAPP_BUNDLE_IDENTIFIER
237 * @discussion The bundle identifier for the Growl background application (GrowlHelperApp).
239 #define GROWL_HELPERAPP_BUNDLE_IDENTIFIER XSTR("com.Growl.GrowlHelperApp")
242 * @defined GROWL_PREFPANE_NAME
243 * @discussion The file name of the Growl preference pane.
245 #define GROWL_PREFPANE_NAME XSTR("Growl.prefPane")
246 #define PREFERENCE_PANES_SUBFOLDER_OF_LIBRARY XSTR("PreferencePanes")
247 #define PREFERENCE_PANE_EXTENSION XSTR("prefPane")
249 //plug-in bundle filename extensions
250 #define GROWL_PLUGIN_EXTENSION XSTR("growlPlugin")
251 #define GROWL_PATHWAY_EXTENSION XSTR("growlPathway")
252 #define GROWL_VIEW_EXTENSION XSTR("growlView")
253 #define GROWL_STYLE_EXTENSION XSTR("growlStyle")
255 /* --- These following macros are intended for plug-ins --- */
257 /*! @function SYNCHRONIZE_GROWL_PREFS
258 * @abstract Synchronizes Growl prefs so they're up-to-date.
259 * @discussion This macro is intended for use by GrowlHelperApp and by
260 * plug-ins (when the prefpane is selected).
262 #define SYNCHRONIZE_GROWL_PREFS() CFPreferencesAppSynchronize(CFSTR("com.Growl.GrowlHelperApp"))
264 /*! @function UPDATE_GROWL_PREFS
265 * @abstract Tells GrowlHelperApp to update its prefs.
266 * @discussion This macro is intended for use by plug-ins.
267 * It sends a notification to tell GrowlHelperApp to update its preferences.
269 #define UPDATE_GROWL_PREFS() do { \
270 SYNCHRONIZE_GROWL_PREFS(); \
271 CFStringRef _key = CFSTR("pid"); \
272 int pid = getpid(); \
273 CFNumberRef _value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pid); \
274 CFDictionaryRef userInfo = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&_key, (const void **)&_value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); \
276 CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(), \
277 CFSTR("GrowlPreferencesChanged"), \
278 CFSTR("GrowlUserDefaults"), \
280 CFRelease(userInfo); \
283 /*! @function READ_GROWL_PREF_VALUE
284 * @abstract Reads the given pref value from the plug-in's preferences.
285 * @discussion This macro is intended for use by plug-ins. It reads the value for the
286 * given key from the plug-in's preferences (which are stored in a dictionary inside of
287 * GrowlHelperApp's prefs).
288 * @param key The preference key to read the value of.
289 * @param domain The bundle ID of the plug-in.
290 * @param type The type of the result expected.
291 * @param result A pointer to an id. Set to the value if exists, left unchanged if not.
293 * If the value is set, you are responsible for releasing it.
295 #define READ_GROWL_PREF_VALUE(key, domain, type, result) do {\
296 CFDictionaryRef prefs = (CFDictionaryRef)CFPreferencesCopyAppValue((CFStringRef)domain, \
297 CFSTR("com.Growl.GrowlHelperApp")); \
299 if (CFDictionaryContainsKey(prefs, key)) {\
300 *result = (type)CFDictionaryGetValue(prefs, key); \
303 CFRelease(prefs); } \
306 /*! @function WRITE_GROWL_PREF_VALUE
307 * @abstract Writes the given pref value to the plug-in's preferences.
308 * @discussion This macro is intended for use by plug-ins. It writes the given
309 * value to the plug-in's preferences.
310 * @param key The preference key to write the value of.
311 * @param value The value to write to the preferences. It should be either a
312 * CoreFoundation type or toll-free bridged with one.
313 * @param domain The bundle ID of the plug-in.
315 #define WRITE_GROWL_PREF_VALUE(key, value, domain) do {\
316 CFDictionaryRef staticPrefs = (CFDictionaryRef)CFPreferencesCopyAppValue((CFStringRef)domain, \
317 CFSTR("com.Growl.GrowlHelperApp")); \
318 CFMutableDictionaryRef prefs; \
319 if (staticPrefs == NULL) {\
320 prefs = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); \
322 prefs = CFDictionaryCreateMutableCopy(NULL, 0, staticPrefs); \
323 CFRelease(staticPrefs); \
325 CFDictionarySetValue(prefs, key, value); \
326 CFPreferencesSetAppValue((CFStringRef)domain, prefs, CFSTR("com.Growl.GrowlHelperApp")); \
327 CFRelease(prefs); } while(0)
329 /*! @function READ_GROWL_PREF_BOOL
330 * @abstract Reads the given Boolean from the plug-in's preferences.
331 * @discussion This is a wrapper around READ_GROWL_PREF_VALUE() intended for
333 * @param key The preference key to read the Boolean from.
334 * @param domain The bundle ID of the plug-in.
335 * @param result A pointer to a Boolean type. Left unchanged if the value doesn't exist.
337 #define READ_GROWL_PREF_BOOL(key, domain, result) do {\
338 CFBooleanRef boolValue = NULL; \
339 READ_GROWL_PREF_VALUE(key, domain, CFBooleanRef, &boolValue); \
341 *result = CFBooleanGetValue(boolValue); \
342 CFRelease(boolValue); \
345 /*! @function WRITE_GROWL_PREF_BOOL
346 * @abstract Writes the given Boolean to the plug-in's preferences.
347 * @discussion This is a wrapper around WRITE_GROWL_PREF_VALUE() intended for
349 * @param key The preference key to write the Boolean for.
350 * @param value The Boolean value to write to the preferences.
351 * @param domain The bundle ID of the plug-in.
353 #define WRITE_GROWL_PREF_BOOL(key, value, domain) do {\
354 WRITE_GROWL_PREF_VALUE(key, value ? kCFBooleanTrue : kCFBooleanFalse, domain); } while(0)
356 /*! @function READ_GROWL_PREF_INT
357 * @abstract Reads the given integer from the plug-in's preferences.
358 * @discussion This is a wrapper around READ_GROWL_PREF_VALUE() intended for
360 * @param key The preference key to read the integer from.
361 * @param domain The bundle ID of the plug-in.
362 * @param result A pointer to an integer. Leaves unchanged if the value doesn't exist.
364 #define READ_GROWL_PREF_INT(key, domain, result) do {\
365 CFNumberRef intValue = NULL; \
366 READ_GROWL_PREF_VALUE(key, domain, CFNumberRef, &intValue); \
368 CFNumberGetValue(intValue, kCFNumberIntType, result); \
369 CFRelease(intValue); \
372 /*! @function WRITE_GROWL_PREF_INT
373 * @abstract Writes the given integer to the plug-in's preferences.
374 * @discussion This is a wrapper around WRITE_GROWL_PREF_VALUE() intended for
376 * @param key The preference key to write the integer for.
377 * @param value The integer value to write to the preferences.
378 * @param domain The bundle ID of the plug-in.
380 #define WRITE_GROWL_PREF_INT(key, value, domain) do {\
381 CFNumberRef intValue = CFNumberCreate(NULL, kCFNumberIntType, &value); \
382 WRITE_GROWL_PREF_VALUE(key, intValue, domain); \
383 CFRelease(intValue); } while(0)
385 /*! @function READ_GROWL_PREF_FLOAT
386 * @abstract Reads the given float from the plug-in's preferences.
387 * @discussion This is a wrapper around READ_GROWL_PREF_VALUE() intended for
389 * @param key The preference key to read the float from.
390 * @param domain The bundle ID of the plug-in.
391 * @param result A pointer to a float. Leaves unchanged if the value doesn't exist.
393 #define READ_GROWL_PREF_FLOAT(key, domain, result) do {\
394 CFNumberRef floatValue = NULL; \
395 READ_GROWL_PREF_VALUE(key, domain, CFNumberRef, &floatValue); \
397 CFNumberGetValue(floatValue, kCFNumberFloatType, result); \
398 CFRelease(floatValue); \
401 /*! @function WRITE_GROWL_PREF_FLOAT
402 * @abstract Writes the given float to the plug-in's preferences.
403 * @discussion This is a wrapper around WRITE_GROWL_PREF_VALUE() intended for
405 * @param key The preference key to write the float for.
406 * @param value The float value to write to the preferences.
407 * @param domain The bundle ID of the plug-in.
409 #define WRITE_GROWL_PREF_FLOAT(key, value, domain) do {\
410 CFNumberRef floatValue = CFNumberCreate(NULL, kCFNumberFloatType, &value); \
411 WRITE_GROWL_PREF_VALUE(key, floatValue, domain); \
412 CFRelease(floatValue); } while(0)
415 /*! @defined GROWL_CLOSE_ALL_NOTIFICATIONS
416 * @abstract Notification to close all Growl notifications
417 * @discussion Should be posted to the default notification center when a close widget is option+clicked.
418 * All notifications should close in response.
420 #define GROWL_CLOSE_ALL_NOTIFICATIONS XSTR("GrowlCloseAllNotifications")
422 #pragma mark Small utilities
425 * @defined FLOAT_EQ(x,y)
426 * @abstract Compares two floats.
428 #define FLOAT_EQ(x,y) (((y - FLT_EPSILON) < x) && (x < (y + FLT_EPSILON)))
430 #endif //ndef _GROWL_GROWLDEFINESINTERNAL_H