diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-11 21:53:42 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-11 21:53:42 +0300 |
| commit | 927ae621c9a3d46dbc401b8e9ea7bbed1bf2e97b (patch) | |
| tree | aeb00c16770dcf5a36d28c1167cc39c6759059fb /src/wayland/internal.h | |
initial: Yet Another Surface Library (YASL) 0.1.0
A minimal, modern desktop window surface library in C.
Supports Wayland on Linux and Cocoa/Metal on macOS with
presentation timing, fractional scaling, IME, and CSD.
Diffstat (limited to 'src/wayland/internal.h')
| -rw-r--r-- | src/wayland/internal.h | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/src/wayland/internal.h b/src/wayland/internal.h new file mode 100644 index 0000000..dc85943 --- /dev/null +++ b/src/wayland/internal.h @@ -0,0 +1,418 @@ +#ifndef YASL_WAYLAND_INTERNAL_H +#define YASL_WAYLAND_INTERNAL_H + +#define _GNU_SOURCE + +#include "yasl/yasl.h" +#include "yasl/timing.h" +#include "clipboard.h" + +#include <wayland-client.h> +#include <wayland-cursor.h> +#include "protocols/xdg-shell-client-protocol.h" +#include "protocols/xdg-decoration-client-protocol.h" +#include "protocols/cursor-shape-v1-client-protocol.h" +#include "protocols/fractional-scale-v1-client-protocol.h" +#include "protocols/viewporter-client-protocol.h" +#include "protocols/tablet-v2-client-protocol.h" +#include "protocols/text-input-unstable-v3-client-protocol.h" +#include "protocols/tearing-control-v1-client-protocol.h" +#include "protocols/presentation-time-client-protocol.h" +#include "protocols/fifo-v1-client-protocol.h" +#include "protocols/commit-timing-v1-client-protocol.h" +#include "protocols/xdg-toplevel-drag-v1-client-protocol.h" +#include "protocols/primary-selection-unstable-v1-client-protocol.h" + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <time.h> +#include <linux/input-event-codes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/timerfd.h> +#include <unistd.h> +#include <xkbcommon/xkbcommon.h> +#include <xkbcommon/xkbcommon-keysyms.h> + +#define NBUF 3 + +struct yasl_surface; +struct tablet_tool; +struct tablet_device; +struct tablet_pad; + +struct buffer { + struct yasl_surface *owner; + struct wl_shm_pool *pool; + struct wl_buffer *proxy; + uint32_t *pixels; + size_t capacity; + int width, height; + bool busy; + bool presented; +}; + +struct wl_conn_output { + struct yasl_display *conn; + struct wl_output *proxy; + struct wl_conn_output *next; + uint64_t mask; + uint32_t name; + int32_t scale, pending_scale; + uint32_t refresh_ns, pending_refresh_ns; +}; + +struct pending_press { + struct yasl_surface *surface; + struct yasl_vector2i pos; + int button; + bool release; +}; + +struct press_queue { + struct pending_press ev[8]; + int n; +}; + +struct drag_icon { + struct wl_surface *surface; + struct wl_buffer *buffer; + struct wl_shm_pool *pool; + struct wp_viewport *viewport; + void *mapping; + size_t size; + int fd; +}; + +struct conn_drag { + struct wl_data_source *source; + struct xdg_toplevel_drag_v1 *toplevel; + struct drag_icon icon; + const struct yasl_drag_listener *listener; + void *ud; + uint32_t scale_120; + struct seat *seat; + bool dropped; + bool carrying; +}; + +#define SEAT_TOUCH_POINTS 10 + +struct touch_point { + struct yasl_surface *surface; + int32_t id; + double x, y; + bool active; + bool down, moved, up; +}; + +struct seat { + struct yasl_display *conn; + struct seat *next; + struct wl_seat *proxy; + uint32_t name; + struct wl_keyboard *keyboard; + struct wl_pointer *pointer; + struct wl_touch *touch; + struct wp_cursor_shape_device_v1 *cursor_shape_dev; + struct wl_surface *cursor_surface; + struct wp_viewport *cursor_viewport; + struct zwp_tablet_seat_v2 *tablet_seat; + struct tablet_tool *tablet_tools; + struct tablet_device *tablet_devices; + struct tablet_pad *tablet_pads; + struct zwp_text_input_v3 *text_input; + struct clipboard *clipboard; + + struct xkb_keymap *xkb_keymap; + struct xkb_state *xkb_state; + xkb_mod_mask_t input_mod_masks[8]; + xkb_mod_index_t mod_shift, mod_alt, mod_ctrl, mod_super; + bool input_mods_ready; + uint64_t repeat_started_ns; + int repeat_fd, repeat_watch; + int32_t repeat_rate, repeat_delay; + uint32_t repeat_key; + bool repeat_held; + + struct yasl_surface *pointer_focus; + struct yasl_surface *keyboard_focus; + struct yasl_surface *tablet_focus; + struct yasl_surface *ime_focus; + struct yasl_surface *focus_leaving; + uint32_t input_serial; + uint32_t press_serial; + struct yasl_surface *press_surface; + + uint32_t pointer_serial; + int cursor_shape; + struct yasl_vector2i pointer_pos; + uint64_t pointer_buttons; + double axis_v, axis_h, frame_v; + int frame_v120; + int axis_discrete_v, axis_discrete_h; + int axis_value120_v, axis_value120_h; + bool axis_has_v120_v, axis_has_v120_h; + bool axis_smooth; + bool motion_pending; + struct press_queue ptr_presses; + struct yasl_surface *ptr_left; + struct yasl_vector2i ptr_left_pos; + bool ptr_left_motion; + + struct tablet_tool *tool; + struct press_queue tool_presses; + struct yasl_vector2i tool_pos; + uint64_t tool_buttons; + struct yasl_pointer_pen pen; + int tool_wheel; + bool tool_motion; + + struct touch_point touch_points[SEAT_TOUCH_POINTS]; + struct touch_point *touch_primary; + bool touch_pressed; + bool touch_scrolling; + double touch_scroll_y, touch_scroll_rest; +}; + +#define YASL_QUEUE_CAP 256 +struct input_queue { + struct yasl_input_event events[YASL_QUEUE_CAP]; + int head; + int tail; + int count; +}; + +static inline void input_queue_push(struct input_queue *q, const struct yasl_input_event *ev) +{ + if (q->count >= YASL_QUEUE_CAP) return; + q->events[q->tail] = *ev; + q->tail = (q->tail + 1) % YASL_QUEUE_CAP; + q->count++; +} + +static inline bool input_queue_pop(struct input_queue *q, struct yasl_input_event *ev) +{ + if (q->count <= 0) return false; + *ev = q->events[q->head]; + q->head = (q->head + 1) % YASL_QUEUE_CAP; + q->count--; + return true; +} + +static inline void input_queue_clear(struct input_queue *q) +{ + q->head = q->tail = q->count = 0; +} + +struct yasl_display { + struct wl_display *wl; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_shm *shm; + struct wl_conn_output *outputs; + uint64_t output_masks; + struct xdg_wm_base *wm_base; + struct zxdg_decoration_manager_v1 *decor_mgr; + struct wp_fractional_scale_manager_v1 *scale_mgr; + struct wp_viewporter *viewporter; + struct seat *seats; + struct seat *active_seat; + struct wl_data_device_manager *data_manager; + struct zwp_primary_selection_device_manager_v1 *primary_selection_mgr; + struct wp_cursor_shape_manager_v1 *cursor_shape_mgr; + struct wl_cursor_theme *cursor_theme; + const char *cursor_theme_name; + int cursor_size, cursor_theme_scale; + struct zwp_tablet_manager_v2 *tablet_mgr; + struct zwp_text_input_manager_v3 *text_input_mgr; + struct wp_tearing_control_manager_v1 *tearing_mgr; + struct wp_presentation *presentation; + struct wp_fifo_manager_v1 *fifo_mgr; + struct wp_commit_timing_manager_v1 *commit_timing_mgr; + struct xkb_context *xkb_ctx; + struct yasl_loop *loop; + const struct yasl_display_cbs *cbs; + void *ud; + char *app_id; + clockid_t pres_clock; + bool pres_clock_known; + struct xdg_toplevel_drag_manager_v1 *toplevel_drag_mgr; + struct conn_drag drag; + struct yasl_surface *surfaces; + struct yasl_surface *paste_target; + int watch; + int depth; + struct yasl_surface *dead; + bool reading; + bool lost; +}; + +struct yasl_surface { + struct yasl_display *conn; + struct yasl_surface *conn_next; + struct yasl_surface *dead_next; + struct yasl_surface *parent; + struct wl_surface *surface; + struct xdg_surface *xdg_surface; + struct xdg_toplevel *toplevel; + struct xdg_popup *popup; + struct zxdg_toplevel_decoration_v1 *toplevel_decor; + bool server_decorated; + struct wp_fractional_scale_v1 *frac_scale; + struct wp_viewport *viewport; + + char *ime_preedit; + char *ime_commit; + char *ime_shown; + int ime_cursor_begin, ime_cursor_end; + int ime_shown_begin, ime_shown_end; + struct yasl_rect2i ime_caret; + struct seat *ime_seat; + struct wp_tearing_control_v1 *tearing_control; + struct latency_feedback *latency_feedbacks; + struct wp_fifo_v1 *fifo; + struct wp_commit_timer_v1 *commit_timer; + struct wl_callback *frame_cb; + const struct yasl_surface_cbs *cbs; + void *ud; + uint64_t frames_skipped; + + struct yasl_frame_clock clock; + struct input_queue input; + + struct buffer buffers[NBUF]; + struct yasl_frame frame; + struct yasl_damage_list damage; + bool frame_active; + bool frame_presented; + + int floating_width, floating_height; + struct yasl_rect2i content; + int cur; + int width, height; + int logical_width, logical_height; + int req_width, req_height; + int bound_width, bound_height; + uint32_t scale_120; + uint32_t pending_scale_120; + uint32_t pending_serial; + double scale_factor; + uint64_t outputs; + + bool tiled; + bool size_pending; + bool sample_refresh; + bool has_pending_serial; + bool configured; + bool closed; + bool destroyed; + bool opaque; + bool fullscreen; + bool maximized; + bool activated; + bool suspended; + bool want_draw; +}; + +char *yasl_utf8_sanitize_dup(const char *str); +bool yasl_utf8_validate(const char *str, size_t len); + +int device_px(int logical, uint32_t scale_120); +bool buffer_size(int width, int height, size_t *bytes); +int buffer_reserve(struct yasl_surface *w, struct buffer *b, size_t needed); +void buffer_destroy(struct buffer *b); +int buffer_pick_free_index(const struct buffer *bufs, int cur); +int buffer_prepare(struct yasl_surface *w, struct buffer *b, int width, int height, + const struct wl_buffer_listener *listener); +int apply_pending_geometry(struct yasl_surface *w); +int logical_px_ceil(int device, uint32_t scale_120); + +static inline void wl_damage_list(struct wl_surface *s, const struct yasl_damage_list *d) +{ + if (d->n < 0) { + wl_surface_damage_buffer(s, d->bounds.x, d->bounds.y, + d->bounds.width, d->bounds.height); + return; + } + for (int i = 0; i < d->n; i++) + wl_surface_damage_buffer(s, d->rects[i].x, d->rects[i].y, + d->rects[i].width, d->rects[i].height); +} + +void surface_update_opaque_region(struct yasl_surface *w); +int surface_init_scaling(struct yasl_surface *w); + +static inline bool surface_gets_preferred_scale(struct wl_surface *s) +{ + return wl_proxy_get_version((struct wl_proxy *)s) >= + WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION; +} + +uint64_t conn_output_mask(const struct yasl_display *c, const struct wl_output *proxy); +uint32_t conn_output_scale_120(const struct yasl_display *c, uint64_t outputs); +void conn_destroy_outputs(struct yasl_display *c); +void surface_follow_outputs(struct yasl_surface *w); +uint64_t conn_pres_to_mono(const struct yasl_display *c, uint64_t ns); +uint64_t conn_mono_to_pres(const struct yasl_display *c, uint64_t ns); +void surface_draw_frame(struct yasl_surface *w); +void surface_fail(struct yasl_surface *w); +void display_enter(struct yasl_display *c); +void display_leave(struct yasl_display *c); + +struct yasl_surface *conn_surface_for(struct yasl_display *c, struct wl_surface *s); + +static inline struct yasl_surface *surface_root(struct yasl_surface *w) +{ + while (w && w->parent) + w = w->parent; + return w; +} + +void conn_drag_end(struct yasl_display *c); +void conn_drop_target(struct yasl_display *c, enum yasl_drop_event ev, + struct wl_surface *on, double x, double y); +void conn_drag_target(struct yasl_display *c, enum yasl_drag_event ev, + struct wl_surface *on, double x, double y); + +void seat_bind(struct yasl_display *c, struct wl_registry *registry, + uint32_t name, uint32_t version); +bool seat_remove(struct yasl_display *c, uint32_t name); +void seat_destroy(struct seat *s); +struct seat *conn_active_seat(const struct yasl_display *c); +void seat_note_input(struct seat *s, uint32_t serial); +void seat_forget_surface(struct seat *s, struct yasl_surface *w); +void seat_clipboard_ensure(struct seat *s); +int display_input_init(struct yasl_display *c); +extern const struct wl_seat_listener seat_listener; + +void keyboard_repeat_stop(struct seat *s); +void keyboard_repeat_sync(struct seat *s); +int keyboard_repeat_init(struct seat *s); +void keyboard_settle_focus(struct yasl_display *c); +bool conn_keyboard_on(const struct yasl_display *c, const struct yasl_surface *w, + const struct seat *except); +extern const struct wl_keyboard_listener keyboard_listener; +int seat_modifiers(const struct seat *s); + +void surface_init_cursor(struct yasl_display *c); +void seat_destroy_tablet(struct seat *s); +void seat_pointer_reset(struct seat *s); + +extern const struct zwp_text_input_v3_listener text_input_listener; +void ime_reset(struct yasl_surface *w); +void ime_send_caret(struct yasl_surface *w); + +int surface_init_shell(struct yasl_surface *w, const char *title); +extern const struct xdg_surface_listener shell_surface_listener; +extern const struct wl_registry_listener registry_listener; + +void surface_feedback_destroy(struct yasl_surface *w); +void surface_request_presentation_feedback(struct yasl_surface *w); + +#endif |
