diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | LICENSE | 24 | ||||
-rw-r--r-- | README.md | 50 | ||||
-rw-r--r-- | docs/xkcd1172.1 | 36 | ||||
-rw-r--r-- | pyproject.toml | 6 | ||||
-rw-r--r-- | requirements.txt | 7 | ||||
-rw-r--r-- | setup.cfg | 29 | ||||
-rw-r--r-- | src/xkcd1172/__init__.py | 1 | ||||
-rw-r--r-- | src/xkcd1172/main.py | 166 |
9 files changed, 322 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..abf156d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.egg-info +dist +*venv* @@ -0,0 +1,24 @@ +BSD 2-Clause License + +Copyright (c) 2022, Dawid Potocki + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..00a73e7 --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# xkcd1172 + +Rapidly increases CPU temperature when holding down the spacebar. + +***https://xkcd.com/1172*** + +![xkcd 1172: Workflow](https://imgs.xkcd.com/comics/workflow.png) + +## Installation + +```sh +$ pip3 install xkcd1172 +``` + +### Requirements + +- Xorg (Wayland works if you are focused on an Xwayland window) +- Spacebar +- CPU + +## Building + +```sh +$ git clone https://git.dawidpotocki.com/dawid/xkcd1172 +$ cd xkcd1172 + +$ python3 -m build +$ pip3 install dist/xkcd1172-<version>-py3-none-any.whl +``` + +## Running standalone + +```sh +$ xkcd1172 +``` + +### Autostart + +```sh +$ xkcd1172 -a # Add to XDG autostart +$ xkcd1172 -r # Remove from XDG autostart +``` + +## Running as a library + +```py +import xkcd1172 + +xkcd1172.start_daemon_thread() +``` diff --git a/docs/xkcd1172.1 b/docs/xkcd1172.1 new file mode 100644 index 0000000..8a2a4ca --- /dev/null +++ b/docs/xkcd1172.1 @@ -0,0 +1,36 @@ +.Dd $Mdocdate$ +.Dt XKCD1172 1 +.Os +.Sh NAME +.Nm xkcd1172 +.Nd rapidly increase CPU temperature when holding down the spacebar +.Sh SYNOPSIS +.Nm +.Op OPTIONS... +.Sh DESCRIPTION +.Nm +is a program that brings back spacebar heating to your system. You can use it +standalone or as a Python library to include it in your program. +.Sh OPTIONS +.Bl -tag -width Ds -compact +.It Fl a, Fl -add-autostart +Adds +.Nm +to XDG autostart. +.Pp +.It Fl r, Fl -rm-autostart +Removes +.Nm +from XDG autostart. +.Sh EXAMPLES +.Pp +Using as a Python library: +.Bd -literal +import xkcd1172 +xkcd1172.start_daemon_thread() +.Sh AUTHORS +.An Dawid Potocki +- +.Lk https://dawidpotocki.com +.Sh BUGS +You mean features? diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..374b58c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,6 @@ +[build-system] +requires = [ + "setuptools>=42", + "wheel" +] +build-backend = "setuptools.build_meta" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e0710ab --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +build==0.7.0 +packaging==21.3 +pep517==0.12.0 +pyparsing==3.0.9 +python-xlib==0.31 +six==1.16.0 +tomli==2.0.1 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..3e97198 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,29 @@ +[metadata] +name = xkcd1172 +version = 0.1.0 +author = Dawid Potocki +author_email = pypi@dawidpotocki.com +description = Rapidly increases CPU temperature when holding down the spacebar +long_description = file: README.md +long_description_content_type = text/markdown +url = https://git.dawidpotocki.com/dawid/xkcd1172 +classifiers = + Programming Language :: Python :: 3 + License :: OSI Approved :: BSD License + Operating System :: POSIX + Environment :: X11 Applications + +[options] +package_dir = + = src +packages = find: +python_requires = >=3.7 +install_requires = + python-xlib>=0.31,<1 + +[options.packages.find] +where = src + +[options.entry_points] +console_scripts = + xkcd1172 = xkcd1172:main.main diff --git a/src/xkcd1172/__init__.py b/src/xkcd1172/__init__.py new file mode 100644 index 0000000..0eedd79 --- /dev/null +++ b/src/xkcd1172/__init__.py @@ -0,0 +1 @@ +from xkcd1172.main import start, start_daemon_thread diff --git a/src/xkcd1172/main.py b/src/xkcd1172/main.py new file mode 100644 index 0000000..610d791 --- /dev/null +++ b/src/xkcd1172/main.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 + +import argparse, atexit, multiprocessing, os, sys, threading + +from Xlib import X, XK, display +from Xlib.ext import record +from Xlib.protocol import rq + + +# +# Variables +# + +APPNAME = "xkcd1172" +ACTIVATE_AT_PRESSES = 2 + +rubbish_launched = False +presses_before_release = 0 +local_dpy = None + +if "XDG_CONFIG_HOME" in os.environ: + XDG_CONFIG_HOME = os.environ["XDG_CONFIG_HOME"] +else: + XDG_CONFIG_HOME = "~/.config" + + +# +# Functions +# + +def main(): + """Main function.""" + + # Don't print traceback on C-c + sys.excepthook = excepthook + + # Argument parsing + parser = argparse.ArgumentParser(description="Rapidly increase CPU temperature when holding down the spacebar.") + parser.add_argument("-a", "--add-autostart", action="store_true", help=f"add itself to XDG autostart") + parser.add_argument("-r", "--rm-autostart", action="store_true", help=f"remove itself from XDG autostart") + args = parser.parse_args() + + if args.add_autostart: + add_autostart() + + elif args.rm_autostart: + rm_autostart() + + else: + start() + + +def start(): + """Setup heating on spacebar holding.""" + global local_dpy + + if "WAYLAND_DISPLAY" in os.environ: + print( + "\033[1;33mWARN:\033[0m This utility depends on Xlib, which means it only works with Xorg.\n" + " Because you are using Wayland, it will only work when you are focused on an Xwayland window.\n" + " How dare these nasty Wayland people break my workflow!\n" + ) + try: + local_dpy = display.Display() + except Xlib.error.DisplayNameError: + print("\033[1;31mCRIT:\033[0m Couldn't find X. Exiting.") + exit(1) + + ctx = local_dpy.record_create_context( + 0, + [record.AllClients], + [{ + 'core_requests': (0, 0), + 'core_replies': (0, 0), + 'ext_requests': (0, 0, 0, 0), + 'ext_replies': (0, 0, 0, 0), + 'delivered_events': (0, 0), + 'device_events': (X.KeyPress, X.KeyRelease), + 'errors': (0, 0), + 'client_started': False, + 'client_died': False, + }] + ) + + atexit.register(exit_handler, ctx) + local_dpy.record_enable_context(ctx, space_handler) + + +def start_daemon_thread(): + threading.Thread(target=start, daemon=True).start() + + +def space_handler(reply): + """Run do_nothing() when space is held.""" + + global presses_before_release, rubbish_launched + + data = reply.data + + while len(data): + event, data = rq.EventField(None).parse_binary_value(data, local_dpy.display, None, None) + + if presses_before_release > ACTIVATE_AT_PRESSES and rubbish_launched == False: + for i in range(multiprocessing.cpu_count()): + multiprocessing.Process(target=do_nothing).start() + rubbish_launched = True + + if event.type in [X.KeyPress, X.KeyRelease]: + # For some reason it's giving numeric keysyms + if local_dpy.keycode_to_keysym(event.detail, 0) == 32: # 32 == XK_space + if event.type == X.KeyPress: + presses_before_release += 1 + else: + for child in multiprocessing.active_children(): + multiprocessing.Process.kill(child) + presses_before_release = 0 + rubbish_launched = False + + +def do_nothing(): + """Do nothing.""" + + while True: + pass + + +def add_autostart(): + """Add itself to XDG autostart.""" + + file_path = f"{XDG_CONFIG_HOME}/autostart/{APPNAME}.desktop" + os.makedirs(os.path.dirname(file_path), exist_ok=True) + with open(file_path, "w") as file: + file.write(f"""[Desktop Entry] +Type=Application +Name={APPNAME} +Comment=Rapidly increase CPU temperature when holding down the spacebar +Exec={APPNAME} +""") + + +def rm_autostart(): + """Remove itself from XDG autostart.""" + + try: + os.remove(f"{XDG_CONFIG_HOME}/autostart/{APPNAME}.desktop") + except FileNotFoundError: + print(f"\033[1;33mWARN:\033[0m {APPNAME} wasn't in the autostart") + + +def excepthook(type, value, traceback): + """Custom exception hook to not print traceback when doing C-c.""" + + if type is KeyboardInterrupt: + return + else: + sys.__excepthook__(type, value, traceback) + + +def exit_handler(ctx): + """Free context on exit.""" + + local_dpy.record_free_context(ctx) + + +if __name__ == "__main__": + main() |