diff options
Diffstat (limited to 'sway/handlers.c')
-rw-r--r-- | sway/handlers.c | 1143 |
1 files changed, 0 insertions, 1143 deletions
diff --git a/sway/handlers.c b/sway/handlers.c deleted file mode 100644 index 33e75d6b..00000000 --- a/sway/handlers.c +++ /dev/null | |||
@@ -1,1143 +0,0 @@ | |||
1 | #define _XOPEN_SOURCE 500 | ||
2 | #include <xkbcommon/xkbcommon.h> | ||
3 | #include <strings.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <stdbool.h> | ||
6 | #include <libinput.h> | ||
7 | #include <math.h> | ||
8 | #include <wlc/wlc.h> | ||
9 | #include <wlc/wlc-render.h> | ||
10 | #include <wlc/wlc-wayland.h> | ||
11 | #include <ctype.h> | ||
12 | #include "sway/handlers.h" | ||
13 | #include "sway/border.h" | ||
14 | #include "sway/layout.h" | ||
15 | #include "sway/config.h" | ||
16 | #include "sway/commands.h" | ||
17 | #include "sway/workspace.h" | ||
18 | #include "sway/container.h" | ||
19 | #include "sway/output.h" | ||
20 | #include "sway/focus.h" | ||
21 | #include "sway/input_state.h" | ||
22 | #include "sway/extensions.h" | ||
23 | #include "sway/criteria.h" | ||
24 | #include "sway/ipc-server.h" | ||
25 | #include "sway/input.h" | ||
26 | #include "sway/security.h" | ||
27 | #include "list.h" | ||
28 | #include "stringop.h" | ||
29 | #include "log.h" | ||
30 | |||
31 | // Event should be sent to client | ||
32 | #define EVENT_PASSTHROUGH false | ||
33 | |||
34 | // Event handled by sway and should not be sent to client | ||
35 | #define EVENT_HANDLED true | ||
36 | |||
37 | static struct panel_config *if_panel_find_config(struct wl_client *client) { | ||
38 | int i; | ||
39 | for (i = 0; i < desktop_shell.panels->length; i++) { | ||
40 | struct panel_config *config = desktop_shell.panels->items[i]; | ||
41 | if (config->client == client) { | ||
42 | return config; | ||
43 | } | ||
44 | } | ||
45 | return NULL; | ||
46 | } | ||
47 | |||
48 | static struct background_config *if_background_find_config(struct wl_client *client) { | ||
49 | int i; | ||
50 | for (i = 0; i < desktop_shell.backgrounds->length; i++) { | ||
51 | struct background_config *config = desktop_shell.backgrounds->items[i]; | ||
52 | if (config->client == client) { | ||
53 | return config; | ||
54 | } | ||
55 | } | ||
56 | return NULL; | ||
57 | } | ||
58 | |||
59 | static struct wlc_geometry compute_panel_geometry(struct panel_config *config) { | ||
60 | struct wlc_size resolution; | ||
61 | output_get_scaled_size(config->output, &resolution); | ||
62 | const struct wlc_geometry *old = wlc_view_get_geometry(config->handle); | ||
63 | struct wlc_geometry new; | ||
64 | |||
65 | switch (config->panel_position) { | ||
66 | case DESKTOP_SHELL_PANEL_POSITION_TOP: | ||
67 | new.origin.x = 0; | ||
68 | new.origin.y = 0; | ||
69 | new.size.w = resolution.w; | ||
70 | new.size.h = old->size.h; | ||
71 | break; | ||
72 | case DESKTOP_SHELL_PANEL_POSITION_BOTTOM: | ||
73 | new.origin.x = 0; | ||
74 | new.origin.y = resolution.h - old->size.h; | ||
75 | new.size.w = resolution.w; | ||
76 | new.size.h = old->size.h; | ||
77 | break; | ||
78 | case DESKTOP_SHELL_PANEL_POSITION_LEFT: | ||
79 | new.origin.x = 0; | ||
80 | new.origin.y = 0; | ||
81 | new.size.w = old->size.w; | ||
82 | new.size.h = resolution.h; | ||
83 | break; | ||
84 | case DESKTOP_SHELL_PANEL_POSITION_RIGHT: | ||
85 | new.origin.x = resolution.w - old->size.w; | ||
86 | new.origin.y = 0; | ||
87 | new.size.w = old->size.w; | ||
88 | new.size.h = resolution.h; | ||
89 | break; | ||
90 | } | ||
91 | |||
92 | return new; | ||
93 | } | ||
94 | |||
95 | static void update_panel_geometry(struct panel_config *config) { | ||
96 | struct wlc_geometry geometry = compute_panel_geometry(config); | ||
97 | wlc_view_set_geometry(config->handle, 0, &geometry); | ||
98 | } | ||
99 | |||
100 | static void update_panel_geometries(wlc_handle output) { | ||
101 | for (int i = 0; i < desktop_shell.panels->length; i++) { | ||
102 | struct panel_config *config = desktop_shell.panels->items[i]; | ||
103 | if (config->output == output) { | ||
104 | update_panel_geometry(config); | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | |||
109 | static void update_background_geometry(struct background_config *config) { | ||
110 | struct wlc_geometry geometry = wlc_geometry_zero; | ||
111 | output_get_scaled_size(config->output, &geometry.size); | ||
112 | wlc_view_set_geometry(config->handle, 0, &geometry); | ||
113 | } | ||
114 | |||
115 | static void update_background_geometries(wlc_handle output) { | ||
116 | for (int i = 0; i < desktop_shell.backgrounds->length; i++) { | ||
117 | struct background_config *config = desktop_shell.backgrounds->items[i]; | ||
118 | if (config->output == output) { | ||
119 | update_background_geometry(config); | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | |||
124 | /* Handles */ | ||
125 | |||
126 | static bool handle_input_created(struct libinput_device *device) { | ||
127 | const char *identifier = libinput_dev_unique_id(device); | ||
128 | if (!identifier) { | ||
129 | sway_log(L_ERROR, "Unable to allocate unique name for input device %p", | ||
130 | device); | ||
131 | return true; | ||
132 | } | ||
133 | sway_log(L_INFO, "Found input device (%s)", identifier); | ||
134 | |||
135 | list_add(input_devices, device); | ||
136 | |||
137 | struct input_config *ic = NULL; | ||
138 | int i; | ||
139 | for (i = 0; i < config->input_configs->length; ++i) { | ||
140 | struct input_config *cur = config->input_configs->items[i]; | ||
141 | if (strcasecmp(identifier, cur->identifier) == 0) { | ||
142 | sway_log(L_DEBUG, "Matched input config for %s", | ||
143 | identifier); | ||
144 | ic = cur; | ||
145 | break; | ||
146 | } | ||
147 | if (strcasecmp("*", cur->identifier) == 0) { | ||
148 | sway_log(L_DEBUG, "Matched wildcard input config for %s", | ||
149 | identifier); | ||
150 | ic = cur; | ||
151 | break; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | apply_input_config(ic, device); | ||
156 | return true; | ||
157 | } | ||
158 | |||
159 | static void handle_input_destroyed(struct libinput_device *device) { | ||
160 | int i; | ||
161 | list_t *list = input_devices; | ||
162 | for (i = 0; i < list->length; ++i) { | ||
163 | if(((struct libinput_device *)list->items[i]) == device) { | ||
164 | list_del(list, i); | ||
165 | break; | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | |||
170 | static bool handle_output_created(wlc_handle output) { | ||
171 | swayc_t *op = new_output(output); | ||
172 | |||
173 | // Visibility mask to be able to make view invisible | ||
174 | wlc_output_set_mask(output, VISIBLE); | ||
175 | |||
176 | if (!op) { | ||
177 | return false; | ||
178 | } | ||
179 | |||
180 | // Switch to workspace if we need to | ||
181 | if (swayc_active_workspace() == NULL) { | ||
182 | swayc_t *ws = op->children->items[0]; | ||
183 | workspace_switch(ws); | ||
184 | } | ||
185 | |||
186 | // Fixes issues with backgrounds and wlc | ||
187 | wlc_handle prev = wlc_get_focused_output(); | ||
188 | wlc_output_focus(output); | ||
189 | wlc_output_focus(prev); | ||
190 | return true; | ||
191 | } | ||
192 | |||
193 | static void handle_output_destroyed(wlc_handle output) { | ||
194 | int i; | ||
195 | list_t *list = root_container.children; | ||
196 | for (i = 0; i < list->length; ++i) { | ||
197 | if (((swayc_t *)list->items[i])->handle == output) { | ||
198 | break; | ||
199 | } | ||
200 | } | ||
201 | if (i < list->length) { | ||
202 | destroy_output(list->items[i]); | ||
203 | } else { | ||
204 | return; | ||
205 | } | ||
206 | if (list->length > 0) { | ||
207 | // switch to other outputs active workspace | ||
208 | workspace_switch(((swayc_t *)root_container.children->items[0])->focused); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | static void handle_output_post_render(wlc_handle output) { | ||
213 | ipc_get_pixels(output); | ||
214 | } | ||
215 | |||
216 | static void handle_view_pre_render(wlc_handle view) { | ||
217 | render_view_borders(view); | ||
218 | } | ||
219 | |||
220 | static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) { | ||
221 | sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h); | ||
222 | |||
223 | swayc_t *c = swayc_by_handle(output); | ||
224 | if (!c) { | ||
225 | return; | ||
226 | } | ||
227 | c->width = to->w; | ||
228 | c->height = to->h; | ||
229 | |||
230 | update_panel_geometries(output); | ||
231 | update_background_geometries(output); | ||
232 | |||
233 | arrange_windows(&root_container, -1, -1); | ||
234 | } | ||
235 | |||
236 | static void handle_output_focused(wlc_handle output, bool focus) { | ||
237 | swayc_t *c = swayc_by_handle(output); | ||
238 | // if for some reason this output doesn't exist, create it. | ||
239 | if (!c) { | ||
240 | handle_output_created(output); | ||
241 | } | ||
242 | if (focus) { | ||
243 | set_focused_container(get_focused_container(c)); | ||
244 | } | ||
245 | } | ||
246 | |||
247 | static void ws_cleanup() { | ||
248 | swayc_t *op, *ws; | ||
249 | int i = 0, j; | ||
250 | if (!root_container.children) | ||
251 | return; | ||
252 | while (i < root_container.children->length) { | ||
253 | op = root_container.children->items[i++]; | ||
254 | if (!op->children) | ||
255 | continue; | ||
256 | j = 0; | ||
257 | while (j < op->children->length) { | ||
258 | ws = op->children->items[j++]; | ||
259 | if (ws->children->length == 0 && ws->floating->length == 0 && ws != op->focused) { | ||
260 | if (destroy_workspace(ws)) { | ||
261 | j--; | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | |||
268 | static void positioner_place_window(wlc_handle handle) { | ||
269 | const struct wlc_geometry *anchor = wlc_view_positioner_get_anchor_rect(handle); | ||
270 | const struct wlc_size *sr = wlc_view_positioner_get_size(handle); | ||
271 | // a positioner is required to have a non-null anchor and a non-negative size | ||
272 | if (!anchor || !sr || | ||
273 | sr->w <= 0 || sr->h <= 0 || | ||
274 | anchor->size.w <= 0 || anchor->size.h <= 0) { | ||
275 | return; | ||
276 | } | ||
277 | const struct wlc_point offset = *wlc_view_positioner_get_offset(handle); | ||
278 | enum wlc_positioner_anchor_bit anchors = wlc_view_positioner_get_anchor(handle); | ||
279 | enum wlc_positioner_gravity_bit gravity = wlc_view_positioner_get_gravity(handle); | ||
280 | struct wlc_geometry geo = { | ||
281 | .origin = offset, | ||
282 | .size = *sr | ||
283 | }; | ||
284 | |||
285 | if (anchors & WLC_BIT_ANCHOR_TOP) { | ||
286 | geo.origin.y += anchor->origin.y; | ||
287 | } else if (anchors & WLC_BIT_ANCHOR_BOTTOM) { | ||
288 | geo.origin.y += anchor->origin.y + anchor->size.h; | ||
289 | } else { | ||
290 | geo.origin.y += anchor->origin.y + anchor->size.h / 2; | ||
291 | } | ||
292 | if (anchors & WLC_BIT_ANCHOR_LEFT) { | ||
293 | geo.origin.x += anchor->origin.x; | ||
294 | } else if (anchors & WLC_BIT_ANCHOR_RIGHT) { | ||
295 | geo.origin.x += anchor->origin.x + anchor->size.w; | ||
296 | } else { | ||
297 | geo.origin.x += anchor->origin.x + anchor->size.w / 2; | ||
298 | } | ||
299 | |||
300 | if (gravity & WLC_BIT_GRAVITY_TOP) { | ||
301 | geo.origin.y -= geo.size.h; | ||
302 | } else if (gravity & WLC_BIT_GRAVITY_BOTTOM) { | ||
303 | /* default */ | ||
304 | } else { | ||
305 | geo.origin.y -= geo.size.h / 2; | ||
306 | } | ||
307 | if (gravity & WLC_BIT_GRAVITY_LEFT) { | ||
308 | geo.origin.x -= geo.size.w; | ||
309 | } else if (gravity & WLC_BIT_GRAVITY_RIGHT) { | ||
310 | /* default */ | ||
311 | } else { | ||
312 | geo.origin.x -= geo.size.w / 2; | ||
313 | } | ||
314 | |||
315 | sway_log(L_DEBUG, "xdg-positioner: placing window %" PRIuPTR " " | ||
316 | "sized (%u,%u) offset by (%d,%d), " | ||
317 | "anchor rectangle sized (%u,%u) at (%d,%d), " | ||
318 | "anchor edges: %s %s, gravity: %s %s", | ||
319 | handle, | ||
320 | sr->w, sr->h, offset.x, offset.y, | ||
321 | anchor->size.w, anchor->size.h, anchor->origin.x, anchor->origin.y, | ||
322 | anchors & WLC_BIT_ANCHOR_TOP ? "top" : | ||
323 | (anchors & WLC_BIT_ANCHOR_BOTTOM ? "bottom" : "middle"), | ||
324 | anchors & WLC_BIT_ANCHOR_LEFT ? "left" : | ||
325 | (anchors & WLC_BIT_ANCHOR_RIGHT ? "right" : "center"), | ||
326 | gravity & WLC_BIT_GRAVITY_TOP ? "top" : | ||
327 | (gravity & WLC_BIT_GRAVITY_BOTTOM ? "bottom" : "middle"), | ||
328 | gravity & WLC_BIT_GRAVITY_LEFT ? "left" : | ||
329 | (gravity & WLC_BIT_GRAVITY_RIGHT ? "right" : "center")); | ||
330 | |||
331 | wlc_handle parent = wlc_view_get_parent(handle); | ||
332 | if (parent) { | ||
333 | const struct wlc_geometry *pg = wlc_view_get_geometry(parent); | ||
334 | geo.origin.x += pg->origin.x; | ||
335 | geo.origin.y += pg->origin.y; | ||
336 | } | ||
337 | wlc_view_set_geometry(handle, 0, &geo); | ||
338 | } | ||
339 | |||
340 | static bool handle_view_created(wlc_handle handle) { | ||
341 | // if view is child of another view, the use that as focused container | ||
342 | wlc_handle parent = wlc_view_get_parent(handle); | ||
343 | swayc_t *focused = NULL; | ||
344 | swayc_t *newview = NULL; | ||
345 | swayc_t *current_ws = swayc_active_workspace(); | ||
346 | bool return_to_workspace = false; | ||
347 | struct wl_client *client = wlc_view_get_wl_client(handle); | ||
348 | struct wl_resource *resource = wlc_surface_get_wl_resource( | ||
349 | wlc_view_get_surface(handle)); | ||
350 | pid_t pid; | ||
351 | struct panel_config *panel_config = NULL; | ||
352 | struct background_config *background_config = NULL; | ||
353 | |||
354 | panel_config = if_panel_find_config(client); | ||
355 | if (panel_config) { | ||
356 | panel_config->handle = handle; | ||
357 | update_panel_geometry(panel_config); | ||
358 | wlc_view_set_mask(handle, VISIBLE); | ||
359 | wlc_view_set_output(handle, panel_config->output); | ||
360 | wlc_view_bring_to_front(handle); | ||
361 | arrange_windows(&root_container, -1, -1); | ||
362 | return true; | ||
363 | } | ||
364 | |||
365 | background_config = if_background_find_config(client); | ||
366 | if (background_config) { | ||
367 | background_config->handle = handle; | ||
368 | update_background_geometry(background_config); | ||
369 | wlc_view_set_mask(handle, VISIBLE); | ||
370 | wlc_view_set_output(handle, background_config->output); | ||
371 | wlc_view_send_to_back(handle); | ||
372 | return true; | ||
373 | } | ||
374 | |||
375 | // Get parent container, to add view in | ||
376 | if (parent) { | ||
377 | focused = swayc_by_handle(parent); | ||
378 | } | ||
379 | |||
380 | if (client) { | ||
381 | pid = wlc_view_get_pid(handle); | ||
382 | |||
383 | if (pid) { | ||
384 | // using newview as a temp storage location here, | ||
385 | // rather than adding yet another workspace var | ||
386 | newview = workspace_for_pid(pid); | ||
387 | if (newview) { | ||
388 | focused = get_focused_container(newview); | ||
389 | return_to_workspace = true; | ||
390 | } | ||
391 | newview = NULL; | ||
392 | } | ||
393 | } | ||
394 | |||
395 | swayc_t *prev_focus = get_focused_container(&root_container); | ||
396 | |||
397 | if (!focused || focused->type == C_OUTPUT) { | ||
398 | focused = prev_focus; | ||
399 | // Move focus from floating view | ||
400 | if (focused->is_floating) { | ||
401 | // To workspace if there are no children | ||
402 | if (focused->parent->children->length == 0) { | ||
403 | focused = focused->parent; | ||
404 | } | ||
405 | // TODO find a better way of doing this | ||
406 | // Or to focused container | ||
407 | else { | ||
408 | focused = get_focused_container(focused->parent->children->items[0]); | ||
409 | } | ||
410 | } | ||
411 | } | ||
412 | |||
413 | positioner_place_window(handle); | ||
414 | |||
415 | sway_log(L_DEBUG, "handle:%" PRIuPTR " type:%x state:%x parent:%" PRIuPTR " " | ||
416 | "mask:%d (x:%d y:%d w:%d h:%d) title:%s " | ||
417 | "class:%s appid:%s", | ||
418 | handle, wlc_view_get_type(handle), wlc_view_get_state(handle), parent, | ||
419 | wlc_view_get_mask(handle), wlc_view_get_geometry(handle)->origin.x, | ||
420 | wlc_view_get_geometry(handle)->origin.y,wlc_view_get_geometry(handle)->size.w, | ||
421 | wlc_view_get_geometry(handle)->size.h, wlc_view_get_title(handle), | ||
422 | wlc_view_get_class(handle), wlc_view_get_app_id(handle)); | ||
423 | |||
424 | // TODO properly figure out how each window should be handled. | ||
425 | switch (wlc_view_get_type(handle)) { | ||
426 | // regular view created regularly | ||
427 | case 0: | ||
428 | if (parent) { | ||
429 | newview = new_floating_view(handle); | ||
430 | } else { | ||
431 | newview = new_view(focused, handle); | ||
432 | wlc_view_set_state(handle, WLC_BIT_MAXIMIZED, true); | ||
433 | } | ||
434 | break; | ||
435 | |||
436 | // Dmenu keeps viewfocus, but others with this flag don't, for now simulate | ||
437 | // dmenu | ||
438 | case WLC_BIT_OVERRIDE_REDIRECT: | ||
439 | wlc_view_focus(handle); | ||
440 | wlc_view_set_state(handle, WLC_BIT_ACTIVATED, true); | ||
441 | wlc_view_bring_to_front(handle); | ||
442 | break; | ||
443 | |||
444 | // Firefox popups have this flag set. | ||
445 | case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: | ||
446 | wlc_view_bring_to_front(handle); | ||
447 | locked_container_focus = true; | ||
448 | break; | ||
449 | |||
450 | // Modals, get focus, popups do not | ||
451 | case WLC_BIT_MODAL: | ||
452 | wlc_view_focus(handle); | ||
453 | wlc_view_bring_to_front(handle); | ||
454 | newview = new_floating_view(handle); | ||
455 | /* fallthrough */ | ||
456 | case WLC_BIT_POPUP: | ||
457 | wlc_view_bring_to_front(handle); | ||
458 | break; | ||
459 | } | ||
460 | |||
461 | // Prevent current ws from being destroyed, if empty | ||
462 | suspend_workspace_cleanup = true; | ||
463 | |||
464 | if (newview) { | ||
465 | ipc_event_window(newview, "new"); | ||
466 | set_focused_container(newview); | ||
467 | wlc_view_set_mask(handle, VISIBLE); | ||
468 | swayc_t *output = swayc_parent_by_type(newview, C_OUTPUT); | ||
469 | arrange_windows(output, -1, -1); | ||
470 | // check if it matches for_window in config and execute if so | ||
471 | list_t *criteria = criteria_for(newview); | ||
472 | for (int i = 0; i < criteria->length; i++) { | ||
473 | struct criteria *crit = criteria->items[i]; | ||
474 | sway_log(L_DEBUG, "for_window '%s' matches new view %p, cmd: '%s'", | ||
475 | crit->crit_raw, newview, crit->cmdlist); | ||
476 | struct cmd_results *res = handle_command(crit->cmdlist, CONTEXT_CRITERIA); | ||
477 | if (res->status != CMD_SUCCESS) { | ||
478 | sway_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error); | ||
479 | } | ||
480 | free_cmd_results(res); | ||
481 | // view must be focused for commands to affect it, so always | ||
482 | // refocus in-between command lists | ||
483 | set_focused_container(newview); | ||
484 | } | ||
485 | swayc_t *workspace = swayc_parent_by_type(focused, C_WORKSPACE); | ||
486 | if (workspace && workspace->fullscreen) { | ||
487 | set_focused_container(workspace->fullscreen); | ||
488 | } | ||
489 | for (int i = 0; i < decoration_state.csd_resources->length; ++i) { | ||
490 | struct wl_resource *res = decoration_state.csd_resources->items[i]; | ||
491 | if (res == resource) { | ||
492 | list_del(decoration_state.csd_resources, i); | ||
493 | server_decoration_enable_csd(handle); | ||
494 | break; | ||
495 | } | ||
496 | } | ||
497 | } else { | ||
498 | swayc_t *output = swayc_parent_by_type(focused, C_OUTPUT); | ||
499 | wlc_handle *h = malloc(sizeof(wlc_handle)); | ||
500 | if (!h) { | ||
501 | sway_log(L_ERROR, "Unable to allocate window handle, view handler bailing out"); | ||
502 | return true; | ||
503 | } | ||
504 | *h = handle; | ||
505 | sway_log(L_DEBUG, "Adding unmanaged window %p to %p", h, output->unmanaged); | ||
506 | list_add(output->unmanaged, h); | ||
507 | wlc_view_set_mask(handle, VISIBLE); | ||
508 | } | ||
509 | |||
510 | if (return_to_workspace && current_ws != swayc_active_workspace()) { | ||
511 | // we were on one workspace, switched to another to add this view, | ||
512 | // now let's return to where we were | ||
513 | workspace_switch(current_ws); | ||
514 | set_focused_container(get_focused_container(current_ws)); | ||
515 | } | ||
516 | if (prev_focus && prev_focus->type == C_VIEW | ||
517 | && newview && criteria_any(newview, config->no_focus)) { | ||
518 | // Restore focus | ||
519 | swayc_t *ws = swayc_parent_by_type(newview, C_WORKSPACE); | ||
520 | if (!ws || ws != newview->parent | ||
521 | || ws->children->length + ws->floating->length != 1) { | ||
522 | sway_log(L_DEBUG, "no_focus: restoring focus to %s", prev_focus->name); | ||
523 | set_focused_container(prev_focus); | ||
524 | } | ||
525 | } | ||
526 | |||
527 | suspend_workspace_cleanup = false; | ||
528 | ws_cleanup(); | ||
529 | return true; | ||
530 | } | ||
531 | |||
532 | static void handle_view_destroyed(wlc_handle handle) { | ||
533 | sway_log(L_DEBUG, "Destroying window %" PRIuPTR, handle); | ||
534 | swayc_t *view = swayc_by_handle(handle); | ||
535 | |||
536 | // destroy views by type | ||
537 | switch (wlc_view_get_type(handle)) { | ||
538 | // regular view created regularly | ||
539 | case 0: | ||
540 | case WLC_BIT_MODAL: | ||
541 | case WLC_BIT_POPUP: | ||
542 | break; | ||
543 | // DMENU has this flag, and takes view_focus, but other things with this | ||
544 | // flag don't | ||
545 | case WLC_BIT_OVERRIDE_REDIRECT: | ||
546 | break; | ||
547 | case WLC_BIT_OVERRIDE_REDIRECT|WLC_BIT_UNMANAGED: | ||
548 | locked_container_focus = false; | ||
549 | break; | ||
550 | } | ||
551 | |||
552 | if (view) { | ||
553 | bool fullscreen = swayc_is_fullscreen(view); | ||
554 | remove_view_from_scratchpad(view); | ||
555 | swayc_t *parent = destroy_view(view), *iter = NULL; | ||
556 | if (parent) { | ||
557 | ipc_event_window(parent, "close"); | ||
558 | |||
559 | // Destroy empty workspaces | ||
560 | if (parent->type == C_WORKSPACE && | ||
561 | parent->children->length == 0 && | ||
562 | parent->floating->length == 0 && | ||
563 | swayc_active_workspace() != parent && | ||
564 | !parent->visible) { | ||
565 | parent = destroy_workspace(parent); | ||
566 | } | ||
567 | |||
568 | if (fullscreen) { | ||
569 | iter = parent; | ||
570 | while (iter) { | ||
571 | if (iter->fullscreen) { | ||
572 | iter->fullscreen = NULL; | ||
573 | break; | ||
574 | } | ||
575 | iter = iter->parent; | ||
576 | } | ||
577 | } | ||
578 | |||
579 | |||
580 | arrange_windows(iter ? iter : parent, -1, -1); | ||
581 | } | ||
582 | } else { | ||
583 | // Is it unmanaged? | ||
584 | int i; | ||
585 | for (i = 0; i < root_container.children->length; ++i) { | ||
586 | swayc_t *output = root_container.children->items[i]; | ||
587 | int j; | ||
588 | for (j = 0; j < output->unmanaged->length; ++j) { | ||
589 | wlc_handle *_handle = output->unmanaged->items[j]; | ||
590 | if (*_handle == handle) { | ||
591 | list_del(output->unmanaged, j); | ||
592 | free(_handle); | ||
593 | break; | ||
594 | } | ||
595 | } | ||
596 | } | ||
597 | // Is it in the scratchpad? | ||
598 | for (i = 0; i < scratchpad->length; ++i) { | ||
599 | swayc_t *item = scratchpad->items[i]; | ||
600 | if (item->handle == handle) { | ||
601 | list_del(scratchpad, i); | ||
602 | destroy_view(item); | ||
603 | break; | ||
604 | } | ||
605 | } | ||
606 | } | ||
607 | set_focused_container(get_focused_view(&root_container)); | ||
608 | } | ||
609 | |||
610 | static void handle_view_focus(wlc_handle view, bool focus) { | ||
611 | return; | ||
612 | } | ||
613 | |||
614 | static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geometry *geometry) { | ||
615 | sway_log(L_DEBUG, "geometry request for %" PRIuPTR " %dx%d @ %d,%d", handle, | ||
616 | geometry->size.w, geometry->size.h, geometry->origin.x, geometry->origin.y); | ||
617 | // If the view is floating, then apply the geometry. | ||
618 | // Otherwise save the desired width/height for the view. | ||
619 | // This will not do anything for the time being as WLC improperly sends geometry requests | ||
620 | swayc_t *view = swayc_by_handle(handle); | ||
621 | if (view) { | ||
622 | view->desired_width = geometry->size.w; | ||
623 | view->desired_height = geometry->size.h; | ||
624 | |||
625 | if (view->is_floating) { | ||
626 | floating_view_sane_size(view); | ||
627 | view->width = view->desired_width; | ||
628 | view->height = view->desired_height; | ||
629 | view->x = geometry->origin.x; | ||
630 | view->y = geometry->origin.y; | ||
631 | update_geometry(view); | ||
632 | } | ||
633 | } else { | ||
634 | wlc_view_set_geometry(handle, 0, geometry); | ||
635 | } | ||
636 | } | ||
637 | |||
638 | static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) { | ||
639 | swayc_t *c = swayc_by_handle(view); | ||
640 | pid_t pid = wlc_view_get_pid(view); | ||
641 | switch (state) { | ||
642 | case WLC_BIT_FULLSCREEN: | ||
643 | if (!(get_feature_policy_mask(pid) & FEATURE_FULLSCREEN)) { | ||
644 | sway_log(L_INFO, "Denying fullscreen to %d (%s)", pid, c->name); | ||
645 | break; | ||
646 | } | ||
647 | // i3 just lets it become fullscreen | ||
648 | wlc_view_set_state(view, state, toggle); | ||
649 | if (c) { | ||
650 | sway_log(L_DEBUG, "setting view %" PRIuPTR " %s, fullscreen %d", view, c->name, toggle); | ||
651 | arrange_windows(c->parent, -1, -1); | ||
652 | // Set it as focused window for that workspace if its going fullscreen | ||
653 | swayc_t *ws = swayc_parent_by_type(c, C_WORKSPACE); | ||
654 | if (toggle) { | ||
655 | // Set ws focus to c | ||
656 | set_focused_container_for(ws, c); | ||
657 | ws->fullscreen = c; | ||
658 | } else { | ||
659 | ws->fullscreen = NULL; | ||
660 | } | ||
661 | } | ||
662 | break; | ||
663 | case WLC_BIT_MAXIMIZED: | ||
664 | case WLC_BIT_RESIZING: | ||
665 | case WLC_BIT_MOVING: | ||
666 | break; | ||
667 | case WLC_BIT_ACTIVATED: | ||
668 | sway_log(L_DEBUG, "View %p requested to be activated", c); | ||
669 | break; | ||
670 | } | ||
671 | return; | ||
672 | } | ||
673 | |||
674 | static void handle_view_properties_updated(wlc_handle view, uint32_t mask) { | ||
675 | if (mask == WLC_BIT_PROPERTY_TITLE) { | ||
676 | swayc_t *c = swayc_by_handle(view); | ||
677 | if (!c) { | ||
678 | return; | ||
679 | } | ||
680 | |||
681 | // update window title | ||
682 | const char *new_name = wlc_view_get_title(view); | ||
683 | |||
684 | if (new_name) { | ||
685 | if (!c->name || strcmp(c->name, new_name) != 0) { | ||
686 | free(c->name); | ||
687 | c->name = strdup(new_name); | ||
688 | swayc_t *p = swayc_tabbed_stacked_ancestor(c); | ||
689 | if (p) { | ||
690 | // TODO: we only got the topmost tabbed/stacked container, update borders of all containers on the path | ||
691 | update_container_border(get_focused_view(p)); | ||
692 | } else if (c->border_type == B_NORMAL) { | ||
693 | update_container_border(c); | ||
694 | } | ||
695 | ipc_event_window(c, "title"); | ||
696 | } | ||
697 | } | ||
698 | } | ||
699 | } | ||
700 | |||
701 | static void handle_binding_command(struct sway_binding *binding) { | ||
702 | struct sway_binding *binding_copy = binding; | ||
703 | bool reload = false; | ||
704 | // if this is a reload command we need to make a duplicate of the | ||
705 | // binding since it will be gone after the reload has completed. | ||
706 | if (strcasecmp(binding->command, "reload") == 0) { | ||
707 | binding_copy = sway_binding_dup(binding); | ||
708 | if (!binding_copy) { | ||
709 | sway_log(L_ERROR, "Unable to duplicate binding during reload"); | ||
710 | return; | ||
711 | } | ||
712 | reload = true; | ||
713 | } | ||
714 | |||
715 | struct cmd_results *res = handle_command(binding->command, CONTEXT_BINDING); | ||
716 | if (res->status != CMD_SUCCESS) { | ||
717 | sway_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error); | ||
718 | } | ||
719 | ipc_event_binding_keyboard(binding_copy); | ||
720 | |||
721 | if (reload) { // free the binding if we made a copy | ||
722 | free_sway_binding(binding_copy); | ||
723 | } | ||
724 | |||
725 | free_cmd_results(res); | ||
726 | } | ||
727 | |||
728 | static bool handle_bindsym(struct sway_binding *binding, uint32_t keysym, uint32_t keycode) { | ||
729 | int i; | ||
730 | for (i = 0; i < binding->keys->length; ++i) { | ||
731 | if (binding->bindcode) { | ||
732 | xkb_keycode_t *key = binding->keys->items[i]; | ||
733 | if (keycode == *key) { | ||
734 | handle_binding_command(binding); | ||
735 | return true; | ||
736 | } | ||
737 | } else { | ||
738 | xkb_keysym_t *key = binding->keys->items[i]; | ||
739 | if (keysym == *key) { | ||
740 | handle_binding_command(binding); | ||
741 | return true; | ||
742 | } | ||
743 | } | ||
744 | } | ||
745 | |||
746 | return false; | ||
747 | } | ||
748 | |||
749 | static bool valid_bindsym(struct sway_binding *binding) { | ||
750 | bool match = false; | ||
751 | int i; | ||
752 | for (i = 0; i < binding->keys->length; ++i) { | ||
753 | if (binding->bindcode) { | ||
754 | xkb_keycode_t *key = binding->keys->items[i]; | ||
755 | if ((match = check_key(0, *key)) == false) { | ||
756 | break; | ||
757 | } | ||
758 | } else { | ||
759 | xkb_keysym_t *key = binding->keys->items[i]; | ||
760 | if ((match = check_key(*key, 0)) == false) { | ||
761 | break; | ||
762 | } | ||
763 | } | ||
764 | } | ||
765 | |||
766 | return match; | ||
767 | } | ||
768 | |||
769 | static bool handle_bindsym_release(struct sway_binding *binding) { | ||
770 | if (binding->keys->length == 1) { | ||
771 | xkb_keysym_t *key = binding->keys->items[0]; | ||
772 | if (check_released_key(*key)) { | ||
773 | handle_binding_command(binding); | ||
774 | return true; | ||
775 | } | ||
776 | } | ||
777 | |||
778 | return false; | ||
779 | } | ||
780 | |||
781 | static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, | ||
782 | uint32_t key, enum wlc_key_state state) { | ||
783 | |||
784 | if (desktop_shell.is_locked) { | ||
785 | return EVENT_PASSTHROUGH; | ||
786 | } | ||
787 | |||
788 | // reset pointer mode on keypress | ||
789 | if (state == WLC_KEY_STATE_PRESSED && pointer_state.mode) { | ||
790 | pointer_mode_reset(); | ||
791 | } | ||
792 | |||
793 | struct sway_mode *mode = config->current_mode; | ||
794 | |||
795 | struct wlc_modifiers no_mods = { 0, 0 }; | ||
796 | uint32_t sym = tolower(wlc_keyboard_get_keysym_for_key(key, &no_mods)); | ||
797 | |||
798 | int i; | ||
799 | |||
800 | if (state == WLC_KEY_STATE_PRESSED) { | ||
801 | press_key(sym, key); | ||
802 | } else { // WLC_KEY_STATE_RELEASED | ||
803 | release_key(sym, key); | ||
804 | } | ||
805 | |||
806 | // handle bar modifiers pressed/released | ||
807 | uint32_t modifier; | ||
808 | for (i = 0; i < config->active_bar_modifiers->length; ++i) { | ||
809 | modifier = *(uint32_t *)config->active_bar_modifiers->items[i]; | ||
810 | |||
811 | switch (modifier_state_changed(modifiers->mods, modifier)) { | ||
812 | case MOD_STATE_PRESSED: | ||
813 | ipc_event_modifier(modifier, "pressed"); | ||
814 | break; | ||
815 | case MOD_STATE_RELEASED: | ||
816 | ipc_event_modifier(modifier, "released"); | ||
817 | break; | ||
818 | } | ||
819 | } | ||
820 | // update modifiers state | ||
821 | modifiers_state_update(modifiers->mods); | ||
822 | |||
823 | // handle bindings | ||
824 | list_t *candidates = create_list(); | ||
825 | for (i = 0; i < mode->bindings->length; ++i) { | ||
826 | struct sway_binding *binding = mode->bindings->items[i]; | ||
827 | if ((modifiers->mods ^ binding->modifiers) == 0) { | ||
828 | switch (state) { | ||
829 | case WLC_KEY_STATE_PRESSED: | ||
830 | if (!binding->release && valid_bindsym(binding)) { | ||
831 | list_add(candidates, binding); | ||
832 | } | ||
833 | break; | ||
834 | case WLC_KEY_STATE_RELEASED: | ||
835 | if (binding->release && handle_bindsym_release(binding)) { | ||
836 | list_free(candidates); | ||
837 | return EVENT_HANDLED; | ||
838 | } | ||
839 | break; | ||
840 | } | ||
841 | } | ||
842 | } | ||
843 | |||
844 | for (i = 0; i < candidates->length; ++i) { | ||
845 | struct sway_binding *binding = candidates->items[i]; | ||
846 | if (state == WLC_KEY_STATE_PRESSED) { | ||
847 | if (!binding->release && handle_bindsym(binding, sym, key)) { | ||
848 | list_free(candidates); | ||
849 | return EVENT_HANDLED; | ||
850 | } | ||
851 | } | ||
852 | } | ||
853 | |||
854 | list_free(candidates); | ||
855 | |||
856 | swayc_t *focused = get_focused_container(&root_container); | ||
857 | if (focused->type == C_VIEW) { | ||
858 | pid_t pid = wlc_view_get_pid(focused->handle); | ||
859 | if (!(get_feature_policy_mask(pid) & FEATURE_KEYBOARD)) { | ||
860 | return EVENT_HANDLED; | ||
861 | } | ||
862 | } | ||
863 | return EVENT_PASSTHROUGH; | ||
864 | } | ||
865 | |||
866 | static bool handle_pointer_motion(wlc_handle handle, uint32_t time, double x, double y) { | ||
867 | if (desktop_shell.is_locked) { | ||
868 | return EVENT_PASSTHROUGH; | ||
869 | } | ||
870 | |||
871 | double new_x = x; | ||
872 | double new_y = y; | ||
873 | // Switch to adjacent output if touching output edge. | ||
874 | // | ||
875 | // Since this doesn't currently support moving windows between outputs we | ||
876 | // don't do the switch if the pointer is in a mode. | ||
877 | if (config->seamless_mouse && !pointer_state.mode && | ||
878 | !pointer_state.left.held && !pointer_state.right.held && !pointer_state.scroll.held) { | ||
879 | |||
880 | swayc_t *output = swayc_active_output(), *adjacent = NULL; | ||
881 | struct wlc_point abs_pos = { .x = x + output->x, .y = y + output->y }; | ||
882 | if (x <= 0) { // Left edge | ||
883 | if ((adjacent = swayc_adjacent_output(output, MOVE_LEFT, &abs_pos, false))) { | ||
884 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { | ||
885 | new_x = adjacent->width; | ||
886 | // adjust for differently aligned outputs (well, this is | ||
887 | // only correct when the two outputs have the same | ||
888 | // resolution or the same dpi I guess, it should take | ||
889 | // physical attributes into account) | ||
890 | new_y += (output->y - adjacent->y); | ||
891 | } | ||
892 | } | ||
893 | } else if (x >= output->width) { // Right edge | ||
894 | if ((adjacent = swayc_adjacent_output(output, MOVE_RIGHT, &abs_pos, false))) { | ||
895 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { | ||
896 | new_x = 0; | ||
897 | new_y += (output->y - adjacent->y); | ||
898 | } | ||
899 | } | ||
900 | } else if (y <= 0) { // Top edge | ||
901 | if ((adjacent = swayc_adjacent_output(output, MOVE_UP, &abs_pos, false))) { | ||
902 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { | ||
903 | new_y = adjacent->height; | ||
904 | new_x += (output->x - adjacent->x); | ||
905 | } | ||
906 | } | ||
907 | } else if (y >= output->height) { // Bottom edge | ||
908 | if ((adjacent = swayc_adjacent_output(output, MOVE_DOWN, &abs_pos, false))) { | ||
909 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { | ||
910 | new_y = 0; | ||
911 | new_x += (output->x - adjacent->x); | ||
912 | } | ||
913 | } | ||
914 | } | ||
915 | } | ||
916 | |||
917 | pointer_position_set(new_x, new_y, false); | ||
918 | |||
919 | swayc_t *focused = get_focused_container(&root_container); | ||
920 | if (focused->type == C_VIEW) { | ||
921 | pid_t pid = wlc_view_get_pid(focused->handle); | ||
922 | if (!(get_feature_policy_mask(pid) & FEATURE_MOUSE)) { | ||
923 | return EVENT_HANDLED; | ||
924 | } | ||
925 | } | ||
926 | |||
927 | return EVENT_PASSTHROUGH; | ||
928 | } | ||
929 | |||
930 | static bool swayc_border_check(swayc_t *c, const void *_origin) { | ||
931 | const struct wlc_point *origin = _origin; | ||
932 | const struct wlc_geometry title_bar = c->title_bar_geometry; | ||
933 | |||
934 | if (c->border_type != B_NORMAL) { | ||
935 | return false; | ||
936 | } | ||
937 | |||
938 | if (origin->x >= title_bar.origin.x && origin->y >= title_bar.origin.y | ||
939 | && origin->x < title_bar.origin.x + (int32_t)title_bar.size.w | ||
940 | && origin->y < title_bar.origin.y + (int32_t)title_bar.size.h) { | ||
941 | return true; | ||
942 | } | ||
943 | return false; | ||
944 | } | ||
945 | |||
946 | static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers, | ||
947 | uint32_t button, enum wlc_button_state state, const struct wlc_point *origin) { | ||
948 | |||
949 | // Update view pointer is on | ||
950 | pointer_state.view = container_under_pointer(); | ||
951 | |||
952 | struct sway_mode *mode = config->current_mode; | ||
953 | // handle bindings | ||
954 | for (int i = 0; i < mode->bindings->length; ++i) { | ||
955 | struct sway_binding *binding = mode->bindings->items[i]; | ||
956 | if ((modifiers->mods ^ binding->modifiers) == 0) { | ||
957 | switch (state) { | ||
958 | case WLC_BUTTON_STATE_PRESSED: | ||
959 | if (!binding->release && handle_bindsym(binding, button, 0)) { | ||
960 | return EVENT_HANDLED; | ||
961 | } | ||
962 | break; | ||
963 | case WLC_BUTTON_STATE_RELEASED: | ||
964 | if (binding->release && handle_bindsym(binding, button, 0)) { | ||
965 | return EVENT_HANDLED; | ||
966 | } | ||
967 | break; | ||
968 | } | ||
969 | } | ||
970 | } | ||
971 | |||
972 | // Update pointer_state | ||
973 | switch (button) { | ||
974 | case M_LEFT_CLICK: | ||
975 | if (state == WLC_BUTTON_STATE_PRESSED) { | ||
976 | pointer_state.left.held = true; | ||
977 | pointer_state.left.x = origin->x; | ||
978 | pointer_state.left.y = origin->y; | ||
979 | pointer_state.left.view = pointer_state.view; | ||
980 | } else { | ||
981 | pointer_state.left.held = false; | ||
982 | } | ||
983 | break; | ||
984 | |||
985 | case M_RIGHT_CLICK: | ||
986 | if (state == WLC_BUTTON_STATE_PRESSED) { | ||
987 | pointer_state.right.held = true; | ||
988 | pointer_state.right.x = origin->x; | ||
989 | pointer_state.right.y = origin->y; | ||
990 | pointer_state.right.view = pointer_state.view; | ||
991 | } else { | ||
992 | pointer_state.right.held = false; | ||
993 | } | ||
994 | break; | ||
995 | |||
996 | case M_SCROLL_CLICK: | ||
997 | if (state == WLC_BUTTON_STATE_PRESSED) { | ||
998 | pointer_state.scroll.held = true; | ||
999 | pointer_state.scroll.x = origin->x; | ||
1000 | pointer_state.scroll.y = origin->y; | ||
1001 | pointer_state.scroll.view = pointer_state.view; | ||
1002 | } else { | ||
1003 | pointer_state.scroll.held = false; | ||
1004 | } | ||
1005 | break; | ||
1006 | |||
1007 | //TODO scrolling behavior | ||
1008 | case M_SCROLL_UP: | ||
1009 | case M_SCROLL_DOWN: | ||
1010 | break; | ||
1011 | } | ||
1012 | |||
1013 | // get focused window and check if to change focus on mouse click | ||
1014 | swayc_t *focused = get_focused_container(&root_container); | ||
1015 | |||
1016 | // don't change focus or mode if fullscreen | ||
1017 | if (swayc_is_fullscreen(focused)) { | ||
1018 | if (focused->type == C_VIEW) { | ||
1019 | pid_t pid = wlc_view_get_pid(focused->handle); | ||
1020 | if (!(get_feature_policy_mask(pid) & FEATURE_MOUSE)) { | ||
1021 | return EVENT_HANDLED; | ||
1022 | } | ||
1023 | } | ||
1024 | return EVENT_PASSTHROUGH; | ||
1025 | } | ||
1026 | |||
1027 | // set pointer mode only if floating mod has been set | ||
1028 | if (config->floating_mod) { | ||
1029 | pointer_mode_set(button, !(modifiers->mods ^ config->floating_mod)); | ||
1030 | } | ||
1031 | |||
1032 | // Check whether to change focus | ||
1033 | swayc_t *pointer = pointer_state.view; | ||
1034 | if (pointer) { | ||
1035 | swayc_t *ws = swayc_parent_by_type(focused, C_WORKSPACE); | ||
1036 | if (ws != NULL) { | ||
1037 | swayc_t *find = container_find(ws, &swayc_border_check, origin); | ||
1038 | if (find != NULL) { | ||
1039 | set_focused_container(find); | ||
1040 | return EVENT_HANDLED; | ||
1041 | } | ||
1042 | } | ||
1043 | |||
1044 | if (focused != pointer) { | ||
1045 | set_focused_container(pointer_state.view); | ||
1046 | } | ||
1047 | // Send to front if floating | ||
1048 | if (pointer->is_floating) { | ||
1049 | int i; | ||
1050 | for (i = 0; i < pointer->parent->floating->length; i++) { | ||
1051 | if (pointer->parent->floating->items[i] == pointer) { | ||
1052 | list_del(pointer->parent->floating, i); | ||
1053 | list_add(pointer->parent->floating, pointer); | ||
1054 | break; | ||
1055 | } | ||
1056 | } | ||
1057 | wlc_view_bring_to_front(pointer->handle); | ||
1058 | } | ||
1059 | } | ||
1060 | |||
1061 | // Return if mode has been set | ||
1062 | if (pointer_state.mode) { | ||
1063 | return EVENT_HANDLED; | ||
1064 | } | ||
1065 | |||
1066 | if (focused->type == C_VIEW) { | ||
1067 | pid_t pid = wlc_view_get_pid(focused->handle); | ||
1068 | if (!(get_feature_policy_mask(pid) & FEATURE_MOUSE)) { | ||
1069 | return EVENT_HANDLED; | ||
1070 | } | ||
1071 | } | ||
1072 | |||
1073 | // Always send mouse release | ||
1074 | if (state == WLC_BUTTON_STATE_RELEASED) { | ||
1075 | return EVENT_PASSTHROUGH; | ||
1076 | } | ||
1077 | |||
1078 | // Finally send click | ||
1079 | return EVENT_PASSTHROUGH; | ||
1080 | } | ||
1081 | |||
1082 | bool handle_pointer_scroll(wlc_handle view, uint32_t time, const struct wlc_modifiers* modifiers, | ||
1083 | uint8_t axis_bits, double _amount[2]) { | ||
1084 | if (!(modifiers->mods ^ config->floating_mod)) { | ||
1085 | int x_amount = (int)_amount[0]; | ||
1086 | int y_amount = (int)_amount[1]; | ||
1087 | |||
1088 | if (x_amount > 0 && strcmp(config->floating_scroll_up_cmd, "")) { | ||
1089 | handle_command(config->floating_scroll_up_cmd, CONTEXT_BINDING); | ||
1090 | return EVENT_HANDLED; | ||
1091 | } else if (x_amount < 0 && strcmp(config->floating_scroll_down_cmd, "")) { | ||
1092 | handle_command(config->floating_scroll_down_cmd, CONTEXT_BINDING); | ||
1093 | return EVENT_HANDLED; | ||
1094 | } | ||
1095 | |||
1096 | if (y_amount > 0 && strcmp(config->floating_scroll_right_cmd, "")) { | ||
1097 | handle_command(config->floating_scroll_right_cmd, CONTEXT_BINDING); | ||
1098 | return EVENT_HANDLED; | ||
1099 | } else if (y_amount < 0 && strcmp(config->floating_scroll_left_cmd, "")) { | ||
1100 | handle_command(config->floating_scroll_left_cmd, CONTEXT_BINDING); | ||
1101 | return EVENT_HANDLED; | ||
1102 | } | ||
1103 | } | ||
1104 | return EVENT_PASSTHROUGH; | ||
1105 | } | ||
1106 | |||
1107 | static void handle_wlc_ready(void) { | ||
1108 | sway_log(L_DEBUG, "Compositor is ready, executing cmds in queue"); | ||
1109 | // Execute commands until there are none left | ||
1110 | config->active = true; | ||
1111 | while (config->cmd_queue->length) { | ||
1112 | char *line = config->cmd_queue->items[0]; | ||
1113 | struct cmd_results *res = handle_command(line, CONTEXT_CONFIG); | ||
1114 | if (res->status != CMD_SUCCESS) { | ||
1115 | sway_log(L_ERROR, "Error on line '%s': %s", line, res->error); | ||
1116 | } | ||
1117 | free_cmd_results(res); | ||
1118 | free(line); | ||
1119 | list_del(config->cmd_queue, 0); | ||
1120 | } | ||
1121 | } | ||
1122 | |||
1123 | void register_wlc_handlers() { | ||
1124 | wlc_set_output_created_cb(handle_output_created); | ||
1125 | wlc_set_output_destroyed_cb(handle_output_destroyed); | ||
1126 | wlc_set_output_resolution_cb(handle_output_resolution_change); | ||
1127 | wlc_set_output_focus_cb(handle_output_focused); | ||
1128 | wlc_set_output_render_post_cb(handle_output_post_render); | ||
1129 | wlc_set_view_created_cb(handle_view_created); | ||
1130 | wlc_set_view_destroyed_cb(handle_view_destroyed); | ||
1131 | wlc_set_view_focus_cb(handle_view_focus); | ||
1132 | wlc_set_view_render_pre_cb(handle_view_pre_render); | ||
1133 | wlc_set_view_request_geometry_cb(handle_view_geometry_request); | ||
1134 | wlc_set_view_request_state_cb(handle_view_state_request); | ||
1135 | wlc_set_view_properties_updated_cb(handle_view_properties_updated); | ||
1136 | wlc_set_keyboard_key_cb(handle_key); | ||
1137 | wlc_set_pointer_motion_cb_v2(handle_pointer_motion); | ||
1138 | wlc_set_pointer_button_cb(handle_pointer_button); | ||
1139 | wlc_set_pointer_scroll_cb(handle_pointer_scroll); | ||
1140 | wlc_set_compositor_ready_cb(handle_wlc_ready); | ||
1141 | wlc_set_input_created_cb(handle_input_created); | ||
1142 | wlc_set_input_destroyed_cb(handle_input_destroyed); | ||
1143 | } | ||