#include #include #include #include #include #include #include #include #include #include #include #include "IOPMPrivate.h" #include #include static aslclient gASLClient; static aslmsg gASLMessage; static void WaitForWindowServerSession(void) { CFDictionaryRef dict; (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "WaitForWindowServerSession begin"); while (dict == NULL) { (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "Checking CGSessionCopyCurrentDictionary"); dict = CGSessionCopyCurrentDictionary(); if (dict == NULL) { (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "No session, sleeping"); usleep(1000000); } } // if (dict != NULL) { CFRelease(dict); // } (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "WaitForWindowServerSession end"); } static void HandleSIGTERMFromRunLoop(CFFileDescriptorRef f, CFOptionFlags callBackTypes, void *info); //forward declaration static void InstallHandleSIGTERMFromRunLoop(void) //installs HandleSIGTERMFromRunLoop as a SIGTERM handler. { static const CFFileDescriptorContext kContext = { 0, NULL, NULL, NULL, NULL }; sig_t sigErr; int kq; CFFileDescriptorRef kqRef; CFRunLoopSourceRef kqSource; struct kevent changes; int changeCount; //Ignore SIGTERM sigErr = signal(SIGTERM, SIG_IGN); assert(sigErr != SIG_ERR); // Create a kqueue and configure it to listen for the SIGTERM signal. kq = kqueue(); assert(kq >= 0); EV_SET(&changes, SIGTERM, EVFILT_SIGNAL, EV_ADD | EV_RECEIPT, 0, 0, NULL); changeCount = kevent(kq, &changes, 1, &changes, 1, NULL); assert(changeCount == 1); //can we get event back? assert(changes.flags & EV_ERROR); //has error assert(changes.data == 0); //with no error //Wrap the kqueue in a CFFileDescriptor kqRef = CFFileDescriptorCreate(NULL, kq, true, HandleSIGTERMFromRunLoop, &kContext); assert(kqRef != NULL); kqSource = CFFileDescriptorCreateRunLoopSource(NULL, kqRef, 0); assert(kqSource != NULL); CFRunLoopAddSource(CFRunLoopGetCurrent(), kqSource, kCFRunLoopDefaultMode); CFFileDescriptorEnableCallBacks(kqRef, kCFFileDescriptorReadCallBack); //Clean up. Release kqSource and kqRef CFRelease(kqSource); CFRelease(kqRef); } static void HandleSIGTERMFromRunLoop(CFFileDescriptorRef f, CFOptionFlags callBackTypes, void *info) { #pragma unused(f) #pragma unused(callBackTypes) #pragma unused(info) (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "Got SIGTERM"); QuitApplicationEventLoop(); } int main(int argc, char *argv[]) { OSStatus err; int argIndex; Boolean delay; Boolean waitForWindowServerSession; Boolean forceShow; Boolean cleanExit; IBNibRef nibRef; WindowRef window; //Initialize ASL gASLClient = asl_open(NULL, "PreLoginAgents", 0); assert(gASLClient != NULL); (void) asl_set_filter(gASLClient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_INFO)); gASLMessage = asl_new(ASL_TYPE_MSG); assert(gASLMessage != NULL); (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "Start"); //Parse our arguments. delay = false; waitForWindowServerSession = false; forceShow = true; cleanExit = true; for (argIndex = 1; argIndex < argc; argIndex++) { if ( strcasecmp(argv[argIndex], "--nodelay") == 0 ) { delay = false; } else if ( strcasecmp(argv[argIndex], "--delay") == 0 ) { delay = true; } else if ( strcasecmp(argv[argIndex], "--nowait") == 0 ) { waitForWindowServerSession = false; } else if ( strcasecmp(argv[argIndex], "--wait") == 0 ) { waitForWindowServerSession = true; } else if ( strcasecmp(argv[argIndex], "--noforce") == 0 ) { forceShow = false; } else if ( strcasecmp(argv[argIndex], "--force") == 0 ) { forceShow = true; } else if ( strcasecmp(argv[argIndex], "--nocleanexit") == 0 ) { cleanExit = false; } else if ( strcasecmp(argv[argIndex], "--cleanexit") == 0 ) { cleanExit = true; } else { (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "Unrecognised argument '%s'", argv[argIndex]); } } //Handle various options. (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "Not waiting for CGSessionCopyCurrentDictionary"); (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "Not delaying"); //Set up UI. err = CreateNibReference(CFSTR("main"), &nibRef); assert(err == noErr); err = CreateWindowFromNib(nibRef, CFSTR("MainWindow"), &window); assert(err == noErr); DisposeNibReference(nibRef); //set kHIWindowBitCanBeVisibleWithoutLogin to let the //system know that we're not accidentally trying to display //a window pre-login. // //Also, window is a utility window and, by default, these have the //kWindowHideOnSuspendAttribute attribute set. As our application is a static const int kAttributesToSet[] = { kHIWindowBitCanBeVisibleWithoutLogin, 0 }; static const int kAttributesToClear[] = { kHIWindowBitHideOnSuspend, 1 }; ShowWindow(window); if (forceShow) { (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "Showing window with extreme prejudice"); BringToFront(window); } else { (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "Showing window normally"); } //Set up our SIGTERM if (cleanExit) { (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "Installing SIGTERM handler"); //InstallHandleSIGTERMFromRunLoop(); } else { (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "Not installing SIGTERM handler"); } //Execute SleepWake kern_return_t kr; CFTypeRef obj; io_registry_entry_t regEntry; regEntry = IORegistryEntryFromPath(kIOMasterPortDefault, kIOServicePlane ":/IOResources/IODisplayWrangler"); obj = CFRetain(kCFBooleanTrue); // if (value >= 0) // { SInt32 num = 1000 * strtol("1", 0, 0); obj = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &num); // } kr = IORegistryEntrySetCFProperty(regEntry, CFSTR("IORequestIdle"), obj); CFRelease(obj); IOObjectRelease(regEntry); //Emulate keypress (option key) to wake up usleep(1000000); CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)55, true); CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)55, false); //Launch Final Biznitch (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "RunApplicationEventLoop"); RunApplicationEventLoop(); //Kill (void) asl_log(gASLClient, gASLMessage, ASL_LEVEL_INFO, "Stop"); return EXIT_SUCCESS; }