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}
#!/usr/bin/env python3 from i3ipc import Connection i3 = Connection() tree = i3.get_tree() for conn in tree: if conn.name and "youtube" in conn.name.lower(): conn.command("move scratchpad")
#!/usr/bin/env python3 from i3ipc import Connection from subprocess import call i3 = Connection() def windownotify(i3, event): if event.container.fullscreen_mode == 0: call('polybar-msg cmd show'.split(' ')) else: call('polybar-msg cmd hide'.split(' ')) #print(event.container.fullscreen_mode) i3.on('window', windownotify) i3.main()
#!/usr/bin/env python3 from i3ipc import Connection, Event from subprocess import call import os i3 = Connection() th = 'polybar-msg hook titlehook 1' show = 'polybar-msg cmd show' hide = 'polybar-msg cmd hide' bh = 'polybar-msg hook backupd 1' ws = 'polybar-msg hook wshook 1' ws1 = 'polybar-msg hook wshook1 1' def windownotify(i3, event): # if event.container.fullscreen_mode == 0: # os.system(show) # #call('polybar-msg cmd show'.split(' ')) # else: # os.system(hide) # #call('polybar-msg cmd hide'.split(' ')) if event.change in "focus" "title": os.system(th) #call('polybar-msg hook titlehook 1'.split(' ')) if event.change in "focus" "title": os.system(bh) #call('polybar-msg hook backupd 1'.split(' ')) def wsnotify(i3, event):
def get_ws(): i3 = Connection() ws = i3.get_tree().find_focused().workspace().name return int(ws[0])
#!/usr/bin/python import argparse import sys # too slow? from i3ipc import Connection parser = argparse.ArgumentParser() parser.add_argument('--name', type=str, help='name of the scratchpad', required=True) args = parser.parse_args() i3 = Connection() programs = ['TelegramDesktop', 'Skype'] prog_name = vars(args)['name'] scratchpad_windows = [ leaf.window_class for leaf in i3.get_tree().scratchpad().leaves() ] if __name__ == '__main__': if prog_name not in programs: print('unknown program name') sys.exit(0) if prog_name in scratchpad_windows:
#!/usr/bin/env python3 from i3ipc import Connection, Event import i3ipc.events as events import time, os, subprocess sway = Connection() def show_notification(text, timeout=1000): proc = subprocess.Popen(['notify-send', text, '-t', str(timeout)]) proc.wait(2) def on_ws_init(_, e: events.WorkspaceEvent): print('ws init', e.current.name) # Start VS Code on workspace 2 if e.current.name == '2' and os.system('pgrep code') != 0: show_notification('Launching VS Code...', 2000) sway.command('exec code') # Start Firefox on workspace 3 if e.current.name == '3' and os.system('pgrep firefox') != 0: show_notification('Launching Firefox...', 3000) sway.command('exec firefox') sway.on(Event.WORKSPACE_INIT, on_ws_init) sway.get_workspaces()
#!/usr/bin/env python3 from i3ipc import Connection, ModeEvent def write_to_file(message): with open("/tmp/binding_mode", "w") as file: file.write(message) def on_event_change(i3, data): if data.change == 'default': message = " " else: message = data.change write_to_file(message) write_to_file(' ') i3 = Connection() i3.on('mode', on_event_change) i3.main()
#!/usr/bin/env python3 from i3ipc import Connection from subprocess import call from re import sub i3 = Connection() def thunar(event): print('window is thunar') ins = format(event.container.window_instance) wid = format(event.container.window) # cid = format(event.container.id) ttl = format(event.container.name) newttl = sub(" - File Manager$", "", ttl) event.container.command("title_format %s" % (newttl)) cmd = ["updatefm", "-p", newttl, "-i", ins, "-d", wid] call(cmd) def windownotify(i3, event): print('window notify method') if event.container.window_class == 'ThunarD':
def __init__(self, *, private: bool, geometry: Optional[QByteArray] = None, parent: Optional[QWidget] = None) -> None: """Create a new main window. Args: geometry: The geometry to load, as a bytes-object (or None). private: Whether the window is in private browsing mode. parent: The parent the window should get. """ super().__init__(parent) self.setAttribute(Qt.WA_TranslucentBackground) # Late import to avoid a circular dependency # - browsertab -> hints -> webelem -> mainwindow -> bar -> browsertab from qutebrowser.mainwindow import tabbedbrowser from qutebrowser.mainwindow.statusbar import bar self.setAttribute(Qt.WA_DeleteOnClose) if config.val.window.transparent: self.setAttribute(Qt.WA_TranslucentBackground) self.palette().setColor(QPalette.Window, Qt.transparent) self._overlays: MutableSequence[_OverlayInfoType] = [] self.win_id = next(win_id_gen) self.registry = objreg.ObjectRegistry() objreg.window_registry[self.win_id] = self objreg.register('main-window', self, scope='window', window=self.win_id) tab_registry = objreg.ObjectRegistry() objreg.register('tab-registry', tab_registry, scope='window', window=self.win_id) self.setWindowTitle('qutebrowser') self._vbox = QVBoxLayout(self) self._vbox.setContentsMargins(0, 0, 0, 0) self._vbox.setSpacing(0) self._init_downloadmanager() self._downloadview = downloadview.DownloadView( model=self._download_model) self.is_private = config.val.content.private_browsing or private self.tabbed_browser: tabbedbrowser.TabbedBrowser = tabbedbrowser.TabbedBrowser( win_id=self.win_id, private=self.is_private, parent=self) objreg.register('tabbed-browser', self.tabbed_browser, scope='window', window=self.win_id) self._init_command_dispatcher() # We need to set an explicit parent for StatusBar because it does some # show/hide magic immediately which would mean it'd show up as a # window. self.status = bar.StatusBar(win_id=self.win_id, private=self.is_private, parent=self) self._add_widgets() self._downloadview.show() self._init_completion() log.init.debug("Initializing modes...") modeman.init(win_id=self.win_id, parent=self) self._commandrunner = runners.CommandRunner(self.win_id, partial_match=True) self._keyhint = keyhintwidget.KeyHintView(self.win_id, self) self._add_overlay(self._keyhint, self._keyhint.update_geometry) self._prompt_container = prompt.PromptContainer(self.win_id, self) self._add_overlay(self._prompt_container, self._prompt_container.update_geometry, centered=True, padding=10) objreg.register('prompt-container', self._prompt_container, scope='window', window=self.win_id, command_only=True) self._prompt_container.hide() self._messageview = messageview.MessageView(parent=self) self._add_overlay(self._messageview, self._messageview.update_geometry) self._xkb_switch = xkbswitch.XkbSwitchPlugin(win_id=self.win_id, parent=self) self._init_geometry(geometry) self._connect_signals() # When we're here the statusbar might not even really exist yet, so # resizing will fail. Therefore, we use singleShot QTimers to make sure # we defer this until everything else is initialized. QTimer.singleShot(0, self._connect_overlay_signals) config.instance.changed.connect(self._on_config_changed) objects.qapp.new_window.emit(self) self._set_decoration(config.val.window.hide_decoration) self.state_before_fullscreen = self.windowState() stylesheet.set_register(self) global i3ipc_used if i3ipc_used: try: self.wm_connection = WMConnection() response = self.wm_connection.get_version() self.wm_variant = 'i3' if 'variant' in response.ipc_data and response.ipc_data[ 'variant'] == 'sway': self.wm_variant = 'sway' except: i3ipc_used = False
class MainWindow(QWidget): """The main window of qutebrowser. Adds all needed components to a vbox, initializes sub-widgets and connects signals. Attributes: status: The StatusBar widget. tabbed_browser: The TabbedBrowser widget. state_before_fullscreen: window state before activation of fullscreen. _downloadview: The DownloadView widget. _download_model: The DownloadModel instance. _vbox: The main QVBoxLayout. _commandrunner: The main CommandRunner instance. _overlays: Widgets shown as overlay for the current webpage. _private: Whether the window is in private browsing mode. """ # Application wide stylesheets STYLESHEET = """ HintLabel { background-color: {{ conf.colors.hints.bg }}; color: {{ conf.colors.hints.fg }}; font: {{ conf.fonts.hints }}; border: {{ conf.hints.border }}; border-radius: {{ conf.hints.radius }}px; padding-top: {{ conf.hints.padding['top'] }}px; padding-left: {{ conf.hints.padding['left'] }}px; padding-right: {{ conf.hints.padding['right'] }}px; padding-bottom: {{ conf.hints.padding['bottom'] }}px; } QMenu { {% if conf.fonts.contextmenu %} font: {{ conf.fonts.contextmenu }}; {% endif %} {% if conf.colors.contextmenu.menu.bg %} background-color: {{ conf.colors.contextmenu.menu.bg }}; {% endif %} {% if conf.colors.contextmenu.menu.fg %} color: {{ conf.colors.contextmenu.menu.fg }}; {% endif %} } QMenu::item:selected { {% if conf.colors.contextmenu.selected.bg %} background-color: {{ conf.colors.contextmenu.selected.bg }}; {% endif %} {% if conf.colors.contextmenu.selected.fg %} color: {{ conf.colors.contextmenu.selected.fg }}; {% endif %} } QMenu::item:disabled { {% if conf.colors.contextmenu.disabled.bg %} background-color: {{ conf.colors.contextmenu.disabled.bg }}; {% endif %} {% if conf.colors.contextmenu.disabled.fg %} color: {{ conf.colors.contextmenu.disabled.fg }}; {% endif %} } """ def __init__(self, *, private: bool, geometry: Optional[QByteArray] = None, parent: Optional[QWidget] = None) -> None: """Create a new main window. Args: geometry: The geometry to load, as a bytes-object (or None). private: Whether the window is in private browsing mode. parent: The parent the window should get. """ super().__init__(parent) self.setAttribute(Qt.WA_TranslucentBackground) # Late import to avoid a circular dependency # - browsertab -> hints -> webelem -> mainwindow -> bar -> browsertab from qutebrowser.mainwindow import tabbedbrowser from qutebrowser.mainwindow.statusbar import bar self.setAttribute(Qt.WA_DeleteOnClose) if config.val.window.transparent: self.setAttribute(Qt.WA_TranslucentBackground) self.palette().setColor(QPalette.Window, Qt.transparent) self._overlays: MutableSequence[_OverlayInfoType] = [] self.win_id = next(win_id_gen) self.registry = objreg.ObjectRegistry() objreg.window_registry[self.win_id] = self objreg.register('main-window', self, scope='window', window=self.win_id) tab_registry = objreg.ObjectRegistry() objreg.register('tab-registry', tab_registry, scope='window', window=self.win_id) self.setWindowTitle('qutebrowser') self._vbox = QVBoxLayout(self) self._vbox.setContentsMargins(0, 0, 0, 0) self._vbox.setSpacing(0) self._init_downloadmanager() self._downloadview = downloadview.DownloadView( model=self._download_model) self.is_private = config.val.content.private_browsing or private self.tabbed_browser: tabbedbrowser.TabbedBrowser = tabbedbrowser.TabbedBrowser( win_id=self.win_id, private=self.is_private, parent=self) objreg.register('tabbed-browser', self.tabbed_browser, scope='window', window=self.win_id) self._init_command_dispatcher() # We need to set an explicit parent for StatusBar because it does some # show/hide magic immediately which would mean it'd show up as a # window. self.status = bar.StatusBar(win_id=self.win_id, private=self.is_private, parent=self) self._add_widgets() self._downloadview.show() self._init_completion() log.init.debug("Initializing modes...") modeman.init(win_id=self.win_id, parent=self) self._commandrunner = runners.CommandRunner(self.win_id, partial_match=True) self._keyhint = keyhintwidget.KeyHintView(self.win_id, self) self._add_overlay(self._keyhint, self._keyhint.update_geometry) self._prompt_container = prompt.PromptContainer(self.win_id, self) self._add_overlay(self._prompt_container, self._prompt_container.update_geometry, centered=True, padding=10) objreg.register('prompt-container', self._prompt_container, scope='window', window=self.win_id, command_only=True) self._prompt_container.hide() self._messageview = messageview.MessageView(parent=self) self._add_overlay(self._messageview, self._messageview.update_geometry) self._xkb_switch = xkbswitch.XkbSwitchPlugin(win_id=self.win_id, parent=self) self._init_geometry(geometry) self._connect_signals() # When we're here the statusbar might not even really exist yet, so # resizing will fail. Therefore, we use singleShot QTimers to make sure # we defer this until everything else is initialized. QTimer.singleShot(0, self._connect_overlay_signals) config.instance.changed.connect(self._on_config_changed) objects.qapp.new_window.emit(self) self._set_decoration(config.val.window.hide_decoration) self.state_before_fullscreen = self.windowState() stylesheet.set_register(self) global i3ipc_used if i3ipc_used: try: self.wm_connection = WMConnection() response = self.wm_connection.get_version() self.wm_variant = 'i3' if 'variant' in response.ipc_data and response.ipc_data[ 'variant'] == 'sway': self.wm_variant = 'sway' except: i3ipc_used = False def _init_geometry(self, geometry): """Initialize the window geometry or load it from disk.""" if geometry is not None: self._load_geometry(geometry) elif self.win_id == 0: self._load_state_geometry() else: self._set_default_geometry() log.init.debug("Initial main window geometry: {}".format( self.geometry())) def _add_overlay(self, widget, signal, *, centered=False, padding=0): self._overlays.append((widget, signal, centered, padding)) def _update_overlay_geometries(self): """Update the size/position of all overlays.""" for w, _signal, centered, padding in self._overlays: self._update_overlay_geometry(w, centered, padding) def _update_overlay_geometry(self, widget, centered, padding): """Reposition/resize the given overlay.""" if not widget.isVisible(): return if widget.sizePolicy().horizontalPolicy() == QSizePolicy.Expanding: width = self.width() - 2 * padding if widget.hasHeightForWidth(): height = widget.heightForWidth(width) else: height = widget.sizeHint().height() left = padding else: size_hint = widget.sizeHint() width = min(size_hint.width(), self.width() - 2 * padding) height = size_hint.height() left = (self.width() - width) // 2 if centered else 0 height_padding = 20 status_position = config.val.statusbar.position if status_position == 'bottom': if self.status.isVisible(): status_height = self.status.height() bottom = self.status.geometry().top() else: status_height = 0 bottom = self.height() top = self.height() - status_height - height top = qtutils.check_overflow(top, 'int', fatal=False) topleft = QPoint(left, max(height_padding, top)) bottomright = QPoint(left + width, bottom) elif status_position == 'top': if self.status.isVisible(): status_height = self.status.height() top = self.status.geometry().bottom() else: status_height = 0 top = 0 topleft = QPoint(left, top) bottom = status_height + height bottom = qtutils.check_overflow(bottom, 'int', fatal=False) bottomright = QPoint(left + width, min(self.height() - height_padding, bottom)) else: raise ValueError("Invalid position {}!".format(status_position)) rect = QRect(topleft, bottomright) log.misc.debug('new geometry for {!r}: {}'.format(widget, rect)) if rect.isValid(): widget.setGeometry(rect) def _init_downloadmanager(self): log.init.debug("Initializing downloads...") qtnetwork_download_manager = objreg.get('qtnetwork-download-manager') try: webengine_download_manager = objreg.get( 'webengine-download-manager') except KeyError: webengine_download_manager = None self._download_model = downloads.DownloadModel( qtnetwork_download_manager, webengine_download_manager) objreg.register('download-model', self._download_model, scope='window', window=self.win_id, command_only=True) def _init_completion(self): self._completion = completionwidget.CompletionView(cmd=self.status.cmd, win_id=self.win_id, parent=self) completer_obj = completer.Completer(cmd=self.status.cmd, win_id=self.win_id, parent=self._completion) self._completion.selection_changed.connect( completer_obj.on_selection_changed) objreg.register('completion', self._completion, scope='window', window=self.win_id, command_only=True) self._add_overlay(self._completion, self._completion.update_geometry) def _init_command_dispatcher(self): # Lazy import to avoid circular imports from qutebrowser.browser import commands self._command_dispatcher = commands.CommandDispatcher( self.win_id, self.tabbed_browser) objreg.register('command-dispatcher', self._command_dispatcher, command_only=True, scope='window', window=self.win_id) widget = self.tabbed_browser.widget widget.destroyed.connect( functools.partial(objreg.delete, 'command-dispatcher', scope='window', window=self.win_id)) def __repr__(self): return utils.get_repr(self) @pyqtSlot(str) def _on_config_changed(self, option): """Resize the completion if related config options changed.""" if option == 'statusbar.padding': self._update_overlay_geometries() elif option == 'downloads.position': self._add_widgets() elif option == 'statusbar.position': self._add_widgets() self._update_overlay_geometries() elif option == 'window.hide_decoration': self._set_decoration(config.val.window.hide_decoration) def _add_widgets(self): """Add or readd all widgets to the VBox.""" self._vbox.removeWidget(self.tabbed_browser.widget) self._vbox.removeWidget(self._downloadview) self._vbox.removeWidget(self.status) widgets: List[QWidget] = [self.tabbed_browser.widget] downloads_position = config.val.downloads.position if downloads_position == 'top': widgets.insert(0, self._downloadview) elif downloads_position == 'bottom': widgets.append(self._downloadview) else: raise ValueError("Invalid position {}!".format(downloads_position)) status_position = config.val.statusbar.position if status_position == 'top': widgets.insert(0, self.status) elif status_position == 'bottom': widgets.append(self.status) else: raise ValueError("Invalid position {}!".format(status_position)) for widget in widgets: self._vbox.addWidget(widget) def _load_state_geometry(self): """Load the geometry from the state file.""" try: data = configfiles.state['geometry']['mainwindow'] geom = base64.b64decode(data, validate=True) except KeyError: # First start self._set_default_geometry() except binascii.Error: log.init.exception("Error while reading geometry") self._set_default_geometry() else: self._load_geometry(geom) def _save_geometry(self): """Save the window geometry to the state config.""" data = self.saveGeometry().data() geom = base64.b64encode(data).decode('ASCII') configfiles.state['geometry']['mainwindow'] = geom def _load_geometry(self, geom): """Load geometry from a bytes object. If loading fails, loads default geometry. """ log.init.debug("Loading mainwindow from {!r}".format(geom)) ok = self.restoreGeometry(geom) if not ok: log.init.warning("Error while loading geometry.") self._set_default_geometry() def _connect_overlay_signals(self): """Connect the resize signal and resize everything once.""" for widget, signal, centered, padding in self._overlays: signal.connect( functools.partial(self._update_overlay_geometry, widget, centered, padding)) self._update_overlay_geometry(widget, centered, padding) def _set_default_geometry(self): """Set some sensible default geometry.""" self.setGeometry(QRect(50, 50, 800, 600)) def _connect_signals(self): """Connect all mainwindow signals.""" mode_manager = modeman.instance(self.win_id) # misc self.tabbed_browser.close_window.connect(self.close) mode_manager.entered.connect(hints.on_mode_entered) # status bar mode_manager.hintmanager.set_text.connect(self.status.set_text) mode_manager.entered.connect(self.status.on_mode_entered) mode_manager.left.connect(self.status.on_mode_left) mode_manager.left.connect(self.status.cmd.on_mode_left) mode_manager.left.connect(message.global_bridge.mode_left) # xkbswitch mode_manager.entered.connect(self._xkb_switch.on_mode_entered) mode_manager.left.connect(self._xkb_switch.on_mode_left) # commands mode_manager.keystring_updated.connect( self.status.keystring.on_keystring_updated) self.status.cmd.got_cmd[str].connect(self._commandrunner.run_safely) self.status.cmd.got_cmd[str, int].connect(self._commandrunner.run_safely) self.status.cmd.returnPressed.connect( self.tabbed_browser.on_cmd_return_pressed) self.status.cmd.got_search.connect(self._command_dispatcher.search) # key hint popup mode_manager.keystring_updated.connect(self._keyhint.update_keyhint) # messages message.global_bridge.show_message.connect( self._messageview.show_message) message.global_bridge.flush() message.global_bridge.clear_messages.connect( self._messageview.clear_messages) # statusbar self.tabbed_browser.current_tab_changed.connect( self.status.on_tab_changed) self.tabbed_browser.cur_progress.connect( self.status.prog.on_load_progress) self.tabbed_browser.cur_load_started.connect( self.status.prog.on_load_started) self.tabbed_browser.cur_scroll_perc_changed.connect( self.status.percentage.set_perc) self.tabbed_browser.widget.tab_index_changed.connect( self.status.tabindex.on_tab_index_changed) self.tabbed_browser.cur_url_changed.connect(self.status.url.set_url) self.tabbed_browser.cur_url_changed.connect( functools.partial(self.status.backforward.on_tab_cur_url_changed, tabs=self.tabbed_browser)) self.tabbed_browser.cur_link_hovered.connect( self.status.url.set_hover_url) self.tabbed_browser.cur_load_status_changed.connect( self.status.url.on_load_status_changed) self.tabbed_browser.cur_caret_selection_toggled.connect( self.status.on_caret_selection_toggled) self.tabbed_browser.cur_fullscreen_requested.connect( self._on_fullscreen_requested) self.tabbed_browser.cur_fullscreen_requested.connect( self.status.maybe_hide) # downloadview self.tabbed_browser.cur_fullscreen_requested.connect( self._downloadview.on_fullscreen_requested) # command input / completion mode_manager.entered.connect(self.tabbed_browser.on_mode_entered) mode_manager.left.connect(self.tabbed_browser.on_mode_left) self.status.cmd.clear_completion_selection.connect( self._completion.on_clear_completion_selection) self.status.cmd.hide_completion.connect(self._completion.hide) def _set_decoration(self, hidden): """Set the visibility of the window decoration via Qt.""" window_flags: int = Qt.Window refresh_window = self.isVisible() if hidden: window_flags |= Qt.CustomizeWindowHint | Qt.NoDropShadowWindowHint self.setWindowFlags(cast(Qt.WindowFlags, window_flags)) if refresh_window: self.show() @pyqtSlot(bool) def _on_fullscreen_requested(self, on): if not config.val.content.fullscreen.window: if on: self.state_before_fullscreen = self.windowState() self.setWindowState( Qt.WindowFullScreen | # type: ignore[arg-type] self.state_before_fullscreen) # type: ignore[operator] elif self.isFullScreen(): self.setWindowState(self.state_before_fullscreen) log.misc.debug('on: {}, state before fullscreen: {}'.format( on, debug.qflags_key(Qt, self.state_before_fullscreen))) @cmdutils.register(instance='main-window', scope='window') @pyqtSlot() def close(self): """Close the current window. // Extend close() so we can register it as a command. """ super().close() def resizeEvent(self, e): """Extend resizewindow's resizeEvent to adjust completion. Args: e: The QResizeEvent """ super().resizeEvent(e) self._update_overlay_geometries() self._downloadview.updateGeometry() self.tabbed_browser.widget.tabBar().refresh() def showEvent(self, e): """Extend showEvent to register us as the last-visible-main-window. Args: e: The QShowEvent """ super().showEvent(e) objreg.register('last-visible-main-window', self, update=True) def _confirm_quit(self): """Confirm that this window should be closed. Return: True if closing is okay, False if a closeEvent should be ignored. """ tab_count = self.tabbed_browser.widget.count() download_count = self._download_model.running_downloads() quit_texts = [] # Ask if multiple-tabs are open if 'multiple-tabs' in config.val.confirm_quit and tab_count > 1: quit_texts.append("{} tabs are open.".format(tab_count)) # Ask if multiple downloads running if 'downloads' in config.val.confirm_quit and download_count > 0: quit_texts.append("{} {} running.".format( download_count, "download is" if download_count == 1 else "downloads are")) # Process all quit messages that user must confirm if quit_texts or 'always' in config.val.confirm_quit: msg = jinja.environment.from_string(""" <ul> {% for text in quit_texts %} <li>{{text}}</li> {% endfor %} </ul> """.strip()).render(quit_texts=quit_texts) confirmed = message.ask('Really quit?', msg, mode=usertypes.PromptMode.yesno, default=True) # Stop asking if the user cancels if not confirmed: log.destroy.debug("Cancelling closing of window {}".format( self.win_id)) return False return True def closeEvent(self, e): """Override closeEvent to display a confirmation if needed.""" if crashsignal.crash_handler.is_crashing: e.accept() return if not self._confirm_quit(): e.ignore() return e.accept() for key in ['last-visible-main-window', 'last-focused-main-window']: try: win = objreg.get(key) if self is win: objreg.delete(key) except KeyError: pass sessions.session_manager.save_last_window_session() self._save_geometry() # Wipe private data if we close the last private window, but there are # still other windows if (self.is_private and len(objreg.window_registry) > 1 and len([ window for window in objreg.window_registry.values() if window.is_private ]) == 1): log.destroy.debug("Wiping private data before closing last " "private window") websettings.clear_private_data() log.destroy.debug("Closing window {}".format(self.win_id)) self.tabbed_browser.shutdown()
#!/usr/bin/env python from i3ipc import Connection import re conn = Connection() ps = conn.get_tree().find_classed("Blueberry.py") killed = False for p in ps: if re.findall("on", p.floating): p.command('kill') killed = True if not killed: conn.command('exec blueberry')
def main(args): '''Connect to IPC, set transparencies, and set up listener''' ipc = Connection() for window in ipc.get_tree(): if args.all or window.focused: window.command('opacity ' + args.opacity)
#!/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("move container to workspace %s" % stash.major(workspace)) else: i3.command("move container to workspace %s" % stash.minor(workspace))
#!/usr/bin/env python3 from i3ipc import Connection from subprocess import call # This shows i3 keybind actions with a notification. # It can be useful as an alternative to showkey. i3 = Connection() def notify(i3, event): # print(event.binding.__dict__) bind = event.binding mods_dict = [ ['Mod4', 'Super'], ['shift', 'Shift'], ['ctrl', 'Control'], ['Mod1', 'Alt'], ] mods = '+'.join([ mod[1] for mod in mods_dict if mod[0] in bind.mods ]) if mods: mods += '+' call('notify-send -t 1000 -a i3wm'.split(' ') + [bind.command, '%s%s' % (mods, bind.symbol)] ) i3.on('binding', notify)
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")
bar_pid = bar.start_bar() lemonbar.set_outputs() lemonbar.render_all(caller=caller, e=data) i3.on('workspace::urgent', lemonbar.on_workspace_event) i3.on('workspace::empty', lemonbar.on_workspace_event) if display_title: i3.on('window::title', lemonbar.on_window_title_change) i3.on('window::close', lemonbar.on_window_close) i3.on('window::focus', lemonbar.on_window_title_change) i3.on('workspace::focus', lemonbar.on_workspace_focus) else: i3.on('workspace::focus', lemonbar.on_workspace_event) i3.on('mode', lemonbar.on_binding_mode_change) i3.on('output', reload_bar) i3.on('shutdown', shutdown) i3.main() bar = Bar() parse_opt() i3 = Connection(socket_path=socket) bar.set_config(i3) if not debug: wbak = dup(1) bar_pid = bar.start_bar() else: print(bar.bar_args) run()
) parser.add_argument( '-s', '--shorten', action='store', type=int, default=-1, dest='shorten', help='shorten names to this length, 0 for no limit', ) args = parser.parse_args() opts = args.__dict__ i3 = Connection() layouts = { 'splith': 'H', 'splitv': 'V', 'stacked': 'S', 'tabbed': 'T', } def parse_tree(con): if opts['pango']: foc_pre = '<u>' foc_pst = '</u>' else: foc_pre = '*' foc_pst = '*'
class I3ipc(Ipc): """ i3ipc - an improved python library to control i3wm and sway """ _focused_workspace = None _focused_window = None def setup(self, parent): from threading import Thread self.parent.cache_timeout = self.parent.py3.CACHE_FOREVER self.window_properties = {} t = Thread(target=self.start) t.daemon = True t.start() # noinspection PyTypeChecker def start(self): from i3ipc import Connection, Event self.i3 = Connection() self._update(self.i3.get_tree().find_focused()) self.i3.on(Event.WORKSPACE_FOCUS, self._on_workplace_focus) self.i3.on(Event.WINDOW_CLOSE, self._on_window_close) self.i3.on(Event.WINDOW_TITLE, self._on_window_title) self.i3.on(Event.WINDOW_FOCUS, self._on_window_focus) self.i3.on(Event.BINDING, self._on_binding) self.i3.main() def _on_workplace_focus(self, i3, event): self._focused_workspace = event.current self._focused_window = None if event.current.nodes or event.current.floating_nodes: return self._update(event.current) def _on_window_close(self, i3, event): if event.container.window == self._focused_window: self._focused_window = None self._update(i3.get_tree().find_focused()) def _on_binding(self, i3, event): self._update(i3.get_tree().find_focused()) def _on_window_title(self, i3, event): if event.container.focused: self._update(event.container) def _on_window_focus(self, i3, event): self._focused_window = event.container.window self._update(event.container) def _update(self, event_element): if not event_element: return # hide title on containers with window title if self.parent.hide_title: show_name = True if event_element.border == "normal" or event_element.type == "workspace": show_name = False else: event_element_parent = event_element.parent or getattr( self.i3.get_tree().find_by_id(event_element.id), "parent", None) if (event_element_parent and event_element_parent.layout in ("stacked", "tabbed") and len(event_element_parent.nodes) > 1): show_name = False window_properties = { "title": event_element.name if show_name else None, "class": event_element.window_class, "instance": event_element.window_instance, } else: window_properties = { "title": event_element.name, "class": event_element.window_class, "instance": event_element.window_instance, } window_properties = self.compatibility(window_properties) if self.window_properties != window_properties: self.window_properties = window_properties self.parent.py3.update() def get_window_properties(self): return self.window_properties
def main(args): i3 = Connection() i3.on(Event.WINDOW_NEW, on_window_new) with Listener(on_click=on_click): i3.main()
def __init__(self): self.i3 = Connection() # Create the Connection object that can be used to send commands and subscribe self.updateWinState()
def set_ws(ws): i3 = Connection() i3.command(f'workspace number {ws}')
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()
#!/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)
#!/usr/bin/env python from i3ipc import Connection from notify2 import Notification, init from psutil import Process # This script only works with 'real' local terminals within Sway. # We need to gracefully exit if using ssh, local console or a multiplexer. multiplexers = ("tmux: server", "screen") # determine if we can connect to ipc and get status try: i3 = Connection() # we won't get a status over ssh, via local console or not running i3/Sway except Exception: exit() # verify if running Sway if "sway" not in i3.socket_path: exit() p = Process() # I am sure there is a better way to loop through all the parent processes # names and make sure they aren't a multiplexer for parent in p.parents(): if parent.name() in multiplexers: exit() # get terminal pid terminal_pid = p.parents()[-2].pid
for i in range(len(con.nodes)): if con.nodes[i].id == new_con.id: child = i if not child: return dest = 2 if child == 1 else 1 if con.nodes[dest].layout == 'splith': con.nodes[dest].command('split v') move_con(new_con, dest - child) def new_move_callback(self, e): def get_workspace(cnx, e): return cnx.get_tree().find_by_id(e.container.id).workspace() cnx = Connection() wsp = get_workspace(cnx, e) if not wsp: # This removes problems on i3 start return new_con = wsp.find_by_id(e.container.id) place_node(cnx, wsp, new_con) i3 = Connection() i3.on('window::new', new_move_callback) i3.on('window::move', new_move_callback) i3.main()
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()
#!/usr/bin/python from i3ipc import Connection import sys i3 = Connection() current = i3.get_tree().find_focused() window_rect = current.window_rect workspace = current.workspace() print("workspace width => %d" % workspace.rect.width) print("workspace height => %d" % workspace.rect.height) print("window width => %d" % window_rect.width) print("window height => %d" % window_rect.height) def change_size(direction: str, target_size_str: str): if direction == 'width': current_screen_size = workspace.rect.width current_window_size = window_rect.width else: current_screen_size = workspace.rect.height current_window_size = window_rect.height if '%' in target_size_str: target_size = int(current_screen_size * (float(target_size_str.replace('%', '')) / 100)) else:
#!/usr/bin/env python3 sway = False if sway: from i3ipc import Connection i3 = Connection() ipc_data = None outputs = {} windows_list = [] taskbars_list = [] controls_list = [] config_dir = "" app_dirs = [] key_missing = False dependencies = { "pyalsa": False, "upower": False, "acpi": False, "netifaces": False, } icons_path = "" # "icons_light", "icons_dark" or "" (GTK icons) commands = { "get_battery": "upower -i $(upower -e | grep BAT) | grep --color=never -E 'state|to\\\\ full|to\\\\ empty|percentage'", "get_battery_alt": "acpi",
#!/usr/bin/env python3 from datetime import datetime from i3ipc import Connection from os import system #https://github.com/altdesktop/i3ipc-python i3 = Connection() focused = i3.get_tree().find_focused() name, workspace = focused.name, focused.workspace().name if len(name) > 40: name = name[:48] + '...' system('notify-send -t 1000 "{}" "{}"'.format(workspace, name))
#!/usr/bin/env python3 import os from i3ipc import Connection, Event i3 = Connection() def on_workspace_focus(self, e): if e.current: os.system("dunstify -r 10551 workspace " + e.current.name) i3.on(Event.WORKSPACE_FOCUS, on_workspace_focus) i3.main()
#!/usr/bin/env python3 # budRich@budlabs - 2019 # # this will make all new windows floating # due to the way i3 handles for_window rules # setting a "global rule" to make all new # windows floating, may have undesired side effects. # # https://github.com/i3/i3/issues/3628 # https://github.com/i3/i3/pull/3188 # https://old.reddit.com/r/i3wm/comments/85ctji/when_windows_are_floating_by_default_how_do_i/ from i3ipc import Connection i3 = Connection() def set_floating(i3, event): event.container.command('floating enable') i3.on('window::new', set_floating) i3.main()
def main(): i3 = Connection() handler = I3UnityFix() i3.on(Event.WORKSPACE_FOCUS, handler.on_workspace_focus) i3.main()
from i3ipc import Connection from subprocess import call def window_notify(i3, event): if event.container.fullscreen_mode == 0: call ('polybar-msg cmd show'.split()) else: call ('polybar-msg cmd hide'.split()) if event.change in ["focus", "title"]: call("polybar-msg hook titlehook 1".split(" ")) def window_ws_notify(i3, event): if event.change in ["title", "focus"]: call('polybar-msg hook wshook 1'.split()) def ws_notify(i3, event): if event.change == "focus": if event.old.num != -1: call('polybar-msg hook wshook 1'.split()) if __name__ == "__main__": i3 = Connection() i3.on('window', window_ws_notify) i3.on('workspace', window_ws_notify) i3.main()
#!/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))