summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyle Avrett2018-08-30 12:48:58 -0600
committerKyle Avrett2018-08-30 12:48:58 -0600
commitb2ae05039e8343b1218f56f9f620b45b2675ad99 (patch)
treebe3a5a07e4ec41dbce17209b9245e45f674fcd93
parent1565f03f76d48c884f0b1af8459210783fdf8991 (diff)
downloadaur-b2ae05039e8343b1218f56f9f620b45b2675ad99.tar.gz
i3-projects
-rw-r--r--i3-projects241
1 files changed, 241 insertions, 0 deletions
diff --git a/i3-projects b/i3-projects
new file mode 100644
index 000000000000..3e272661e57b
--- /dev/null
+++ b/i3-projects
@@ -0,0 +1,241 @@
+#!/usr/bin/env python3
+
+import subprocess
+from pprint import pprint
+import json
+import time
+import sys
+
+
+"""Project Creation and Management for i3-wm.
+
+Terminology
+ - project :: a collection of workspaces
+ - workspace :: a collection of applications on a single monitor
+ - move :: make an application go somewhere
+ - focus :: change what you are looking at
+"""
+
+
+version = '1.0.0'
+
+
+def _ask_for_project_name() -> str:
+ """Use a popup utility to ask the user for a project name.
+
+ The popup utility is zenity. See https://en.wikipedia.org/wiki/Zenity for more information.
+
+ Returns:
+ A project name.
+
+ """
+ process = subprocess.Popen(['zenity', '--entry', '--title=i3', "--text=Project Name:"],
+ stdout=subprocess.PIPE)
+ out, err = process.communicate()
+ return out.decode('utf-8').replace('\n', '').replace('\r', '')
+
+
+def _get_all_workspaces() -> list:
+ """A helper function to get all workspaces.
+
+ Returns:
+ A list of all workspaces.
+
+ """
+ process = subprocess.Popen(['i3-msg', '-t', 'get_workspaces'], stdout=subprocess.PIPE)
+ out, err = process.communicate()
+ return json.loads(out.decode('utf-8'))
+
+
+def _get_current_project_name() -> str:
+ """A helper function to get the project name of the currently focused workspace.
+
+ Returns:
+ The project name.
+
+ """
+ workspaces = _get_all_workspaces()
+
+ # figure out the project name based on the current workspace
+ current_workspace = next(workspace for workspace in workspaces
+ if workspace['focused'] == True)
+ return current_workspace['name'].split(':')[0]
+
+
+def focus_project(project_name: str) -> None:
+ """Focuses a workspace on all xrandr outputs with the project name & output number.
+ Because of how i3 works, "focus workspace" means "create if not existing".
+
+ Args:
+ project_name: The name of the project
+
+ Returns:
+ None
+
+ """
+ workspaces = _get_all_workspaces()
+
+ # for each xrandr output
+ unique_outputs = {workspace['output'] for workspace in workspaces}
+ for output in unique_outputs:
+ # find an already existing workspace for the output
+ target_workspace = next(workspace for workspace in workspaces
+ if workspace['output'] == output)
+
+ # move to that workspace
+ workspace_name = target_workspace['name']
+ subprocess.call(['i3-msg', 'workspace ', workspace_name])
+
+ # create a new workspace with the project name
+ workspace_num = workspace_name[workspace_name.find(':') + 1:]
+ subprocess.call(['i3-msg', 'workspace ', project_name + ':' + workspace_num])
+
+
+def focus_workspace(workspace_num: str) -> None:
+ """Change the focus to the requested workspace number INSIDE of the project.
+
+ Args:
+ workspace_num: Requested workspace number to move to.
+
+ Returns:
+ None
+
+ """
+ project_name = _get_current_project_name()
+
+ # move to the requested workspace number
+ subprocess.call(['i3-msg', 'workspace ', project_name + ':' + workspace_num])
+
+
+def move_to_workspace(workspace_num: str) -> None:
+ """Move the focused application to the requested workspace number INSIDE of the project.
+
+ Args:
+ workspace_num: Requested workspace number to move to.
+
+ Returns:
+ None
+
+ """
+ project_name = _get_current_project_name()
+
+ # move to the requested workspace number
+ subprocess.call(['i3-msg', 'move container to workspace ', project_name + ':' + workspace_num])
+
+
+def move_to_project(project_name: str, workspace_num) -> None:
+ """Move the focused application to the requested workspace number IN ANOTHER project.
+
+ Args:
+ project_name: The name of the project to move the application to.
+ workspace_num: The workspace number inside of the other project to move to.
+
+ Returns:
+ None
+
+ """
+ subprocess.call(['i3-msg', 'move container to workspace ', project_name + ':' + workspace_num])
+
+
+def show_help() -> None:
+ """Show help text on stdout.
+
+ """
+ help_msg = """\
+i3-projects [command] [args]
+
+Description:
+ This is a command line utility that interacts with i3-msg to make creation and management
+ of projects easier in i3-wm.
+
+Commands:
+ focus_project [project_name]
+ Change the focus on all xrandr outputs to be a workspace in the requested project.
+ If project_name is not given, a gui popup will ask for it.
+
+ focus_workspace [workspace_num]
+ Change the focus to the requested workspace number in the current project.
+
+ move_to_workspace [workspace_num]
+ Move the focused application to the requested workspace number in the current project.
+
+ move_to_project [workspace_num]
+ Move the focused application to the requested workspace number on another project.
+ A gui popup will ask the user for the name of the project.
+
+Example .i3/config:
+ # focus or create a new project on all outputs
+ bindsym $mod+p exec i3-projects focus_project
+
+ # switch to workspace inside of current project
+ bindsym $mod+1 exec i3-projects focus_workspace 1
+ bindsym $mod+2 exec i3-projects focus_workspace 2
+ bindsym $mod+3 exec i3-projects focus_workspace 3
+ bindsym $mod+4 exec i3-projects focus_workspace 4
+ bindsym $mod+5 exec i3-projects focus_workspace 5
+
+ # move container to the current project's workspace
+ bindsym $mod+Shift+1 exec i3-projects move_to_workspace 1
+ bindsym $mod+Shift+2 exec i3-projects move_to_workspace 2
+ bindsym $mod+Shift+3 exec i3-projects move_to_workspace 3
+ bindsym $mod+Shift+4 exec i3-projects move_to_workspace 4
+ bindsym $mod+Shift+5 exec i3-projects move_to_workspace 5
+
+ # move container to another project's workspace
+ bindsym $mod+Ctrl+1 exec i3-projects move_to_project 1
+ bindsym $mod+Ctrl+2 exec i3-projects move_to_project 2
+ bindsym $mod+Ctrl+3 exec i3-projects move_to_project 3
+ bindsym $mod+Ctrl+4 exec i3-projects move_to_project 4
+ bindsym $mod+Ctrl+5 exec i3-projects move_to_project 5
+
+ # startup with a project called misc
+ exec --no-startup-id i3-projects focus_project misc
+
+Version:
+ {}
+
+Author:
+ Kyle Avrett <kyle dot avrett at gmail dot com>""".format(version)
+
+ print(help_msg)
+
+
+def main() -> None:
+ """Provide cli bindings to be used in .i3/config
+
+ Returns:
+ None
+
+ """
+ if len(sys.argv) == 1:
+ show_help()
+ return
+
+ if sys.argv[1] == '--version':
+ print(version)
+
+ if sys.argv[1] == '-h' or \
+ sys.argv[1] == '--help':
+ show_help()
+
+ if sys.argv[1] == 'focus_project':
+ if len(sys.argv) >= 3:
+ project_name = sys.argv[2]
+ else:
+ project_name = _ask_for_project_name()
+ if project_name:
+ focus_project(project_name)
+
+ if sys.argv[1] == 'focus_workspace':
+ focus_workspace(sys.argv[2])
+
+ if sys.argv[1] == 'move_to_workspace':
+ move_to_workspace(sys.argv[2])
+
+ if sys.argv[1] == 'move_to_project':
+ project_name = _ask_for_project_name()
+ move_to_project(project_name, sys.argv[2])
+
+
+if __name__ == '__main__':
+ main()