16 Commits

Author SHA1 Message Date
generaldenmark
2f455a6a5e Last release introduced a bug, where if you had a monitor in your config that was not active, it would error out the script and prevent screenchanges 2020-11-13 15:50:12 +01:00
generaldenmark
57fe74e4d1 Removes the random regex, and just tries to match with what monitors are availble. (remember to update your config to match available outputs dummy) 2020-11-13 15:39:31 +01:00
Asger Geel Weirsøe
46b6c1bd56 Fixed bug with how the output is detected, and minor spelling fixes 2020-11-12 14:55:47 +01:00
Asger Geel Weirsøe
230243cfec setup script 2020-09-15 14:48:43 +02:00
Asger Geel Weirsøe
4381c24a82 removes debug print 2020-09-15 14:44:32 +02:00
Asger Geel Weirsøe
57b3328ebe fml 2020-09-15 14:41:00 +02:00
Asger Geel Weirsøe
280436f050 fixes setup version v0.1.4 to new file 2020-09-15 14:37:41 +02:00
Asger Geel Weirsøe
7b7d371332 fixes setup to new file 2020-09-15 14:36:28 +02:00
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
6 changed files with 130 additions and 19 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/*

3
.gitignore vendored
View File

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

View File

@@ -16,6 +16,14 @@ Usage
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.
Installation
------------
@@ -34,7 +42,7 @@ Example config to be inserted into your i3 config.
set $left HDMI-0
set $right HDMI-1
# WOrkspaces
# Workspaces
set $ws1 1:1:Code
set $ws2 2:2:Code
set $ws3 3:3:Code

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

@@ -3,6 +3,18 @@ import sys
import pynput
import re
import argparse
import pprint
import subprocess
def get_active_outputs():
ps = subprocess.Popen(('xrandr', '--listmonitors'), stdout=subprocess.PIPE)
output = subprocess.check_output(('awk', "{print $4}"), stdin=ps.stdout)
ps.wait()
return [x for x in output.decode('UTF-8').split('\n') if x is not None and x != '']
names_for_outputs = r'(' + '|'.join(get_active_outputs()) + ')'
class WorkSpacer:
@@ -19,27 +31,42 @@ class WorkSpacer:
self.current_output_name = None
def _connect(self):
self.print_if_debug('All available outputs on device')
self.print_if_debug(names_for_outputs)
try:
self.i3 = Connection()
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]+) (' +
names_for_outputs + ')', self.config, re.MULTILINE), start=1
):
config_outputs[match.group(1)] = match.group(2)
self.print_if_debug('All outputs listed in the config, matched on available configs')
self.print_if_debug(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)
self.print_if_debug('All config_workspaces_names')
self.print_if_debug(config_workspace_names)
for matchNum, match in enumerate(
re.finditer(r'workspace (\$.*) output (\$.*)', self.config, re.MULTILINE)
):
if not config_outputs.keys().__contains__(match.group(2)):
continue # Not an active display, skip it
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.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:
if self.args.debug:
raise exc
sys.exit(1)
self.workspaces = [workspaces for workspaces in self.i3.get_workspaces()]
outputs = self.i3.get_outputs()
@@ -51,7 +78,8 @@ class WorkSpacer:
self.current_output_name = self._get_workspace_from_courser_position()
if self.args.shift:
self.i3.command(f'move container to workspace {self.workspaces_on_outputs[self.current_output_name][self.args.index - 1]}')
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]}')
@@ -64,41 +92,49 @@ class WorkSpacer:
y_offset = output.__dict__["rect"].__dict__["y"]
if x_offset == 0 and y_offset == 0:
if x_offset <= self.mouse_position[0] <= x_offset + width and y_offset <= self.mouse_position[1] <= y_offset + height:
if x_offset <= self.mouse_position[0] <= x_offset + width and y_offset <= \
self.mouse_position[1] <= y_offset + height:
return output.__dict__["name"]
elif x_offset == 0:
if x_offset <= self.mouse_position[0] <= x_offset + width and y_offset < self.mouse_position[1] <= y_offset + height:
if x_offset <= self.mouse_position[0] <= x_offset + width and y_offset < \
self.mouse_position[1] <= y_offset + height:
return output.__dict__["name"]
elif y_offset == 0:
if x_offset < self.mouse_position[0] <= x_offset + width and y_offset <= self.mouse_position[1] <= y_offset + height:
if x_offset < self.mouse_position[0] <= x_offset + width and y_offset <= \
self.mouse_position[1] <= y_offset + height:
return output.__dict__["name"]
else:
if x_offset < self.mouse_position[0] <= x_offset + width and y_offset < self.mouse_position[1] <= y_offset + height:
if x_offset < self.mouse_position[0] <= x_offset + width and y_offset < \
self.mouse_position[1] <= y_offset + height:
return output.__dict__["name"]
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."
description="Dynamic changes the workspace, based on what output your cursor is on."
)
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.")
help="The indexed workspace for the output where the cursor is currently located")
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")
help="Moves the active window to the index workspace")
shift_group.add_argument('-k', '--keep-with-it', action='store_true',
help='if present, moves with the ')
help='Moves the active window to the index workspace, and moves with it')
# pprint.pprint(parser.parse_args().__dict__)
WorkSpacer(parser.parse_args()).run()
if __name__ == '__main__':
main()

View File

@@ -4,7 +4,7 @@ with open('README.rst', 'r') as fh:
setup(
name='pi3-smart-workspace',
version='0.1.0',
version='0.1.8',
packages=['pi3'],
url='https://github.com/GeneralDenmark/PyOutputHandler',
license='Apache-2.0 License ',
@@ -18,6 +18,7 @@ setup(
entry_points={"console_scripts": ["pi3-smart-workspace=pi3.smart_workspace:main"]},
scripts=["pi3/smart_workspace.py"],
long_description=long_description,
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.',