Created
April 7, 2016 08:15
-
-
Save pudquick/9683c333e73a82379b8e377eb2e6fc41 to your computer and use it in GitHub Desktop.
Send polite Logout / "really" Logout / Restart / Shutdown Apple Events to loginwindow via python and pyObjC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import struct, objc | |
from Foundation import NSBundle | |
from Cocoa import NSAppleEventDescriptor | |
def OSType(s): | |
# Convert 4 character code into 4 byte integer | |
return struct.unpack('>I', s)[0] | |
# Create an opaque pointer type to mask the raw AEDesc pointers we'll throw around | |
AEDescRef = objc.createOpaquePointerType('AEDescRef', '^{AEDesc=I^^{OpaqueAEDataStorageType}}') | |
# Load AESendMessage from AE.framework for sending the AppleEvent | |
AE_bundle = NSBundle.bundleWithIdentifier_('com.apple.AE') | |
functions = [("AESendMessage", b"i^{AEDesc=I^^{OpaqueAEDataStorageType}}^{AEDesc=I^^{OpaqueAEDataStorageType}}iq"),] | |
objc.loadBundleFunctions(AE_bundle, globals(), functions) | |
# defined in AEDataModel.h | |
kAENoReply = 1 | |
kAENeverInteract = 16 | |
kAEDefaultTimeout = -1 | |
kAnyTransactionID = 0 | |
kAutoGenerateReturnID = -1 | |
# defined in AEDataModel.h | |
typeAppleEvent = OSType('aevt') | |
typeApplicationBundleID = OSType('bund') | |
# defined in AERegistry.h | |
kAELogOut = OSType('logo') | |
kAEReallyLogOut = OSType('rlgo') | |
kAEShowRestartDialog = OSType('rrst') | |
kAEShowShutdownDialog = OSType('rsdn') | |
# Build a standalone application descriptor by bundle id | |
loginwindowDesc = NSAppleEventDescriptor.alloc().initWithDescriptorType_data_(typeApplicationBundleID, buffer('com.apple.loginwindow')) | |
# build an event descriptor with our app descriptor as the target and the kAELogOut eventID | |
event = NSAppleEventDescriptor.appleEventWithEventClass_eventID_targetDescriptor_returnID_transactionID_( | |
typeAppleEvent, kAELogOut, loginwindowDesc, kAutoGenerateReturnID, kAnyTransactionID) | |
eventDesc = event.aeDesc() | |
# Send a polite logout (returns immediately) | |
err = AESendMessage(eventDesc, None, kAENoReply|kAENeverInteract, kAEDefaultTimeout) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Round 3, via NSAppleScript:
Same issues as the SBApplication method, in terms of effectiveness/usability. Had to use the "asian encoding compatible" chevrons listed here: https://developer.apple.com/library/mac/documentation/AppleScript/Conceptual/AppleScriptLangGuide/conceptual/ASLR_lexical_conventions.html#//apple_ref/doc/uid/TP40000983-CH214-SW5
Likely because the original left/right chevrons were part of MacRoman encoding and NSString <-> NSAppleScript communication trips all over itself about how to interpret. Even if you build the NSString from data with the right encoding specified, NSAppleScript keeps receiving the UTF-8 encoded form. By moving to the alternate encoding, we're forcing pure Unicode.