Burninating LoginItemsAE. We use LSSharedFileList now.
Also, first use of fast enumeration in Growl code! Woo!
1.1 --- a/Common/Source/LoginItemsAE.c Sun Aug 02 00:52:57 2009 -0700
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,805 +0,0 @@
1.4 - /*
1.5 - File: LoginItemsAE.c
1.6 -
1.7 - Contains: Login items manipulation via Apple events.
1.8 -
1.9 - Copyright: Copyright (c) 2005 by Apple Computer, Inc., All Rights Reserved.
1.10 -
1.11 - Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
1.12 - ("Apple") in consideration of your agreement to the following terms, and your
1.13 - use, installation, modification or redistribution of this Apple software
1.14 - constitutes acceptance of these terms. If you do not agree with these terms,
1.15 - please do not use, install, modify or redistribute this Apple software.
1.16 -
1.17 - In consideration of your agreement to abide by the following terms, and subject
1.18 - to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
1.19 - copyrights in this original Apple software (the "Apple Software"), to use,
1.20 - reproduce, modify and redistribute the Apple Software, with or without
1.21 - modifications, in source and/or binary forms; provided that if you redistribute
1.22 - the Apple Software in its entirety and without modifications, you must retain
1.23 - this notice and the following text and disclaimers in all such redistributions of
1.24 - the Apple Software. Neither the name, trademarks, service marks or logos of
1.25 - Apple Computer, Inc. may be used to endorse or promote products derived from the
1.26 - Apple Software without specific prior written permission from Apple. Except as
1.27 - expressly stated in this notice, no other rights or licenses, express or implied,
1.28 - are granted by Apple herein, including but not limited to any patent rights that
1.29 - may be infringed by your derivative works or by other works in which the Apple
1.30 - Software may be incorporated.
1.31 -
1.32 - The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
1.33 - WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
1.34 - WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1.35 - PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
1.36 - COMBINATION WITH YOUR PRODUCTS.
1.37 -
1.38 - IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
1.39 - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
1.40 - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1.41 - ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
1.42 - OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
1.43 - (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
1.44 - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.45 -
1.46 - Change History (most recent first):
1.47 -
1.48 -$Log: LoginItemsAE.c,v $
1.49 -Revision 1.1 2005/09/27 12:29:26
1.50 -First checked in.
1.51 -
1.52 -
1.53 -*/
1.54 -
1.55 -/////////////////////////////////////////////////////////////////
1.56 -
1.57 -// Our prototypes
1.58 -
1.59 -#include "LoginItemsAE.h"
1.60 -
1.61 -// System interfaces
1.62 -
1.63 -// We need to pull in all of Carbon just to get the definition of
1.64 -// pProperties. *sigh* This is purely a compile-time dependency,
1.65 -// which is why we include it in the implementation and not the
1.66 -// header.
1.67 -
1.68 -#include <Carbon/Carbon.h>
1.69 -
1.70 -#include <string.h>
1.71 -
1.72 -extern OSStatus LSOpenApplication() __attribute__((weak_import));
1.73 -
1.74 -/////////////////////////////////////////////////////////////////
1.75 -#pragma mark ***** Apple event utilities
1.76 -
1.77 -enum {
1.78 - kSystemEventsCreator = 'sevs'
1.79 -};
1.80 -
1.81 -static OSStatus LaunchSystemEvents(ProcessSerialNumber *psnPtr)
1.82 - // Launches the "System Events" process.
1.83 -{
1.84 - OSStatus err;
1.85 - FSRef appRef;
1.86 -
1.87 - assert(psnPtr != NULL);
1.88 -
1.89 - // Ask Launch Services to find System Events by creator.
1.90 -
1.91 - err = LSFindApplicationForInfo(
1.92 - kSystemEventsCreator,
1.93 - NULL,
1.94 - NULL,
1.95 - &appRef,
1.96 - NULL
1.97 - );
1.98 -
1.99 - // Launch it!
1.100 -
1.101 - if (err == noErr) {
1.102 - if (LSOpenApplication) {
1.103 - LSApplicationParameters appParams;
1.104 -
1.105 - // Do it the easy way on 10.4 and later.
1.106 -
1.107 - memset(&appParams, 0, sizeof(appParams));
1.108 - appParams.version = 0;
1.109 - appParams.flags = kLSLaunchDefaults;
1.110 - appParams.application = &appRef;
1.111 -
1.112 - err = LSOpenApplication(&appParams, psnPtr);
1.113 - } else {
1.114 - FSSpec appSpec;
1.115 - LaunchParamBlockRec lpb;
1.116 -
1.117 - // Do it the compatible way on earlier systems.
1.118 -
1.119 - // I launch System Events using LaunchApplication, rather than
1.120 - // Launch Services, because LaunchApplication gives me back
1.121 - // the ProcessSerialNumber. Unfortunately this requires me to
1.122 - // get an FSSpec for the application because there's no
1.123 - // FSRef version of Launch Application.
1.124 -
1.125 -#ifdef __LP64__
1.126 -#pragma unused(appSpec)
1.127 -#else
1.128 - if (err == noErr)
1.129 - err = FSGetCatalogInfo(&appRef, kFSCatInfoNone, NULL, NULL, &appSpec, NULL);
1.130 -#endif
1.131 - if (err == noErr) {
1.132 - memset(&lpb, 0, sizeof(lpb));
1.133 - lpb.launchBlockID = extendedBlock;
1.134 - lpb.launchEPBLength = extendedBlockLen;
1.135 - lpb.launchControlFlags = launchContinue | launchNoFileFlags;
1.136 -#ifdef __LP64__
1.137 - lpb.launchAppRef = &appRef;
1.138 -#else
1.139 - lpb.launchAppSpec = &appSpec;
1.140 -#endif
1.141 -
1.142 - err = LaunchApplication(&lpb);
1.143 - }
1.144 - if (err == noErr)
1.145 - *psnPtr = lpb.launchProcessSN;
1.146 - }
1.147 - }
1.148 -
1.149 - return err;
1.150 -}
1.151 -
1.152 -static OSStatus FindSystemEvents(ProcessSerialNumber *psnPtr)
1.153 - // Finds the "System Events" process or, if it's not
1.154 - // running, launches it.
1.155 -{
1.156 - OSStatus err;
1.157 - Boolean found;
1.158 - ProcessInfoRec info;
1.159 -
1.160 - assert(psnPtr != NULL);
1.161 -
1.162 - found = false;
1.163 - psnPtr->lowLongOfPSN = kNoProcess;
1.164 - psnPtr->highLongOfPSN = kNoProcess;
1.165 -
1.166 - do {
1.167 - err = GetNextProcess(psnPtr);
1.168 - if (err == noErr) {
1.169 - memset(&info, 0, sizeof(info));
1.170 - err = GetProcessInformation(psnPtr, &info);
1.171 - }
1.172 - if (err == noErr)
1.173 - found = (info.processSignature == kSystemEventsCreator);
1.174 - } while ((err == noErr) && !found);
1.175 -
1.176 - if (err == procNotFound)
1.177 - err = LaunchSystemEvents(psnPtr);
1.178 - return err;
1.179 -}
1.180 -
1.181 -#if ! defined(LOGIN_ITEMS_AE_PRINT_DESC)
1.182 - #if defined(NDEBUG)
1.183 - #define LOGIN_ITEMS_AE_PRINT_DESC 0
1.184 - #else
1.185 - #define LOGIN_ITEMS_AE_PRINT_DESC 0 // change this to 1 to get output in debug build
1.186 - #endif
1.187 -#endif
1.188 -
1.189 -static OSStatus SendAppleEvent(const AEDesc *event, AEDesc *reply)
1.190 - // This is the bottleneck routine we use for sending Apple events.
1.191 - // It has a number of neato features.
1.192 - //
1.193 - // o It use the "AEMach.h" routine AESendMessage because that allows
1.194 - // us to do an RPC without having to field UI events while waiting
1.195 - // for the reply. Yay for Mac OS X!
1.196 - //
1.197 - // o It automatically extracts the error from the reply.
1.198 - //
1.199 - // o It allows you to enable printing of events and their replies
1.200 - // for debugging purposes.
1.201 -{
1.202 - static const long kAETimeoutTicks = 5 * 60;
1.203 - OSStatus err;
1.204 - OSErr replyErr;
1.205 - DescType junkType;
1.206 - Size junkSize;
1.207 -
1.208 - // Normally I don't declare function prototypes in local scope,
1.209 - // but I made this exception because I don't want anyone except
1.210 - // for this routine calling GDBPrintAEDesc. This routine takes
1.211 - // care to only link with the routine when debugging is enabled;
1.212 - // everyone else might not be so careful.
1.213 -
1.214 - #if LOGIN_ITEMS_AE_PRINT_DESC
1.215 -
1.216 - extern void GDBPrintAEDesc(const AEDesc *desc);
1.217 - // This is private system function used to print a
1.218 - // textual representation of an AEDesc to stderr.
1.219 - // It's very handy when debugging, and is meant only
1.220 - // for that purpose. It's only available to Mach-O
1.221 - // clients. We use it when debugging *only*.
1.222 -
1.223 - #endif
1.224 -
1.225 - assert(event != NULL);
1.226 - assert(reply != NULL);
1.227 -
1.228 - #if LOGIN_ITEMS_AE_PRINT_DESC
1.229 - GDBPrintAEDesc(event);
1.230 - #endif
1.231 -
1.232 - err = AESendMessage(event, reply, kAEWaitReply, kAETimeoutTicks);
1.233 -
1.234 - #if LOGIN_ITEMS_AE_PRINT_DESC
1.235 - GDBPrintAEDesc(reply);
1.236 - #endif
1.237 -
1.238 - // Extract any error from the Apple event handler via the
1.239 - // keyErrorNumber parameter of the reply.
1.240 -
1.241 - if ((err == noErr) && (reply->descriptorType != typeNull)) {
1.242 - err = AEGetParamPtr(
1.243 - reply,
1.244 - keyErrorNumber,
1.245 - typeSInt16,
1.246 - &junkType,
1.247 - &replyErr,
1.248 - sizeof(replyErr),
1.249 - &junkSize
1.250 - );
1.251 -
1.252 - if (err == errAEDescNotFound )
1.253 - err = noErr;
1.254 - else
1.255 - err = replyErr;
1.256 - }
1.257 -
1.258 - return err;
1.259 -}
1.260 -
1.261 -/////////////////////////////////////////////////////////////////
1.262 -#pragma mark ***** Constants from Login Items AppleScript Dictionary
1.263 -
1.264 -enum {
1.265 - cLoginItem = 'logi',
1.266 -
1.267 - propPath = 'ppth',
1.268 - propHidden = 'hidn'
1.269 -};
1.270 -
1.271 -/////////////////////////////////////////////////////////////////
1.272 -#pragma mark ***** Public routines (and helpers)
1.273 -
1.274 -static const AEDesc kAENull = { typeNull, NULL };
1.275 -
1.276 -static void AEDisposeDescQ(AEDesc *descPtr)
1.277 -{
1.278 - OSStatus junk;
1.279 -
1.280 - junk = AEDisposeDesc(descPtr);
1.281 - assert(junk == noErr);
1.282 - *descPtr = kAENull;
1.283 -}
1.284 -
1.285 -static OSStatus CreateCFArrayFromAEDescList(
1.286 - const AEDescList * descList,
1.287 - CFArrayRef * itemsPtr
1.288 -)
1.289 - // This routine's input is an AEDescList that contains replies
1.290 - // from the "properties of every login item" event. Each element
1.291 - // of the list is an AERecord with two important properties,
1.292 - // "path" and "hidden". This routine creates a CFArray that
1.293 - // corresponds to this list. Each element of the CFArray
1.294 - // contains two properties, kLIAEURL and
1.295 - // kLIAEHidden, that are derived from the corresponding
1.296 - // AERecord properties.
1.297 - //
1.298 - // On entry, descList must not be NULL
1.299 - // On entry, itemsPtr must not be NULL
1.300 - // On entry, *itemsPtr must be NULL
1.301 - // On success, *itemsPtr will be a valid CFArray
1.302 - // On error, *itemsPtr will be NULL
1.303 -{
1.304 - OSStatus err;
1.305 - CFMutableArrayRef result;
1.306 - long itemCount;
1.307 - long itemIndex;
1.308 - AEKeyword junkKeyword;
1.309 - DescType junkType;
1.310 - Size junkSize;
1.311 -
1.312 - assert( itemsPtr != NULL);
1.313 - assert(*itemsPtr == NULL);
1.314 -
1.315 - result = NULL;
1.316 -
1.317 - // Create a place for the result.
1.318 -
1.319 - err = noErr;
1.320 - result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1.321 - if (!result)
1.322 - err = coreFoundationUnknownErr;
1.323 -
1.324 - // For each element in the descriptor list...
1.325 -
1.326 - if (err == noErr)
1.327 - err = AECountItems(descList, &itemCount);
1.328 - if (err == noErr) {
1.329 - for (itemIndex = 1; itemIndex <= itemCount; itemIndex++) {
1.330 - AERecord thisItem;
1.331 - UInt8 thisPath[1024];
1.332 - Size thisPathSize;
1.333 - FSRef thisItemRef;
1.334 - CFURLRef thisItemURL;
1.335 - Boolean thisItemHidden;
1.336 - CFDictionaryRef thisItemDict;
1.337 -
1.338 - thisItem = kAENull;
1.339 - thisItemURL = NULL;
1.340 - thisItemDict = NULL;
1.341 -
1.342 - // Get this element's AERecord.
1.343 -
1.344 - err = AEGetNthDesc(descList, itemIndex, typeAERecord, &junkKeyword, &thisItem);
1.345 -
1.346 - // Extract the path and create a CFURL.
1.347 -
1.348 - if (err == noErr)
1.349 - err = AEGetKeyPtr(
1.350 - &thisItem,
1.351 - propPath,
1.352 - typeUTF8Text,
1.353 - &junkType,
1.354 - thisPath,
1.355 - sizeof(thisPath) - 1, // to ensure that we can always add null terminator
1.356 - &thisPathSize
1.357 - );
1.358 - if (err == noErr) {
1.359 - thisPath[thisPathSize] = 0;
1.360 -
1.361 - err = FSPathMakeRef(thisPath, &thisItemRef, NULL);
1.362 -
1.363 - if (err == noErr) {
1.364 - thisItemURL = CFURLCreateFromFSRef(kCFAllocatorDefault, &thisItemRef);
1.365 - } else {
1.366 - err = noErr; // swallow error and create an imprecise URL
1.367 -
1.368 - thisItemURL = CFURLCreateFromFileSystemRepresentation(
1.369 - NULL,
1.370 - thisPath,
1.371 - thisPathSize,
1.372 - false
1.373 - );
1.374 - }
1.375 - if (!thisItemURL)
1.376 - err = coreFoundationUnknownErr;
1.377 - }
1.378 -
1.379 - // Extract the hidden flag.
1.380 -
1.381 - if (err == noErr) {
1.382 - err = AEGetKeyPtr(
1.383 - &thisItem,
1.384 - propHidden,
1.385 - typeBoolean,
1.386 - &junkType,
1.387 - &thisItemHidden,
1.388 - sizeof(thisItemHidden),
1.389 - &junkSize
1.390 - );
1.391 -
1.392 - // Work around <rdar://problem/4052117> by assuming that hidden
1.393 - // is false if we can't get its value.
1.394 -
1.395 - if (err != noErr) {
1.396 - thisItemHidden = false;
1.397 - err = noErr;
1.398 - }
1.399 - }
1.400 -
1.401 - // Create the CFDictionary for this item.
1.402 -
1.403 - if (err == noErr) {
1.404 - CFStringRef keys[2];
1.405 - CFTypeRef values[2];
1.406 -
1.407 - keys[0] = kLIAEURL;
1.408 - keys[1] = kLIAEHidden;
1.409 -
1.410 - values[0] = thisItemURL;
1.411 - values[1] = (thisItemHidden ? kCFBooleanTrue : kCFBooleanFalse);
1.412 -
1.413 - thisItemDict = CFDictionaryCreate(
1.414 - kCFAllocatorDefault,
1.415 - (const void **) keys,
1.416 - values,
1.417 - 2,
1.418 - &kCFTypeDictionaryKeyCallBacks,
1.419 - &kCFTypeDictionaryValueCallBacks
1.420 - );
1.421 - if (!thisItemDict)
1.422 - err = coreFoundationUnknownErr;
1.423 - }
1.424 -
1.425 - // Add it to the results array.
1.426 -
1.427 - if (err == noErr)
1.428 - CFArrayAppendValue(result, thisItemDict);
1.429 -
1.430 - AEDisposeDescQ(&thisItem);
1.431 - if (thisItemURL)
1.432 - CFRelease(thisItemURL);
1.433 - if (thisItemDict)
1.434 - CFRelease(thisItemDict);
1.435 -
1.436 - if (err != noErr)
1.437 - break;
1.438 - }
1.439 - }
1.440 -
1.441 - // Clean up.
1.442 -
1.443 - if (err != noErr && result) {
1.444 - CFRelease(result);
1.445 - result = NULL;
1.446 - }
1.447 - *itemsPtr = result;
1.448 - assert((err == noErr) == (*itemsPtr != NULL));
1.449 -
1.450 - return err;
1.451 -}
1.452 -
1.453 -static OSStatus SendEventToSystemEventsWithParameters(
1.454 - AEEventClass theClass,
1.455 - AEEventID theEvent,
1.456 - AppleEvent * reply,
1.457 - ...
1.458 -)
1.459 - // Creates an Apple event and sends it to the System Events
1.460 - // process. theClass and theEvent are the event class and ID,
1.461 - // respectively. If reply is not NULL, the caller gets a copy
1.462 - // of the reply. Following reply is a variable number of Apple event
1.463 - // parameters. Each AE parameter is made up of two C parameters,
1.464 - // the first being the AEKeyword, the second being a pointer to
1.465 - // the AEDesc for that parameter. This list is terminated by an
1.466 - // AEKeyword of value 0.
1.467 - //
1.468 - // You typically call this as:
1.469 - //
1.470 - // err = SendEventToSystemEventsWithParameters(
1.471 - // kClass,
1.472 - // kEvent,
1.473 - // NULL,
1.474 - // param1_keyword, param1_desc_ptr,
1.475 - // param2_keyword, param2_desc_ptr,
1.476 - // 0
1.477 - // );
1.478 - //
1.479 - // On entry, reply must be NULL or *reply must be the null AEDesc.
1.480 - // On success, if reply is not NULL, *reply will be the AE reply
1.481 - // (that is, not a null desc).
1.482 - // On error, if reply is not NULL, *reply will be the null AEDesc.
1.483 -{
1.484 - OSStatus err;
1.485 - ProcessSerialNumber psn;
1.486 - AppleEvent target;
1.487 - AppleEvent event;
1.488 - AppleEvent localReply;
1.489 - AEDescList results;
1.490 -
1.491 - assert((reply == NULL) || (reply->descriptorType == typeNull));
1.492 -
1.493 - target = kAENull;
1.494 - event = kAENull;
1.495 - localReply = kAENull;
1.496 - results = kAENull;
1.497 -
1.498 - // Create Apple event.
1.499 -
1.500 - err = FindSystemEvents(&psn);
1.501 - if (err == noErr)
1.502 - err = AECreateDesc(typeProcessSerialNumber, &psn, sizeof(psn), &target);
1.503 - if (err == noErr)
1.504 - err = AECreateAppleEvent(
1.505 - theClass,
1.506 - theEvent,
1.507 - &target,
1.508 - kAutoGenerateReturnID,
1.509 - kAnyTransactionID,
1.510 - &event
1.511 - );
1.512 -
1.513 - // Handle varargs parameters.
1.514 -
1.515 - if (err == noErr) {
1.516 - va_list ap;
1.517 - AEKeyword thisKeyword;
1.518 - const AEDesc * thisDesc;
1.519 -
1.520 - va_start(ap, reply);
1.521 -
1.522 - do {
1.523 - thisKeyword = va_arg(ap, AEKeyword);
1.524 - if (thisKeyword != 0) {
1.525 - thisDesc = va_arg(ap, const AEDesc *);
1.526 - assert(thisDesc != NULL);
1.527 -
1.528 - err = AEPutParamDesc(&event, thisKeyword, thisDesc);
1.529 - }
1.530 - } while ((err == noErr) && (thisKeyword != 0));
1.531 -
1.532 - va_end(ap);
1.533 - }
1.534 -
1.535 - // Send event and get reply.
1.536 -
1.537 - if (err == noErr)
1.538 - err = SendAppleEvent(&event, &localReply);
1.539 -
1.540 - // Clean up.
1.541 -
1.542 - if (!reply || (err != noErr)) {
1.543 - // *reply is already null because of our precondition
1.544 - AEDisposeDescQ(&localReply);
1.545 - } else {
1.546 - *reply = localReply;
1.547 - }
1.548 - AEDisposeDescQ(&event);
1.549 - AEDisposeDescQ(&target);
1.550 - assert((reply == NULL) || ((err == noErr) == (reply->descriptorType != typeNull)));
1.551 -
1.552 - return err;
1.553 -}
1.554 -
1.555 -extern OSStatus LIAECopyLoginItems(CFArrayRef *itemsPtr)
1.556 - // See comment in header.
1.557 - //
1.558 - // This routine creates an Apple event that corresponds to the
1.559 - // AppleScript:
1.560 - //
1.561 - // get properties of every login item
1.562 - //
1.563 - // and sends it to System Events. It then processes the reply
1.564 - // into a CFArray in the format that's documented in the header
1.565 - // comments.
1.566 -{
1.567 - OSStatus err;
1.568 - AppleEvent reply;
1.569 - AEDescList results;
1.570 - AEDesc propertiesOfEveryLoginItem;
1.571 -
1.572 - assert( itemsPtr != NULL);
1.573 - assert(*itemsPtr == NULL);
1.574 -
1.575 - reply = kAENull;
1.576 - results = kAENull;
1.577 - propertiesOfEveryLoginItem = kAENull;
1.578 -
1.579 - // Build object specifier for "properties of every login item".
1.580 -
1.581 - {
1.582 - static const DescType keyAEPropertiesLocal = pProperties;
1.583 - static const DescType kAEAllLocal = kAEAll;
1.584 - AEDesc every;
1.585 - AEDesc everyLoginItem;
1.586 - AEDesc properties;
1.587 -
1.588 - every = kAENull;
1.589 - everyLoginItem = kAENull;
1.590 - properties = kAENull;
1.591 -
1.592 - err = AECreateDesc(typeAbsoluteOrdinal, &kAEAllLocal, sizeof(kAEAllLocal), &every);
1.593 - if (err == noErr)
1.594 - err = CreateObjSpecifier(cLoginItem, (AEDesc *) &kAENull, formAbsolutePosition, &every, false, &everyLoginItem);
1.595 - if (err == noErr)
1.596 - err = AECreateDesc(typeType, &keyAEPropertiesLocal, sizeof(keyAEPropertiesLocal), &properties);
1.597 - if (err == noErr)
1.598 - err = CreateObjSpecifier(
1.599 - typeProperty,
1.600 - &everyLoginItem,
1.601 - formPropertyID,
1.602 - &properties,
1.603 - false,
1.604 - &propertiesOfEveryLoginItem);
1.605 -
1.606 - AEDisposeDescQ(&every);
1.607 - AEDisposeDescQ(&everyLoginItem);
1.608 - AEDisposeDescQ(&properties);
1.609 - }
1.610 -
1.611 - // Send event and get reply.
1.612 -
1.613 - if (err == noErr)
1.614 - err = SendEventToSystemEventsWithParameters(
1.615 - kAECoreSuite,
1.616 - kAEGetData,
1.617 - &reply,
1.618 - keyDirectObject, &propertiesOfEveryLoginItem,
1.619 - 0
1.620 - );
1.621 -
1.622 - // Process reply.
1.623 -
1.624 - if (err == noErr)
1.625 - err = AEGetParamDesc(&reply, keyDirectObject, typeAEList, &results);
1.626 - if (err == noErr)
1.627 - err = CreateCFArrayFromAEDescList(&results, itemsPtr);
1.628 -
1.629 - // Clean up.
1.630 -
1.631 - AEDisposeDescQ(&reply);
1.632 - AEDisposeDescQ(&results);
1.633 - AEDisposeDescQ(&propertiesOfEveryLoginItem);
1.634 - assert((err == noErr) == (*itemsPtr != NULL));
1.635 -
1.636 - return err;
1.637 -}
1.638 -
1.639 -extern OSStatus LIAEAddRefAtEnd(const FSRef *item, Boolean hideIt)
1.640 - // See comment in header.
1.641 - //
1.642 - // This routine creates an Apple event that corresponds to the
1.643 - // AppleScript:
1.644 - //
1.645 - // make new login item
1.646 - // with properties {
1.647 - // path:<path of item>,
1.648 - // hidden:hideIt
1.649 - // }
1.650 - // at end
1.651 - //
1.652 - // and sends it to System Events.
1.653 -{
1.654 - OSStatus err;
1.655 - AEDesc newLoginItem;
1.656 - AERecord properties;
1.657 - AERecord endLoc;
1.658 - static const DescType cLoginItemLocal = cLoginItem;
1.659 -
1.660 - assert(item != NULL);
1.661 -
1.662 - newLoginItem = kAENull;
1.663 - endLoc = kAENull;
1.664 - properties = kAENull;
1.665 -
1.666 - // Create "new login item" parameter.
1.667 -
1.668 - err = AECreateDesc(typeType, &cLoginItemLocal, sizeof(cLoginItemLocal), &newLoginItem);
1.669 -
1.670 - // Create "with properties" parameter.
1.671 -
1.672 - if (err == noErr) {
1.673 - char path[1024];
1.674 - AEDesc pathDesc;
1.675 -
1.676 - pathDesc = kAENull;
1.677 -
1.678 - err = AECreateList(NULL, 0, true, &properties);
1.679 - if (err == noErr)
1.680 - err = FSRefMakePath(item, (UInt8 *) path, (UInt32)sizeof(path));
1.681 -
1.682 - // System Events complains if you pass it typeUTF8Text directly, so
1.683 - // we do the conversion from typeUTF8Text to typeUnicodeText on our
1.684 - // side of the world.
1.685 -
1.686 - if (err == noErr)
1.687 - err = AECoercePtr(typeUTF8Text, path, (Size) strlen(path), typeUnicodeText, &pathDesc);
1.688 - if (err == noErr)
1.689 - err = AEPutKeyDesc(&properties, propPath, &pathDesc);
1.690 - if (err == noErr)
1.691 - err = AEPutKeyPtr(&properties, propHidden, typeBoolean, &hideIt, sizeof(hideIt));
1.692 -
1.693 - AEDisposeDescQ(&pathDesc);
1.694 - }
1.695 -
1.696 - // Create "at end" parameter.
1.697 -
1.698 - if (err == noErr) {
1.699 - AERecord end;
1.700 - static const DescType kAEEndLocal = kAEEnd;
1.701 -
1.702 - end = kAENull;
1.703 -
1.704 - err = AECreateList(NULL, 0, true, &end);
1.705 - if (err == noErr)
1.706 - err = AEPutKeyPtr(&end, keyAEObject, typeNull, NULL, 0);
1.707 - if (err == noErr)
1.708 - err = AEPutKeyPtr(&end, keyAEPosition, typeEnumerated, &kAEEndLocal, (Size) sizeof(kAEEndLocal));
1.709 - if (err == noErr)
1.710 - err = AECoerceDesc(&end, cInsertionLoc, &endLoc);
1.711 -
1.712 - AEDisposeDescQ(&end);
1.713 - }
1.714 -
1.715 - // Send the event.
1.716 -
1.717 - if (err == noErr)
1.718 - err = SendEventToSystemEventsWithParameters(
1.719 - kAECoreSuite,
1.720 - kAECreateElement,
1.721 - NULL,
1.722 - keyAEObjectClass, &newLoginItem,
1.723 - keyAEPropData, &properties,
1.724 - keyAEInsertHere, &endLoc,
1.725 - 0
1.726 - );
1.727 -
1.728 - // Clean up.
1.729 -
1.730 - AEDisposeDescQ(&newLoginItem);
1.731 - AEDisposeDescQ(&endLoc);
1.732 - AEDisposeDescQ(&properties);
1.733 -
1.734 - return err;
1.735 -}
1.736 -
1.737 -extern OSStatus LIAEAddURLAtEnd(CFURLRef item, Boolean hideIt)
1.738 - // See comment in header.
1.739 - //
1.740 - // This is implemented as a wrapper around LIAEAddRef.
1.741 - // I chose to do it this way because an URL can reference a
1.742 - // file that doesn't except, whereas an FSRef can't, so by
1.743 - // having the URL routine call the FSRef routine, I naturally
1.744 - // ensure that the item exists on disk.
1.745 -{
1.746 - OSStatus err;
1.747 - Boolean success;
1.748 - FSRef ref;
1.749 -
1.750 - assert(item != NULL);
1.751 -
1.752 - success = CFURLGetFSRef(item, &ref);
1.753 - if (success)
1.754 - err = LIAEAddRefAtEnd(&ref, hideIt);
1.755 - else
1.756 - // I have no idea what went wrong (thanks CF!). Normally I'd
1.757 - // return coreFoundationUnknownErr here, but in this case I'm
1.758 - // going to go out on a limb and say that we have a file not found.
1.759 - err = fnfErr;
1.760 -
1.761 - return err;
1.762 -}
1.763 -
1.764 -extern OSStatus LIAERemove(CFIndex itemIndex)
1.765 - // See comment in header.
1.766 - //
1.767 - // This routine creates an Apple event that corresponds to the
1.768 - // AppleScript:
1.769 - //
1.770 - // delete login item itemIndex
1.771 - //
1.772 - // and sends it to System Events.
1.773 -{
1.774 - OSStatus err;
1.775 - SInt32 itemIndexPlusOne;
1.776 - AEDesc indexDesc;
1.777 - AEDesc loginItemAtIndex;
1.778 -
1.779 - assert(itemIndex >= 0);
1.780 -
1.781 - indexDesc = kAENull;
1.782 - loginItemAtIndex = kAENull;
1.783 -
1.784 - // Build object specifier for "login item X".
1.785 -
1.786 - itemIndexPlusOne = (SInt32)itemIndex + 1; // AppleScript is one-based, CF is zero-based
1.787 - err = AECreateDesc(typeSInt32, &itemIndexPlusOne, sizeof(itemIndexPlusOne), &indexDesc);
1.788 - if (err == noErr)
1.789 - err = CreateObjSpecifier(cLoginItem, (AEDesc *) &kAENull, formAbsolutePosition, &indexDesc, false, &loginItemAtIndex);
1.790 -
1.791 - // Send the event.
1.792 -
1.793 - if (err == noErr)
1.794 - err = SendEventToSystemEventsWithParameters(
1.795 - kAECoreSuite,
1.796 - kAEDelete,
1.797 - NULL,
1.798 - keyDirectObject, &loginItemAtIndex,
1.799 - 0
1.800 - );
1.801 -
1.802 - // Clean up.
1.803 -
1.804 - AEDisposeDescQ(&indexDesc);
1.805 - AEDisposeDescQ(&loginItemAtIndex);
1.806 -
1.807 - return err;
1.808 -}
2.1 --- a/Common/Source/LoginItemsAE.h Sun Aug 02 00:52:57 2009 -0700
2.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2.3 @@ -1,101 +0,0 @@
2.4 -/*
2.5 - File: LoginItemsAE.h
2.6 -
2.7 - Contains: Login items manipulation via Apple events.
2.8 -
2.9 - Copyright: Copyright (c) 2005 by Apple Computer, Inc., All Rights Reserved.
2.10 -
2.11 - Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
2.12 - ("Apple") in consideration of your agreement to the following terms, and your
2.13 - use, installation, modification or redistribution of this Apple software
2.14 - constitutes acceptance of these terms. If you do not agree with these terms,
2.15 - please do not use, install, modify or redistribute this Apple software.
2.16 -
2.17 - In consideration of your agreement to abide by the following terms, and subject
2.18 - to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
2.19 - copyrights in this original Apple software (the "Apple Software"), to use,
2.20 - reproduce, modify and redistribute the Apple Software, with or without
2.21 - modifications, in source and/or binary forms; provided that if you redistribute
2.22 - the Apple Software in its entirety and without modifications, you must retain
2.23 - this notice and the following text and disclaimers in all such redistributions of
2.24 - the Apple Software. Neither the name, trademarks, service marks or logos of
2.25 - Apple Computer, Inc. may be used to endorse or promote products derived from the
2.26 - Apple Software without specific prior written permission from Apple. Except as
2.27 - expressly stated in this notice, no other rights or licenses, express or implied,
2.28 - are granted by Apple herein, including but not limited to any patent rights that
2.29 - may be infringed by your derivative works or by other works in which the Apple
2.30 - Software may be incorporated.
2.31 -
2.32 - The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
2.33 - WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
2.34 - WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2.35 - PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
2.36 - COMBINATION WITH YOUR PRODUCTS.
2.37 -
2.38 - IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
2.39 - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2.40 - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2.41 - ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
2.42 - OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
2.43 - (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
2.44 - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2.45 -
2.46 - Change History (most recent first):
2.47 -
2.48 -$Log: LoginItemsAE.h,v $
2.49 -Revision 1.1 2005/09/27 12:29:29
2.50 -First checked in.
2.51 -
2.52 -
2.53 -*/
2.54 -
2.55 -#ifndef _LOGINITEMSAE_H
2.56 -#define _LOGINITEMSAE_H
2.57 -
2.58 -/////////////////////////////////////////////////////////////////
2.59 -
2.60 -// System prototypes
2.61 -
2.62 -#include <ApplicationServices/ApplicationServices.h>
2.63 -
2.64 -/////////////////////////////////////////////////////////////////
2.65 -
2.66 -#ifdef __cplusplus
2.67 -extern "C" {
2.68 -#endif
2.69 -
2.70 -/////////////////////////////////////////////////////////////////
2.71 -
2.72 -// Keys for the dictionary return by LIAECopyLoginItems.
2.73 -
2.74 -#define kLIAEURL CFSTR("URL") // CFURL
2.75 -#define kLIAEHidden CFSTR("Hidden") // CFBoolean
2.76 -
2.77 -extern OSStatus LIAECopyLoginItems(CFArrayRef *itemsPtr);
2.78 - // Returns an array of CFDictionaries, each one describing a
2.79 - // login item. Each dictionary has two elements,
2.80 - // kLIAEURL and kLIAEHidden, which are
2.81 - // documented above.
2.82 - //
2.83 - // On input, itemsPtr must not be NULL.
2.84 - // On input, *itemsPtr must be NULL.
2.85 - // On success, *itemsPtr will be a pointer to a CFArray.
2.86 - // Or error, *itemsPtr will be NULL.
2.87 -
2.88 -extern OSStatus LIAEAddRefAtEnd(const FSRef *item, Boolean hideIt);
2.89 -extern OSStatus LIAEAddURLAtEnd(CFURLRef item, Boolean hideIt);
2.90 - // Add a new login item at the end of the list, using either
2.91 - // an FSRef or a CFURL. The hideIt parameter controls whether
2.92 - // the item is hidden when it's launched.
2.93 -
2.94 -extern OSStatus LIAERemove(CFIndex itemIndex);
2.95 - // Remove a login item. itemIndex is an index into the array
2.96 - // of login items as returned by LIAECopyLoginItems.
2.97 -
2.98 -/////////////////////////////////////////////////////////////////
2.99 -
2.100 -#ifdef __cplusplus
2.101 -}
2.102 -#endif
2.103 -
2.104 -#endif
3.1 --- a/Core/Source/GrowlPreferencesController.h Sun Aug 02 00:52:57 2009 -0700
3.2 +++ b/Core/Source/GrowlPreferencesController.h Sun Aug 02 13:03:53 2009 -0700
3.3 @@ -50,6 +50,7 @@
3.4 #import "GrowlAbstractSingletonObject.h"
3.5
3.6 @interface GrowlPreferencesController : GrowlAbstractSingletonObject {
3.7 + LSSharedFileListRef loginItems;
3.8 }
3.9
3.10 + (GrowlPreferencesController *) sharedController;
4.1 --- a/Core/Source/GrowlPreferencesController.m Sun Aug 02 00:52:57 2009 -0700
4.2 +++ b/Core/Source/GrowlPreferencesController.m Sun Aug 02 13:03:53 2009 -0700
4.3 @@ -60,12 +60,14 @@
4.4 selector:@selector(growlPreferencesChanged:)
4.5 name:GrowlPreferencesChanged
4.6 object:nil];
4.7 + loginItems = LSSharedFileListCreate(kCFAllocatorDefault, kLSSharedFileListSessionLoginItems, /*options*/ NULL);
4.8 }
4.9 return self;
4.10 }
4.11
4.12 - (void) destroy {
4.13 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
4.14 + CFRelease(loginItems);
4.15
4.16 [super destroy];
4.17 }
4.18 @@ -158,24 +160,28 @@
4.19 #pragma mark Start-at-login control
4.20
4.21 - (BOOL) shouldStartGrowlAtLogin {
4.22 - OSStatus status;
4.23 Boolean foundIt = false;
4.24 - CFArrayRef loginItems = NULL;
4.25
4.26 //get the prefpane bundle and find GHA within it.
4.27 NSString *pathToGHA = [[NSBundle bundleWithIdentifier:GROWL_PREFPANE_BUNDLE_IDENTIFIER] pathForResource:@"GrowlHelperApp" ofType:@"app"];
4.28 //get the file url to GHA.
4.29 CFURLRef urlToGHA = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)pathToGHA, kCFURLPOSIXPathStyle, true);
4.30
4.31 - status = LIAECopyLoginItems(&loginItems);
4.32 - if (status == noErr) {
4.33 - for (CFIndex i=0, count=CFArrayGetCount(loginItems); i<count; ++i) {
4.34 - CFDictionaryRef loginItem = CFArrayGetValueAtIndex(loginItems, i);
4.35 - foundIt = CFEqual(CFDictionaryGetValue(loginItem, kLIAEURL), urlToGHA);
4.36 + UInt32 seed = 0U;
4.37 + NSArray *currentLoginItems = [NSMakeCollectable(LSSharedFileListCopySnapshot(loginItems, &seed)) autorelease];
4.38 + for (id itemObject in currentLoginItems) {
4.39 + LSSharedFileListItemRef item = (LSSharedFileListItemRef)itemObject;
4.40 +
4.41 + UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
4.42 + CFURLRef URL = NULL;
4.43 + OSStatus err = LSSharedFileListItemResolve(item, resolutionFlags, &URL, /*outRef*/ NULL);
4.44 + if (err == noErr) {
4.45 + foundIt = CFEqual(URL, urlToGHA);
4.46 + CFRelease(URL);
4.47 +
4.48 if (foundIt)
4.49 break;
4.50 }
4.51 - CFRelease(loginItems);
4.52 }
4.53
4.54 CFRelease(urlToGHA);
4.55 @@ -191,31 +197,47 @@
4.56
4.57 - (void) setStartAtLogin:(NSString *)path enabled:(BOOL)enabled {
4.58 OSStatus status;
4.59 - CFArrayRef loginItems = NULL;
4.60 - NSURL *url = [NSURL fileURLWithPath:path];
4.61 - NSInteger existingLoginItemIndex = -1;
4.62 -
4.63 - status = LIAECopyLoginItems(&loginItems);
4.64 -
4.65 - if (status == noErr) {
4.66 - NSEnumerator *enumerator = [(NSArray *)loginItems objectEnumerator];
4.67 - NSDictionary *loginItemDict;
4.68 -
4.69 - while ((loginItemDict = [enumerator nextObject])) {
4.70 - if ([[loginItemDict objectForKey:(NSString *)kLIAEURL] isEqual:url]) {
4.71 - existingLoginItemIndex = [(NSArray *)loginItems indexOfObjectIdenticalTo:loginItemDict];
4.72 + CFURLRef URLToToggle = (CFURLRef)[NSURL fileURLWithPath:path];
4.73 + LSSharedFileListItemRef existingItem = NULL;
4.74 +
4.75 + UInt32 seed = 0U;
4.76 + NSArray *currentLoginItems = [NSMakeCollectable(LSSharedFileListCopySnapshot(loginItems, &seed)) autorelease];
4.77 + for (id itemObject in currentLoginItems) {
4.78 + LSSharedFileListItemRef item = (LSSharedFileListItemRef)itemObject;
4.79 +
4.80 + UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
4.81 + CFURLRef URL = NULL;
4.82 + OSStatus err = LSSharedFileListItemResolve(item, resolutionFlags, &URL, /*outRef*/ NULL);
4.83 + if (err == noErr) {
4.84 + Boolean foundIt = CFEqual(URL, URLToToggle);
4.85 + CFRelease(URL);
4.86 +
4.87 + if (foundIt) {
4.88 + existingItem = item;
4.89 break;
4.90 }
4.91 }
4.92 }
4.93
4.94 - if (enabled && (existingLoginItemIndex == -1))
4.95 - LIAEAddURLAtEnd((CFURLRef)url, false);
4.96 - else if (!enabled && (existingLoginItemIndex != -1))
4.97 - LIAERemove(existingLoginItemIndex);
4.98 -
4.99 - if(loginItems)
4.100 - CFRelease(loginItems);
4.101 + if (enabled && (existingItem == NULL)) {
4.102 + NSString *displayName = [[NSFileManager defaultManager] displayNameAtPath:path];
4.103 + IconRef icon = NULL;
4.104 + FSRef ref;
4.105 + Boolean gotRef = CFURLGetFSRef(URLToToggle, &ref);
4.106 + if (gotRef) {
4.107 + status = GetIconRefFromFileInfo(&ref,
4.108 + /*fileNameLength*/ 0, /*fileName*/ NULL,
4.109 + kFSCatInfoNone, /*catalogInfo*/ NULL,
4.110 + kIconServicesNormalUsageFlag,
4.111 + &icon,
4.112 + /*outLabel*/ NULL);
4.113 + if (status != noErr)
4.114 + icon = NULL;
4.115 + }
4.116 +
4.117 + LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, (CFStringRef)displayName, icon, URLToToggle, /*propertiesToSet*/ NULL, /*propertiesToClear*/ NULL);
4.118 + } else if (!enabled && (existingItem != NULL))
4.119 + LSSharedFileListItemRemove(loginItems, existingItem);
4.120 }
4.121
4.122 #pragma mark -
5.1 --- a/Growl.xcodeproj/project.pbxproj Sun Aug 02 00:52:57 2009 -0700
5.2 +++ b/Growl.xcodeproj/project.pbxproj Sun Aug 02 13:03:53 2009 -0700
5.3 @@ -329,9 +329,6 @@
5.4 95EC864C08DDB4D800110810 /* CFDictionaryAdditions.c in Sources */ = {isa = PBXBuildFile; fileRef = 95F9767A084A297400915BFE /* CFDictionaryAdditions.c */; };
5.5 95EC864D08DDB4DD00110810 /* CFDictionaryAdditions.c in Sources */ = {isa = PBXBuildFile; fileRef = 95F9767A084A297400915BFE /* CFDictionaryAdditions.c */; };
5.6 95EC864E08DDB4E600110810 /* CFDictionaryAdditions.c in Sources */ = {isa = PBXBuildFile; fileRef = 95F9767A084A297400915BFE /* CFDictionaryAdditions.c */; };
5.7 - 95F0A21D0904D7EA00BD679D /* LoginItemsAE.c in Sources */ = {isa = PBXBuildFile; fileRef = 95F0A21B0904D7EA00BD679D /* LoginItemsAE.c */; };
5.8 - 95F0A21F0904D7EA00BD679D /* LoginItemsAE.c in Sources */ = {isa = PBXBuildFile; fileRef = 95F0A21B0904D7EA00BD679D /* LoginItemsAE.c */; };
5.9 - 95F0A2200904D7EA00BD679D /* LoginItemsAE.c in Sources */ = {isa = PBXBuildFile; fileRef = 95F0A21B0904D7EA00BD679D /* LoginItemsAE.c */; };
5.10 95F975AE084A23F500915BFE /* CFMutableDictionaryAdditions.c in Sources */ = {isa = PBXBuildFile; fileRef = 95F975AC084A23F500915BFE /* CFMutableDictionaryAdditions.c */; };
5.11 95F9767C084A297400915BFE /* CFDictionaryAdditions.c in Sources */ = {isa = PBXBuildFile; fileRef = 95F9767A084A297400915BFE /* CFDictionaryAdditions.c */; };
5.12 95F9771E084A2C7700915BFE /* CFMutableDictionaryAdditions.c in Sources */ = {isa = PBXBuildFile; fileRef = 95F975AC084A23F500915BFE /* CFMutableDictionaryAdditions.c */; };
5.13 @@ -1073,8 +1070,6 @@
5.14 95E2458008EEAC8F0092EAAC /* GrowlNotificationDisplayBridge.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = GrowlNotificationDisplayBridge.m; path = Plugins/Displays/GrowlNotificationDisplayBridge.m; sourceTree = "<group>"; };
5.15 95E678F307511471002BF4E6 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
5.16 95EF04F207C77C1500218584 /* CoreGraphicsServices.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = CoreGraphicsServices.h; path = Core/Source/CoreGraphicsServices.h; sourceTree = "<group>"; };
5.17 - 95F0A21B0904D7EA00BD679D /* LoginItemsAE.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = LoginItemsAE.c; path = Common/Source/LoginItemsAE.c; sourceTree = "<group>"; };
5.18 - 95F0A21C0904D7EA00BD679D /* LoginItemsAE.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = LoginItemsAE.h; path = Common/Source/LoginItemsAE.h; sourceTree = "<group>"; };
5.19 95F975AB084A23F500915BFE /* CFMutableDictionaryAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFMutableDictionaryAdditions.h; path = Common/Source/CFMutableDictionaryAdditions.h; sourceTree = "<group>"; };
5.20 95F975AC084A23F500915BFE /* CFMutableDictionaryAdditions.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = CFMutableDictionaryAdditions.c; path = Common/Source/CFMutableDictionaryAdditions.c; sourceTree = "<group>"; };
5.21 95F97679084A297400915BFE /* CFDictionaryAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFDictionaryAdditions.h; path = Common/Source/CFDictionaryAdditions.h; sourceTree = "<group>"; };
5.22 @@ -1373,8 +1368,6 @@
5.23 070C1AF80912D1F500884E7D /* Headers */,
5.24 0790135207D932140023B640 /* GrowlVersionUtilities.h */,
5.25 0790135507D9321B0023B640 /* GrowlVersionUtilities.c */,
5.26 - 95F0A21C0904D7EA00BD679D /* LoginItemsAE.h */,
5.27 - 95F0A21B0904D7EA00BD679D /* LoginItemsAE.c */,
5.28 95CF98A0082A5B8E001A409D /* cdsa.h */,
5.29 95CF98A1082A5B8E001A409D /* cdsa.c */,
5.30 );
5.31 @@ -2858,7 +2851,6 @@
5.32 95E2457808EEAC630092EAAC /* GrowlDisplayPlugin.m in Sources */,
5.33 95E2458208EEAC8F0092EAAC /* GrowlNotificationDisplayBridge.m in Sources */,
5.34 95E246A008EF02E80092EAAC /* GrowlPositionController.m in Sources */,
5.35 - 95F0A21D0904D7EA00BD679D /* LoginItemsAE.c in Sources */,
5.36 743EDE0809273C8A002A9670 /* GrowlWebKitPluginHandler.m in Sources */,
5.37 743EDE14092740F5002A9670 /* GrowlWebKitDisplayPlugin.m in Sources */,
5.38 743EE18E0927A85E002A9670 /* GrowlNonCopyingMutableDictionary.m in Sources */,
5.39 @@ -2911,7 +2903,6 @@
5.40 9507CEA208C9D6C900209F9E /* CFMutableDictionaryAdditions.c in Sources */,
5.41 9555388808DACC1B00D49CB1 /* CFDictionaryAdditions.c in Sources */,
5.42 9555388908DACC2500D49CB1 /* CFGrowlAdditions.c in Sources */,
5.43 - 95F0A21F0904D7EA00BD679D /* LoginItemsAE.c in Sources */,
5.44 934EBCB80931F529002C378F /* GrowlApplicationBridge.m in Sources */,
5.45 );
5.46 runOnlyForDeploymentPostprocessing = 0;
5.47 @@ -2981,7 +2972,6 @@
5.48 95E2457A08EEAC630092EAAC /* GrowlDisplayPlugin.m in Sources */,
5.49 95E2458408EEAC8F0092EAAC /* GrowlNotificationDisplayBridge.m in Sources */,
5.50 EE17E56D08EFFCDB0086F0C3 /* GrowlThreadedView.m in Sources */,
5.51 - 95F0A2200904D7EA00BD679D /* LoginItemsAE.c in Sources */,
5.52 070C1AE80912D16600884E7D /* GrowlNonCopyingMutableDictionary.m in Sources */,
5.53 745352AF09313ABA0000B26A /* GrowlWebKitPrefsController.m in Sources */,
5.54 745352B009313ABB0000B26A /* GrowlWebKitPluginHandler.m in Sources */,