diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da0928e8..8d34c3de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,18 +14,20 @@ jobs: libdrm-version: "2.4.114" seatd-version: "0.6.4" pixman-version: "0.42.0" + xwayland-version: "22.1.9" hwdata-version: "0.364" wayland-version: "1.22.0" - wayland-protocols-version: "1.31" + wayland-protocols-version: "1.32" strategy: fail-fast: false matrix: - wlroots-version: ["0.16.2", master] + wlroots-version: ["0.17.3", master] steps: - name: Install dependencies run: | sudo apt update sudo apt-get install -y --no-install-recommends \ + libepoxy-dev \ libegl1-mesa-dev \ libgbm-dev \ libgles2-mesa-dev \ @@ -33,6 +35,7 @@ jobs: libpciaccess-dev \ libxcb-composite0-dev \ libxcb-dri3-dev \ + libxcb-ewmh-dev \ libxcb-icccm4-dev \ libxcb-image0-dev \ libxcb-present-dev \ @@ -41,9 +44,12 @@ jobs: libxcb-xfixes0-dev \ libxcb-xinput-dev \ libxcb1-dev \ + libxfont-dev \ libxkbcommon-dev \ - ninja-build \ - xwayland + libxshmfence-dev \ + xfonts-utils \ + xserver-xorg-dev \ + ninja-build sudo pip install meson - name: Set environment variables run: | @@ -55,6 +61,7 @@ jobs: run: | wget $WAYLAND_URL wget $WAYLAND_PROTOCOLS_URL + wget $XWAYLAND_URL wget $LIBDRM_URL wget -O seatd.tar.gz $SEATD_URL wget $PIXMAN_URL @@ -62,6 +69,7 @@ jobs: wget -O wlroots.tar.gz $WLROOTS_URL tar -xJf wayland-${{ env.wayland-version }}.tar.xz tar -xJf wayland-protocols-${{ env.wayland-protocols-version }}.tar.xz + tar -xzf xserver-xwayland-${{ env.xwayland-version }}.tar.gz tar -xzf drm-libdrm-${{ env.libdrm-version }}.tar.gz tar -xzf seatd.tar.gz tar -xjf pixman-pixman-${{ env.pixman-version }}.tar.bz2 @@ -70,6 +78,7 @@ jobs: env: WAYLAND_URL: https://gitlab.freedesktop.org/wayland/wayland/-/releases/${{ env.wayland-version }}/downloads/wayland-${{ env.wayland-version }}.tar.xz WAYLAND_PROTOCOLS_URL: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/releases/${{ env.wayland-protocols-version }}/downloads/wayland-protocols-${{ env.wayland-protocols-version }}.tar.xz + XWAYLAND_URL: https://gitlab.freedesktop.org/xorg/xserver/-/archive/xwayland-${{ env.xwayland-version }}/xserver-xwayland-${{ env.xwayland-version }}.tar.gz LIBDRM_URL: https://gitlab.freedesktop.org/mesa/drm/-/archive/libdrm-${{ env.libdrm-version }}/drm-libdrm-${{ env.libdrm-version }}.tar.gz SEATD_URL: https://git.sr.ht/~kennylevinsen/seatd/archive/${{ env.seatd-version }}.tar.gz PIXMAN_URL: https://gitlab.freedesktop.org/pixman/pixman/-/archive/pixman-${{ env.pixman-version }}/pixman-pixman-${{ env.pixman-version }}.tar.bz2 @@ -116,6 +125,13 @@ jobs: ./configure --prefix=/usr --libdir=/lib --datadir=/usr/share make sudo make install + - name: Build xwayland + working-directory: xserver-xwayland-${{ env.xwayland-version }} + run: | + meson build --prefix=/usr + ninja -C build + DESTDIR=~/wayland ninja -C build install + sudo ninja -C build install - name: Build wlroots working-directory: wlroots-${{ matrix.wlroots-version }} continue-on-error: ${{ matrix.wlroots-version == 'master' }} @@ -147,7 +163,7 @@ jobs: - "pypy-3.8" - "pypy-3.9" - "pypy-3.10" - wlroots-version: ["0.16.2"] + wlroots-version: ["0.17.3"] include: - python-version: "3.12" wlroots-version: master @@ -174,6 +190,7 @@ jobs: libinput-dev \ libpciaccess-dev \ libxcb-composite0-dev \ + libxcb-ewmh-dev \ libxcb-dri3-dev \ libxcb-icccm4-dev \ libxcb-image0-dev \ @@ -262,7 +279,7 @@ jobs: needs: build-wayland env: python-version: "3.12" - wlroots-version: "0.16.2" + wlroots-version: "0.17.3" steps: - name: Download wayland libraries uses: actions/download-artifact@v3 @@ -298,7 +315,7 @@ jobs: needs: build-wayland env: python-version: "3.12" - wlroots-version: "0.16.2" + wlroots-version: "0.17.3" steps: - name: Download wayland libraries uses: actions/download-artifact@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 28ba559a..6d098e49 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,29 +13,40 @@ jobs: libdrm-version: "2.4.114" seatd-version: "0.6.3" pixman-version: "0.42.0" - wayland-protocols-version: "1.31" + xwayland-version: "22.1.9" + xcvt-version: "0.1.2" + inputproto-version: "2021.5" + wayland-protocols-version: "1.32" wayland-version: "1.22.0" - wlroots-version: "0.16.2" + wlroots-version: "0.17.3" steps: - name: Install dependencies run: | yum -y install \ hwdata \ python3-pip \ + libepoxy-devel \ libffi-devel \ libinput-devel \ libpciaccess-devel \ + libtirpc-devel \ libudev-devel \ + libXdmcp-devel \ + libXfont2-devel \ libxkbcommon-x11-devel \ + libxkbfile-devel \ libxml2-devel \ + libxshmfence-devel \ mesa-libEGL-devel \ mesa-libgbm-devel \ + openssl-devel \ xcb-util-devel \ xcb-util-image-devel \ xcb-util-keysyms-devel \ xcb-util-renderutil-devel \ xcb-util-wm-devel \ - xorg-x11-server-Xwayland \ + xorg-x11-font-utils \ + xorg-x11-xtrans-devel \ ninja-build \ wget - name: Set environment variables @@ -48,12 +59,18 @@ jobs: run: | wget $WAYLAND_URL wget $WAYLAND_PROTOCOLS_URL + wget $XCVT_URL + wget $INPUTPROTO_URL + wget $XWAYLAND_URL wget $LIBDRM_URL wget -O seatd.tar.gz $SEATD_URL wget $PIXMAN_URL wget -O wlroots.tar.gz $WLROOTS_URL tar -xJf wayland-${{ env.wayland-version }}.tar.xz tar -xJf wayland-protocols-${{ env.wayland-protocols-version }}.tar.xz + tar -xzf xorgproto-xorgproto-${{ env.inputproto-version }}.tar.gz + tar -xzf libxcvt-libxcvt-${{ env.xcvt-version }}.tar.gz + tar -xzf xserver-xwayland-${{ env.xwayland-version }}.tar.gz tar -xzf drm-libdrm-${{ env.libdrm-version }}.tar.gz tar -xjf pixman-pixman-${{ env.pixman-version }}.tar.bz2 tar -xzf seatd.tar.gz @@ -61,6 +78,9 @@ jobs: env: WAYLAND_URL: https://gitlab.freedesktop.org/wayland/wayland/-/releases/${{ env.wayland-version }}/downloads/wayland-${{ env.wayland-version }}.tar.xz WAYLAND_PROTOCOLS_URL: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/releases/${{ env.wayland-protocols-version }}/downloads/wayland-protocols-${{ env.wayland-protocols-version }}.tar.xz + XWAYLAND_URL: https://gitlab.freedesktop.org/xorg/xserver/-/archive/xwayland-${{ env.xwayland-version }}/xserver-xwayland-${{ env.xwayland-version }}.tar.gz + XCVT_URL: https://gitlab.freedesktop.org/xorg/lib/libxcvt/-/archive/libxcvt-${{ env.xcvt-version }}/libxcvt-libxcvt-${{ env.xcvt-version }}.tar.gz + INPUTPROTO_URL: https://gitlab.freedesktop.org/xorg/proto/xorgproto/-/archive/xorgproto-${{ env.inputproto-version}}/xorgproto-xorgproto-${{ env.inputproto-version}}.tar.gz LIBDRM_URL: https://gitlab.freedesktop.org/mesa/drm/-/archive/libdrm-${{ env.libdrm-version }}/drm-libdrm-${{ env.libdrm-version }}.tar.gz SEATD_URL: https://git.sr.ht/~kennylevinsen/seatd/archive/${{ env.seatd-version }}.tar.gz PIXMAN_URL: https://gitlab.freedesktop.org/pixman/pixman/-/archive/pixman-${{ env.pixman-version }}/pixman-pixman-${{ env.pixman-version }}.tar.bz2 @@ -103,6 +123,27 @@ jobs: ninja -C build DESTDIR=~/wayland ninja -C build install ninja -C build install + - name: Build inputproto + working-directory: xorgproto-xorgproto-${{ env.inputproto-version }} + run: | + meson build --prefix=/usr + ninja -C build + DESTDIR=~/wayland ninja -C build install + ninja -C build install + - name: Build libxcvt + working-directory: libxcvt-libxcvt-${{ env.xcvt-version }} + run: | + meson build --prefix=/usr + ninja -C build + DESTDIR=~/wayland ninja -C build install + ninja -C build install + - name: Build xwayland + working-directory: xserver-xwayland-${{ env.xwayland-version }} + run: | + meson build --prefix=/usr + ninja -C build + DESTDIR=~/wayland ninja -C build install + ninja -C build install - name: Build wlroots working-directory: wlroots-${{ env.wlroots-version }} run: | diff --git a/CHANGES.rst b/CHANGES.rst index 9efda852..34598e6f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,9 @@ +0.17.0 -- 2024-mm-dd +------ +* Support for wlroots 0.17.x +* **Breaking change** Rename all declarations of XdgTopLevel.* to XdgToplevel.* + + 0.16.9 -- 2024-05-12 -------------------- * Fixed ``Seat.touch_point_clear_focus``: The method took too many arguments diff --git a/check_headers.py b/check_headers.py index f98d7ff5..94470e53 100644 --- a/check_headers.py +++ b/check_headers.py @@ -13,7 +13,6 @@ "unstable/pointer-constraints/pointer-constraints-unstable-v1.xml", ] WLROOTS_PROTOCOLS = [ - "protocol/idle.xml", "protocol/wlr-output-power-management-unstable-v1.xml", "protocol/wlr-layer-shell-unstable-v1.xml", ] diff --git a/tiny/__main__.py b/tiny/__main__.py index 704253e5..a998b9b4 100644 --- a/tiny/__main__.py +++ b/tiny/__main__.py @@ -35,11 +35,11 @@ def main(argv) -> None: xdg_shell = XdgShell(display) with OutputLayout() as output_layout, Cursor( output_layout - ) as cursor, XCursorManager(24) as xcursor_manager, Seat( + ) as cursor, XCursorManager(None, 24) as xcursor_manager, Seat( display, "seat0" ) as seat: scene = Scene() - scene.attach_output_layout(output_layout) + scene_layout = scene.attach_output_layout(output_layout) tinywl_server = TinywlServer( # noqa: F841 display=display, backend=backend, @@ -51,6 +51,7 @@ def main(argv) -> None: cursor_manager=xcursor_manager, seat=seat, output_layout=output_layout, + scene_layout=scene_layout, ) socket = display.add_socket() diff --git a/tiny/server.py b/tiny/server.py index 3c8eb70c..4025da5c 100644 --- a/tiny/server.py +++ b/tiny/server.py @@ -26,6 +26,8 @@ Scene, SceneBuffer, SceneNodeType, + SceneOutput, + SceneOutputLayout, SceneSurface, SceneTree, Seat, @@ -52,6 +54,7 @@ if TYPE_CHECKING: from wlroots.wlr_types import InputDevice from wlroots.wlr_types.keyboard import KeyboardKeyEvent, KeyboardModifiers + from wlroots.wlr_types.output import OutputEventRequestState _weakkeydict: WeakKeyDictionary = WeakKeyDictionary() @@ -81,6 +84,7 @@ def __init__( cursor_manager: XCursorManager, seat: Seat, output_layout: OutputLayout, + scene_layout: SceneOutputLayout | None, ) -> None: # elements that we need to hold on to self._display = display @@ -116,6 +120,7 @@ def __init__( self.resize_edges: Edges = Edges.NONE self._output_layout = output_layout + self._scene_layout = scene_layout self.outputs: list[Output] = [] xdg_shell.new_surface_event.add(Listener(self.server_new_xdg_surface)) @@ -214,7 +219,7 @@ def process_cursor_motion(self, time) -> None: logging.debug("Processing cursor motion: %s, %s", sx, sy) if view is None: - self._cursor_manager.set_cursor_image("left_ptr", self._cursor) + self._cursor.set_xcursor(self._cursor_manager, "default") if surface is None: # Clear pointer focus so future button events and such are not sent @@ -229,7 +234,7 @@ def send_modifiers( self, modifiers: KeyboardModifiers, input_device: InputDevice ) -> None: keyboard = Keyboard.from_input_device(input_device) - self._seat.keyboard = keyboard + self._seat.set_keyboard(keyboard) self._seat.keyboard_notify_modifiers(modifiers) def send_key(self, key_event: KeyboardKeyEvent, input_device: InputDevice) -> None: @@ -255,7 +260,7 @@ def send_key(self, key_event: KeyboardKeyEvent, input_device: InputDevice) -> No # Otherwise, we pass it along to the client if not handled: - self._seat.keyboard = keyboard + self._seat.set_keyboard(keyboard) self._seat.keyboard_notify_key(key_event) def handle_keybinding(self, keysym: int) -> bool: @@ -290,8 +295,8 @@ def focus_view(self, view: View, surface: Surface | None = None) -> None: if previous_surface is not None: # Deactivate the previously focused surface logging.info("Un-focusing previous") - previous_xdg_surface = XdgSurface.from_surface(previous_surface) - previous_xdg_surface.set_activated(False) + if previous_xdg_surface := XdgSurface.try_from_surface(previous_surface): + previous_xdg_surface.set_activated(False) view.scene_node.raise_to_top() # roll the given surface to the front of the list, copy and modify the @@ -307,7 +312,7 @@ def focus_view(self, view: View, surface: Surface | None = None) -> None: # Tell the seat to have the keyboard enter this surface. wlroots will # keep track of this and automatically send key events to the # appropriate clients without additional work on your part. - keyboard = self._seat.keyboard + keyboard = self._seat.get_keyboard() if keyboard: self._seat.keyboard_notify_enter(view.xdg_surface.surface, keyboard) @@ -323,10 +328,12 @@ def server_new_xdg_surface(self, listener, xdg_surface: XdgSurface) -> None: # we must provide the proper parent scene node of the xdg popup. To # enable this, we always set the user data field of xdg_surfaces to # the corresponding scene node. - parent_xdg_surface = XdgSurface.from_surface(xdg_surface.popup.parent) - parent_scene_tree = cast(SceneTree, parent_xdg_surface.data) - scene_tree = Scene.xdg_surface_create(parent_scene_tree, xdg_surface) - xdg_surface.data = scene_tree + if parent_xdg_surface := XdgSurface.try_from_surface( + xdg_surface.popup.parent + ): + parent_scene_tree = cast(SceneTree, parent_xdg_surface.data) + scene_tree = Scene.xdg_surface_create(parent_scene_tree, xdg_surface) + xdg_surface.data = scene_tree return assert xdg_surface.role == XdgSurfaceRole.TOPLEVEL @@ -348,15 +355,25 @@ def server_new_output(self, listener, output: Output) -> None: output.init_render(self._allocator, self._renderer) state = OutputState() - state.enabled = True - state.mode = output.preferred_mode() + state.set_enabled(True) + if mode := output.preferred_mode(): + state.set_mode(mode) output.commit(state) + state.finish() self.outputs.append(output) - self._output_layout.add_auto(output) + l_output = self._output_layout.add_auto(output) + if not l_output: + logging.warning("Failed to add output to layout.") + return output.frame_event.add(Listener(self.output_frame)) + output.request_state_event.add(Listener(self.output_request_state)) + + scene_output = SceneOutput.create(self._scene, output) + if self._scene_layout: + self._scene_layout.add_output(l_output, scene_output) def output_frame(self, listener, data) -> None: output = self.outputs[0] @@ -366,6 +383,10 @@ def output_frame(self, listener, data) -> None: now = Timespec.get_monotonic_time() scene_output.send_frame_done(now) + def output_request_state(self, listener, request: OutputEventRequestState) -> None: + output = self.outputs[0] + output.commit(request.state) + # ############################################################# # input handling callbacks @@ -399,7 +420,7 @@ def _server_new_keyboard(self, input_device: InputDevice) -> None: keyboard_handler = KeyboardHandler(keyboard, input_device, self) self.keyboards.append(keyboard_handler) - self._seat.keyboard = keyboard + self._seat.set_keyboard(keyboard) # ############################################################# # cursor motion callbacks diff --git a/tiny/view.py b/tiny/view.py index 82266b3d..7089e523 100644 --- a/tiny/view.py +++ b/tiny/view.py @@ -31,8 +31,8 @@ def __init__( self.x = 0.0 self.y = 0.0 - xdg_surface.map_event.add(Listener(self.xdg_toplevel_map)) - xdg_surface.unmap_event.add(Listener(self.xdg_toplevel_unmap)) + xdg_surface.surface.map_event.add(Listener(self.xdg_toplevel_map)) + xdg_surface.surface.unmap_event.add(Listener(self.xdg_toplevel_unmap)) xdg_surface.destroy_event.add(Listener(self.xdg_toplevel_destroy)) toplevel = xdg_surface.toplevel diff --git a/wlroots/backend.py b/wlroots/backend.py index d54d41ff..34f79944 100644 --- a/wlroots/backend.py +++ b/wlroots/backend.py @@ -32,8 +32,12 @@ def __init__(self, display: Display, *, backend_type=BackendType.AUTO) -> None: backends), $WAYLAND_DISPLAY (for Wayland backends), and $WLR_BACKENDS (to set the available backends). """ + self.session: Session | None = None + if backend_type == BackendType.AUTO: - ptr = lib.wlr_backend_autocreate(display._ptr) + session_ptr = ffi.new("struct wlr_session **") + ptr = lib.wlr_backend_autocreate(display._ptr, session_ptr) + self.session = Session(session_ptr[0]) elif backend_type == BackendType.HEADLESS: ptr = lib.wlr_headless_backend_create(display._ptr) else: @@ -92,7 +96,9 @@ def __exit__(self, exc_type, exc_value, exc_tb) -> None: self.destroy() def get_session(self) -> Session: - return Session(self) + if self.session is None: + raise ValueError("Backend does not have a session") + return self.session @property def is_headless(self) -> bool: @@ -110,9 +116,9 @@ def is_multi(self) -> bool: class Session: - def __init__(self, backend: Backend) -> None: + def __init__(self, ptr) -> None: """The running session""" - self._ptr = lib.wlr_backend_get_session(backend._ptr) + self._ptr = ptr def change_vt(self, vt: int) -> bool: return lib.wlr_session_change_vt(self._ptr, vt) diff --git a/wlroots/ffi_build.py b/wlroots/ffi_build.py index b2e6f0cc..8a0a0747 100644 --- a/wlroots/ffi_build.py +++ b/wlroots/ffi_build.py @@ -114,11 +114,11 @@ def has_xwayland() -> bool: ...; }; -struct wlr_backend *wlr_backend_autocreate(struct wl_display *display); +struct wlr_backend *wlr_backend_autocreate(struct wl_display *display, + struct wlr_session **session_ptr); bool wlr_backend_start(struct wlr_backend *backend); void wlr_backend_destroy(struct wlr_backend *backend); -struct wlr_session *wlr_backend_get_session(struct wlr_backend *backend); """ # wlr/backend/libinput.h @@ -154,7 +154,7 @@ def has_xwayland() -> bool: CDEF += """ struct wlr_renderer *wlr_renderer_autocreate(struct wlr_backend *backend); -void wlr_renderer_begin(struct wlr_renderer *r, int width, int height); +bool wlr_renderer_begin(struct wlr_renderer *r, int width, int height); void wlr_renderer_end(struct wlr_renderer *r); void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]); @@ -311,6 +311,8 @@ def has_xwayland() -> bool: struct wlr_output *output); void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, struct wlr_input_device *dev, struct wlr_output *output); +void wlr_cursor_set_xcursor(struct wlr_cursor *cur, + struct wlr_xcursor_manager *manager, const char *name); """ # types/wlr_compositor.h @@ -329,7 +331,7 @@ def has_xwayland() -> bool: }; struct wlr_compositor *wlr_compositor_create(struct wl_display *display, - struct wlr_renderer *renderer); + uint32_t version, struct wlr_renderer *renderer); struct wlr_surface_state { uint32_t committed; @@ -353,9 +355,9 @@ def has_xwayland() -> bool: struct wlr_surface_role { const char *name; + bool no_object; void (*commit)(struct wlr_surface *surface); - void (*precommit)(struct wlr_surface *surface, - const struct wlr_surface_state *state); + void (*unmap)(struct wlr_surface *surface); void (*destroy)(struct wlr_surface *surface); ...; }; @@ -373,7 +375,6 @@ def has_xwayland() -> bool: struct wl_resource *resource; struct wlr_renderer *renderer; struct wlr_client_buffer *buffer; - int sx, sy; struct pixman_region32 buffer_damage; struct pixman_region32 external_damage; struct pixman_region32 opaque_region; @@ -381,13 +382,17 @@ def has_xwayland() -> bool: struct wlr_surface_state current, pending; struct wl_list cached; + bool mapped; const struct wlr_surface_role *role; - void *role_data; + struct wl_resource *role_resource; struct { struct wl_signal client_commit; + struct wl_signal precommit; struct wl_signal commit; + struct wl_signal map; + struct wl_signal unmap; struct wl_signal new_subsurface; struct wl_signal destroy; } events; @@ -395,19 +400,15 @@ def has_xwayland() -> bool: struct wl_list current_outputs; struct wlr_addon_set addons; void *data; - struct wl_listener renderer_destroy; ...; }; typedef void (*wlr_surface_iterator_func_t)(struct wlr_surface *surface, int sx, int sy, void *data); -bool wlr_surface_set_role(struct wlr_surface *surface, - const struct wlr_surface_role *role, void *role_data, +bool wlr_surface_set_role(struct wlr_surface *surface, const struct wlr_surface_role *role, struct wl_resource *error_resource, uint32_t error_code); -void wlr_surface_destroy_role_object(struct wlr_surface *surface); - bool wlr_surface_has_buffer(struct wlr_surface *surface); struct wlr_texture *wlr_surface_get_texture(struct wlr_surface *surface); @@ -468,7 +469,6 @@ def has_xwayland() -> bool: bool synchronized; bool reordered; - bool mapped; bool added; struct wl_listener surface_client_commit; @@ -476,8 +476,6 @@ def has_xwayland() -> bool: struct { struct wl_signal destroy; - struct wl_signal map; - struct wl_signal unmap; } events; void *data; @@ -489,11 +487,6 @@ def has_xwayland() -> bool: ...; }; -bool wlr_surface_is_subsurface(struct wlr_surface *surface); - -struct wlr_subsurface *wlr_subsurface_from_wlr_surface( - struct wlr_surface *surface); - struct wlr_subcompositor *wlr_subcompositor_create(struct wl_display *display); """ @@ -538,12 +531,10 @@ def has_xwayland() -> bool: struct wlr_drag_icon { struct wlr_drag *drag; struct wlr_surface *surface; - bool mapped; struct { - struct wl_signal map; - struct wl_signal unmap; struct wl_signal destroy; } events; + struct wl_listener surface_destroy; void *data; ...; }; @@ -744,90 +735,44 @@ def has_xwayland() -> bool: struct wlr_foreign_toplevel_handle_v1 *parent); """ -# types/wlr_gamma_control_v1.h +# types/wlr_fractional_scale_v1.h CDEF += """ -struct wlr_gamma_control_manager_v1 { - struct wl_global *global; - struct wl_list controls; // wlr_gamma_control_v1::link +struct wlr_fractional_scale_manager_v1 { + struct wl_global *global; - struct wl_listener display_destroy; + struct { + struct wl_signal destroy; + } events; - struct { - struct wl_signal destroy; - } events; - - void *data; - ...; + ...; }; -struct wlr_gamma_control_manager_v1 *wlr_gamma_control_manager_v1_create( - struct wl_display *display); + + +void wlr_fractional_scale_v1_notify_scale( + struct wlr_surface *surface, double scale); + +struct wlr_fractional_scale_manager_v1 *wlr_fractional_scale_manager_v1_create( + struct wl_display *display, uint32_t version); """ -# types/wlr_idle.h +# types/wlr_gamma_control_v1.h CDEF += """ -struct wlr_idle { +struct wlr_gamma_control_manager_v1 { struct wl_global *global; - struct wl_list idle_timers; // wlr_idle_timeout::link - struct wl_event_loop *event_loop; - bool enabled; + struct wl_list controls; // wlr_gamma_control_v1::link struct wl_listener display_destroy; - struct { - struct wl_signal activity_notify; - struct wl_signal destroy; - } events; - - void *data; - ...; -}; - -struct wlr_idle_timeout { - struct wl_resource *resource; - struct wl_list link; - struct wlr_seat *seat; - - struct wl_event_source *idle_source; - bool idle_state; - bool enabled; - uint32_t timeout; // milliseconds struct { - struct wl_signal idle; - struct wl_signal resume; struct wl_signal destroy; + struct wl_signal set_gamma; } events; - struct wl_listener input_listener; - struct wl_listener seat_destroy; - void *data; ...; }; - -struct wlr_idle *wlr_idle_create(struct wl_display *display); - -/** - * Send notification to restart all timers for the given seat. Called by - * compositor when there is an user activity event on that seat. - */ -void wlr_idle_notify_activity(struct wlr_idle *idle, struct wlr_seat *seat); - -/** - * Enable or disable timers for a given idle resource by seat. - * Passing a NULL seat means update timers for all seats. - */ -void wlr_idle_set_enabled(struct wlr_idle *idle, struct wlr_seat *seat, - bool enabled); - -/** - * Create a new timer on the given seat. The idle event will be called after - * the given amount of milliseconds of inactivity, and the resumed event will - * be sent at the first user activity after the fired event. - */ -struct wlr_idle_timeout *wlr_idle_timeout_create(struct wlr_idle *idle, - struct wlr_seat *seat, uint32_t timeout); - -void wlr_idle_timeout_destroy(struct wlr_idle_timeout *timeout); +struct wlr_gamma_control_manager_v1 *wlr_gamma_control_manager_v1_create( + struct wl_display *display); """ # types/wlr_input_inhibit_v1.h @@ -974,11 +919,13 @@ def has_xwayland() -> bool: char *keymap_string; size_t keymap_size; + int keymap_fd; struct xkb_keymap *keymap; struct xkb_state *xkb_state; xkb_led_index_t led_indexes[WLR_LED_COUNT]; xkb_mod_index_t mod_indexes[WLR_MODIFIER_COUNT]; + uint32_t leds; uint32_t keycodes[WLR_KEYBOARD_KEYS_CAP]; size_t num_keycodes; struct wlr_keyboard_modifiers modifiers; @@ -1026,7 +973,7 @@ def has_xwayland() -> bool: # types/wlr_linux_dmabuf_v1.h CDEF += """ struct wlr_linux_dmabuf_v1 *wlr_linux_dmabuf_v1_create(struct wl_display *display, - struct wlr_renderer *renderer); + uint32_t version, const struct wlr_linux_dmabuf_feedback_v1 *default_feedback); """ # types/wlr_matrix.h @@ -1124,13 +1071,19 @@ def has_xwayland() -> bool: float scale; enum wl_output_subpixel subpixel; enum wl_output_transform transform; + enum wlr_output_adaptive_sync_status adaptive_sync_status; + uint32_t render_format; bool needs_frame; bool frame_pending; float transform_matrix[9]; + bool non_desktop; struct wlr_output_state pending; + // Commit sequence number. Incremented on each commit, may overflow. + uint32_t commit_seq; + struct { struct wl_signal frame; struct wl_signal damage; @@ -1139,27 +1092,36 @@ def has_xwayland() -> bool: struct wl_signal commit; struct wl_signal present; struct wl_signal bind; - struct wl_signal enable; - struct wl_signal mode; struct wl_signal description; + struct wl_signal request_state; struct wl_signal destroy; } events; struct wl_event_source *idle_frame; struct wl_event_source *idle_done; - - int attach_render_locks; // number of locks forcing rendering - - struct wl_list cursors; // wlr_output_cursor::link + int attach_render_locks; + struct wl_list cursors; struct wlr_output_cursor *hardware_cursor; + struct wlr_swapchain *cursor_swapchain; + struct wlr_buffer *cursor_front_buffer; int software_cursor_locks; - + struct wlr_allocator *allocator; + struct wlr_renderer *renderer; + struct wlr_swapchain *swapchain; + struct wlr_buffer *back_buffer; struct wl_listener display_destroy; + struct wlr_addon_set addons; void *data; ...; }; +struct wlr_output_event_request_state { + struct wlr_output *output; + const struct wlr_output_state *state; + ...; +}; + void wlr_output_enable(struct wlr_output *output, bool enable); void wlr_output_create_global(struct wlr_output *output); void wlr_output_destroy_global(struct wlr_output *output); @@ -1193,6 +1155,8 @@ def has_xwayland() -> bool: bool wlr_output_commit_state(struct wlr_output *output, const struct wlr_output_state *state); +void wlr_output_state_init(struct wlr_output_state *state); +void wlr_output_state_finish(struct wlr_output_state *state); void wlr_output_state_set_enabled(struct wlr_output_state *state, bool enabled); void wlr_output_state_set_mode(struct wlr_output_state *state, @@ -1217,50 +1181,6 @@ def has_xwayland() -> bool: enum wl_output_transform wlr_output_transform_compose( enum wl_output_transform tr_a, enum wl_output_transform tr_b); - -""" - -# types/wlr_output_damage.h -CDEF += """ -#define WLR_OUTPUT_DAMAGE_PREVIOUS_LEN 2 - -struct wlr_output_damage { - struct wlr_output *output; - int max_rects; // max number of damaged rectangles - - struct pixman_region32 current; // in output-local coordinates - - // circular queue for previous damage - struct pixman_region32 previous[WLR_OUTPUT_DAMAGE_PREVIOUS_LEN]; - size_t previous_idx; - - struct { - struct wl_signal frame; - struct wl_signal destroy; - } events; - - struct wl_listener output_destroy; - struct wl_listener output_mode; - struct wl_listener output_needs_frame; - struct wl_listener output_damage; - struct wl_listener output_frame; - struct wl_listener output_commit; - ...; -}; - -struct wlr_output_damage *wlr_output_damage_create(struct wlr_output *output); -void wlr_output_damage_destroy(struct wlr_output_damage *output_damage); - -bool wlr_output_damage_attach_render(struct wlr_output_damage *output_damage, - bool *needs_frame, struct pixman_region32 *buffer_damage); - -void wlr_output_damage_add(struct wlr_output_damage *output_damage, - struct pixman_region32 *damage); - -void wlr_output_damage_add_whole(struct wlr_output_damage *output_damage); - -void wlr_output_damage_add_box(struct wlr_output_damage *output_damage, - struct wlr_box *box); """ # types/wlr_output_layout.h @@ -1287,10 +1207,7 @@ def has_xwayland() -> bool: struct wlr_output *reference, double lx, double ly, double *dest_lx, double *dest_ly); -void wlr_output_layout_add(struct wlr_output_layout *layout, - struct wlr_output *output, int lx, int ly); - -void wlr_output_layout_move(struct wlr_output_layout *layout, +struct wlr_output_layout_output *wlr_output_layout_add(struct wlr_output_layout *layout, struct wlr_output *output, int lx, int ly); void wlr_output_layout_remove(struct wlr_output_layout *layout, @@ -1299,7 +1216,7 @@ def has_xwayland() -> bool: void wlr_output_layout_get_box(struct wlr_output_layout *layout, struct wlr_output *reference, struct wlr_box *dest_box); -void wlr_output_layout_add_auto(struct wlr_output_layout *layout, +struct wlr_output_layout_output *wlr_output_layout_add_auto(struct wlr_output_layout *layout, struct wlr_output *output); struct wlr_output *wlr_output_layout_output_at(struct wlr_output_layout *layout, @@ -1780,7 +1697,7 @@ def has_xwayland() -> bool: # types/wlr_scene.h CDEF += """ typedef bool (*wlr_scene_buffer_point_accepts_input_func_t)( - struct wlr_scene_buffer *buffer, int sx, int sy); + struct wlr_scene_buffer *buffer, double *sx, double *sy); typedef void (*wlr_scene_buffer_iterator_func_t)( struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data); extern "Python" void buffer_iterator_callback( @@ -1841,9 +1758,10 @@ def has_xwayland() -> bool: struct wlr_buffer *buffer; struct { + struct wl_signal outputs_update; struct wl_signal output_enter; // struct wlr_scene_output struct wl_signal output_leave; // struct wlr_scene_output - struct wl_signal output_present; // struct wlr_scene_output + struct wl_signal output_sample; // struct wlr_scene_output struct wl_signal frame_done; // struct timespec } events; @@ -1872,6 +1790,10 @@ def has_xwayland() -> bool: ...; }; +struct wlr_scene_output_state_options { + struct wlr_scene_timer *timer; +}; + void wlr_scene_node_destroy(struct wlr_scene_node *node); void wlr_scene_node_set_enabled(struct wlr_scene_node *node, bool enabled); @@ -1911,7 +1833,7 @@ def has_xwayland() -> bool: struct wlr_scene_buffer *wlr_scene_buffer_from_node(struct wlr_scene_node *node); -struct wlr_scene_surface *wlr_scene_surface_from_buffer( +struct wlr_scene_surface *wlr_scene_surface_try_from_buffer( struct wlr_scene_buffer *scene_buffer); struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent, @@ -1945,6 +1867,9 @@ def has_xwayland() -> bool: void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer, struct timespec *now); +void wlr_scene_buffer_set_opacity(struct wlr_scene_buffer *scene_buffer, + float opacity); + struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, struct wlr_output *output); @@ -1953,7 +1878,8 @@ def has_xwayland() -> bool: void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, int lx, int ly); -bool wlr_scene_output_commit(struct wlr_scene_output *scene_output); +bool wlr_scene_output_commit(struct wlr_scene_output *scene_output, + const struct wlr_scene_output_state_options *options); void wlr_scene_output_send_frame_done(struct wlr_scene_output *scene_output, struct timespec *now); @@ -1964,12 +1890,17 @@ def has_xwayland() -> bool: struct wlr_scene_output *wlr_scene_get_scene_output(struct wlr_scene *scene, struct wlr_output *output); -bool wlr_scene_attach_output_layout(struct wlr_scene *scene, +struct wlr_scene_output_layout *wlr_scene_attach_output_layout(struct wlr_scene *scene, struct wlr_output_layout *output_layout); +void wlr_scene_output_layout_add_output(struct wlr_scene_output_layout *sol, struct wlr_output_layout_output *lo, struct wlr_scene_output *so); + struct wlr_scene_tree *wlr_scene_subsurface_tree_create( struct wlr_scene_tree *parent, struct wlr_surface *surface); +void wlr_scene_subsurface_tree_set_clip(struct wlr_scene_node *node, + struct wlr_box *clip); + struct wlr_scene_tree *wlr_scene_xdg_surface_create( struct wlr_scene_tree *parent, struct wlr_xdg_surface *xdg_surface); @@ -1979,6 +1910,9 @@ def has_xwayland() -> bool: void wlr_scene_layer_surface_v1_configure( struct wlr_scene_layer_surface_v1 *scene_layer_surface, const struct wlr_box *full_area, struct wlr_box *usable_area); + +struct wlr_scene_tree *wlr_scene_drag_icon_create( + struct wlr_scene_tree *parent, struct wlr_drag_icon *drag_icon); """ # types/wlr_screencopy_v1.h @@ -2331,6 +2265,18 @@ def has_xwayland() -> bool: void *data; }; +struct wlr_session_lock_surface_v1_state { + uint32_t width, height; + uint32_t configure_serial; +}; + +struct wlr_session_lock_surface_v1_configure { + struct wl_list link; // wlr_session_lock_surface_v1.configure_list + uint32_t serial; + + uint32_t width, height; +}; + struct wlr_session_lock_surface_v1 { struct wl_resource *resource; struct wl_list link; // wlr_session_lock_v1.surfaces @@ -2338,15 +2284,18 @@ def has_xwayland() -> bool: struct wlr_output *output; struct wlr_surface *surface; - bool configured, mapped; + bool configured; + + struct wl_list configure_list; // wlr_session_lock_surface_v1_configure.link + + struct wlr_session_lock_surface_v1_state current; + struct wlr_session_lock_surface_v1_state pending; struct { - struct wl_signal map; - struct wl_signal destroy; + struct wl_signal destroy; } events; void *data; - ...; }; @@ -2360,9 +2309,7 @@ def has_xwayland() -> bool: struct wlr_session_lock_surface_v1 *lock_surface, uint32_t width, uint32_t height); -bool wlr_surface_is_session_lock_surface_v1(struct wlr_surface *surface); - -struct wlr_session_lock_surface_v1 *wlr_session_lock_surface_v1_from_wlr_surface( +struct wlr_session_lock_surface_v1 *wlr_session_lock_surface_v1_try_from_wlr_surface( struct wlr_surface *surface); """ @@ -2531,8 +2478,6 @@ def has_xwayland() -> bool: int wlr_xcursor_manager_load(struct wlr_xcursor_manager *manager, float scale); -void wlr_xcursor_manager_set_cursor_image(struct wlr_xcursor_manager *manager, - const char *name, struct wlr_cursor *cursor); struct wlr_xcursor *wlr_xcursor_manager_get_xcursor( struct wlr_xcursor_manager *manager, const char *name, float scale); """ @@ -2564,6 +2509,7 @@ def has_xwayland() -> bool: struct { struct wl_signal destroy; struct wl_signal request_activate; + struct wl_signal new_token; } events; ...; }; @@ -2615,7 +2561,7 @@ def has_xwayland() -> bool: struct wlr_xdg_toplevel_decoration_v1 { struct wl_resource *resource; - struct wlr_xdg_surface *surface; + struct wlr_xdg_toplevel *toplevel; struct wlr_xdg_decoration_manager_v1 *manager; struct wl_list link; // wlr_xdg_decoration_manager_v1::link @@ -2762,7 +2708,7 @@ def has_xwayland() -> bool: struct wl_list link; struct wl_resource *resource; - bool committed; + bool sent_initial_configure; struct wlr_surface *parent; struct wlr_seat *seat; @@ -2807,7 +2753,6 @@ def has_xwayland() -> bool: struct wlr_xdg_toplevel { struct wl_resource *resource; struct wlr_xdg_surface *base; - bool added; struct wlr_xdg_toplevel *parent; struct wl_listener parent_unmap; @@ -2855,6 +2800,7 @@ def has_xwayland() -> bool: struct wlr_surface *surface; struct wl_list link; // wlr_xdg_client::surfaces enum wlr_xdg_surface_role role; + struct wl_resource *role_resource; union { struct wlr_xdg_toplevel *toplevel; @@ -2863,21 +2809,20 @@ def has_xwayland() -> bool: struct wl_list popups; // wlr_xdg_popup::link - bool added, configured, mapped; + bool added, configured; struct wl_event_source *configure_idle; uint32_t scheduled_serial; struct wl_list configure_list; struct wlr_xdg_surface_state current, pending; - struct wl_listener surface_commit; + bool initialized; + bool initial_commit; struct { struct wl_signal destroy; struct wl_signal ping_timeout; struct wl_signal new_popup; - struct wl_signal map; - struct wl_signal unmap; struct wl_signal configure; // wlr_xdg_surface_configure struct wl_signal ack_configure; // wlr_xdg_surface_configure @@ -2953,9 +2898,8 @@ def has_xwayland() -> bool: struct wlr_surface *wlr_xdg_surface_surface_at( struct wlr_xdg_surface *surface, double sx, double sy, double *sub_x, double *sub_y); -bool wlr_surface_is_xdg_surface(struct wlr_surface *surface); -struct wlr_xdg_surface *wlr_xdg_surface_from_wlr_surface( +struct wlr_xdg_surface *wlr_xdg_surface_try_from_wlr_surface( struct wlr_surface *surface); void wlr_xdg_surface_get_geometry(struct wlr_xdg_surface *surface, @@ -3042,8 +2986,8 @@ def has_xwayland() -> bool: #include #include #include +#include #include -#include #include #include #include @@ -3052,7 +2996,6 @@ def has_xwayland() -> bool: #include #include #include -#include #include #include #include @@ -3155,13 +3098,11 @@ def has_xwayland() -> bool: struct wlr_layer_shell_v1 *shell; struct wl_list popups; // wlr_xdg_popup::link char *namespace; - bool added, configured, mapped; + bool added, configured; struct wl_list configure_list; struct wlr_layer_surface_v1_state current, pending; struct { struct wl_signal destroy; - struct wl_signal map; - struct wl_signal unmap; struct wl_signal new_popup; } events; @@ -3169,16 +3110,15 @@ def has_xwayland() -> bool: ...; }; -struct wlr_layer_shell_v1 *wlr_layer_shell_v1_create(struct wl_display *display); +struct wlr_layer_shell_v1 *wlr_layer_shell_v1_create(struct wl_display *display, + uint32_t version); void wlr_layer_surface_v1_configure(struct wlr_layer_surface_v1 *surface, uint32_t width, uint32_t height); void wlr_layer_surface_v1_destroy(struct wlr_layer_surface_v1 *surface); -bool wlr_surface_is_layer_surface(struct wlr_surface *surface); - -struct wlr_layer_surface_v1 *wlr_layer_surface_v1_from_wlr_surface( +struct wlr_layer_surface_v1 *wlr_layer_surface_v1_try_from_wlr_surface( struct wlr_surface *surface); void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface, @@ -3204,6 +3144,9 @@ def has_xwayland() -> bool: typedef struct { ...; } xcb_generic_event_t; + typedef struct { + ...; + } xcb_ewmh_wm_strut_partial_t; typedef uint32_t xcb_pixmap_t; typedef uint32_t xcb_window_t; typedef uint32_t xcb_atom_t; @@ -3236,6 +3179,7 @@ def has_xwayland() -> bool: struct wl_client *client; struct wl_event_source *pipe_source; int wm_fd[2], wl_fd[2]; + bool ready; time_t server_start; int display; char display_name[16]; @@ -3287,15 +3231,19 @@ def has_xwayland() -> bool: xcb_window_t window_id; struct wlr_xwm *xwm; uint32_t surface_id; + uint64_t serial; struct wl_list link; struct wl_list stack_link; struct wl_list unpaired_link; struct wlr_surface *surface; + struct wlr_addon surface_addon; + struct wl_listener surface_commit; + struct wl_listener surface_map; + struct wl_listener surface_unmap; int16_t x, y; uint16_t width, height; uint16_t saved_width, saved_height; bool override_redirect; - bool mapped; char *title; char *class; char *instance; @@ -3313,13 +3261,14 @@ def has_xwayland() -> bool: uint32_t decorations; xcb_icccm_wm_hints_t *hints; xcb_size_hints_t *size_hints; + xcb_ewmh_wm_strut_partial_t *strut_partial; bool pinging; struct wl_event_source *ping_timer; - // _NET_WM_STATE bool modal; bool fullscreen; bool maximized_vert, maximized_horz; bool minimized; + bool withdrawn; bool has_alpha; struct { struct wl_signal destroy; @@ -3330,17 +3279,17 @@ def has_xwayland() -> bool: struct wl_signal request_maximize; struct wl_signal request_fullscreen; struct wl_signal request_activate; - struct wl_signal map; - struct wl_signal unmap; + struct wl_signal associate; + struct wl_signal dissociate; struct wl_signal set_title; struct wl_signal set_class; struct wl_signal set_role; struct wl_signal set_parent; - struct wl_signal set_pid; struct wl_signal set_startup_id; struct wl_signal set_window_type; struct wl_signal set_hints; struct wl_signal set_decorations; + struct wl_signal set_strut_partial; struct wl_signal set_override_redirect; struct wl_signal set_geometry; struct wl_signal ping_timeout; @@ -3355,10 +3304,6 @@ def has_xwayland() -> bool: uint16_t mask; // xcb_config_window_t ...; }; - struct wlr_xwayland_move_event { - struct wlr_xwayland_surface *surface; - ...; - }; struct wlr_xwayland_remove_startup_info_event { const char *id; xcb_window_t window; @@ -3398,8 +3343,7 @@ def has_xwayland() -> bool: bool fullscreen); void wlr_xwayland_set_seat(struct wlr_xwayland *xwayland, struct wlr_seat *seat); - bool wlr_surface_is_xwayland_surface(struct wlr_surface *surface); - struct wlr_xwayland_surface *wlr_xwayland_surface_from_wlr_surface( + struct wlr_xwayland_surface *wlr_xwayland_surface_try_from_wlr_surface( struct wlr_surface *surface); void wlr_xwayland_surface_ping(struct wlr_xwayland_surface *surface); bool wlr_xwayland_or_surface_wants_focus( diff --git a/wlroots/helper.py b/wlroots/helper.py index 2c4bcedf..daf347e5 100644 --- a/wlroots/helper.py +++ b/wlroots/helper.py @@ -11,7 +11,10 @@ def build_compositor( - display: Display, *, backend_type=BackendType.AUTO + display: Display, + *, + backend_type=BackendType.AUTO, + compositor_version: int = 5, ) -> tuple[Compositor, Allocator, Renderer, Backend, SubCompositor]: """Build and run a compositor @@ -21,6 +24,8 @@ def build_compositor( :param backend_type: The type of the backend to setup the compositor for, by default use the auto-detected backend. + :param compositor_version: + The version of the wlr_compositor interface to use. :return: The compositor, allocator, renderer, and the backend. """ @@ -28,7 +33,7 @@ def build_compositor( renderer = Renderer.autocreate(backend) renderer.init_display(display) allocator = Allocator.autocreate(backend, renderer) - compositor = Compositor(display, renderer) + compositor = Compositor(display, compositor_version, renderer) subcompositor = SubCompositor(display) return compositor, allocator, renderer, backend, subcompositor diff --git a/wlroots/include/idle-inhibit-unstable-v1-protocol.h b/wlroots/include/idle-inhibit-unstable-v1-protocol.h index 9673a68e..f1425b55 100644 --- a/wlroots/include/idle-inhibit-unstable-v1-protocol.h +++ b/wlroots/include/idle-inhibit-unstable-v1-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.21.0 */ +/* Generated by wayland-scanner 1.22.0 */ #ifndef IDLE_INHIBIT_UNSTABLE_V1_SERVER_PROTOCOL_H #define IDLE_INHIBIT_UNSTABLE_V1_SERVER_PROTOCOL_H diff --git a/wlroots/include/idle-protocol.h b/wlroots/include/idle-protocol.h deleted file mode 100644 index 7351126f..00000000 --- a/wlroots/include/idle-protocol.h +++ /dev/null @@ -1,176 +0,0 @@ -/* Generated by wayland-scanner 1.21.0 */ - -#ifndef IDLE_SERVER_PROTOCOL_H -#define IDLE_SERVER_PROTOCOL_H - -#include -#include -#include "wayland-server.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct wl_client; -struct wl_resource; - -/** - * @page page_idle The idle protocol - * @section page_ifaces_idle Interfaces - * - @subpage page_iface_org_kde_kwin_idle - User idle time manager - * - @subpage page_iface_org_kde_kwin_idle_timeout - - * @section page_copyright_idle Copyright - *
- *
- * Copyright (C) 2015 Martin Gräßlin
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program.  If not, see .
- * 
- */ -struct org_kde_kwin_idle; -struct org_kde_kwin_idle_timeout; -struct wl_seat; - -#ifndef ORG_KDE_KWIN_IDLE_INTERFACE -#define ORG_KDE_KWIN_IDLE_INTERFACE -/** - * @page page_iface_org_kde_kwin_idle org_kde_kwin_idle - * @section page_iface_org_kde_kwin_idle_desc Description - * - * This interface allows to monitor user idle time on a given seat. The interface - * allows to register timers which trigger after no user activity was registered - * on the seat for a given interval. It notifies when user activity resumes. - * - * This is useful for applications wanting to perform actions when the user is not - * interacting with the system, e.g. chat applications setting the user as away, power - * management features to dim screen, etc.. - * @section page_iface_org_kde_kwin_idle_api API - * See @ref iface_org_kde_kwin_idle. - */ -/** - * @defgroup iface_org_kde_kwin_idle The org_kde_kwin_idle interface - * - * This interface allows to monitor user idle time on a given seat. The interface - * allows to register timers which trigger after no user activity was registered - * on the seat for a given interval. It notifies when user activity resumes. - * - * This is useful for applications wanting to perform actions when the user is not - * interacting with the system, e.g. chat applications setting the user as away, power - * management features to dim screen, etc.. - */ -extern const struct wl_interface org_kde_kwin_idle_interface; -#endif -#ifndef ORG_KDE_KWIN_IDLE_TIMEOUT_INTERFACE -#define ORG_KDE_KWIN_IDLE_TIMEOUT_INTERFACE -/** - * @page page_iface_org_kde_kwin_idle_timeout org_kde_kwin_idle_timeout - * @section page_iface_org_kde_kwin_idle_timeout_api API - * See @ref iface_org_kde_kwin_idle_timeout. - */ -/** - * @defgroup iface_org_kde_kwin_idle_timeout The org_kde_kwin_idle_timeout interface - */ -extern const struct wl_interface org_kde_kwin_idle_timeout_interface; -#endif - -/** - * @ingroup iface_org_kde_kwin_idle - * @struct org_kde_kwin_idle_interface - */ -struct org_kde_kwin_idle_interface { - /** - * @param timeout The idle timeout in msec - */ - void (*get_idle_timeout)(struct wl_client *client, - struct wl_resource *resource, - uint32_t id, - struct wl_resource *seat, - uint32_t timeout); -}; - - -/** - * @ingroup iface_org_kde_kwin_idle - */ -#define ORG_KDE_KWIN_IDLE_GET_IDLE_TIMEOUT_SINCE_VERSION 1 - -/** - * @ingroup iface_org_kde_kwin_idle_timeout - * @struct org_kde_kwin_idle_timeout_interface - */ -struct org_kde_kwin_idle_timeout_interface { - /** - * release the timeout object - * - * - */ - void (*release)(struct wl_client *client, - struct wl_resource *resource); - /** - * Simulates user activity for this timeout, behaves just like real user activity on the seat - * - * - */ - void (*simulate_user_activity)(struct wl_client *client, - struct wl_resource *resource); -}; - -#define ORG_KDE_KWIN_IDLE_TIMEOUT_IDLE 0 -#define ORG_KDE_KWIN_IDLE_TIMEOUT_RESUMED 1 - -/** - * @ingroup iface_org_kde_kwin_idle_timeout - */ -#define ORG_KDE_KWIN_IDLE_TIMEOUT_IDLE_SINCE_VERSION 1 -/** - * @ingroup iface_org_kde_kwin_idle_timeout - */ -#define ORG_KDE_KWIN_IDLE_TIMEOUT_RESUMED_SINCE_VERSION 1 - -/** - * @ingroup iface_org_kde_kwin_idle_timeout - */ -#define ORG_KDE_KWIN_IDLE_TIMEOUT_RELEASE_SINCE_VERSION 1 -/** - * @ingroup iface_org_kde_kwin_idle_timeout - */ -#define ORG_KDE_KWIN_IDLE_TIMEOUT_SIMULATE_USER_ACTIVITY_SINCE_VERSION 1 - -/** - * @ingroup iface_org_kde_kwin_idle_timeout - * Sends an idle event to the client owning the resource. - * @param resource_ The client's resource - */ -static inline void -org_kde_kwin_idle_timeout_send_idle(struct wl_resource *resource_) -{ - wl_resource_post_event(resource_, ORG_KDE_KWIN_IDLE_TIMEOUT_IDLE); -} - -/** - * @ingroup iface_org_kde_kwin_idle_timeout - * Sends an resumed event to the client owning the resource. - * @param resource_ The client's resource - */ -static inline void -org_kde_kwin_idle_timeout_send_resumed(struct wl_resource *resource_) -{ - wl_resource_post_event(resource_, ORG_KDE_KWIN_IDLE_TIMEOUT_RESUMED); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/wlroots/include/pointer-constraints-unstable-v1-protocol.h b/wlroots/include/pointer-constraints-unstable-v1-protocol.h index 2802032b..cd12cf17 100644 --- a/wlroots/include/pointer-constraints-unstable-v1-protocol.h +++ b/wlroots/include/pointer-constraints-unstable-v1-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.21.0 */ +/* Generated by wayland-scanner 1.22.0 */ #ifndef POINTER_CONSTRAINTS_UNSTABLE_V1_SERVER_PROTOCOL_H #define POINTER_CONSTRAINTS_UNSTABLE_V1_SERVER_PROTOCOL_H diff --git a/wlroots/include/wlr-layer-shell-unstable-v1-protocol.h b/wlroots/include/wlr-layer-shell-unstable-v1-protocol.h index 3b4d7e7d..6c82a16c 100644 --- a/wlroots/include/wlr-layer-shell-unstable-v1-protocol.h +++ b/wlroots/include/wlr-layer-shell-unstable-v1-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.21.0 */ +/* Generated by wayland-scanner 1.22.0 */ #ifndef WLR_LAYER_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H #define WLR_LAYER_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H diff --git a/wlroots/include/wlr-output-power-management-unstable-v1-protocol.h b/wlroots/include/wlr-output-power-management-unstable-v1-protocol.h index 6d92e782..4387c518 100644 --- a/wlroots/include/wlr-output-power-management-unstable-v1-protocol.h +++ b/wlroots/include/wlr-output-power-management-unstable-v1-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.21.0 */ +/* Generated by wayland-scanner 1.22.0 */ #ifndef WLR_OUTPUT_POWER_MANAGEMENT_UNSTABLE_V1_SERVER_PROTOCOL_H #define WLR_OUTPUT_POWER_MANAGEMENT_UNSTABLE_V1_SERVER_PROTOCOL_H diff --git a/wlroots/include/xdg-shell-protocol.h b/wlroots/include/xdg-shell-protocol.h index 8db7e1c6..184572b5 100644 --- a/wlroots/include/xdg-shell-protocol.h +++ b/wlroots/include/xdg-shell-protocol.h @@ -1,4 +1,4 @@ -/* Generated by wayland-scanner 1.21.0 */ +/* Generated by wayland-scanner 1.22.0 */ #ifndef XDG_SHELL_SERVER_PROTOCOL_H #define XDG_SHELL_SERVER_PROTOCOL_H @@ -172,8 +172,10 @@ extern const struct wl_interface xdg_positioner_interface; * * After creating a role-specific object and setting it up, the client must * perform an initial commit without any buffer attached. The compositor - * will reply with an xdg_surface.configure event. The client must - * acknowledge it and is then allowed to attach a buffer to map the surface. + * will reply with initial wl_surface state such as + * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + * event. The client must acknowledge it and is then allowed to attach a + * buffer to map the surface. * * Mapping an xdg_surface-based role surface is defined as making it * possible for the surface to be shown by the compositor. Note that @@ -223,8 +225,10 @@ extern const struct wl_interface xdg_positioner_interface; * * After creating a role-specific object and setting it up, the client must * perform an initial commit without any buffer attached. The compositor - * will reply with an xdg_surface.configure event. The client must - * acknowledge it and is then allowed to attach a buffer to map the surface. + * will reply with initial wl_surface state such as + * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure + * event. The client must acknowledge it and is then allowed to attach a + * buffer to map the surface. * * Mapping an xdg_surface-based role surface is defined as making it * possible for the surface to be shown by the compositor. Note that @@ -959,13 +963,22 @@ struct xdg_surface_interface { * commit. This unset is meant for extremely simple clients. * * The arguments are given in the surface-local coordinate space of - * the wl_surface associated with this xdg_surface. + * the wl_surface associated with this xdg_surface, and may extend + * outside of the wl_surface itself to mark parts of the subsurface + * tree as part of the window geometry. * - * The width and height must be greater than zero. Setting an - * invalid size will raise an invalid_size error. When applied, the - * effective window geometry will be the set window geometry - * clamped to the bounding rectangle of the combined geometry of - * the surface of the xdg_surface and the associated subsurfaces. + * When applied, the effective window geometry will be the set + * window geometry clamped to the bounding rectangle of the + * combined geometry of the surface of the xdg_surface and the + * associated subsurfaces. + * + * The effective geometry will not be recalculated unless a new + * call to set_window_geometry is done and the new pending surface + * state is subsequently applied. + * + * The width and height of the effective window geometry must be + * greater than zero. Setting an invalid size will raise an + * invalid_size error. */ void (*set_window_geometry)(struct wl_client *client, struct wl_resource *resource, @@ -1117,7 +1130,8 @@ enum xdg_toplevel_state { * the surface is maximized * * The surface is maximized. The window geometry specified in the - * configure event must be obeyed by the client. + * configure event must be obeyed by the client, or the + * xdg_wm_base.invalid_surface_state error is raised. * * The client should draw without shadow or other decoration * outside of the window geometry. @@ -1185,6 +1199,15 @@ enum xdg_toplevel_state { * @since 2 */ XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8, + /** + * surface repaint is suspended + * + * The surface is currently not ordinarily being repainted; for + * example because its content is occluded by another window, or + * its outputs are switched off due to screen locking. + * @since 6 + */ + XDG_TOPLEVEL_STATE_SUSPENDED = 9, }; /** * @ingroup iface_xdg_toplevel @@ -1202,6 +1225,10 @@ enum xdg_toplevel_state { * @ingroup iface_xdg_toplevel */ #define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6 #endif /* XDG_TOPLEVEL_STATE_ENUM */ #ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM @@ -1397,11 +1424,12 @@ struct xdg_toplevel_interface { * * The edges parameter specifies how the surface should be resized, * and is one of the values of the resize_edge enum. Values not - * matching a variant of the enum will cause a protocol error. The - * compositor may use this information to update the surface - * position for example when dragging the top left corner. The - * compositor may also use this information to adapt its behavior, - * e.g. choose an appropriate cursor image. + * matching a variant of the enum will cause the + * invalid_resize_edge protocol error. The compositor may use this + * information to update the surface position for example when + * dragging the top left corner. The compositor may also use this + * information to adapt its behavior, e.g. choose an appropriate + * cursor image. * @param seat the wl_seat of the user event * @param serial the serial of the user event * @param edges which edge or corner is being dragged @@ -1765,8 +1793,8 @@ struct xdg_popup_interface { * This destroys the popup. Explicitly destroying the xdg_popup * object will also dismiss the popup, and unmap the surface. * - * If this xdg_popup is not the "topmost" popup, a protocol error - * will be sent. + * If this xdg_popup is not the "topmost" popup, the + * xdg_wm_base.not_the_topmost_popup protocol error will be sent. */ void (*destroy)(struct wl_client *client, struct wl_resource *resource); diff --git a/wlroots/renderer.py b/wlroots/renderer.py index 5d85f9c0..6e7ea06f 100644 --- a/wlroots/renderer.py +++ b/wlroots/renderer.py @@ -50,9 +50,9 @@ def render(self, width: int, height: int) -> Iterator[Renderer]: finally: self.end() - def begin(self, width: int, height: int) -> None: + def begin(self, width: int, height: int) -> bool: """Begin rendering with the given height and width""" - lib.wlr_renderer_begin(self._ptr, width, height) + return lib.wlr_renderer_begin(self._ptr, width, height) def end(self): """Finish rendering""" diff --git a/wlroots/wlr_types/__init__.py b/wlroots/wlr_types/__init__.py index 78952fdf..ab214ed0 100644 --- a/wlroots/wlr_types/__init__.py +++ b/wlroots/wlr_types/__init__.py @@ -13,6 +13,7 @@ from .data_device_manager import DataDeviceManager # noqa: F401 from .export_dmabuf_v1 import ExportDmabufManagerV1 # noqa: F401 from .foreign_toplevel_management_v1 import ForeignToplevelManagerV1 # noqa: F401 +from .fractional_scale_v1 import FractionalScaleManagerV1 # noqa: F401 from .gamma_control_v1 import GammaControlManagerV1 # noqa: F401 from .input_device import InputDevice # noqa: F401 from .input_inhibit import InputInhibitManager # noqa: F401 @@ -20,8 +21,7 @@ from .layer_shell_v1 import LayerShellV1 # noqa: F401 from .matrix import Matrix # noqa: F401 from .output import Output, OutputState # noqa: F401 -from .output_damage import OutputDamage # noqa: F401 -from .output_layout import OutputLayout # noqa: F401 +from .output_layout import OutputLayout, OutputLayoutOutput # noqa: F401 from .pointer import ( # noqa: F401 PointerAxisEvent, PointerButtonEvent, @@ -42,6 +42,7 @@ SceneNode, SceneNodeType, SceneOutput, + SceneOutputLayout, SceneSurface, SceneTree, ) diff --git a/wlroots/wlr_types/compositor.py b/wlroots/wlr_types/compositor.py index 42d114fe..acfdd524 100644 --- a/wlroots/wlr_types/compositor.py +++ b/wlroots/wlr_types/compositor.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Final from weakref import WeakKeyDictionary from pywayland.protocol.wayland import WlOutput @@ -19,16 +19,30 @@ from wlroots.renderer import Renderer +_MAX_COMPOSITOR_VERSION: Final = 5 + + class Compositor(Ptr): - def __init__(self, display: Display, renderer: Renderer) -> None: + def __init__( + self, display: Display, version: int, renderer: Renderer | None = None + ) -> None: """A compositor for clients to be able to allocate surfaces :param display: The Wayland server display to attach to the compositor. + :param version: + The version of the wlr_compositor interface to use. :param renderer: The wlroots renderer to attach the compositor to. """ - self._ptr = lib.wlr_compositor_create(display._ptr, renderer._ptr) + if not 0 < version <= _MAX_COMPOSITOR_VERSION: + raise ValueError( + f"Invalid compositor version, should be a value between 1 (inclusive) and {_MAX_COMPOSITOR_VERSION} (inclusive), got: {version}" + ) + if renderer is None: + self._ptr = lib.wlr_compositor_create(display._ptr, version, ffi.NULL) + else: + self._ptr = lib.wlr_compositor_create(display._ptr, version, renderer._ptr) class SubCompositor(Ptr): @@ -45,42 +59,19 @@ def __init__(self, ptr) -> None: """ self._ptr = ptr + self.precommit_event = Signal( + ptr=ffi.addressof(self._ptr.events.precommit), + data_wrapper=SurfaceState, + ) self.commit_event = Signal(ptr=ffi.addressof(self._ptr.events.commit)) + self.map_event = Signal(ptr=ffi.addressof(self._ptr.events.map)) + self.unmap_event = Signal(ptr=ffi.addressof(self._ptr.events.unmap)) self.new_subsurface_event = Signal( ptr=ffi.addressof(self._ptr.events.new_subsurface), data_wrapper=SubSurface, ) self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) - @property - def is_xdg_surface(self) -> bool: - """True if the current surface is an XDG surface""" - return lib.wlr_surface_is_xdg_surface(self._ptr) - - @property - def is_layer_surface(self) -> bool: - """True if the current surface is a layer surface""" - return lib.wlr_surface_is_layer_surface(self._ptr) - - @property - def is_xwayland_surface(self) -> bool: - """ - True if the current surface is an XWayland surface. - - Requires that pywlroots was built with XWayland support. - """ - return lib.wlr_surface_is_xwayland_surface(self._ptr) - - @property - def sx(self) -> int: - """Surface local buffer x position""" - return self._ptr.sx - - @property - def sy(self) -> int: - """Surface local buffer y position""" - return self._ptr.sy - @property def current(self) -> SurfaceState: """The current commited surface state""" @@ -147,8 +138,6 @@ def __init__(self, ptr): self._ptr = ffi.cast("struct wlr_subsurface *", ptr) self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) - self.map_event = Signal(ptr=ffi.addressof(self._ptr.events.map)) - self.unmap_event = Signal(ptr=ffi.addressof(self._ptr.events.unmap)) @property def surface(self) -> Surface: diff --git a/wlroots/wlr_types/cursor.py b/wlroots/wlr_types/cursor.py index efd9753f..6662bc0e 100644 --- a/wlroots/wlr_types/cursor.py +++ b/wlroots/wlr_types/cursor.py @@ -2,6 +2,7 @@ from __future__ import annotations import enum +from typing import TYPE_CHECKING from pywayland.server import Signal @@ -32,6 +33,9 @@ TouchUpEvent, ) +if TYPE_CHECKING: + from .xcursor_manager import XCursorManager + class WarpMode(enum.Enum): Layout = enum.auto() @@ -292,3 +296,11 @@ def map_input_to_output( """ output_ptr = ptr_or_null(output) lib.wlr_cursor_map_input_to_output(self._ptr, input_device._ptr, output_ptr) + + def set_xcursor(self, manager: XCursorManager, name: str) -> None: + """ + Set the cursor image from an XCursor theme. + + The image will be loaded from the struct wlr_xcursor_manager. + """ + lib.wlr_cursor_set_xcursor(self._ptr, manager._ptr, name.encode()) diff --git a/wlroots/wlr_types/data_device_manager.py b/wlroots/wlr_types/data_device_manager.py index 4970e13c..ab43e6f2 100644 --- a/wlroots/wlr_types/data_device_manager.py +++ b/wlroots/wlr_types/data_device_manager.py @@ -86,8 +86,6 @@ class DragIcon(PtrHasData): def __init__(self, ptr) -> None: self._ptr = ffi.cast("struct wlr_drag_icon *", ptr) - self.map_event = Signal(ptr=ffi.addressof(self._ptr.events.map)) - self.unmap_event = Signal(ptr=ffi.addressof(self._ptr.events.unmap)) self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) @property diff --git a/wlroots/wlr_types/fractional_scale_v1.py b/wlroots/wlr_types/fractional_scale_v1.py new file mode 100644 index 00000000..17802064 --- /dev/null +++ b/wlroots/wlr_types/fractional_scale_v1.py @@ -0,0 +1,17 @@ +# Copyright (c) 2024 Jeroen Wijenbergh + +from pywayland.server import Display + +from wlroots import PtrHasData, lib + +from .compositor import Surface + + +class FractionalScaleManagerV1(PtrHasData): + def __init__(self, display: Display, version: int = 1) -> None: + """Create a wlr_fractional_scale_manager_v1""" + self._ptr = lib.wlr_fractional_scale_manager_v1_create(display._ptr, version) + + +def notify_scale(surface: Surface, scale: float): + lib.wlr_fractional_scale_v1_notify_scale(surface._ptr, scale) diff --git a/wlroots/wlr_types/idle.py b/wlroots/wlr_types/idle.py deleted file mode 100644 index 2e7414bd..00000000 --- a/wlroots/wlr_types/idle.py +++ /dev/null @@ -1,67 +0,0 @@ -from pywayland.server import Display, Signal - -from wlroots import Ptr, ffi, lib - -from .seat import Seat - - -class IdleTimeout(Ptr): - def __init__(self, ptr) -> None: - self._ptr = ffi.cast("struct wlr_idle_timeout *", ptr) - - self.idle_event = Signal(ptr=ffi.addressof(self._ptr.events.idle)) - self.resume_event = Signal(ptr=ffi.addressof(self._ptr.events.resume)) - self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) - - @property - def idle_state(self) -> bool: - return self._ptr.idle_state - - @property - def enabled(self) -> bool: - return self._ptr.enabled - - @property - def timeout(self) -> int: - return self._ptr.timeout - - def destroy(self) -> None: - if self._ptr is not None: - ffi.release(self._ptr) - self._ptr = None - - -class Idle(Ptr): - def __init__(self, display: Display) -> None: - self._ptr = lib.wlr_idle_create(display._ptr) - - self.activity_notify_event = Signal( - ptr=ffi.addressof(self._ptr.events.activity_notify) - ) - self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) - - @property - def enabled(self) -> bool: - return self._ptr.enabled - - def notify_activity(self, seat: Seat) -> None: - """ - Send notification to restart all timers for the given seat. Called by - compositor when there is an user activity event on that seat. - """ - lib.wlr_idle_notify_activity(self._ptr, seat._ptr) - - def set_enabled(self, seat: Seat, enabled: bool): - """ - Enable or disable timers for a given idle resource by seat. - Passing a NULL seat means update timers for all seats. - """ - lib.wlr_idle_set_enabled(self._ptr, seat._ptr, enabled) - - def idle_timeout_create(self, seat: Seat, timeout: int) -> IdleTimeout: - """ - Create a new timer on the given seat. The idle event will be called after - the given amount of milliseconds of inactivity, and the resumed event will - be sent at the first user activity after the fired event. - """ - return IdleTimeout(lib.wlr_idle_timeout_create(self._ptr, seat._ptr, timeout)) diff --git a/wlroots/wlr_types/input_inhibit.py b/wlroots/wlr_types/input_inhibit.py index 7a31c0a3..ef44567b 100644 --- a/wlroots/wlr_types/input_inhibit.py +++ b/wlroots/wlr_types/input_inhibit.py @@ -1,5 +1,7 @@ # Copyright (c) 2021 Graeme Holliday +import warnings + from pywayland.server import Client, Display, Signal from wlroots import Ptr, ffi, lib @@ -8,6 +10,13 @@ class InputInhibitManager(Ptr): def __init__(self, display: Display) -> None: """Creates a wlr_input_inhibit_manager""" + warnings.warn( + "Following the protocol deprecation, wlr/types/wlr_input_inhibitor.h is" + " deprecated and will be removed in the next release.", + DeprecationWarning, + stacklevel=1, + ) + self._ptr = lib.wlr_input_inhibit_manager_create(display._ptr) self.activate_event = Signal(ptr=ffi.addressof(self._ptr.events.activate)) diff --git a/wlroots/wlr_types/layer_shell_v1.py b/wlroots/wlr_types/layer_shell_v1.py index 1698cd54..ec8c75af 100644 --- a/wlroots/wlr_types/layer_shell_v1.py +++ b/wlroots/wlr_types/layer_shell_v1.py @@ -3,7 +3,7 @@ import enum from dataclasses import dataclass -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Final from weakref import WeakKeyDictionary from pywayland.server import Signal @@ -97,8 +97,6 @@ def __init__(self, ptr): self._ptr = ffi.cast("struct wlr_layer_surface_v1 *", ptr) self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) - self.map_event = Signal(ptr=ffi.addressof(self._ptr.events.map)) - self.unmap_event = Signal(ptr=ffi.addressof(self._ptr.events.unmap)) self.new_popup_event = Signal(ptr=ffi.addressof(self._ptr.events.new_popup)) @property @@ -163,10 +161,12 @@ def destroy(self) -> None: lib.wlr_layer_surface_v1_destroy(self._ptr) @staticmethod - def from_wlr_surface(surface: Surface): - surface_ptr = lib.wlr_layer_surface_v1_from_wlr_surface(surface._ptr) - _weakkeydict[surface_ptr] = surface._ptr - return LayerSurfaceV1(surface_ptr) + def try_from_wlr_surface(surface: Surface) -> LayerSurfaceV1 | None: + maybe_ptr = lib.wlr_layer_surface_v1_try_from_wlr_surface(surface._ptr) + if maybe_ptr == ffi.NULL: + return None + _weakkeydict[maybe_ptr] = maybe_ptr._ptr + return LayerSurfaceV1(maybe_ptr) def for_each_surface( self, iterator: SurfaceCallback[T], data: T | None = None @@ -197,10 +197,18 @@ def surface_at(self, sx: float, sy: float) -> tuple[Surface | None, float, float return Surface(surface_ptr), sub_x_data[0], sub_y_data[0] +_MAX_LAYER_SHELL_VERSION: Final = 4 + + class LayerShellV1(PtrHasData): - def __init__(self, display: Display) -> None: + def __init__(self, display: Display, version: int) -> None: """Create an wlr_xdg_output_manager_v1""" - self._ptr = lib.wlr_layer_shell_v1_create(display._ptr) + if not 0 < version <= _MAX_LAYER_SHELL_VERSION: + raise ValueError( + f"Invalid layer shell version, should be a value between 1 (inclusive) and {_MAX_LAYER_SHELL_VERSION} (inclusive), got: {version}" + ) + + self._ptr = lib.wlr_layer_shell_v1_create(display._ptr, version) self.new_surface_event = Signal( ptr=ffi.addressof(self._ptr.events.new_surface), data_wrapper=LayerSurfaceV1 diff --git a/wlroots/wlr_types/output.py b/wlroots/wlr_types/output.py index e1895147..cc4f8480 100644 --- a/wlroots/wlr_types/output.py +++ b/wlroots/wlr_types/output.py @@ -48,9 +48,11 @@ def __init__(self, ptr) -> None: self.commit_event = Signal(ptr=ffi.addressof(self._ptr.events.commit)) self.present_event = Signal(ptr=ffi.addressof(self._ptr.events.present)) self.bind_event = Signal(ptr=ffi.addressof(self._ptr.events.bind)) - self.enable_event = Signal(ptr=ffi.addressof(self._ptr.events.enable)) - self.mode_event = Signal(ptr=ffi.addressof(self._ptr.events.mode)) self.description_event = Signal(ptr=ffi.addressof(self._ptr.events.description)) + self.request_state_event = Signal( + ptr=ffi.addressof(self._ptr.events.request_state), + data_wrapper=OutputEventRequestState, + ) self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) @property @@ -138,13 +140,15 @@ def set_mode(self, mode: OutputMode | None) -> None: """ lib.wlr_output_set_mode(self._ptr, ptr_or_null(mode)) - def set_custom_mode(self, width: int, height: int, refresh: int) -> None: + def set_custom_mode(self, custom_mode: CustomMode) -> None: """ Sets a custom mode on the output. If modes are available, they are preferred. Setting `refresh` to zero lets the backend pick a preferred value. The output needs to be enabled. """ - lib.wlr_output_set_custom_mode(self._ptr, width, height, refresh) + lib.wlr_output_set_custom_mode( + self._ptr, custom_mode.width, custom_mode.height, custom_mode.refresh + ) def create_global(self) -> None: """Create the global corresponding to the output""" @@ -341,54 +345,49 @@ class OutputState(Ptr): def __init__(self, ptr: ffi.CData | None = None) -> None: if ptr is None: ptr = ffi.new("struct wlr_output_state *") + lib.wlr_output_state_init(ptr) self._ptr = ptr @property def enabled(self) -> bool: return self._ptr.enabled - @enabled.setter - def enabled(self, enabled: bool) -> None: + def set_enabled(self, enabled: bool) -> None: lib.wlr_output_state_set_enabled(self._ptr, enabled) @property def scale(self) -> float: return self._ptr.scale - @scale.setter - def scale(self, scale: float) -> None: + def set_scale(self, scale: float) -> None: lib.wlr_output_state_set_scale(self._ptr, scale) @property def transform(self) -> WlOutput.transform: return WlOutput.transform(self._ptr.transform) - @transform.setter - def transform(self, transform: WlOutput.transform) -> None: + def set_transform(self, transform: WlOutput.transform) -> None: lib.wlr_output_state_set_transform(self._ptr, transform) @property def adaptive_sync_enabled(self) -> bool: return self._ptr.adaptive_sync_enabled - @adaptive_sync_enabled.setter - def adaptive_sync_enabled(self, enabled: bool) -> None: + def set_adaptive_sync_enabled(self, enabled: bool) -> None: lib.wlr_output_state_set_adaptive_sync_enabled(self._ptr, enabled) @property def render_format(self) -> int: return self._ptr.render_format - @render_format.setter - def render_format(self, format: int) -> None: + def set_render_format(self, format: int) -> None: lib.wlr_output_state_set_render_format(self._ptr, format) @property def subpixel(self) -> WlOutput.subpixel: return WlOutput.subpixel(self._ptr.subpixel) - @subpixel.setter - def subpixel(self, subpixel: WlOutput.subpixel) -> None: + def set_subpixel(self, subpixel: WlOutput.subpixel) -> None: lib.wlr_output_state_set_subpixel(self._ptr, subpixel) @property @@ -396,8 +395,7 @@ def mode(self) -> OutputMode | None: mode_ptr = self._ptr.mode return OutputMode(mode_ptr) if mode_ptr != ffi.NULL else None - @mode.setter - def mode(self, mode: OutputMode | None) -> None: + def set_mode(self, mode: OutputMode | None) -> None: lib.wlr_output_state_set_mode(self._ptr, ptr_or_null(mode)) @property @@ -405,8 +403,23 @@ def custom_mode(self) -> CustomMode: mode = self._ptr.custom_mode return CustomMode(width=mode.width, height=mode.height, refresh=mode.refresh) - @custom_mode.setter - def custom_mode(self, mode: CustomMode) -> None: + def set_custom_mode(self, mode: CustomMode) -> None: lib.wlr_output_state_set_custom_mode( self._ptr, mode.width, mode.height, mode.refresh ) + + def finish(self) -> None: + lib.wlr_output_state_finish(self._ptr) + + +class OutputEventRequestState(Ptr): + def __init__(self, ptr) -> None: + self._ptr = ffi.cast("struct wlr_output_event_request_state *", ptr) + + @property + def output(self) -> Output: + return Output(self._ptr.output) + + @property + def state(self) -> OutputState: + return OutputState(self._ptr.state) diff --git a/wlroots/wlr_types/output_damage.py b/wlroots/wlr_types/output_damage.py deleted file mode 100644 index 9d58bedf..00000000 --- a/wlroots/wlr_types/output_damage.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (c) Matt Colligan 2021 - -from pywayland.server import Signal - -from wlroots import Ptr, ffi, lib -from wlroots.util.box import Box -from wlroots.util.region import PixmanRegion32 - -from .output import Output - - -class OutputDamage(Ptr): - def __init__(self, output: Output) -> None: - """ - Tracks damage for an output. - - The `frame` event will be emitted when it is a good time for the compositor - to submit a new frame. - - To render a new frame, compositors should call - `wlr_output_damage_attach_render`, render and call `wlr_output_commit`. No - rendering should happen outside a `frame` event handler or before - `wlr_output_damage_attach_render`. - """ - self._ptr = lib.wlr_output_damage_create(output._ptr) - - self.frame_event = Signal(ptr=ffi.addressof(self._ptr.events.frame)) - self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) - - @property - def output(self) -> Output: - """The name of the output""" - return Output(self._ptr.output) - - @property - def current(self) -> PixmanRegion32: - return PixmanRegion32(ffi.addressof(self._ptr.current)) - - def destroy(self) -> None: - """The name of the output""" - lib.wlr_output_damage_destroy(self._ptr) - self._ptr = None - - def attach_render(self, damage: PixmanRegion32) -> bool: - """ - Attach the renderer's buffer to the output. Compositors must call this - function before rendering. After they are done rendering, they should call - `wlr_output_set_damage` and `wlr_output_commit` to submit the new frame. - - `needs_frame` will be set to true if a frame should be submitted. `damage` - will be set to the region of the output that needs to be repainted, in - output-buffer-local coordinates. - - The buffer damage region accumulates all damage since the buffer has last - been swapped. This is not to be confused with the output surface damage, - which only contains the changes between two frames. - - Returns a bool specifying whether the output needs a new frame rendered. - """ - needs_frame_ptr = ffi.new("bool *") - if not lib.wlr_output_damage_attach_render( - self._ptr, needs_frame_ptr, damage._ptr - ): - raise RuntimeError("Rendering on output failed") - - return needs_frame_ptr[0] - - def add(self, damage: PixmanRegion32) -> None: - """Accumulates damage and schedules a `frame` event.""" - lib.wlr_output_damage_add(self._ptr, damage._ptr) - - def add_whole(self) -> None: - """Damages the whole output and schedules a `frame` event.""" - lib.wlr_output_damage_add_whole(self._ptr) - - def add_box(self, box: Box) -> None: - """Accumulates damage from a box and schedules a `frame` event.""" - lib.wlr_output_damage_add_box(self._ptr, box._ptr) diff --git a/wlroots/wlr_types/output_layout.py b/wlroots/wlr_types/output_layout.py index a7bf3a73..ae40dadf 100644 --- a/wlroots/wlr_types/output_layout.py +++ b/wlroots/wlr_types/output_layout.py @@ -31,19 +31,19 @@ def destroy(self) -> None: ffi.release(self._ptr) self._ptr = None - def add_auto(self, output: Output) -> None: - """Add an auto configured output to the layout - - This will place the output in a sensible location in the layout. The - coordinates of the output in the layout may adjust dynamically when the - layout changes. If the output is already in the layout, it will become - auto configured. If the position of the output is set such as with - `wlr_output_layout_move()`, the output will become manually configured. + def add_auto(self, output: Output) -> OutputLayoutOutput | None: + """ + Add the output to the layout as automatically configured. This will place the + output in a sensible location in the layout. The coordinates of the output in + the layout will be adjusted dynamically when the layout changes. If the output + is already a part of the layout, it will become automatically configured. - :param output: - The output to configure the layout against. + Returns true on success, false on a memory allocation error. """ - lib.wlr_output_layout_add_auto(self._ptr, output._ptr) + ptr = lib.wlr_output_layout_add_auto(self._ptr, output._ptr) + if ptr == ffi.NULL: + return None + return OutputLayoutOutput(ptr) def output_coords(self, output: Output) -> tuple[float, float]: """Determine coordinates of the output in the layout @@ -75,16 +75,16 @@ def output_at(self, x: float, y: float) -> Output | None: return None return Output(output_ptr) - def add(self, output: Output, lx: int, ly: int) -> None: + def add(self, output: Output, lx: int, ly: int) -> OutputLayoutOutput | None: """ Add the output to the layout at the specified coordinates. If the output is - already part of the output layout, this moves the output. + already a part of the output layout, it will become manually configured and will + be moved to the specified coordinates. """ - lib.wlr_output_layout_add(self._ptr, output._ptr, lx, ly) - - def move(self, output: Output, lx: int, ly: int) -> None: - """Move an output to specified coordinates.""" - lib.wlr_output_layout_move(self._ptr, output._ptr, lx, ly) + ptr = lib.wlr_output_layout_add(self._ptr, output._ptr, lx, ly) + if ptr == ffi.NULL: + return None + return OutputLayoutOutput(ptr) def remove(self, output: Output) -> None: """Remove an output from the layout.""" @@ -127,3 +127,9 @@ def closest_point( self._ptr, reference_ptr, lx, ly, dest_lx, dest_ly ) return dest_lx[0], dest_ly[0] + + +class OutputLayoutOutput(Ptr): + def __init__(self, ptr) -> None: + """A `struct wlr_output_layout_output`""" + self._ptr = ptr diff --git a/wlroots/wlr_types/scene.py b/wlroots/wlr_types/scene.py index d34951cc..3972e700 100644 --- a/wlroots/wlr_types/scene.py +++ b/wlroots/wlr_types/scene.py @@ -5,14 +5,19 @@ import enum from typing import TYPE_CHECKING, Callable, TypeVar +from pywayland.utils import wl_list_for_each + from wlroots import Ptr, PtrHasData, ffi, lib from wlroots.util.region import PixmanRegion32 -from wlroots.wlr_types import Surface +from wlroots.wlr_types import OutputLayoutOutput, Surface if TYPE_CHECKING: + from typing import Iterator + from wlroots.util.box import Box from wlroots.util.clock import Timespec from wlroots.wlr_types import Buffer, Output, OutputLayout + from wlroots.wlr_types.data_device_manager import DragIcon from wlroots.wlr_types.layer_shell_v1 import LayerSurfaceV1 from wlroots.wlr_types.presentation_time import Presentation from wlroots.wlr_types.xdg_shell import XdgSurface @@ -35,9 +40,14 @@ def tree(self) -> SceneTree: ptr = ffi.addressof(self._ptr.tree) return SceneTree(ptr) - def attach_output_layout(self, output_layout: OutputLayout) -> bool: - """Get a scene-graph output from a wlr_output.""" - return lib.wlr_scene_attach_output_layout(self._ptr, output_layout._ptr) + def attach_output_layout( + self, output_layout: OutputLayout + ) -> SceneOutputLayout | None: + """Attach an output layout to a scene.""" + ptr = lib.wlr_scene_attach_output_layout(self._ptr, output_layout._ptr) + if ptr == ffi.NULL: + return None + return SceneOutputLayout(ptr) def set_presentation(self, presentation: Presentation) -> None: """ @@ -90,9 +100,11 @@ def create(cls, scene: Scene, output: Output) -> SceneOutput: """ return cls(lib.wlr_scene_output_create(scene._ptr, output._ptr)) - def commit(self) -> bool: + def commit(self, options: SceneOutputStateOptions | None = None) -> bool: """Render and commit an output.""" - return lib.wlr_scene_output_commit(self._ptr) + options_ptr = options._ptr if options is not None else ffi.NULL + + return lib.wlr_scene_output_commit(self._ptr, options_ptr) def destroy(self) -> None: """Destroy a scene-graph output.""" @@ -133,6 +145,20 @@ def subsurface_tree_create(cls, parent: SceneTree, surface: Surface) -> SceneTre lib.wlr_scene_subsurface_tree_create(parent._ptr, surface._ptr) ) + @classmethod + def drag_icon_create(cls, parent: SceneTree, drag_icon: DragIcon) -> SceneTree: + return SceneTree(lib.wlr_scene_drag_icon_create(parent._ptr, drag_icon._ptr)) + + @property + def children(self) -> Iterator[SceneNode]: + for ptr in wl_list_for_each( + "struct wlr_scene_node *", + self._ptr.children, + "link", + ffi=ffi, + ): + yield SceneNode(ptr) + class SceneBuffer(Ptr): def __init__(self, ptr) -> None: @@ -169,6 +195,10 @@ def set_buffer_with_damage( region_ptr = region._ptr if region else ffi.NULL lib.wlr_scene_buffer_set_buffer_with_damage(self._ptr, buffer_ptr, region_ptr) + def set_opacity(self, opacity: float) -> None: + """Sets the opacity of this buffer""" + lib.wlr_scene_buffer_set_opacity(self._ptr, opacity) + T = TypeVar("T") BufferCallback = Callable[[SceneBuffer, int, int, T], None] @@ -272,6 +302,17 @@ def for_each_buffer( self._ptr, lib.buffer_iterator_callback, handle ) + def subsurface_tree_set_clip(self, clip: Box | None): + """ + Sets a cropping region for any subsurface trees that are children of this scene node. + + A None value will disable clipping + """ + clip_ptr = ffi.NULL + if clip is not None: + clip_ptr = clip._ptr + lib.wlr_scene_subsurface_tree_set_clip(self._ptr, clip_ptr) + class SceneSurface(Ptr): def __init__(self, ptr) -> None: @@ -280,7 +321,7 @@ def __init__(self, ptr) -> None: @classmethod def from_buffer(cls, buffer: SceneBuffer) -> SceneSurface | None: - ptr = lib.wlr_scene_surface_from_buffer(buffer._ptr) + ptr = lib.wlr_scene_surface_try_from_buffer(buffer._ptr) if ptr == ffi.NULL: return None return cls(ptr) @@ -335,3 +376,23 @@ def configure(self, full_area: Box, usable_area: Box) -> None: lib.wlr_scene_layer_surface_v1_configure( self._ptr, full_area._ptr, usable_area._ptr ) + + +class SceneOutputLayout(Ptr): + def __init__(self, ptr) -> None: + """A `struct wlr_scene_output_layout_scene`""" + self._ptr = ptr + + def add_output( + self, output_layout_output: OutputLayoutOutput, scene_output: SceneOutput + ) -> None: + """Add an output to the scene output layout.""" + lib.wlr_scene_output_layout_add_output( + self._ptr, output_layout_output._ptr, scene_output._ptr + ) + + +class SceneOutputStateOptions(Ptr): + def __init__(self, ptr) -> None: + """A `struct wlr_scene_output_state_options`.""" + self._ptr = ptr diff --git a/wlroots/wlr_types/seat.py b/wlroots/wlr_types/seat.py index 43de0ec3..b0ecf8c7 100644 --- a/wlroots/wlr_types/seat.py +++ b/wlroots/wlr_types/seat.py @@ -2,7 +2,6 @@ from __future__ import annotations -import warnings from typing import Iterator from weakref import WeakKeyDictionary @@ -118,13 +117,11 @@ def keyboard_state(self) -> SeatKeyboardState: _weakkeydict[keyboard_state_ptr] = self._ptr return SeatKeyboardState(keyboard_state_ptr) - @property - def keyboard(self) -> Keyboard | None: + def get_keyboard(self) -> Keyboard | None: """Get the active keyboard for the seat.""" return instance_or_none(Keyboard, lib.wlr_seat_get_keyboard(self._ptr)) - @keyboard.setter - def keyboard(self, keyboard: Keyboard | None) -> None: + def set_keyboard(self, keyboard: Keyboard | None) -> None: """Set this keyboard as the active keyboard for the seat""" lib.wlr_seat_set_keyboard(self._ptr, ptr_or_null(keyboard)) @@ -233,21 +230,6 @@ def pointer_has_grab(self) -> bool: """Whether or not the pointer has a grab other than the default grab""" return lib.wlr_seat_pointer_has_grab(self._ptr) - def set_keyboard(self, keyboard: Keyboard | None) -> None: - """Set this keyboard as the active keyboard for the seat - - Deprecated: Use the keyboard property. - - :param keyboard: - The keyboard to set as active. - """ - warnings.warn( - "Use the keyboard property of the seat, this method will be removed in the future.", - DeprecationWarning, - stacklevel=1, - ) - self.keyboard = keyboard - def grab(self) -> KeyboardGrab: """Start a grab of the keyboard of this seat""" return KeyboardGrab(self) diff --git a/wlroots/wlr_types/session_lock_v1.py b/wlroots/wlr_types/session_lock_v1.py index fa7e77b2..6c25d6f6 100644 --- a/wlroots/wlr_types/session_lock_v1.py +++ b/wlroots/wlr_types/session_lock_v1.py @@ -97,7 +97,7 @@ def configure(self, width: int, height: int) -> int: return lib.wlr_session_lock_surface_v1_configure(self._ptr, width, height) @staticmethod - def from_surface(surface: Surface) -> SessionLockSurfaceV1 | None: + def try_from_surface(surface: Surface) -> SessionLockSurfaceV1 | None: """ Get a SessionLockSurfaceV1 from a surface. @@ -105,12 +105,5 @@ def from_surface(surface: Surface) -> SessionLockSurfaceV1 | None: May return None even if the surface has the session lock surface role if the corresponding session lock surface has been destroyed. """ - surface_ptr = lib.wlr_session_lock_surface_v1_from_wlr_surface(surface._ptr) + surface_ptr = lib.wlr_session_lock_surface_v1_try_from_wlr_surface(surface._ptr) return SessionLockSurfaceV1(surface_ptr) if surface_ptr != ffi.NULL else None - - -def surface_is_session_lock_surface_v1(surface: Surface) -> bool: - """ - Returns true if the surface has the session lock surface role. - """ - return lib.wlr_surface_is_session_lock_surface_v1(surface._ptr) diff --git a/wlroots/wlr_types/surface.py b/wlroots/wlr_types/surface.py deleted file mode 100644 index 31a47dff..00000000 --- a/wlroots/wlr_types/surface.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright Sean Vig (c) 2020 -# -# The contents of this module has been moved to compositor.py for wlroots 0.16.0 and -# this file will be removed in the future. - -import warnings - -from wlroots.wlr_types.compositor import * # noqa: F403 - -warnings.warn( - "wlroots.wlr_types.surface has moved to wlroots.wlr_types.compositor and will be removed in the future.", - DeprecationWarning, - stacklevel=1, -) diff --git a/wlroots/wlr_types/xcursor_manager.py b/wlroots/wlr_types/xcursor_manager.py index f83eb7c5..98663a87 100644 --- a/wlroots/wlr_types/xcursor_manager.py +++ b/wlroots/wlr_types/xcursor_manager.py @@ -6,19 +6,20 @@ from wlroots import Ptr, ffi, lib -from .cursor import Cursor - if TYPE_CHECKING: from typing import Iterator class XCursorManager(Ptr): - def __init__(self, size, scale=1): - """Creates a new XCursor manager + def __init__(self, theme: str | None, size: int = 24, scale: float = 1.0): + """Creates a new XCursor manager using the theme and size - Create cursor with base size and scale. + and ensures an xcursor with scale is loaded """ - ptr = lib.wlr_xcursor_manager_create(ffi.NULL, size) + theme_ptr = ffi.NULL + if theme is not None: + theme_ptr = theme.encode() + ptr = lib.wlr_xcursor_manager_create(theme_ptr, size) self._ptr = ffi.gc(ptr, lib.wlr_xcursor_manager_destroy) lib.wlr_xcursor_manager_load(self._ptr, scale) @@ -29,17 +30,6 @@ def destroy(self): ffi.release(self._ptr) self._ptr = None - def set_cursor_image(self, name: str, cursor: Cursor): - """Set the cursor image - - Set a Cursor image to the specified cursor name for all scale factors. - The wlroots cursor will take over from this point and ensure the - correct cursor is used on each output, assuming an output layout is - attached to it. - """ - name_cdata = ffi.new("char []", name.encode()) - lib.wlr_xcursor_manager_set_cursor_image(self._ptr, name_cdata, cursor._ptr) - def get_xcursor(self, name: str, scale: float = 1) -> XCursor | None: """ Retrieves a wlr_xcursor reference for the given cursor name at the given scale diff --git a/wlroots/wlr_types/xdg_decoration_v1.py b/wlroots/wlr_types/xdg_decoration_v1.py index d0f09ef0..53b04b99 100644 --- a/wlroots/wlr_types/xdg_decoration_v1.py +++ b/wlroots/wlr_types/xdg_decoration_v1.py @@ -10,7 +10,7 @@ from wlroots import PtrHasData, ffi, lib -from .compositor import Surface +from .xdg_shell import XdgToplevel if TYPE_CHECKING: from pywayland.server import Display @@ -53,10 +53,10 @@ def __init__(self, ptr) -> None: ) @property - def surface(self) -> Surface: - surface_ptr = self._ptr.surface - _weakkeydict[surface_ptr] = self._ptr - return Surface(surface_ptr) + def toplevel(self) -> XdgToplevel: + toplevel_ptr = self._ptr.toplevel + _weakkeydict[toplevel_ptr] = self._ptr + return XdgToplevel(toplevel_ptr) @property def manager(self) -> XdgDecorationManagerV1: diff --git a/wlroots/wlr_types/xdg_shell.py b/wlroots/wlr_types/xdg_shell.py index 27742afa..5cba883a 100644 --- a/wlroots/wlr_types/xdg_shell.py +++ b/wlroots/wlr_types/xdg_shell.py @@ -35,7 +35,7 @@ class XdgSurfaceRole(enum.IntEnum): POPUP = lib.WLR_XDG_SURFACE_ROLE_POPUP -class XdgTopLevelWMCapabilities(enum.IntFlag): +class XdgToplevelWMCapabilities(enum.IntFlag): WINDOW_MENU = lib.WLR_XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU MAXIMIZE = lib.WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE FULLSCREEN = lib.WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN @@ -72,8 +72,6 @@ def __init__(self, ptr) -> None: """ self._ptr = ffi.cast("struct wlr_xdg_surface *", ptr) - self.map_event = Signal(ptr=ffi.addressof(self._ptr.events.map)) - self.unmap_event = Signal(ptr=ffi.addressof(self._ptr.events.unmap)) self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) self.new_popup_event = Signal( ptr=ffi.addressof(self._ptr.events.new_popup), data_wrapper=XdgPopup @@ -88,12 +86,12 @@ def __init__(self, ptr) -> None: ) @staticmethod - def from_surface(surface: Surface) -> XdgSurface: + def try_from_surface(surface: Surface) -> XdgSurface | None: """Get the xdg surface associated with the given surface""" - if not surface.is_xdg_surface: - raise RuntimeError("Surface is not XDG surface") - surface_ptr = lib.wlr_xdg_surface_from_wlr_surface(surface._ptr) - return XdgSurface(surface_ptr) + maybe_ptr = lib.wlr_xdg_surface_try_from_wlr_surface(surface._ptr) + if maybe_ptr == ffi.NULL: + return None + return XdgSurface(maybe_ptr) @property def surface(self) -> Surface: @@ -106,15 +104,15 @@ def role(self) -> XdgSurfaceRole: return XdgSurfaceRole(self._ptr.role) @property - def toplevel(self) -> XdgTopLevel: + def toplevel(self) -> XdgToplevel: """Return the top level xdg object This shell must be a top level role """ if self.role != XdgSurfaceRole.TOPLEVEL: - raise ValueError(f"xdg surface must be top-level, got: {self.role}") + raise ValueError(f"xdg surface must be top-level, got: {self.role.name}") - toplevel = XdgTopLevel(self._ptr.toplevel) + toplevel = XdgToplevel(self._ptr.toplevel) # the toplevel does not own the ptr data, ensure the underlying cdata # is kept alive @@ -153,7 +151,7 @@ def set_size(self, width: int, height: int) -> int: def set_activated(self, activated: bool) -> int: if self.role != XdgSurfaceRole.TOPLEVEL: - raise ValueError(f"xdg surface must be top-level, got: {self.role}") + raise ValueError(f"xdg surface must be top-level, got: {self.role.name}") return lib.wlr_xdg_toplevel_set_activated(self._ptr.toplevel, activated) @@ -172,7 +170,7 @@ def set_tiled(self, tiled_edges: int) -> int: def set_bounds(self, width: int, height: int) -> int: return lib.wlr_xdg_toplevel_set_bounds(self._ptr.toplevel, width, height) - def set_wm_capabilities(self, caps: XdgTopLevelWMCapabilities) -> int: + def set_wm_capabilities(self, caps: XdgToplevelWMCapabilities) -> int: return lib.wlr_xdg_toplevel_set_wm_capabilities(self._ptr.toplevel, caps) def send_close(self) -> int: @@ -238,7 +236,7 @@ def serial(self) -> int: return self._ptr.serial -class XdgTopLevel(Ptr): +class XdgToplevel(Ptr): def __init__(self, ptr) -> None: """A top level surface object @@ -258,27 +256,32 @@ def __init__(self, ptr) -> None: ) self.request_move_event = Signal( ptr=ffi.addressof(self._ptr.events.request_move), - data_wrapper=XdgTopLevelMoveEvent, + data_wrapper=XdgToplevelMoveEvent, ) self.request_resize_event = Signal( ptr=ffi.addressof(self._ptr.events.request_resize), - data_wrapper=XdgTopLevelResizeEvent, + data_wrapper=XdgToplevelResizeEvent, ) self.request_show_window_menu_event = Signal( ptr=ffi.addressof(self._ptr.events.request_show_window_menu), - data_wrapper=XdgTopLevelShowWindowMenuEvent, + data_wrapper=XdgToplevelShowWindowMenuEvent, ) self.set_parent_event = Signal(ptr=ffi.addressof(self._ptr.events.set_parent)) self.set_title_event = Signal(ptr=ffi.addressof(self._ptr.events.set_title)) self.set_app_id_event = Signal(ptr=ffi.addressof(self._ptr.events.set_app_id)) @property - def parent(self) -> XdgTopLevel | None: + def base(self) -> XdgSurface: + """The XDG surface associated with this toplevel""" + return XdgSurface(self._ptr.base) + + @property + def parent(self) -> XdgToplevel | None: """The parent of this toplevel""" parent_ptr = self._ptr.parent if parent_ptr == ffi.NULL: return None - return XdgTopLevel(parent_ptr) + return XdgToplevel(parent_ptr) @property def title(self) -> str | None: @@ -291,19 +294,19 @@ def app_id(self) -> str | None: return str_or_none(self._ptr.app_id) @property - def requested(self) -> XdgTopLevelRequested: + def requested(self) -> XdgToplevelRequested: """Requested initial state""" - return XdgTopLevelRequested(self._ptr.requested) + return XdgToplevelRequested(self._ptr.requested) -class XdgTopLevelMoveEvent(Ptr): +class XdgToplevelMoveEvent(Ptr): def __init__(self, ptr) -> None: self._ptr = ffi.cast("struct wlr_xdg_toplevel_move_event *", ptr) @property - def toplevel(self) -> XdgTopLevel: + def toplevel(self) -> XdgToplevel: # TODO: keep weakref - return XdgTopLevel(self._ptr.toplevel) + return XdgToplevel(self._ptr.toplevel) # TODO: seat client @@ -312,14 +315,14 @@ def serial(self) -> int: return self._ptr.serial -class XdgTopLevelResizeEvent(Ptr): +class XdgToplevelResizeEvent(Ptr): def __init__(self, ptr) -> None: self._ptr = ffi.cast("struct wlr_xdg_toplevel_resize_event *", ptr) @property - def toplevel(self) -> XdgTopLevel: + def toplevel(self) -> XdgToplevel: # TODO: keep weakref - return XdgTopLevel(self._ptr.toplevel) + return XdgToplevel(self._ptr.toplevel) # TODO: seat client @@ -332,14 +335,14 @@ def edges(self) -> Edges: return self._ptr.edges -class XdgTopLevelShowWindowMenuEvent(Ptr): +class XdgToplevelShowWindowMenuEvent(Ptr): def __init__(self, ptr) -> None: self._ptr = ffi.cast("struct wlr_xdg_toplevel_show_window_menu_event *", ptr) @property - def toplevel(self) -> XdgTopLevel: + def toplevel(self) -> XdgToplevel: # TODO: keep weakref - return XdgTopLevel(self._ptr.toplevel) + return XdgToplevel(self._ptr.toplevel) # TODO: seat client @@ -422,7 +425,7 @@ def reactive(self) -> bool: return self._ptr.reactive -class XdgTopLevelRequested(Ptr): +class XdgToplevelRequested(Ptr): def __init__(self, ptr) -> None: self._ptr = ptr diff --git a/wlroots/xwayland.py b/wlroots/xwayland.py index e5c052d0..c6853a87 100644 --- a/wlroots/xwayland.py +++ b/wlroots/xwayland.py @@ -71,6 +71,10 @@ def __init__(self, display: Display, options: ServerOptions) -> None: self.ready_event = Signal(ptr=ffi.addressof(self._ptr.events.ready)) self.destroy_event = Signal(ptr=ffi.addressof(self._ptr.events.destroy)) + @property + def ready(self) -> bool: + return self._ptr.ready + class XWayland(PtrHasData): def __init__(self, display: Display, compositor: Compositor, lazy: bool) -> None: @@ -172,13 +176,12 @@ def __init__(self, ptr) -> None: self.request_activate_event = Signal( ptr=ffi.addressof(self._ptr.events.request_activate) ) - self.map_event = Signal(ptr=ffi.addressof(self._ptr.events.map)) - self.unmap_event = Signal(ptr=ffi.addressof(self._ptr.events.unmap)) + self.associate_event = Signal(ptr=ffi.addressof(self._ptr.events.associate)) + self.dissociate_event = Signal(ptr=ffi.addressof(self._ptr.events.dissociate)) self.set_title_event = Signal(ptr=ffi.addressof(self._ptr.events.set_title)) self.set_class_event = Signal(ptr=ffi.addressof(self._ptr.events.set_class)) self.set_role_event = Signal(ptr=ffi.addressof(self._ptr.events.set_role)) self.set_parent_event = Signal(ptr=ffi.addressof(self._ptr.events.set_parent)) - self.set_pid_event = Signal(ptr=ffi.addressof(self._ptr.events.set_pid)) self.set_startup_id_event = Signal( ptr=ffi.addressof(self._ptr.events.set_startup_id) ) @@ -224,8 +227,11 @@ def set_fullscreen(self, fullscreen: bool) -> None: lib.wlr_xwayland_surface_set_fullscreen(self._ptr, fullscreen) @classmethod - def from_wlr_surface(cls, surface: WlrSurface) -> Surface: - return cls(lib.wlr_xwayland_surface_from_wlr_surface(surface._ptr)) + def try_from_wlr_surface(cls, surface: WlrSurface) -> Surface | None: + maybe_ptr = lib.wlr_xwayland_surface_try_from_wlr_surface(surface._ptr) + if maybe_ptr == ffi.NULL: + return None + return cls(maybe_ptr) def ping(self) -> None: lib.wlr_xwayland_surface_ping(self._ptr) @@ -237,7 +243,9 @@ def icccm_input_model(self) -> int: return lib.wlr_xwayland_icccm_input_model(self._ptr) @property - def surface(self) -> WlrSurface: + def surface(self) -> WlrSurface | None: + if self._ptr.surface == ffi.NULL: + return None return WlrSurface(self._ptr.surface) @property @@ -260,10 +268,6 @@ def height(self) -> int: def override_redirect(self) -> bool: return self._ptr.override_redirect - @property - def mapped(self) -> bool: - return self._ptr.mapped - @property def title(self) -> str | None: return str_or_none(self._ptr.title) @@ -360,7 +364,8 @@ def for_each_surface( The iterator is called using the only wlr_surface and it's local coordinates. """ - iterator(self.surface, 0, 0, data) + if surface := self.surface: + iterator(surface, 0, 0, data) class SurfaceConfigureEvent(Ptr):