diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da0928e8..4b06089e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,11 +16,11 @@ jobs: pixman-version: "0.42.0" 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.0", master] steps: - name: Install dependencies run: | @@ -147,7 +147,7 @@ jobs: - "pypy-3.8" - "pypy-3.9" - "pypy-3.10" - wlroots-version: ["0.16.2"] + wlroots-version: ["0.17.0"] include: - python-version: "3.12" wlroots-version: master @@ -262,7 +262,7 @@ jobs: needs: build-wayland env: python-version: "3.12" - wlroots-version: "0.16.2" + wlroots-version: "0.17.0" steps: - name: Download wayland libraries uses: actions/download-artifact@v3 @@ -298,7 +298,7 @@ jobs: needs: build-wayland env: python-version: "3.12" - wlroots-version: "0.16.2" + wlroots-version: "0.17.0" steps: - name: Download wayland libraries uses: actions/download-artifact@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fb637b96..d464b7d4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,9 +13,9 @@ jobs: libdrm-version: "2.4.114" seatd-version: "0.6.3" pixman-version: "0.42.0" - wayland-protocols-version: "1.31" + wayland-protocols-version: "1.32" wayland-version: "1.22.0" - wlroots-version: "0.16.2" + wlroots-version: "0.17.0" steps: - name: Install dependencies run: | diff --git a/tiny/server.py b/tiny/server.py index 18cea1ee..7422430d 100644 --- a/tiny/server.py +++ b/tiny/server.py @@ -22,9 +22,11 @@ Keyboard, Output, OutputLayout, + OutputState, Scene, SceneBuffer, SceneNodeType, + SceneOutput, SceneSurface, SceneTree, Seat, @@ -51,6 +53,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() @@ -213,7 +216,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 @@ -289,8 +292,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 @@ -322,10 +325,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 @@ -344,16 +349,24 @@ def server_new_xdg_surface(self, listener, xdg_surface: XdgSurface) -> None: # output and frame handling callbacks def server_new_output(self, listener, output: Output) -> None: + SceneOutput.create(self._scene, output) output.init_render(self._allocator, self._renderer) - output.set_mode(output.preferred_mode()) - output.enable() - output.commit() + state = OutputState() + state.set_enabled() + if mode := output.preferred_mode(): + state.set_mode(mode) + + output.commit_state(state) + state.finish() self.outputs.append(output) - self._output_layout.add_auto(output) + if not self._output_layout.add_auto(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)) def output_frame(self, listener, data) -> None: output = self.outputs[0] @@ -363,6 +376,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_state(request.state) + # ############################################################# # input handling 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 8ddf5372..4c8a4b36 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: @@ -93,7 +97,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: @@ -101,9 +107,9 @@ def is_headless(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 f5606844..71c2ad83 100644 --- a/wlroots/ffi_build.py +++ b/wlroots/ffi_build.py @@ -110,11 +110,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); """ # backend/libinput.h @@ -145,7 +145,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]); @@ -300,6 +300,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 @@ -318,7 +320,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; @@ -342,9 +344,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); ...; }; @@ -362,7 +364,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; @@ -370,13 +371,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; @@ -384,19 +389,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); @@ -457,7 +458,6 @@ def has_xwayland() -> bool: bool synchronized; bool reordered; - bool mapped; bool added; struct wl_listener surface_client_commit; @@ -465,8 +465,6 @@ def has_xwayland() -> bool: struct { struct wl_signal destroy; - struct wl_signal map; - struct wl_signal unmap; } events; void *data; @@ -478,11 +476,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); """ @@ -527,12 +520,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; ...; }; @@ -743,6 +734,7 @@ def has_xwayland() -> bool: struct { struct wl_signal destroy; + struct wl_signal set_gamma; } events; void *data; @@ -752,73 +744,6 @@ def has_xwayland() -> bool: struct wl_display *display); """ -# types/wlr_idle.h -CDEF += """ -struct wlr_idle { - struct wl_global *global; - struct wl_list idle_timers; // wlr_idle_timeout::link - struct wl_event_loop *event_loop; - bool enabled; - - 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; - } 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); -""" - # types/wlr_input_inhibit_v1.h CDEF += """ struct wlr_idle_inhibit_manager_v1 { @@ -963,11 +888,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; @@ -1015,7 +942,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 @@ -1102,13 +1029,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; @@ -1117,27 +1050,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); @@ -1165,55 +1107,23 @@ def has_xwayland() -> bool: bool wlr_output_test(struct wlr_output *output); bool wlr_output_commit(struct wlr_output *output); void wlr_output_rollback(struct wlr_output *output); +bool wlr_output_commit_state(struct wlr_output *output, + const struct wlr_output_state *state); void wlr_output_render_software_cursors(struct wlr_output *output, struct pixman_region32 *damage); enum wl_output_transform wlr_output_transform_invert( enum wl_output_transform tr); -""" - -# 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); +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, + struct wlr_output_mode *mode); +void wlr_output_state_set_custom_mode(struct wlr_output_state *state, + int32_t width, int32_t height, int32_t refresh); """ # types/wlr_output_layout.h @@ -1240,10 +1150,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, @@ -1252,7 +1159,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, @@ -1729,7 +1636,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( @@ -1790,9 +1697,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; @@ -1821,6 +1729,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); @@ -1860,7 +1772,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, @@ -1894,6 +1806,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); @@ -1902,7 +1817,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); @@ -1913,7 +1829,7 @@ 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); struct wlr_scene_tree *wlr_scene_subsurface_tree_create( @@ -1928,6 +1844,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 @@ -2282,8 +2201,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); """ @@ -2315,6 +2232,7 @@ def has_xwayland() -> bool: struct { struct wl_signal destroy; struct wl_signal request_activate; + struct wl_signal new_token; } events; ...; }; @@ -2366,7 +2284,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 @@ -2513,7 +2431,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; @@ -2558,7 +2476,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; @@ -2606,6 +2523,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; @@ -2614,21 +2532,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 @@ -2704,9 +2621,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, @@ -2793,7 +2709,6 @@ def has_xwayland() -> bool: #include #include #include -#include #include #include #include @@ -2802,7 +2717,6 @@ def has_xwayland() -> bool: #include #include #include -#include #include #include #include @@ -2901,13 +2815,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; @@ -2915,16 +2827,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, @@ -2950,6 +2861,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; @@ -2982,6 +2896,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]; @@ -3033,15 +2948,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; @@ -3059,13 +2978,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; @@ -3076,17 +2996,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; @@ -3101,10 +3021,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; @@ -3144,8 +3060,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/renderer.py b/wlroots/renderer.py index 904f5ac2..b1f350a5 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 96f1261a..1666d18a 100644 --- a/wlroots/wlr_types/__init__.py +++ b/wlroots/wlr_types/__init__.py @@ -19,9 +19,8 @@ from .keyboard import Keyboard # noqa: F401 from .layer_shell_v1 import LayerShellV1 # noqa: F401 from .matrix import Matrix # noqa: F401 -from .output import Output # noqa: F401 -from .output_damage import OutputDamage # noqa: F401 -from .output_layout import OutputLayout # noqa: F401 +from .output import Output, OutputState # noqa: F401 +from .output_layout import OutputLayout, OutputLayoutOutput # noqa: F401 from .pointer import ( # noqa: F401 PointerAxisEvent, PointerButtonEvent, diff --git a/wlroots/wlr_types/compositor.py b/wlroots/wlr_types/compositor.py index 42d114fe..8f3232d9 100644 --- a/wlroots/wlr_types/compositor.py +++ b/wlroots/wlr_types/compositor.py @@ -19,16 +19,30 @@ from wlroots.renderer import Renderer +COMPOSITOR_VERSION = 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 version <= COMPOSITOR_VERSION: + raise ValueError( + f"Compositor version must be less than or equal to {COMPOSITOR_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 fe00c015..90ab97d1 100644 --- a/wlroots/wlr_types/cursor.py +++ b/wlroots/wlr_types/cursor.py @@ -2,11 +2,13 @@ from __future__ import annotations import enum +from typing import TYPE_CHECKING from pywayland.server import Signal from wlroots import PtrHasData, ffi, lib +from .compositor import Surface from .input_device import InputDevice, InputDeviceType from .output import Output from .output_layout import OutputLayout @@ -24,7 +26,6 @@ PointerSwipeEndEvent, PointerSwipeUpdateEvent, ) -from .surface import Surface from .touch import ( TouchEventCancel, TouchEventDown, @@ -32,6 +33,9 @@ TouchEventUp, ) +if TYPE_CHECKING: + from .xcursor_manager import XCursorManager + class WarpMode(enum.Enum): Layout = enum.auto() @@ -293,3 +297,11 @@ def map_input_to_output( output_ptr = output._ptr 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 4baf333d..ab43e6f2 100644 --- a/wlroots/wlr_types/data_device_manager.py +++ b/wlroots/wlr_types/data_device_manager.py @@ -7,7 +7,7 @@ from wlroots import Ptr, PtrHasData, ffi, lib -from .surface import Surface +from .compositor import Surface _weakkeydict: WeakKeyDictionary = WeakKeyDictionary() @@ -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/foreign_toplevel_management_v1.py b/wlroots/wlr_types/foreign_toplevel_management_v1.py index de7af312..9e132451 100644 --- a/wlroots/wlr_types/foreign_toplevel_management_v1.py +++ b/wlroots/wlr_types/foreign_toplevel_management_v1.py @@ -10,8 +10,8 @@ from wlroots import Ptr, PtrHasData, ffi, lib +from .compositor import Surface from .output import Output -from .surface import Surface if TYPE_CHECKING: from pywayland.server import Display 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/idle_inhibit_v1.py b/wlroots/wlr_types/idle_inhibit_v1.py index ee074561..93d7bf3b 100644 --- a/wlroots/wlr_types/idle_inhibit_v1.py +++ b/wlroots/wlr_types/idle_inhibit_v1.py @@ -3,7 +3,7 @@ from wlroots import Ptr, PtrHasData, ffi, lib -from .surface import Surface +from .compositor import Surface class IdleInhibitorManagerV1(Ptr): 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 2cca23a3..f696102f 100644 --- a/wlroots/wlr_types/layer_shell_v1.py +++ b/wlroots/wlr_types/layer_shell_v1.py @@ -10,8 +10,8 @@ from wlroots import Ptr, PtrHasData, ffi, lib +from .compositor import Surface from .output import Output -from .surface import Surface from .xdg_shell import SurfaceCallback, T if TYPE_CHECKING: @@ -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) @classmethod - def from_wlr_surface(cls, 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(cls, 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,16 @@ 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] +LAYER_SHELL_VERSION = 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 <= LAYER_SHELL_VERSION: + raise ValueError("Invalid layer shell 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 21fac421..7b102b9e 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 @@ -203,6 +205,10 @@ def rollback(self) -> None: """Discard the pending output state""" lib.wlr_output_rollback(self._ptr) + def commit_state(self, state: OutputState) -> bool: + """Commit requested state""" + return lib.wlr_output_commit_state(self._ptr, state._ptr) + def effective_resolution(self) -> tuple[int, int]: """Computes the transformed and scaled output resolution""" width_ptr = ffi.new("int *") @@ -300,3 +306,39 @@ def refresh_mhz(self) -> int: @property def preferred(self) -> int: return self._ptr.preferred + + +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 + + def finish(self) -> None: + lib.wlr_output_state_finish(self._ptr) + + def set_enabled(self, *, enabled: bool = True) -> None: + lib.wlr_output_state_set_enabled(self._ptr, enabled) + + def set_mode(self, mode: OutputMode | None) -> None: + if mode is None: + lib.wlr_output_state_set_mode(self._ptr, ffi.NULL) + else: + lib.wlr_output_state_set_mode(self._ptr, mode._ptr) + + def set_custom_mode(self, width: int, height: int, refresh: int) -> None: + lib.wlr_output_state_set_custom_mode(self._ptr, width, height, refresh) + + +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/pointer_constraints_v1.py b/wlroots/wlr_types/pointer_constraints_v1.py index 2c2f2f1a..98db3bb8 100644 --- a/wlroots/wlr_types/pointer_constraints_v1.py +++ b/wlroots/wlr_types/pointer_constraints_v1.py @@ -11,7 +11,7 @@ from wlroots import Ptr, ffi, lib from wlroots.util.region import PixmanRegion32 -from .surface import Surface +from .compositor import Surface if TYPE_CHECKING: from pywayland.server import Display diff --git a/wlroots/wlr_types/scene.py b/wlroots/wlr_types/scene.py index 3a99d2f9..18648293 100644 --- a/wlroots/wlr_types/scene.py +++ b/wlroots/wlr_types/scene.py @@ -7,12 +7,13 @@ 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 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 +36,14 @@ def tree(self) -> SceneTree: ptr = ffi.addressof(self._ptr.tree) return SceneTree(ptr) - def attach_output_layout(self, output_layout: OutputLayout) -> bool: + def attach_output_layout( + self, output_layout: OutputLayout + ) -> OutputLayoutOutput | None: """Get a scene-graph output from a wlr_output.""" - return lib.wlr_scene_attach_output_layout(self._ptr, output_layout._ptr) + ptr = lib.wlr_scene_attach_output_layout(self._ptr, output_layout._ptr) + if ptr == ffi.NULL: + return None + return OutputLayoutOutput(ptr) def set_presentation(self, presentation: Presentation) -> None: """ @@ -90,9 +96,11 @@ def create(cls, scene: Scene, output: Output) -> SceneOutput: """ return cls(lib.wlr_scene_output_create(scene._ptr, output._ptr)) - def commit(self) -> None: + def commit(self, options: SceneOutputStateOptions | None = None) -> None: """Render and commit an output.""" - if not lib.wlr_scene_output_commit(self._ptr): + options_ptr = options._ptr if options is not None else ffi.NULL + + if not lib.wlr_scene_output_commit(self._ptr, options_ptr): raise RuntimeError("Unable to commit scene output") def destroy(self) -> None: @@ -134,6 +142,10 @@ 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)) + class SceneBuffer(Ptr): def __init__(self, ptr) -> None: @@ -170,6 +182,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] @@ -281,7 +297,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) @@ -336,3 +352,9 @@ 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 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 a0c86670..449e1e18 100644 --- a/wlroots/wlr_types/seat.py +++ b/wlroots/wlr_types/seat.py @@ -9,11 +9,11 @@ from wlroots import Ptr, PtrHasData, ffi, lib +from .compositor import Surface from .data_device_manager import Drag from .input_device import ButtonState from .keyboard import Keyboard, KeyboardKeyEvent, KeyboardModifiers from .pointer import AxisOrientation, AxisSource -from .surface import Surface _weakkeydict: WeakKeyDictionary = WeakKeyDictionary() 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..7e43fb40 100644 --- a/wlroots/wlr_types/xcursor_manager.py +++ b/wlroots/wlr_types/xcursor_manager.py @@ -6,8 +6,6 @@ from wlroots import Ptr, ffi, lib -from .cursor import Cursor - if TYPE_CHECKING: from typing import Iterator @@ -29,17 +27,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_activation_v1.py b/wlroots/wlr_types/xdg_activation_v1.py index d92c9cce..02a7a437 100644 --- a/wlroots/wlr_types/xdg_activation_v1.py +++ b/wlroots/wlr_types/xdg_activation_v1.py @@ -9,7 +9,7 @@ from wlroots import Ptr, ffi, lib -from .surface import Surface +from .compositor import Surface if TYPE_CHECKING: from pywayland.server import Display diff --git a/wlroots/wlr_types/xdg_decoration_v1.py b/wlroots/wlr_types/xdg_decoration_v1.py index 311ff741..adfdeae2 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 .surface 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 73a5eefd..c7396bfc 100644 --- a/wlroots/wlr_types/xdg_shell.py +++ b/wlroots/wlr_types/xdg_shell.py @@ -12,8 +12,8 @@ from wlroots.util.box import Box from wlroots.util.edges import Edges +from .compositor import Surface from .output import Output -from .surface import Surface _weakkeydict: weakref.WeakKeyDictionary = weakref.WeakKeyDictionary() @@ -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: ) @classmethod - def from_surface(cls, surface: Surface) -> XdgSurface: + def try_from_surface(cls, 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: diff --git a/wlroots/xwayland.py b/wlroots/xwayland.py index 8ed51e76..c6853a87 100644 --- a/wlroots/xwayland.py +++ b/wlroots/xwayland.py @@ -8,7 +8,7 @@ from pywayland.server import Signal from wlroots import Ptr, PtrHasData, ffi, lib, str_or_none -from wlroots.wlr_types.surface import Surface as WlrSurface +from wlroots.wlr_types.compositor import Surface as WlrSurface if TYPE_CHECKING: from typing import TypeVar @@ -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):