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