Permalink
Browse files

Make the start at login option work.

Use playdar as playdar to prevent confusion, added a build step to
rename the prefpane binary to playdar.prefPane to avoid conflict. Smart.
  • Loading branch information...
1 parent fd5aa7d commit 40403448cc277300c7d6d92a875b4d46417be674 @mxcl committed Mar 6, 2009
Showing with 1,010 additions and 36 deletions.
  1. +23 −3 English.lproj/main.xib
  2. +1 −1 Info.plist
  3. +797 −0 LoginItemsAE.c
  4. +88 −0 LoginItemsAE.h
  5. +5 −1 main.h
  6. +76 −14 main.m
  7. +20 −17 playdar.prefPane.xcodeproj/project.pbxproj
View
26 English.lproj/main.xib
@@ -295,6 +295,22 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA</bytes>
</object>
<int key="connectionID">140</int>
</object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">check</string>
+ <reference key="source" ref="294453543"/>
+ <reference key="destination" ref="558698099"/>
+ </object>
+ <int key="connectionID">141</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">onStartAtLogin:</string>
+ <reference key="source" ref="294453543"/>
+ <reference key="destination" ref="558698099"/>
+ </object>
+ <int key="connectionID">142</int>
+ </object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@@ -503,9 +519,9 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA</bytes>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{163, 866}, {341, 158}}</string>
+ <string>{{1027, 998}, {341, 158}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{163, 866}, {341, 158}}</string>
+ <string>{{1027, 998}, {341, 158}}</string>
<integer value="1" id="5"/>
<reference ref="5"/>
<string>{3.40282e+38, 3.40282e+38}</string>
@@ -545,7 +561,7 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA</bytes>
</object>
</object>
<nil key="sourceID"/>
- <int key="maxID">140</int>
+ <int key="maxID">142</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -592,25 +608,29 @@ ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA</bytes>
<bool key="EncodedWithXMLCoder">YES</bool>
<string>onScan:</string>
<string>onStart:</string>
+ <string>onStartAtLogin:</string>
<string>select:</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>id</string>
<string>id</string>
<string>id</string>
+ <string>id</string>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMutableArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
+ <string>check</string>
<string>popup</string>
<string>scan</string>
<string>start</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSButton</string>
<string>NSPopUpButton</string>
<string>NSButton</string>
<string>NSButton</string>
View
2 Info.plist
@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
- <string>${EXECUTABLE_NAME}</string>
+ <string>playdar.prefPane</string>
<key>CFBundleIconFile</key>
<string>playdar.icns</string>
<key>CFBundleIdentifier</key>
View
797 LoginItemsAE.c
@@ -0,0 +1,797 @@
+/*
+ File: LoginItemsAE.c
+
+ Contains: Login items manipulation via Apple events.
+
+ Copyright: Copyright (c) 2005 by Apple Computer, Inc., All Rights Reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple’s
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Change History (most recent first):
+
+ $Log: LoginItemsAE.c,v $
+ Revision 1.1 2005/09/27 12:29:26
+ First checked in.
+
+
+ */
+
+/////////////////////////////////////////////////////////////////
+
+// Our prototypes
+
+#include "LoginItemsAE.h"
+
+// System interfaces
+
+// We need to pull in all of Carbon just to get the definition of
+// pProperties. *sigh* This is purely a compile-time dependency,
+// which is why we include it in the implementation and not the
+// header.
+
+#include <Carbon/Carbon.h>
+
+#include <string.h>
+
+extern OSStatus LSOpenApplication() __attribute__((weak_import));
+
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** Apple event utilities
+
+enum {
+ kSystemEventsCreator = 'sevs'
+};
+
+static OSStatus LaunchSystemEvents(ProcessSerialNumber *psnPtr)
+// Launches the "System Events" process.
+{
+ OSStatus err;
+ FSRef appRef;
+
+ assert(psnPtr != NULL);
+
+ // Ask Launch Services to find System Events by creator.
+
+ err = LSFindApplicationForInfo(
+ kSystemEventsCreator,
+ NULL,
+ NULL,
+ &appRef,
+ NULL
+ );
+
+ // Launch it!
+
+ if (err == noErr) {
+ if (LSOpenApplication) {
+ LSApplicationParameters appParams;
+
+ // Do it the easy way on 10.4 and later.
+
+ memset(&appParams, 0, sizeof(appParams));
+ appParams.version = 0;
+ appParams.flags = kLSLaunchDefaults;
+ appParams.application = &appRef;
+
+ err = LSOpenApplication(&appParams, psnPtr);
+ } else {
+ FSSpec appSpec;
+ LaunchParamBlockRec lpb;
+
+ // Do it the compatible way on earlier systems.
+
+ // I launch System Events using LaunchApplication, rather than
+ // Launch Services, because LaunchApplication gives me back
+ // the ProcessSerialNumber. Unfortunately this requires me to
+ // get an FSSpec for the application because there's no
+ // FSRef version of Launch Application.
+
+ if (err == noErr)
+ err = FSGetCatalogInfo(&appRef, kFSCatInfoNone, NULL, NULL, &appSpec, NULL);
+ if (err == noErr) {
+ memset(&lpb, 0, sizeof(lpb));
+ lpb.launchBlockID = extendedBlock;
+ lpb.launchEPBLength = extendedBlockLen;
+ lpb.launchControlFlags = launchContinue | launchNoFileFlags;
+ lpb.launchAppSpec = &appSpec;
+
+ err = LaunchApplication(&lpb);
+ }
+ if (err == noErr)
+ *psnPtr = lpb.launchProcessSN;
+ }
+ }
+
+ return err;
+}
+
+static OSStatus FindSystemEvents(ProcessSerialNumber *psnPtr)
+// Finds the "System Events" process or, if it's not
+// running, launches it.
+{
+ OSStatus err;
+ Boolean found;
+ ProcessInfoRec info;
+
+ assert(psnPtr != NULL);
+
+ found = false;
+ psnPtr->lowLongOfPSN = kNoProcess;
+ psnPtr->highLongOfPSN = kNoProcess;
+
+ do {
+ err = GetNextProcess(psnPtr);
+ if (err == noErr) {
+ memset(&info, 0, sizeof(info));
+ err = GetProcessInformation(psnPtr, &info);
+ }
+ if (err == noErr)
+ found = (info.processSignature == kSystemEventsCreator);
+ } while ((err == noErr) && !found);
+
+ if (err == procNotFound)
+ err = LaunchSystemEvents(psnPtr);
+ return err;
+}
+
+#if ! defined(LOGIN_ITEMS_AE_PRINT_DESC)
+#if defined(NDEBUG)
+#define LOGIN_ITEMS_AE_PRINT_DESC 0
+#else
+#define LOGIN_ITEMS_AE_PRINT_DESC 0 // change this to 1 to get output in debug build
+#endif
+#endif
+
+static OSStatus SendAppleEvent(const AEDesc *event, AEDesc *reply)
+// This is the bottleneck routine we use for sending Apple events.
+// It has a number of neato features.
+//
+// o It use the "AEMach.h" routine AESendMessage because that allows
+// us to do an RPC without having to field UI events while waiting
+// for the reply. Yay for Mac OS X!
+//
+// o It automatically extracts the error from the reply.
+//
+// o It allows you to enable printing of events and their replies
+// for debugging purposes.
+{
+ static const long kAETimeoutTicks = 5 * 60;
+ OSStatus err;
+ OSErr replyErr;
+ DescType junkType;
+ Size junkSize;
+
+ // Normally I don't declare function prototypes in local scope,
+ // but I made this exception because I don't want anyone except
+ // for this routine calling GDBPrintAEDesc. This routine takes
+ // care to only link with the routine when debugging is enabled;
+ // everyone else might not be so careful.
+
+#if LOGIN_ITEMS_AE_PRINT_DESC
+
+ extern void GDBPrintAEDesc(const AEDesc *desc);
+ // This is private system function used to print a
+ // textual representation of an AEDesc to stderr.
+ // It's very handy when debugging, and is meant only
+ // for that purpose. It's only available to Mach-O
+ // clients. We use it when debugging *only*.
+
+#endif
+
+ assert(event != NULL);
+ assert(reply != NULL);
+
+#if LOGIN_ITEMS_AE_PRINT_DESC
+ GDBPrintAEDesc(event);
+#endif
+
+ err = AESendMessage(event, reply, kAEWaitReply, kAETimeoutTicks);
+
+#if LOGIN_ITEMS_AE_PRINT_DESC
+ GDBPrintAEDesc(reply);
+#endif
+
+ // Extract any error from the Apple event handler via the
+ // keyErrorNumber parameter of the reply.
+
+ if ((err == noErr) && (reply->descriptorType != typeNull)) {
+ err = AEGetParamPtr(
+ reply,
+ keyErrorNumber,
+ typeShortInteger,
+ &junkType,
+ &replyErr,
+ sizeof(replyErr),
+ &junkSize
+ );
+
+ if (err == errAEDescNotFound )
+ err = noErr;
+ else
+ err = replyErr;
+ }
+
+ return err;
+}
+
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** Constants from Login Items AppleScript Dictionary
+
+enum {
+ cLoginItem = 'logi',
+
+ propPath = 'ppth',
+ propHidden = 'hidn'
+};
+
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** Public routines (and helpers)
+
+static const AEDesc kAENull = { typeNull, NULL };
+
+static void AEDisposeDescQ(AEDesc *descPtr)
+{
+ OSStatus junk;
+
+ junk = AEDisposeDesc(descPtr);
+ assert(junk == noErr);
+ *descPtr = kAENull;
+}
+
+static OSStatus CreateCFArrayFromAEDescList(
+ const AEDescList * descList,
+ CFArrayRef * itemsPtr
+)
+// This routine's input is an AEDescList that contains replies
+// from the "properties of every login item" event. Each element
+// of the list is an AERecord with two important properties,
+// "path" and "hidden". This routine creates a CFArray that
+// corresponds to this list. Each element of the CFArray
+// contains two properties, kLIAEURL and
+// kLIAEHidden, that are derived from the corresponding
+// AERecord properties.
+//
+// On entry, descList must not be NULL
+// On entry, itemsPtr must not be NULL
+// On entry, *itemsPtr must be NULL
+// On success, *itemsPtr will be a valid CFArray
+// On error, *itemsPtr will be NULL
+{
+ OSStatus err;
+ CFMutableArrayRef result;
+ long itemCount;
+ long itemIndex;
+ AEKeyword junkKeyword;
+ DescType junkType;
+ Size junkSize;
+
+ assert( itemsPtr != NULL);
+ assert(*itemsPtr == NULL);
+
+ result = NULL;
+
+ // Create a place for the result.
+
+ err = noErr;
+ result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ if (!result)
+ err = coreFoundationUnknownErr;
+
+ // For each element in the descriptor list...
+
+ if (err == noErr)
+ err = AECountItems(descList, &itemCount);
+ if (err == noErr) {
+ for (itemIndex = 1; itemIndex <= itemCount; itemIndex++) {
+ AERecord thisItem;
+ UInt8 thisPath[1024];
+ Size thisPathSize;
+ FSRef thisItemRef;
+ CFURLRef thisItemURL;
+ Boolean thisItemHidden;
+ CFDictionaryRef thisItemDict;
+
+ thisItem = kAENull;
+ thisItemURL = NULL;
+ thisItemDict = NULL;
+
+ // Get this element's AERecord.
+
+ err = AEGetNthDesc(descList, itemIndex, typeAERecord, &junkKeyword, &thisItem);
+
+ // Extract the path and create a CFURL.
+
+ if (err == noErr)
+ err = AEGetKeyPtr(
+ &thisItem,
+ propPath,
+ typeUTF8Text,
+ &junkType,
+ thisPath,
+ sizeof(thisPath) - 1, // to ensure that we can always add null terminator
+ &thisPathSize
+ );
+ if (err == noErr) {
+ thisPath[thisPathSize] = 0;
+
+ err = FSPathMakeRef(thisPath, &thisItemRef, NULL);
+
+ if (err == noErr) {
+ thisItemURL = CFURLCreateFromFSRef(kCFAllocatorDefault, &thisItemRef);
+ } else {
+ err = noErr; // swallow error and create an imprecise URL
+
+ thisItemURL = CFURLCreateFromFileSystemRepresentation(
+ NULL,
+ thisPath,
+ thisPathSize,
+ false
+ );
+ }
+ if (!thisItemURL)
+ err = coreFoundationUnknownErr;
+ }
+
+ // Extract the hidden flag.
+
+ if (err == noErr) {
+ err = AEGetKeyPtr(
+ &thisItem,
+ propHidden,
+ typeBoolean,
+ &junkType,
+ &thisItemHidden,
+ sizeof(thisItemHidden),
+ &junkSize
+ );
+
+ // Work around <rdar://problem/4052117> by assuming that hidden
+ // is false if we can't get its value.
+
+ if (err != noErr) {
+ thisItemHidden = false;
+ err = noErr;
+ }
+ }
+
+ // Create the CFDictionary for this item.
+
+ if (err == noErr) {
+ CFStringRef keys[2];
+ CFTypeRef values[2];
+
+ keys[0] = kLIAEURL;
+ keys[1] = kLIAEHidden;
+
+ values[0] = thisItemURL;
+ values[1] = (thisItemHidden ? kCFBooleanTrue : kCFBooleanFalse);
+
+ thisItemDict = CFDictionaryCreate(
+ kCFAllocatorDefault,
+ (const void **) keys,
+ values,
+ 2,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks
+ );
+ if (!thisItemDict)
+ err = coreFoundationUnknownErr;
+ }
+
+ // Add it to the results array.
+
+ if (err == noErr)
+ CFArrayAppendValue(result, thisItemDict);
+
+ AEDisposeDescQ(&thisItem);
+ if (thisItemURL)
+ CFRelease(thisItemURL);
+ if (thisItemDict)
+ CFRelease(thisItemDict);
+
+ if (err != noErr)
+ break;
+ }
+ }
+
+ // Clean up.
+
+ if (err != noErr && result) {
+ CFRelease(result);
+ result = NULL;
+ }
+ *itemsPtr = result;
+ assert((err == noErr) == (*itemsPtr != NULL));
+
+ return err;
+}
+
+static OSStatus SendEventToSystemEventsWithParameters(
+ AEEventClass theClass,
+ AEEventID theEvent,
+ AppleEvent * reply,
+ ...
+)
+// Creates an Apple event and sends it to the System Events
+// process. theClass and theEvent are the event class and ID,
+// respectively. If reply is not NULL, the caller gets a copy
+// of the reply. Following reply is a variable number of Apple event
+// parameters. Each AE parameter is made up of two C parameters,
+// the first being the AEKeyword, the second being a pointer to
+// the AEDesc for that parameter. This list is terminated by an
+// AEKeyword of value 0.
+//
+// You typically call this as:
+//
+// err = SendEventToSystemEventsWithParameters(
+// kClass,
+// kEvent,
+// NULL,
+// param1_keyword, param1_desc_ptr,
+// param2_keyword, param2_desc_ptr,
+// 0
+// );
+//
+// On entry, reply must be NULL or *reply must be the null AEDesc.
+// On success, if reply is not NULL, *reply will be the AE reply
+// (that is, not a null desc).
+// On error, if reply is not NULL, *reply will be the null AEDesc.
+{
+ OSStatus err;
+ ProcessSerialNumber psn;
+ AppleEvent target;
+ AppleEvent event;
+ AppleEvent localReply;
+ AEDescList results;
+
+ assert((reply == NULL) || (reply->descriptorType == typeNull));
+
+ target = kAENull;
+ event = kAENull;
+ localReply = kAENull;
+ results = kAENull;
+
+ // Create Apple event.
+
+ err = FindSystemEvents(&psn);
+ if (err == noErr)
+ err = AECreateDesc(typeProcessSerialNumber, &psn, sizeof(psn), &target);
+ if (err == noErr)
+ err = AECreateAppleEvent(
+ theClass,
+ theEvent,
+ &target,
+ kAutoGenerateReturnID,
+ kAnyTransactionID,
+ &event
+ );
+
+ // Handle varargs parameters.
+
+ if (err == noErr) {
+ va_list ap;
+ AEKeyword thisKeyword;
+ const AEDesc * thisDesc;
+
+ va_start(ap, reply);
+
+ do {
+ thisKeyword = va_arg(ap, AEKeyword);
+ if (thisKeyword != 0) {
+ thisDesc = va_arg(ap, const AEDesc *);
+ assert(thisDesc != NULL);
+
+ err = AEPutParamDesc(&event, thisKeyword, thisDesc);
+ }
+ } while ((err == noErr) && (thisKeyword != 0));
+
+ va_end(ap);
+ }
+
+ // Send event and get reply.
+
+ if (err == noErr)
+ err = SendAppleEvent(&event, &localReply);
+
+ // Clean up.
+
+ if (!reply || (err != noErr)) {
+ // *reply is already null because of our precondition
+ AEDisposeDescQ(&localReply);
+ } else {
+ *reply = localReply;
+ }
+ AEDisposeDescQ(&event);
+ AEDisposeDescQ(&target);
+ assert((reply == NULL) || ((err == noErr) == (reply->descriptorType != typeNull)));
+
+ return err;
+}
+
+extern OSStatus LIAECopyLoginItems(CFArrayRef *itemsPtr)
+// See comment in header.
+//
+// This routine creates an Apple event that corresponds to the
+// AppleScript:
+//
+// get properties of every login item
+//
+// and sends it to System Events. It then processes the reply
+// into a CFArray in the format that's documented in the header
+// comments.
+{
+ OSStatus err;
+ AppleEvent reply;
+ AEDescList results;
+ AEDesc propertiesOfEveryLoginItem;
+
+ assert( itemsPtr != NULL);
+ assert(*itemsPtr == NULL);
+
+ reply = kAENull;
+ results = kAENull;
+ propertiesOfEveryLoginItem = kAENull;
+
+ // Build object specifier for "properties of every login item".
+
+ {
+ static const DescType keyAEPropertiesLocal = pProperties;
+ static const DescType kAEAllLocal = kAEAll;
+ AEDesc every;
+ AEDesc everyLoginItem;
+ AEDesc properties;
+
+ every = kAENull;
+ everyLoginItem = kAENull;
+ properties = kAENull;
+
+ err = AECreateDesc(typeAbsoluteOrdinal, &kAEAllLocal, sizeof(kAEAllLocal), &every);
+ if (err == noErr)
+ err = CreateObjSpecifier(cLoginItem, (AEDesc *) &kAENull, formAbsolutePosition, &every, false, &everyLoginItem);
+ if (err == noErr)
+ err = AECreateDesc(typeType, &keyAEPropertiesLocal, sizeof(keyAEPropertiesLocal), &properties);
+ if (err == noErr)
+ err = CreateObjSpecifier(
+ typeProperty,
+ &everyLoginItem,
+ formPropertyID,
+ &properties,
+ false,
+ &propertiesOfEveryLoginItem);
+
+ AEDisposeDescQ(&every);
+ AEDisposeDescQ(&everyLoginItem);
+ AEDisposeDescQ(&properties);
+ }
+
+ // Send event and get reply.
+
+ if (err == noErr)
+ err = SendEventToSystemEventsWithParameters(
+ kAECoreSuite,
+ kAEGetData,
+ &reply,
+ keyDirectObject, &propertiesOfEveryLoginItem,
+ 0
+ );
+
+ // Process reply.
+
+ if (err == noErr)
+ err = AEGetParamDesc(&reply, keyDirectObject, typeAEList, &results);
+ if (err == noErr)
+ err = CreateCFArrayFromAEDescList(&results, itemsPtr);
+
+ // Clean up.
+
+ AEDisposeDescQ(&reply);
+ AEDisposeDescQ(&results);
+ AEDisposeDescQ(&propertiesOfEveryLoginItem);
+ assert((err == noErr) == (*itemsPtr != NULL));
+
+ return err;
+}
+
+extern OSStatus LIAEAddRefAtEnd(const FSRef *item, Boolean hideIt)
+// See comment in header.
+//
+// This routine creates an Apple event that corresponds to the
+// AppleScript:
+//
+// make new login item
+// with properties {
+// path:<path of item>,
+// hidden:hideIt
+// }
+// at end
+//
+// and sends it to System Events.
+{
+ OSStatus err;
+ AEDesc newLoginItem;
+ AERecord properties;
+ AERecord endLoc;
+ static const DescType cLoginItemLocal = cLoginItem;
+
+ assert(item != NULL);
+
+ newLoginItem = kAENull;
+ endLoc = kAENull;
+ properties = kAENull;
+
+ // Create "new login item" parameter.
+
+ err = AECreateDesc(typeType, &cLoginItemLocal, sizeof(cLoginItemLocal), &newLoginItem);
+
+ // Create "with properties" parameter.
+
+ if (err == noErr) {
+ char path[1024];
+ AEDesc pathDesc;
+
+ pathDesc = kAENull;
+
+ err = AECreateList(NULL, 0, true, &properties);
+ if (err == noErr)
+ err = FSRefMakePath(item, (UInt8 *) path, sizeof(path));
+
+ // System Events complains if you pass it typeUTF8Text directly, so
+ // we do the conversion from typeUTF8Text to typeUnicodeText on our
+ // side of the world.
+
+ if (err == noErr)
+ err = AECoercePtr(typeUTF8Text, path, (Size) strlen(path), typeUnicodeText, &pathDesc);
+ if (err == noErr)
+ err = AEPutKeyDesc(&properties, propPath, &pathDesc);
+ if (err == noErr)
+ err = AEPutKeyPtr(&properties, propHidden, typeBoolean, &hideIt, sizeof(hideIt));
+
+ AEDisposeDescQ(&pathDesc);
+ }
+
+ // Create "at end" parameter.
+
+ if (err == noErr) {
+ AERecord end;
+ static const DescType kAEEndLocal = kAEEnd;
+
+ end = kAENull;
+
+ err = AECreateList(NULL, 0, true, &end);
+ if (err == noErr)
+ err = AEPutKeyPtr(&end, keyAEObject, typeNull, NULL, 0);
+ if (err == noErr)
+ err = AEPutKeyPtr(&end, keyAEPosition, typeEnumerated, &kAEEndLocal, (Size) sizeof(kAEEndLocal));
+ if (err == noErr)
+ err = AECoerceDesc(&end, cInsertionLoc, &endLoc);
+
+ AEDisposeDescQ(&end);
+ }
+
+ // Send the event.
+
+ if (err == noErr)
+ err = SendEventToSystemEventsWithParameters(
+ kAECoreSuite,
+ kAECreateElement,
+ NULL,
+ keyAEObjectClass, &newLoginItem,
+ keyAEPropData, &properties,
+ keyAEInsertHere, &endLoc,
+ 0
+ );
+
+ // Clean up.
+
+ AEDisposeDescQ(&newLoginItem);
+ AEDisposeDescQ(&endLoc);
+ AEDisposeDescQ(&properties);
+
+ return err;
+}
+
+extern OSStatus LIAEAddURLAtEnd(CFURLRef item, Boolean hideIt)
+// See comment in header.
+//
+// This is implemented as a wrapper around LIAEAddRef.
+// I chose to do it this way because an URL can reference a
+// file that doesn't except, whereas an FSRef can't, so by
+// having the URL routine call the FSRef routine, I naturally
+// ensure that the item exists on disk.
+{
+ OSStatus err;
+ Boolean success;
+ FSRef ref;
+
+ assert(item != NULL);
+
+ success = CFURLGetFSRef(item, &ref);
+ if (success)
+ err = LIAEAddRefAtEnd(&ref, hideIt);
+ else
+ // I have no idea what went wrong (thanks CF!). Normally I'd
+ // return coreFoundationUnknownErr here, but in this case I'm
+ // going to go out on a limb and say that we have a file not found.
+ err = fnfErr;
+
+ return err;
+}
+
+extern OSStatus LIAERemove(CFIndex itemIndex)
+// See comment in header.
+//
+// This routine creates an Apple event that corresponds to the
+// AppleScript:
+//
+// delete login item itemIndex
+//
+// and sends it to System Events.
+{
+ OSStatus err;
+ long itemIndexPlusOne;
+ AEDesc indexDesc;
+ AEDesc loginItemAtIndex;
+
+ assert(itemIndex >= 0);
+
+ indexDesc = kAENull;
+ loginItemAtIndex = kAENull;
+
+ // Build object specifier for "login item X".
+
+ itemIndexPlusOne = itemIndex + 1; // AppleScript is one-based, CF is zero-based
+ err = AECreateDesc(typeLongInteger, &itemIndexPlusOne, sizeof(itemIndexPlusOne), &indexDesc);
+ if (err == noErr)
+ err = CreateObjSpecifier(cLoginItem, (AEDesc *) &kAENull, formAbsolutePosition, &indexDesc, false, &loginItemAtIndex);
+
+ // Send the event.
+
+ if (err == noErr)
+ err = SendEventToSystemEventsWithParameters(
+ kAECoreSuite,
+ kAEDelete,
+ NULL,
+ keyDirectObject, &loginItemAtIndex,
+ 0
+ );
+
+ // Clean up.
+
+ AEDisposeDescQ(&indexDesc);
+ AEDisposeDescQ(&loginItemAtIndex);
+
+ return err;
+}
View
88 LoginItemsAE.h
@@ -0,0 +1,88 @@
+/*
+ File: LoginItemsAE.h
+
+ Contains: Login items manipulation via Apple events.
+
+ Copyright: Copyright (c) 2005 by Apple Computer, Inc., All Rights Reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple’s
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Change History (most recent first):
+
+ $Log: LoginItemsAE.h,v $
+ Revision 1.1 2005/09/27 12:29:29
+ First checked in.
+
+
+ */
+
+#ifndef _LOGINITEMSAE_H
+#define _LOGINITEMSAE_H
+
+// http://developer.apple.com/documentation/UserExperience/Conceptual/PreferencePanes/Tasks/Conflicts.html
+//TODO would be better just to prevent these symbols getting exported
+#define LIAECopyLoginItems OrgPlaydarLIAECopyLoginItems
+#define LIAEAddRefAtEnd OrgPlaydarLIAEAddRefAtEnd
+#define LIAEAddURLAtEnd OrgPlaydarLIAEAddURLAtEnd
+#define LIAERemove OrgPlaydarLIAERemove
+
+#include <ApplicationServices/ApplicationServices.h>
+
+#define kLIAEURL CFSTR("URL") // CFURL
+#define kLIAEHidden CFSTR("Hidden") // CFBoolean
+
+ extern OSStatus LIAECopyLoginItems(CFArrayRef *itemsPtr);
+ // Returns an array of CFDictionaries, each one describing a
+ // login item. Each dictionary has two elements,
+ // kLIAEURL and kLIAEHidden, which are
+ // documented above.
+ //
+ // On input, itemsPtr must not be NULL.
+ // On input, *itemsPtr must be NULL.
+ // On success, *itemsPtr will be a pointer to a CFArray.
+ // Or error, *itemsPtr will be NULL.
+
+ extern OSStatus LIAEAddRefAtEnd(const FSRef *item, Boolean hideIt);
+ extern OSStatus LIAEAddURLAtEnd(CFURLRef item, Boolean hideIt);
+ // Add a new login item at the end of the list, using either
+ // an FSRef or a CFURL. The hideIt parameter controls whether
+ // the item is hidden when it's launched.
+
+ extern OSStatus LIAERemove(CFIndex itemIndex);
+ // Remove a login item. itemIndex is an index into the array
+ // of login items as returned by LIAECopyLoginItems.
+
+#endif
View
6 main.h
@@ -20,12 +20,13 @@
// long class name is because we get loaded into System Preferences process, so
// we are required to be ultra verbose
-// http://developer.apple.com/documentation/UserExperience/Conceptual/PreferencePanes/Tasks/Conflicts.html#//apple_ref/doc/uid/20000706
+// http://developer.apple.com/documentation/UserExperience/Conceptual/PreferencePanes/Tasks/Conflicts.html
@interface OrgPlaydarPreferencePane : NSPreferencePane
{
IBOutlet NSPopUpButton* popup;
IBOutlet NSButton* scan;
IBOutlet NSButton* start;
+ IBOutlet NSButton* check;
pid_t pid;
}
@@ -37,8 +38,11 @@
-(int)exec:(NSString*)command withArgs:(NSArray*)args;
+-(bool)isLoginItem;
+
-(IBAction)select:(id)sender; //TODO doesn't need to be IBAction
-(IBAction)onScan:(id)sender;
-(IBAction)onStart:(id)sender;
+-(IBAction)onStartAtLogin:(id)sender;
@end
View
90 main.m
@@ -16,6 +16,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+//TODO the daemon needs be named the same as cmake builds it, or conflicts with
+// source users occur, xcode hates you for this though
//TODO watch exit code of playdard (if early exits), and watch process while pref pane is open
// ^^ important in case playdard exits immediately due to crash or somesuch
@@ -31,6 +33,7 @@
#import "main.h"
#include <sys/sysctl.h>
#include <Sparkle/SUUpdater.h>
+#include "LoginItemsAE.h"
/** returns the pid of the running playdard instance, or 0 if not found */
@@ -50,19 +53,19 @@ static pid_t playdard_pid()
N = N / sizeof(struct kinfo_proc);
for(size_t i = 0; i < N; i++)
- if(strcmp(info[i].kp_proc.p_comm, "playdard") == 0)
+ if(strcmp(info[i].kp_proc.p_comm, "playdar") == 0)
{ pid = info[i].kp_proc.p_pid; break; }
end:
NSZoneFree(NULL, info);
return pid;
}
-static inline NSString* iniPath()
+static inline NSString* ini_path()
{
return [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Preferences/org.playdar.ini"];
}
-static inline NSString* collectionDbPath()
+static inline NSString* db_path()
{
return [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Playdar/collection.db"];
}
@@ -74,17 +77,19 @@ static pid_t playdard_pid()
return (fullname && [fullname length] > 0) ? fullname : NSUserName();
}
+#define PLAYDAR_BIN_PATH [[[self bundle] bundlePath] stringByAppendingPathComponent:@"Contents/MacOS/playdar"]
+
@implementation OrgPlaydarPreferencePane
-(void)mainViewDidLoad
{
[[SUUpdater updaterForBundle:[self bundle]] resetUpdateCycle];
- NSString* ini = iniPath();
- if ([[NSFileManager defaultManager] fileExistsAtPath:ini] == false)
+ NSString* ini = ini_path();
+ if([[NSFileManager defaultManager] fileExistsAtPath:ini] == false)
{
- NSArray* args = [NSArray arrayWithObjects: fullname(), collectionDbPath(), ini, nil];
+ NSArray* args = [NSArray arrayWithObjects: fullname(), db_path(), ini, nil];
[self exec:@"playdar.ini.rb" withArgs:args];
}
@@ -94,28 +99,85 @@ -(void)mainViewDidLoad
[[popup menu] addItem:[NSMenuItem separatorItem]];
[[[popup menu] addItemWithTitle:@"Select..." action:@selector(select:) keyEquivalent:@""] setTarget:self];
- if (pid = playdard_pid()) [start setTitle:@"Stop Playdar"];
+ if(pid = playdard_pid()) [start setTitle:@"Stop Playdar"];
+ if(![self isLoginItem]) [check setState:NSOffState];
}
-(void)onScan:(id)sender
{
- NSArray* args = [NSArray arrayWithObjects:[popup titleOfSelectedItem], collectionDbPath(), nil];
+ NSArray* args = [NSArray arrayWithObjects:[popup titleOfSelectedItem], db_path(), nil];
[self exec:@"scan.sh" withArgs:args];
}
-(void)onStart:(id)sender
{
if(pid) {
- if(kill( pid, SIGKILL ) != 0) return;
- [start setTitle:@"Start Playdar"];
- pid = 0;
+ if([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)
+ {
+ } else {
+ if(kill( pid, SIGKILL ) != 0) return;
+ [start setTitle:@"Start Playdar"];
+ pid = 0;
+ }
} else {
- NSArray* args = [NSArray arrayWithObjects:@"-c", iniPath(), nil];
- pid = [self exec:@"../MacOS/playdard" withArgs:args];
+ NSArray* args = [NSArray arrayWithObjects:@"-c", ini_path(), nil];
+ pid = [self exec:@"../MacOS/playdar" withArgs:args];
if(pid) [start setTitle:@"Stop Playdar"];
}
}
+-(void)onStartAtLogin:(id)sender
+{
+ bool const enabled = [check state] == NSOnState;
+
+ CFArrayRef loginItems = NULL;
+ NSURL *url = [NSURL fileURLWithPath:PLAYDAR_BIN_PATH];
+ int existingLoginItemIndex = -1;
+
+ NSLog( @"%@", url );
+
+ OSStatus status = LIAECopyLoginItems(&loginItems);
+
+ if(status == noErr) {
+ NSEnumerator *enumerator = [(NSArray *)loginItems objectEnumerator];
+ NSDictionary *loginItemDict;
+
+ while((loginItemDict = [enumerator nextObject])) {
+ if([[loginItemDict objectForKey:(NSString *)kLIAEURL] isEqual:url]) {
+ existingLoginItemIndex = [(NSArray *)loginItems indexOfObjectIdenticalTo:loginItemDict];
+ break;
+ }
+ }
+ }
+
+ if(enabled && (existingLoginItemIndex == -1))
+ LIAEAddURLAtEnd((CFURLRef)url, false);
+ else if(!enabled && (existingLoginItemIndex != -1))
+ LIAERemove(existingLoginItemIndex);
+
+ if(loginItems)
+ CFRelease(loginItems);
+}
+
+-(bool)isLoginItem
+{
+ Boolean foundIt = false;
+ CFArrayRef loginItems = NULL;
+ CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)PLAYDAR_BIN_PATH, kCFURLPOSIXPathStyle, false);
+ NSLog( @"%@", url );
+ OSStatus status = LIAECopyLoginItems(&loginItems);
+ if(status == noErr) {
+ for(CFIndex i=0, N=CFArrayGetCount(loginItems); i<N; ++i) {
+ CFDictionaryRef loginItem = CFArrayGetValueAtIndex(loginItems, i);
+ foundIt = CFEqual(CFDictionaryGetValue(loginItem, kLIAEURL), url);
+ if(foundIt) break;
+ }
+ CFRelease(loginItems);
+ }
+ CFRelease(url);
+ return foundIt;
+}
+
////// Directory selector
-(void)select:(id)sender
{
@@ -161,8 +223,8 @@ -(int)exec:(NSString*)command withArgs:(NSArray*)args
@catch (NSException* e)
{
//TODO log - couldn't figure out easy way to do this
- return 0;
}
+ return 0;
}
@end
View
37 playdar.prefPane.xcodeproj/project.pbxproj
@@ -22,9 +22,13 @@
638388320F5B6FBF000C8EAF /* libboost_filesystem-mt.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 6383882A0F5B6FA3000C8EAF /* libboost_filesystem-mt.dylib */; };
6383883C0F5B7065000C8EAF /* libtag.1.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 638388340F5B6FEF000C8EAF /* libtag.1.dylib */; };
6383883D0F5B7065000C8EAF /* libz.1.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 6383883A0F5B704D000C8EAF /* libz.1.dylib */; };
- 63BE46E60F5B6C0C00BFA9E0 /* playdard in CopyFiles */ = {isa = PBXBuildFile; fileRef = 63BE46E40F5B6C0600BFA9E0 /* playdard */; };
+ 63BE46E60F5B6C0C00BFA9E0 /* playdar in CopyFiles */ = {isa = PBXBuildFile; fileRef = 63BE46E40F5B6C0600BFA9E0 /* playdar */; };
63DFABE70F5CAAA1001855D4 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63DFABE60F5CAAA1001855D4 /* Sparkle.framework */; };
63DFABEE0F5CAAFA001855D4 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 63DFABE60F5CAAA1001855D4 /* Sparkle.framework */; };
+ 63E2F3800F609BFE00738CA2 /* terminal.sh in Resources */ = {isa = PBXBuildFile; fileRef = 63E2F37F0F609BFE00738CA2 /* terminal.sh */; };
+ 63E2F3BD0F60A11B00738CA2 /* pc.h in Headers */ = {isa = PBXBuildFile; fileRef = 32DBCFA20370C41700C91783 /* pc.h */; };
+ 63E2F3BE0F60A11B00738CA2 /* LoginItemsAE.h in Headers */ = {isa = PBXBuildFile; fileRef = 635AD4D00F5E152D003C0805 /* LoginItemsAE.h */; };
+ 63E2F3BF0F60A11B00738CA2 /* LoginItemsAE.c in Sources */ = {isa = PBXBuildFile; fileRef = 635AD4D20F5E1552003C0805 /* LoginItemsAE.c */; };
8D202CEB0486D31800D8A456 /* main.h in Headers */ = {isa = PBXBuildFile; fileRef = F506C03C013D9D7901CA16C8 /* main.h */; };
8D202CED0486D31800D8A456 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; };
8D202CEF0486D31800D8A456 /* main.xib in Resources */ = {isa = PBXBuildFile; fileRef = F506C042013D9D8C01CA16C8 /* main.xib */; };
@@ -60,7 +64,7 @@
632DF4C20F5B70C00078F66A /* liburiparser.1.dylib in CopyFiles */,
632DF4C30F5B70C00078F66A /* libuuid.16.dylib in CopyFiles */,
6383883D0F5B7065000C8EAF /* libz.1.dylib in CopyFiles */,
- 63BE46E60F5B6C0C00BFA9E0 /* playdard in CopyFiles */,
+ 63BE46E60F5B6C0C00BFA9E0 /* playdar in CopyFiles */,
6381AABA0F5AC655003D1B3F /* scanner in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -84,6 +88,8 @@
1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
32DBCFA20370C41700C91783 /* pc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pc.h; sourceTree = "<group>"; };
632DF4DC0F5B79B90078F66A /* libboost_program_options-mt.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libboost_program_options-mt.dylib"; path = "/opt/local/lib/libboost_program_options-mt.dylib"; sourceTree = "<absolute>"; };
+ 635AD4D00F5E152D003C0805 /* LoginItemsAE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginItemsAE.h; sourceTree = "<group>"; };
+ 635AD4D20F5E1552003C0805 /* LoginItemsAE.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = LoginItemsAE.c; sourceTree = "<group>"; };
63773AB60F59674B002D0DE9 /* playdar.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = playdar.icns; sourceTree = "<group>"; };
63773ABC0F596C6B002D0DE9 /* scan.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = scan.sh; sourceTree = "<group>"; };
6381AA7F0F5AC101003D1B3F /* playdar.ini.rb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.ruby; path = playdar.ini.rb; sourceTree = "<group>"; };
@@ -98,8 +104,9 @@
6383883A0F5B704D000C8EAF /* libz.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.1.dylib; path = /opt/local/lib/libz.1.dylib; sourceTree = "<absolute>"; };
638388400F5B708F000C8EAF /* liburiparser.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = liburiparser.1.dylib; path = /opt/local/lib/liburiparser.1.dylib; sourceTree = "<absolute>"; };
638388410F5B708F000C8EAF /* libuuid.16.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libuuid.16.dylib; path = /opt/local/lib/libuuid.16.dylib; sourceTree = "<absolute>"; };
- 63BE46E40F5B6C0600BFA9E0 /* playdard */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = playdard; path = build/playdard; sourceTree = "<group>"; };
+ 63BE46E40F5B6C0600BFA9E0 /* playdar */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = playdar; path = "../playdar-daemon/bin/playdar"; sourceTree = "<group>"; };
63DFABE60F5CAAA1001855D4 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Sparkle.framework; sourceTree = "<group>"; };
+ 63E2F37F0F609BFE00738CA2 /* terminal.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = terminal.sh; sourceTree = "<group>"; };
8D202CF70486D31800D8A456 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
8D202CF80486D31800D8A456 /* playdar.prefPane */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = playdar.prefPane; sourceTree = BUILT_PRODUCTS_DIR; };
F506C035013D953901CA16C8 /* PreferencePanes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PreferencePanes.framework; path = /System/Library/Frameworks/PreferencePanes.framework; sourceTree = "<absolute>"; };
@@ -153,6 +160,7 @@
F506C042013D9D8C01CA16C8 /* main.xib */,
63773ABC0F596C6B002D0DE9 /* scan.sh */,
6381AA7F0F5AC101003D1B3F /* playdar.ini.rb */,
+ 63E2F37F0F609BFE00738CA2 /* terminal.sh */,
);
name = Resources;
sourceTree = "<group>";
@@ -197,6 +205,8 @@
isa = PBXGroup;
children = (
32DBCFA20370C41700C91783 /* pc.h */,
+ 635AD4D00F5E152D003C0805 /* LoginItemsAE.h */,
+ 635AD4D20F5E1552003C0805 /* LoginItemsAE.c */,
);
name = "Other Sources";
sourceTree = "<group>";
@@ -213,7 +223,7 @@
638388400F5B708F000C8EAF /* liburiparser.1.dylib */,
638388410F5B708F000C8EAF /* libuuid.16.dylib */,
6383883A0F5B704D000C8EAF /* libz.1.dylib */,
- 63BE46E40F5B6C0600BFA9E0 /* playdard */,
+ 63BE46E40F5B6C0600BFA9E0 /* playdar */,
6381AAB80F5AC655003D1B3F /* scanner */,
6381AAB30F5AC5E0003D1B3F /* playdar.ini */,
6381AAA80F5AC541003D1B3F /* schema.sql */,
@@ -229,6 +239,8 @@
buildActionMask = 2147483647;
files = (
8D202CEB0486D31800D8A456 /* main.h in Headers */,
+ 63E2F3BD0F60A11B00738CA2 /* pc.h in Headers */,
+ 63E2F3BE0F60A11B00738CA2 /* LoginItemsAE.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -239,12 +251,11 @@
isa = PBXNativeTarget;
buildConfigurationList = 1DBD214808BA80EA00186707 /* Build configuration list for PBXNativeTarget "main" */;
buildPhases = (
- 631F5A880F5B6A0A00332254 /* ShellScript */,
8D202CE90486D31800D8A456 /* Headers */,
8D202CEC0486D31800D8A456 /* Resources */,
8D202CF00486D31800D8A456 /* Sources */,
8D202CF20486D31800D8A456 /* Frameworks */,
- 8D202CF50486D31800D8A456 /* Rez */,
+ 631F5A880F5B6A0A00332254 /* ShellScript */,
63DFABED0F5CAAF6001855D4 /* CopyFiles */,
6381AA960F5AC1D8003D1B3F /* CopyFiles */,
6381AB6A0F5B5CA1003D1B3F /* CopyFiles */,
@@ -287,21 +298,12 @@
63773AB70F59674B002D0DE9 /* playdar.icns in Resources */,
63773ABD0F596C6B002D0DE9 /* scan.sh in Resources */,
6381AA800F5AC101003D1B3F /* playdar.ini.rb in Resources */,
+ 63E2F3800F609BFE00738CA2 /* terminal.sh in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
-/* Begin PBXRezBuildPhase section */
- 8D202CF50486D31800D8A456 /* Rez */ = {
- isa = PBXRezBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXRezBuildPhase section */
-
/* Begin PBXShellScriptBuildPhase section */
631F5A880F5B6A0A00332254 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
@@ -315,7 +317,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "cp ../playdar-daemon/bin/playdar build/playdard";
+ shellScript = "cd $BUILT_PRODUCTS_DIR/$EXECUTABLE_FOLDER_PATH\nmv playdar playdar.prefPane";
};
632DF4CE0F5B76940078F66A /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
@@ -338,6 +340,7 @@
buildActionMask = 2147483647;
files = (
8D202CF10486D31800D8A456 /* main.m in Sources */,
+ 63E2F3BF0F60A11B00738CA2 /* LoginItemsAE.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

0 comments on commit 4040344

Please sign in to comment.