diff options
Diffstat (limited to 'src/x11/window.c')
| -rw-r--r-- | src/x11/window.c | 51 |
1 files changed, 42 insertions, 9 deletions
diff --git a/src/x11/window.c b/src/x11/window.c index b80bfe0..4680d3f 100644 --- a/src/x11/window.c +++ b/src/x11/window.c @@ -19,6 +19,13 @@ #define INPUT_CAP 256 #define TEXT_LIMIT (16 * 1024 * 1024) +#ifndef likely +#define likely(x) __builtin_expect(!!(x), 1) +#endif +#ifndef unlikely +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + struct x11_surface { struct yasl_surface base; struct x11_surface *next; @@ -58,6 +65,7 @@ struct x11_display { struct x11_surface *paste_target; uint32_t mods; char *app_id; + bool owns_loop; }; static struct x11_display *display_of(const struct yasl_surface *s) @@ -438,10 +446,10 @@ static void dispatch(struct yasl_display *base) static unsigned long component(uint32_t color, unsigned long mask) { - if (!mask) return 0; - unsigned shift = 0; - while (!(mask & 1)) { mask >>= 1; shift++; } - return (((unsigned long)color * mask + 127) / 255) << shift; + if (unlikely(!mask)) return 0; + unsigned shift = (unsigned)__builtin_ctzl(mask); + unsigned long m = mask >> shift; + return (((unsigned long)color * m + 127) / 255) << shift; } static bool present(struct yasl_surface *base, const struct yasl_framebuffer *fb, @@ -511,6 +519,18 @@ static int ready(int fd, short events, void *ud) return 0; } +static int dispatch_timeout(struct yasl_display *base, int timeout_ms) +{ + struct x11_display *d = (struct x11_display *)base; + if (unlikely(!d || !d->native)) return -1; + dispatch(base); + if (!XPending(d->native) && d->loop && timeout_ms != 0) { + yasl_loop_step(d->loop, timeout_ms); + dispatch(base); + } + return 0; +} + static struct yasl_display *display_open(struct yasl_loop *loop, const struct yasl_display_spec *spec) { @@ -520,7 +540,12 @@ static struct yasl_display *display_open(struct yasl_loop *loop, d->native = XOpenDisplay(NULL); if (!d->native) { free(d); errno = ENODEV; return NULL; } d->screen = DefaultScreen(d->native); - d->loop = loop; + if (!loop) { + d->loop = yasl_loop_create(); + d->owns_loop = true; + } else { + d->loop = loop; + } d->app_id = strdup(spec && spec->app_id ? spec->app_id : "YASL"); if (!d->app_id) { XCloseDisplay(d->native); free(d); return NULL; } d->im = XOpenIM(d->native, NULL, NULL, NULL); @@ -539,13 +564,14 @@ static struct yasl_display *display_open(struct yasl_loop *loop, ATOM(maximized_h, "_NET_WM_STATE_MAXIMIZED_HORZ"); ATOM(maximized_v, "_NET_WM_STATE_MAXIMIZED_VERT"); #undef ATOM - if (loop) { - d->watch = yasl_loop_add_fd(loop, ConnectionNumber(d->native), POLLIN, ready, &d->base); + if (d->loop) { + 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); free(d->app_id); + if (d->owns_loop) yasl_loop_destroy(d->loop); free(d); return NULL; } @@ -557,7 +583,8 @@ static void display_close(struct yasl_display *base) { struct x11_display *d = (struct x11_display *)base; assert(!d->surfaces && "destroy every surface before its display"); - if (d->loop) yasl_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_loop_destroy(d->loop); if (d->im) XCloseIM(d->im); XDestroyWindow(d->native, d->selection_window); XCloseDisplay(d->native); @@ -619,7 +646,12 @@ static bool input_poll(struct yasl_surface *base, struct yasl_input_event *event static void schedule_redraw(struct yasl_surface *base) { struct x11_surface *s = (struct x11_surface *)base; - if (!s->destroyed) s->want_draw = true; + if (!s->destroyed) { + s->want_draw = true; + struct x11_display *d = display_of(base); + if (d && d->loop) + yasl_loop_kick(d->loop); + } } static struct yasl_display *surface_display(const struct yasl_surface *s) { return s->display; } @@ -698,6 +730,7 @@ const struct yasl_backend_ops yasl_x11_backend = { .display_close = display_close, .display_caps = caps, .display_dispatch = dispatch, + .display_dispatch_timeout = dispatch_timeout, .display_flush = flush, .display_modifiers = mods, .display_copy = copy, |
