Refactored python code into library.
This commit is contained in:
parent
aae65e3825
commit
309bafd5d1
7 changed files with 247 additions and 203 deletions
127
setsysmode
127
setsysmode
|
@ -1,132 +1,7 @@
|
||||||
#! /usr/bin/env python3
|
#! /usr/bin/env python3
|
||||||
"""Sets the system mode."""
|
"""Sets the system mode."""
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from tabletmode.cli import main
|
||||||
from subprocess import DEVNULL, CalledProcessError, check_call, run
|
|
||||||
from sys import stderr
|
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION = 'Sets or toggles the system mode.'
|
|
||||||
LAPTOP_MODE_SERVICE = 'laptop-mode.service'
|
|
||||||
TABLET_MODE_SERVICE = 'tablet-mode.service'
|
|
||||||
|
|
||||||
|
|
||||||
def get_arguments():
|
|
||||||
"""Returns the CLI arguments."""
|
|
||||||
|
|
||||||
parser = ArgumentParser(description=DESCRIPTION)
|
|
||||||
parser.add_argument(
|
|
||||||
'-n', '--notify', action='store_true',
|
|
||||||
help='display an on-screen notification')
|
|
||||||
subparsers = parser.add_subparsers(dest='mode')
|
|
||||||
subparsers.add_parser('toggle', help='toggles the system mode')
|
|
||||||
subparsers.add_parser('laptop', help='switch to laptop mode')
|
|
||||||
subparsers.add_parser('tablet', help='switch to tablet mode')
|
|
||||||
subparsers.add_parser('default', help='do not disable any input devices')
|
|
||||||
return parser.parse_args()
|
|
||||||
|
|
||||||
|
|
||||||
def systemctl(action, unit, *, root=False):
|
|
||||||
"""Runs systemctl."""
|
|
||||||
|
|
||||||
command = ['/usr/bin/sudo'] if root else []
|
|
||||||
command.append('systemctl')
|
|
||||||
command.append(action)
|
|
||||||
command.append(unit)
|
|
||||||
|
|
||||||
try:
|
|
||||||
check_call(command, stdout=DEVNULL) # Return 0 on success.
|
|
||||||
except CalledProcessError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def notify_send(summary, body=None):
|
|
||||||
"""Sends the respective message."""
|
|
||||||
|
|
||||||
command = ['/usr/bin/notify-send', summary]
|
|
||||||
|
|
||||||
if body is not None:
|
|
||||||
command.append(body)
|
|
||||||
|
|
||||||
return run(command, stdout=DEVNULL)
|
|
||||||
|
|
||||||
|
|
||||||
def notify_laptop_mode():
|
|
||||||
"""Notifies about laptop mode."""
|
|
||||||
|
|
||||||
return notify_send('Laptop mode.', 'The system is now in laptop mode.')
|
|
||||||
|
|
||||||
|
|
||||||
def notify_tablet_mode():
|
|
||||||
"""Notifies about tablet mode."""
|
|
||||||
|
|
||||||
return notify_send('Tablet mode.', 'The system is now in tablet mode.')
|
|
||||||
|
|
||||||
|
|
||||||
def toggle_mode(notify):
|
|
||||||
"""Toggles between laptop and tablet mode."""
|
|
||||||
|
|
||||||
if systemctl('status', TABLET_MODE_SERVICE):
|
|
||||||
systemctl('stop', TABLET_MODE_SERVICE, root=True)
|
|
||||||
systemctl('start', LAPTOP_MODE_SERVICE, root=True)
|
|
||||||
|
|
||||||
if notify:
|
|
||||||
notify_tablet_mode()
|
|
||||||
else:
|
|
||||||
systemctl('stop', LAPTOP_MODE_SERVICE, root=True)
|
|
||||||
systemctl('start', TABLET_MODE_SERVICE, root=True)
|
|
||||||
|
|
||||||
if notify:
|
|
||||||
notify_laptop_mode()
|
|
||||||
|
|
||||||
|
|
||||||
def default_mode(notify):
|
|
||||||
"""Restores all blocked input devices."""
|
|
||||||
|
|
||||||
systemctl('stop', LAPTOP_MODE_SERVICE, root=True)
|
|
||||||
systemctl('stop', TABLET_MODE_SERVICE, root=True)
|
|
||||||
|
|
||||||
if notify:
|
|
||||||
notify_send('Default mode.', 'The system is now in default mode.')
|
|
||||||
|
|
||||||
|
|
||||||
def laptop_mode(notify):
|
|
||||||
"""Starts the laptop mode."""
|
|
||||||
|
|
||||||
systemctl('stop', TABLET_MODE_SERVICE, root=True)
|
|
||||||
systemctl('start', LAPTOP_MODE_SERVICE, root=True)
|
|
||||||
|
|
||||||
if notify:
|
|
||||||
notify_laptop_mode()
|
|
||||||
|
|
||||||
|
|
||||||
def tablet_mode(notify):
|
|
||||||
"""Starts the tablet mode."""
|
|
||||||
|
|
||||||
systemctl('stop', LAPTOP_MODE_SERVICE, root=True)
|
|
||||||
systemctl('start', TABLET_MODE_SERVICE, root=True)
|
|
||||||
|
|
||||||
if notify:
|
|
||||||
notify_tablet_mode()
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Runs the main program."""
|
|
||||||
|
|
||||||
arguments = get_arguments()
|
|
||||||
|
|
||||||
if arguments.mode == 'toggle':
|
|
||||||
toggle_mode(arguments.notify)
|
|
||||||
elif arguments.mode == 'default':
|
|
||||||
default_mode(arguments.notify)
|
|
||||||
elif arguments.mode == 'laptop':
|
|
||||||
laptop_mode(arguments.notify)
|
|
||||||
elif arguments.mode == 'tablet':
|
|
||||||
tablet_mode(arguments.notify)
|
|
||||||
else:
|
|
||||||
print('Must specify a mode.', file=stderr, flush=True)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
20
setup.py
Executable file
20
setup.py
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='tabletmode',
|
||||||
|
version_format='{tag}',
|
||||||
|
setup_requires=['setuptools-git-version'],
|
||||||
|
author='Richard Neumann',
|
||||||
|
author_email='mail@richard-neumann.de',
|
||||||
|
python_requires='>=3.8',
|
||||||
|
packages=['tabletmode'],
|
||||||
|
scripts=['setsysmode', 'sysmoded'],
|
||||||
|
url='https://github.com/conqp/tablet-mode',
|
||||||
|
license='GPLv3',
|
||||||
|
description='Tablet mode switch for GNOME 3.',
|
||||||
|
long_description=open('README.md').read(),
|
||||||
|
long_description_content_type="text/markdown",
|
||||||
|
keywords='tablet mode tent convertible switch'
|
||||||
|
)
|
78
sysmoded
78
sysmoded
|
@ -1,83 +1,7 @@
|
||||||
#! /usr/bin/env python3
|
#! /usr/bin/env python3
|
||||||
"""System mode daemon."""
|
"""System mode daemon."""
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from tabletmode.daemon import main
|
||||||
from json import load
|
|
||||||
from logging import DEBUG, INFO, basicConfig, getLogger
|
|
||||||
from pathlib import Path
|
|
||||||
from subprocess import Popen
|
|
||||||
|
|
||||||
|
|
||||||
CONFIG_FILE = Path('/etc/tablet-mode.json')
|
|
||||||
DESCRIPTION = 'Setup system for laptop or tablet mode.'
|
|
||||||
EVTEST = '/usr/bin/evtest'
|
|
||||||
LOG_FORMAT = '[%(levelname)s] %(name)s: %(message)s'
|
|
||||||
LOGGER = getLogger(__file__)
|
|
||||||
|
|
||||||
|
|
||||||
def get_arguments():
|
|
||||||
"""Parses the CLI arguments."""
|
|
||||||
|
|
||||||
parser = ArgumentParser(description=DESCRIPTION)
|
|
||||||
parser.add_argument(
|
|
||||||
'-v', '--verbose', action='store_true',
|
|
||||||
help='turn on verbose logging')
|
|
||||||
subparsers = parser.add_subparsers(dest='mode')
|
|
||||||
subparsers.add_parser('laptop', help='enable laptop mode')
|
|
||||||
subparsers.add_parser('tablet', help='enable tablet mode')
|
|
||||||
return parser.parse_args()
|
|
||||||
|
|
||||||
|
|
||||||
def load_configuration():
|
|
||||||
"""Returns the configuration."""
|
|
||||||
|
|
||||||
try:
|
|
||||||
with CONFIG_FILE.open('r') as cfg:
|
|
||||||
return load(cfg)
|
|
||||||
except FileNotFoundError:
|
|
||||||
LOGGER.warning('Config file %s does not exist.', CONFIG_FILE)
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
def disable_device(device):
|
|
||||||
"""Disables the respective device via evtest."""
|
|
||||||
|
|
||||||
return Popen((EVTEST, '--grab', device))
|
|
||||||
|
|
||||||
|
|
||||||
def disable_devices(devices):
|
|
||||||
"""Disables the given devices."""
|
|
||||||
|
|
||||||
subprocesses = []
|
|
||||||
|
|
||||||
for device in devices:
|
|
||||||
subprocess = disable_device(device)
|
|
||||||
subprocesses.append(subprocess)
|
|
||||||
|
|
||||||
for subprocess in subprocesses:
|
|
||||||
subprocess.wait()
|
|
||||||
|
|
||||||
|
|
||||||
def get_devices(mode):
|
|
||||||
"""Reads the device from the config file."""
|
|
||||||
|
|
||||||
configuration = load_configuration()
|
|
||||||
devices = configuration.get(mode) or ()
|
|
||||||
|
|
||||||
if not devices:
|
|
||||||
LOGGER.info('No devices configured to disable.')
|
|
||||||
|
|
||||||
return devices
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Runs the main program."""
|
|
||||||
|
|
||||||
arguments = get_arguments()
|
|
||||||
level = DEBUG if arguments.verbose else INFO
|
|
||||||
basicConfig(level=level, format=LOG_FORMAT)
|
|
||||||
devices = get_devices(arguments.mode)
|
|
||||||
disable_devices(devices)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
1
tabletmode/__init__.py
Normal file
1
tabletmode/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
"""Tablet mode library."""
|
133
tabletmode/cli.py
Normal file
133
tabletmode/cli.py
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
|
||||||
|
"""Sets the system mode."""
|
||||||
|
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
from subprocess import DEVNULL, CalledProcessError, check_call, run
|
||||||
|
from sys import stderr
|
||||||
|
|
||||||
|
from tabletmode.config import load_configuration
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTION = 'Sets or toggles the system mode.'
|
||||||
|
LAPTOP_MODE_SERVICE = 'laptop-mode.service'
|
||||||
|
TABLET_MODE_SERVICE = 'tablet-mode.service'
|
||||||
|
|
||||||
|
|
||||||
|
def get_arguments():
|
||||||
|
"""Returns the CLI arguments."""
|
||||||
|
|
||||||
|
parser = ArgumentParser(description=DESCRIPTION)
|
||||||
|
parser.add_argument(
|
||||||
|
'-n', '--notify', action='store_true',
|
||||||
|
help='display an on-screen notification')
|
||||||
|
subparsers = parser.add_subparsers(dest='mode')
|
||||||
|
subparsers.add_parser('toggle', help='toggles the system mode')
|
||||||
|
subparsers.add_parser('laptop', help='switch to laptop mode')
|
||||||
|
subparsers.add_parser('tablet', help='switch to tablet mode')
|
||||||
|
subparsers.add_parser('default', help='do not disable any input devices')
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def systemctl(action, unit, *, root=False):
|
||||||
|
"""Runs systemctl."""
|
||||||
|
|
||||||
|
command = ['/usr/bin/sudo'] if root else []
|
||||||
|
command.append('systemctl')
|
||||||
|
command.append(action)
|
||||||
|
command.append(unit)
|
||||||
|
|
||||||
|
try:
|
||||||
|
check_call(command, stdout=DEVNULL) # Return 0 on success.
|
||||||
|
except CalledProcessError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def notify_send(summary, body=None):
|
||||||
|
"""Sends the respective message."""
|
||||||
|
|
||||||
|
command = ['/usr/bin/notify-send', summary]
|
||||||
|
|
||||||
|
if body is not None:
|
||||||
|
command.append(body)
|
||||||
|
|
||||||
|
return run(command, stdout=DEVNULL, check=False)
|
||||||
|
|
||||||
|
|
||||||
|
def notify_laptop_mode():
|
||||||
|
"""Notifies about laptop mode."""
|
||||||
|
|
||||||
|
return notify_send('Laptop mode.', 'The system is now in laptop mode.')
|
||||||
|
|
||||||
|
|
||||||
|
def notify_tablet_mode():
|
||||||
|
"""Notifies about tablet mode."""
|
||||||
|
|
||||||
|
return notify_send('Tablet mode.', 'The system is now in tablet mode.')
|
||||||
|
|
||||||
|
|
||||||
|
def toggle_mode(notify=False):
|
||||||
|
"""Toggles between laptop and tablet mode."""
|
||||||
|
|
||||||
|
if systemctl('status', TABLET_MODE_SERVICE):
|
||||||
|
systemctl('stop', TABLET_MODE_SERVICE, root=True)
|
||||||
|
systemctl('start', LAPTOP_MODE_SERVICE, root=True)
|
||||||
|
|
||||||
|
if notify:
|
||||||
|
notify_tablet_mode()
|
||||||
|
else:
|
||||||
|
systemctl('stop', LAPTOP_MODE_SERVICE, root=True)
|
||||||
|
systemctl('start', TABLET_MODE_SERVICE, root=True)
|
||||||
|
|
||||||
|
if notify:
|
||||||
|
notify_laptop_mode()
|
||||||
|
|
||||||
|
|
||||||
|
def default_mode(notify=False):
|
||||||
|
"""Restores all blocked input devices."""
|
||||||
|
|
||||||
|
systemctl('stop', LAPTOP_MODE_SERVICE, root=True)
|
||||||
|
systemctl('stop', TABLET_MODE_SERVICE, root=True)
|
||||||
|
|
||||||
|
if notify:
|
||||||
|
notify_send('Default mode.', 'The system is now in default mode.')
|
||||||
|
|
||||||
|
|
||||||
|
def laptop_mode(notify=False):
|
||||||
|
"""Starts the laptop mode."""
|
||||||
|
|
||||||
|
systemctl('stop', TABLET_MODE_SERVICE, root=True)
|
||||||
|
systemctl('start', LAPTOP_MODE_SERVICE, root=True)
|
||||||
|
|
||||||
|
if notify:
|
||||||
|
notify_laptop_mode()
|
||||||
|
|
||||||
|
|
||||||
|
def tablet_mode(notify=False):
|
||||||
|
"""Starts the tablet mode."""
|
||||||
|
|
||||||
|
systemctl('stop', LAPTOP_MODE_SERVICE, root=True)
|
||||||
|
systemctl('start', TABLET_MODE_SERVICE, root=True)
|
||||||
|
|
||||||
|
if notify:
|
||||||
|
notify_tablet_mode()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Runs the main program."""
|
||||||
|
|
||||||
|
arguments = get_arguments()
|
||||||
|
configuration = load_configuration()
|
||||||
|
notify = configuration.get('notify', False) or arguments.notify
|
||||||
|
|
||||||
|
if arguments.mode == 'toggle':
|
||||||
|
toggle_mode(notify=notify)
|
||||||
|
elif arguments.mode == 'default':
|
||||||
|
default_mode(notify=notify)
|
||||||
|
elif arguments.mode == 'laptop':
|
||||||
|
laptop_mode(notify=notify)
|
||||||
|
elif arguments.mode == 'tablet':
|
||||||
|
tablet_mode(notify=notify)
|
||||||
|
else:
|
||||||
|
print('Must specify a mode.', file=stderr, flush=True)
|
23
tabletmode/config.py
Normal file
23
tabletmode/config.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
"""Configuration file parsing."""
|
||||||
|
|
||||||
|
from json import load
|
||||||
|
from logging import getLogger
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ['load_configuration']
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_FILE = Path('/etc/tablet-mode.json')
|
||||||
|
LOGGER = getLogger('tabletmode')
|
||||||
|
|
||||||
|
|
||||||
|
def load_configuration():
|
||||||
|
"""Returns the configuration."""
|
||||||
|
|
||||||
|
try:
|
||||||
|
with CONFIG_FILE.open('r') as cfg:
|
||||||
|
return load(cfg)
|
||||||
|
except FileNotFoundError:
|
||||||
|
LOGGER.warning('Config file %s does not exist.', CONFIG_FILE)
|
||||||
|
return {}
|
68
tabletmode/daemon.py
Normal file
68
tabletmode/daemon.py
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
|
||||||
|
"""System mode daemon."""
|
||||||
|
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
from logging import DEBUG, INFO, basicConfig, getLogger
|
||||||
|
from subprocess import Popen
|
||||||
|
|
||||||
|
from tabletmode.config import load_configuration
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTION = 'Setup system for laptop or tablet mode.'
|
||||||
|
EVTEST = '/usr/bin/evtest'
|
||||||
|
LOG_FORMAT = '[%(levelname)s] %(name)s: %(message)s'
|
||||||
|
LOGGER = getLogger('sysmoded')
|
||||||
|
|
||||||
|
|
||||||
|
def get_arguments():
|
||||||
|
"""Parses the CLI arguments."""
|
||||||
|
|
||||||
|
parser = ArgumentParser(description=DESCRIPTION)
|
||||||
|
parser.add_argument(
|
||||||
|
'-v', '--verbose', action='store_true',
|
||||||
|
help='turn on verbose logging')
|
||||||
|
subparsers = parser.add_subparsers(dest='mode')
|
||||||
|
subparsers.add_parser('laptop', help='enable laptop mode')
|
||||||
|
subparsers.add_parser('tablet', help='enable tablet mode')
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def disable_device(device):
|
||||||
|
"""Disables the respective device via evtest."""
|
||||||
|
|
||||||
|
return Popen((EVTEST, '--grab', device))
|
||||||
|
|
||||||
|
|
||||||
|
def disable_devices(devices):
|
||||||
|
"""Disables the given devices."""
|
||||||
|
|
||||||
|
subprocesses = []
|
||||||
|
|
||||||
|
for device in devices:
|
||||||
|
subprocess = disable_device(device)
|
||||||
|
subprocesses.append(subprocess)
|
||||||
|
|
||||||
|
for subprocess in subprocesses:
|
||||||
|
subprocess.wait()
|
||||||
|
|
||||||
|
|
||||||
|
def get_devices(mode):
|
||||||
|
"""Reads the device from the config file."""
|
||||||
|
|
||||||
|
configuration = load_configuration()
|
||||||
|
devices = configuration.get(mode) or ()
|
||||||
|
|
||||||
|
if not devices:
|
||||||
|
LOGGER.info('No devices configured to disable.')
|
||||||
|
|
||||||
|
return devices
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Runs the main program."""
|
||||||
|
|
||||||
|
arguments = get_arguments()
|
||||||
|
level = DEBUG if arguments.verbose else INFO
|
||||||
|
basicConfig(level=level, format=LOG_FORMAT)
|
||||||
|
devices = get_devices(arguments.mode)
|
||||||
|
disable_devices(devices)
|
Loading…
Reference in a new issue