summaryrefslogtreecommitdiff
path: root/src/platform/x11
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/x11')
-rw-r--r--src/platform/x11/window.c117
1 files changed, 56 insertions, 61 deletions
diff --git a/src/platform/x11/window.c b/src/platform/x11/window.c
index 630eb91..2751c91 100644
--- a/src/platform/x11/window.c
+++ b/src/platform/x11/window.c
@@ -143,7 +143,7 @@ struct x11_display {
struct x11_display *next_open;
Display *native;
int screen;
- struct yasl_private_loop *loop;
+ struct yasl_loop *loop;
int watch;
struct x11_surface *surfaces, *dead;
int depth;
@@ -354,7 +354,8 @@ static int yasl_private_x11_error_handler(Display *native, XErrorEvent *event)
}
/* Marks the display lost once and queues DISPLAY_LOST. The poll watch is removed
- * by ready(), on the thread that owns the loop, because this can run on a GL thread. */
+ * by prepare() or check(), on the thread that owns the loop, because this can run
+ * on a GL thread. */
static void display_lost(struct x11_display *d)
{
if (d->lost) return;
@@ -1025,7 +1026,7 @@ static void cancel_pastes(struct x11_display *d, struct x11_surface *target)
} else if (!target || r->target == target) {
/* An INCR transfer in progress is abandoned; its owner times out. */
*p = r->next;
- if (r->timeout) yasl_private_loop_del_timer(d->loop, r->timeout);
+ if (r->timeout) yasl_loop_del_timer(d->loop, r->timeout);
if (!d->lost) XDestroyWindow(d->native, r->window);
free(r->buf);
free(r);
@@ -1058,8 +1059,8 @@ static uint64_t paste_timeout(void *ud, yasl_private_timer_id id, uint64_t inter
static void paste_rearm(struct paste_request *r)
{
struct x11_display *d = r->display;
- if (r->timeout) yasl_private_loop_del_timer(d->loop, r->timeout);
- r->timeout = yasl_private_loop_add_timer(d->loop, PASTE_TIMEOUT_NS, paste_timeout, r);
+ if (r->timeout) yasl_loop_del_timer(d->loop, r->timeout);
+ r->timeout = yasl_loop_add_timer(d->loop, PASTE_TIMEOUT_NS, paste_timeout, r);
}
/* Unlink a paste request at *link and report its outcome to the surface, if alive. */
@@ -1068,7 +1069,7 @@ static void paste_complete(struct x11_display *d, struct paste_request **link,
{
struct paste_request *r = *link;
*link = r->next;
- if (r->timeout) yasl_private_loop_del_timer(d->loop, r->timeout);
+ if (r->timeout) yasl_loop_del_timer(d->loop, r->timeout);
XDestroyWindow(d->native, r->window);
if (r->target && !r->target->destroyed)
yasl_private_surface_complete_paste(&r->target->base, r->id, status, text, len);
@@ -2027,7 +2028,7 @@ static void incr_send_retire(struct x11_display *d, struct incr_send *st, bool c
*p = st->next;
break;
}
- if (cancel_timer && st->timeout) yasl_private_loop_del_timer(d->loop, st->timeout);
+ if (cancel_timer && st->timeout) yasl_loop_del_timer(d->loop, st->timeout);
free(st->data);
free(st);
}
@@ -2045,8 +2046,8 @@ static uint64_t incr_send_timeout(void *ud, yasl_private_timer_id id, uint64_t i
static void incr_send_arm(struct incr_send *st)
{
struct x11_display *d = st->display;
- if (st->timeout) yasl_private_loop_del_timer(d->loop, st->timeout);
- st->timeout = yasl_private_loop_add_timer(d->loop, PASTE_TIMEOUT_NS, incr_send_timeout, st);
+ if (st->timeout) yasl_loop_del_timer(d->loop, st->timeout);
+ st->timeout = yasl_loop_add_timer(d->loop, PASTE_TIMEOUT_NS, incr_send_timeout, st);
}
/* Start an INCR send: publish the total size, then wait for the requestor to
@@ -2062,7 +2063,7 @@ static bool incr_send_start(struct x11_display *d, Window requestor, Atom proper
st->target = target;
st->data = data;
st->length = length;
- st->timeout = yasl_private_loop_add_timer(d->loop, PASTE_TIMEOUT_NS, incr_send_timeout, st);
+ st->timeout = yasl_loop_add_timer(d->loop, PASTE_TIMEOUT_NS, incr_send_timeout, st);
if (!st->timeout) {
free(st);
return false;
@@ -2325,14 +2326,14 @@ static void selection_notify(struct x11_display *d, XSelectionEvent *event)
/* Surface destruction detached this accepted request. The reply means
* the owner has finished writing the initial property; retire safely. */
*p = r->next;
- if (r->timeout) yasl_private_loop_del_timer(d->loop, r->timeout);
+ if (r->timeout) yasl_loop_del_timer(d->loop, r->timeout);
XDestroyWindow(d->native, r->window);
free(r);
return;
}
if (event->property == None) {
*p = r->next;
- if (r->timeout) yasl_private_loop_del_timer(d->loop, r->timeout);
+ if (r->timeout) yasl_loop_del_timer(d->loop, r->timeout);
enum yasl_private_transfer_status status =
XGetSelectionOwner(d->native, r->selection) == None
? YASL_PRIVATE_TRANSFER_UNAVAILABLE : YASL_PRIVATE_TRANSFER_FAILED;
@@ -2361,7 +2362,7 @@ static void selection_notify(struct x11_display *d, XSelectionEvent *event)
return;
}
*p = r->next;
- if (r->timeout) yasl_private_loop_del_timer(d->loop, r->timeout);
+ if (r->timeout) yasl_loop_del_timer(d->loop, r->timeout);
Atom actual = None;
int format = 0;
unsigned long count = 0, left = 0;
@@ -2938,56 +2939,49 @@ static void flush(struct yasl_private_display *base)
leave(d);
}
-static int ready(int fd, short events, void *ud)
+/* The connection is read in check(), before any callback. */
+static void ready(void *ud, int fd, short events)
+{
+ (void)ud; (void)fd; (void)events;
+}
+
+/* A hung-up socket stays readable; stop watching it so the loop does not spin. */
+static void drop_watch(struct x11_display *d)
+{
+ if (d->watch > 0) yasl_loop_del_fd(d->loop, d->watch);
+ d->watch = 0;
+}
+
+/* Before the wait: dispatch what Xlib already holds, draw due surfaces, and send
+ * requests. Loss is final, so a lost display only drops its watch. */
+static bool prepare(struct yasl_private_display *base)
{
- (void)fd;
- struct yasl_private_display *base = ud;
struct x11_display *d = (struct x11_display *)base;
- if (events & (POLLERR | POLLHUP)) display_lost(d);
- if (d->lost) {
- /* A hung-up socket stays readable; stop watching it so the loop does not spin. */
- if (d->watch > 0) yasl_private_loop_del_fd(d->loop, d->watch);
- d->watch = 0;
- return 0;
- }
- if (events & POLLIN) {
+ if (!d->lost) {
dispatch(base);
flush(base);
}
- return 0;
+ if (d->lost) {
+ drop_watch(d);
+ return false;
+ }
+ /* Replies awaited while drawing can read events into Xlib's queue. */
+ return XEventsQueued(d->native, QueuedAlready) > 0;
}
-static int dispatch_timeout(struct yasl_private_display *base, int timeout_ms)
+static void check(struct yasl_private_display *base)
{
struct x11_display *d = (struct x11_display *)base;
- if (unlikely(!d || !d->native)) { errno = ENODEV; return -1; }
- /* The DISPLAY_LOST event is delivered by the wait that found the loss. */
- if (d->lost) { errno = ENOTCONN; return -1; }
- dispatch(base);
- if (d->lost) return 0;
- for (struct x11_surface *s = d->surfaces; s; s = s->next) {
- if (s->want_draw || s->input.count || s->input.reset_pending) {
- timeout_ms = 0;
- break;
- }
- }
- if (d->loop) {
- XFlush(d->native);
- if (d->lost) return 0;
- if (XEventsQueued(d->native, QueuedAlready) > 0)
- timeout_ms = 0;
- if (!XPending(d->native) && timeout_ms != 0) {
- yasl_private_loop_step(d->loop, timeout_ms);
- dispatch(base);
- } else {
- yasl_private_loop_step(d->loop, 0);
- dispatch(base);
- }
+ short revents = d->watch > 0 ? yasl_private_loop_revents(d->loop, d->watch) : 0;
+ if (revents & (POLLERR | POLLHUP)) display_lost(d);
+ if (d->lost) {
+ drop_watch(d);
+ return;
}
- return 0;
+ if (revents & POLLIN) dispatch(base);
}
-static struct yasl_private_display *display_open(struct yasl_private_loop *loop,
+static struct yasl_private_display *display_open(struct yasl_loop *loop,
const struct yasl_private_display_spec *spec)
{
struct x11_display *d = calloc(1, sizeof(*d));
@@ -3046,7 +3040,7 @@ static struct yasl_private_display *display_open(struct yasl_private_loop *loop,
XISelectEvents(d->native, RootWindow(d->native, d->screen), &mask, 1);
}
if (!loop) {
- d->loop = yasl_private_loop_create();
+ d->loop = yasl_loop_create();
d->owns_loop = true;
} else {
d->loop = loop;
@@ -3055,7 +3049,7 @@ static struct yasl_private_display *display_open(struct yasl_private_loop *loop,
d->app_id = strdup(spec && spec->app_id ? spec->app_id : "YASL");
d->base.app_id = d->app_id;
if (!d->loop || !d->app_id) {
- if (d->owns_loop) yasl_private_loop_destroy(d->loop);
+ if (d->owns_loop) yasl_loop_destroy(d->loop);
free(d->app_id);
XCloseDisplay(d->native);
display_unregister(d);
@@ -3095,14 +3089,14 @@ static struct yasl_private_display *display_open(struct yasl_private_loop *loop,
ATOM(uri_list, "text/uri-list");
#undef ATOM
if (d->loop) {
- d->watch = yasl_private_loop_add_fd(d->loop, ConnectionNumber(d->native), POLLIN, ready, &d->base);
+ d->watch = yasl_loop_add_fd(d->loop, ConnectionNumber(d->native), POLLIN, ready, &d->base);
if (d->watch < 0) {
if (d->im) XCloseIM(d->im);
XDestroyWindow(d->native, d->selection_window);
XCloseDisplay(d->native);
display_unregister(d);
free(d->app_id);
- if (d->owns_loop) yasl_private_loop_destroy(d->loop);
+ if (d->owns_loop) yasl_loop_destroy(d->loop);
free(d);
return NULL;
}
@@ -3118,9 +3112,9 @@ static void display_close(struct yasl_private_display *base)
cancel_pastes(d, NULL);
incr_cancel_all(d);
d->pending_drop.active = false;
- if (d->loop && d->watch > 0) yasl_private_loop_del_fd(d->loop, d->watch);
+ if (d->loop && d->watch > 0) yasl_loop_del_fd(d->loop, d->watch);
if (d->owns_loop && d->loop) {
- yasl_private_loop_destroy(d->loop);
+ yasl_loop_destroy(d->loop);
d->loop = NULL;
d->base.loop = NULL;
}
@@ -3208,7 +3202,7 @@ static bool request_paste(struct yasl_private_display *base, enum yasl_private_s
r->selection = selection;
r->id = id;
errno = 0;
- r->timeout = yasl_private_loop_add_timer(d->loop, PASTE_TIMEOUT_NS,
+ r->timeout = yasl_loop_add_timer(d->loop, PASTE_TIMEOUT_NS,
paste_timeout, r);
if (!r->timeout) {
XDestroyWindow(d->native, r->window);
@@ -3236,8 +3230,8 @@ static void schedule_redraw(struct yasl_surface *base)
if (!s->destroyed) {
s->want_draw = true;
struct x11_display *d = (struct x11_display *)base->display;
- if (d && d->loop)
- yasl_private_loop_kick(d->loop);
+ if (d)
+ yasl_private_loop_wake(d->loop);
}
}
@@ -3668,7 +3662,8 @@ const struct yasl_private_backend_ops yasl_private_x11_backend = {
.display_open = display_open,
.display_close = display_close,
.display_caps = caps,
- .display_dispatch_timeout = dispatch_timeout,
+ .display_prepare = prepare,
+ .display_check = check,
.display_flush = flush,
.display_modifiers = mods,
.display_copy_text = copy_text,