summaryrefslogtreecommitdiff
path: root/src/platform/wayland/internal.h
blob: d619dba6d98c75531a35a5bc78b78ad2aa27e0f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
#ifndef YASL_WAYLAND_INTERNAL_H
#define YASL_WAYLAND_INTERNAL_H

#define _GNU_SOURCE

#include "api.h"
#include "common/backend.h"
#include "common/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 <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>
#include <xkbcommon/xkbcommon-compose.h>

#define NBUF 3

struct wayland_surface;
struct tablet_tool;
struct tablet_device;
struct tablet_pad;

struct buffer {
    struct wayland_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 wayland_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 wayland_surface *surface;
    struct yasl_vector2i pos;
    int button;
    bool release;
};

struct press_queue {
    struct pending_press ev[8];
    int head;
    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;
};

#ifndef likely
#define likely(x)   __builtin_expect(!!(x), 1)
#endif
#ifndef unlikely
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif

struct conn_drag {
    struct wl_data_source *source;
    struct xdg_toplevel_drag_v1 *toplevel;
    struct drag_icon icon;
    struct yasl_drag_listener listener;
    void *ud;
    struct seat *seat;
    uint32_t scale_120;
    bool dropped;
    bool carrying;
};

#define SEAT_TOUCH_POINTS 10

struct touch_point {
    struct wayland_surface *surface;
    double x, y;
    int32_t id;
    bool active;
    bool down;
    bool moved;
    bool up;
};

struct seat {
    /* 8-byte aligned pointers and 64-bit values */
    struct wayland_display *conn;
    struct seat *next;
    struct wl_seat *proxy;
    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;
    struct xkb_compose_state *compose;
    bool compose_attempted;
    uint64_t repeat_started_ns;
    struct wayland_surface *pointer_focus;
    struct wayland_surface *keyboard_focus;
    struct wayland_surface *tablet_focus;
    struct wayland_surface *ime_focus;
    struct wayland_surface *focus_leaving;
    struct wayland_surface *press_surface;
    struct wayland_surface *ptr_left;
    struct tablet_tool *tool;
    struct touch_point *touch_primary;
    uint64_t pointer_buttons;
    uint64_t tool_buttons;
    double axis[2], axis_value120[2];
    int64_t axis_discrete[2];
    bool axis_has_value120[2], axis_has_discrete[2];
    double touch_scroll_y;

    /* Embedded structs */
    xkb_mod_mask_t input_mod_masks[8];
    struct yasl_vector2i pointer_pos;
    struct yasl_vector2i ptr_left_pos;
    struct yasl_vector2i tool_pos;
    struct touch_point touch_points[SEAT_TOUCH_POINTS];
    struct press_queue ptr_presses;
    struct press_queue tool_presses;

    /* 4-byte integers */
    uint32_t name;
    xkb_mod_index_t mod_shift, mod_alt, mod_ctrl, mod_super;
    int repeat_fd, repeat_watch;
    int32_t repeat_rate, repeat_delay;
    uint32_t repeat_key;
    uint32_t input_serial;
    uint32_t press_serial;
    uint32_t pointer_serial;
    int cursor_shape;
    struct yasl_pointer_pen pen;
    int tool_wheel;

    /* 1-byte booleans grouped tightly */
    bool input_mods_ready;
    bool repeat_held;
    bool motion_pending;
    bool ptr_left_motion;
    bool tool_motion;
    bool touch_pressed;
    bool touch_scrolling;
};

#include "common/input.h"

struct wayland_display {
    struct yasl_display base;
    /* 8-byte pointers & 64-bit masks */
    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;
    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;
    struct xdg_toplevel_drag_manager_v1 *toplevel_drag_mgr;
    struct conn_drag drag;
    struct wayland_surface *surfaces;
    struct wayland_surface *dead;

    /* 4-byte integers */
    int cursor_size;
    int cursor_theme_scale;
    clockid_t pres_clock;
    int watch;
    int depth;

    /* 1-byte booleans */
    bool owns_loop;
    bool pres_clock_known;
    bool reading;
    bool lost;
};

struct latency_feedback {
    struct wayland_surface *window;
    struct wp_presentation_feedback *proxy;
    struct latency_feedback *next;
    bool in_pool;
};

struct wayland_surface {
    struct yasl_surface base;
    /* 8-byte pointers & 64-bit values */
    struct wayland_display *conn;
    struct wayland_surface *conn_next;
    struct wayland_surface *dead_next;
    struct wayland_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;
    struct wp_fractional_scale_v1 *frac_scale;
    struct wp_viewport *viewport;
    char *ime_preedit;
    char *ime_commit;
    char *ime_shown;
    struct seat *ime_seat;
    struct wp_tearing_control_v1 *tearing_control;
    struct latency_feedback *latency_feedbacks;
    struct latency_feedback latency_pool[8];
    struct wp_fifo_v1 *fifo;
    struct wp_commit_timer_v1 *commit_timer;
    struct wl_callback *frame_cb;
    const struct yasl_window_cbs *cbs;
    void *ud;
    uint64_t frames_skipped;
    uint64_t outputs;
    double scale_factor;

    /* Sub-structures */
    struct yasl_rect2i ime_caret;
    struct yasl_rect2i content;
    struct yasl_frame_clock clock;
    struct buffer buffers[NBUF];
    struct yasl_frame frame;
    struct yasl_damage_list damage;
    int ime_cursor_begin;
    struct input_queue input;

    /* 4-byte integers */
    enum yasl_cursor cursor;
    int ime_cursor_end;
    int ime_shown_begin, ime_shown_end;
    int floating_width, floating_height;
    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;

    /* 1-byte booleans packed tightly */
    bool frame_active;
    bool frame_presented;
    bool size_pending;
    bool sample_refresh;
    bool has_pending_serial;
    bool configured;
    bool closed;
    bool destroyed;
    bool opaque;
    bool want_draw;
};


int  device_px(int logical, uint32_t scale_120);
bool buffer_size(int width, int height, size_t *bytes);
int  buffer_reserve(struct wayland_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 wayland_surface *w, struct buffer *b, int width, int height,
                    const struct wl_buffer_listener *listener);
int  apply_pending_geometry(struct wayland_surface *w);

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 wayland_surface *w);
int  surface_init_scaling(struct wayland_surface *w);

uint64_t conn_output_mask(const struct wayland_display *c, const struct wl_output *proxy);
uint32_t conn_output_scale_120(const struct wayland_display *c, uint64_t outputs);
void     conn_destroy_outputs(struct wayland_display *c);
void     surface_follow_outputs(struct wayland_surface *w);
uint64_t conn_pres_to_mono(const struct wayland_display *c, uint64_t ns);
uint64_t conn_mono_to_pres(const struct wayland_display *c, uint64_t ns);
void surface_draw_frame(struct wayland_surface *w);
void surface_fail(struct wayland_surface *w);
void display_leave(struct wayland_display *c);

static inline struct wayland_surface *surface_root(struct wayland_surface *w)
{
    while (w && w->parent)
        w = w->parent;
    return w;
}

void conn_drag_end(struct wayland_display *c);
void conn_drop_target(struct wayland_display *c, enum yasl_drop_event ev,
                      struct wl_surface *on, double x, double y);
void conn_drag_target(struct wayland_display *c, enum yasl_drag_event ev,
                      struct wl_surface *on, double x, double y);

void seat_bind(struct wayland_display *c, struct wl_registry *registry,
               uint32_t name, uint32_t version);
bool seat_remove(struct wayland_display *c, uint32_t name);
void seat_destroy(struct seat *s);
void seat_note_input(struct seat *s, uint32_t serial);
void seat_forget_surface(struct seat *s, struct wayland_surface *w);
void seat_clipboard_ensure(struct seat *s);
int  display_input_init(struct wayland_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 wayland_display *c);
bool conn_keyboard_on(const struct wayland_display *c, const struct wayland_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 wayland_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 wayland_surface *w);
void keyboard_text_reset(struct seat *s);
void ime_send_caret(struct wayland_surface *w);

int  surface_init_shell(struct wayland_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 wayland_surface *w);
void surface_request_presentation_feedback(struct wayland_surface *w);

#endif