By using this site, you agree to have cookies stored on your device, strictly for functional purposes, such as storing your session and preferences.

Dismiss

window-list: Fix multiple panels on multiple outputs

soreau,
created on Sunday, 17 August 2025, 22:03:49 (1755468229), received on Monday, 18 August 2025, 07:14:27 (1755501267)
Author identity: Scott Moreau <oreaus@gmail.com>

1a0bc673cb5c634e4731d4e41215be03d129437b

applets/wf-window-list/__init__.py

@@ -339,7 +339,7 @@ class WFWindowList(panorama_panel.Applet):

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    action_group.add_action(options_action)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.insert_action_group("applet", action_group)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    # Wait for the widget to be in a layer-shell window before doing this
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.connect("realize", lambda *args: self.get_wl_resources())
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.connect("realize", self.get_wl_resources)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.options_window = None
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -378,6 +378,7 @@ class WFWindowList(panorama_panel.Applet):

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                                case "view-workspace-changed":
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                                    view = message.get("view", {})
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                                    if view["output-name"] == self.get_root().monitor_name:
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                    output = self.get_wf_output_by_name(view["output-name"])
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                                        current_workspace = output["workspace"]["x"], output["workspace"]["y"]
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                                        if not self.show_only_this_wf_workspace or (message["to"]["x"], message["to"]["y"]) == current_workspace:
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                                            if self.toplevel_buttons_by_wf_id[view["id"]].get_parent() is None:
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -447,7 +448,7 @@ class WFWindowList(panorama_panel.Applet):

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                            if button.get_parent() is self:
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                                self.remove(button)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            def get_wl_resources(self):
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            def get_wl_resources(self, widget):
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    ctypes.pythonapi.PyCapsule_GetPointer.argtypes = (ctypes.py_object,)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -464,22 +465,31 @@ class WFWindowList(panorama_panel.Applet):

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    # Iterate through monitors and get their Wayland output (wl_output)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    # This is a hack to ensure output_enter/leave is called for toplevels
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                for monitor in self.get_root().get_native().get_display().get_monitors():
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                for monitor in self.get_root().get_application().monitors:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        wl_output = gtk.gdk_wayland_monitor_get_wl_output(ffi.cast("void *", ctypes.pythonapi.PyCapsule_GetPointer(monitor.__gpointer__, None)))
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    if wl_output:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    if wl_output and not monitor.output_proxy:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                            print("Create proxy")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                            output_proxy = WlOutputProxy(wl_output, self.display)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                            output_proxy.interface.registry[output_proxy._ptr] = output_proxy
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        monitor.output_proxy = output_proxy
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        if monitor == my_monitor:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            self.my_output = output_proxy
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    if monitor == my_monitor:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        self.my_output = monitor.output_proxy
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    # End hack
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                fd = self.display.get_fd()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                GLib.io_add_watch(fd, GLib.IO_IN, self.on_display_event)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.manager = None
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.registry = self.display.get_registry()
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.registry.dispatcher["global"] = self.on_global
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.display.roundtrip()
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                if self.manager is None:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    print("Could not load wf-window-list. Is foreign-toplevel protocol advertised by the compositor?")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    print("(Wayfire requires enabling foreign-toplevel plugin)")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    return
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.manager.dispatcher["toplevel"] = self.on_new_toplevel
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.manager.dispatcher["finished"] = lambda *a: print("Toplevel manager finished")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.display.roundtrip()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                fd = self.display.get_fd()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                GLib.io_add_watch(fd, GLib.IO_IN, self.on_display_event)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    if self.wf_socket is not None:
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        self.filter_to_wf_workspace()
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -493,10 +503,6 @@ class WFWindowList(panorama_panel.Applet):

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    if interface == "zwlr_foreign_toplevel_manager_v1":
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        self.print_log("Interface registered")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        self.manager = registry.bind(name, ZwlrForeignToplevelManagerV1, version)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    self.manager.dispatcher["toplevel"] = self.on_new_toplevel
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    self.manager.dispatcher["finished"] = lambda *a: print("Toplevel manager finished")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    self.display.roundtrip()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    self.display.flush()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    elif interface == "wl_seat":
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        self.print_log("Seat found")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        self.seat = registry.bind(name, WlSeat, version)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -508,34 +514,29 @@ class WFWindowList(panorama_panel.Applet):

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                def on_new_toplevel(self, manager: ZwlrForeignToplevelManagerV1,
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                                     handle: ZwlrForeignToplevelHandleV1):
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                handle.dispatcher["title"] = lambda h, title: self.on_title_changed(h, title)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                handle.dispatcher["app_id"] = lambda h, app_id: self.on_app_id_changed(h, app_id)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                handle.dispatcher["title"] = self.on_title_changed
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                handle.dispatcher["app_id"] = self.on_app_id_changed
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    handle.dispatcher["output_enter"] = self.on_output_entered
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    handle.dispatcher["output_leave"] = self.on_output_left
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                handle.dispatcher["state"] = lambda h, states: self.on_state_changed(h, states)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                handle.dispatcher["closed"] = lambda h: self.on_closed(h)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                handle.dispatcher["state"] = self.on_state_changed
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                handle.dispatcher["closed"] = self.on_closed
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                def on_output_entered(self, handle, output):
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                if handle not in self.toplevel_buttons:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    button = WindowButton(handle, handle.title)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    self.set_title(button, handle.title)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    self.set_app_id(button, handle.app_id)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    button.set_group(self.initial_button)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    button.set_layout_manager(WindowButtonLayoutManager(self.window_button_options))
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    button.connect("clicked", self.on_button_click)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    self.toplevel_buttons[handle] = button
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                else:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    button = self.toplevel_buttons[handle]
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                button = WindowButton(handle, handle.title)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                if output == self.my_output:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    self.append(button)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    self.set_all_rectangles()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                if self.show_only_this_output and output != self.my_output:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    return
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.set_title(button, handle.title)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                button.set_group(self.initial_button)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                button.set_layout_manager(WindowButtonLayoutManager(self.window_button_options))
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                button.connect("clicked", self.on_button_click)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.set_app_id(button, handle.app_id)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.toplevel_buttons[handle] = button
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.append(button)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                self.set_all_rectangles()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                def on_output_left(self, handle, output):
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                if not self.show_only_this_output:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    return
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                if output != self.my_output:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    return
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    if handle in self.toplevel_buttons:
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        button = self.toplevel_buttons[handle]
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        self.remove(button)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                            
                                

main.py

@@ -580,6 +580,8 @@ class PanoramaPanel(Gtk.Application):

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    )
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.display = Gdk.Display.get_default()
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.monitors = self.display.get_monitors()
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                for monitor in self.monitors:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    monitor.output_proxy = None
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.applets_by_name: dict[str, panorama_panel.Applet] = {}
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.panels: list[Panel] = []
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    self.manager_window = None