diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/loop.c | 180 | ||||
-rw-r--r-- | common/meson.build | 1 | ||||
-rw-r--r-- | common/pango.c | 15 |
3 files changed, 190 insertions, 6 deletions
diff --git a/common/loop.c b/common/loop.c new file mode 100644 index 00000000..750bee75 --- /dev/null +++ b/common/loop.c @@ -0,0 +1,180 @@ +#define _POSIX_C_SOURCE 199309L +#include <limits.h> +#include <string.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <poll.h> +#include <time.h> +#include <unistd.h> +#include "list.h" +#include "log.h" +#include "loop.h" + +struct loop_fd_event { + void (*callback)(int fd, short mask, void *data); + void *data; +}; + +struct loop_timer { + void (*callback)(void *data); + void *data; + struct timespec expiry; +}; + +struct loop { + struct pollfd *fds; + int fd_length; + int fd_capacity; + + list_t *fd_events; // struct loop_fd_event + list_t *timers; // struct loop_timer +}; + +struct loop *loop_create(void) { + struct loop *loop = calloc(1, sizeof(struct loop)); + if (!loop) { + wlr_log(WLR_ERROR, "Unable to allocate memory for loop"); + return NULL; + } + loop->fd_capacity = 10; + loop->fds = malloc(sizeof(struct pollfd) * loop->fd_capacity); + loop->fd_events = create_list(); + loop->timers = create_list(); + return loop; +} + +void loop_destroy(struct loop *loop) { + list_foreach(loop->fd_events, free); + list_foreach(loop->timers, free); + list_free(loop->fd_events); + list_free(loop->timers); + free(loop->fds); + free(loop); +} + +void loop_poll(struct loop *loop) { + // Calculate next timer in ms + int ms = INT_MAX; + if (loop->timers->length) { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + for (int i = 0; i < loop->timers->length; ++i) { + struct loop_timer *timer = loop->timers->items[i]; + int timer_ms = (timer->expiry.tv_sec - now.tv_sec) * 1000; + timer_ms += (timer->expiry.tv_nsec - now.tv_nsec) / 1000000; + if (timer_ms < ms) { + ms = timer_ms; + } + } + } + if (ms < 0) { + ms = 0; + } + + poll(loop->fds, loop->fd_length, ms); + + // Dispatch fds + for (int i = 0; i < loop->fd_length; ++i) { + struct pollfd pfd = loop->fds[i]; + struct loop_fd_event *event = loop->fd_events->items[i]; + + // Always send these events + unsigned events = pfd.events | POLLHUP | POLLERR; + + if (pfd.revents & events) { + event->callback(pfd.fd, pfd.revents, event->data); + } + } + + // Dispatch timers + if (loop->timers->length) { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + for (int i = 0; i < loop->timers->length; ++i) { + struct loop_timer *timer = loop->timers->items[i]; + bool expired = timer->expiry.tv_sec < now.tv_sec || + (timer->expiry.tv_sec == now.tv_sec && + timer->expiry.tv_nsec < now.tv_nsec); + if (expired) { + timer->callback(timer->data); + loop_remove_timer(loop, timer); + --i; + } + } + } +} + +void loop_add_fd(struct loop *loop, int fd, short mask, + void (*callback)(int fd, short mask, void *data), void *data) { + struct loop_fd_event *event = calloc(1, sizeof(struct loop_fd_event)); + if (!event) { + wlr_log(WLR_ERROR, "Unable to allocate memory for event"); + return; + } + event->callback = callback; + event->data = data; + list_add(loop->fd_events, event); + + struct pollfd pfd = {fd, mask, 0}; + + if (loop->fd_length == loop->fd_capacity) { + loop->fd_capacity += 10; + loop->fds = realloc(loop->fds, + sizeof(struct pollfd) * loop->fd_capacity); + } + + loop->fds[loop->fd_length++] = pfd; +} + +struct loop_timer *loop_add_timer(struct loop *loop, int ms, + void (*callback)(void *data), void *data) { + struct loop_timer *timer = calloc(1, sizeof(struct loop_timer)); + if (!timer) { + wlr_log(WLR_ERROR, "Unable to allocate memory for timer"); + return NULL; + } + timer->callback = callback; + timer->data = data; + + clock_gettime(CLOCK_MONOTONIC, &timer->expiry); + timer->expiry.tv_sec += ms / 1000; + + long int nsec = (ms % 1000) * 1000000; + if (timer->expiry.tv_nsec + nsec >= 1000000000) { + timer->expiry.tv_sec++; + nsec -= 1000000000; + } + timer->expiry.tv_nsec += nsec; + + list_add(loop->timers, timer); + + return timer; +} + +bool loop_remove_fd(struct loop *loop, int fd) { + for (int i = 0; i < loop->fd_length; ++i) { + if (loop->fds[i].fd == fd) { + free(loop->fd_events->items[i]); + list_del(loop->fd_events, i); + + loop->fd_length--; + memmove(&loop->fds[i], &loop->fds[i + 1], + sizeof(struct pollfd) * (loop->fd_length - i)); + + return true; + } + } + return false; +} + +bool loop_remove_timer(struct loop *loop, struct loop_timer *timer) { + for (int i = 0; i < loop->timers->length; ++i) { + if (loop->timers->items[i] == timer) { + list_del(loop->timers, i); + free(timer); + return true; + } + } + return false; +} diff --git a/common/meson.build b/common/meson.build index 44a29508..224a9c3f 100644 --- a/common/meson.build +++ b/common/meson.build @@ -5,6 +5,7 @@ lib_sway_common = static_library( 'cairo.c', 'ipc-client.c', 'log.c', + 'loop.c', 'list.c', 'pango.c', 'readline.c', diff --git a/common/pango.c b/common/pango.c index ba74692e..3bc97808 100644 --- a/common/pango.c +++ b/common/pango.c @@ -10,6 +10,9 @@ #include "log.h" #include "stringop.h" +static const char overflow[] = "[buffer overflow]"; +static const int max_chars = 16384; + size_t escape_markup_text(const char *src, char *dest) { size_t length = 0; if (dest) { @@ -84,12 +87,12 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, int *baseline, double scale, bool markup, const char *fmt, ...) { - static char buf[2048]; + char buf[max_chars]; va_list args; va_start(args, fmt); - if (vsnprintf(buf, 2048, fmt, args) >= 2048) { - strcpy(buf, "[buffer overflow]"); + if (vsnprintf(buf, sizeof(buf), fmt, args) >= max_chars) { + strcpy(&buf[sizeof(buf) - sizeof(overflow)], overflow); } va_end(args); @@ -104,12 +107,12 @@ void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, void pango_printf(cairo_t *cairo, const char *font, double scale, bool markup, const char *fmt, ...) { - static char buf[2048]; + char buf[max_chars]; va_list args; va_start(args, fmt); - if (vsnprintf(buf, 2048, fmt, args) >= 2048) { - strcpy(buf, "[buffer overflow]"); + if (vsnprintf(buf, sizeof(buf), fmt, args) >= max_chars) { + strcpy(&buf[sizeof(buf) - sizeof(overflow)], overflow); } va_end(args); |