mirror of
				https://github.com/swaywm/sway.git
				synced 2025-11-03 09:01:43 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			156 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			156 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#define _XOPEN_SOURCE 700
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdbool.h>
 | 
						|
#include <string.h>
 | 
						|
#include <strings.h>
 | 
						|
#include <poll.h>
 | 
						|
#include <time.h>
 | 
						|
#include "swaybar/event_loop.h"
 | 
						|
#include "list.h"
 | 
						|
 | 
						|
struct event_item {
 | 
						|
	void (*cb)(int fd, short mask, void *data);
 | 
						|
	void *data;
 | 
						|
};
 | 
						|
 | 
						|
struct timer_item {
 | 
						|
	timer_t timer;
 | 
						|
	void (*cb)(timer_t timer, void *data);
 | 
						|
	void *data;
 | 
						|
};
 | 
						|
 | 
						|
static struct {
 | 
						|
	// The order of each must be kept consistent
 | 
						|
	struct {   /* pollfd array */
 | 
						|
		struct pollfd *items;
 | 
						|
		int capacity;
 | 
						|
		int length;
 | 
						|
	} fds;
 | 
						|
	list_t *items; /* event_item list */
 | 
						|
 | 
						|
	// Timer list
 | 
						|
	list_t *timers;
 | 
						|
} event_loop;
 | 
						|
 | 
						|
void add_timer(timer_t timer,
 | 
						|
		void(*cb)(timer_t timer, void *data),
 | 
						|
		void *data) {
 | 
						|
 | 
						|
	struct timer_item *item = malloc(sizeof(struct timer_item));
 | 
						|
	item->timer = timer;
 | 
						|
	item->cb = cb;
 | 
						|
	item->data = data;
 | 
						|
 | 
						|
	list_add(event_loop.timers, item);
 | 
						|
}
 | 
						|
 | 
						|
void add_event(int fd, short mask,
 | 
						|
		void(*cb)(int fd, short mask, void *data), void *data) {
 | 
						|
 | 
						|
	struct pollfd pollfd = {
 | 
						|
		fd,
 | 
						|
		mask,
 | 
						|
		0,
 | 
						|
	};
 | 
						|
 | 
						|
	// Resize
 | 
						|
	if (event_loop.fds.length == event_loop.fds.capacity) {
 | 
						|
		event_loop.fds.capacity += 10;
 | 
						|
		event_loop.fds.items = realloc(event_loop.fds.items,
 | 
						|
			sizeof(struct pollfd) * event_loop.fds.capacity);
 | 
						|
	}
 | 
						|
 | 
						|
	event_loop.fds.items[event_loop.fds.length++] = pollfd;
 | 
						|
 | 
						|
	struct event_item *item = malloc(sizeof(struct event_item));
 | 
						|
	item->cb = cb;
 | 
						|
	item->data = data;
 | 
						|
 | 
						|
	list_add(event_loop.items, item);
 | 
						|
 | 
						|
	return;
 | 
						|
}
 | 
						|
 | 
						|
bool remove_event(int fd) {
 | 
						|
	/*
 | 
						|
	 * Instead of removing events immediately, we mark them for deletion
 | 
						|
	 * and clean them up later. This is so we can call remove_event inside
 | 
						|
	 * an event callback safely.
 | 
						|
	 */
 | 
						|
	for (int i = 0; i < event_loop.fds.length; ++i) {
 | 
						|
		if (event_loop.fds.items[i].fd == fd) {
 | 
						|
			event_loop.fds.items[i].fd = -1;
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return false;
 | 
						|
}
 | 
						|
 | 
						|
static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) {
 | 
						|
	const struct timer_item *timer_item = _timer_item;
 | 
						|
	const timer_t *timer = _timer;
 | 
						|
	if (timer_item->timer == *timer) {
 | 
						|
		return 0;
 | 
						|
	} else {
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
}
 | 
						|
bool remove_timer(timer_t timer) {
 | 
						|
	int index = list_seq_find(event_loop.timers, timer_item_timer_cmp, &timer);
 | 
						|
	if (index != -1) {
 | 
						|
		free(event_loop.timers->items[index]);
 | 
						|
		list_del(event_loop.timers, index);
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
	return false;
 | 
						|
}
 | 
						|
 | 
						|
void event_loop_poll(void) {
 | 
						|
	poll(event_loop.fds.items, event_loop.fds.length, -1);
 | 
						|
 | 
						|
	for (int i = 0; i < event_loop.fds.length; ++i) {
 | 
						|
		struct pollfd pfd = event_loop.fds.items[i];
 | 
						|
		struct event_item *item = (struct event_item *)event_loop.items->items[i];
 | 
						|
 | 
						|
		// Always send these events
 | 
						|
		unsigned events = pfd.events | POLLHUP | POLLERR;
 | 
						|
 | 
						|
		if (pfd.revents & events) {
 | 
						|
			item->cb(pfd.fd, pfd.revents, item->data);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Cleanup removed events
 | 
						|
	int end = 0;
 | 
						|
	int length = event_loop.fds.length;
 | 
						|
	for (int i = 0; i < length; ++i) {
 | 
						|
		if (event_loop.fds.items[i].fd == -1) {
 | 
						|
			free(event_loop.items->items[i]);
 | 
						|
			list_del(event_loop.items, i);
 | 
						|
			--event_loop.fds.length;
 | 
						|
		} else if (end != i) {
 | 
						|
			event_loop.fds.items[end++] = event_loop.fds.items[i];
 | 
						|
		} else {
 | 
						|
			end = i + 1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// check timers
 | 
						|
	// not tested, but seems to work
 | 
						|
	for (int i = 0; i < event_loop.timers->length; ++i) {
 | 
						|
		struct timer_item *item = event_loop.timers->items[i];
 | 
						|
		int overrun = timer_getoverrun(item->timer);
 | 
						|
		if (overrun && overrun != -1) {
 | 
						|
			item->cb(item->timer, item->data);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void init_event_loop(void) {
 | 
						|
	event_loop.fds.length = 0;
 | 
						|
	event_loop.fds.capacity = 10;
 | 
						|
	event_loop.fds.items = malloc(
 | 
						|
			event_loop.fds.capacity * sizeof(struct pollfd));
 | 
						|
	event_loop.items = create_list();
 | 
						|
	event_loop.timers = create_list();
 | 
						|
}
 |