summaryrefslogtreecommitdiff
path: root/src/wayland
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-11 23:27:41 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-11 23:27:41 +0300
commit472ed3e4e50a165638acecaf071ec3c2c13c451f (patch)
treed1894debde800d8e87d3c242ae6c3f4760c68787 /src/wayland
parent8d9f7c7cb39359d62bf28ef1775b944a7dddd6fb (diff)
core: optimize struct layouts, eliminate branches, and fix event loop dispatch
- Fix Wayland event loop lockout by properly decoupling read arming and adding poll-backed dispatching - Support standalone display lifecycle without requiring caller to manage a loop - Eliminate alignment holes across yasl_surface, yasl_display, seat, touch_point, and conn_drag using pahole - Replace branching state/button decoders with compile-time locked LUTs and branchless bitwise operations - Accelerate UTF-8 validation with 64-bit word scanning for ASCII runs
Diffstat (limited to 'src/wayland')
-rw-r--r--src/wayland/buffer.c31
-rw-r--r--src/wayland/internal.h129
-rw-r--r--src/wayland/keyboard.c12
-rw-r--r--src/wayland/pointer.c73
-rw-r--r--src/wayland/shell.c29
-rw-r--r--src/wayland/surface.c118
6 files changed, 269 insertions, 123 deletions
diff --git a/src/wayland/buffer.c b/src/wayland/buffer.c
index 492cfde..0d639e6 100644
--- a/src/wayland/buffer.c
+++ b/src/wayland/buffer.c
@@ -305,13 +305,20 @@ static void arm_frame(struct yasl_surface *w)
}
}
+static const int8_t free_buf_lut[3][8] = {
+ [0] = { 1, 1, 2, 2, 1, 1, 0, -1 },
+ [1] = { 0, 2, 0, 2, 0, 1, 0, -1 },
+ [2] = { 0, 1, 0, 2, 0, 1, 0, -1 },
+};
+
int buffer_pick_free_index(const struct buffer *bufs, int cur)
{
- if (!bufs[cur ^ 1].busy) return cur ^ 1;
- for (int i = 0; i < NBUF; i++)
- if (i != cur && i != (cur ^ 1) && !bufs[i].busy) return i;
- if (!bufs[cur].busy) return cur;
- return -1;
+ unsigned busy = ((unsigned)bufs[0].busy) |
+ (((unsigned)bufs[1].busy) << 1) |
+ (((unsigned)bufs[2].busy) << 2);
+ unsigned c = (unsigned)cur;
+ if (unlikely(c >= 3)) c = 0;
+ return free_buf_lut[c][busy];
}
struct latency_feedback {
@@ -523,14 +530,12 @@ void yasl_surface_set_title(struct yasl_surface *w, const char *title)
uint32_t yasl_surface_state(const struct yasl_surface *w)
{
- if (!w) return 0;
- uint32_t s = 0;
- if (w->fullscreen) s |= YASL_STATE_FULLSCREEN;
- if (w->maximized) s |= YASL_STATE_MAXIMIZED;
- if (w->activated) s |= YASL_STATE_ACTIVATED;
- if (w->suspended) s |= YASL_STATE_SUSPENDED;
- if (!w->server_decorated) s |= YASL_STATE_CSD;
- return s;
+ if (unlikely(!w)) return 0;
+ return ((uint32_t)w->fullscreen * YASL_STATE_FULLSCREEN) |
+ ((uint32_t)w->maximized * YASL_STATE_MAXIMIZED) |
+ ((uint32_t)w->activated * YASL_STATE_ACTIVATED) |
+ ((uint32_t)w->suspended * YASL_STATE_SUSPENDED) |
+ ((uint32_t)!w->server_decorated * YASL_STATE_CSD);
}
struct yasl_timing yasl_surface_timing(const struct yasl_surface *w)
diff --git a/src/wayland/internal.h b/src/wayland/internal.h
index dc85943..79fd88d 100644
--- a/src/wayland/internal.h
+++ b/src/wayland/internal.h
@@ -89,14 +89,21 @@ struct drag_icon {
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;
const struct yasl_drag_listener *listener;
void *ud;
- uint32_t scale_120;
struct seat *seat;
+ uint32_t scale_120;
bool dropped;
bool carrying;
};
@@ -105,17 +112,19 @@ struct conn_drag {
struct touch_point {
struct yasl_surface *surface;
- int32_t id;
double x, y;
+ int32_t id;
bool active;
- bool down, moved, up;
+ bool down;
+ bool moved;
+ bool up;
};
struct seat {
+ /* 8-byte aligned pointers and 64-bit values */
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;
@@ -128,59 +137,63 @@ struct seat {
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;
+ struct yasl_surface *ptr_left;
+ struct tablet_tool *tool;
+ struct touch_point *touch_primary;
+ uint64_t pointer_buttons;
+ uint64_t tool_buttons;
+ double axis_v, axis_h, frame_v;
+ double touch_scroll_y, touch_scroll_rest;
+
+ /* 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_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;
+ struct yasl_pointer_pen pen;
+ int tool_wheel;
+
+ /* 1-byte booleans grouped tightly */
+ bool input_mods_ready;
+ bool repeat_held;
+ bool axis_has_v120_v;
+ bool 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
+#define YASL_QUEUE_MASK (YASL_QUEUE_CAP - 1)
struct input_queue {
struct yasl_input_event events[YASL_QUEUE_CAP];
int head;
@@ -190,17 +203,17 @@ struct input_queue {
static inline void input_queue_push(struct input_queue *q, const struct yasl_input_event *ev)
{
- if (q->count >= YASL_QUEUE_CAP) return;
+ if (unlikely(q->count >= YASL_QUEUE_CAP)) return;
q->events[q->tail] = *ev;
- q->tail = (q->tail + 1) % YASL_QUEUE_CAP;
+ q->tail = (q->tail + 1) & YASL_QUEUE_MASK;
q->count++;
}
static inline bool input_queue_pop(struct input_queue *q, struct yasl_input_event *ev)
{
- if (q->count <= 0) return false;
+ if (unlikely(q->count <= 0)) return false;
*ev = q->events[q->head];
- q->head = (q->head + 1) % YASL_QUEUE_CAP;
+ q->head = (q->head + 1) & YASL_QUEUE_MASK;
q->count--;
return true;
}
@@ -211,6 +224,7 @@ static inline void input_queue_clear(struct input_queue *q)
}
struct yasl_display {
+ /* 8-byte pointers & 64-bit masks */
struct wl_display *wl;
struct wl_registry *registry;
struct wl_compositor *compositor;
@@ -228,7 +242,6 @@ struct yasl_display {
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;
@@ -240,20 +253,28 @@ struct yasl_display {
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;
+ struct yasl_surface *dead;
+
+ /* 4-byte integers */
+ int cursor_size;
+ int cursor_theme_scale;
+ clockid_t pres_clock;
int watch;
int depth;
- struct yasl_surface *dead;
+
+ /* 1-byte booleans */
+ bool owns_loop;
+ bool pres_clock_known;
bool reading;
bool lost;
};
struct yasl_surface {
+ /* 8-byte pointers & 64-bit values */
struct yasl_display *conn;
struct yasl_surface *conn_next;
struct yasl_surface *dead_next;
@@ -263,16 +284,11 @@ struct yasl_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;
@@ -282,18 +298,23 @@ struct yasl_surface {
const struct yasl_surface_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 input_queue input;
-
struct buffer buffers[NBUF];
struct yasl_frame frame;
struct yasl_damage_list damage;
- bool frame_active;
- bool frame_presented;
+ int ime_cursor_begin;
+ struct input_queue input;
+ /* 4-byte integers */
+ int ime_cursor_end;
+ int ime_shown_begin, ime_shown_end;
int floating_width, floating_height;
- struct yasl_rect2i content;
int cur;
int width, height;
int logical_width, logical_height;
@@ -302,9 +323,11 @@ struct yasl_surface {
uint32_t scale_120;
uint32_t pending_scale_120;
uint32_t pending_serial;
- double scale_factor;
- uint64_t outputs;
+ /* 1-byte booleans packed tightly */
+ bool server_decorated;
+ bool frame_active;
+ bool frame_presented;
bool tiled;
bool size_pending;
bool sample_refresh;
diff --git a/src/wayland/keyboard.c b/src/wayland/keyboard.c
index 7283d58..6045962 100644
--- a/src/wayland/keyboard.c
+++ b/src/wayland/keyboard.c
@@ -346,13 +346,11 @@ static bool mod_index_active(const struct seat *s, xkb_mod_index_t mod)
int seat_modifiers(const struct seat *s)
{
- if (!s || !s->xkb_state) return 0;
- int mods = 0;
- if (mod_index_active(s, s->mod_shift)) mods |= YASL_MOD_SHIFT;
- if (mod_index_active(s, s->mod_alt)) mods |= YASL_MOD_ALT;
- if (mod_index_active(s, s->mod_ctrl)) mods |= YASL_MOD_CTRL;
- if (mod_index_active(s, s->mod_super)) mods |= YASL_MOD_SUPER;
- return mods;
+ if (unlikely(!s || !s->xkb_state)) return 0;
+ return (mod_index_active(s, s->mod_shift) * YASL_MOD_SHIFT) |
+ (mod_index_active(s, s->mod_alt) * YASL_MOD_ALT) |
+ (mod_index_active(s, s->mod_ctrl) * YASL_MOD_CTRL) |
+ (mod_index_active(s, s->mod_super) * YASL_MOD_SUPER);
}
int yasl_display_modifiers(const struct yasl_display *c)
diff --git a/src/wayland/pointer.c b/src/wayland/pointer.c
index 37e72f3..89dacde 100644
--- a/src/wayland/pointer.c
+++ b/src/wayland/pointer.c
@@ -39,12 +39,44 @@ static struct yasl_vector2i device_from_fixed(const struct yasl_surface *w,
};
}
-static int motion_button(uint64_t buttons)
-{
- for (int b = 0; b <= 7; b++)
- if (buttons & (1ull << b))
- return b;
- return 3;
+static inline int motion_button(uint64_t buttons)
+{
+ static const uint8_t motion_btn_lut[256] = {
+ [0] = 3,
+ [1] = 0, [2] = 1, [3] = 0, [4] = 2, [5] = 0, [6] = 1, [7] = 0,
+ [8] = 3, [9] = 0, [10] = 1, [11] = 0, [12] = 2, [13] = 0, [14] = 1, [15] = 0,
+ [16] = 4, [17] = 0, [18] = 1, [19] = 0, [20] = 2, [21] = 0, [22] = 1, [23] = 0,
+ [24] = 3, [25] = 0, [26] = 1, [27] = 0, [28] = 2, [29] = 0, [30] = 1, [31] = 0,
+ [32] = 5, [33] = 0, [34] = 1, [35] = 0, [36] = 2, [37] = 0, [38] = 1, [39] = 0,
+ [40] = 3, [41] = 0, [42] = 1, [43] = 0, [44] = 2, [45] = 0, [46] = 1, [47] = 0,
+ [48] = 4, [49] = 0, [50] = 1, [51] = 0, [52] = 2, [53] = 0, [54] = 1, [55] = 0,
+ [56] = 3, [57] = 0, [58] = 1, [59] = 0, [60] = 2, [61] = 0, [62] = 1, [63] = 0,
+ [64] = 6, [65] = 0, [66] = 1, [67] = 0, [68] = 2, [69] = 0, [70] = 1, [71] = 0,
+ [72] = 3, [73] = 0, [74] = 1, [75] = 0, [76] = 2, [77] = 0, [78] = 1, [79] = 0,
+ [80] = 4, [81] = 0, [82] = 1, [83] = 0, [84] = 2, [85] = 0, [86] = 1, [87] = 0,
+ [88] = 3, [89] = 0, [90] = 1, [91] = 0, [92] = 2, [93] = 0, [94] = 1, [95] = 0,
+ [96] = 5, [97] = 0, [98] = 1, [99] = 0, [100] = 2, [101] = 0, [102] = 1, [103] = 0,
+ [104] = 3, [105] = 0, [106] = 1, [107] = 0, [108] = 2, [109] = 0, [110] = 1, [111] = 0,
+ [112] = 4, [113] = 0, [114] = 1, [115] = 0, [116] = 2, [117] = 0, [118] = 1, [119] = 0,
+ [120] = 3, [121] = 0, [122] = 1, [123] = 0, [124] = 2, [125] = 0, [126] = 1, [127] = 0,
+ [128] = 7, [129] = 0, [130] = 1, [131] = 0, [132] = 2, [133] = 0, [134] = 1, [135] = 0,
+ [136] = 3, [137] = 0, [138] = 1, [139] = 0, [140] = 2, [141] = 0, [142] = 1, [143] = 0,
+ [144] = 4, [145] = 0, [146] = 1, [147] = 0, [148] = 2, [149] = 0, [150] = 1, [151] = 0,
+ [152] = 3, [153] = 0, [154] = 1, [155] = 0, [156] = 2, [157] = 0, [158] = 1, [159] = 0,
+ [160] = 5, [161] = 0, [162] = 1, [163] = 0, [164] = 2, [165] = 0, [166] = 1, [167] = 0,
+ [168] = 3, [169] = 0, [170] = 1, [171] = 0, [172] = 2, [173] = 0, [174] = 1, [175] = 0,
+ [176] = 4, [177] = 0, [178] = 1, [179] = 0, [180] = 2, [181] = 0, [182] = 1, [183] = 0,
+ [184] = 3, [185] = 0, [186] = 1, [187] = 0, [188] = 2, [189] = 0, [190] = 1, [191] = 0,
+ [192] = 6, [193] = 0, [194] = 1, [195] = 0, [196] = 2, [197] = 0, [198] = 1, [199] = 0,
+ [200] = 3, [201] = 0, [202] = 1, [203] = 0, [204] = 2, [205] = 0, [206] = 1, [207] = 0,
+ [208] = 4, [209] = 0, [210] = 1, [211] = 0, [212] = 2, [213] = 0, [214] = 1, [215] = 0,
+ [216] = 3, [217] = 0, [218] = 1, [219] = 0, [220] = 2, [221] = 0, [222] = 1, [223] = 0,
+ [224] = 5, [225] = 0, [226] = 1, [227] = 0, [228] = 2, [229] = 0, [230] = 1, [231] = 0,
+ [232] = 3, [233] = 0, [234] = 1, [235] = 0, [236] = 2, [237] = 0, [238] = 1, [239] = 0,
+ [240] = 4, [241] = 0, [242] = 1, [243] = 0, [244] = 2, [245] = 0, [246] = 1, [247] = 0,
+ [248] = 3, [249] = 0, [250] = 1, [251] = 0, [252] = 2, [253] = 0, [254] = 1, [255] = 0,
+ };
+ return motion_btn_lut[(uint8_t)buttons];
}
void seat_note_input(struct seat *s, uint32_t serial)
@@ -333,18 +365,25 @@ static void pointer_button(void *data, struct wl_pointer *pointer,
(void)pointer; (void)time;
struct seat *s = data;
struct yasl_surface *w = s->pointer_focus;
- if (!w) return;
- int b;
- switch (button) {
- case BTN_LEFT: b = 0; break;
- case BTN_MIDDLE: b = 1; break;
- case BTN_RIGHT: b = 2; break;
- case BTN_BACK: b = 3; break;
- case BTN_FORWARD: b = 4; break;
- default: return;
- }
+ if (unlikely(!w)) return;
+
+ static const int8_t btn_map[8] = {
+ [0] = 0, /* BTN_LEFT (0x110) */
+ [1] = 2, /* BTN_RIGHT (0x111) */
+ [2] = 1, /* BTN_MIDDLE (0x112) */
+ [3] = 3, /* BTN_SIDE (0x113) */
+ [4] = 4, /* BTN_EXTRA (0x114) */
+ [5] = 4, /* BTN_FORWARD (0x115) */
+ [6] = 3, /* BTN_BACK (0x116) */
+ [7] = -1,
+ };
+ unsigned idx = button - 0x110;
+ if (unlikely(idx >= 7)) return;
+ int b = btn_map[idx];
+ if (unlikely(b < 0)) return;
+
seat_note_input(s, serial);
- bool release = state == WL_POINTER_BUTTON_STATE_RELEASED;
+ bool release = (state == WL_POINTER_BUTTON_STATE_RELEASED);
if (!release) {
s->press_serial = serial;
s->press_surface = w;
diff --git a/src/wayland/shell.c b/src/wayland/shell.c
index ef72512..bc8083a 100644
--- a/src/wayland/shell.c
+++ b/src/wayland/shell.c
@@ -277,24 +277,25 @@ static void toplevel_configure(void *data, struct xdg_toplevel *toplevel,
(void)toplevel;
struct yasl_surface *w = data;
- bool fs = false, max = false, act = false, susp = false, tiled = false;
+ uint32_t state_mask = 0;
uint32_t *s;
wl_array_for_each(s, states) {
- switch (*s) {
- case XDG_TOPLEVEL_STATE_FULLSCREEN: fs = true; break;
- case XDG_TOPLEVEL_STATE_MAXIMIZED: max = true; break;
- case XDG_TOPLEVEL_STATE_ACTIVATED: act = true; break;
- case XDG_TOPLEVEL_STATE_SUSPENDED: susp = true; break;
- case XDG_TOPLEVEL_STATE_TILED_LEFT:
- case XDG_TOPLEVEL_STATE_TILED_RIGHT:
- case XDG_TOPLEVEL_STATE_TILED_TOP:
- case XDG_TOPLEVEL_STATE_TILED_BOTTOM: tiled = true; break;
- default: break;
- }
+ if (*s < 32)
+ state_mask |= (1u << *s);
}
- if (fs != w->fullscreen || max != w->maximized ||
- act != w->activated || susp != w->suspended) {
+ bool max = (state_mask & (1u << XDG_TOPLEVEL_STATE_MAXIMIZED)) != 0;
+ bool fs = (state_mask & (1u << XDG_TOPLEVEL_STATE_FULLSCREEN)) != 0;
+ bool act = (state_mask & (1u << XDG_TOPLEVEL_STATE_ACTIVATED)) != 0;
+ bool susp = (state_mask & (1u << XDG_TOPLEVEL_STATE_SUSPENDED)) != 0;
+ bool tiled = (state_mask & (
+ (1u << XDG_TOPLEVEL_STATE_TILED_LEFT) |
+ (1u << XDG_TOPLEVEL_STATE_TILED_RIGHT) |
+ (1u << XDG_TOPLEVEL_STATE_TILED_TOP) |
+ (1u << XDG_TOPLEVEL_STATE_TILED_BOTTOM))) != 0;
+
+ if ((fs ^ w->fullscreen) | (max ^ w->maximized) |
+ (act ^ w->activated) | (susp ^ w->suspended)) {
w->fullscreen = fs;
w->maximized = max;
w->activated = act;
diff --git a/src/wayland/surface.c b/src/wayland/surface.c
index da334e4..5138201 100644
--- a/src/wayland/surface.c
+++ b/src/wayland/surface.c
@@ -83,6 +83,14 @@ static int display_ready(int fd, short revents, void *ud)
else if (wl_display_read_events(c->wl) < 0)
revents |= POLLERR;
}
+ if (revents & POLLOUT) {
+ if (wl_display_flush(c->wl) >= 0) {
+ if (c->loop && c->watch > 0)
+ yasl_loop_set_fd_events(c->loop, c->watch, POLLIN);
+ } else if (errno != EAGAIN) {
+ display_lose(c);
+ }
+ }
if (wl_display_dispatch_pending(c->wl) < 0 ||
(revents & (POLLERR | POLLHUP | POLLNVAL)))
display_lose(c);
@@ -90,35 +98,92 @@ static int display_ready(int fd, short revents, void *ud)
return 0;
}
-void yasl_display_dispatch(struct yasl_display *c)
-{
- if (!c || c->lost || c->reading)
- return;
- display_enter(c);
- if (wl_display_dispatch_pending(c->wl) < 0)
- display_lose(c);
- display_leave(c);
-}
-
-static void display_arm(struct yasl_display *c)
+static bool display_arm(struct yasl_display *c)
{
+ bool had_pending = false;
while (!c->reading && wl_display_prepare_read(c->wl) != 0) {
+ had_pending = true;
if (wl_display_dispatch_pending(c->wl) < 0) {
display_lose(c);
- return;
+ return false;
}
}
c->reading = true;
short events = POLLIN;
if (wl_display_flush(c->wl) < 0) {
if (errno != EAGAIN) {
+ display_cancel_read(c);
display_lose(c);
- return;
+ return false;
}
events |= POLLOUT;
}
- if (c->loop)
+ if (c->loop && c->watch > 0)
yasl_loop_set_fd_events(c->loop, c->watch, events);
+ return had_pending;
+}
+
+static bool display_has_immediate_work(const struct yasl_display *c)
+{
+ if (!c || c->lost) return false;
+ for (struct yasl_surface *w = c->surfaces; w; w = w->conn_next) {
+ if (w->closed) continue;
+ if (w->input.count > 0)
+ return true;
+ if (w->want_draw && !w->frame_cb && w->configured)
+ return true;
+ }
+ return false;
+}
+
+int yasl_display_dispatch_timeout(struct yasl_display *c, int timeout_ms)
+{
+ if (!c || c->lost)
+ return -1;
+
+ display_enter(c);
+
+ if (wl_display_dispatch_pending(c->wl) < 0) {
+ display_lose(c);
+ display_leave(c);
+ return -1;
+ }
+
+ bool had_pending = display_arm(c);
+ if (c->lost) {
+ display_leave(c);
+ return -1;
+ }
+
+ if (had_pending && timeout_ms != 0 && display_has_immediate_work(c)) {
+ timeout_ms = 0;
+ }
+
+ int n = 0;
+ if (c->loop) {
+ n = yasl_loop_step(c->loop, timeout_ms);
+ }
+
+ if (c->reading) {
+ display_cancel_read(c);
+ }
+
+ if (wl_display_dispatch_pending(c->wl) < 0) {
+ display_lose(c);
+ display_leave(c);
+ return -1;
+ }
+
+ display_leave(c);
+ return n;
+}
+
+void yasl_display_dispatch(struct yasl_display *c)
+{
+ if (!c || c->lost)
+ return;
+ int timeout = display_has_immediate_work(c) ? 0 : -1;
+ yasl_display_dispatch_timeout(c, timeout);
}
void yasl_display_flush(struct yasl_display *c)
@@ -130,8 +195,10 @@ void yasl_display_flush(struct yasl_display *c)
next = w->conn_next;
surface_draw_frame(w);
}
- if (!c->lost)
- display_arm(c);
+ if (!c->lost && c->wl) {
+ if (wl_display_flush(c->wl) < 0 && errno != EAGAIN)
+ display_lose(c);
+ }
display_leave(c);
}
@@ -163,6 +230,10 @@ static void display_free(struct yasl_display *c)
if (c->compositor) wl_compositor_destroy(c->compositor);
if (c->registry) wl_registry_destroy(c->registry);
if (c->wl) wl_display_disconnect(c->wl);
+ if (c->owns_loop && c->loop) {
+ yasl_loop_destroy(c->loop);
+ c->loop = NULL;
+ }
free(c->app_id);
free(c);
}
@@ -171,7 +242,13 @@ struct yasl_display *yasl_display_open(struct yasl_loop *loop, const struct yasl
{
struct yasl_display *c = calloc(1, sizeof(*c));
if (!c) return NULL;
- c->loop = loop;
+ if (!loop) {
+ c->loop = yasl_loop_create();
+ c->owns_loop = true;
+ } else {
+ c->loop = loop;
+ }
+ if (!c->loop) goto err;
if (spec) {
c->cbs = spec->cbs;
c->ud = spec->ud;
@@ -189,7 +266,7 @@ struct yasl_display *yasl_display_open(struct yasl_loop *loop, const struct yasl
surface_init_cursor(c);
if (c->loop) {
- c->watch = yasl_loop_add_fd(loop, wl_display_get_fd(c->wl), POLLIN, display_ready, c);
+ c->watch = yasl_loop_add_fd(c->loop, wl_display_get_fd(c->wl), POLLIN, display_ready, c);
if (c->watch <= 0) { c->watch = 0; goto err; }
}
if (display_input_init(c) < 0)
@@ -371,7 +448,10 @@ struct yasl_display *yasl_surface_display(const struct yasl_surface *w)
void yasl_surface_schedule_redraw(struct yasl_surface *w)
{
- if (w) w->want_draw = true;
+ if (!w || w->closed) return;
+ w->want_draw = true;
+ if (w->conn && w->conn->loop)
+ yasl_loop_kick(w->conn->loop);
}
struct yasl_vector2i yasl_surface_size(const struct yasl_surface *w)