PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
display.c
Go to the documentation of this file.
1#include "internal.h"
2
3#include <errno.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <sys/list.h>
8
9static inline uint64_t display_events_read(display_t* disp, event_t* event)
10{
11 if (disp->events.readIndex == disp->events.writeIndex)
12 {
13 return 0;
14 }
15
16 *event = disp->events.buffer[disp->events.readIndex];
18 return sizeof(event_t);
19}
20
21static inline uint64_t display_events_write(display_t* disp, const event_t* event)
22{
23 uint64_t nextIndex = (disp->events.writeIndex + 1) % DISPLAY_MAX_EVENT;
24 if (nextIndex == disp->events.readIndex)
25 {
26 return ERR;
27 }
28
29 disp->events.buffer[disp->events.writeIndex] = *event;
30 disp->events.writeIndex = nextIndex;
31 return sizeof(event_t);
32}
33
35{
36 if (disp->events.writeIndex >= disp->events.readIndex)
37 {
38 return disp->events.writeIndex - disp->events.readIndex;
39 }
40 else
41 {
42 return DISPLAY_MAX_EVENT - (disp->events.readIndex - disp->events.writeIndex);
43 }
44}
45
47{
48 display_t* disp = malloc(sizeof(display_t));
49 if (disp == NULL)
50 {
51 errno = ENOMEM;
52 return NULL;
53 }
54
55 disp->id = readfiles("/net/local/seqpacket");
56 if (disp->id == NULL)
57 {
58 free(disp);
59 return NULL;
60 }
61
62 disp->ctl = open(F("/net/local/%s/ctl", disp->id));
63 if (disp->ctl == ERR)
64 {
65 free(disp->id);
66 free(disp);
67 return NULL;
68 }
69 if (writes(disp->ctl, "connect dwm") == ERR)
70 {
71 close(disp->ctl);
72 free(disp->id);
73 free(disp);
74 return NULL;
75 }
76
77 disp->data = open(F("/net/local/%s/data", disp->id));
78 if (disp->data == ERR)
79 {
80 close(disp->ctl);
81 free(disp->id);
82 free(disp);
83 return NULL;
84 }
85
86 memset(&disp->events, 0, sizeof(disp->events));
87
88 disp->isConnected = true;
89 disp->cmds.amount = 0;
91 list_init(&disp->windows);
92 list_init(&disp->fonts);
93 list_init(&disp->images);
94
95 // Default font might be `NULL`.
96 disp->defaultFont = font_new(disp, "default", "regular", 16);
97
98 if (mtx_init(&disp->mutex, mtx_recursive) == thrd_error)
99 {
100 font_free(disp->defaultFont);
101 close(disp->data);
102 close(disp->ctl);
103 free(disp->id);
104 free(disp);
105 return NULL;
106 }
107
108 return disp;
109}
110
112{
113 if (disp == NULL)
114 {
115 return;
116 }
117
118 window_t* window;
119 window_t* temp1;
120 LIST_FOR_EACH_SAFE(window, temp1, &disp->windows, entry)
121 {
122 window_free(window);
123 }
124
125 font_t* font;
126 font_t* temp2;
127 LIST_FOR_EACH_SAFE(font, temp2, &disp->fonts, entry)
128 {
129 font_free(font);
130 }
131
132 image_t* image;
133 image_t* temp3;
134 LIST_FOR_EACH_SAFE(image, temp3, &disp->images, entry)
135 {
137 }
138
139 close(disp->ctl);
140 close(disp->data);
141 mtx_destroy(&disp->mutex);
142 free(disp->id);
143 free(disp);
144}
145
147{
148 if (disp == NULL)
149 {
150 return false;
151 }
152
153 mtx_lock(&disp->mutex);
154 bool temp = disp->isConnected;
155 mtx_unlock(&disp->mutex);
156 return temp;
157}
158
160{
161 if (disp == NULL)
162 {
163 return;
164 }
165
166 mtx_lock(&disp->mutex);
167 disp->isConnected = false;
168 mtx_unlock(&disp->mutex);
169}
170
172{
173 if (disp == NULL || size > CMD_BUFFER_MAX_DATA)
174 {
175 errno = EINVAL;
176 return NULL;
177 }
178
179 mtx_lock(&disp->mutex);
180 if (disp->cmds.size + size >= CMD_BUFFER_MAX_DATA)
181 {
182 display_cmds_flush(disp);
183 }
184
185 cmd_header_t* cmd = (cmd_header_t*)((uint64_t)&disp->cmds + disp->cmds.size);
186 disp->cmds.amount++;
187 disp->cmds.size += size;
188
189 cmd->magic = CMD_MAGIC;
190 cmd->type = type;
191 cmd->size = size;
192 mtx_unlock(&disp->mutex);
193 return cmd;
194}
195
197{
198 mtx_lock(&disp->mutex);
199 if (disp->isConnected && disp->cmds.amount != 0)
200 {
201 if (write(disp->data, &disp->cmds, disp->cmds.size) != disp->cmds.size)
202 {
203 disp->isConnected = false;
204 }
205 }
207 disp->cmds.amount = 0;
208 mtx_unlock(&disp->mutex);
209}
210
212{
213 if (disp == NULL || event == NULL)
214 {
215 errno = EINVAL;
216 return ERR;
217 }
218
219 mtx_lock(&disp->mutex);
220 if (!disp->isConnected)
221 {
222 mtx_unlock(&disp->mutex);
223 errno = ENOTCONN;
224 return ERR;
225 }
226 size_t readBytes = display_events_read(disp, event);
227 mtx_unlock(&disp->mutex);
228 if (readBytes == sizeof(event_t))
229 {
230 return 0;
231 }
232 else if (readBytes == ERR)
233 {
234 return ERR;
235 }
236
237 poll_events_t revents = poll1(disp->data, POLLIN, timeout);
238 if (revents & POLLERR)
239 {
240 display_disconnect(disp);
241 return ERR;
242 }
243 else if (!(revents & POLLIN))
244 {
246 return ERR;
247 }
248
249 mtx_lock(&disp->mutex);
250 if (!disp->isConnected)
251 {
252 mtx_unlock(&disp->mutex);
253 errno = ENOTCONN;
254 return ERR;
255 }
256 if (read(disp->data, event, sizeof(event_t)) != sizeof(event_t))
257 {
258 disp->isConnected = false;
259 mtx_unlock(&disp->mutex);
260 return ERR;
261 }
262 mtx_unlock(&disp->mutex);
263 return 0;
264}
265
267{
268 if (disp == NULL || fds == NULL)
269 {
270 errno = EINVAL;
271 return ERR;
272 }
273
274 if (!display_is_connected(disp))
275 {
276 errno = ENOTCONN;
277 return ERR;
278 }
279
280 pollfd_t* allFds = malloc(sizeof(pollfd_t) * (nfds + 2));
281 if (allFds == NULL)
282 {
283 errno = ENOMEM;
284 return ERR;
285 }
286
287 allFds[0].fd = disp->data;
288 allFds[0].events = POLLIN;
289 for (uint64_t i = 0; i < nfds; i++)
290 {
291 allFds[i + 1] = fds[i];
292 }
293
294 size_t ready = poll(allFds, nfds + 1, timeout);
295 if (ready == ERR)
296 {
297 free(allFds);
298 return ERR;
299 }
300
301 if (allFds[0].revents & POLLERR)
302 {
303 display_disconnect(disp);
304 free(allFds);
305 return ERR;
306 }
307
308 uint64_t totalReady = ready;
309 if (allFds[0].revents & POLLIN)
310 {
311 totalReady--;
312 }
313 for (uint64_t i = 0; i < nfds; i++)
314 {
315 fds[i].revents = allFds[i + 1].revents;
316 }
317 free(allFds);
318 return totalReady;
319}
320
321void display_push(display_t* disp, surface_id_t target, event_type_t type, void* data, uint64_t size)
322{
323 if (disp == NULL || (data == NULL && size > 0) || size > EVENT_MAX_DATA)
324 {
325 return;
326 }
327
328 event_t event = {
329 .target = target,
330 .type = type,
331 };
332 memcpy(event.raw, data, MIN(EVENT_MAX_DATA, size));
333
334 mtx_lock(&disp->mutex);
335 display_events_write(disp, &event);
336 mtx_unlock(&disp->mutex);
337}
338
340{
341 if (disp == NULL || event == NULL)
342 {
343 errno = EINVAL;
344 return ERR;
345 }
346
347 mtx_lock(&disp->mutex);
348 uint64_t eventsInPipe = display_events_amount(disp);
349 for (uint64_t i = 0; i < eventsInPipe; i++)
350 {
351 if (display_events_read(disp, event) == ERR)
352 {
353 mtx_unlock(&disp->mutex);
354 return ERR;
355 }
356
357 if (event->type != expected)
358 {
359 display_events_write(disp, event);
360 }
361 else
362 {
363 mtx_unlock(&disp->mutex);
364 return 0;
365 }
366 }
367
368 while (true)
369 {
370 if (read(disp->data, event, sizeof(event_t)) != sizeof(event_t))
371 {
372 disp->isConnected = false;
373 mtx_unlock(&disp->mutex);
374 return ERR;
375 }
376
377 if (event->type == expected)
378 {
379 mtx_unlock(&disp->mutex);
380 return 0;
381 }
382
383 mtx_lock(&disp->mutex);
384 display_events_write(disp, event);
385 mtx_unlock(&disp->mutex);
386 }
387}
388
390{
391 if (disp == NULL || (data == NULL && size > 0) || size > EVENT_MAX_DATA)
392 {
393 errno = EINVAL;
394 return ERR;
395 }
396
397 event_t event = {
398 .target = target,
399 .type = type,
400 };
401 memcpy(event.raw, data, MIN(EVENT_MAX_DATA, size));
402 if (display_dispatch(disp, &event) == ERR)
403 {
404 return ERR;
405 }
406
407 return 0;
408}
409
411{
412 if (disp == NULL || event == NULL)
413 {
414 errno = EINVAL;
415 return ERR;
416 }
417
418 mtx_lock(&disp->mutex);
419 window_t* win;
420 window_t* temp;
421 LIST_FOR_EACH_SAFE(win, temp, &disp->windows, entry)
422 {
423 if (event->target == win->surface || event->target == SURFACE_ID_NONE)
424 {
425 if (window_dispatch(win, event) == ERR)
426 {
427 disp->isConnected = false;
428 }
429
430 if (event->target == win->surface)
431 {
432 break;
433 }
434 }
435 }
436
437 display_cmds_flush(disp);
438 mtx_unlock(&disp->mutex);
439 return 0;
440}
441
443{
444 if (disp == NULL)
445 {
446 errno = EINVAL;
447 return ERR;
448 }
449
450 mtx_lock(&disp->mutex);
451 uint64_t eventsInPipe = display_events_amount(disp);
452 for (uint64_t i = 0; i < eventsInPipe; i++)
453 {
454 event_t event;
455 if (display_events_read(disp, &event) == ERR)
456 {
457 mtx_unlock(&disp->mutex);
458 return ERR;
459 }
460
461 if (event.type == type && (event.target == target || target == SURFACE_ID_NONE))
462 {
463 if (display_dispatch(disp, &event) == ERR)
464 {
465 mtx_unlock(&disp->mutex);
466 return ERR;
467 }
468 }
469 else
470 {
471 display_events_write(disp, &event);
472 }
473 }
474 mtx_unlock(&disp->mutex);
475
476 return 0;
477}
478
480{
481 if (disp == NULL)
482 {
483 errno = EINVAL;
484 return ERR;
485 }
486
488 if (cmd == NULL)
489 {
490 mtx_unlock(&disp->mutex);
491 return ERR;
492 }
493 cmd->event = type;
494 display_cmds_flush(disp);
495 return 0;
496}
497
499{
500 if (disp == NULL)
501 {
502 errno = EINVAL;
503 return ERR;
504 }
505
507 if (cmd == NULL)
508 {
509 mtx_unlock(&disp->mutex);
510 return ERR;
511 }
512 cmd->event = type;
513 display_cmds_flush(disp);
514 return 0;
515}
516
518{
519 if (disp == NULL || info == NULL)
520 {
521 errno = EINVAL;
522 return ERR;
523 }
524
526 if (cmd == NULL)
527 {
528 mtx_unlock(&disp->mutex);
529 return ERR;
530 }
531 cmd->isGlobal = true;
532 cmd->target = id;
533 display_cmds_flush(disp);
534
535 event_t event;
536 if (display_wait(disp, &event, EVENT_REPORT) == ERR)
537 {
538 return ERR;
539 }
540 *info = event.report.info;
541 return 0;
542}
543
545{
547 if (cmd == NULL)
548 {
549 mtx_unlock(&disp->mutex);
550 return ERR;
551 }
552 cmd->isGlobal = true;
553 cmd->target = id;
554 display_cmds_flush(disp);
555 return 0;
556}
557
559{
562 if (cmd == NULL)
563 {
564 return ERR;
565 }
566 cmd->isGlobal = true;
567 cmd->target = id;
568 cmd->isVisible = isVisible;
569 display_cmds_flush(disp);
570 return 0;
571}
572
574{
575 if (disp == NULL || rect == NULL)
576 {
577 errno = EINVAL;
578 return ERR;
579 }
580
582 if (cmd == NULL)
583 {
584 return ERR;
585 }
586 cmd->index = index;
587 display_cmds_flush(disp);
588
589 event_t event;
590 if (display_wait(disp, &event, EVENT_SCREEN_INFO) == ERR)
591 {
592 return ERR;
593 }
594 *rect = RECT_INIT(0, 0, event.screenInfo.width, event.screenInfo.height);
595 return 0;
596}
static image_t * image
Definition main.c:6
cmd_type_t
Definition cmd.h:23
@ CMD_SUBSCRIBE
Definition cmd.h:33
@ CMD_UNSUBSCRIBE
Definition cmd.h:34
@ CMD_SURFACE_REPORT
Definition cmd.h:32
@ CMD_SURFACE_VISIBLE_SET
Definition cmd.h:31
@ CMD_SURFACE_FOCUS_SET
Definition cmd.h:30
@ CMD_SCREEN_INFO
Definition cmd.h:24
#define CMD_BUFFER_MAX_DATA
Definition cmd.h:129
#define CMD_MAGIC
Definition cmd.h:38
static uint64_t display_events_write(display_t *disp, const event_t *event)
Definition display.c:21
static uint64_t display_events_read(display_t *disp, event_t *event)
Definition display.c:9
static uint64_t display_events_amount(display_t *disp)
Definition display.c:34
static fd_t data
Definition dwm.c:21
static char * id
Definition dwm.c:20
void font_free(font_t *font)
Definition font.c:91
font_t * font_new(display_t *disp, const char *family, const char *weight, uint64_t size)
Definition font.c:17
void display_disconnect(display_t *disp)
Disconnect the display connection.
Definition display.c:159
uint64_t display_poll(display_t *disp, pollfd_t *fds, uint64_t nfds, clock_t timeout)
Poll the display connection for events together with other file descriptors.
Definition display.c:266
void * display_cmd_alloc(display_t *disp, cmd_type_t type, uint64_t size)
Allocate a section of the displays command buffer.
Definition display.c:171
uint64_t display_next(display_t *disp, event_t *event, clock_t timeout)
Retrieve the next event from the display connection.
Definition display.c:211
uint64_t display_unsubscribe(display_t *disp, event_type_t type)
Unsubscribe from events of a specific type.
Definition display.c:498
void display_cmds_flush(display_t *disp)
Flush the display's command buffer.
Definition display.c:196
uint64_t display_dispatch(display_t *disp, const event_t *event)
Dispatch an event to the appropriate surface.
Definition display.c:410
void display_push(display_t *disp, surface_id_t target, event_type_t type, void *data, uint64_t size)
Push an event to the display's internal event queue.
Definition display.c:321
uint64_t display_wait(display_t *disp, event_t *event, event_type_t expected)
Wait for the display to receive an event of the expected type.
Definition display.c:339
uint64_t display_get_screen(display_t *disp, rect_t *rect, uint64_t index)
Get the rectangle of a screen.
Definition display.c:573
void display_free(display_t *disp)
Free a display connection.
Definition display.c:111
uint64_t display_set_focus(display_t *disp, surface_id_t id)
Set the focus to a surface.
Definition display.c:544
bool display_is_connected(display_t *disp)
Check if the display connection is still connected.
Definition display.c:146
uint64_t display_emit(display_t *disp, surface_id_t target, event_type_t type, void *data, uint64_t size)
Emit an event to a target surface.
Definition display.c:389
uint64_t display_dispatch_pending(display_t *disp, event_type_t type, surface_id_t target)
Dispatch all events currently in the display's internal event queue of a specific type and target.
Definition display.c:442
display_t * display_new(void)
Create a new display connection.
Definition display.c:46
uint64_t display_get_surface_info(display_t *disp, surface_id_t id, surface_info_t *info)
Get information about a surface.
Definition display.c:517
uint64_t display_subscribe(display_t *disp, event_type_t type)
Subscribe to events of a specific type.
Definition display.c:479
uint64_t display_set_is_visible(display_t *disp, surface_id_t id, bool isVisible)
Set the visibility of a surface.
Definition display.c:558
#define EVENT_MAX_DATA
Maximum size of event data.
Definition event.h:298
uint16_t event_type_t
Event type.
Definition event.h:71
#define EVENT_REPORT
Definition event.h:88
#define EVENT_SCREEN_INFO
Definition event.h:81
#define SURFACE_ID_NONE
Definition surface.h:54
uint64_t surface_id_t
Definition surface.h:53
uint64_t window_dispatch(window_t *win, const event_t *event)
Dispatch an event to the window's elements.
Definition window.c:610
void window_free(window_t *win)
Free a window.
Definition window.c:427
#define EINVAL
Invalid argument.
Definition errno.h:142
#define ETIMEDOUT
Connection timed out.
Definition errno.h:577
#define ENOMEM
Out of memory.
Definition errno.h:92
#define errno
Error number variable.
Definition errno.h:27
#define ENOTCONN
Transport endpoint is not connected.
Definition errno.h:562
fd_t open(const char *path)
System call for opening files.
Definition open.c:8
poll_events_t poll1(fd_t fd, poll_events_t events, clock_t timeout)
Wrapper for polling one file.
Definition poll1.c:8
uint64_t close(fd_t fd)
System call for closing files.
Definition close.c:8
char * readfiles(const char *path)
Wrapper for reading an entire file directly into a null-terminated string.
Definition sreadfile.c:3
#define F(format,...)
Allocates a formatted string on the stack.
Definition fs.h:67
size_t write(fd_t fd, const void *buffer, size_t count)
System call for writing to files.
Definition write.c:8
uint64_t poll(pollfd_t *fds, uint64_t amount, clock_t timeout)
System call for polling files.
Definition poll.c:8
size_t read(fd_t fd, void *buffer, size_t count)
System call for reading from files.
Definition read.c:8
poll_events_t
Poll events type.
Definition fs.h:286
size_t writes(fd_t fd, const char *string)
Wrapper for writing a null-terminated string to a file.
Definition swrite.c:4
@ POLLIN
File descriptor is ready to read.
Definition fs.h:288
@ POLLERR
File descriptor caused an error.
Definition fs.h:290
#define LIST_FOR_EACH_SAFE(elem, temp, list, member)
Safely iterates over a list, allowing for element removal during iteration.
Definition list.h:73
static void list_init(list_t *list)
Initializes a list.
Definition list.h:185
#define MIN(x, y)
Definition math.h:18
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
__UINT64_TYPE__ clock_t
A nanosecond time.
Definition clock_t.h:13
void image_free(image_t *image)
Definition image.c:74
#define DISPLAY_MAX_EVENT
Definition internal.h:58
#define RECT_INIT(left, top, right, bottom)
Definition rect.h:26
#define offsetof(type, member)
Definition stddef.h:16
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC void * memcpy(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
Definition memcpy.c:61
_PUBLIC void * memset(void *s, int c, size_t n)
Definition memset.c:4
uint64_t amount
Definition cmd.h:138
uint64_t size
Definition cmd.h:139
uint32_t magic
Definition cmd.h:42
cmd_type_t type
Definition cmd.h:43
uint64_t size
Definition cmd.h:44
uint64_t index
Definition cmd.h:50
event_type_t event
Definition cmd.h:120
surface_id_t target
Definition cmd.h:99
surface_id_t target
Definition cmd.h:114
surface_id_t target
Definition cmd.h:106
event_type_t event
Definition cmd.h:126
Opaque display structure.
Definition internal.h:68
mtx_t mutex
Definition internal.h:79
fd_t ctl
Definition internal.h:70
list_t images
Definition internal.h:77
char * id
Definition internal.h:69
event_queue_t events
Definition internal.h:72
font_t * defaultFont
Definition internal.h:78
cmd_buffer_t cmds
Definition internal.h:74
bool isConnected
Definition internal.h:73
fd_t data
Definition internal.h:71
list_t fonts
Definition internal.h:76
list_t windows
Definition internal.h:75
size_t writeIndex
Definition internal.h:64
size_t readIndex
Definition internal.h:63
event_t buffer[DISPLAY_MAX_EVENT]
Definition internal.h:62
uint64_t width
Definition event.h:117
uint64_t height
Definition event.h:118
Event structure.
Definition event.h:306
surface_id_t target
Definition event.h:308
event_type_t type
Definition event.h:307
event_screen_info_t screenInfo
Definition event.h:310
Poll file descriptor structure.
Definition fs.h:305
poll_events_t revents
The events that occurred.
Definition fs.h:308
poll_events_t events
The events to wait for.
Definition fs.h:307
fd_t fd
The file descriptor to poll.
Definition fs.h:306
Definition rect.h:13
Opaque window structure.
Definition internal.h:44
surface_id_t surface
Definition internal.h:52
@ thrd_error
Definition threads.h:76
_PUBLIC int mtx_lock(mtx_t *mtx)
Definition mtx_lock.c:11
_PUBLIC int mtx_init(mtx_t *mtx, int type)
Definition mtx_init.c:10
_PUBLIC int mtx_unlock(mtx_t *mtx)
Definition mtx_unlock.c:10
@ mtx_recursive
Definition threads.h:67
_PUBLIC void mtx_destroy(mtx_t *mtx)
Definition mtx_destroy.c:10