17 Commits

Author SHA1 Message Date
Asger Geel Weirsøe
0a44792155 adds extra monitors to the possible outputs 2020-09-15 14:31:23 +02:00
Asger Geel Weirsøe
2659ec1d9e Automatically deploys to pypi 2020-09-05 13:34:35 +02:00
Asger Geel Weirsøe
d6b8aa7dce updates build script to remove old builds before uploading 2020-09-05 13:05:09 +02:00
Asger Geel Weirsøe
4ae10eb8dd updates build script to remove old builds before uploading 2020-09-05 12:39:58 +02:00
Asger Geel Weirsøe
f4ec4385b2 v0.1.2 2020-09-05 12:36:16 +02:00
Asger Geel Weirsøe
184832d805 updates readme 2020-09-05 12:29:38 +02:00
Asger Geel Weirsøe
d6015c5576 adds build script for deploying to pypi.org and smaller changes to the setup script 2020-09-05 12:25:33 +02:00
Asger Geel Weirsøe
4646f1c230 final fixes for v0.1.1 2020-09-05 11:59:07 +02:00
Asger Geel Weirsøe
34bfc4dea3 V0.1.0 2020-09-05 11:28:45 +02:00
Asger Geel Weirsøe
71f066f775 Updates ignore to ignore eggs generated by pip 2020-09-05 11:23:35 +02:00
Asger Geel Weirsøe
a056463fec cleanup 2020-09-05 11:21:18 +02:00
Asger Geel Weirsøe
1bd2a3bb7b Updates the git ignore file 2020-09-05 11:20:29 +02:00
Asger Geel Weirsøe
85ec3cd1d2 Demos the move of active container to workspace based on mouse cursor 2020-09-05 11:18:25 +02:00
Asger Geel Weirsøe
6dc86952db Merge branch 'master' of github.com:GeneralDenmark/PyOutputHandler into master 2020-09-05 10:59:53 +02:00
Asger Geel Weirsøe
8715e681ab fixes problems with installing the pacage with pip 2020-09-05 10:59:46 +02:00
Asger Geel Weirsøe
39f384e64b Update README.rst 2020-09-05 10:27:35 +02:00
Asger Geel Weirsøe
f848e2f746 Fixes a problem with args parse and updates the readme 2020-09-05 10:26:59 +02:00
14 changed files with 224 additions and 109 deletions

31
.github/workflows/python-publish.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
# This workflows will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
name: Upload Python Package
on:
release:
types: [created]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload --repository pypi dist/*

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
**__pycache__/
.idea
**.egg-info/
build/
dist/
.pypirc

8
.idea/.gitignore generated vendored
View File

@@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

1
.idea/.name generated
View File

@@ -1 +0,0 @@
pi3-smart-workspace

View File

@@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

View File

@@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

4
.idea/misc.xml generated
View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (PyOutputHandler)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/../pi3-smart-workspace/.idea/pi3-smart-workspace.iml" filepath="$PROJECT_DIR$/../pi3-smart-workspace/.idea/pi3-smart-workspace.iml" />
</modules>
</component>
</project>

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.8 (PyOutputHandler)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="Twisted Trial" />
</component>
</module>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -10,55 +10,131 @@ Usage
::
usage: pi3-smar-switch [-h] [-f] [-p | -m | -s] WORKSPACE_NAME
usage: pi3-smart-switch [-h] -i num
Openens the [i] number of workspace assigned in the config, on the output the cursor is currently on.
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
requred arguments:
-i, --index the number index of the workspace that should be openend. 1 = first workspace in config etc.
Current limitations
--------------------
The way this script is set up, it is sending commands in strings. and thus we cannot keep track of each workspace other than by its name. This is a limmitiaion as there is no way for us to know if the workspace "1" is reffering to the workspace 1 assigned to output DS-1 or output HDMI-2..
So in order to differentiate between these, you need to name your workspaces new names for each output. See example configuration under #Installation.
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:
Install using pip (recommended):
::
pipsi install pi3-switch
pip install pi3-smart-workspace
Add keybindings to ~/.config/i3/config and reload i3 (remember to modify flags to your liking):
Example config to be inserted into your i3 config.
::
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
# Displays
set $primary DP-2
set $left HDMI-0
set $right HDMI-1
# Workspaces
set $ws1 1:1:Code
set $ws2 2:2:Code
set $ws3 3:3:Code
set $ws4 4:4:Code
set $ws5 5:5:Code
set $ws6 6:6:Code
set $ws7 7:7:Code
set $ws8 8:8:Code
set $LeftWs1 1:1:Browser
set $LeftWs2 2:2:Left
set $LeftWs3 3:3:Left
set $LeftWs4 4:4:Left
set $LeftWs5 5:5:Left
set $LeftWs6 6:6:Left
set $LeftWs7 7:7:Left
set $LeftWs8 8:8:Left
set $RightWs1 1:1:Right
set $RightWs2 2:2:Right
set $RightWs3 3:3:Right
set $RightWs4 4:4:Right
set $RightWs5 5:5:Right
set $RightWs6 6:6:Right
set $RightWs7 7:7:Right
set $RightWs8 8:8:Right
# Workspace assignments
workspace $ws1 output $primary
workspace $ws2 output $primary
workspace $ws3 output $primary
workspace $ws4 output $primary
workspace $ws5 output $primary
workspace $ws6 output $primary
workspace $ws7 output $primary
workspace $ws8 output $primary
workspace $LeftWs1 output $left
workspace $LeftWs2 output $left
workspace $LeftWs3 output $left
workspace $LeftWs4 output $left
workspace $LeftWs5 output $left
workspace $LeftWs6 output $left
workspace $LeftWs7 output $left
workspace $LeftWs8 output $left
workspace $RightWs1 output $right
workspace $RightWs2 output $right
workspace $RightWs3 output $right
workspace $RightWs4 output $right
workspace $RightWs5 output $right
workspace $RightWs6 output $right
workspace $RightWs7 output $right
workspace $RightWs8 output $right
# Shift workspace
bindsym $mod+1 exec pi3-smart-workspace -i 1
bindsym $mod+2 exec pi3-smart-workspace -i 2
bindsym $mod+3 exec pi3-smart-workspace -i 3
bindsym $mod+4 exec pi3-smart-workspace -i 4
bindsym $mod+5 exec pi3-smart-workspace -i 5
bindsym $mod+6 exec pi3-smart-workspace -i 6
bindsym $mod+7 exec pi3-smart-workspace -i 7
bindsym $mod+8 exec pi3-smart-workspace -i 8
# Move focused container to workspace
bindsym $mod+Ctrl+1 exec pi3-smart-workspace -i 1 -s
bindsym $mod+Ctrl+2 exec pi3-smart-workspace -i 2 -s
bindsym $mod+Ctrl+3 exec pi3-smart-workspace -i 3 -s
bindsym $mod+Ctrl+4 exec pi3-smart-workspace -i 4 -s
bindsym $mod+Ctrl+5 exec pi3-smart-workspace -i 5 -s
bindsym $mod+Ctrl+6 exec pi3-smart-workspace -i 6 -s
bindsym $mod+Ctrl+7 exec pi3-smart-workspace -i 7 -s
bindsym $mod+Ctrl+8 exec pi3-smart-workspace -i 8 -s
# Move to workspace with focused container
bindsym $mod+Shift+1 exec pi3-smart-workspace -i 1 -sk
bindsym $mod+Shift+2 exec pi3-smart-workspace -i 2 -sk
bindsym $mod+Shift+3 exec pi3-smart-workspace -i 3 -sk
bindsym $mod+Shift+4 exec pi3-smart-workspace -i 4 -sk
bindsym $mod+Shift+5 exec pi3-smart-workspace -i 5 -sk
bindsym $mod+Shift+6 exec pi3-smart-workspace -i 6 -sk
bindsym $mod+Shift+7 exec pi3-smart-workspace -i 7 -sk
bindsym $mod+Shift+8 exec pi3-smart-workspace -i 8 -sk
Credits
-------
Thanks to Travis Finkenauer for an inspiration (`i3-wk-switch`_) and
Thanks to Michał Wieluński for an inspiration (`pi3-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
.. _pi3-switch: https://github.com/landmaj/pi3-switch
.. _i3ipc-python: https://github.com/acrisci/i3ipc-python

32
build.py Normal file
View File

@@ -0,0 +1,32 @@
import argparse
import subprocess
import pathlib
import os
def main():
parser = argparse.ArgumentParser("Build script for pypi and pypi test")
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--test', action='store_true', help='Build to test.pypi.org')
group.add_argument('--pypi', action='store_true', help='Build to pypi.org')
group.add_argument('--check', action='store_true', help='Displays the twine check for dist')
args = parser.parse_args()
for path in pathlib.Path('dist').iterdir():
os.remove(path)
subprocess.call(['python3', 'setup.py', 'sdist', 'bdist_wheel'], stdout=subprocess.PIPE)
if args.test:
subprocess.call(['twine', 'upload', '--config-file', '.pypirc', '--repository', 'testpypi', 'dist/*'])
elif args.pypi:
subprocess.call(['twine', 'upload', '--config-file', '.pypirc', '--repository', 'pypi', 'dist/*'])
else:
subprocess.call(['twine', 'check', 'dist/*'])
if __name__ == '__main__':
main()

View File

@@ -1,9 +1,9 @@
from i3ipc import Connection
import sys
from pprint import pprint
import pynput
import re
import argparse
import pprint
class WorkSpacer:
@@ -25,24 +25,25 @@ class WorkSpacer:
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
re.finditer(r'set (\$[a-zA-Z]+) ((HDMI|DP|VGA|eDP)(-|)\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)])
self.print_if_debug("All workspaces with outputs")
self.print_if_debug(self.workspaces_on_outputs)
except Exception as exc:
self.print_if_debug(exc)
sys.exit(1)
self.workspaces = [workspaces for workspaces in self.i3.get_workspaces()]
outputs = self.i3.get_outputs()
@@ -52,7 +53,12 @@ class WorkSpacer:
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]}')
if self.args.shift:
self.i3.command(f'move container to workspace {self.workspaces_on_outputs[self.current_output_name][self.args.index - 1]}')
if not self.args.keep_with_it:
return
self.i3.command(f'workspace {self.workspaces_on_outputs[self.current_output_name][self.args.index - 1]}')
def _get_workspace_from_courser_position(self):
for output in self.outputs:
@@ -77,18 +83,31 @@ class WorkSpacer:
def _get_workspaces_for_output(self, output):
return [workspace for workspace in self.workspaces if workspace.__dict__['output'] == output]
def print_if_debug(self, to_print):
if self.args.debug:
pprint.pprint(to_print)
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()
parser.add_argument('-d', '--debug', action='store_true',
help='Turn on debug mode.')
required_group = parser.add_argument_group('Required', '')
required_group.add_argument("-i", "--index", type=int, required=True,
help="the number index of the workspace that should be openend. 1 = first workspace in config etc.")
shift_group = parser.add_argument_group('Shift', 'manipulate the active window')
shift_group.add_argument("-s", "--shift", action='store_true',
help="if present, moves the current active window to target workspace")
shift_group.add_argument('-k', '--keep-with-it', action='store_true',
help='if present, moves with the ')
pprint.pprint(parser.parse_args().__dict__)
WorkSpacer(parser.parse_args()).run()
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
main()

View File

@@ -1,29 +1,29 @@
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.",
name='pi3-smart-workspace',
version='0.1.2',
packages=['pi3'],
url='https://github.com/GeneralDenmark/PyOutputHandler',
license='Apache-2.0 License ',
install_requires=[
"evdev==1.3.0",
"i3ipc==2.2.1",
"pynput==1.7.1",
"python-xlib==0.27",
"six==1.15.0"
],
entry_points={"console_scripts": ["pi3-smart-workspace=pi3.smart_workspace:main"]},
scripts=["pi3/smart_workspace.py"],
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"],
long_description_content_type='text/x-rst',
author='Asger Geel Weirsøe',
author_email='asger@weirsoe.dk',
description='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.',
classifiers=[
"Development Status :: 2 - Pre-Alpha",
"Development Status :: 3 - Alpha",
"License :: OSI Approved :: Apache Software License",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: 3",