Example #1
0
class LayoutSwitcher:
    def __init__(self):
        config_dir = os.getenv("XDG_CONFIG_HOME") or os.getenv("HOME")
        self.LAYOUT_STATE_FILE = os.path.join(config_dir, "screenlayout.state")
        self.LAYOUTS_DIR = os.path.join(os.getenv("HOME"), ".screenlayout")

        self.loadAvailableLayouts(self.LAYOUTS_DIR)
        self.loadCurrentLayout(self.LAYOUT_STATE_FILE)
        self.i3control = Connection()

    def loadAvailableLayouts(self, layoutsDir):
        self.AVAILABLE_LAYOUTS = [
            getLayoutName(l) for l in os.listdir(layoutsDir)
        ]
        self.AVAILABLE_LAYOUTS.sort()
        print(self.AVAILABLE_LAYOUTS)

        self.NUM_AVAILABLE_LAYOUTS = len(self.AVAILABLE_LAYOUTS)
        if self.NUM_AVAILABLE_LAYOUTS == 0:
            raise Exception("No layouts defined in {}".format(layoutsDir))

    def loadCurrentLayout(self, stateFile):
        self.CURRENT_LAYOUT = self.__readCurrentLayoutOrNull(stateFile)

    def __readCurrentLayoutOrNull(self, stateFile):
        try:
            return open(stateFile, "r").readline()
        except:
            return self.AVAILABLE_LAYOUTS[0]

    def __loadLayout(self, layout):
        layoutFile = os.path.join(self.LAYOUTS_DIR, layout + ".sh")
        print("loading layout {}".format(layout))
        open(self.LAYOUT_STATE_FILE, "w").writelines([layout])
        subprocess.run(layoutFile)
        print(
            subprocess.run([
                "notify-send", "Layout-Switcher",
                "selected layout: {}".format(layout)
            ],
                           capture_output=True))

    def __loadLayoutByIndex(self, index):
        self.__loadLayout(self.AVAILABLE_LAYOUTS[index])

    def __getCurrentLayoutIndexOrNull(self):
        try:
            return self.AVAILABLE_LAYOUTS.index(self.CURRENT_LAYOUT)
        except:
            return 0

    def cycleLayouts(self):
        currentLayoutIndex = self.__getCurrentLayoutIndexOrNull() or 0
        print("current layout idx: {}".format(currentLayoutIndex))

        nextLayoutIndex = (currentLayoutIndex + 1) % self.NUM_AVAILABLE_LAYOUTS
        print("next layout: {}".format(nextLayoutIndex))

        self.__loadLayoutByIndex(nextLayoutIndex)
        self.i3control.command("restart")
Example #2
0
class Checker():
    def __init__(self):
        try:
            self.ctx = Connection().get_tree().find_focused()
        except Exception as e:
            print('Could not connect to i3 ipc')
            exit(e)

    def check(self):
        if args.connect:
            self.set_title(self.get_warn_title())

        if args.disconnect:
            title = '{}@{}: {}'.format(
                getuser(), gethostname(),
                getcwd().replace(path.expanduser("~"), "~"))
            self.set_title(title)

    def set_title(self, title):
        self.ctx.command(f'title_format { title }')

    def get_warn_title(self):
        span_start = f'<span  size="x-large" foreground="{ args.font_color }">'
        warn_text = '   PRODUCTION SERVER:'
        title_text = self.ctx.name.replace('ssh ', '')
        return f'{ span_start }{ warn_text } { title_text } </span>'
Example #3
0
class I3Thread(threading.Thread):
    def __init__(self, queue):
        self.queue = queue
        self.i3 = Connection()
        super().__init__()

    def i3_update(self):
        self.queue.put(self.i3.get_tree().descendants())

    def on_new_window(self, _, event):
        # when bar window becomes visible
        if event.container.name == TITLE:
            # make it floating and sticky
            self.i3.command(
                f"[title=\"{TITLE}\"] floating enable, sticky enable")
            # send the containers structure to it
            self.i3_update()
            # disable this event handler
            self.i3.off(self.on_new_window)

    def run(self):
        # this event is used to set up the bar window
        self.i3.on(Event.WINDOW_NEW, self.on_new_window)

        def update_on(event):
            self.i3.on(event, (lambda _, __: self.i3_update()))

        update_on(Event.WORKSPACE)
        update_on(Event.WINDOW_NEW)
        update_on(Event.WINDOW_CLOSE)
        self.i3.main()

    def switch_to_workspace(self, workspace_index):
        self.i3.command(f"workspace {workspace_index}")
def main():
    name = "1:1:AT_Translated_Set_2_keyboard"
    sway = Connection()
    focused = sway.get_tree().find_focused()
    if (focused.window_class == 'Emacs'):
        system(
            'emacsclient -e "(with-current-buffer (window-buffer) (toggle-input-method))"'
        )
    else:
        sway.command(f"input {name} xkb_switch_layout next")
Example #5
0
def undo_window_renaming(ipc: i3ipc.Connection) -> None:
    """reset workspace names to original name"""

    for workspace in ipc.get_tree().workspaces():
        name_parts = parse_workspace_name(workspace.name)
        name_parts["icons"] = None
        new_name = construct_workspace_name(name_parts)
        ipc.command('rename workspace "%s" to "%s"' %
                    (workspace.name, new_name))
    ipc.main_quit()
    sys.exit(0)
class i3focus:
    def __init__(self):
        self.i3 = Connection() # Create the Connection object that can be used to send commands and subscribe
        self.updateWinState()

    def updateWinState(self):
        self.winstate = self.i3.get_tree().find_focused().workspace().find_focused().workspace().name

    # Define a funtion to switch workspaces when eye position changes
    def on_eye_change(self, ws):
        if ws == 0:
            self.i3.command('focus output left')
        else:
            self.i3.command('focus output right')
        self.updateWinState()
Example #7
0
def rename_workspaces(ipc: i3ipc.Connection, duplicates: bool) -> None:
    """scans for windows in all workspaces as renames the workspaces"""

    for workspace in ipc.get_tree().workspaces():
        name_parts = parse_workspace_name(workspace.name)
        icon_tuple = ()
        for wksp in workspace:
            if wksp.app_id is not None or wksp.window_class is not None:
                icon = icon_for_window(wksp)
                if not duplicates and icon in icon_tuple:
                    continue
                icon_tuple += (icon, )
        name_parts["icons"] = "  ".join(icon_tuple)
        new_name = construct_workspace_name(name_parts)
        ipc.command('rename workspace "%s" to "%s"' %
                    (workspace.name, new_name))
Example #8
0
def swap_workspaces():
    """Swap two workspaces"""
    direction = sys.argv[1] if len(sys.argv) > 1 else False
    if not direction in ['left', 'right']:
        return False

    _i3 = Connection()

    # Get workspace objects
    focused = _i3.get_tree().find_focused().workspace()
    outputs = [output for output in _i3.get_outputs() if output.active]
    workspaces = [o.current_workspace for o in outputs][::-1]

    focused_idx = workspaces.index(focused.name)
    direction_num = {'left': -1, 'right': 1}[direction]
    direction_opp = {'left': 'right', 'right': 'left'}[direction]
    swap_idx = (focused_idx + direction_num) % len(workspaces)

    _i3.command('workspace ' + workspaces[focused_idx])
    _i3.command('move ' + 'workspace to output ' + direction)
    _i3.command('workspace ' + workspaces[swap_idx])
    _i3.command('move ' + 'workspace to output ' + direction_opp)
    return True
Example #9
0
#!/usr/bin/env python

# Script to choose between the current scratchpads using rofi

########### REQUIRED #############
# Rofi (obviously)               #
# sudo pip install i3ipc-python  #
# sudo pip install python-rofi   #
##################################

import sys

from i3ipc import Connection, Event
from rofi import Rofi

i3 = Connection()
r = Rofi()

scratchpads = []
for node in i3.get_tree().scratchpad().floating_nodes:
    scratchpads.append((node.nodes[0].name, node.nodes[0].window))

selected_index, selected_key = r.select("Choose a scratchpad", [x[0] for x in scratchpads])

if selected_index == -1:
    sys.exit(1)

i3.command('[id='"%s"'] scratchpad show' % scratchpads[selected_index][1])
Example #10
0
def i3_setup():
    i3 = Connection()
    i3.command("workspace bar")
    i3.command("split v")
    i3.command("exec google-chrome-stable")
    i3.command("focus name 'gear bar'")
    i3.command("border none")
    i3.command("resize shrink width 30 px or 30 ppt")
Example #11
0
#!/usr/bin/env python3

from i3ipc import Connection

i3 = Connection()

scratch = i3.get_tree().scratchpad().leaves()

# If there is something in the scratchpad
# Lists are true if not empty
if scratch:
    #switch to workspace 42 and making the windows stack
    i3.command("workspace 42")
    i3.command("layout stacking")

    #remove each window from scratchpad and defloat it
    for window in scratch:
        window.command("scratchpad show")
        window.command("floating toggle")
else:
    #make list of used workspaces
    workspaces = i3.get_workspaces()
    wsinuse = []

    for i in workspaces:
        wsinuse.append(i.num)

    #if workspace 42 is already in use, switch to it
    if 42 in wsinuse:
        i3.command("workspace 42")
Example #12
0
# Print the name of the focused window
focused = i3.get_tree().find_focused()
print('Focused window %s is on workspace %s' %
      (focused.name, focused.workspace().name))

# Query the ipc for outputs. The result is a list that represents the parsed
# reply of a command like `i3-msg -t get_outputs`.
outputs = i3.get_outputs()

print('Active outputs:')

for output in filter(lambda o: o.active, outputs):
    print(output.name)

# Send a command to be executed synchronously.
i3.command('focus left')

# Take all fullscreen windows out of fullscreen
for container in i3.get_tree().find_fullscreen():
    container.command('fullscreen')

# Print the names of all the containers in the tree
root = i3.get_tree()
print(root.name)
for con in root:
    print(con.name)


# Define a callback to be called when you switch workspaces.
def on_workspace_focus(self, e):
    # The first parameter is the connection to the ipc and the second is an object
Example #13
0
from i3ipc import Connection

i3 = Connection()

workspace_no = i3.get_tree().find_focused().workspace().num
new_workspace_no = 1 if (workspace_no + 1) > 10 else (workspace_no + 1)

command = f'move container to workspace number {new_workspace_no}'
print(command)
i3.command(command)

command = f'workspace number "{new_workspace_no}"'
print(command)
i3.command(command)
Example #14
0
#!/usr/bin/env python
from i3ipc import Connection

conn = Connection()
terms = conn.get_tree().find_instanced('gnome-terminal-server')
for term in terms:
    if term.parent.scratchpad_state != 'none':
        conn.command('scratchpad show')
        exit(0)

conn.command('exec --no-startup-id "gnome-terminal --window --title terminal-dropdown"')
from i3ipc import Connection, Con

if __name__ == "__main__":

    i3 = Connection()

    def _is_scratchpad(con: Con) -> bool:
        return con.window and con.parent.type != 'dockarea' and con.workspace(
        ).name == '__i3_scratch'

    for con in i3.get_tree():

        if _is_scratchpad(con):
            con.command("fullscreen")
            break

    i3.command("scratchpad show")
Example #16
0
#!/usr/bin/env python

from i3ipc import Connection
import re

conn = Connection()
es = conn.get_tree().find_classed("Evolution")

killed = False
for e in es:
    if re.findall("on", e.floating) and re.findall("(K|C)alend(e|a)r – Evolution", e.window_title):
        e.command('kill')
        killed = True

if not killed:
    conn.command('exec "evolution -c calendar"')
class WorkSpacer:

    def __init__(self, args):
        self.i3 = None
        self.args = args
        self.workspaces_on_outputs = {}
        self.workspaces = None
        self.outputs = None
        self.config = None
        self.mouse = pynput.mouse.Controller()
        self.mouse_position = None
        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-Z0-9]+) (' + 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.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()
        self.outputs = [output for output in outputs if output.__dict__["active"] is True]

    def run(self):
        self._connect()
        self.mouse_position = self.mouse.position
        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]}')
            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:
            width = output.__dict__["rect"].__dict__["width"]
            height = output.__dict__["rect"].__dict__["height"]
            x_offset = output.__dict__["rect"].__dict__["x"]
            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:
                    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:
                    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:
                    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:
                    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)
Example #18
0
def current_focused_workspace(con):
    return con.get_tree().find_focused().workspace().name


def current_workspace(con, outputName):
    output = first(lambda x: x.name == outputName, con.get_outputs())
    if output is None:
        return None
    return output.current_workspace


def swap_workspaces(con, aOutput, bOutput):
    a_ws = current_workspace(con, aOutput)
    b_ws = current_workspace(con, bOutput)

    print("A workspace: %s\nB workspace: %s" % (a_ws, b_ws))
    if a_ws is None or b_ws is None:
        print("either workspace %s or %s was not found" % (a_ws, b_ws))
        return

    i3.command("focus output %s" % aOutput)
    i3.command("move workspace to %s" % bOutput)
    i3.command("focus output %s" % bOutput)
    i3.command("workspace %s" % b_ws)
    i3.command("move workspace to %s" % aOutput)


current_focused = current_focused_workspace(i3)
swap_workspaces(i3, sys.argv[1], sys.argv[2])
i3.command("workspace %s" % current_focused)
Example #19
0
        print("usage: swap_ws.py [ window# ]")
        sys.exit(2)

    return args[1]


def ws_exists(num):
    return i3.get_tree().find_named(num) is not None


if __name__ == "__main__":
    swap_num = check_usage(sys.argv)

    current_ws = i3.get_tree().find_focused()
    # current_ws_num = str(get_current_ws()['num'])
    current_ws_num = str(current_ws.workspace().num)
    print('current_ws_num', current_ws_num)
    print('swap_num', swap_num)
    print('ws_exists(swap_num)', ws_exists(swap_num))

    if (current_ws_num == swap_num):
        print("already on that number")
        sys.exit(2)

    if (ws_exists(swap_num)):
        i3.command(f"rename workspace {swap_num} to {TEMPNAME}")
        i3.command(f"rename workspace {current_ws_num} to {swap_num}")
        i3.command(f"rename workspace {TEMPNAME} to {current_ws_num}")
    else:
        i3.command(f"rename workspace {current_ws_num} to {swap_num}")
Example #20
0
#!/usr/bin/env python3
#
# Promotes the focused window by swapping it with the largest window.

from i3ipc import Connection, Event


def find_biggest_window(container):
    max_leaf = None
    max_area = 0
    for leaf in container.leaves():
        rect = leaf.rect
        area = rect.width * rect.height
        if not leaf.focused and area > max_area:
            max_area = area
            max_leaf = leaf
    return max_leaf


i3 = Connection()

for reply in i3.get_workspaces():
    if reply.focused:
        workspace = i3.get_tree().find_by_id(reply.ipc_data["id"])
        master = find_biggest_window(workspace)
        i3.command("swap container with con_id %s" % master.id)
Example #21
0
#!/usr/bin/env python3

from i3ipc import Connection
import stash

if __name__ == "__main__":

    i3 = Connection()

    workspace = i3.get_tree().find_focused().workspace().name

    if stash.is_minor(workspace):
        i3.command("workspace %s" % stash.major(workspace))
    else:
        minor = stash.minor(workspace)
        i3.command("workspace %s" % minor)
Example #22
0
#!/usr/bin/env python

from i3ipc import Connection
import re

conn = Connection()
htops = conn.get_tree().find_titled("htop-floating")

killed = False
for e in htops:
    print(e.window_title, e.floating)

    if re.findall("on", e.floating) and re.findall("htop-floating",
                                                   e.window_title):
        e.command('kill')
        killed = True

if not killed:
    conn.command(
        'exec "gnome-terminal --window --title htop-floating -- htop"')
#!/usr/bin/python3
from i3ipc import Connection, Event
import sys

i3 = Connection()

workspaces = i3.get_workspaces()
current_ws = [ws for ws in workspaces if ws.focused][0]
ws_on_output = [ws for ws in workspaces if ws.output == current_ws.output]
# print((ws_on_output,current_ws))
if sys.argv[1] == "forward":
    next_num = ws_on_output[(ws_on_output.index(current_ws) + 1) %
                            len(ws_on_output)].num
elif sys.argv[1] == "backward":
    next_num = ws_on_output[ws_on_output.index(current_ws) - 1].num
else:
    print("Error: No valid direction supplied.")
    next_num = current_ws.num

i3.command('workspace number %d' % next_num)
Example #24
0
#!/usr/bin/python
import sys
from i3ipc import Connection, Event

i3 = Connection()

next_num = next(i for i in range(1, 100)
                if not [ws for ws in i3.get_workspaces() if int(ws.name) == i])

i3.command(f'workspace number {next_num};')
Example #25
0
def _try_ipc(conn: i3ipc.Connection, cmd: str):
    try:
        conn.command(cmd)
    except BrokenPipeError:
        pass
Example #26
0
#!/usr/bin/env python3

from sys import argv
from i3ipc import Connection

i3 = Connection()
ws = i3.get_tree().find_focused().workspace().num 
ws = ws % 10 + 1 if argv[1] == 'right' else (ws - 2) % 10 + 1
i3.command("workspace {}".format(ws))
Example #27
0
def reload_i3():
    i3 = Connection()
    ret_val = i3.command("reload")
    logger.debug(f"i3ipc reload command output: {ret_val}.")
Example #28
0
#!/usr/bin/env python3

from i3ipc import Connection
from sys import argv, exit

if len(argv) < 2:
    exit()

i3 = Connection()

focused = i3.get_tree().find_focused()

if focused.type != "workspace":
    windows = focused.workspace().leaves()
    windows[-1].command("focus")
    i3.command("split " + ("horizontal" if len(windows) % 2 else "vertical"))

i3.command("exec " + argv[1])
Example #29
0

def wifi_rfkill():
    """
    get wifi state from rfkill
    """
    output = subprocess.check_output(['rfkill', 'list', 'wifi'])
    r = re.findall("blocked: yes", output.decode('utf-8'))
    if len(r) == 0:
        # wifi not blocked
        return True
    else:
        return False


conn = Connection()
nets = conn.get_tree().find_instanced("gnome-control-center")

killed = False
for e in nets:
    if re.findall("on", e.floating):
        e.command('kill')
        killed = True
if not killed:
    if wifi_nm():
        # show wifi settings
        conn.command('exec "gnome-control-center wifi')
    else:
        # show network settings
        conn.command('exec "gnome-control-center network')
def load_i3_layout(json_url):
  from i3ipc import Connection, Event

  _download(json_url, "/tmp/layout.json")
  i3 = Connection()
  i3.command("workspace 1; append_layout /tmp/layout.json")
Example #31
0
#!/usr/bin/env python2

from i3ipc import Connection
from workspacer import get_current_workspace_num, get_workspace_names
from sys import argv
import subprocess

if __name__ == "__main__":
    con = Connection()
    names = get_workspace_names(con)
    current_num = get_current_workspace_num(con)
    if current_num in names:
        current_name = names[current_num]
    else:
        current_name = current_num
    p = subprocess.Popen(["dmenu", "-p","{}:".format(current_name)], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    p.stdin.close()
    newname = p.stdout.read().strip()
    if newname:
        con.command("rename workspace to {}:{}".format(current_num,newname))
    else:
        con.command("rename workspace to {}".format(current_num))