-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathloop.c
More file actions
184 lines (158 loc) · 4.58 KB
/
loop.c
File metadata and controls
184 lines (158 loc) · 4.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#define _XOPEN_SOURCE 700
#include "bgce.h"
#include "server.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
/* Externs from server.c */
extern struct ServerState server;
void* client_thread(void* arg) {
int client_fd = *(int*)arg;
free(arg);
// Allocate memory for the client
struct Client* client = calloc(1, sizeof(struct Client));
if (!client) {
perror("Failed to allocate memory for client");
close(client_fd);
return NULL;
}
client->fd = client_fd;
// Add client to the linked list
client->next = server.clients;
client->z = server.clients->z + 1;
server.clients = client;
/* last connected client gets focus (notify old focus only; don't notify the new client yet) */
struct Client* old_focus = server.focused_client;
if (old_focus && old_focus != client) {
struct BGCEMessage lost = {0};
lost.type = MSG_FOCUS_CHANGE;
lost.data.focus_event.state = 0;
bgce_send_msg(old_focus->fd, &lost);
}
server.focused_client = client;
printf("[BGCE] Thread started for client fd=%d z=%d\n", client_fd, client->z);
while (1) {
struct BGCEMessage msg;
ssize_t rc = bgce_recv_msg(client_fd, &msg);
if (rc <= 0) {
printf("[BGCE] Client disconnected (fd=%d)\n", client_fd);
break;
}
switch (msg.type) {
case MSG_GET_SERVER_INFO: {
struct ServerInfo info = {
.width = server.display_w,
.height = server.display_h,
.color_depth = server.display_bpp,
.input_device_count = server.input.count,
};
for (int d = 0; d < server.input.count; d++) {
info.devices[d] = server.input.devs[d];
}
msg.data.server_info = info;
bgce_send_msg(client_fd, &msg);
break;
}
case MSG_GET_BUFFER: {
struct BufferRequest req = msg.data.buffer_request;
printf(
"[BGCE] Client requested buffer of size %dx%d\n",
req.width,
req.height);
snprintf(client->shm_name, sizeof(client->shm_name),
"bgce_buf_%d_%ld", getpid(), time(NULL));
// Unmap and unlink the existing buffer: for resize
if (client->buffer) {
printf("[BGCE] Client already has a buffer, unmapping.\n");
munmap(client->buffer, client->width * client->height * 4);
shm_unlink(client->shm_name);
}
int shm_fd = shm_open(client->shm_name, O_CREAT | O_RDWR, 0600);
if (shm_fd < 0) {
perror("shm_open");
break;
}
size_t buf_size = req.width * req.height * 4;
if (ftruncate(shm_fd, buf_size) < 0) {
perror("ftruncate");
close(shm_fd);
break;
}
client->buffer = mmap(NULL, buf_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
client->width = req.width;
client->height = req.height;
client->x = 0;
client->y = 0;
close(shm_fd);
printf("[BGCE] Client buffer: %p size=%zu (%dx%d) name=%s\n",
client->buffer,
client->width * client->height * 4UL,
client->width, client->height,
client->shm_name);
struct BufferReply reply = {0};
strncpy(reply.shm_name, client->shm_name, sizeof(reply.shm_name));
reply.width = req.width;
reply.height = req.height;
msg.data.buffer_reply = reply;
bgce_send_msg(client_fd, &msg);
break;
}
case MSG_DRAW: {
printf("[BGCE] Received draw event from client %s\n", client->shm_name);
/*
* Drawing must be allowed even when the client is not focused.
* Focus only affects input routing.
*/
draw(&server, *client);
break;
}
case MSG_MOVE: {
struct MoveRequest move_req = msg.data.move_request;
printf(
"[BGCE] Client requested move to position (%d, %d)\n",
move_req.x, move_req.y);
// Update client position
client->x = move_req.x;
client->y = move_req.y;
break;
}
default:
fprintf(stderr, "[BGCE] Unknown message type %d\n", msg.type);
}
}
if (client->buffer) {
munmap(client->buffer, client->width * client->height * 4);
shm_unlink(client->shm_name);
}
// Remove client from the linked list
struct Client* prev = NULL;
struct Client* curr = server.clients;
while (curr) {
if (curr == client) {
if (prev) {
prev->next = curr->next;
} else {
server.clients = curr->next;
}
break;
}
prev = curr;
curr = curr->next;
}
if (server.focused_client == client) {
/* notify focused client it lost focus before we clear */
struct BGCEMessage lost = {0};
lost.type = MSG_FOCUS_CHANGE;
lost.data.focus_event.state = 0;
bgce_send_msg(client->fd, &lost);
server.focused_client = NULL;
}
close(client->fd);
printf("[BGCE] Thread exiting for client fd=%d\n", client->fd);
free(client);
return NULL;
}