aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sway/extensions.h56
-rw-r--r--include/sway/server.h31
-rw-r--r--sway/CMakeLists.txt3
-rw-r--r--sway/commands.c2
-rw-r--r--sway/extensions.c407
-rw-r--r--sway/focus.c3
-rw-r--r--sway/ipc-server.c389
-rw-r--r--sway/layout.c5
-rw-r--r--sway/main.c113
-rw-r--r--sway/server.c54
-rw-r--r--sway/workspace.c1
11 files changed, 160 insertions, 904 deletions
diff --git a/include/sway/extensions.h b/include/sway/extensions.h
deleted file mode 100644
index 5212eb3a..00000000
--- a/include/sway/extensions.h
+++ /dev/null
@@ -1,56 +0,0 @@
1#ifndef _SWAY_EXTENSIONS_H
2#define _SWAY_EXTENSIONS_H
3
4#include <wayland-server.h>
5#include <wlc/wlc-wayland.h>
6#include "wayland-desktop-shell-server-protocol.h"
7#include "list.h"
8
9struct background_config {
10 wlc_handle output;
11 wlc_resource surface;
12 // we need the wl_resource of the surface in the destructor
13 struct wl_resource *wl_surface_res;
14 struct wl_client *client;
15 wlc_handle handle;
16};
17
18struct panel_config {
19 // wayland resource used in callbacks, is used to track this panel
20 struct wl_resource *wl_resource;
21 wlc_handle output;
22 wlc_resource surface;
23 // we need the wl_resource of the surface in the destructor
24 struct wl_resource *wl_surface_res;
25 enum desktop_shell_panel_position panel_position;
26 // used to determine if client is a panel
27 struct wl_client *client;
28 // wlc handle for this panel's surface, not set until panel is created
29 wlc_handle handle;
30};
31
32struct desktop_shell_state {
33 list_t *backgrounds;
34 list_t *panels;
35 list_t *lock_surfaces;
36 bool is_locked;
37};
38
39struct swaylock_state {
40 bool active;
41 wlc_handle output;
42 wlc_resource surface;
43};
44
45struct decoration_state {
46 list_t *csd_resources;
47};
48
49extern struct desktop_shell_state desktop_shell;
50extern struct decoration_state decoration_state;
51
52void register_extensions(void);
53
54void server_decoration_enable_csd(wlc_handle handle);
55
56#endif
diff --git a/include/sway/server.h b/include/sway/server.h
new file mode 100644
index 00000000..471a0270
--- /dev/null
+++ b/include/sway/server.h
@@ -0,0 +1,31 @@
1#ifndef _SWAY_SERVER_H
2#define _SWAY_SERVER_H
3#include <stdbool.h>
4#include <wayland-server.h>
5#include <wlr/backend.h>
6#include <wlr/backend/session.h>
7#include <wlr/types/wlr_data_device_manager.h>
8#include <wlr/render.h>
9// TODO WLR: make Xwayland optional
10#include <wlr/xwayland.h>
11
12struct sway_server {
13 // TODO WLR
14 //struct roots_desktop *desktop;
15 //struct roots_input *input;
16
17 struct wl_display *wl_display;
18 struct wl_event_loop *wl_event_loop;
19
20 struct wlr_backend *backend;
21 struct wlr_renderer *renderer;
22
23 struct wlr_data_device_manager *data_device_manager;
24};
25
26bool server_init(struct sway_server *server);
27void server_fini(struct sway_server *server);
28
29struct sway_server server;
30
31#endif
diff --git a/sway/CMakeLists.txt b/sway/CMakeLists.txt
index 67af0f70..ac0530e5 100644
--- a/sway/CMakeLists.txt
+++ b/sway/CMakeLists.txt
@@ -25,9 +25,7 @@ add_executable(sway
25 container.c 25 container.c
26 criteria.c 26 criteria.c
27 debug_log.c 27 debug_log.c
28 extensions.c
29 focus.c 28 focus.c
30 handlers.c
31 input.c 29 input.c
32 input_state.c 30 input_state.c
33 ipc-json.c 31 ipc-json.c
@@ -38,6 +36,7 @@ add_executable(sway
38 workspace.c 36 workspace.c
39 border.c 37 border.c
40 security.c 38 security.c
39 server.c
41) 40)
42 41
43add_definitions( 42add_definitions(
diff --git a/sway/commands.c b/sway/commands.c
index c7dbf731..e1181893 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -120,6 +120,7 @@ void input_cmd_apply(struct input_config *input) {
120 // Try to find the input device and apply configuration now. If 120 // Try to find the input device and apply configuration now. If
121 // this is during startup then there will be no container and config 121 // this is during startup then there will be no container and config
122 // will be applied during normal "new input" event from wlc. 122 // will be applied during normal "new input" event from wlc.
123 /* TODO WLR
123 struct libinput_device *device = NULL; 124 struct libinput_device *device = NULL;
124 for (int i = 0; i < input_devices->length; ++i) { 125 for (int i = 0; i < input_devices->length; ++i) {
125 device = input_devices->items[i]; 126 device = input_devices->items[i];
@@ -134,6 +135,7 @@ void input_cmd_apply(struct input_config *input) {
134 break; 135 break;
135 } 136 }
136 } 137 }
138 */
137 } 139 }
138} 140}
139 141
diff --git a/sway/extensions.c b/sway/extensions.c
deleted file mode 100644
index 91746561..00000000
--- a/sway/extensions.c
+++ /dev/null
@@ -1,407 +0,0 @@
1#include <stdlib.h>
2#include <wlc/wlc.h>
3#include <wlc/wlc-wayland.h>
4#include <wlc/wlc-render.h>
5#include "wayland-desktop-shell-server-protocol.h"
6#include "wayland-swaylock-server-protocol.h"
7#include "wayland-gamma-control-server-protocol.h"
8#include "wayland-server-decoration-server-protocol.h"
9#include "sway/layout.h"
10#include "sway/input_state.h"
11#include "sway/extensions.h"
12#include "sway/security.h"
13#include "sway/ipc-server.h"
14#include "log.h"
15
16struct desktop_shell_state desktop_shell;
17struct decoration_state decoration_state;
18
19static struct panel_config *find_or_create_panel_config(struct wl_resource *resource) {
20 for (int i = 0; i < desktop_shell.panels->length; i++) {
21 struct panel_config *conf = desktop_shell.panels->items[i];
22 if (conf->wl_resource == resource) {
23 sway_log(L_DEBUG, "Found existing panel config for resource %p", resource);
24 return conf;
25 }
26 }
27 sway_log(L_DEBUG, "Creating panel config for resource %p", resource);
28 struct panel_config *config = calloc(1, sizeof(struct panel_config));
29 if (!config) {
30 sway_log(L_ERROR, "Unable to create panel config");
31 return NULL;
32 }
33 list_add(desktop_shell.panels, config);
34 config->wl_resource = resource;
35 return config;
36}
37
38void background_surface_destructor(struct wl_resource *resource) {
39 sway_log(L_DEBUG, "Background surface killed");
40 int i;
41 for (i = 0; i < desktop_shell.backgrounds->length; ++i) {
42 struct background_config *config = desktop_shell.backgrounds->items[i];
43 if (config->wl_surface_res == resource) {
44 list_del(desktop_shell.backgrounds, i);
45 break;
46 }
47 }
48}
49
50void panel_surface_destructor(struct wl_resource *resource) {
51 sway_log(L_DEBUG, "Panel surface killed");
52 int i;
53 for (i = 0; i < desktop_shell.panels->length; ++i) {
54 struct panel_config *config = desktop_shell.panels->items[i];
55 if (config->wl_surface_res == resource) {
56 list_del(desktop_shell.panels, i);
57 arrange_windows(&root_container, -1, -1);
58 break;
59 }
60 }
61}
62
63void lock_surface_destructor(struct wl_resource *resource) {
64 sway_log(L_DEBUG, "Lock surface killed");
65 int i;
66 for (i = 0; i < desktop_shell.lock_surfaces->length; ++i) {
67 struct wl_resource *surface = desktop_shell.lock_surfaces->items[i];
68 if (surface == resource) {
69 list_del(desktop_shell.lock_surfaces, i);
70 arrange_windows(&root_container, -1, -1);
71 break;
72 }
73 }
74 if (desktop_shell.lock_surfaces->length == 0) {
75 sway_log(L_DEBUG, "Desktop shell unlocked");
76 desktop_shell.is_locked = false;
77
78 // We need to now give focus back to the focus which we internally
79 // track, since when we lock sway we don't actually change our internal
80 // focus tracking.
81 swayc_t *focus = get_focused_container(swayc_active_workspace());
82 set_focused_container(focus);
83 wlc_view_focus(focus->handle);
84 }
85}
86
87static void set_background(struct wl_client *client, struct wl_resource *resource,
88 struct wl_resource *_output, struct wl_resource *surface) {
89 pid_t pid;
90 wl_client_get_credentials(client, &pid, NULL, NULL);
91 if (!(get_feature_policy_mask(pid) & FEATURE_BACKGROUND)) {
92 sway_log(L_INFO, "Denying background feature to %d", pid);
93 return;
94 }
95 wlc_handle output = wlc_handle_from_wl_output_resource(_output);
96 if (!output) {
97 return;
98 }
99 sway_log(L_DEBUG, "Setting surface %p as background for output %d", surface, (int)output);
100 struct background_config *config = malloc(sizeof(struct background_config));
101 if (!config) {
102 sway_log(L_ERROR, "Unable to allocate background config");
103 return;
104 }
105 config->client = client;
106 config->output = output;
107 config->surface = wlc_resource_from_wl_surface_resource(surface);
108 config->wl_surface_res = surface;
109 list_add(desktop_shell.backgrounds, config);
110 wl_resource_set_destructor(surface, background_surface_destructor);
111 arrange_windows(swayc_by_handle(output), -1, -1);
112 wlc_output_schedule_render(config->output);
113}
114
115static void set_panel(struct wl_client *client, struct wl_resource *resource,
116 struct wl_resource *_output, struct wl_resource *surface) {
117 pid_t pid;
118 wl_client_get_credentials(client, &pid, NULL, NULL);
119 if (!(get_feature_policy_mask(pid) & FEATURE_PANEL)) {
120 sway_log(L_INFO, "Denying panel feature to %d", pid);
121 return;
122 }
123 wlc_handle output = wlc_handle_from_wl_output_resource(_output);
124 if (!output) {
125 return;
126 }
127 sway_log(L_DEBUG, "Setting surface %p as panel for output %d (wl_resource: %p)", surface, (int)output, resource);
128 struct panel_config *config = find_or_create_panel_config(resource);
129 config->output = output;
130 config->client = client;
131 config->surface = wlc_resource_from_wl_surface_resource(surface);
132 config->wl_surface_res = surface;
133 wl_resource_set_destructor(surface, panel_surface_destructor);
134 arrange_windows(&root_container, -1, -1);
135 wlc_output_schedule_render(config->output);
136}
137
138static void desktop_set_lock_surface(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface) {
139 sway_log(L_ERROR, "desktop_set_lock_surface is not currently supported");
140}
141
142static void desktop_unlock(struct wl_client *client, struct wl_resource *resource) {
143 sway_log(L_ERROR, "desktop_unlock is not currently supported");
144}
145
146static void set_grab_surface(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface) {
147 sway_log(L_ERROR, "desktop_set_grab_surface is not currently supported");
148}
149
150static void desktop_ready(struct wl_client *client, struct wl_resource *resource) {
151 // nop
152}
153
154static void set_panel_position(struct wl_client *client, struct wl_resource *resource, uint32_t position) {
155 pid_t pid;
156 wl_client_get_credentials(client, &pid, NULL, NULL);
157 if (!(get_feature_policy_mask(pid) & FEATURE_PANEL)) {
158 sway_log(L_INFO, "Denying panel feature to %d", pid);
159 return;
160 }
161 struct panel_config *config = find_or_create_panel_config(resource);
162 sway_log(L_DEBUG, "Panel position for wl_resource %p changed %d => %d", resource, config->panel_position, position);
163 config->panel_position = position;
164 arrange_windows(&root_container, -1, -1);
165}
166
167static struct desktop_shell_interface desktop_shell_implementation = {
168 .set_background = set_background,
169 .set_panel = set_panel,
170 .set_lock_surface = desktop_set_lock_surface,
171 .unlock = desktop_unlock,
172 .set_grab_surface = set_grab_surface,
173 .desktop_ready = desktop_ready,
174 .set_panel_position = set_panel_position
175};
176
177static void desktop_shell_bind(struct wl_client *client, void *data,
178 uint32_t version, uint32_t id) {
179 if (version > 3) {
180 // Unsupported version
181 return;
182 }
183
184 struct wl_resource *resource = wl_resource_create(client, &desktop_shell_interface, version, id);
185 if (!resource) {
186 wl_client_post_no_memory(client);
187 }
188
189 wl_resource_set_implementation(resource, &desktop_shell_implementation, NULL, NULL);
190}
191
192static void set_lock_surface(struct wl_client *client, struct wl_resource *resource,
193 struct wl_resource *_output, struct wl_resource *surface) {
194 pid_t pid;
195 wl_client_get_credentials(client, &pid, NULL, NULL);
196 if (!(get_feature_policy_mask(pid) & FEATURE_LOCK)) {
197 sway_log(L_INFO, "Denying lock feature to %d", pid);
198 return;
199 }
200 swayc_t *output = swayc_by_handle(wlc_handle_from_wl_output_resource(_output));
201 swayc_t *view = swayc_by_handle(wlc_handle_from_wl_surface_resource(surface));
202 sway_log(L_DEBUG, "Setting lock surface to %p", view);
203 if (view && output) {
204 swayc_t *workspace = output->focused;
205 if (!swayc_is_child_of(view, workspace)) {
206 move_container_to(view, workspace);
207 }
208 // make the view floating so it doesn't rearrange other siblings.
209 if (!view->is_floating) {
210 destroy_container(remove_child(view));
211 add_floating(workspace, view);
212 }
213 wlc_view_set_state(view->handle, WLC_BIT_FULLSCREEN, true);
214 wlc_view_bring_to_front(view->handle);
215 wlc_view_focus(view->handle);
216 desktop_shell.is_locked = true;
217 input_init();
218 arrange_windows(workspace, -1, -1);
219 list_add(desktop_shell.lock_surfaces, surface);
220 wl_resource_set_destructor(surface, lock_surface_destructor);
221 } else {
222 sway_log(L_ERROR, "Attempted to set lock surface to non-view");
223 }
224}
225
226static void unlock(struct wl_client *client, struct wl_resource *resource) {
227 sway_log(L_ERROR, "unlock is not currently supported");
228 // This isn't really necessary, we just unlock when the client exits.
229}
230
231static struct lock_interface swaylock_implementation = {
232 .set_lock_surface = set_lock_surface,
233 .unlock = unlock
234};
235
236static void swaylock_bind(struct wl_client *client, void *data,
237 uint32_t version, uint32_t id) {
238 if (version > 1) {
239 // Unsupported version
240 return;
241 }
242
243 struct wl_resource *resource = wl_resource_create(client, &lock_interface, version, id);
244 if (!resource) {
245 wl_client_post_no_memory(client);
246 }
247
248 wl_resource_set_implementation(resource, &swaylock_implementation, NULL, NULL);
249}
250
251static void gamma_control_destroy(struct wl_client *client, struct wl_resource *res) {
252 wl_resource_destroy(res);
253}
254
255static void gamma_control_set_gamma(struct wl_client *client,
256 struct wl_resource *res, struct wl_array *red,
257 struct wl_array *green, struct wl_array *blue) {
258 if (red->size != green->size || red->size != blue->size) {
259 wl_resource_post_error(res, GAMMA_CONTROL_ERROR_INVALID_GAMMA,
260 "The gamma ramps don't have the same size");
261 return;
262 }
263 uint16_t *r = (uint16_t *)red->data;
264 uint16_t *g = (uint16_t *)green->data;
265 uint16_t *b = (uint16_t *)blue->data;
266 wlc_handle output = wlc_handle_from_wl_output_resource(
267 wl_resource_get_user_data(res));
268 if (!output) {
269 return;
270 }
271 sway_log(L_DEBUG, "Setting gamma for output");
272 wlc_output_set_gamma(output, red->size / sizeof(uint16_t), r, g, b);
273}
274
275static void gamma_control_reset_gamma(struct wl_client *client,
276 struct wl_resource *resource) {
277 // This space intentionally left blank
278}
279
280static struct gamma_control_interface gamma_control_implementation = {
281 .destroy = gamma_control_destroy,
282 .set_gamma = gamma_control_set_gamma,
283 .reset_gamma = gamma_control_reset_gamma
284};
285
286static void gamma_control_manager_destroy(struct wl_client *client,
287 struct wl_resource *res) {
288 wl_resource_destroy(res);
289}
290
291static void gamma_control_manager_get(struct wl_client *client,
292 struct wl_resource *res, uint32_t id, struct wl_resource *_output) {
293 struct wl_resource *manager_res = wl_resource_create(client,
294 &gamma_control_interface, wl_resource_get_version(res), id);
295 wlc_handle output = wlc_handle_from_wl_output_resource(_output);
296 if (!output) {
297 return;
298 }
299 wl_resource_set_implementation(manager_res, &gamma_control_implementation,
300 _output, NULL);
301 gamma_control_send_gamma_size(manager_res, wlc_output_get_gamma_size(output));
302}
303
304static struct gamma_control_manager_interface gamma_manager_implementation = {
305 .destroy = gamma_control_manager_destroy,
306 .get_gamma_control = gamma_control_manager_get
307};
308
309static void gamma_control_manager_bind(struct wl_client *client, void *data,
310 uint32_t version, uint32_t id) {
311 if (version > 1) {
312 // Unsupported version
313 return;
314 }
315 struct wl_resource *resource = wl_resource_create(client,
316 &gamma_control_manager_interface, version, id);
317 if (!resource) {
318 wl_client_post_no_memory(client);
319 }
320 wl_resource_set_implementation(resource, &gamma_manager_implementation, NULL, NULL);
321}
322
323static void server_decoration_release(struct wl_client *client,
324 struct wl_resource *resource) {
325 wl_resource_destroy(resource);
326}
327
328void server_decoration_enable_csd(wlc_handle handle) {
329 swayc_t *view = swayc_by_handle(handle);
330 if (!view) {
331 sway_log(L_DEBUG, "view invalid");
332 return;
333 }
334 sway_log(L_DEBUG, "%s requested client side decorations", view->name);
335 view->border_type = B_NONE;
336 update_geometry(view);
337}
338
339static void server_decoration_request_mode(struct wl_client *client,
340 struct wl_resource *resource, uint32_t mode) {
341 sway_log(L_DEBUG, "Client requested server decoration mode %d", mode);
342 if (mode == ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER) {
343 return;
344 }
345 struct wl_resource *surface = wl_resource_get_user_data(resource);
346 if (!surface) {
347 sway_log(L_DEBUG, "surface invalid");
348 return;
349 }
350 wlc_handle handle = wlc_handle_from_wl_surface_resource(surface);
351 if (!handle) {
352 list_add(decoration_state.csd_resources, surface);
353 return;
354 }
355 server_decoration_enable_csd(handle);
356}
357
358static struct org_kde_kwin_server_decoration_interface server_decoration_implementation = {
359 .release = server_decoration_release,
360 .request_mode = server_decoration_request_mode,
361};
362
363static void server_decoration_manager_create(struct wl_client *client,
364 struct wl_resource *resource, uint32_t id, struct wl_resource *surface) {
365 sway_log(L_DEBUG, "Client requested server decoration manager");
366 struct wl_resource *manager = wl_resource_create(client,
367 &org_kde_kwin_server_decoration_interface, 1, id);
368 if (!manager) {
369 wl_client_post_no_memory(client);
370 }
371 wl_resource_set_implementation(manager, &server_decoration_implementation, surface, NULL);
372}
373
374// Jesus christ KDE, these names are whack as hell
375static struct org_kde_kwin_server_decoration_manager_interface server_decoration_manager_implementation = {
376 .create = server_decoration_manager_create,
377};
378
379static void server_decoration_manager_bind(struct wl_client *client, void *data,
380 uint32_t version, uint32_t id) {
381 if (version > 1) {
382 // Unsupported version
383 return;
384 }
385 struct wl_resource *resource = wl_resource_create(client,
386 &org_kde_kwin_server_decoration_manager_interface, version, id);
387 if (!resource) {
388 wl_client_post_no_memory(client);
389 }
390 wl_resource_set_implementation(resource, &server_decoration_manager_implementation, NULL, NULL);
391 org_kde_kwin_server_decoration_manager_send_default_mode(resource,
392 ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER);
393}
394
395void register_extensions(void) {
396 wl_global_create(wlc_get_wl_display(), &desktop_shell_interface, 3, NULL, desktop_shell_bind);
397 desktop_shell.backgrounds = create_list();
398 desktop_shell.panels = create_list();
399 desktop_shell.lock_surfaces = create_list();
400 desktop_shell.is_locked = false;
401 decoration_state.csd_resources = create_list();
402 wl_global_create(wlc_get_wl_display(), &lock_interface, 1, NULL, swaylock_bind);
403 wl_global_create(wlc_get_wl_display(), &gamma_control_manager_interface, 1,
404 NULL, gamma_control_manager_bind);
405 wl_global_create(wlc_get_wl_display(), &org_kde_kwin_server_decoration_manager_interface ,
406 1, NULL, server_decoration_manager_bind);
407}
diff --git a/sway/focus.c b/sway/focus.c
index e9b032f8..66f7ee17 100644
--- a/sway/focus.c
+++ b/sway/focus.c
@@ -4,7 +4,6 @@
4#include "sway/workspace.h" 4#include "sway/workspace.h"
5#include "sway/layout.h" 5#include "sway/layout.h"
6#include "sway/config.h" 6#include "sway/config.h"
7#include "sway/extensions.h"
8#include "sway/input_state.h" 7#include "sway/input_state.h"
9#include "sway/ipc-server.h" 8#include "sway/ipc-server.h"
10#include "sway/border.h" 9#include "sway/border.h"
@@ -163,12 +162,14 @@ bool set_focused_container(swayc_t *c) {
163 if (c->type == C_VIEW) { 162 if (c->type == C_VIEW) {
164 wlc_view_set_state(c->handle, WLC_BIT_ACTIVATED, true); 163 wlc_view_set_state(c->handle, WLC_BIT_ACTIVATED, true);
165 } 164 }
165 /* TODO WLR
166 if (!desktop_shell.is_locked) { 166 if (!desktop_shell.is_locked) {
167 // If the system is locked, we do everything _but_ actually setting 167 // If the system is locked, we do everything _but_ actually setting
168 // focus. This includes making our internals think that this view is 168 // focus. This includes making our internals think that this view is
169 // focused. 169 // focused.
170 wlc_view_focus(c->handle); 170 wlc_view_focus(c->handle);
171 } 171 }
172 */
172 if (c->parent->layout != L_TABBED && c->parent->layout != L_STACKED) { 173 if (c->parent->layout != L_TABBED && c->parent->layout != L_STACKED) {
173 update_container_border(c); 174 update_container_border(c);
174 } 175 }
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index b560b930..9ba736d8 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -10,7 +10,6 @@
10#include <sys/socket.h> 10#include <sys/socket.h>
11#include <sys/un.h> 11#include <sys/un.h>
12#include <stdbool.h> 12#include <stdbool.h>
13#include <wlc/wlc-render.h>
14#include <unistd.h> 13#include <unistd.h>
15#include <stdlib.h> 14#include <stdlib.h>
16#include <sys/ioctl.h> 15#include <sys/ioctl.h>
@@ -31,21 +30,22 @@ struct ucred {
31#include "sway/config.h" 30#include "sway/config.h"
32#include "sway/commands.h" 31#include "sway/commands.h"
33#include "sway/input.h" 32#include "sway/input.h"
33#include "sway/server.h"
34#include "stringop.h" 34#include "stringop.h"
35#include "log.h" 35#include "log.h"
36#include "list.h" 36#include "list.h"
37#include "util.h" 37#include "util.h"
38 38
39static int ipc_socket = -1; 39static int ipc_socket = -1;
40static struct wlc_event_source *ipc_event_source = NULL; 40static struct wl_event_source *ipc_event_source = NULL;
41static struct sockaddr_un *ipc_sockaddr = NULL; 41static struct sockaddr_un *ipc_sockaddr = NULL;
42static list_t *ipc_client_list = NULL; 42static list_t *ipc_client_list = NULL;
43 43
44static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; 44static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'};
45 45
46struct ipc_client { 46struct ipc_client {
47 struct wlc_event_source *event_source; 47 struct wl_event_source *event_source;
48 struct wlc_event_source *writable_event_source; 48 struct wl_event_source *writable_event_source;
49 int fd; 49 int fd;
50 uint32_t payload_length; 50 uint32_t payload_length;
51 uint32_t security_policy; 51 uint32_t security_policy;
@@ -58,25 +58,6 @@ struct ipc_client {
58 58
59static list_t *ipc_get_pixel_requests = NULL; 59static list_t *ipc_get_pixel_requests = NULL;
60 60
61struct get_pixels_request {
62 struct ipc_client *client;
63 wlc_handle output;
64 struct wlc_geometry geo;
65};
66
67struct get_clipboard_request {
68 struct ipc_client *client;
69 json_object *json;
70 int fd;
71 struct wlc_event_source *fd_event_source;
72 struct wlc_event_source *timer_event_source;
73 char *type;
74 unsigned int *pending;
75 char *buf;
76 size_t buf_size;
77 size_t buf_position;
78};
79
80struct sockaddr_un *ipc_user_sockaddr(void); 61struct sockaddr_un *ipc_user_sockaddr(void);
81int ipc_handle_connection(int fd, uint32_t mask, void *data); 62int ipc_handle_connection(int fd, uint32_t mask, void *data);
82int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); 63int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
@@ -118,12 +99,13 @@ void ipc_init(void) {
118 ipc_client_list = create_list(); 99 ipc_client_list = create_list();
119 ipc_get_pixel_requests = create_list(); 100 ipc_get_pixel_requests = create_list();
120 101
121 ipc_event_source = wlc_event_loop_add_fd(ipc_socket, WLC_EVENT_READABLE, ipc_handle_connection, NULL); 102 ipc_event_source = wl_event_loop_add_fd(server.wl_event_loop, ipc_socket,
103 WL_EVENT_READABLE, ipc_handle_connection, NULL);
122} 104}
123 105
124void ipc_terminate(void) { 106void ipc_terminate(void) {
125 if (ipc_event_source) { 107 if (ipc_event_source) {
126 wlc_event_source_remove(ipc_event_source); 108 wl_event_source_remove(ipc_event_source);
127 } 109 }
128 close(ipc_socket); 110 close(ipc_socket);
129 unlink(ipc_sockaddr->sun_path); 111 unlink(ipc_sockaddr->sun_path);
@@ -176,7 +158,7 @@ static pid_t get_client_pid(int client_fd) {
176int ipc_handle_connection(int fd, uint32_t mask, void *data) { 158int ipc_handle_connection(int fd, uint32_t mask, void *data) {
177 (void) fd; (void) data; 159 (void) fd; (void) data;
178 sway_log(L_DEBUG, "Event on IPC listening socket"); 160 sway_log(L_DEBUG, "Event on IPC listening socket");
179 assert(mask == WLC_EVENT_READABLE); 161 assert(mask == WL_EVENT_READABLE);
180 162
181 int client_fd = accept(ipc_socket, NULL, NULL); 163 int client_fd = accept(ipc_socket, NULL, NULL);
182 if (client_fd == -1) { 164 if (client_fd == -1) {
@@ -207,7 +189,8 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) {
207 client->payload_length = 0; 189 client->payload_length = 0;
208 client->fd = client_fd; 190 client->fd = client_fd;
209 client->subscribed_events = 0; 191 client->subscribed_events = 0;
210 client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client); 192 client->event_source = wl_event_loop_add_fd(server.wl_event_loop, client_fd,
193 WL_EVENT_READABLE, ipc_client_handle_readable, client);
211 client->writable_event_source = NULL; 194 client->writable_event_source = NULL;
212 195
213 client->write_buffer_size = 128; 196 client->write_buffer_size = 128;
@@ -234,13 +217,13 @@ static const int ipc_header_size = sizeof(ipc_magic)+8;
234int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { 217int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
235 struct ipc_client *client = data; 218 struct ipc_client *client = data;
236 219
237 if (mask & WLC_EVENT_ERROR) { 220 if (mask & WL_EVENT_ERROR) {
238 sway_log(L_ERROR, "IPC Client socket error, removing client"); 221 sway_log(L_ERROR, "IPC Client socket error, removing client");
239 ipc_client_disconnect(client); 222 ipc_client_disconnect(client);
240 return 0; 223 return 0;
241 } 224 }
242 225
243 if (mask & WLC_EVENT_HANGUP) { 226 if (mask & WL_EVENT_HANGUP) {
244 sway_log(L_DEBUG, "Client %d hung up", client->fd); 227 sway_log(L_DEBUG, "Client %d hung up", client->fd);
245 ipc_client_disconnect(client); 228 ipc_client_disconnect(client);
246 return 0; 229 return 0;
@@ -296,13 +279,13 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
296int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { 279int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
297 struct ipc_client *client = data; 280 struct ipc_client *client = data;
298 281
299 if (mask & WLC_EVENT_ERROR) { 282 if (mask & WL_EVENT_ERROR) {
300 sway_log(L_ERROR, "IPC Client socket error, removing client"); 283 sway_log(L_ERROR, "IPC Client socket error, removing client");
301 ipc_client_disconnect(client); 284 ipc_client_disconnect(client);
302 return 0; 285 return 0;
303 } 286 }
304 287
305 if (mask & WLC_EVENT_HANGUP) { 288 if (mask & WL_EVENT_HANGUP) {
306 sway_log(L_DEBUG, "Client %d hung up", client->fd); 289 sway_log(L_DEBUG, "Client %d hung up", client->fd);
307 ipc_client_disconnect(client); 290 ipc_client_disconnect(client);
308 return 0; 291 return 0;
@@ -328,7 +311,7 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
328 client->write_buffer_len -= written; 311 client->write_buffer_len -= written;
329 312
330 if (client->write_buffer_len == 0 && client->writable_event_source) { 313 if (client->write_buffer_len == 0 && client->writable_event_source) {
331 wlc_event_source_remove(client->writable_event_source); 314 wl_event_source_remove(client->writable_event_source);
332 client->writable_event_source = NULL; 315 client->writable_event_source = NULL;
333 } 316 }
334 317
@@ -345,9 +328,9 @@ void ipc_client_disconnect(struct ipc_client *client) {
345 } 328 }
346 329
347 sway_log(L_INFO, "IPC Client %d disconnected", client->fd); 330 sway_log(L_INFO, "IPC Client %d disconnected", client->fd);
348 wlc_event_source_remove(client->event_source); 331 wl_event_source_remove(client->event_source);
349 if (client->writable_event_source) { 332 if (client->writable_event_source) {
350 wlc_event_source_remove(client->writable_event_source); 333 wl_event_source_remove(client->writable_event_source);
351 } 334 }
352 int i = 0; 335 int i = 0;
353 while (i < ipc_client_list->length && ipc_client_list->items[i] != client) i++; 336 while (i < ipc_client_list->length && ipc_client_list->items[i] != client) i++;
@@ -365,165 +348,6 @@ bool output_by_name_test(swayc_t *view, void *data) {
365 return !strcmp(name, view->name); 348 return !strcmp(name, view->name);
366} 349}
367 350
368void ipc_get_pixels(wlc_handle output) {
369 if (ipc_get_pixel_requests->length == 0) {
370 return;
371 }
372
373 list_t *unhandled = create_list();
374
375 struct get_pixels_request *req;
376 int i;
377 for (i = 0; i < ipc_get_pixel_requests->length; ++i) {
378 req = ipc_get_pixel_requests->items[i];
379 if (req->output != output) {
380 list_add(unhandled, req);
381 continue;
382 }
383
384 const struct wlc_size *size = &req->geo.size;
385 struct wlc_geometry g_out;
386 char response_header[9];
387 memset(response_header, 0, sizeof(response_header));
388 char *data = malloc(sizeof(response_header) + size->w * size->h * 4);
389 if (!data) {
390 sway_log(L_ERROR, "Unable to allocate pixels for get_pixels");
391 ipc_client_disconnect(req->client);
392 free(req);
393 continue;
394 }
395 wlc_pixels_read(WLC_RGBA8888, &req->geo, &g_out, data + sizeof(response_header));
396
397 response_header[0] = 1;
398 uint32_t *_size = (uint32_t *)(response_header + 1);
399 _size[0] = g_out.size.w;
400 _size[1] = g_out.size.h;
401 size_t len = sizeof(response_header) + (g_out.size.w * g_out.size.h * 4);
402 memcpy(data, response_header, sizeof(response_header));
403 ipc_send_reply(req->client, data, len);
404 free(data);
405 // free the request since it has been handled
406 free(req);
407 }
408
409 // free old list of pixel requests and set new list to all unhandled
410 // requests (request for another output).
411 list_free(ipc_get_pixel_requests);
412 ipc_get_pixel_requests = unhandled;
413}
414
415static bool is_text_target(const char *target) {
416 return (strncmp(target, "text/", 5) == 0
417 || strcmp(target, "UTF8_STRING") == 0
418 || strcmp(target, "STRING") == 0
419 || strcmp(target, "TEXT") == 0
420 || strcmp(target, "COMPOUND_TEXT") == 0);
421}
422
423static void release_clipboard_request(struct get_clipboard_request *req) {
424 if (--(*req->pending) == 0) {
425 const char *str = json_object_to_json_string(req->json);
426 ipc_send_reply(req->client, str, (uint32_t)strlen(str));
427 json_object_put(req->json);
428 }
429
430 free(req->type);
431 free(req->buf);
432 wlc_event_source_remove(req->fd_event_source);
433 wlc_event_source_remove(req->timer_event_source);
434 close(req->fd);
435 free(req);
436}
437
438static int ipc_selection_data_cb(int fd, uint32_t mask, void *data) {
439 assert(data);
440 struct get_clipboard_request *req = (struct get_clipboard_request *)data;
441
442 if (mask & WLC_EVENT_ERROR) {
443 sway_log(L_ERROR, "Selection data fd error");
444 goto error;
445 }
446
447 if (mask & WLC_EVENT_READABLE) {
448 static const unsigned int max_size = 8192 * 1024;
449 int amt = 0;
450
451 do {
452 int size = req->buf_size - req->buf_position;
453 int amt = read(fd, req->buf + req->buf_position, size - 1);
454 if (amt < 0) {
455 if (errno == EAGAIN) {
456 return 0;
457 }
458
459 sway_log_errno(L_INFO, "Failed to read from clipboard data fd");
460 goto release;
461 }
462
463 req->buf_position += amt;
464 if (req->buf_position >= req->buf_size - 1) {
465 if (req->buf_size >= max_size) {
466 sway_log(L_ERROR, "get_clipbard: selection data too large");
467 goto error;
468 }
469 char *next = realloc(req->buf, req->buf_size *= 2);
470 if (!next) {
471 sway_log_errno(L_ERROR, "get_clipboard: realloc data buffer failed");
472 goto error;
473 }
474
475 req->buf = next;
476 }
477 } while(amt != 0);
478
479 req->buf[req->buf_position] = '\0';
480
481 json_object *obj = json_object_new_object();
482 json_object_object_add(obj, "success", json_object_new_boolean(true));
483 if (is_text_target(req->type)) {
484 json_object_object_add(obj, "content", json_object_new_string(req->buf));
485 json_object_object_add(req->json, req->type, obj);
486 } else {
487 size_t outlen;
488 char *b64 = b64_encode(req->buf, req->buf_position, &outlen);
489 json_object_object_add(obj, "content", json_object_new_string(b64));
490 free(b64);
491
492 char *type = malloc(strlen(req->type) + 8);
493 strcat(type, ";base64");
494 json_object_object_add(req->json, type, obj);
495 free(type);
496 }
497 }
498
499 goto release;
500
501error:;
502 json_object *obj = json_object_new_object();
503 json_object_object_add(obj, "success", json_object_new_boolean(false));
504 json_object_object_add(obj, "error",
505 json_object_new_string("Failed to retrieve data"));
506 json_object_object_add(req->json, req->type, obj);
507
508release:
509 release_clipboard_request(req);
510 return 0;
511}
512
513static int ipc_selection_timer_cb(void *data) {
514 assert(data);
515 struct get_clipboard_request *req = (struct get_clipboard_request *)data;
516
517 sway_log(L_INFO, "get_clipbard: timeout for type %s", req->type);
518 json_object *obj = json_object_new_object();
519 json_object_object_add(obj, "success", json_object_new_boolean(false));
520 json_object_object_add(obj, "error", json_object_new_string("Timeout"));
521 json_object_object_add(req->json, req->type, obj);
522
523 release_clipboard_request(req);
524 return 0;
525}
526
527// greedy wildcard (only "*") matching 351// greedy wildcard (only "*") matching
528bool mime_type_matches(const char *mime_type, const char *pattern) { 352bool mime_type_matches(const char *mime_type, const char *pattern) {
529 const char *wildcard = NULL; 353 const char *wildcard = NULL;
@@ -553,125 +377,6 @@ bool mime_type_matches(const char *mime_type, const char *pattern) {
553 return (*mime_type == *pattern); 377 return (*mime_type == *pattern);
554} 378}
555 379
556void ipc_get_clipboard(struct ipc_client *client, char *buf) {
557 size_t size;
558 const char **types = wlc_get_selection_types(&size);
559 if (client->payload_length == 0) {
560 json_object *obj = json_object_new_array();
561 for (size_t i = 0; i < size; ++i) {
562 json_object_array_add(obj, json_object_new_string(types[i]));
563 }
564
565 const char *str = json_object_to_json_string(obj);
566 ipc_send_reply(client, str, strlen(str));
567 json_object_put(obj);
568 return;
569 }
570
571 unescape_string(buf);
572 strip_quotes(buf);
573 list_t *requested = split_string(buf, " ");
574 json_object *json = json_object_new_object();
575 unsigned int *pending = malloc(sizeof(unsigned int));
576 *pending = 0;
577
578 for (size_t l = 0; l < (size_t) requested->length; ++l) {
579 const char *pattern = requested->items[l];
580 bool found = false;
581 for (size_t i = 0; i < size; ++i) {
582 if (!mime_type_matches(types[i], pattern)) {
583 continue;
584 }
585
586 found = true;
587
588 struct get_clipboard_request *req = malloc(sizeof(*req));
589 if (!req) {
590 sway_log(L_ERROR, "get_clipboard: request malloc failed");
591 goto data_error;
592 }
593
594 int pipes[2];
595 if (pipe(pipes) == -1) {
596 sway_log_errno(L_ERROR, "get_clipboard: pipe call failed");
597 free(req);
598 goto data_error;
599 }
600
601 fcntl(pipes[0], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
602 fcntl(pipes[1], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
603
604 if (!wlc_get_selection_data(types[i], pipes[1])) {
605 close(pipes[0]);
606 close(pipes[1]);
607 free(req);
608 sway_log(L_ERROR, "get_clipboard: failed to retrieve "
609 "selection data");
610 goto data_error;
611 }
612
613 if (!(req->buf = malloc(512))) {
614 close(pipes[0]);
615 close(pipes[1]);
616 free(req);
617 sway_log_errno(L_ERROR, "get_clipboard: buf malloc failed");
618 goto data_error;
619 }
620
621 (*pending)++;
622
623 req->client = client;
624 req->type = strdup(types[i]);
625 req->json = json;
626 req->pending = pending;
627 req->buf_position = 0;
628 req->buf_size = 512;
629 req->fd = pipes[0];
630 req->timer_event_source = wlc_event_loop_add_timer(ipc_selection_timer_cb, req);
631 req->fd_event_source = wlc_event_loop_add_fd(pipes[0],
632 WLC_EVENT_READABLE | WLC_EVENT_ERROR | WLC_EVENT_HANGUP,
633 &ipc_selection_data_cb, req);
634
635 wlc_event_source_timer_update(req->timer_event_source, 30000);
636
637 // NOTE: remove this goto to enable retrieving multiple
638 // targets at once. The whole implementation is already
639 // made for it. The only reason it was disabled
640 // at the time of writing is that neither wlc's xselection
641 // implementation nor (apparently) gtk on wayland supports
642 // multiple send requests at the same time which makes
643 // every request except the last one fail (and therefore
644 // return empty data)
645 goto cleanup;
646 }
647
648 if (!found) {
649 sway_log(L_INFO, "Invalid clipboard type %s requested", pattern);
650 }
651 }
652
653 if (*pending == 0) {
654 static const char *error_empty = "{ \"success\": false, \"error\": "
655 "\"No matching types found\" }";
656 ipc_send_reply(client, error_empty, (uint32_t)strlen(error_empty));
657 free(json);
658 free(pending);
659 }
660
661 goto cleanup;
662
663data_error:;
664 static const char *error_json = "{ \"success\": false, \"error\": "
665 "\"Failed to create clipboard data request\" }";
666 ipc_send_reply(client, error_json, (uint32_t)strlen(error_json));
667 free(json);
668 free(pending);
669
670cleanup:
671 list_free(requested);
672 free(types);
673}
674
675void ipc_client_handle_command(struct ipc_client *client) { 380void ipc_client_handle_command(struct ipc_client *client) {
676 if (!sway_assert(client != NULL, "client != NULL")) { 381 if (!sway_assert(client != NULL, "client != NULL")) {
677 return; 382 return;
@@ -830,52 +535,6 @@ void ipc_client_handle_command(struct ipc_client *client) {
830 goto exit_cleanup; 535 goto exit_cleanup;
831 } 536 }
832 537
833 case IPC_SWAY_GET_PIXELS:
834 {
835 char response_header[9];
836 memset(response_header, 0, sizeof(response_header));
837
838 json_object *obj = json_tokener_parse(buf);
839 json_object *o, *x, *y, *w, *h;
840
841 json_object_object_get_ex(obj, "output", &o);
842 json_object_object_get_ex(obj, "x", &x);
843 json_object_object_get_ex(obj, "y", &y);
844 json_object_object_get_ex(obj, "w", &w);
845 json_object_object_get_ex(obj, "h", &h);
846
847 struct wlc_geometry g = {
848 .origin = {
849 .x = json_object_get_int(x),
850 .y = json_object_get_int(y)
851 },
852 .size = {
853 .w = json_object_get_int(w),
854 .h = json_object_get_int(h)
855 }
856 };
857
858 swayc_t *output = swayc_by_test(&root_container, output_by_name_test, (void *)json_object_get_string(o));
859 json_object_put(obj);
860
861 if (!output) {
862 sway_log(L_ERROR, "IPC GET_PIXELS request with unknown output name");
863 ipc_send_reply(client, response_header, sizeof(response_header));
864 goto exit_cleanup;
865 }
866 struct get_pixels_request *req = malloc(sizeof(struct get_pixels_request));
867 if (!req) {
868 sway_log(L_ERROR, "Unable to allocate get_pixels request");
869 goto exit_cleanup;
870 }
871 req->client = client;
872 req->output = output->handle;
873 req->geo = g;
874 list_add(ipc_get_pixel_requests, req);
875 wlc_output_schedule_render(output->handle);
876 goto exit_cleanup;
877 }
878
879 case IPC_GET_BAR_CONFIG: 538 case IPC_GET_BAR_CONFIG:
880 { 539 {
881 if (!(client->security_policy & IPC_FEATURE_GET_BAR_CONFIG)) { 540 if (!(client->security_policy & IPC_FEATURE_GET_BAR_CONFIG)) {
@@ -917,14 +576,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
917 } 576 }
918 577
919 case IPC_GET_CLIPBOARD: 578 case IPC_GET_CLIPBOARD:
920 { 579 // TODO WLR
921 if (!(client->security_policy & IPC_FEATURE_GET_CLIPBOARD)) { 580 break;
922 goto exit_denied;
923 }
924
925 ipc_get_clipboard(client, buf);
926 goto exit_cleanup;
927 }
928 581
929 default: 582 default:
930 sway_log(L_INFO, "Unknown IPC command type %i", client->current_command); 583 sway_log(L_INFO, "Unknown IPC command type %i", client->current_command);
@@ -977,7 +630,9 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
977 client->write_buffer_len += payload_length; 630 client->write_buffer_len += payload_length;
978 631
979 if (!client->writable_event_source) { 632 if (!client->writable_event_source) {
980 client->writable_event_source = wlc_event_loop_add_fd(client->fd, WLC_EVENT_WRITABLE, ipc_client_handle_writable, client); 633 client->writable_event_source = wl_event_loop_add_fd(
634 server.wl_event_loop, client->fd, WL_EVENT_WRITABLE,
635 ipc_client_handle_writable, client);
981 } 636 }
982 637
983 sway_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload); 638 sway_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload);
diff --git a/sway/layout.c b/sway/layout.c
index 69291daf..22f81688 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -3,7 +3,6 @@
3#include <stdbool.h> 3#include <stdbool.h>
4#include <math.h> 4#include <math.h>
5#include <wlc/wlc.h> 5#include <wlc/wlc.h>
6#include "sway/extensions.h"
7#include "sway/config.h" 6#include "sway/config.h"
8#include "sway/container.h" 7#include "sway/container.h"
9#include "sway/workspace.h" 8#include "sway/workspace.h"
@@ -1001,6 +1000,7 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
1001 { 1000 {
1002 swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); 1001 swayc_t *output = swayc_parent_by_type(container, C_OUTPUT);
1003 width = output->width, height = output->height; 1002 width = output->width, height = output->height;
1003 /* TODO WLR
1004 for (i = 0; i < desktop_shell.panels->length; ++i) { 1004 for (i = 0; i < desktop_shell.panels->length; ++i) {
1005 struct panel_config *config = desktop_shell.panels->items[i]; 1005 struct panel_config *config = desktop_shell.panels->items[i];
1006 if (config->output == output->handle) { 1006 if (config->output == output->handle) {
@@ -1022,6 +1022,7 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
1022 } 1022 }
1023 } 1023 }
1024 } 1024 }
1025 */
1025 int gap = swayc_gap(container); 1026 int gap = swayc_gap(container);
1026 x = container->x = x + gap; 1027 x = container->x = x + gap;
1027 y = container->y = y + gap; 1028 y = container->y = y + gap;
@@ -1380,11 +1381,13 @@ void arrange_windows(swayc_t *container, double width, double height) {
1380} 1381}
1381 1382
1382void arrange_backgrounds(void) { 1383void arrange_backgrounds(void) {
1384 /* TODO WLR
1383 struct background_config *bg; 1385 struct background_config *bg;
1384 for (int i = 0; i < desktop_shell.backgrounds->length; ++i) { 1386 for (int i = 0; i < desktop_shell.backgrounds->length; ++i) {
1385 bg = desktop_shell.backgrounds->items[i]; 1387 bg = desktop_shell.backgrounds->items[i];
1386 wlc_view_send_to_back(bg->handle); 1388 wlc_view_send_to_back(bg->handle);
1387 } 1389 }
1390 */
1388} 1391}
1389 1392
1390/** 1393/**
diff --git a/sway/main.c b/sway/main.c
index cc9147b8..efca96d5 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -3,7 +3,6 @@
3#include <stdio.h> 3#include <stdio.h>
4#include <stdlib.h> 4#include <stdlib.h>
5#include <stdbool.h> 5#include <stdbool.h>
6#include <wlc/wlc.h>
7#include <sys/wait.h> 6#include <sys/wait.h>
8#include <sys/types.h> 7#include <sys/types.h>
9#include <sys/stat.h> 8#include <sys/stat.h>
@@ -15,13 +14,13 @@
15#include <sys/capability.h> 14#include <sys/capability.h>
16#include <sys/prctl.h> 15#include <sys/prctl.h>
17#endif 16#endif
18#include "sway/extensions.h"
19#include "sway/layout.h" 17#include "sway/layout.h"
20#include "sway/config.h" 18#include "sway/config.h"
21#include "sway/security.h" 19#include "sway/security.h"
22#include "sway/handlers.h" 20#include "sway/handlers.h"
23#include "sway/input.h" 21#include "sway/input.h"
24#include "sway/ipc-server.h" 22#include "sway/ipc-server.h"
23#include "sway/server.h"
25#include "ipc-client.h" 24#include "ipc-client.h"
26#include "readline.h" 25#include "readline.h"
27#include "stringop.h" 26#include "stringop.h"
@@ -31,11 +30,12 @@
31 30
32static bool terminate_request = false; 31static bool terminate_request = false;
33static int exit_value = 0; 32static int exit_value = 0;
33struct sway_server server;
34 34
35void sway_terminate(int exit_code) { 35void sway_terminate(int exit_code) {
36 terminate_request = true; 36 terminate_request = true;
37 exit_value = exit_code; 37 exit_value = exit_code;
38 wlc_terminate(); 38 wl_display_terminate(server.wl_display);
39} 39}
40 40
41void sig_handler(int signal) { 41void sig_handler(int signal) {
@@ -43,16 +43,6 @@ void sig_handler(int signal) {
43 sway_terminate(EXIT_SUCCESS); 43 sway_terminate(EXIT_SUCCESS);
44} 44}
45 45
46static void wlc_log_handler(enum wlc_log_type type, const char *str) {
47 if (type == WLC_LOG_ERROR) {
48 sway_log(L_ERROR, "[wlc] %s", str);
49 } else if (type == WLC_LOG_WARN) {
50 sway_log(L_INFO, "[wlc] %s", str);
51 } else {
52 sway_log(L_DEBUG, "[wlc] %s", str);
53 }
54}
55
56void detect_raspi() { 46void detect_raspi() {
57 bool raspi = false; 47 bool raspi = false;
58 FILE *f = fopen("/sys/firmware/devicetree/base/model", "r"); 48 FILE *f = fopen("/sys/firmware/devicetree/base/model", "r");
@@ -189,19 +179,7 @@ static void log_env() {
189 "LD_LIBRARY_PATH", 179 "LD_LIBRARY_PATH",
190 "SWAY_CURSOR_THEME", 180 "SWAY_CURSOR_THEME",
191 "SWAY_CURSOR_SIZE", 181 "SWAY_CURSOR_SIZE",
192 "SWAYSOCK", 182 "SWAYSOCK"
193 "WLC_DRM_DEVICE",
194 "WLC_SHM",
195 "WLC_OUTPUTS",
196 "WLC_XWAYLAND",
197 "WLC_LIBINPUT",
198 "WLC_REPEAT_DELAY",
199 "WLC_REPEAT_RATE",
200 "XKB_DEFAULT_RULES",
201 "XKB_DEFAULT_MODEL",
202 "XKB_DEFAULT_LAYOUT",
203 "XKB_DEFAULT_VARIANT",
204 "XKB_DEFAULT_OPTIONS",
205 }; 183 };
206 for (size_t i = 0; i < sizeof(log_vars) / sizeof(char *); ++i) { 184 for (size_t i = 0; i < sizeof(log_vars) / sizeof(char *); ++i) {
207 sway_log(L_INFO, "%s=%s", log_vars[i], getenv(log_vars[i])); 185 sway_log(L_INFO, "%s=%s", log_vars[i], getenv(log_vars[i]));
@@ -295,6 +273,37 @@ static void executable_sanity_check() {
295#endif 273#endif
296} 274}
297 275
276static void drop_permissions(bool keep_caps) {
277 if (getuid() != geteuid() || getgid() != getegid()) {
278 if (setgid(getgid()) != 0) {
279 sway_log(L_ERROR, "Unable to drop root");
280 exit(EXIT_FAILURE);
281 }
282 if (setuid(getuid()) != 0) {
283 sway_log(L_ERROR, "Unable to drop root");
284 exit(EXIT_FAILURE);
285 }
286 }
287 if (setuid(0) != -1) {
288 sway_log(L_ERROR, "Root privileges can be restored.");
289 exit(EXIT_FAILURE);
290 }
291#ifdef __linux__
292 if (keep_caps) {
293 // Drop every cap except CAP_SYS_PTRACE
294 cap_t caps = cap_init();
295 cap_value_t keep = CAP_SYS_PTRACE;
296 sway_log(L_INFO, "Dropping extra capabilities");
297 if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) ||
298 cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) ||
299 cap_set_proc(caps)) {
300 sway_log(L_ERROR, "Failed to drop extra capabilities");
301 exit(EXIT_FAILURE);
302 }
303 }
304#endif
305}
306
298int main(int argc, char **argv) { 307int main(int argc, char **argv) {
299 static int verbose = 0, debug = 0, validate = 0; 308 static int verbose = 0, debug = 0, validate = 0;
300 309
@@ -374,7 +383,7 @@ int main(int argc, char **argv) {
374 } 383 }
375 } 384 }
376 385
377 // we need to setup logging before wlc_init in case it fails. 386 // TODO: switch logging over to wlroots?
378 if (debug) { 387 if (debug) {
379 init_log(L_DEBUG); 388 init_log(L_DEBUG);
380 } else if (verbose || validate) { 389 } else if (verbose || validate) {
@@ -388,20 +397,7 @@ int main(int argc, char **argv) {
388 sway_log(L_ERROR, "Don't use options with the IPC client"); 397 sway_log(L_ERROR, "Don't use options with the IPC client");
389 exit(EXIT_FAILURE); 398 exit(EXIT_FAILURE);
390 } 399 }
391 if (getuid() != geteuid() || getgid() != getegid()) { 400 drop_permissions(false);
392 if (setgid(getgid()) != 0) {
393 sway_log(L_ERROR, "Unable to drop root");
394 exit(EXIT_FAILURE);
395 }
396 if (setuid(getuid()) != 0) {
397 sway_log(L_ERROR, "Unable to drop root");
398 exit(EXIT_FAILURE);
399 }
400 }
401 if (setuid(0) != -1) {
402 sway_log(L_ERROR, "Root privileges can be restored.");
403 exit(EXIT_FAILURE);
404 }
405 char *socket_path = getenv("SWAYSOCK"); 401 char *socket_path = getenv("SWAYSOCK");
406 if (!socket_path) { 402 if (!socket_path) {
407 sway_log(L_ERROR, "Unable to retrieve socket path"); 403 sway_log(L_ERROR, "Unable to retrieve socket path");
@@ -413,8 +409,8 @@ int main(int argc, char **argv) {
413 } 409 }
414 410
415 executable_sanity_check(); 411 executable_sanity_check();
416#ifdef __linux__
417 bool suid = false; 412 bool suid = false;
413#ifdef __linux__
418 if (getuid() != geteuid() || getgid() != getegid()) { 414 if (getuid() != geteuid() || getgid() != getegid()) {
419 // Retain capabilities after setuid() 415 // Retain capabilities after setuid()
420 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) { 416 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
@@ -425,37 +421,14 @@ int main(int argc, char **argv) {
425 } 421 }
426#endif 422#endif
427 423
428 wlc_log_set_handler(wlc_log_handler);
429 log_kernel(); 424 log_kernel();
430 log_distro(); 425 log_distro();
431 log_env(); 426 log_env();
432 detect_proprietary(); 427 detect_proprietary();
433 detect_raspi(); 428 detect_raspi();
434 429
435 input_devices = create_list();
436
437 /* Changing code earlier than this point requires detailed review */
438 /* (That code runs as root on systems without logind, and wlc_init drops to
439 * another user.) */
440 register_wlc_handlers();
441 if (!wlc_init()) {
442 return 1;
443 }
444 register_extensions();
445
446#ifdef __linux__ 430#ifdef __linux__
447 if (suid) { 431 drop_permissions(suid);
448 // Drop every cap except CAP_SYS_PTRACE
449 cap_t caps = cap_init();
450 cap_value_t keep = CAP_SYS_PTRACE;
451 sway_log(L_INFO, "Dropping extra capabilities");
452 if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) ||
453 cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) ||
454 cap_set_proc(caps)) {
455 sway_log(L_ERROR, "Failed to drop extra capabilities");
456 exit(EXIT_FAILURE);
457 }
458 }
459#endif 432#endif
460 // handle SIGTERM signals 433 // handle SIGTERM signals
461 signal(SIGTERM, sig_handler); 434 signal(SIGTERM, sig_handler);
@@ -465,8 +438,10 @@ int main(int argc, char **argv) {
465 438
466 sway_log(L_INFO, "Starting sway version " SWAY_VERSION "\n"); 439 sway_log(L_INFO, "Starting sway version " SWAY_VERSION "\n");
467 440
441 if (!server_init(&server)) {
442 return 1;
443 }
468 init_layout(); 444 init_layout();
469
470 ipc_init(); 445 ipc_init();
471 446
472 if (validate) { 447 if (validate) {
@@ -485,10 +460,10 @@ int main(int argc, char **argv) {
485 security_sanity_check(); 460 security_sanity_check();
486 461
487 if (!terminate_request) { 462 if (!terminate_request) {
488 wlc_run(); 463 wl_display_run(server.wl_display);
489 } 464 }
490 465
491 list_free(input_devices); 466 server_fini(&server);
492 467
493 ipc_terminate(); 468 ipc_terminate();
494 469
diff --git a/sway/server.c b/sway/server.c
new file mode 100644
index 00000000..39fa5d28
--- /dev/null
+++ b/sway/server.c
@@ -0,0 +1,54 @@
1#define _POSIX_C_SOURCE 200112L
2#include <stdlib.h>
3#include <stdbool.h>
4#include <wayland-server.h>
5#include <wlr/backend.h>
6#include <wlr/backend/session.h>
7#include <wlr/types/wlr_data_device_manager.h>
8#include <wlr/render.h>
9#include <wlr/render/gles2.h>
10// TODO WLR: make Xwayland optional
11#include <wlr/xwayland.h>
12#include "sway/server.h"
13#include "log.h"
14
15bool server_init(struct sway_server *server) {
16 sway_log(L_DEBUG, "Initializing Wayland server");
17
18 server->wl_display = wl_display_create();
19 server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
20 server->backend = wlr_backend_autocreate(server->wl_display);
21
22 server->renderer = wlr_gles2_renderer_create(server->backend);
23 wl_display_init_shm(server->wl_display);
24
25 // TODO WLR
26 //server->desktop = desktop_create(server, server.config);
27 //server->input = input_create(&server, server.config);
28 server->data_device_manager =
29 wlr_data_device_manager_create(server->wl_display);
30
31 const char *socket = wl_display_add_socket_auto(server->wl_display);
32 if (!socket) {
33 sway_log_errno(L_ERROR, "Unable to open wayland socket");
34 wlr_backend_destroy(server->backend);
35 return false;
36 }
37
38 sway_log(L_INFO, "Running compositor on wayland display '%s'", socket);
39 setenv("_WAYLAND_DISPLAY", socket, true);
40
41 if (!wlr_backend_start(server->backend)) {
42 sway_log(L_ERROR, "Failed to start backend");
43 wlr_backend_destroy(server->backend);
44 return false;
45 }
46
47 setenv("WAYLAND_DISPLAY", socket, true);
48 return true;
49}
50
51void server_fini(struct sway_server *server) {
52 // TODO WLR: tear down more stuff
53 wlr_backend_destroy(server->backend);
54}
diff --git a/sway/workspace.c b/sway/workspace.c
index e0367190..14cde146 100644
--- a/sway/workspace.c
+++ b/sway/workspace.c
@@ -8,7 +8,6 @@
8#include <strings.h> 8#include <strings.h>
9#include <sys/types.h> 9#include <sys/types.h>
10#include "sway/ipc-server.h" 10#include "sway/ipc-server.h"
11#include "sway/extensions.h"
12#include "sway/workspace.h" 11#include "sway/workspace.h"
13#include "sway/layout.h" 12#include "sway/layout.h"
14#include "sway/container.h" 13#include "sway/container.h"