Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce78dd2e7c | ||
|
|
2f455a6a5e | ||
|
|
57fe74e4d1 | ||
|
|
46b6c1bd56 | ||
|
|
230243cfec | ||
|
|
4381c24a82 |
166
README.rst
166
README.rst
@@ -10,18 +10,24 @@ Usage
|
||||
|
||||
::
|
||||
|
||||
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.
|
||||
usage: pi3-smart-workspace [-h] [-d] -i INDEX [-s] [-k]
|
||||
|
||||
Changes the workspace, based on what output your cursor is on.
|
||||
|
||||
requred arguments:
|
||||
-i, --index the number index of the workspace that should be openend. 1 = first workspace in config etc.
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-d, --debug Turn on debug mode.
|
||||
|
||||
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..
|
||||
Required:
|
||||
|
||||
So in order to differentiate between these, you need to name your workspaces new names for each output. See example configuration under #Installation.
|
||||
-i INDEX, --index INDEX
|
||||
The indexed workspace for the output where the cursor is currently located
|
||||
|
||||
Shift:
|
||||
manipulate the active window
|
||||
|
||||
-s, --shift Moves the active window to the index workspace
|
||||
-k, --keep-with-it Moves the active window to the index workspace, and moves with it
|
||||
|
||||
|
||||
Installation
|
||||
@@ -37,98 +43,80 @@ Example config to be inserted into your i3 config.
|
||||
|
||||
::
|
||||
|
||||
# Displays
|
||||
set $primary DP-2
|
||||
set $left HDMI-0
|
||||
set $right HDMI-1
|
||||
# Displays
|
||||
set $primary eDP
|
||||
set $top HDMI-A-0
|
||||
set $bottom HDMI2
|
||||
|
||||
# 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
|
||||
# Workspaces
|
||||
set $ws1 1:1
|
||||
... # And so on
|
||||
set $ws{n} {n}:{n}
|
||||
|
||||
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 $TopWs1 {n+1}:1
|
||||
... # and so on
|
||||
set $TopWs{k} {n+1+k}:{k}
|
||||
|
||||
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
|
||||
set $BottomWs1 {k+1}:1
|
||||
... # and so on
|
||||
set $BottomWs{q} {k+1+q}:{q}
|
||||
|
||||
# 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 $ws1 output $primary
|
||||
... # and so on
|
||||
workspace $ws{n} 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 $TopWs1 output $top
|
||||
... # and so on
|
||||
workspace $TopWs{k} output $top
|
||||
|
||||
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
|
||||
workspace $BottomWs1 output $bottom
|
||||
... # and so on
|
||||
workspace $BottomWs{q} output $bottom
|
||||
|
||||
# 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
|
||||
# Shift workspace
|
||||
bindsym $mod+1 exec --no-startup-id pi3-smart-workspace -i 1
|
||||
bindsym $mod+2 exec --no-startup-id pi3-smart-workspace -i 2
|
||||
bindsym $mod+3 exec --no-startup-id pi3-smart-workspace -i 3
|
||||
bindsym $mod+4 exec --no-startup-id pi3-smart-workspace -i 4
|
||||
bindsym $mod+5 exec --no-startup-id pi3-smart-workspace -i 5
|
||||
bindsym $mod+6 exec --no-startup-id pi3-smart-workspace -i 6
|
||||
bindsym $mod+7 exec --no-startup-id pi3-smart-workspace -i 7
|
||||
bindsym $mod+8 exec --no-startup-id 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 focused container to workspace
|
||||
bindsym $mod+Shift+1 exec --no-startup-id pi3-smart-workspace -i 1 -s
|
||||
bindsym $mod+Shift+2 exec --no-startup-id pi3-smart-workspace -i 2 -s
|
||||
bindsym $mod+Shift+3 exec --no-startup-id pi3-smart-workspace -i 3 -s
|
||||
bindsym $mod+Shift+4 exec --no-startup-id pi3-smart-workspace -i 4 -s
|
||||
bindsym $mod+Shift+5 exec --no-startup-id pi3-smart-workspace -i 5 -s
|
||||
bindsym $mod+Shift+6 exec --no-startup-id pi3-smart-workspace -i 6 -s
|
||||
bindsym $mod+Shift+7 exec --no-startup-id pi3-smart-workspace -i 7 -s
|
||||
bindsym $mod+Shift+8 exec --no-startup-id 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
|
||||
# Move to workspace with focused container
|
||||
bindsym $mod+Ctrl+1 exec --no-startup-id pi3-smart-workspace -i 1 -sk
|
||||
bindsym $mod+Ctrl+2 exec --no-startup-id pi3-smart-workspace -i 2 -sk
|
||||
bindsym $mod+Ctrl+3 exec --no-startup-id pi3-smart-workspace -i 3 -sk
|
||||
bindsym $mod+Ctrl+4 exec --no-startup-id pi3-smart-workspace -i 4 -sk
|
||||
bindsym $mod+Ctrl+5 exec --no-startup-id pi3-smart-workspace -i 5 -sk
|
||||
bindsym $mod+Ctrl+6 exec --no-startup-id pi3-smart-workspace -i 6 -sk
|
||||
bindsym $mod+Ctrl+7 exec --no-startup-id pi3-smart-workspace -i 7 -sk
|
||||
bindsym $mod+Ctrl+8 exec --no-startup-id pi3-smart-workspace -i 8 -sk
|
||||
|
||||
|
||||
Future work
|
||||
-----------
|
||||
Here a few ideas on how to improve pi3-smart-workspace could be improved in the future.
|
||||
If anyone wants to submit a pr that solves one of the problems stated below feel free to do so :)
|
||||
|
||||
|
||||
- Save the outputs and the mapped outputs in a json file, instead of looking through the config every time a button is pressed.
|
||||
This would greatly reduce the cost of running this program, if we could just look up the required value in the json instead of the whole i3 config.
|
||||
|
||||
In order for this to be a thing, we need to transition away from looking at active display, have the user set a exec_always and out indexer in their i3 config.
|
||||
|
||||
-
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
|
||||
@@ -4,6 +4,17 @@ 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:
|
||||
@@ -20,32 +31,44 @@ 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|eDP)(-|)\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)
|
||||
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)
|
||||
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:
|
||||
self.print_if_debug(exc)
|
||||
if self.args.debug:
|
||||
raise exc
|
||||
sys.exit(1)
|
||||
self.workspaces = [workspaces for workspaces in self.i3.get_workspaces()]
|
||||
self.workspaces = [workspaces for workspaces in self.i3.get_workspaces()]
|
||||
outputs = self.i3.get_outputs()
|
||||
self.outputs = [output for output in outputs if output.__dict__["active"] is True]
|
||||
|
||||
@@ -55,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]}')
|
||||
@@ -68,16 +92,20 @@ 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):
|
||||
@@ -90,25 +118,23 @@ class WorkSpacer:
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Dynamic changes the workspace, based on what output your cursoer is on."
|
||||
description="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 ')
|
||||
pprint.pprint(parser.parse_args().__dict__)
|
||||
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()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user