__init__.py
Python script, ASCII text executable
1import os 2from pathlib import Path 3from pywayland.client import Display 4from pywayland.protocol.wayland import WlRegistry 5from pywayland.protocol.wlr_foreign_toplevel_management_unstable_v1 import ( 6ZwlrForeignToplevelManagerV1, 7ZwlrForeignToplevelHandleV1 8) 9import panorama_panel 10 11import gi 12 13gi.require_version("Gtk", "4.0") 14 15from gi.repository import Gtk, GLib, Gio, Gdk 16 17 18module_directory = Path(__file__).resolve().parent 19 20 21class WindowButton(Gtk.ToggleButton): 22def __init__(self, window_id, window_title, **kwargs): 23super().__init__(**kwargs) 24 25self.window_id = window_id 26self.window_title = window_title 27self.set_has_frame(False) 28 29self.set_label(self.window_title) 30 31self.last_state = False 32 33 34class WFWindowList(panorama_panel.Applet): 35name = "Wayfire window list" 36description = "Traditional window list (for Wayfire)" 37 38def __init__(self, orientation=Gtk.Orientation.HORIZONTAL, config=None): 39super().__init__(orientation=orientation, config=config) 40if config is None: 41config = {} 42 43self.toplevel_buttons: dict[ZwlrForeignToplevelHandleV1, WindowButton] = {} 44# This button doesn't belong to any window but is used for the button group and to be 45# selected when no window is focused 46self.initial_button = Gtk.ToggleButton() 47 48self.display = Display() 49self.display.connect() 50self.registry = self.display.get_registry() 51self.registry.dispatcher["global"] = self.on_global 52self.display.roundtrip() 53fd = self.display.get_fd() 54GLib.io_add_watch(fd, GLib.IO_IN, self.on_display_event) 55 56self.context_menu = self.make_context_menu() 57panorama_panel.track_popover(self.context_menu) 58 59right_click_controller = Gtk.GestureClick() 60right_click_controller.set_button(3) 61right_click_controller.connect("pressed", self.show_context_menu) 62 63self.add_controller(right_click_controller) 64 65action_group = Gio.SimpleActionGroup() 66options_action = Gio.SimpleAction.new("options", None) 67options_action.connect("activate", self.show_options) 68action_group.add_action(options_action) 69self.insert_action_group("applet", action_group) 70 71self.options_window = None 72 73def on_display_event(self, source, condition): 74if condition == GLib.IO_IN: 75self.display.dispatch(block=True) 76return True 77 78def on_global(self, registry, name, interface, version): 79print(f"Global: {interface} (v{version})") 80if interface == "zwlr_foreign_toplevel_manager_v1": 81print("Interface registered") 82self.manager = registry.bind(name, ZwlrForeignToplevelManagerV1, version) 83self.manager.dispatcher["toplevel"] = self.on_new_toplevel 84self.manager.dispatcher["finished"] = lambda *a: print("Toplevel manager finished") 85self.display.roundtrip() 86self.display.flush() 87 88def on_new_toplevel(self, manager: ZwlrForeignToplevelManagerV1, 89handle: ZwlrForeignToplevelHandleV1): 90print("Toplevel received") 91handle.dispatcher["title"] = lambda h, title: self.on_title_changed(h, title) 92#handle.dispatcher["app_id"] = lambda h, app_id: self.on_app_id_changed(h, app_id) 93#handle.dispatcher["state"] = lambda h, states: self.on_state_changed(h, states) 94#handle.dispatcher["closed"] = lambda h: self.on_closed(h) 95 96def on_title_changed(self, handle, title): 97print(f"Window title: {title}") 98if handle not in self.toplevel_buttons: 99button = WindowButton(id(handle), title) 100button.set_group(self.initial_button) 101button.connect("clicked", lambda *a: self.on_button_click(handle)) 102self.toplevel_buttons[handle] = button 103self.append(button) 104 105def make_context_menu(self): 106menu = Gio.Menu() 107menu.append("Window list _options", "applet.options") 108context_menu = Gtk.PopoverMenu.new_from_model(menu) 109context_menu.set_has_arrow(False) 110context_menu.set_parent(self) 111context_menu.set_halign(Gtk.Align.START) 112context_menu.set_flags(Gtk.PopoverMenuFlags.NESTED) 113return context_menu 114 115def show_context_menu(self, gesture, n_presses, x, y): 116rect = Gdk.Rectangle() 117rect.x = int(x) 118rect.y = int(y) 119rect.width = 1 120rect.height = 1 121 122self.context_menu.set_pointing_to(rect) 123self.context_menu.popup() 124 125def show_options(self, _0=None, _1=None): 126pass 127 128def get_config(self): 129return {} 130