PatchworkOS
Loading...
Searching...
No Matches
client.c
Go to the documentation of this file.
1#define __STDC_WANT_LIB_EXT1__ 1
2#include "client.h"
3
4#include "compositor.h"
5#include "dwm.h"
6#include "screen.h"
7
8#include <errno.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
14{
15 surface_t* surface;
16 LIST_FOR_EACH(surface, &client->surfaces, clientEntry)
17 {
18 if (surface->id == id)
19 {
20 return surface;
21 }
22
23 // Surfaces are sorted
24 if (surface->id > id)
25 {
26 return NULL;
27 }
28 }
29 return NULL;
30}
31
33{
34 client_t* client = malloc(sizeof(client_t));
35 if (client == NULL)
36 {
37 errno = ENOMEM;
38 return NULL;
39 }
40 list_entry_init(&client->entry);
41 client->fd = fd;
42 list_init(&client->surfaces);
43 // Subscibe to events 0-63 by default
44 client->bitmask[0] = UINT64_MAX;
45 client->bitmask[1] = 0;
46 client->bitmask[2] = 0;
47 client->bitmask[3] = 0;
48
49 return client;
50}
51
52void client_free(client_t* client)
53{
54 surface_t* surface;
55 surface_t* temp;
56 LIST_FOR_EACH_SAFE(surface, temp, &client->surfaces, clientEntry)
57 {
60
61 list_remove(&client->surfaces, &surface->clientEntry);
62 dwm_detach(surface);
63 surface_free(surface);
64 }
65
66 close(client->fd);
67 free(client);
68}
69
71{
72 if (header->size != sizeof(cmd_screen_info_t))
73 {
74 errno = EINVAL;
75 return ERR;
76 }
78
80 if (cmd->index != 0)
81 {
82 event.width = 0;
83 event.height = 0;
84 errno = EINVAL;
85 return ERR;
86 }
87 else
88 {
89 event.width = screen_width();
90 event.height = screen_height();
91 }
93 return 0;
94}
95
97{
98 if (header->size != sizeof(cmd_surface_new_t))
99 {
100 errno = EINVAL;
101 return ERR;
102 }
103 cmd_surface_new_t* cmd = (cmd_surface_new_t*)header;
104
105 if (cmd->type < 0 || cmd->type >= SURFACE_TYPE_AMOUNT)
106 {
107 errno = EINVAL;
108 return ERR;
109 }
110
111 int32_t width = RECT_WIDTH(&cmd->rect);
112 int32_t height = RECT_HEIGHT(&cmd->rect);
113 if (width <= 0 || height <= 0)
114 {
115 errno = EINVAL;
116 return ERR;
117 }
118
119 if (strnlen_s(cmd->name, MAX_NAME) >= MAX_NAME)
120 {
122 return ERR;
123 }
124
125 point_t point = {.x = cmd->rect.left, .y = cmd->rect.top};
126 surface_t* surface = surface_new(client, cmd->name, &point, width, height, cmd->type);
127 if (surface == NULL)
128 {
129 return ERR;
130 }
131
133 if (share(&event.shmemKey, surface->shmem, CLOCKS_NEVER) == ERR)
134 {
135 surface_free(surface);
136 return ERR;
137 }
138
139 if (dwm_attach(surface) == ERR)
140 {
141 surface_free(surface);
142 return ERR;
143 }
144
145 list_push(&client->surfaces, &surface->clientEntry);
146
147 client_send_event(client, surface->id, EVENT_SURFACE_NEW, &event, sizeof(event));
148 return 0;
149}
150
152{
153 if (header->size != sizeof(cmd_surface_free_t))
154 {
155 errno = EINVAL;
156 return ERR;
157 }
159
160 surface_t* surface = client_surface_find(client, cmd->target);
161 if (surface == NULL)
162 {
163 errno = ENOENT;
164 return ERR;
165 }
166
169
170 list_remove(&client->surfaces, &surface->clientEntry);
171 dwm_detach(surface);
172 surface_free(surface);
173 return 0;
174}
175
177{
178 if (header->size != sizeof(cmd_surface_move_t))
179 {
180 errno = EINVAL;
181 return ERR;
182 }
184
185 surface_t* surface = client_surface_find(client, cmd->target);
186 if (surface == NULL)
187 {
188 errno = ENOENT;
189 return ERR;
190 }
191
192 uint64_t width = RECT_WIDTH(&cmd->rect);
193 uint64_t height = RECT_HEIGHT(&cmd->rect);
194
195 rect_t oldScreenRect = SURFACE_SCREEN_RECT(surface);
196 if (surface->width != width || surface->height != height)
197 {
198 // TODO: Reimplement resizing
199 errno = ENOSYS;
200 return ERR;
201 }
202 surface->pos = (point_t){.x = cmd->rect.left, .y = cmd->rect.top};
203 rect_t newScreenRect = SURFACE_SCREEN_RECT(surface);
204
205 compositor_invalidate(&oldScreenRect);
206 compositor_invalidate(&newScreenRect);
207
208 dwm_report_produce(surface, surface->client, REPORT_RECT);
209 return 0;
210}
211
213{
214 if (header->size != sizeof(cmd_surface_timer_set_t))
215 {
216 errno = EINVAL;
217 return ERR;
218 }
220
221 surface_t* surface = client_surface_find(client, cmd->target);
222 if (surface == NULL)
223 {
224 errno = ENOENT;
225 return ERR;
226 }
227
228 surface->timer.flags = cmd->flags;
229 surface->timer.timeout = cmd->timeout;
230 surface->timer.deadline = cmd->timeout == CLOCKS_NEVER ? CLOCKS_NEVER : uptime() + cmd->timeout;
231 return 0;
232}
233
235{
236 if (header->size != sizeof(cmd_surface_invalidate_t))
237 {
238 errno = EINVAL;
239 return ERR;
240 }
242
244 {
245 errno = EINVAL;
246 return ERR;
247 }
248
249 surface_t* surface = client_surface_find(client, cmd->target);
250 if (surface == NULL)
251 {
252 errno = ENOENT; // No such surface
253 return ERR;
254 }
255
256 rect_t surfaceRect = SURFACE_CONTENT_RECT(surface);
257 rect_t invalidRect = cmd->invalidRect;
258 RECT_FIT(&invalidRect, &surfaceRect);
259
260 rect_t screenInvalidRect = RECT_INIT_DIM(surface->pos.x + invalidRect.left, surface->pos.y + invalidRect.top,
261 RECT_WIDTH(&invalidRect), RECT_HEIGHT(&invalidRect));
262 compositor_invalidate(&screenInvalidRect);
263 return 0;
264}
265
267{
268 if (header->size != sizeof(cmd_surface_focus_set_t))
269 {
270 return ERR;
271 }
273
274 surface_t* surface = cmd->isGlobal ? dwm_surface_find(cmd->target) : client_surface_find(client, cmd->target);
275 if (surface == NULL)
276 {
277 return 0; // In the future some error system needs to be created to notify clients of errors like these, but
278 // since this needs to be able to fail (race conditions dont worry) we just have to ignore the error
279 // for now.
280 }
281
282 dwm_focus_set(surface);
285 return 0;
286}
287
289{
290 if (header->size != sizeof(cmd_surface_visible_set_t))
291 {
292 return ERR;
293 }
295
296 surface_t* surface = cmd->isGlobal ? dwm_surface_find(cmd->target) : client_surface_find(client, cmd->target);
297 if (surface == NULL)
298 {
299 return 0; // See client_action_surface_focus_set().
300 }
301
302 bool isSurfaceVisible = surface->flags & SURFACE_VISIBLE;
303 if (isSurfaceVisible != cmd->isVisible)
304 {
305 surface->flags ^= SURFACE_VISIBLE;
306 dwm_focus_set(surface);
309 dwm_report_produce(surface, surface->client, REPORT_IS_VISIBLE);
310 }
311 return 0;
312}
313
315{
316 if (header->size != sizeof(cmd_surface_report_t))
317 {
318 return ERR;
319 }
321
322 surface_t* surface = cmd->isGlobal ? dwm_surface_find(cmd->target) : client_surface_find(client, cmd->target);
323 if (surface == NULL)
324 {
325 return 0; // See client_action_surface_focus_set().
326 }
327
328 dwm_report_produce(surface, client, REPORT_NONE);
329 return 0;
330}
331
333{
334 if (header->size != sizeof(cmd_subscribe_t))
335 {
336 errno = EINVAL;
337 return ERR;
338 }
339 cmd_subscribe_t* cmd = (cmd_subscribe_t*)header;
340
341 if (cmd->event >= DWM_MAX_EVENT)
342 {
343 errno = EINVAL;
344 return ERR;
345 }
346
347 client->bitmask[cmd->event / 64] |= (1ULL << (cmd->event % 64));
348 return 0;
349}
350
352{
353 if (header->size != sizeof(cmd_unsubscribe_t))
354 {
355 errno = EINVAL;
356 return ERR;
357 }
358 cmd_unsubscribe_t* cmd = (cmd_unsubscribe_t*)header;
359
360 if (cmd->event >= DWM_MAX_EVENT)
361 {
362 errno = EINVAL;
363 return ERR;
364 }
365
366 client->bitmask[cmd->event / 64] &= ~(1ULL << (cmd->event % 64));
367 return 0;
368}
369
383
385{
386 if (cmds->size > CMD_BUFFER_MAX_DATA)
387 {
388 printf("dwm client: invalid command buffer size, got %lu\n", cmds->size);
389 errno = EPROTO;
390 return ERR;
391 }
392
393 uint64_t amount = 0;
394 cmd_header_t* cmd;
395 CMD_BUFFER_FOR_EACH(cmds, cmd)
396 {
397 amount++;
398 if (amount > cmds->amount || ((uint64_t)cmd + cmd->size - (uint64_t)cmds) > cmds->size ||
399 cmd->magic != CMD_MAGIC || cmd->type >= CMD_TYPE_AMOUNT)
400 {
401 printf("dwm client: corrupt command detected amount=%lu size=%lu magic=%x type=%u\n", amount, cmd->size,
402 cmd->magic, cmd->type);
403 errno = EPROTO;
404 return ERR;
405 }
406 }
407
408 if (amount != cmds->amount)
409 {
410 printf("dwm client: invalid command amount, expected %lu, got %lu\n", cmds->amount, amount);
411 errno = EPROTO;
412 return ERR;
413 }
414
415 CMD_BUFFER_FOR_EACH(cmds, cmd)
416 {
417 if (actions[cmd->type](client, cmd) == ERR)
418 {
419 printf("dwm client: command type %u caused error\n", cmd->type);
420 return ERR;
421 }
422 }
423
424 return 0;
425}
426
428{
429 errno = EOK;
430 uint64_t freeSpace = CLIENT_RECV_BUFFER_SIZE - client->recvLen;
431 if (freeSpace == 0)
432 {
433 printf("dwm client: receive buffer full\n");
434 errno = EMSGSIZE;
435 return ERR;
436 }
437
438 uint64_t readSize = read(client->fd, client->recvBuffer + client->recvLen, freeSpace);
439 if (readSize == ERR)
440 {
441 if (errno == EWOULDBLOCK)
442 {
443 return 0;
444 }
445 perror("dwm client: read error");
446 return ERR;
447 }
448
449 if (readSize == 0)
450 {
451 printf("dwm client: end of file\n");
452 errno = EPIPE;
453 return ERR;
454 }
455
456 client->recvLen += readSize;
457
458 while (client->recvLen > 0)
459 {
460 if (client->recvLen < sizeof(uint64_t))
461 {
462 break;
463 }
464
465 cmd_buffer_t* cmds = (cmd_buffer_t*)client->recvBuffer;
466 if (client->recvLen < cmds->size)
467 {
468 break;
469 }
470
471 if (client_process_cmds(client, cmds) == ERR)
472 {
473 return ERR;
474 }
475
476 client->recvLen -= cmds->size;
477 if (client->recvLen > 0)
478 {
479 memmove(client->recvBuffer, client->recvBuffer + cmds->size, client->recvLen);
480 }
481 }
482
483 return 0;
484}
485
486static uint64_t client_send_all(fd_t fd, const void* data, size_t size)
487{
488 const char* p = (const char*)data;
489 uint64_t sent = 0;
490 while (sent < size)
491 {
492 uint64_t n = write(fd, p + sent, size - sent);
493 if (n == ERR)
494 {
495 if (errno == EINTR)
496 {
497 continue;
498 }
499 perror("dwm client: write error");
500 return ERR;
501 }
502
503 if (n == 0)
504 {
505 errno = EPIPE;
506 perror("dwm client: write error (0 bytes written)");
507 return ERR;
508 }
509
510 sent += n;
511 }
512
513 return 0;
514}
515
517{
518 if (client->bitmask[type / 64] & (1ULL << (type % 64)))
519 {
520 event_t event = {.type = type, .target = target};
521 memcpy(&event.raw, data, size);
522
523 if (client_send_all(client->fd, &event, sizeof(event_t)) == ERR)
524 {
525 return ERR;
526 }
527 }
528
529 return 0;
530}
#define MAX_NAME
Maximum length of names.
Definition MAX_NAME.h:11
static uint64_t client_action_surface_timer_set(client_t *client, const cmd_header_t *header)
Definition client.c:212
static uint64_t client_action_surface_report(client_t *client, const cmd_header_t *header)
Definition client.c:314
uint64_t client_receive_cmds(client_t *client)
Definition client.c:427
static surface_t * client_surface_find(client_t *client, surface_id_t id)
Definition client.c:13
static uint64_t client_action_surface_new(client_t *client, const cmd_header_t *header)
Definition client.c:96
void client_free(client_t *client)
Definition client.c:52
static uint64_t client_action_surface_free(client_t *client, const cmd_header_t *header)
Definition client.c:151
static uint64_t client_process_cmds(client_t *client, cmd_buffer_t *cmds)
Definition client.c:384
static uint64_t client_action_surface_invalidate(client_t *client, const cmd_header_t *header)
Definition client.c:234
static uint64_t(* actions[])(client_t *, const cmd_header_t *)
Definition client.c:370
uint64_t client_send_event(client_t *client, surface_id_t target, event_type_t type, void *data, uint64_t size)
Definition client.c:516
static uint64_t client_action_subscribe(client_t *client, const cmd_header_t *header)
Definition client.c:332
static uint64_t client_action_surface_move(client_t *client, const cmd_header_t *header)
Definition client.c:176
static uint64_t client_action_screen_info(client_t *client, const cmd_header_t *header)
Definition client.c:70
static uint64_t client_action_surface_focus_set(client_t *client, const cmd_header_t *header)
Definition client.c:266
static uint64_t client_action_unsubscribe(client_t *client, const cmd_header_t *header)
Definition client.c:351
static uint64_t client_send_all(fd_t fd, const void *data, size_t size)
Definition client.c:486
client_t * client_new(fd_t fd)
Definition client.c:32
static uint64_t client_action_surface_visible_set(client_t *client, const cmd_header_t *header)
Definition client.c:288
#define CLIENT_RECV_BUFFER_SIZE
Definition client.h:10
#define CLOCKS_NEVER
Definition clock_t.h:16
@ CMD_SUBSCRIBE
Definition cmd.h:33
@ CMD_UNSUBSCRIBE
Definition cmd.h:34
@ CMD_SURFACE_TIMER_SET
Definition cmd.h:28
@ CMD_SURFACE_MOVE
Definition cmd.h:27
@ CMD_SURFACE_NEW
Definition cmd.h:25
@ CMD_SURFACE_REPORT
Definition cmd.h:32
@ CMD_SURFACE_VISIBLE_SET
Definition cmd.h:31
@ CMD_SURFACE_FREE
Definition cmd.h:26
@ CMD_SURFACE_FOCUS_SET
Definition cmd.h:30
@ CMD_SURFACE_INVALIDATE
Definition cmd.h:29
@ CMD_TYPE_AMOUNT
Definition cmd.h:35
@ CMD_SCREEN_INFO
Definition cmd.h:24
#define CMD_BUFFER_MAX_DATA
Definition cmd.h:129
#define CMD_MAGIC
Definition cmd.h:38
#define CMD_BUFFER_FOR_EACH(buffer, cmd)
Definition cmd.h:131
void compositor_invalidate(const rect_t *rect)
Definition compositor.c:135
static rect_t screenRect
Definition compositor.c:10
static fd_t data
Definition dwm.c:21
#define EVENT_SURFACE_NEW
Definition event.h:83
uint16_t event_type_t
Event type.
Definition event.h:72
#define DWM_MAX_EVENT
Definition event.h:97
#define EVENT_SCREEN_INFO
Definition event.h:82
@ REPORT_NONE
Definition event.h:35
@ REPORT_IS_VISIBLE
Definition event.h:37
@ REPORT_RECT
Definition event.h:36
#define SURFACE_ID_NONE
Definition surface.h:54
uint64_t surface_id_t
Definition surface.h:53
@ SURFACE_TYPE_AMOUNT
Definition surface.h:40
@ SURFACE_VISIBLE
Definition surface.h:49
#define ENOENT
No such file or directory.
Definition errno.h:42
#define EINVAL
Invalid argument.
Definition errno.h:142
#define ENAMETOOLONG
File name too long.
Definition errno.h:212
#define ENOSYS
Function not implemented.
Definition errno.h:222
#define EINTR
Interrupted system call.
Definition errno.h:52
#define EWOULDBLOCK
Operation would block.
Definition errno.h:237
#define EPROTO
Protocol error.
Definition errno.h:382
#define EPIPE
Broken pipe.
Definition errno.h:192
#define ENOMEM
Out of memory.
Definition errno.h:92
#define errno
Error number variable.
Definition errno.h:27
#define EOK
No error.
Definition errno.h:32
#define EMSGSIZE
Message too long.
Definition errno.h:477
uint64_t close(fd_t fd)
System call for closing files.
Definition close.c:9
uint64_t read(fd_t fd, void *buffer, uint64_t count)
System call for reading from files.
Definition read.c:9
uint64_t share(key_t *key, fd_t fd, clock_t timeout)
System call for sharing a file descriptor with another process.
Definition share.c:6
uint64_t write(fd_t fd, const void *buffer, uint64_t count)
System call for writing to files.
Definition write.c:9
#define LIST_FOR_EACH(elem, list, member)
Iterates over a list.
Definition list.h:65
#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_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:317
static void list_push(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:345
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:184
static void list_init(list_t *list)
Initializes a list.
Definition list.h:198
clock_t uptime(void)
System call for retreving the time since boot.
Definition uptime.c:6
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
__UINT64_TYPE__ fd_t
A file descriptor.
Definition fd_t.h:12
void dwm_focus_set(surface_t *surface)
Definition dwm.c:331
uint64_t dwm_attach(surface_t *surface)
Definition dwm.c:215
void dwm_report_produce(surface_t *surface, client_t *client, report_flags_t flags)
Definition dwm.c:167
void dwm_detach(surface_t *surface)
Definition dwm.c:280
surface_t * dwm_surface_find(surface_id_t id)
Definition dwm.c:182
#define RECT_FIT(rect, parent)
Definition rect.h:73
#define RECT_HAS_NEGATIVE_DIMS(rect)
Definition rect.h:42
#define RECT_INIT_DIM(x, y, width, height)
Definition rect.h:32
#define RECT_HEIGHT(rect)
Definition rect.h:39
#define RECT_WIDTH(rect)
Definition rect.h:38
uint64_t screen_height(void)
Definition screen.c:199
uint64_t screen_width(void)
Definition screen.c:194
#define SURFACE_SCREEN_RECT(surface)
Definition surface.h:37
#define SURFACE_CONTENT_RECT(surface)
Definition surface.h:39
__INT32_TYPE__ int32_t
Definition stdint.h:14
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
#define UINT64_MAX
Definition stdint.h:74
_PUBLIC int printf(const char *_RESTRICT format,...)
Definition printf.c:5
_PUBLIC void perror(const char *s)
Definition perror.c:5
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC void * memmove(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
_PUBLIC void * memcpy(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
Definition memcpy.c:4
size_t strnlen_s(const char *s, size_t maxsize)
Definition strnlen_s.c:4
char recvBuffer[CLIENT_RECV_BUFFER_SIZE]
Definition client.h:18
event_bitmask_t bitmask
Definition client.h:17
list_entry_t entry
Definition client.h:14
fd_t fd
Definition client.h:15
list_t surfaces
Definition client.h:16
size_t recvLen
Definition client.h:19
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:64
surface_id_t target
Definition cmd.h:91
surface_id_t target
Definition cmd.h:70
rect_t rect
Definition cmd.h:71
char name[MAX_NAME]
Definition cmd.h:58
rect_t rect
Definition cmd.h:57
surface_type_t type
Definition cmd.h:56
surface_id_t target
Definition cmd.h:114
surface_id_t target
Definition cmd.h:83
timer_flags_t flags
Definition cmd.h:84
surface_id_t target
Definition cmd.h:106
event_type_t event
Definition cmd.h:126
Screen Info event.
Definition event.h:117
uint64_t width
Definition event.h:118
Surface New event.
Definition event.h:128
key_t shmemKey
Key that can be claim()ed to access the surface's shared memory.
Definition event.h:129
Event structure.
Definition event.h:271
event_type_t type
Definition event.h:272
int64_t y
Definition point.h:14
int64_t x
Definition point.h:13
Definition rect.h:13
int32_t top
Definition rect.h:15
int32_t left
Definition rect.h:14
client_t * client
Definition surface.h:24
list_entry_t clientEntry
Definition surface.h:23
fd_t shmem
Definition surface.h:26
uint32_t height
Definition surface.h:29
timer_t timer
Definition surface.h:32
uint32_t width
Definition surface.h:28
point_t pos
Definition surface.h:25
surface_id_t id
Definition surface.h:30
surface_flags_t flags
Definition surface.h:33
timer_flags_t flags
Definition surface.h:15
clock_t timeout
Definition surface.h:16
clock_t deadline
Definition surface.h:17
surface_t * surface_new(client_t *client, const char *name, const point_t *point, uint64_t width, uint64_t height, surface_type_t type)
Definition surface.c:14
void surface_free(surface_t *surface)
Definition surface.c:57