Spaces:
No application file
No application file
| #----------------------------------------------------------------------------- | |
| # Copyright (C) 2013 Min RK | |
| # | |
| # Distributed under the terms of the 2-clause BSD License. | |
| #----------------------------------------------------------------------------- | |
| from contextlib import contextmanager | |
| import ctypes | |
| import ctypes.util | |
| objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc')) | |
| _ = ctypes.cdll.LoadLibrary(ctypes.util.find_library('Foundation')) | |
| void_p = ctypes.c_void_p | |
| ull = ctypes.c_uint64 | |
| objc.objc_getClass.restype = void_p | |
| objc.sel_registerName.restype = void_p | |
| objc.objc_msgSend.restype = void_p | |
| objc.objc_msgSend.argtypes = [void_p, void_p] | |
| msg = objc.objc_msgSend | |
| def _utf8(s): | |
| """ensure utf8 bytes""" | |
| if not isinstance(s, bytes): | |
| s = s.encode('utf8') | |
| return s | |
| def n(name): | |
| """create a selector name (for methods)""" | |
| return objc.sel_registerName(_utf8(name)) | |
| def C(classname): | |
| """get an ObjC Class by name""" | |
| ret = objc.objc_getClass(_utf8(classname)) | |
| assert ret is not None, "Couldn't find Class %s" % classname | |
| return ret | |
| # constants from Foundation | |
| NSActivityIdleDisplaySleepDisabled = (1 << 40) | |
| NSActivityIdleSystemSleepDisabled = (1 << 20) | |
| NSActivitySuddenTerminationDisabled = (1 << 14) | |
| NSActivityAutomaticTerminationDisabled = (1 << 15) | |
| NSActivityUserInitiated = (0x00FFFFFF | NSActivityIdleSystemSleepDisabled) | |
| NSActivityUserInitiatedAllowingIdleSystemSleep = (NSActivityUserInitiated & ~NSActivityIdleSystemSleepDisabled) | |
| NSActivityBackground = 0x000000FF | |
| NSActivityLatencyCritical = 0xFF00000000 | |
| def beginActivityWithOptions(options, reason=""): | |
| """Wrapper for: | |
| [ [ NSProcessInfo processInfo] | |
| beginActivityWithOptions: (uint64)options | |
| reason: (str)reason | |
| ] | |
| """ | |
| NSProcessInfo = C('NSProcessInfo') | |
| NSString = C('NSString') | |
| objc.objc_msgSend.argtypes = [void_p, void_p, void_p] | |
| reason = msg(NSString, n("stringWithUTF8String:"), _utf8(reason)) | |
| objc.objc_msgSend.argtypes = [void_p, void_p] | |
| info = msg(NSProcessInfo, n('processInfo')) | |
| objc.objc_msgSend.argtypes = [void_p, void_p, ull, void_p] | |
| activity = msg(info, | |
| n('beginActivityWithOptions:reason:'), | |
| ull(options), | |
| void_p(reason) | |
| ) | |
| return activity | |
| def endActivity(activity): | |
| """end a process activity assertion""" | |
| NSProcessInfo = C('NSProcessInfo') | |
| objc.objc_msgSend.argtypes = [void_p, void_p] | |
| info = msg(NSProcessInfo, n('processInfo')) | |
| objc.objc_msgSend.argtypes = [void_p, void_p, void_p] | |
| msg(info, n("endActivity:"), void_p(activity)) | |
| _theactivity = None | |
| def nope(): | |
| """disable App Nap by setting NSActivityUserInitiatedAllowingIdleSystemSleep""" | |
| global _theactivity | |
| _theactivity = beginActivityWithOptions( | |
| NSActivityUserInitiatedAllowingIdleSystemSleep, | |
| "Because Reasons" | |
| ) | |
| def nap(): | |
| """end the caffeinated state started by `nope`""" | |
| global _theactivity | |
| if _theactivity is not None: | |
| endActivity(_theactivity) | |
| _theactivity = None | |
| def napping_allowed(): | |
| """is napping allowed?""" | |
| return _theactivity is None | |
| def nope_scope( | |
| options=NSActivityUserInitiatedAllowingIdleSystemSleep, | |
| reason="Because Reasons" | |
| ): | |
| """context manager for beginActivityWithOptions. | |
| Within this context, App Nap will be disabled. | |
| """ | |
| activity = beginActivityWithOptions(options, reason) | |
| try: | |
| yield | |
| finally: | |
| endActivity(activity) | |
| __all__ = [ | |
| "NSActivityIdleDisplaySleepDisabled", | |
| "NSActivityIdleSystemSleepDisabled", | |
| "NSActivitySuddenTerminationDisabled", | |
| "NSActivityAutomaticTerminationDisabled", | |
| "NSActivityUserInitiated", | |
| "NSActivityUserInitiatedAllowingIdleSystemSleep", | |
| "NSActivityBackground", | |
| "NSActivityLatencyCritical", | |
| "beginActivityWithOptions", | |
| "endActivity", | |
| "nope", | |
| "nap", | |
| "napping_allowed", | |
| "nope_scope", | |
| ] | |