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