diff options
author | Drew DeVault <sir@cmpwn.com> | 2019-07-05 14:45:11 -0400 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2019-08-20 14:53:22 +0900 |
commit | d6846ad3afc4a77efe79443e939bb3a79708790c (patch) | |
tree | aa3bca5254017567d58eaa77cd2c3b872439dfdc | |
parent | properly check pixman_region32_contains_rectangle return (diff) | |
download | sway-62a88d5c93e1ece190867493abd7561264f03a3f.tar.gz sway-62a88d5c93e1ece190867493abd7561264f03a3f.tar.zst sway-62a88d5c93e1ece190867493abd7561264f03a3f.zip |
layer-shell: add support for popups1.2-rc2
-rw-r--r-- | include/sway/layers.h | 20 | ||||
-rw-r--r-- | sway/desktop/layer_shell.c | 130 | ||||
-rw-r--r-- | sway/desktop/output.c | 30 | ||||
-rw-r--r-- | sway/input/cursor.c | 11 |
4 files changed, 182 insertions, 9 deletions
diff --git a/include/sway/layers.h b/include/sway/layers.h index 51878fc9..01d066d5 100644 --- a/include/sway/layers.h +++ b/include/sway/layers.h | |||
@@ -5,6 +5,11 @@ | |||
5 | #include <wlr/types/wlr_surface.h> | 5 | #include <wlr/types/wlr_surface.h> |
6 | #include <wlr/types/wlr_layer_shell_v1.h> | 6 | #include <wlr/types/wlr_layer_shell_v1.h> |
7 | 7 | ||
8 | enum layer_parent { | ||
9 | LAYER_PARENT_LAYER, | ||
10 | LAYER_PARENT_POPUP, | ||
11 | }; | ||
12 | |||
8 | struct sway_layer_surface { | 13 | struct sway_layer_surface { |
9 | struct wlr_layer_surface_v1 *layer_surface; | 14 | struct wlr_layer_surface_v1 *layer_surface; |
10 | struct wl_list link; | 15 | struct wl_list link; |
@@ -14,11 +19,26 @@ struct sway_layer_surface { | |||
14 | struct wl_listener unmap; | 19 | struct wl_listener unmap; |
15 | struct wl_listener surface_commit; | 20 | struct wl_listener surface_commit; |
16 | struct wl_listener output_destroy; | 21 | struct wl_listener output_destroy; |
22 | struct wl_listener new_popup; | ||
17 | 23 | ||
18 | bool configured; | 24 | bool configured; |
19 | struct wlr_box geo; | 25 | struct wlr_box geo; |
20 | }; | 26 | }; |
21 | 27 | ||
28 | struct sway_layer_popup { | ||
29 | struct wlr_xdg_popup *wlr_popup; | ||
30 | enum layer_parent parent_type; | ||
31 | union { | ||
32 | struct sway_layer_surface *parent_layer; | ||
33 | struct sway_layer_popup *parent_popup; | ||
34 | }; | ||
35 | struct wl_listener map; | ||
36 | struct wl_listener unmap; | ||
37 | struct wl_listener destroy; | ||
38 | struct wl_listener commit; | ||
39 | struct wl_listener new_popup; | ||
40 | }; | ||
41 | |||
22 | struct sway_output; | 42 | struct sway_output; |
23 | void arrange_layers(struct sway_output *output); | 43 | void arrange_layers(struct sway_output *output); |
24 | 44 | ||
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 34ba5592..f1f79c1b 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c | |||
@@ -320,6 +320,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
320 | wl_list_remove(&sway_layer->map.link); | 320 | wl_list_remove(&sway_layer->map.link); |
321 | wl_list_remove(&sway_layer->unmap.link); | 321 | wl_list_remove(&sway_layer->unmap.link); |
322 | wl_list_remove(&sway_layer->surface_commit.link); | 322 | wl_list_remove(&sway_layer->surface_commit.link); |
323 | wl_list_remove(&sway_layer->new_popup.link); | ||
323 | if (sway_layer->layer_surface->output != NULL) { | 324 | if (sway_layer->layer_surface->output != NULL) { |
324 | struct sway_output *output = sway_layer->layer_surface->output->data; | 325 | struct sway_output *output = sway_layer->layer_surface->output->data; |
325 | if (output != NULL) { | 326 | if (output != NULL) { |
@@ -338,7 +339,6 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
338 | struct sway_output *output = sway_layer->layer_surface->output->data; | 339 | struct sway_output *output = sway_layer->layer_surface->output->data; |
339 | output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, | 340 | output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, |
340 | sway_layer->layer_surface->surface, true); | 341 | sway_layer->layer_surface->surface, true); |
341 | // TODO: send enter to subsurfaces and popups | ||
342 | wlr_surface_send_enter(sway_layer->layer_surface->surface, | 342 | wlr_surface_send_enter(sway_layer->layer_surface->surface, |
343 | sway_layer->layer_surface->output); | 343 | sway_layer->layer_surface->output); |
344 | cursor_rebase_all(); | 344 | cursor_rebase_all(); |
@@ -350,6 +350,131 @@ static void handle_unmap(struct wl_listener *listener, void *data) { | |||
350 | unmap(sway_layer); | 350 | unmap(sway_layer); |
351 | } | 351 | } |
352 | 352 | ||
353 | static struct sway_layer_surface *popup_get_layer( | ||
354 | struct sway_layer_popup *popup) { | ||
355 | while (popup->parent_type == LAYER_PARENT_POPUP) { | ||
356 | popup = popup->parent_popup; | ||
357 | } | ||
358 | return popup->parent_layer; | ||
359 | } | ||
360 | |||
361 | static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) { | ||
362 | struct wlr_xdg_popup *popup = layer_popup->wlr_popup; | ||
363 | struct wlr_surface *surface = popup->base->surface; | ||
364 | int popup_sx = popup->geometry.x - popup->base->geometry.x; | ||
365 | int popup_sy = popup->geometry.y - popup->base->geometry.y; | ||
366 | int ox = popup_sx, oy = popup_sy; | ||
367 | struct sway_layer_surface *layer; | ||
368 | while (true) { | ||
369 | if (layer_popup->parent_type == LAYER_PARENT_POPUP) { | ||
370 | layer_popup = layer_popup->parent_popup; | ||
371 | ox += layer_popup->wlr_popup->base->geometry.x + | ||
372 | layer_popup->wlr_popup->geometry.x; | ||
373 | oy += layer_popup->wlr_popup->base->geometry.y + | ||
374 | layer_popup->wlr_popup->geometry.y; | ||
375 | } else { | ||
376 | layer = layer_popup->parent_layer; | ||
377 | ox += layer->geo.x; | ||
378 | oy += layer->geo.y; | ||
379 | break; | ||
380 | } | ||
381 | } | ||
382 | struct wlr_output *wlr_output = layer->layer_surface->output; | ||
383 | struct sway_output *output = wlr_output->data; | ||
384 | output_damage_surface(output, ox, oy, surface, whole); | ||
385 | } | ||
386 | |||
387 | static void popup_handle_map(struct wl_listener *listener, void *data) { | ||
388 | struct sway_layer_popup *popup = wl_container_of(listener, popup, map); | ||
389 | struct sway_layer_surface *layer = popup_get_layer(popup); | ||
390 | struct wlr_output *wlr_output = layer->layer_surface->output; | ||
391 | wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output); | ||
392 | popup_damage(popup, true); | ||
393 | } | ||
394 | |||
395 | static void popup_handle_unmap(struct wl_listener *listener, void *data) { | ||
396 | struct sway_layer_popup *popup = wl_container_of(listener, popup, unmap); | ||
397 | popup_damage(popup, true); | ||
398 | } | ||
399 | |||
400 | static void popup_handle_commit(struct wl_listener *listener, void *data) { | ||
401 | struct sway_layer_popup *popup = wl_container_of(listener, popup, commit); | ||
402 | popup_damage(popup, false); | ||
403 | } | ||
404 | |||
405 | static void popup_handle_destroy(struct wl_listener *listener, void *data) { | ||
406 | struct sway_layer_popup *popup = | ||
407 | wl_container_of(listener, popup, destroy); | ||
408 | |||
409 | wl_list_remove(&popup->map.link); | ||
410 | wl_list_remove(&popup->unmap.link); | ||
411 | wl_list_remove(&popup->destroy.link); | ||
412 | wl_list_remove(&popup->commit.link); | ||
413 | free(popup); | ||
414 | } | ||
415 | |||
416 | static void popup_unconstrain(struct sway_layer_popup *popup) { | ||
417 | struct sway_layer_surface *layer = popup_get_layer(popup); | ||
418 | struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; | ||
419 | |||
420 | struct sway_output *output = layer->layer_surface->output->data; | ||
421 | |||
422 | // the output box expressed in the coordinate system of the toplevel parent | ||
423 | // of the popup | ||
424 | struct wlr_box output_toplevel_sx_box = { | ||
425 | .x = -layer->geo.x, | ||
426 | .y = -layer->geo.y, | ||
427 | .width = output->width, | ||
428 | .height = output->height, | ||
429 | }; | ||
430 | |||
431 | wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); | ||
432 | } | ||
433 | |||
434 | static void popup_handle_new_popup(struct wl_listener *listener, void *data); | ||
435 | |||
436 | static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup, | ||
437 | enum layer_parent parent_type, void *parent) { | ||
438 | struct sway_layer_popup *popup = | ||
439 | calloc(1, sizeof(struct sway_layer_popup)); | ||
440 | if (popup == NULL) { | ||
441 | return NULL; | ||
442 | } | ||
443 | |||
444 | popup->wlr_popup = wlr_popup; | ||
445 | popup->parent_type = parent_type; | ||
446 | popup->parent_layer = parent; | ||
447 | |||
448 | popup->map.notify = popup_handle_map; | ||
449 | wl_signal_add(&wlr_popup->base->events.map, &popup->map); | ||
450 | popup->unmap.notify = popup_handle_unmap; | ||
451 | wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap); | ||
452 | popup->destroy.notify = popup_handle_destroy; | ||
453 | wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); | ||
454 | popup->commit.notify = popup_handle_commit; | ||
455 | wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit); | ||
456 | popup->new_popup.notify = popup_handle_new_popup; | ||
457 | wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); | ||
458 | |||
459 | popup_unconstrain(popup); | ||
460 | |||
461 | return popup; | ||
462 | } | ||
463 | |||
464 | static void popup_handle_new_popup(struct wl_listener *listener, void *data) { | ||
465 | struct sway_layer_popup *sway_layer_popup = | ||
466 | wl_container_of(listener, sway_layer_popup, new_popup); | ||
467 | struct wlr_xdg_popup *wlr_popup = data; | ||
468 | create_popup(wlr_popup, LAYER_PARENT_POPUP, sway_layer_popup); | ||
469 | } | ||
470 | |||
471 | static void handle_new_popup(struct wl_listener *listener, void *data) { | ||
472 | struct sway_layer_surface *sway_layer_surface = | ||
473 | wl_container_of(listener, sway_layer_surface, new_popup); | ||
474 | struct wlr_xdg_popup *wlr_popup = data; | ||
475 | create_popup(wlr_popup, LAYER_PARENT_LAYER, sway_layer_surface); | ||
476 | } | ||
477 | |||
353 | struct sway_layer_surface *layer_from_wlr_layer_surface_v1( | 478 | struct sway_layer_surface *layer_from_wlr_layer_surface_v1( |
354 | struct wlr_layer_surface_v1 *layer_surface) { | 479 | struct wlr_layer_surface_v1 *layer_surface) { |
355 | return layer_surface->data; | 480 | return layer_surface->data; |
@@ -406,7 +531,8 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { | |||
406 | wl_signal_add(&layer_surface->events.map, &sway_layer->map); | 531 | wl_signal_add(&layer_surface->events.map, &sway_layer->map); |
407 | sway_layer->unmap.notify = handle_unmap; | 532 | sway_layer->unmap.notify = handle_unmap; |
408 | wl_signal_add(&layer_surface->events.unmap, &sway_layer->unmap); | 533 | wl_signal_add(&layer_surface->events.unmap, &sway_layer->unmap); |
409 | // TODO: Listen for subsurfaces | 534 | sway_layer->new_popup.notify = handle_new_popup; |
535 | wl_signal_add(&layer_surface->events.new_popup, &sway_layer->new_popup); | ||
410 | 536 | ||
411 | sway_layer->layer_surface = layer_surface; | 537 | sway_layer->layer_surface = layer_surface; |
412 | layer_surface->data = sway_layer; | 538 | layer_surface->data = sway_layer; |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index e7bdf677..4bfc3b77 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -204,6 +204,36 @@ void output_layer_for_each_surface(struct sway_output *output, | |||
204 | output_surface_for_each_surface(output, wlr_layer_surface_v1->surface, | 204 | output_surface_for_each_surface(output, wlr_layer_surface_v1->surface, |
205 | layer_surface->geo.x, layer_surface->geo.y, iterator, | 205 | layer_surface->geo.x, layer_surface->geo.y, iterator, |
206 | user_data); | 206 | user_data); |
207 | |||
208 | struct wlr_xdg_popup *state; | ||
209 | wl_list_for_each(state, &wlr_layer_surface_v1->popups, link) { | ||
210 | struct wlr_xdg_surface *popup = state->base; | ||
211 | if (!popup->configured) { | ||
212 | continue; | ||
213 | } | ||
214 | |||
215 | double popup_sx, popup_sy; | ||
216 | popup_sx = layer_surface->geo.x + | ||
217 | popup->popup->geometry.x - popup->geometry.x; | ||
218 | popup_sy = layer_surface->geo.y + | ||
219 | popup->popup->geometry.y - popup->geometry.y; | ||
220 | |||
221 | struct wlr_surface *surface = popup->surface; | ||
222 | |||
223 | struct surface_iterator_data data = { | ||
224 | .user_iterator = iterator, | ||
225 | .user_data = user_data, | ||
226 | .output = output, | ||
227 | .ox = popup_sx, | ||
228 | .oy = popup_sy, | ||
229 | .width = surface->current.width, | ||
230 | .height = surface->current.height, | ||
231 | .rotation = 0, | ||
232 | }; | ||
233 | |||
234 | wlr_xdg_surface_for_each_surface( | ||
235 | popup, output_for_each_surface_iterator, &data); | ||
236 | } | ||
207 | } | 237 | } |
208 | } | 238 | } |
209 | 239 | ||
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 5739aafb..c6a332b8 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -39,15 +39,12 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output, | |||
39 | struct wl_list *layer, double ox, double oy, double *sx, double *sy) { | 39 | struct wl_list *layer, double ox, double oy, double *sx, double *sy) { |
40 | struct sway_layer_surface *sway_layer; | 40 | struct sway_layer_surface *sway_layer; |
41 | wl_list_for_each_reverse(sway_layer, layer, link) { | 41 | wl_list_for_each_reverse(sway_layer, layer, link) { |
42 | struct wlr_surface *wlr_surface = | ||
43 | sway_layer->layer_surface->surface; | ||
44 | double _sx = ox - sway_layer->geo.x; | 42 | double _sx = ox - sway_layer->geo.x; |
45 | double _sy = oy - sway_layer->geo.y; | 43 | double _sy = oy - sway_layer->geo.y; |
46 | // TODO: Test popups/subsurfaces | 44 | struct wlr_surface *sub = wlr_layer_surface_v1_surface_at( |
47 | if (wlr_surface_point_accepts_input(wlr_surface, _sx, _sy)) { | 45 | sway_layer->layer_surface, _sx, _sy, sx, sy); |
48 | *sx = _sx; | 46 | if (sub) { |
49 | *sy = _sy; | 47 | return sub; |
50 | return wlr_surface; | ||
51 | } | 48 | } |
52 | } | 49 | } |
53 | return NULL; | 50 | return NULL; |