|
#!/usr/bin/python |
|
|
|
from collections import defaultdict |
|
from AppKit import NSWorkspace |
|
from time import sleep |
|
import os |
|
|
|
import logging |
|
|
|
logger = logging.getLogger() |
|
handler = logging.StreamHandler() |
|
formatter = logging.Formatter( |
|
'%(asctime)s %(name)-8s %(levelname)-8s %(message)s') |
|
handler.setFormatter(formatter) |
|
logger.addHandler(handler) |
|
logger.setLevel(logging.INFO) |
|
|
|
state = defaultdict() |
|
|
|
|
|
def get_active_app_name(): |
|
# https://stackoverflow.com/a/25214024 |
|
# return NSWorkspace.sharedWorkspace().frontmostApplication().localizedName() |
|
return NSWorkspace.sharedWorkspace().activeApplication()['NSApplicationName'] |
|
|
|
|
|
def suspend(app, app_bin): |
|
logger.info('SUSPEND: {}'.format(app)) |
|
if isinstance(app_bin, str): |
|
app_bin = (app_bin, ) |
|
for a_bin in app_bin: |
|
cmd = 'killall -STOP {}'.format(a_bin) |
|
logger.debug('CMD: {!r}'.format(cmd)) |
|
os.system(cmd) |
|
state[app] = False |
|
|
|
|
|
def resume(app, app_bin): |
|
logger.info('RESUME: {}'.format(app)) |
|
if isinstance(app_bin, str): |
|
app_bin = (app_bin, ) |
|
for a_bin in app_bin: |
|
cmd = 'killall -CONT {}'.format(a_bin) |
|
logger.debug('CMD: {!r}'.format(cmd)) |
|
os.system(cmd) |
|
state[app] = True |
|
|
|
|
|
def monitor(suspend_apps): |
|
try: |
|
while True: |
|
sleep(0.2) |
|
active = get_active_app_name() |
|
if active in suspend_apps: |
|
if active not in state: |
|
resume(active, suspend_apps[active]) |
|
state[active] = True |
|
if not state[active]: |
|
resume(active, suspend_apps[active]) |
|
all_except_active = {k:v for k, v in state.items() if v and k!= active} |
|
if any(all_except_active.values()): |
|
[suspend(k, suspend_apps[k]) for k, v in all_except_active.items()] |
|
except (Exception, BaseException): |
|
print('') |
|
logger.info('Resuming all apps before exiting.') |
|
[resume(k, suspend_apps[k]) for k, v in state.items() if not v] |
|
|
|
if __name__ == '__main__': |
|
# Configuration format: |
|
# App name as it appears in `Activity Monitor` utility. |
|
# App binary-name as it appears in "ps aux | egrep -i [APP-NAME] " |
|
# If an app (example Firefox) has multiple worker processes |
|
# with different binary names, you can pass a list of all binaries to suspend. |
|
config = { |
|
# AppName: binary-name |
|
'Firefox': ['firefox', 'plugin-container'], |
|
'Preview': 'Preview', |
|
'PyCharm': 'pycharm', |
|
'TagSpaces': 'TagSpaces', |
|
} |
|
monitor(config) |