def main(): args = parse_args() inc = -1 if args.reverse else 1 i3 = Connection() if args.current: focused = i3.get_tree().find_focused() containers = focused.workspace().descendants() for c in containers[:]: if c.name is None: containers.remove(c) index = (containers.index(focused) + inc) % len(containers) containers[index].command('focus') else: all_containers = i3.get_tree().leaves() is_focused = [c.focused for c in all_containers] index = (is_focused.index(True) + inc) % len(all_containers) all_containers[index].command('focus')
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 __init__(self): self.floating_windows = [] self.fader_running = False self.fade_queue = [] self.fade_data = {} self.bottom_win = None self.old_win = None self.active_win = None ipc = Connection() ipc.on(Event.WINDOW_FOCUS, self.on_window_focus) ipc.on(Event.WINDOW_NEW, self.on_window_new) ipc.on(Event.WINDOW_FLOATING, self.on_window_floating) for win in ipc.get_tree(): if win.type == "floating_con": self.floating_windows.append(win.id) if win.focused: change_opacity(win, FLOAT_AC) self.active_win = win else: change_opacity(win, FLOAT_INAC) elif win.type == "con": if win.focused: self.active_win = win change_opacity(win, CON_AC) else: change_opacity(win, CON_INAC) ipc.main()
def main(): parse_options() cnx = Connection() focused = cnx.get_tree().find_focused() wsp = focused.workspace() if not wsp or wsp.name == "__i3_scratch": return switch_col(wsp, focused)
def run(self): # Establish socket connection conn = Connection() # Get window tree and name of focused window tree = conn.get_tree() win_name = tree.find_focused().name self.output = {"full_text": win_name, "color": self.color, "urgent": False}
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")
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()
def get_current_workspace( conn: i3ipc.Connection) -> Tuple[i3ipc.WorkspaceReply, object]: """ Get the focused workspace. Returns ------- A tuple in form (workspace, con), with the focused workspace and the container object for the focused workspace, respectively. """ ws = [w for w in conn.get_workspaces() if w['focused']][0] tree = conn.get_tree() ws_tree = [c for c in tree.descendents() if c.type == 'workspace' and c.name == ws['name']][0] return ws, ws_tree
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))
def on_window_focus(ipc: i3ipc.Connection, e): c: i3ipc.con.Con for c in ipc.get_tree(): # only consider windows if c.type != 'con': continue opaque = c.focused opaque |= 'YouTube' in (c.name or '') opaque |= 'Netflix' in (c.name or '') opaque |= 'Zoom' in (c.name or '') opaque |= 'Jitsi' in (c.name or '') opaque |= 'vlc' == c.window_class if opaque: c.command('opacity 1') else: c.command('opacity 0.9')
def render_apps(i3: i3ipc.Connection, ws: Optional[int]): tree = i3.get_tree() wss = i3.get_workspaces() visible_ws = [ws.name for ws in wss if ws.visible] apps = tree.leaves() apps = [app for app in apps if app.workspace().name in visible_ws] if ws is not None: apps = [ app for app in apps if (int(app.workspace().name) - 1) % 3 == ws ] apps.sort(key=lambda app: app.workspace().name) out = '%{O12}'.join(format_entry(app) for app in apps) print(out, flush=True)
def __init__(self): self.fader_running = False self.fade_queue = [] self.fade_data = {} self.current_win = None self.new_win = None ipc = Connection() ipc.on(Event.WINDOW_FOCUS, self.on_window_focus) ipc.on(Event.WINDOW_NEW, self.on_window_new) ipc.on(Event.WINDOW_FLOATING, self.on_window_floating) for win in ipc.get_tree(): if win.focused: change_opacity(win, AC_TRANS) self.current_win = win else: change_opacity(win, INAC_TRANS) ipc.main()
def get_track_name_from_i3(): """ get title of Spotify window in i3WM """ i3 = Connection() trees = i3.get_tree() # retrieves all open windows in i3 playing_track_name = None for tree in trees: if tree.name == '3:Music': # static value in my own computer """ Above condition is static because I open my Spotify in workspace 3 which has a label `:Music` """ playing_track_name = tree.nodes[0].window_title playing_track_name = playing_track_name.split('-') if len(playing_track_name) > 1: playing_track_name = playing_track_name[1].strip() return playing_track_name else: return playing_track_name[0].strip()
def focus(i3: i3ipc.Connection, dir: Direction): tree = i3.get_tree() active_window = tree.find_focused() x, y = active_window.rect.x, active_window.rect.y width, height = active_window.rect.width, active_window.rect.height if dir == Direction.LEFT: x = x - 1 elif dir == Direction.RIGHT: x = x + width + 1 elif dir == Direction.UP: y = y - 1 elif dir == Direction.DOWN: y = y + height + 1 else: raise ValueError('{} is not a valid direction', dir) correct_window = find_eligible_node_at(x, y, tree) if correct_window is not None: correct_window.command('focus')
def start(self): ipc = Connection() ipc.on(Event.WINDOW_FOCUS, self.on_window_focus) ipc.on(Event.WINDOW_NEW, self.on_window_new) ipc.on(Event.WINDOW_FLOATING, self.on_window_floating) for win in ipc.get_tree(): if win.type == "floating_con": self.floating_windows.append(win.id) if win.focused: change_opacity(win, FLOAT_AC) self.active_win = win else: change_opacity(win, FLOAT_INAC) elif win.type == "con": if win.focused: self.active_win = win change_opacity(win, CON_AC) else: change_opacity(win, CON_INAC) ipc.main()
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
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)
return data if opts['only_child'] and len(con.nodes) == 1: return parse_tree(con.nodes[0]) # implicit container if len(con.nodes) >= 1: children = [parse_tree(i) for i in con.nodes] data = str() if con.focused: data += foc_pre data += layouts[con.layout] if con.focused: data += foc_pst data += '[' data += ' '.join(children) data += ']' return data workspace = i3.get_tree().find_focused().workspace() data = parse_tree(workspace) print(data, flush = True)
#!/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"')
#!/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")
#!/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"')
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")
#!/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"')
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')
# # This effect is similar to dwm's window swallowing patch: https://www.youtube.com/watch?v=92uo5OBOKfY # # To be super minimal, configure i3 to use a 0px font size to hide the tab title bars. With the # unfortunate caveat that this will cause i3 error messages to become unreadable. from i3ipc import Connection import subprocess import sys if len(sys.argv) < 2: print("Usage: %s <command...>" % sys.argv[0]) sys.exit(1) i3 = Connection() orig = i3.get_tree().find_focused() # If the layout was already tabbed or stacked, don't do anything layout = orig.parent.layout if layout == "splith": orig.command("split v") orig.command("layout tabbed") elif layout == "splitv": orig.command("split h") orig.command("layout tabbed") try: # Run the given command code = subprocess.run(sys.argv[1:]).returncode finally:
#!/usr/bin/env python3 from i3ipc import Connection import sys REVERSE = {'right': 'left', 'left': 'right', 'down': 'up', 'up': 'down'} if __name__ == "__main__": direction = sys.argv[1] i3 = Connection() last_focused = i3.get_tree().find_focused() if not last_focused.fullscreen_mode: last_focused.command('focus ' + direction) sys.exit() last_focused.command('fullscreen') last_focused.command('focus ' + direction) cur_focused = i3.get_tree().find_focused() if last_focused.workspace().id == cur_focused.workspace().id: cur_focused.command('fullscreen') else: last_focused.command('focus; fullscreen') sys.exit()
class Fader: ipc = None def __init__(self, active_opacity, inactive_opacity, floating_opacity, fade_time, frame_time): self.active_opacity = active_opacity self.inactive_opacity = inactive_opacity self.floating_opacity = floating_opacity self.fade_time = fade_time self.frame_time = frame_time self.fader_running = False self.fade_queue = [] self.fade_data = {} self.current_win = None self.new_win = None def start(self): if self.ipc is not None: raise Exception('Already started') self.ipc = Connection() self.ipc.on(Event.WINDOW_FOCUS, self.on_window_focus) self.ipc.on(Event.WINDOW_NEW, self.on_window_new) self.ipc.on(Event.WINDOW_FLOATING, self.on_window_floating) for win in self.ipc.get_tree(): if win.focused: change_opacity(win, self.active_opacity) self.current_win = win else: change_opacity(win, self.inactive_opacity) self.ipc.main() def stop(self): if self.ipc is None: raise Exception('Not started') self.ipc.off(self.on_window_focus) self.ipc.off(self.on_window_new) self.ipc.off(self.on_window_floating) for win in self.ipc.get_tree(): change_opacity(win, 1) self.ipc.main_quit() def enqueue_fade(self, win, start, target, duration): if win.id in self.fade_queue: f = self.fade_data[win.id] change = (self.frame_time / duration) * (target - f['opacity']) f['change'] = change f['target'] = target else: change_opacity(win, start) change = (self.frame_time / duration) * (target - start) fade_data = { 'opacity': start, 'change': change, 'target': target, 'win': win } self.fade_queue.append(win.id) self.fade_data[win.id] = fade_data def start_fader(self): if not self.fader_running: self.fader_running = True Thread(target=self.fader).start() def fader(self): while self.fade_queue: for win_id in self.fade_queue.copy(): f = self.fade_data[win_id] f['opacity'] += f['change'] finished = False if f['change'] > 0: if f['opacity'] >= f['target']: finished = True elif f['opacity'] <= f['target']: finished = True if finished: change_opacity(f['win'], f['target']) self.fade_queue.remove(win_id) del self.fade_data[win_id] else: change_opacity(f['win'], f['opacity']) sleep(self.frame_time) self.fader_running = False def on_window_new(self, ipc, event): if event.container.type == 'floating_con': change_opacity(event.container, self.floating_opacity) else: change_opacity(event.container, self.inactive_opacity) self.new_win = event.container.id def on_window_floating(self, ipc, event): if event.container.id == self.current_win.id: self.current_win = event.container def on_window_focus(self, ipc, event): if self.current_win.id == event.container.id: return if self.current_win.type == 'floating_con': trans = self.floating_opacity else: trans = self.inactive_opacity if event.container.id == self.new_win: change_opacity(self.current_win, trans) change_opacity(event.container, self.active_opacity) else: self.enqueue_fade(self.current_win, self.active_opacity, trans, self.fade_time) if event.container.type == 'floating_con': self.enqueue_fade(event.container, self.floating_opacity, self.active_opacity, self.fade_time) else: self.enqueue_fade(event.container, self.inactive_opacity, self.active_opacity, self.fade_time) self.start_fader() self.current_win = event.container self.new_win = None
#!/usr/bin/env python3 from i3ipc import Connection import sys i3 = Connection() tree = i3.get_tree() focused = tree.find_focused() workspace = focused.workspace() if focused.name == workspace.name: sys.exit(0) else: sys.exit(1)
#!/usr/bin/env python3 from i3ipc import Connection # Lil util to flatten 2d list flatten = lambda t: [item for sublist in t for item in sublist] i3 = Connection() visible_workspaces = list(filter(lambda ws: ws.visible, i3.get_workspaces())) focused_workspace = list(filter(lambda ws: ws.focused, visible_workspaces))[0] named_workspace = i3.get_tree().find_named(focused_workspace.name) workspace_index = list(map(lambda ws: ws.name, named_workspace)).index(focused_workspace.name) floating_windows = list( filter(lambda window: window.floating == 'user_on', named_workspace[workspace_index].leaves())) floating_index = list(map(lambda win: win.focused, floating_windows)).index(True) next_win = floating_windows[(floating_index + 1) % len(floating_windows)] next_win.command('focus')
#!/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)
def get_focused_window_name(): connection = Connection() root = connection.get_tree() focus_con = root.find_focused() return focus_con.name, focus_con, root, connection