diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..d0e6a2a --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +pi3-smart-workspace \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 1cbbf47..734b730 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/.idea/PyOutputHandler.iml b/.idea/pi3-smart-workspace.iml similarity index 100% rename from .idea/PyOutputHandler.iml rename to .idea/pi3-smart-workspace.iml diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..582da73 --- /dev/null +++ b/README.rst @@ -0,0 +1,64 @@ +About +----- + +Simple program that looks through the i3 config and finds the bound workspaces for each output, and then opening that workspace on the output, that the mouse is currently on. + +Allowing for a more seameless interaction with how workspaces are openend. + +Usage +----- + +:: + + usage: pi3-smar-switch [-h] [-f] [-p | -m | -s] WORKSPACE_NAME + + Moves selected i3 workspace to the current output (by default determined by + cursor location) and focuses it. + + positional arguments: + workspace name of the i3 workspace + + optional arguments: + -h, --help show this help message and exit + -f, --focus use focused window instead of cursor position to determine the + current output + -p, --push moves replaced workspace to the second output (works only if + there are two outputs, ignored otherwise) + -m, --master same as 'push' but will only move from primary output to the + secondary + -s, --swap (NOT IMPLEMENTED YET) behaves like xmonad, swaps workspaces if + they are on a different output + +Installation +------------ + +Install using `pipsi`_ (recommended) or pip: + +:: + + pipsi install pi3-switch + +Add keybindings to ~/.config/i3/config and reload i3 (remember to modify flags to your liking): + +:: + + bindsym $mod+1 exec pi3-switch -p 1 + bindsym $mod+2 exec pi3-switch -p 2 + bindsym $mod+3 exec pi3-switch -p 3 + bindsym $mod+4 exec pi3-switch -p 4 + bindsym $mod+5 exec pi3-switch -p 5 + bindsym $mod+6 exec pi3-switch -p 6 + bindsym $mod+7 exec pi3-switch -p 7 + bindsym $mod+8 exec pi3-switch -p 8 + bindsym $mod+9 exec pi3-switch -p 9 + bindsym $mod+0 exec pi3-switch -p 10 + +Credits +------- + +Thanks to Travis Finkenauer for an inspiration (`i3-wk-switch`_) and +Tony Crisci for an easy-to-use i3 python library (`i3ipc-python`_). + +.. _pipsi: https://github.com/mitsuhiko/pipsi +.. _i3-wk-switch: https://github.com/tmfink/i3-wk-switch +.. _i3ipc-python: https://github.com/acrisci/i3ipc-python diff --git a/pi3/__init__.py b/pi3/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/main.py b/pi3/smart-workspace.py similarity index 56% rename from main.py rename to pi3/smart-workspace.py index 1c8eac1..ef06ea3 100644 --- a/main.py +++ b/pi3/smart-workspace.py @@ -1,15 +1,9 @@ -from i3ipc import connection, Connection -import logging +from i3ipc import Connection import sys from pprint import pprint import pynput import re -import asyncio - -"""import argparse -""" - -logger = logging.getLogger(__name__) +import argparse class WorkSpacer: @@ -17,32 +11,48 @@ class WorkSpacer: def __init__(self, args): self.i3 = None self.args = args - self.workspaces_on_outputs = None + self.workspaces_on_outputs = {} self.workspaces = None self.outputs = None - + self.config = None self.mouse = pynput.mouse.Controller() - self.mouse_position = None self.current_output_name = None def _connect(self): try: self.i3 = Connection() - re.compile(r'') - self.workspaces_on_outputs = [ws for ws in self.i3.get_config().__dict__['config'].split('\n') if ws] + self.config = self.i3.get_config().__dict__['config'] + config_outputs = {} + for matchNo, match in enumerate( + re.finditer(r'set (\$[a-zA-Z]+) ((HDMI|DP|VGA)-\d)', self.config, re.MULTILINE), start=1 + ): + config_outputs[match.group(1)] = match.group(2) + pprint(config_outputs) + config_workspace_names = {} + for matchNum, match in enumerate( + re.finditer(r'set (\$.*) (\d.*)', self.config, re.MULTILINE) + ): + config_workspace_names[match.group(1)] = match.group(2) + pprint(config_workspace_names) + for matchNum, match in enumerate( + re.finditer(r'workspace (\$.*) output (\$.*)', self.config, re.MULTILINE) + ): + if not self.workspaces_on_outputs.keys().__contains__(config_outputs[match.group(2)]): + self.workspaces_on_outputs[config_outputs[match.group(2)]] = [] + self.workspaces_on_outputs[config_outputs[match.group(2)]].append(config_workspace_names[match.group(1)]) + except Exception as exc: - logger.error(f"Could not load i3: {exc}", exc_info=exc) sys.exit(1) self.workspaces = [workspaces for workspaces in self.i3.get_workspaces()] - outputs = self.i3.get_outputs() - #pprint(outputs[1].__dict__) + outputs = self.i3.get_outputs() self.outputs = [output for output in outputs if output.__dict__["active"] is True] def run(self): self._connect() self.mouse_position = self.mouse.position self.current_output_name = self._get_workspace_from_courser_position() + self.i3.command(f'workspace {self.workspaces_on_outputs[self.current_output_name][self.args]}') def _get_workspace_from_courser_position(self): for output in self.outputs: @@ -68,12 +78,18 @@ class WorkSpacer: return [workspace for workspace in self.workspaces if workspace.__dict__['output'] == output] -def tst(): - ws = WorkSpacer('') +def main(): + parser = argparse.ArgumentParser( + description="Dynamic changes the workspace, based on what output your cursoer is on." + ) + parser.add_argument("-i", "--index", type=int, + help="the number index of the workspace that should be openend. 1 = workspace 1 etc.") + ws = WorkSpacer(parser.parse_args()) ws.run() + # Press the green button in the gutter to run the script. if __name__ == '__main__': - tst() + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..57eb532 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +evdev==1.3.0 +i3ipc==2.2.1 +pynput==1.7.1 +python-xlib==0.27 +six==1.15.0 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..e2e78d3 --- /dev/null +++ b/setup.py @@ -0,0 +1,32 @@ +from setuptools import setup + +with open('README.rst', 'r') as fh: + long_description = fh.read() +with open('requirements.txt', 'r') as file: + required = [] + for x in file.readline(): + required.append(x) + + +setup( + name="pi3-smart-workspace", + description="A smart switcher for multiple workspaces.", + long_description=long_description, + version="0.0.1", + license="Apache License", + author="Asger Geel Weirsøe", + author_email="asger@weirsoe.dk", + url="https://github.com/GeneralDenmark/PyOutputHandler", + install_requires=required, + packages=["pi3"], + zip_safe=True, + entry_points={"console_scripts": ["pi3-smart-workspace = pi3.smart-workspace:main"]}, + scripts=["pi3/smart-workspace.py"], + classifiers=[ + "Development Status :: 2 - Pre-Alpha", + "License :: OSI Approved :: Apache Software License", + "Operating System :: POSIX :: Linux", + "Programming Language :: Python :: 3", + "Topic :: Desktop Environment :: Window Managers", + ], +) \ No newline at end of file