diff options
author | Kyle Avrett | 2018-08-30 12:48:58 -0600 |
---|---|---|
committer | Kyle Avrett | 2018-08-30 12:48:58 -0600 |
commit | b2ae05039e8343b1218f56f9f620b45b2675ad99 (patch) | |
tree | be3a5a07e4ec41dbce17209b9245e45f674fcd93 | |
parent | 1565f03f76d48c884f0b1af8459210783fdf8991 (diff) | |
download | aur-b2ae05039e8343b1218f56f9f620b45b2675ad99.tar.gz |
i3-projects
-rw-r--r-- | i3-projects | 241 |
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() |