diff options
48 files changed, 1854 insertions, 1358 deletions
diff --git a/common/pango.c b/common/pango.c index 2ae7883c..658d2876 100644 --- a/common/pango.c +++ b/common/pango.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <stdio.h> | 6 | #include <stdio.h> |
7 | #include <stdlib.h> | 7 | #include <stdlib.h> |
8 | #include <string.h> | 8 | #include <string.h> |
9 | #include "log.h" | ||
9 | 10 | ||
10 | PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, | 11 | PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, |
11 | const char *text, int32_t scale, bool markup) { | 12 | const char *text, int32_t scale, bool markup) { |
@@ -13,7 +14,13 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, | |||
13 | PangoAttrList *attrs; | 14 | PangoAttrList *attrs; |
14 | if (markup) { | 15 | if (markup) { |
15 | char *buf; | 16 | char *buf; |
16 | pango_parse_markup(text, -1, 0, &attrs, &buf, NULL, NULL); | 17 | GError *error = NULL; |
18 | if (!sway_assert(pango_parse_markup( | ||
19 | text, -1, 0, &attrs, &buf, NULL, &error), | ||
20 | "pango_parse_markup '%s' -> error %s", text, | ||
21 | error ? error->message : NULL)) { | ||
22 | return NULL; | ||
23 | } | ||
17 | pango_layout_set_markup(layout, buf, -1); | 24 | pango_layout_set_markup(layout, buf, -1); |
18 | free(buf); | 25 | free(buf); |
19 | } else { | 26 | } else { |
diff --git a/include/sway/config.h b/include/sway/config.h index 03b51948..91f772b5 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -377,6 +377,7 @@ void free_config(struct sway_config *config); | |||
377 | void config_clear_handler_context(struct sway_config *config); | 377 | void config_clear_handler_context(struct sway_config *config); |
378 | 378 | ||
379 | void free_sway_variable(struct sway_variable *var); | 379 | void free_sway_variable(struct sway_variable *var); |
380 | |||
380 | /** | 381 | /** |
381 | * Does variable replacement for a string based on the config's currently loaded variables. | 382 | * Does variable replacement for a string based on the config's currently loaded variables. |
382 | */ | 383 | */ |
@@ -385,44 +386,68 @@ char *do_var_replacement(char *str); | |||
385 | struct cmd_results *check_security_config(); | 386 | struct cmd_results *check_security_config(); |
386 | 387 | ||
387 | int input_identifier_cmp(const void *item, const void *data); | 388 | int input_identifier_cmp(const void *item, const void *data); |
389 | |||
388 | struct input_config *new_input_config(const char* identifier); | 390 | struct input_config *new_input_config(const char* identifier); |
391 | |||
389 | void merge_input_config(struct input_config *dst, struct input_config *src); | 392 | void merge_input_config(struct input_config *dst, struct input_config *src); |
393 | |||
390 | struct input_config *copy_input_config(struct input_config *ic); | 394 | struct input_config *copy_input_config(struct input_config *ic); |
395 | |||
391 | void free_input_config(struct input_config *ic); | 396 | void free_input_config(struct input_config *ic); |
397 | |||
392 | void apply_input_config(struct input_config *input); | 398 | void apply_input_config(struct input_config *input); |
393 | 399 | ||
394 | int seat_name_cmp(const void *item, const void *data); | 400 | int seat_name_cmp(const void *item, const void *data); |
401 | |||
395 | struct seat_config *new_seat_config(const char* name); | 402 | struct seat_config *new_seat_config(const char* name); |
403 | |||
396 | void merge_seat_config(struct seat_config *dst, struct seat_config *src); | 404 | void merge_seat_config(struct seat_config *dst, struct seat_config *src); |
405 | |||
397 | struct seat_config *copy_seat_config(struct seat_config *seat); | 406 | struct seat_config *copy_seat_config(struct seat_config *seat); |
407 | |||
398 | void free_seat_config(struct seat_config *ic); | 408 | void free_seat_config(struct seat_config *ic); |
409 | |||
399 | struct seat_attachment_config *seat_attachment_config_new(); | 410 | struct seat_attachment_config *seat_attachment_config_new(); |
411 | |||
400 | struct seat_attachment_config *seat_config_get_attachment( | 412 | struct seat_attachment_config *seat_config_get_attachment( |
401 | struct seat_config *seat_config, char *identifier); | 413 | struct seat_config *seat_config, char *identifier); |
414 | |||
402 | void apply_seat_config(struct seat_config *seat); | 415 | void apply_seat_config(struct seat_config *seat); |
403 | 416 | ||
404 | int output_name_cmp(const void *item, const void *data); | 417 | int output_name_cmp(const void *item, const void *data); |
418 | |||
405 | void output_get_identifier(char *identifier, size_t len, | 419 | void output_get_identifier(char *identifier, size_t len, |
406 | struct sway_output *output); | 420 | struct sway_output *output); |
421 | |||
407 | struct output_config *new_output_config(const char *name); | 422 | struct output_config *new_output_config(const char *name); |
423 | |||
408 | void merge_output_config(struct output_config *dst, struct output_config *src); | 424 | void merge_output_config(struct output_config *dst, struct output_config *src); |
425 | |||
409 | void apply_output_config(struct output_config *oc, | 426 | void apply_output_config(struct output_config *oc, |
410 | struct sway_container *output); | 427 | struct sway_container *output); |
428 | |||
411 | void free_output_config(struct output_config *oc); | 429 | void free_output_config(struct output_config *oc); |
412 | 430 | ||
413 | int workspace_output_cmp_workspace(const void *a, const void *b); | 431 | int workspace_output_cmp_workspace(const void *a, const void *b); |
414 | 432 | ||
415 | int sway_binding_cmp(const void *a, const void *b); | 433 | int sway_binding_cmp(const void *a, const void *b); |
434 | |||
416 | int sway_binding_cmp_qsort(const void *a, const void *b); | 435 | int sway_binding_cmp_qsort(const void *a, const void *b); |
436 | |||
417 | int sway_binding_cmp_keys(const void *a, const void *b); | 437 | int sway_binding_cmp_keys(const void *a, const void *b); |
438 | |||
418 | void free_sway_binding(struct sway_binding *sb); | 439 | void free_sway_binding(struct sway_binding *sb); |
440 | |||
419 | struct sway_binding *sway_binding_dup(struct sway_binding *sb); | 441 | struct sway_binding *sway_binding_dup(struct sway_binding *sb); |
420 | 442 | ||
421 | /* Bar stuff */ | ||
422 | void load_swaybars(); | 443 | void load_swaybars(); |
444 | |||
423 | void invoke_swaybar(struct bar_config *bar); | 445 | void invoke_swaybar(struct bar_config *bar); |
446 | |||
424 | void terminate_swaybg(pid_t pid); | 447 | void terminate_swaybg(pid_t pid); |
448 | |||
425 | struct bar_config *default_bar_config(void); | 449 | struct bar_config *default_bar_config(void); |
450 | |||
426 | void free_bar_config(struct bar_config *bar); | 451 | void free_bar_config(struct bar_config *bar); |
427 | 452 | ||
428 | /* Global config singleton. */ | 453 | /* Global config singleton. */ |
diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index c6c73dba..8e39a4a7 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h | |||
@@ -14,7 +14,6 @@ extern struct sway_input_manager *input_manager; | |||
14 | struct sway_input_device { | 14 | struct sway_input_device { |
15 | char *identifier; | 15 | char *identifier; |
16 | struct wlr_input_device *wlr_device; | 16 | struct wlr_input_device *wlr_device; |
17 | struct input_config *config; | ||
18 | struct wl_list link; | 17 | struct wl_list link; |
19 | struct wl_listener device_destroy; | 18 | struct wl_listener device_destroy; |
20 | }; | 19 | }; |
@@ -27,30 +26,34 @@ struct sway_input_manager { | |||
27 | struct wl_listener new_input; | 26 | struct wl_listener new_input; |
28 | }; | 27 | }; |
29 | 28 | ||
30 | struct sway_input_manager *sway_input_manager_create( | 29 | struct sway_input_manager *input_manager_create(struct sway_server *server); |
31 | struct sway_server *server); | ||
32 | 30 | ||
33 | bool sway_input_manager_has_focus(struct sway_input_manager *input, | 31 | bool input_manager_has_focus(struct sway_input_manager *input, |
34 | struct sway_container *container); | 32 | struct sway_container *container); |
35 | 33 | ||
36 | void sway_input_manager_set_focus(struct sway_input_manager *input, | 34 | void input_manager_set_focus(struct sway_input_manager *input, |
37 | struct sway_container *container); | 35 | struct sway_container *container); |
38 | 36 | ||
39 | void sway_input_manager_configure_xcursor(struct sway_input_manager *input); | 37 | void input_manager_configure_xcursor(struct sway_input_manager *input); |
40 | 38 | ||
41 | void sway_input_manager_apply_input_config(struct sway_input_manager *input, | 39 | void input_manager_apply_input_config(struct sway_input_manager *input, |
42 | struct input_config *input_config); | 40 | struct input_config *input_config); |
43 | 41 | ||
44 | void sway_input_manager_apply_seat_config(struct sway_input_manager *input, | 42 | void input_manager_apply_seat_config(struct sway_input_manager *input, |
45 | struct seat_config *seat_config); | 43 | struct seat_config *seat_config); |
46 | 44 | ||
47 | struct sway_seat *sway_input_manager_get_default_seat( | 45 | struct sway_seat *input_manager_get_default_seat( |
48 | struct sway_input_manager *input); | 46 | struct sway_input_manager *input); |
49 | 47 | ||
50 | struct sway_seat *input_manager_get_seat(struct sway_input_manager *input, | 48 | struct sway_seat *input_manager_get_seat(struct sway_input_manager *input, |
51 | const char *seat_name); | 49 | const char *seat_name); |
52 | 50 | ||
53 | /** Gets the last seat the user interacted with */ | 51 | /** |
52 | * Gets the last seat the user interacted with | ||
53 | */ | ||
54 | struct sway_seat *input_manager_current_seat(struct sway_input_manager *input); | 54 | struct sway_seat *input_manager_current_seat(struct sway_input_manager *input); |
55 | 55 | ||
56 | struct input_config *input_device_get_config(struct sway_input_device *device); | ||
57 | |||
58 | |||
56 | #endif | 59 | #endif |
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 31210a5a..137fcd22 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef _SWAY_INPUT_SEAT_H | 1 | #ifndef _SWAY_INPUT_SEAT_H |
2 | #define _SWAY_INPUT_SEAT_H | 2 | #define _SWAY_INPUT_SEAT_H |
3 | 3 | ||
4 | #include <wlr/types/wlr_layer_shell.h> | ||
4 | #include <wlr/types/wlr_seat.h> | 5 | #include <wlr/types/wlr_seat.h> |
5 | #include "sway/input/input-manager.h" | 6 | #include "sway/input/input-manager.h" |
6 | 7 | ||
@@ -8,7 +9,6 @@ struct sway_seat_device { | |||
8 | struct sway_seat *sway_seat; | 9 | struct sway_seat *sway_seat; |
9 | struct sway_input_device *input_device; | 10 | struct sway_input_device *input_device; |
10 | struct sway_keyboard *keyboard; | 11 | struct sway_keyboard *keyboard; |
11 | struct seat_attachment_config *attachment_config; | ||
12 | struct wl_list link; // sway_seat::devices | 12 | struct wl_list link; // sway_seat::devices |
13 | }; | 13 | }; |
14 | 14 | ||
@@ -23,13 +23,15 @@ struct sway_seat_container { | |||
23 | 23 | ||
24 | struct sway_seat { | 24 | struct sway_seat { |
25 | struct wlr_seat *wlr_seat; | 25 | struct wlr_seat *wlr_seat; |
26 | struct seat_config *config; | ||
27 | struct sway_cursor *cursor; | 26 | struct sway_cursor *cursor; |
28 | struct sway_input_manager *input; | 27 | struct sway_input_manager *input; |
29 | 28 | ||
30 | bool has_focus; | 29 | bool has_focus; |
31 | struct wl_list focus_stack; // list of containers in focus order | 30 | struct wl_list focus_stack; // list of containers in focus order |
32 | 31 | ||
32 | // If the focused layer is set, views cannot receive keyboard focus | ||
33 | struct wlr_layer_surface *focused_layer; | ||
34 | |||
33 | struct wl_listener focus_destroy; | 35 | struct wl_listener focus_destroy; |
34 | struct wl_listener new_container; | 36 | struct wl_listener new_container; |
35 | 37 | ||
@@ -38,28 +40,31 @@ struct sway_seat { | |||
38 | struct wl_list link; // input_manager::seats | 40 | struct wl_list link; // input_manager::seats |
39 | }; | 41 | }; |
40 | 42 | ||
41 | struct sway_seat *sway_seat_create(struct sway_input_manager *input, | 43 | struct sway_seat *seat_create(struct sway_input_manager *input, |
42 | const char *seat_name); | 44 | const char *seat_name); |
43 | 45 | ||
44 | void sway_seat_destroy(struct sway_seat *seat); | 46 | void seat_destroy(struct sway_seat *seat); |
45 | 47 | ||
46 | void sway_seat_add_device(struct sway_seat *seat, | 48 | void seat_add_device(struct sway_seat *seat, |
47 | struct sway_input_device *device); | 49 | struct sway_input_device *device); |
48 | 50 | ||
49 | void sway_seat_configure_device(struct sway_seat *seat, | 51 | void seat_configure_device(struct sway_seat *seat, |
50 | struct sway_input_device *device); | 52 | struct sway_input_device *device); |
51 | 53 | ||
52 | void sway_seat_remove_device(struct sway_seat *seat, | 54 | void seat_remove_device(struct sway_seat *seat, |
53 | struct sway_input_device *device); | 55 | struct sway_input_device *device); |
54 | 56 | ||
55 | void sway_seat_configure_xcursor(struct sway_seat *seat); | 57 | void seat_configure_xcursor(struct sway_seat *seat); |
56 | 58 | ||
57 | void sway_seat_set_focus(struct sway_seat *seat, struct sway_container *container); | 59 | void seat_set_focus(struct sway_seat *seat, struct sway_container *container); |
58 | 60 | ||
59 | void sway_seat_set_focus_warp(struct sway_seat *seat, | 61 | void seat_set_focus_warp(struct sway_seat *seat, |
60 | struct sway_container *container, bool warp); | 62 | struct sway_container *container, bool warp); |
61 | 63 | ||
62 | struct sway_container *sway_seat_get_focus(struct sway_seat *seat); | 64 | void seat_set_focus_layer(struct sway_seat *seat, |
65 | struct wlr_layer_surface *layer); | ||
66 | |||
67 | struct sway_container *seat_get_focus(struct sway_seat *seat); | ||
63 | 68 | ||
64 | /** | 69 | /** |
65 | * Return the last container to be focused for the seat (or the most recently | 70 | * Return the last container to be focused for the seat (or the most recently |
@@ -70,12 +75,14 @@ struct sway_container *sway_seat_get_focus(struct sway_seat *seat); | |||
70 | * is destroyed, or focus moves to a container with children and we need to | 75 | * is destroyed, or focus moves to a container with children and we need to |
71 | * descend into the next leaf in focus order. | 76 | * descend into the next leaf in focus order. |
72 | */ | 77 | */ |
73 | struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, | 78 | struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, |
74 | struct sway_container *container); | 79 | struct sway_container *container); |
75 | 80 | ||
76 | struct sway_container *sway_seat_get_focus_by_type(struct sway_seat *seat, | 81 | struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, |
77 | enum sway_container_type type); | 82 | struct sway_container *container, enum sway_container_type type); |
83 | |||
84 | void seat_apply_config(struct sway_seat *seat, struct seat_config *seat_config); | ||
78 | 85 | ||
79 | void sway_seat_set_config(struct sway_seat *seat, struct seat_config *seat_config); | 86 | struct seat_config *seat_get_config(struct sway_seat *seat); |
80 | 87 | ||
81 | #endif | 88 | #endif |
diff --git a/include/sway/output.h b/include/sway/output.h index b4980cd8..98d0f83f 100644 --- a/include/sway/output.h +++ b/include/sway/output.h | |||
@@ -24,6 +24,7 @@ struct sway_output { | |||
24 | struct wl_listener destroy; | 24 | struct wl_listener destroy; |
25 | struct wl_listener mode; | 25 | struct wl_listener mode; |
26 | struct wl_listener transform; | 26 | struct wl_listener transform; |
27 | struct wl_listener scale; | ||
27 | 28 | ||
28 | struct wl_listener damage_destroy; | 29 | struct wl_listener damage_destroy; |
29 | struct wl_listener damage_frame; | 30 | struct wl_listener damage_frame; |
@@ -36,4 +37,6 @@ void output_damage_whole(struct sway_output *output); | |||
36 | void output_damage_whole_view(struct sway_output *output, | 37 | void output_damage_whole_view(struct sway_output *output, |
37 | struct sway_view *view); | 38 | struct sway_view *view); |
38 | 39 | ||
40 | struct sway_container *output_by_name(const char *name); | ||
41 | |||
39 | #endif | 42 | #endif |
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 6aa66da0..464f80c4 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -70,9 +70,10 @@ struct sway_container { | |||
70 | enum sway_container_layout prev_layout; | 70 | enum sway_container_layout prev_layout; |
71 | enum sway_container_layout workspace_layout; | 71 | enum sway_container_layout workspace_layout; |
72 | 72 | ||
73 | // TODO convert to layout coordinates | 73 | // For C_ROOT, this has no meaning |
74 | // For C_OUTPUT, this is the output position in layout coordinates | ||
75 | // For other types, this is the position in output-local coordinates | ||
74 | double x, y; | 76 | double x, y; |
75 | |||
76 | // does not include borders or gaps. | 77 | // does not include borders or gaps. |
77 | double width, height; | 78 | double width, height; |
78 | 79 | ||
@@ -84,38 +85,67 @@ struct sway_container { | |||
84 | 85 | ||
85 | struct { | 86 | struct { |
86 | struct wl_signal destroy; | 87 | struct wl_signal destroy; |
88 | // Raised after the tree updates, but before arrange_windows | ||
89 | // Passed the previous parent | ||
90 | struct wl_signal reparent; | ||
87 | } events; | 91 | } events; |
88 | }; | 92 | }; |
89 | 93 | ||
94 | // TODO make private and use the container-specific create functions | ||
95 | struct sway_container *container_create(enum sway_container_type type); | ||
96 | |||
97 | const char *container_type_to_str(enum sway_container_type type); | ||
98 | |||
90 | // TODO only one container create function and pass the type? | 99 | // TODO only one container create function and pass the type? |
91 | struct sway_container *container_output_create( | 100 | struct sway_container *container_output_create( |
92 | struct sway_output *sway_output); | 101 | struct sway_output *sway_output); |
93 | 102 | ||
94 | struct sway_container *container_workspace_create( | 103 | /** |
95 | struct sway_container *output, const char *name); | 104 | * Create a new container container. A container container can be a a child of |
105 | * a workspace container or another container container. | ||
106 | */ | ||
107 | struct sway_container *container_container_create(); | ||
96 | 108 | ||
97 | struct sway_container *container_view_create( | 109 | /** |
98 | struct sway_container *sibling, struct sway_view *sway_view); | 110 | * Create a new output. Outputs are children of the root container and have no |
111 | * order in the tree structure. | ||
112 | */ | ||
113 | struct sway_container *container_output_create(struct sway_output *sway_output); | ||
99 | 114 | ||
100 | struct sway_container *container_output_destroy(struct sway_container *output); | 115 | /** |
116 | * Create a new workspace container. Workspaces are children of an output | ||
117 | * container and are ordered alphabetically by name. | ||
118 | */ | ||
119 | struct sway_container *container_workspace_create(struct sway_container *output, const char *name); | ||
101 | 120 | ||
102 | struct sway_container *container_workspace_destroy( | 121 | /* |
103 | struct sway_container *workspace); | 122 | * Create a new view container. A view can be a child of a workspace container |
123 | * or a container container and are rendered in the order and structure of | ||
124 | * how they are attached to the tree. | ||
125 | */ | ||
126 | // TODO view containers should be created in a detached state. | ||
127 | struct sway_container *container_view_create( | ||
128 | struct sway_container *sibling, struct sway_view *sway_view); | ||
104 | 129 | ||
105 | struct sway_container *container_view_destroy(struct sway_container *view); | 130 | // TODO don't return the parent on destroy |
131 | struct sway_container *container_destroy(struct sway_container *container); | ||
106 | 132 | ||
107 | struct sway_container *container_destroy(struct sway_container *cont); | 133 | struct sway_container *container_workspace_destroy(struct sway_container *container); |
134 | struct sway_container *container_output_destroy(struct sway_container *container); | ||
135 | struct sway_container *container_view_destroy(struct sway_container *container); | ||
108 | 136 | ||
137 | // TODO move to layout.c | ||
109 | struct sway_container *container_set_layout(struct sway_container *container, | 138 | struct sway_container *container_set_layout(struct sway_container *container, |
110 | enum sway_container_layout layout); | 139 | enum sway_container_layout layout); |
111 | 140 | ||
141 | // TODO rename to container_descendants_for_each() | ||
112 | void container_descendants(struct sway_container *root, | 142 | void container_descendants(struct sway_container *root, |
113 | enum sway_container_type type, | 143 | enum sway_container_type type, |
114 | void (*func)(struct sway_container *item, void *data), void *data); | 144 | void (*func)(struct sway_container *item, void *data), void *data); |
115 | 145 | ||
116 | /** | 146 | /** |
117 | * Finds a container based on test criteria. Returns the first container that | 147 | * Search a container's descendants a container based on test criteria. Returns |
118 | * passes the test. | 148 | * the first container that passes the test. |
119 | */ | 149 | */ |
120 | struct sway_container *container_find(struct sway_container *container, | 150 | struct sway_container *container_find(struct sway_container *container, |
121 | bool (*test)(struct sway_container *view, void *data), void *data); | 151 | bool (*test)(struct sway_container *view, void *data), void *data); |
@@ -123,18 +153,21 @@ struct sway_container *container_find(struct sway_container *container, | |||
123 | /** | 153 | /** |
124 | * Finds a parent container with the given struct sway_containerype. | 154 | * Finds a parent container with the given struct sway_containerype. |
125 | */ | 155 | */ |
156 | // TODO rename to container_parent_of_type() | ||
126 | struct sway_container *container_parent(struct sway_container *container, | 157 | struct sway_container *container_parent(struct sway_container *container, |
127 | enum sway_container_type type); | 158 | enum sway_container_type type); |
128 | 159 | ||
129 | /** | 160 | /** |
130 | * Find a container at the given coordinates. | 161 | * Find a container at the given coordinates. Returns the the surface and |
162 | * surface-local coordinates of the given layout coordinates if the container | ||
163 | * is a view and the view contains a surface at those coordinates. | ||
131 | */ | 164 | */ |
132 | struct sway_container *container_at(struct sway_container *parent, | 165 | struct sway_container *container_at(struct sway_container *container, |
133 | double lx, double ly, struct wlr_surface **surface, | 166 | double lx, double ly, struct wlr_surface **surface, |
134 | double *sx, double *sy); | 167 | double *sx, double *sy); |
135 | 168 | ||
136 | /** | 169 | /** |
137 | * Apply the function for each child of the container breadth first. | 170 | * Apply the function for each descendant of the container breadth first. |
138 | */ | 171 | */ |
139 | void container_for_each_descendant_bfs(struct sway_container *container, | 172 | void container_for_each_descendant_bfs(struct sway_container *container, |
140 | void (*f)(struct sway_container *container, void *data), void *data); | 173 | void (*f)(struct sway_container *container, void *data), void *data); |
@@ -145,7 +178,16 @@ void container_for_each_descendant_bfs(struct sway_container *container, | |||
145 | void container_for_each_descendant_dfs(struct sway_container *container, | 178 | void container_for_each_descendant_dfs(struct sway_container *container, |
146 | void (*f)(struct sway_container *container, void *data), void *data); | 179 | void (*f)(struct sway_container *container, void *data), void *data); |
147 | 180 | ||
148 | bool container_has_anscestor(struct sway_container *descendant, | 181 | /** |
182 | * Returns true if the given container is an ancestor of this container. | ||
183 | */ | ||
184 | bool container_has_anscestor(struct sway_container *container, | ||
149 | struct sway_container *anscestor); | 185 | struct sway_container *anscestor); |
150 | 186 | ||
187 | /** | ||
188 | * Returns true if the given container is a child descendant of this container. | ||
189 | */ | ||
190 | bool container_has_child(struct sway_container *con, | ||
191 | struct sway_container *child); | ||
192 | |||
151 | #endif | 193 | #endif |
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index 0a904c4b..8badb244 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h | |||
@@ -11,9 +11,6 @@ enum movement_direction { | |||
11 | MOVE_DOWN, | 11 | MOVE_DOWN, |
12 | MOVE_PARENT, | 12 | MOVE_PARENT, |
13 | MOVE_CHILD, | 13 | MOVE_CHILD, |
14 | MOVE_NEXT, | ||
15 | MOVE_PREV, | ||
16 | MOVE_FIRST | ||
17 | }; | 14 | }; |
18 | 15 | ||
19 | struct sway_container; | 16 | struct sway_container; |
@@ -23,7 +20,7 @@ struct sway_root { | |||
23 | 20 | ||
24 | struct wl_listener output_layout_change; | 21 | struct wl_listener output_layout_change; |
25 | 22 | ||
26 | struct wl_list unmanaged_views; // sway_view::unmanaged_view_link | 23 | struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link |
27 | 24 | ||
28 | struct { | 25 | struct { |
29 | struct wl_signal new_container; | 26 | struct wl_signal new_container; |
@@ -32,26 +29,43 @@ struct sway_root { | |||
32 | 29 | ||
33 | void layout_init(void); | 30 | void layout_init(void); |
34 | 31 | ||
35 | void container_add_child(struct sway_container *parent, struct sway_container *child); | 32 | // TODO move to tree.h |
33 | void container_add_child(struct sway_container *parent, | ||
34 | struct sway_container *child); | ||
36 | 35 | ||
36 | // TODO move to tree.h | ||
37 | struct sway_container *container_add_sibling(struct sway_container *parent, | 37 | struct sway_container *container_add_sibling(struct sway_container *parent, |
38 | struct sway_container *child); | 38 | struct sway_container *child); |
39 | 39 | ||
40 | // TODO move to tree.h | ||
40 | struct sway_container *container_remove_child(struct sway_container *child); | 41 | struct sway_container *container_remove_child(struct sway_container *child); |
41 | 42 | ||
43 | // TODO PRIVATE in tree.h | ||
42 | struct sway_container *container_reap_empty(struct sway_container *container); | 44 | struct sway_container *container_reap_empty(struct sway_container *container); |
43 | 45 | ||
46 | // TODO move to tree.h | ||
44 | void container_move_to(struct sway_container* container, | 47 | void container_move_to(struct sway_container* container, |
45 | struct sway_container* destination); | 48 | struct sway_container* destination); |
46 | 49 | ||
47 | enum sway_container_layout container_get_default_layout(struct sway_container *output); | 50 | void container_move(struct sway_container *container, |
51 | enum movement_direction dir, int move_amt); | ||
52 | |||
53 | // TODO move to output.c | ||
54 | enum sway_container_layout container_get_default_layout( | ||
55 | struct sway_container *output); | ||
48 | 56 | ||
57 | // TODO move to output.c | ||
49 | void container_sort_workspaces(struct sway_container *output); | 58 | void container_sort_workspaces(struct sway_container *output); |
50 | 59 | ||
51 | void arrange_windows(struct sway_container *container, | 60 | void arrange_windows(struct sway_container *container, |
52 | double width, double height); | 61 | double width, double height); |
53 | 62 | ||
63 | // TODO move to container.h | ||
54 | struct sway_container *container_get_in_direction(struct sway_container | 64 | struct sway_container *container_get_in_direction(struct sway_container |
55 | *container, struct sway_seat *seat, enum movement_direction dir); | 65 | *container, struct sway_seat *seat, enum movement_direction dir); |
56 | 66 | ||
67 | // TODO move to tree.h | ||
68 | struct sway_container *container_split(struct sway_container *child, | ||
69 | enum sway_container_layout layout); | ||
70 | |||
57 | #endif | 71 | #endif |
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 3965d2b7..4b84205e 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -4,6 +4,8 @@ | |||
4 | #include <wlr/types/wlr_surface.h> | 4 | #include <wlr/types/wlr_surface.h> |
5 | #include <wlr/types/wlr_xdg_shell_v6.h> | 5 | #include <wlr/types/wlr_xdg_shell_v6.h> |
6 | #include <wlr/xwayland.h> | 6 | #include <wlr/xwayland.h> |
7 | #include "sway/input/input-manager.h" | ||
8 | #include "sway/input/seat.h" | ||
7 | 9 | ||
8 | struct sway_container; | 10 | struct sway_container; |
9 | struct sway_view; | 11 | struct sway_view; |
@@ -37,6 +39,13 @@ struct sway_xwayland_surface { | |||
37 | int pending_width, pending_height; | 39 | int pending_width, pending_height; |
38 | }; | 40 | }; |
39 | 41 | ||
42 | struct sway_xwayland_unmanaged { | ||
43 | struct wlr_xwayland_surface *wlr_xwayland_surface; | ||
44 | struct wl_list link; | ||
45 | |||
46 | struct wl_listener destroy; | ||
47 | }; | ||
48 | |||
40 | struct sway_wl_shell_surface { | 49 | struct sway_wl_shell_surface { |
41 | struct sway_view *view; | 50 | struct sway_view *view; |
42 | 51 | ||
@@ -64,10 +73,21 @@ enum sway_view_prop { | |||
64 | VIEW_PROP_INSTANCE, | 73 | VIEW_PROP_INSTANCE, |
65 | }; | 74 | }; |
66 | 75 | ||
76 | struct sway_view_impl { | ||
77 | const char *(*get_prop)(struct sway_view *view, | ||
78 | enum sway_view_prop prop); | ||
79 | void (*configure)(struct sway_view *view, double ox, double oy, int width, | ||
80 | int height); | ||
81 | void (*set_activated)(struct sway_view *view, bool activated); | ||
82 | void (*close)(struct sway_view *view); | ||
83 | }; | ||
84 | |||
67 | struct sway_view { | 85 | struct sway_view { |
68 | enum sway_view_type type; | 86 | enum sway_view_type type; |
69 | struct sway_container *swayc; | 87 | const struct sway_view_impl *impl; |
70 | struct wlr_surface *surface; | 88 | |
89 | struct sway_container *swayc; // NULL for unmanaged views | ||
90 | struct wlr_surface *surface; // NULL for unmapped views | ||
71 | int width, height; | 91 | int width, height; |
72 | 92 | ||
73 | union { | 93 | union { |
@@ -82,21 +102,15 @@ struct sway_view { | |||
82 | struct sway_wl_shell_surface *sway_wl_shell_surface; | 102 | struct sway_wl_shell_surface *sway_wl_shell_surface; |
83 | }; | 103 | }; |
84 | 104 | ||
85 | struct { | ||
86 | const char *(*get_prop)(struct sway_view *view, | ||
87 | enum sway_view_prop prop); | ||
88 | void (*set_size)(struct sway_view *view, | ||
89 | int width, int height); | ||
90 | void (*set_position)(struct sway_view *view, | ||
91 | double ox, double oy); | ||
92 | void (*set_activated)(struct sway_view *view, bool activated); | ||
93 | void (*close)(struct sway_view *view); | ||
94 | } iface; | ||
95 | |||
96 | // only used for unmanaged views (shell specific) | 105 | // only used for unmanaged views (shell specific) |
97 | struct wl_list unmanaged_view_link; // sway_root::unmanaged views | 106 | struct wl_list unmanaged_view_link; // sway_root::unmanaged_views |
98 | }; | 107 | }; |
99 | 108 | ||
109 | struct sway_view *view_create(enum sway_view_type type, | ||
110 | const struct sway_view_impl *impl); | ||
111 | |||
112 | void view_destroy(struct sway_view *view); | ||
113 | |||
100 | const char *view_get_title(struct sway_view *view); | 114 | const char *view_get_title(struct sway_view *view); |
101 | 115 | ||
102 | const char *view_get_app_id(struct sway_view *view); | 116 | const char *view_get_app_id(struct sway_view *view); |
@@ -105,18 +119,25 @@ const char *view_get_class(struct sway_view *view); | |||
105 | 119 | ||
106 | const char *view_get_instance(struct sway_view *view); | 120 | const char *view_get_instance(struct sway_view *view); |
107 | 121 | ||
108 | void view_set_size(struct sway_view *view, int width, int height); | 122 | void view_configure(struct sway_view *view, double ox, double oy, int width, |
109 | 123 | int height); | |
110 | void view_set_position(struct sway_view *view, double ox, double oy); | ||
111 | 124 | ||
112 | void view_set_activated(struct sway_view *view, bool activated); | 125 | void view_set_activated(struct sway_view *view, bool activated); |
113 | 126 | ||
114 | void view_close(struct sway_view *view); | 127 | void view_close(struct sway_view *view); |
115 | 128 | ||
116 | void view_update_outputs(struct sway_view *view, const struct wlr_box *before); | ||
117 | |||
118 | void view_damage_whole(struct sway_view *view); | 129 | void view_damage_whole(struct sway_view *view); |
119 | 130 | ||
120 | void view_damage_from(struct sway_view *view); | 131 | void view_damage_from(struct sway_view *view); |
121 | 132 | ||
133 | // view implementation | ||
134 | |||
135 | void view_map(struct sway_view *view, struct wlr_surface *wlr_surface); | ||
136 | |||
137 | void view_unmap(struct sway_view *view); | ||
138 | |||
139 | void view_update_position(struct sway_view *view, double ox, double oy); | ||
140 | |||
141 | void view_update_size(struct sway_view *view, int width, int height); | ||
142 | |||
122 | #endif | 143 | #endif |
diff --git a/include/swaybar/ipc.h b/include/swaybar/ipc.h index 6ea7c4d6..a1696bcf 100644 --- a/include/swaybar/ipc.h +++ b/include/swaybar/ipc.h | |||
@@ -4,7 +4,7 @@ | |||
4 | #include "swaybar/bar.h" | 4 | #include "swaybar/bar.h" |
5 | 5 | ||
6 | void ipc_initialize(struct swaybar *bar, const char *bar_id); | 6 | void ipc_initialize(struct swaybar *bar, const char *bar_id); |
7 | bool handle_ipc_event(struct swaybar *bar); | 7 | bool handle_ipc_readable(struct swaybar *bar); |
8 | void ipc_get_workspaces(struct swaybar *bar); | 8 | void ipc_get_workspaces(struct swaybar *bar); |
9 | void ipc_send_workspace_command(struct swaybar *bar, const char *ws); | 9 | void ipc_send_workspace_command(struct swaybar *bar, const char *ws); |
10 | 10 | ||
diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h index 6c595df0..3538f49c 100644 --- a/include/swaybar/status_line.h +++ b/include/swaybar/status_line.h | |||
@@ -7,10 +7,52 @@ | |||
7 | 7 | ||
8 | enum status_protocol { | 8 | enum status_protocol { |
9 | PROTOCOL_UNDEF, | 9 | PROTOCOL_UNDEF, |
10 | PROTOCOL_ERROR, | ||
10 | PROTOCOL_TEXT, | 11 | PROTOCOL_TEXT, |
11 | PROTOCOL_I3BAR, | 12 | PROTOCOL_I3BAR, |
12 | }; | 13 | }; |
13 | 14 | ||
15 | struct text_protocol_state { | ||
16 | char *buffer; | ||
17 | size_t buffer_size; | ||
18 | }; | ||
19 | |||
20 | enum json_node_type { | ||
21 | JSON_NODE_UNKNOWN, | ||
22 | JSON_NODE_ARRAY, | ||
23 | JSON_NODE_STRING, | ||
24 | }; | ||
25 | |||
26 | struct i3bar_protocol_state { | ||
27 | bool click_events; | ||
28 | char *buffer; | ||
29 | size_t buffer_size; | ||
30 | size_t buffer_index; | ||
31 | const char *current_node; | ||
32 | bool escape; | ||
33 | size_t depth; | ||
34 | enum json_node_type nodes[16]; | ||
35 | }; | ||
36 | |||
37 | struct i3bar_block { | ||
38 | struct wl_list link; | ||
39 | char *full_text, *short_text, *align; | ||
40 | bool urgent; | ||
41 | uint32_t *color; | ||
42 | int min_width; | ||
43 | char *name, *instance; | ||
44 | bool separator; | ||
45 | int separator_block_width; | ||
46 | bool markup; | ||
47 | // Airblader features | ||
48 | uint32_t background; | ||
49 | uint32_t border; | ||
50 | int border_top; | ||
51 | int border_bottom; | ||
52 | int border_left; | ||
53 | int border_right; | ||
54 | }; | ||
55 | |||
14 | struct status_line { | 56 | struct status_line { |
15 | pid_t pid; | 57 | pid_t pid; |
16 | int read_fd, write_fd; | 58 | int read_fd, write_fd; |
@@ -18,13 +60,18 @@ struct status_line { | |||
18 | 60 | ||
19 | enum status_protocol protocol; | 61 | enum status_protocol protocol; |
20 | const char *text; | 62 | const char *text; |
63 | struct wl_list blocks; // i3bar_block::link | ||
21 | 64 | ||
22 | char *buffer; | 65 | struct text_protocol_state text_state; |
23 | size_t buffer_size; | 66 | struct i3bar_protocol_state i3bar_state; |
24 | }; | 67 | }; |
25 | 68 | ||
26 | struct status_line *status_line_init(char *cmd); | 69 | struct status_line *status_line_init(char *cmd); |
70 | void status_error(struct status_line *status, const char *text); | ||
71 | bool status_handle_readable(struct status_line *status); | ||
27 | void status_line_free(struct status_line *status); | 72 | void status_line_free(struct status_line *status); |
28 | bool handle_status_readable(struct status_line *status); | 73 | bool i3bar_handle_readable(struct status_line *status); |
74 | void i3bar_block_send_click(struct status_line *status, | ||
75 | struct i3bar_block *block, int x, int y, uint32_t button); | ||
29 | 76 | ||
30 | #endif | 77 | #endif |
diff --git a/protocols/desktop-shell.xml b/protocols/desktop-shell.xml deleted file mode 100644 index 581f0c5d..00000000 --- a/protocols/desktop-shell.xml +++ /dev/null | |||
@@ -1,138 +0,0 @@ | |||
1 | <protocol name="desktop"> | ||
2 | |||
3 | <interface name="desktop_shell" version="3"> | ||
4 | <description summary="create desktop widgets and helpers"> | ||
5 | Traditional user interfaces can rely on this interface to define the | ||
6 | foundations of typical desktops. Currently it's possible to set up | ||
7 | background, panels and locking surfaces. | ||
8 | </description> | ||
9 | |||
10 | <request name="set_background"> | ||
11 | <arg name="output" type="object" interface="wl_output"/> | ||
12 | <arg name="surface" type="object" interface="wl_surface"/> | ||
13 | </request> | ||
14 | |||
15 | <request name="set_panel"> | ||
16 | <arg name="output" type="object" interface="wl_output"/> | ||
17 | <arg name="surface" type="object" interface="wl_surface"/> | ||
18 | </request> | ||
19 | |||
20 | <request name="set_lock_surface"> | ||
21 | <arg name="surface" type="object" interface="wl_surface"/> | ||
22 | </request> | ||
23 | |||
24 | <request name="unlock"/> | ||
25 | |||
26 | <request name="set_grab_surface"> | ||
27 | <description summary="set grab surface"> | ||
28 | The surface set by this request will receive a fake | ||
29 | pointer.enter event during grabs at position 0, 0 and is | ||
30 | expected to set an appropriate cursor image as described by | ||
31 | the grab_cursor event sent just before the enter event. | ||
32 | </description> | ||
33 | <arg name="surface" type="object" interface="wl_surface"/> | ||
34 | </request> | ||
35 | |||
36 | <!-- We'll fold most of wl_shell into this interface and then | ||
37 | they'll share the configure event. --> | ||
38 | <event name="configure"> | ||
39 | <arg name="edges" type="uint"/> | ||
40 | <arg name="surface" type="object" interface="wl_surface"/> | ||
41 | <arg name="width" type="int"/> | ||
42 | <arg name="height" type="int"/> | ||
43 | </event> | ||
44 | |||
45 | <event name="prepare_lock_surface"> | ||
46 | <description summary="tell the client to create, set the lock surface"> | ||
47 | Tell the client we want it to create and set the lock surface, which is | ||
48 | a GUI asking the user to unlock the screen. The lock surface is | ||
49 | announced with 'set_lock_surface'. Whether or not the client actually | ||
50 | implements locking, it MUST send 'unlock' request to let the normal | ||
51 | desktop resume. | ||
52 | </description> | ||
53 | </event> | ||
54 | |||
55 | <event name="grab_cursor"> | ||
56 | <description summary="tell client what cursor to show during a grab"> | ||
57 | This event will be sent immediately before a fake enter event on the | ||
58 | grab surface. | ||
59 | </description> | ||
60 | <arg name="cursor" type="uint"/> | ||
61 | </event> | ||
62 | |||
63 | <enum name="cursor"> | ||
64 | <entry name="none" value="0"/> | ||
65 | |||
66 | <entry name="resize_top" value="1"/> | ||
67 | <entry name="resize_bottom" value="2"/> | ||
68 | |||
69 | <entry name="arrow" value="3"/> | ||
70 | |||
71 | <entry name="resize_left" value="4"/> | ||
72 | <entry name="resize_top_left" value="5"/> | ||
73 | <entry name="resize_bottom_left" value="6"/> | ||
74 | |||
75 | <entry name="move" value="7"/> | ||
76 | |||
77 | <entry name="resize_right" value="8"/> | ||
78 | <entry name="resize_top_right" value="9"/> | ||
79 | <entry name="resize_bottom_right" value="10"/> | ||
80 | |||
81 | <entry name="busy" value="11"/> | ||
82 | </enum> | ||
83 | |||
84 | <!-- Version 2 additions --> | ||
85 | |||
86 | <request name="desktop_ready" since="2"> | ||
87 | <description summary="desktop is ready to be shown"> | ||
88 | Tell the server, that enough desktop elements have been drawn | ||
89 | to make the desktop look ready for use. During start-up, the | ||
90 | server can wait for this request with a black screen before | ||
91 | starting to fade in the desktop, for instance. If the client | ||
92 | parts of a desktop take a long time to initialize, we avoid | ||
93 | showing temporary garbage. | ||
94 | </description> | ||
95 | </request> | ||
96 | |||
97 | <!-- Version 3 additions --> | ||
98 | |||
99 | <enum name="panel_position"> | ||
100 | <entry name="top" value="0"/> | ||
101 | <entry name="bottom" value="1"/> | ||
102 | <entry name="left" value="2"/> | ||
103 | <entry name="right" value="3"/> | ||
104 | </enum> | ||
105 | |||
106 | <enum name="error"> | ||
107 | <entry name="invalid_argument" value="0" | ||
108 | summary="an invalid argument was provided in a request"/> | ||
109 | </enum> | ||
110 | |||
111 | <request name="set_panel_position" since="3"> | ||
112 | <description summary="set panel position"> | ||
113 | Tell the shell which side of the screen the panel is | ||
114 | located. This is so that new windows do not overlap the panel | ||
115 | and maximized windows maximize properly. | ||
116 | </description> | ||
117 | <arg name="position" type="uint"/> | ||
118 | </request> | ||
119 | |||
120 | </interface> | ||
121 | |||
122 | <interface name="screensaver" version="1"> | ||
123 | <description summary="interface for implementing screensavers"> | ||
124 | Only one client can bind this interface at a time. | ||
125 | </description> | ||
126 | |||
127 | <request name="set_surface"> | ||
128 | <description summary="set the surface type as a screensaver"> | ||
129 | A screensaver surface is normally hidden, and only visible after an | ||
130 | idle timeout. | ||
131 | </description> | ||
132 | |||
133 | <arg name="surface" type="object" interface="wl_surface"/> | ||
134 | <arg name="output" type="object" interface="wl_output"/> | ||
135 | </request> | ||
136 | |||
137 | </interface> | ||
138 | </protocol> | ||
diff --git a/protocols/gamma-control.xml b/protocols/gamma-control.xml deleted file mode 100644 index e6e33265..00000000 --- a/protocols/gamma-control.xml +++ /dev/null | |||
@@ -1,57 +0,0 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <protocol name="gamma_control"> | ||
3 | |||
4 | <copyright> | ||
5 | Copyright © 2015 Giulio camuffo | ||
6 | |||
7 | Permission to use, copy, modify, distribute, and sell this | ||
8 | software and its documentation for any purpose is hereby granted | ||
9 | without fee, provided that the above copyright notice appear in | ||
10 | all copies and that both that copyright notice and this permission | ||
11 | notice appear in supporting documentation, and that the name of | ||
12 | the copyright holders not be used in advertising or publicity | ||
13 | pertaining to distribution of the software without specific, | ||
14 | written prior permission. The copyright holders make no | ||
15 | representations about the suitability of this software for any | ||
16 | purpose. It is provided "as is" without express or implied | ||
17 | warranty. | ||
18 | |||
19 | THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | ||
20 | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
21 | FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
22 | SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
23 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | ||
24 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | ||
25 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | ||
26 | THIS SOFTWARE. | ||
27 | </copyright> | ||
28 | |||
29 | <interface name="gamma_control_manager" version="1"> | ||
30 | <request name="destroy" type="destructor"/> | ||
31 | |||
32 | <request name="get_gamma_control"> | ||
33 | <arg name="id" type="new_id" interface="gamma_control"/> | ||
34 | <arg name="output" type="object" interface="wl_output"/> | ||
35 | </request> | ||
36 | </interface> | ||
37 | |||
38 | <interface name="gamma_control" version="1"> | ||
39 | <enum name="error"> | ||
40 | <entry name="invalid_gamma" value="0"/> | ||
41 | </enum> | ||
42 | |||
43 | <request name="destroy" type="destructor"/> | ||
44 | |||
45 | <request name="set_gamma"> | ||
46 | <arg name="red" type="array"/> | ||
47 | <arg name="green" type="array"/> | ||
48 | <arg name="blue" type="array"/> | ||
49 | </request> | ||
50 | |||
51 | <request name="reset_gamma"/> | ||
52 | |||
53 | <event name="gamma_size"> | ||
54 | <arg name="size" type="uint"/> | ||
55 | </event> | ||
56 | </interface> | ||
57 | </protocol> | ||
diff --git a/protocols/server-decoration.xml b/protocols/server-decoration.xml deleted file mode 100644 index 8bc106c7..00000000 --- a/protocols/server-decoration.xml +++ /dev/null | |||
@@ -1,94 +0,0 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <protocol name="server_decoration"> | ||
3 | <copyright><![CDATA[ | ||
4 | Copyright (C) 2015 Martin Gräßlin | ||
5 | |||
6 | This program is free software: you can redistribute it and/or modify | ||
7 | it under the terms of the GNU Lesser General Public License as published by | ||
8 | the Free Software Foundation, either version 2.1 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU Lesser General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU Lesser General Public License | ||
17 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | ]]></copyright> | ||
19 | <interface name="org_kde_kwin_server_decoration_manager" version="1"> | ||
20 | <description summary="Server side window decoration manager"> | ||
21 | This interface allows to coordinate whether the server should create | ||
22 | a server-side window decoration around a wl_surface representing a | ||
23 | shell surface (wl_shell_surface or similar). By announcing support | ||
24 | for this interface the server indicates that it supports server | ||
25 | side decorations. | ||
26 | </description> | ||
27 | <request name="create"> | ||
28 | <description summary="Create a server-side decoration object for a given surface"> | ||
29 | When a client creates a server-side decoration object it indicates | ||
30 | that it supports the protocol. The client is supposed to tell the | ||
31 | server whether it wants server-side decorations or will provide | ||
32 | client-side decorations. | ||
33 | |||
34 | If the client does not create a server-side decoration object for | ||
35 | a surface the server interprets this as lack of support for this | ||
36 | protocol and considers it as client-side decorated. Nevertheless a | ||
37 | client-side decorated surface should use this protocol to indicate | ||
38 | to the server that it does not want a server-side deco. | ||
39 | </description> | ||
40 | <arg name="id" type="new_id" interface="org_kde_kwin_server_decoration"/> | ||
41 | <arg name="surface" type="object" interface="wl_surface"/> | ||
42 | </request> | ||
43 | <enum name="mode"> | ||
44 | <description summary="Possible values to use in request_mode and the event mode."/> | ||
45 | <entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither server nor client-side. An example is a popup surface which should not be decorated."/> | ||
46 | <entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the surface and the client."/> | ||
47 | <entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface into a decoration frame."/> | ||
48 | </enum> | ||
49 | <event name="default_mode"> | ||
50 | <description summary="The default mode used on the server"> | ||
51 | This event is emitted directly after binding the interface. It contains | ||
52 | the default mode for the decoration. When a new server decoration object | ||
53 | is created this new object will be in the default mode until the first | ||
54 | request_mode is requested. | ||
55 | |||
56 | The server may change the default mode at any time. | ||
57 | </description> | ||
58 | <arg name="mode" type="uint" summary="The default decoration mode applied to newly created server decorations."/> | ||
59 | </event> | ||
60 | </interface> | ||
61 | <interface name="org_kde_kwin_server_decoration" version="1"> | ||
62 | <request name="release" type="destructor"> | ||
63 | <description summary="release the server decoration object"/> | ||
64 | </request> | ||
65 | <enum name="mode"> | ||
66 | <description summary="Possible values to use in request_mode and the event mode."/> | ||
67 | <entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither server nor client-side. An example is a popup surface which should not be decorated."/> | ||
68 | <entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the surface and the client."/> | ||
69 | <entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface into a decoration frame."/> | ||
70 | </enum> | ||
71 | <request name="request_mode"> | ||
72 | <description summary="The decoration mode the surface wants to use."/> | ||
73 | <arg name="mode" type="uint" summary="The mode this surface wants to use."/> | ||
74 | </request> | ||
75 | <event name="mode"> | ||
76 | <description summary="The new decoration mode applied by the server"> | ||
77 | This event is emitted directly after the decoration is created and | ||
78 | represents the base decoration policy by the server. E.g. a server | ||
79 | which wants all surfaces to be client-side decorated will send Client, | ||
80 | a server which wants server-side decoration will send Server. | ||
81 | |||
82 | The client can request a different mode through the decoration request. | ||
83 | The server will acknowledge this by another event with the same mode. So | ||
84 | even if a server prefers server-side decoration it's possible to force a | ||
85 | client-side decoration. | ||
86 | |||
87 | The server may emit this event at any time. In this case the client can | ||
88 | again request a different mode. It's the responsibility of the server to | ||
89 | prevent a feedback loop. | ||
90 | </description> | ||
91 | <arg name="mode" type="uint" summary="The decoration mode applied to the surface by the server."/> | ||
92 | </event> | ||
93 | </interface> | ||
94 | </protocol> | ||
diff --git a/protocols/swaylock.xml b/protocols/swaylock.xml deleted file mode 100644 index c7a102dd..00000000 --- a/protocols/swaylock.xml +++ /dev/null | |||
@@ -1,18 +0,0 @@ | |||
1 | <protocol name="lock"> | ||
2 | |||
3 | <interface name="lock" version="1"> | ||
4 | <description summary="create lock screen UIs"> | ||
5 | The Weston desktop-shell protocol's locking functionality depends more | ||
6 | on the behavior of the compositor than of a screen locking client, so | ||
7 | another protocol is necessary. | ||
8 | </description> | ||
9 | |||
10 | <request name="set_lock_surface"> | ||
11 | <arg name="output" type="object" interface="wl_output"/> | ||
12 | <arg name="surface" type="object" interface="wl_surface"/> | ||
13 | </request> | ||
14 | |||
15 | <request name="unlock"/> | ||
16 | |||
17 | </interface> | ||
18 | </protocol> | ||
diff --git a/protocols/xdg-shell.xml b/protocols/xdg-shell.xml deleted file mode 100644 index 7bf4ae3a..00000000 --- a/protocols/xdg-shell.xml +++ /dev/null | |||
@@ -1,430 +0,0 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <protocol name="xdg_shell"> | ||
3 | |||
4 | <copyright> | ||
5 | Copyright © 2008-2013 Kristian Høgsberg | ||
6 | Copyright © 2013 Rafael Antognolli | ||
7 | Copyright © 2013 Jasper St. Pierre | ||
8 | Copyright © 2010-2013 Intel Corporation | ||
9 | |||
10 | Permission to use, copy, modify, distribute, and sell this | ||
11 | software and its documentation for any purpose is hereby granted | ||
12 | without fee, provided that the above copyright notice appear in | ||
13 | all copies and that both that copyright notice and this permission | ||
14 | notice appear in supporting documentation, and that the name of | ||
15 | the copyright holders not be used in advertising or publicity | ||
16 | pertaining to distribution of the software without specific, | ||
17 | written prior permission. The copyright holders make no | ||
18 | representations about the suitability of this software for any | ||
19 | purpose. It is provided "as is" without express or implied | ||
20 | warranty. | ||
21 | |||
22 | THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | ||
23 | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||
24 | FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
25 | SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
26 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | ||
27 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | ||
28 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | ||
29 | THIS SOFTWARE. | ||
30 | </copyright> | ||
31 | |||
32 | <interface name="xdg_shell" version="1"> | ||
33 | <description summary="create desktop-style surfaces"> | ||
34 | This interface is implemented by servers that provide | ||
35 | desktop-style user interfaces. | ||
36 | |||
37 | It allows clients to associate a xdg_surface with | ||
38 | a basic surface. | ||
39 | </description> | ||
40 | |||
41 | <enum name="version"> | ||
42 | <description summary="latest protocol version"> | ||
43 | The 'current' member of this enum gives the version of the | ||
44 | protocol. Implementations can compare this to the version | ||
45 | they implement using static_assert to ensure the protocol and | ||
46 | implementation versions match. | ||
47 | </description> | ||
48 | <entry name="current" value="4" summary="Always the latest version"/> | ||
49 | </enum> | ||
50 | |||
51 | <enum name="error"> | ||
52 | <entry name="role" value="0" summary="given wl_surface has another role"/> | ||
53 | </enum> | ||
54 | |||
55 | <request name="use_unstable_version"> | ||
56 | <description summary="enable use of this unstable version"> | ||
57 | Negotiate the unstable version of the interface. This | ||
58 | mechanism is in place to ensure client and server agree on the | ||
59 | unstable versions of the protocol that they speak or exit | ||
60 | cleanly if they don't agree. This request will go away once | ||
61 | the xdg-shell protocol is stable. | ||
62 | </description> | ||
63 | <arg name="version" type="int"/> | ||
64 | </request> | ||
65 | |||
66 | <request name="get_xdg_surface"> | ||
67 | <description summary="create a shell surface from a surface"> | ||
68 | Create a shell surface for an existing surface. | ||
69 | |||
70 | This request gives the surface the role of xdg_surface. If the | ||
71 | surface already has another role, it raises a protocol error. | ||
72 | |||
73 | Only one shell or popup surface can be associated with a given | ||
74 | surface. | ||
75 | </description> | ||
76 | <arg name="id" type="new_id" interface="xdg_surface"/> | ||
77 | <arg name="surface" type="object" interface="wl_surface"/> | ||
78 | </request> | ||
79 | |||
80 | <request name="get_xdg_popup"> | ||
81 | <description summary="create a shell surface from a surface"> | ||
82 | Create a popup surface for an existing surface. | ||
83 | |||
84 | This request gives the surface the role of xdg_popup. If the | ||
85 | surface already has another role, it raises a protocol error. | ||
86 | |||
87 | Only one shell or popup surface can be associated with a given | ||
88 | surface. | ||
89 | </description> | ||
90 | <arg name="id" type="new_id" interface="xdg_popup"/> | ||
91 | <arg name="surface" type="object" interface="wl_surface"/> | ||
92 | <arg name="parent" type="object" interface="wl_surface"/> | ||
93 | <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/> | ||
94 | <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> | ||
95 | <arg name="x" type="int"/> | ||
96 | <arg name="y" type="int"/> | ||
97 | <arg name="flags" type="uint"/> | ||
98 | </request> | ||
99 | |||
100 | <event name="ping"> | ||
101 | <description summary="check if the client is alive"> | ||
102 | The ping event asks the client if it's still alive. Pass the | ||
103 | serial specified in the event back to the compositor by sending | ||
104 | a "pong" request back with the specified serial. | ||
105 | |||
106 | Compositors can use this to determine if the client is still | ||
107 | alive. It's unspecified what will happen if the client doesn't | ||
108 | respond to the ping request, or in what timeframe. Clients should | ||
109 | try to respond in a reasonable amount of time. | ||
110 | </description> | ||
111 | <arg name="serial" type="uint" summary="pass this to the callback"/> | ||
112 | </event> | ||
113 | |||
114 | <request name="pong"> | ||
115 | <description summary="respond to a ping event"> | ||
116 | A client must respond to a ping event with a pong request or | ||
117 | the client may be deemed unresponsive. | ||
118 | </description> | ||
119 | <arg name="serial" type="uint" summary="serial of the ping event"/> | ||
120 | </request> | ||
121 | </interface> | ||
122 | |||
123 | <interface name="xdg_surface" version="1"> | ||
124 | |||
125 | <description summary="desktop-style metadata interface"> | ||
126 | An interface that may be implemented by a wl_surface, for | ||
127 | implementations that provide a desktop-style user interface. | ||
128 | |||
129 | It provides requests to treat surfaces like windows, allowing to set | ||
130 | properties like maximized, fullscreen, minimized, and to move and resize | ||
131 | them, and associate metadata like title and app id. | ||
132 | |||
133 | On the server side the object is automatically destroyed when | ||
134 | the related wl_surface is destroyed. On client side, | ||
135 | xdg_surface.destroy() must be called before destroying | ||
136 | the wl_surface object. | ||
137 | </description> | ||
138 | |||
139 | <request name="destroy" type="destructor"> | ||
140 | <description summary="remove xdg_surface interface"> | ||
141 | The xdg_surface interface is removed from the wl_surface object | ||
142 | that was turned into a xdg_surface with | ||
143 | xdg_shell.get_xdg_surface request. The xdg_surface properties, | ||
144 | like maximized and fullscreen, are lost. The wl_surface loses | ||
145 | its role as a xdg_surface. The wl_surface is unmapped. | ||
146 | </description> | ||
147 | </request> | ||
148 | |||
149 | <request name="set_parent"> | ||
150 | <description summary="surface is a child of another surface"> | ||
151 | Child surfaces are stacked above their parents, and will be | ||
152 | unmapped if the parent is unmapped too. They should not appear | ||
153 | on task bars and alt+tab. | ||
154 | </description> | ||
155 | <arg name="parent" type="object" interface="wl_surface" allow-null="true"/> | ||
156 | </request> | ||
157 | |||
158 | <request name="set_title"> | ||
159 | <description summary="set surface title"> | ||
160 | Set a short title for the surface. | ||
161 | |||
162 | This string may be used to identify the surface in a task bar, | ||
163 | window list, or other user interface elements provided by the | ||
164 | compositor. | ||
165 | |||
166 | The string must be encoded in UTF-8. | ||
167 | </description> | ||
168 | <arg name="title" type="string"/> | ||
169 | </request> | ||
170 | |||
171 | <request name="set_app_id"> | ||
172 | <description summary="set surface class"> | ||
173 | Set an id for the surface. | ||
174 | |||
175 | The app id identifies the general class of applications to which | ||
176 | the surface belongs. | ||
177 | |||
178 | It should be the ID that appears in the new desktop entry | ||
179 | specification, the interface name. | ||
180 | </description> | ||
181 | <arg name="app_id" type="string"/> | ||
182 | </request> | ||
183 | |||
184 | <request name="show_window_menu"> | ||
185 | <description summary="show the window menu"> | ||
186 | Clients implementing client-side decorations might want to show | ||
187 | a context menu when right-clicking on the decorations, giving the | ||
188 | user a menu that they can use to maximize or minimize the window. | ||
189 | |||
190 | This request asks the compositor to pop up such a window menu at | ||
191 | the given position, relative to the parent surface. There are | ||
192 | no guarantees as to what the window menu contains. | ||
193 | |||
194 | Your surface must have focus on the seat passed in to pop up the | ||
195 | window menu. | ||
196 | </description> | ||
197 | |||
198 | <arg name="seat" type="object" interface="wl_seat" summary="the seat to pop the window up on"/> | ||
199 | <arg name="serial" type="uint" summary="serial of the event to pop up the window for"/> | ||
200 | <arg name="x" type="int" summary="the x position to pop up the window menu at"/> | ||
201 | <arg name="y" type="int" summary="the y position to pop up the window menu at"/> | ||
202 | </request> | ||
203 | |||
204 | <request name="move"> | ||
205 | <description summary="start an interactive move"> | ||
206 | Start a pointer-driven move of the surface. | ||
207 | |||
208 | This request must be used in response to a button press event. | ||
209 | The server may ignore move requests depending on the state of | ||
210 | the surface (e.g. fullscreen or maximized). | ||
211 | </description> | ||
212 | <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/> | ||
213 | <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> | ||
214 | </request> | ||
215 | |||
216 | <enum name="resize_edge"> | ||
217 | <description summary="edge values for resizing"> | ||
218 | These values are used to indicate which edge of a surface | ||
219 | is being dragged in a resize operation. The server may | ||
220 | use this information to adapt its behavior, e.g. choose | ||
221 | an appropriate cursor image. | ||
222 | </description> | ||
223 | <entry name="none" value="0"/> | ||
224 | <entry name="top" value="1"/> | ||
225 | <entry name="bottom" value="2"/> | ||
226 | <entry name="left" value="4"/> | ||
227 | <entry name="top_left" value="5"/> | ||
228 | <entry name="bottom_left" value="6"/> | ||
229 | <entry name="right" value="8"/> | ||
230 | <entry name="top_right" value="9"/> | ||
231 | <entry name="bottom_right" value="10"/> | ||
232 | </enum> | ||
233 | |||
234 | <request name="resize"> | ||
235 | <description summary="start an interactive resize"> | ||
236 | Start a pointer-driven resizing of the surface. | ||
237 | |||
238 | This request must be used in response to a button press event. | ||
239 | The server may ignore resize requests depending on the state of | ||
240 | the surface (e.g. fullscreen or maximized). | ||
241 | </description> | ||
242 | <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat whose pointer is used"/> | ||
243 | <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> | ||
244 | <arg name="edges" type="uint" summary="which edge or corner is being dragged"/> | ||
245 | </request> | ||
246 | |||
247 | <enum name="state"> | ||
248 | <description summary="types of state on the surface"> | ||
249 | The different state values used on the surface. This is designed for | ||
250 | state values like maximized, fullscreen. It is paired with the | ||
251 | configure event to ensure that both the client and the compositor | ||
252 | setting the state can be synchronized. | ||
253 | |||
254 | States set in this way are double-buffered. They will get applied on | ||
255 | the next commit. | ||
256 | |||
257 | Desktop environments may extend this enum by taking up a range of | ||
258 | values and documenting the range they chose in this description. | ||
259 | They are not required to document the values for the range that they | ||
260 | chose. Ideally, any good extensions from a desktop environment should | ||
261 | make its way into standardization into this enum. | ||
262 | |||
263 | The current reserved ranges are: | ||
264 | |||
265 | 0x0000 - 0x0FFF: xdg-shell core values, documented below. | ||
266 | 0x1000 - 0x1FFF: GNOME | ||
267 | </description> | ||
268 | <entry name="maximized" value="1"> | ||
269 | <description summary="the surface is maximized"> | ||
270 | The surface is maximized. The window geometry specified in the configure | ||
271 | event must be obeyed by the client. | ||
272 | </description> | ||
273 | </entry> | ||
274 | <entry name="fullscreen" value="2"> | ||
275 | <description summary="the surface is fullscreen"> | ||
276 | The surface is fullscreen. The window geometry specified in the configure | ||
277 | event must be obeyed by the client. | ||
278 | </description> | ||
279 | </entry> | ||
280 | <entry name="resizing" value="3"> | ||
281 | <description summary="the surface is being resized"> | ||
282 | The surface is being resized. The window geometry specified in the | ||
283 | configure event is a maximum; the client cannot resize beyond it. | ||
284 | Clients that have aspect ratio or cell sizing configuration can use | ||
285 | a smaller size, however. | ||
286 | </description> | ||
287 | </entry> | ||
288 | <entry name="activated" value="4"> | ||
289 | <description summary="the client window is active"> | ||
290 | Client window decorations should be painted as if the window is | ||
291 | active. Do not assume this means that the window actually has | ||
292 | keyboard or pointer focus. | ||
293 | </description> | ||
294 | </entry> | ||
295 | </enum> | ||
296 | |||
297 | <event name="configure"> | ||
298 | <description summary="suggest a surface change"> | ||
299 | The configure event asks the client to resize its surface. | ||
300 | |||
301 | The width and height arguments specify a hint to the window | ||
302 | about how its surface should be resized in window geometry | ||
303 | coordinates. The states listed in the event specify how the | ||
304 | width/height arguments should be interpreted. | ||
305 | |||
306 | A client should arrange a new surface, and then send a | ||
307 | ack_configure request with the serial sent in this configure | ||
308 | event before attaching a new surface. | ||
309 | |||
310 | If the client receives multiple configure events before it | ||
311 | can respond to one, it is free to discard all but the last | ||
312 | event it received. | ||
313 | </description> | ||
314 | |||
315 | <arg name="width" type="int"/> | ||
316 | <arg name="height" type="int"/> | ||
317 | <arg name="states" type="array"/> | ||
318 | <arg name="serial" type="uint"/> | ||
319 | </event> | ||
320 | |||
321 | <request name="ack_configure"> | ||
322 | <description summary="ack a configure event"> | ||
323 | When a configure event is received, a client should then ack it | ||
324 | using the ack_configure request to ensure that the compositor | ||
325 | knows the client has seen the event. | ||
326 | |||
327 | By this point, the state is confirmed, and the next attach should | ||
328 | contain the buffer drawn for the configure event you are acking. | ||
329 | </description> | ||
330 | <arg name="serial" type="uint" summary="a serial to configure for"/> | ||
331 | </request> | ||
332 | |||
333 | <request name="set_window_geometry"> | ||
334 | <description summary="set the new window geometry"> | ||
335 | The window geometry of a window is its "visible bounds" from the | ||
336 | user's perspective. Client-side decorations often have invisible | ||
337 | portions like drop-shadows which should be ignored for the | ||
338 | purposes of aligning, placing and constraining windows. | ||
339 | |||
340 | The default value is the full bounds of the surface, including any | ||
341 | subsurfaces. Once the window geometry of the surface is set once, | ||
342 | it is not possible to unset it, and it will remain the same until | ||
343 | set_window_geometry is called again, even if a new subsurface or | ||
344 | buffer is attached. | ||
345 | |||
346 | If responding to a configure event, the window geometry in here | ||
347 | must respect the sizing negotiations specified by the states in | ||
348 | the configure event. | ||
349 | </description> | ||
350 | <arg name="x" type="int"/> | ||
351 | <arg name="y" type="int"/> | ||
352 | <arg name="width" type="int"/> | ||
353 | <arg name="height" type="int"/> | ||
354 | </request> | ||
355 | |||
356 | <request name="set_maximized" /> | ||
357 | <request name="unset_maximized" /> | ||
358 | |||
359 | <request name="set_fullscreen"> | ||
360 | <description summary="set the window as fullscreen on a monitor"> | ||
361 | Make the surface fullscreen. | ||
362 | |||
363 | You can specify an output that you would prefer to be fullscreen. | ||
364 | If this value is NULL, it's up to the compositor to choose which | ||
365 | display will be used to map this surface. | ||
366 | </description> | ||
367 | <arg name="output" type="object" interface="wl_output" allow-null="true"/> | ||
368 | </request> | ||
369 | <request name="unset_fullscreen" /> | ||
370 | |||
371 | <request name="set_minimized" /> | ||
372 | |||
373 | <event name="close"> | ||
374 | <description summary="surface wants to be closed"> | ||
375 | The close event is sent by the compositor when the user | ||
376 | wants the surface to be closed. This should be equivalent to | ||
377 | the user clicking the close button in client-side decorations, | ||
378 | if your application has any... | ||
379 | |||
380 | This is only a request that the user intends to close your | ||
381 | window. The client may choose to ignore this request, or show | ||
382 | a dialog to ask the user to save their data... | ||
383 | </description> | ||
384 | </event> | ||
385 | </interface> | ||
386 | |||
387 | <interface name="xdg_popup" version="1"> | ||
388 | <description summary="desktop-style metadata interface"> | ||
389 | An interface that may be implemented by a wl_surface, for | ||
390 | implementations that provide a desktop-style popups/menus. A popup | ||
391 | surface is a transient surface with an added pointer grab. | ||
392 | |||
393 | An existing implicit grab will be changed to owner-events mode, | ||
394 | and the popup grab will continue after the implicit grab ends | ||
395 | (i.e. releasing the mouse button does not cause the popup to be | ||
396 | unmapped). | ||
397 | |||
398 | The popup grab continues until the window is destroyed or a mouse | ||
399 | button is pressed in any other clients window. A click in any of | ||
400 | the clients surfaces is reported as normal, however, clicks in | ||
401 | other clients surfaces will be discarded and trigger the callback. | ||
402 | |||
403 | The x and y arguments specify the locations of the upper left | ||
404 | corner of the surface relative to the upper left corner of the | ||
405 | parent surface, in surface local coordinates. | ||
406 | |||
407 | xdg_popup surfaces are always transient for another surface. | ||
408 | </description> | ||
409 | |||
410 | <request name="destroy" type="destructor"> | ||
411 | <description summary="remove xdg_surface interface"> | ||
412 | The xdg_surface interface is removed from the wl_surface object | ||
413 | that was turned into a xdg_surface with | ||
414 | xdg_shell.get_xdg_surface request. The xdg_surface properties, | ||
415 | like maximized and fullscreen, are lost. The wl_surface loses | ||
416 | its role as a xdg_surface. The wl_surface is unmapped. | ||
417 | </description> | ||
418 | </request> | ||
419 | |||
420 | <event name="popup_done"> | ||
421 | <description summary="popup interaction is done"> | ||
422 | The popup_done event is sent out when a popup grab is broken, | ||
423 | that is, when the users clicks a surface that doesn't belong | ||
424 | to the client owning the popup surface. | ||
425 | </description> | ||
426 | <arg name="serial" type="uint" summary="serial of the implicit grab on the pointer"/> | ||
427 | </event> | ||
428 | |||
429 | </interface> | ||
430 | </protocol> | ||
diff --git a/sway/commands.c b/sway/commands.c index 90544220..8156a08e 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -72,23 +72,23 @@ void apply_input_config(struct input_config *input) { | |||
72 | list_add(config->input_configs, input); | 72 | list_add(config->input_configs, input); |
73 | } | 73 | } |
74 | 74 | ||
75 | sway_input_manager_apply_input_config(input_manager, input); | 75 | input_manager_apply_input_config(input_manager, input); |
76 | } | 76 | } |
77 | 77 | ||
78 | void apply_seat_config(struct seat_config *seat) { | 78 | void apply_seat_config(struct seat_config *seat_config) { |
79 | int i; | 79 | int i; |
80 | i = list_seq_find(config->seat_configs, seat_name_cmp, seat->name); | 80 | i = list_seq_find(config->seat_configs, seat_name_cmp, seat_config->name); |
81 | if (i >= 0) { | 81 | if (i >= 0) { |
82 | // merge existing config | 82 | // merge existing config |
83 | struct seat_config *sc = config->seat_configs->items[i]; | 83 | struct seat_config *sc = config->seat_configs->items[i]; |
84 | merge_seat_config(sc, seat); | 84 | merge_seat_config(sc, seat_config); |
85 | free_seat_config(seat); | 85 | free_seat_config(seat_config); |
86 | seat = sc; | 86 | seat_config = sc; |
87 | } else { | 87 | } else { |
88 | list_add(config->seat_configs, seat); | 88 | list_add(config->seat_configs, seat_config); |
89 | } | 89 | } |
90 | 90 | ||
91 | sway_input_manager_apply_seat_config(input_manager, seat); | 91 | input_manager_apply_seat_config(input_manager, seat_config); |
92 | } | 92 | } |
93 | 93 | ||
94 | /* Keep alphabetized */ | 94 | /* Keep alphabetized */ |
@@ -162,7 +162,12 @@ static struct cmd_handler command_handlers[] = { | |||
162 | { "focus", cmd_focus }, | 162 | { "focus", cmd_focus }, |
163 | { "kill", cmd_kill }, | 163 | { "kill", cmd_kill }, |
164 | { "layout", cmd_layout }, | 164 | { "layout", cmd_layout }, |
165 | { "move", cmd_move }, | ||
165 | { "reload", cmd_reload }, | 166 | { "reload", cmd_reload }, |
167 | { "split", cmd_split }, | ||
168 | { "splith", cmd_splith }, | ||
169 | { "splitt", cmd_splitt }, | ||
170 | { "splitv", cmd_splitv }, | ||
166 | }; | 171 | }; |
167 | 172 | ||
168 | static int handler_compare(const void *_a, const void *_b) { | 173 | static int handler_compare(const void *_a, const void *_b) { |
@@ -262,7 +267,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { | |||
262 | 267 | ||
263 | if (seat == NULL) { | 268 | if (seat == NULL) { |
264 | // passing a NULL seat means we just pick the default seat | 269 | // passing a NULL seat means we just pick the default seat |
265 | seat = sway_input_manager_get_default_seat(input_manager); | 270 | seat = input_manager_get_default_seat(input_manager); |
266 | if (!sway_assert(seat, "could not find a seat to run the command on")) { | 271 | if (!sway_assert(seat, "could not find a seat to run the command on")) { |
267 | return NULL; | 272 | return NULL; |
268 | } | 273 | } |
@@ -340,7 +345,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { | |||
340 | // without criteria, the command acts upon the focused | 345 | // without criteria, the command acts upon the focused |
341 | // container | 346 | // container |
342 | config->handler_context.current_container = | 347 | config->handler_context.current_container = |
343 | sway_seat_get_focus_inactive(seat, &root_container); | 348 | seat_get_focus_inactive(seat, &root_container); |
344 | if (!sway_assert(config->handler_context.current_container, | 349 | if (!sway_assert(config->handler_context.current_container, |
345 | "could not get focus-inactive for root container")) { | 350 | "could not get focus-inactive for root container")) { |
346 | return NULL; | 351 | return NULL; |
diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 64f079f4..74d9d535 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c | |||
@@ -20,10 +20,6 @@ static bool parse_movement_direction(const char *name, | |||
20 | *out = MOVE_PARENT; | 20 | *out = MOVE_PARENT; |
21 | } else if (strcasecmp(name, "child") == 0) { | 21 | } else if (strcasecmp(name, "child") == 0) { |
22 | *out = MOVE_CHILD; | 22 | *out = MOVE_CHILD; |
23 | } else if (strcasecmp(name, "next") == 0) { | ||
24 | *out = MOVE_NEXT; | ||
25 | } else if (strcasecmp(name, "prev") == 0) { | ||
26 | *out = MOVE_PREV; | ||
27 | } else { | 23 | } else { |
28 | return false; | 24 | return false; |
29 | } | 25 | } |
@@ -40,7 +36,7 @@ struct cmd_results *cmd_focus(int argc, char **argv) { | |||
40 | } | 36 | } |
41 | 37 | ||
42 | if (argc == 0) { | 38 | if (argc == 0) { |
43 | sway_seat_set_focus(seat, con); | 39 | seat_set_focus(seat, con); |
44 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 40 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
45 | } | 41 | } |
46 | 42 | ||
@@ -51,9 +47,10 @@ struct cmd_results *cmd_focus(int argc, char **argv) { | |||
51 | "Expected 'focus <direction|parent|child|mode_toggle>' or 'focus output <direction|name>'"); | 47 | "Expected 'focus <direction|parent|child|mode_toggle>' or 'focus output <direction|name>'"); |
52 | } | 48 | } |
53 | 49 | ||
54 | struct sway_container *next_focus = container_get_in_direction(con, seat, direction); | 50 | struct sway_container *next_focus = container_get_in_direction( |
51 | con, seat, direction); | ||
55 | if (next_focus) { | 52 | if (next_focus) { |
56 | sway_seat_set_focus(seat, next_focus); | 53 | seat_set_focus(seat, next_focus); |
57 | } | 54 | } |
58 | 55 | ||
59 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 56 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/kill.c b/sway/commands/kill.c index f6774767..46d6e98e 100644 --- a/sway/commands/kill.c +++ b/sway/commands/kill.c | |||
@@ -3,21 +3,28 @@ | |||
3 | #include "sway/input/input-manager.h" | 3 | #include "sway/input/input-manager.h" |
4 | #include "sway/input/seat.h" | 4 | #include "sway/input/seat.h" |
5 | #include "sway/tree/view.h" | 5 | #include "sway/tree/view.h" |
6 | #include "sway/tree/container.h" | ||
6 | #include "sway/commands.h" | 7 | #include "sway/commands.h" |
7 | 8 | ||
8 | struct cmd_results *cmd_kill(int argc, char **argv) { | 9 | struct cmd_results *cmd_kill(int argc, char **argv) { |
9 | enum sway_container_type type = config->handler_context.current_container->type; | 10 | struct sway_container *con = |
10 | if (type != C_VIEW && type != C_CONTAINER) { | 11 | config->handler_context.current_container; |
12 | |||
13 | switch (con->type) { | ||
14 | case C_ROOT: | ||
15 | case C_OUTPUT: | ||
16 | case C_WORKSPACE: | ||
17 | case C_TYPES: | ||
11 | return cmd_results_new(CMD_INVALID, NULL, | 18 | return cmd_results_new(CMD_INVALID, NULL, |
12 | "Can only kill views and containers with this command"); | 19 | "Can only kill views and containers with this command"); |
13 | } | 20 | break; |
14 | 21 | case C_CONTAINER: | |
15 | // TODO close arbitrary containers without a view | 22 | con = container_destroy(con); |
16 | struct sway_view *view = | 23 | arrange_windows(con, -1, -1); |
17 | config->handler_context.current_container->sway_view; | 24 | break; |
18 | 25 | case C_VIEW: | |
19 | if (view) { | 26 | view_close(con->sway_view); |
20 | view_close(view); | 27 | break; |
21 | } | 28 | } |
22 | 29 | ||
23 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 30 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/move.c b/sway/commands/move.c new file mode 100644 index 00000000..644c622b --- /dev/null +++ b/sway/commands/move.c | |||
@@ -0,0 +1,184 @@ | |||
1 | #include <string.h> | ||
2 | #include <strings.h> | ||
3 | #include <wlr/types/wlr_output.h> | ||
4 | #include <wlr/types/wlr_output_layout.h> | ||
5 | #include <wlr/util/log.h> | ||
6 | #include "sway/commands.h" | ||
7 | #include "sway/input/seat.h" | ||
8 | #include "sway/output.h" | ||
9 | #include "sway/tree/container.h" | ||
10 | #include "sway/tree/layout.h" | ||
11 | #include "sway/tree/workspace.h" | ||
12 | #include "stringop.h" | ||
13 | #include "list.h" | ||
14 | |||
15 | static const char* expected_syntax = | ||
16 | "Expected 'move <left|right|up|down> <[px] px>' or " | ||
17 | "'move <container|window> to workspace <name>' or " | ||
18 | "'move <container|window|workspace> to output <name|direction>' or " | ||
19 | "'move position mouse'"; | ||
20 | |||
21 | static struct sway_container *output_in_direction(const char *direction, | ||
22 | struct wlr_output *reference, int ref_ox, int ref_oy) { | ||
23 | int ref_lx = ref_ox + reference->lx, | ||
24 | ref_ly = ref_oy + reference->ly; | ||
25 | struct { | ||
26 | char *name; | ||
27 | enum wlr_direction direction; | ||
28 | } names[] = { | ||
29 | { "up", WLR_DIRECTION_UP }, | ||
30 | { "down", WLR_DIRECTION_DOWN }, | ||
31 | { "left", WLR_DIRECTION_LEFT }, | ||
32 | { "right", WLR_DIRECTION_RIGHT }, | ||
33 | }; | ||
34 | for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); ++i) { | ||
35 | if (strcasecmp(names[i].name, direction) == 0) { | ||
36 | struct wlr_output *adjacent = wlr_output_layout_adjacent_output( | ||
37 | root_container.sway_root->output_layout, | ||
38 | names[i].direction, reference, ref_lx, ref_ly); | ||
39 | if (adjacent) { | ||
40 | struct sway_output *sway_output = adjacent->data; | ||
41 | return sway_output->swayc; | ||
42 | } | ||
43 | break; | ||
44 | } | ||
45 | } | ||
46 | return output_by_name(direction); | ||
47 | } | ||
48 | |||
49 | static struct cmd_results *cmd_move_container(struct sway_container *current, | ||
50 | int argc, char **argv) { | ||
51 | struct cmd_results *error = NULL; | ||
52 | if ((error = checkarg(argc, "move container/window", | ||
53 | EXPECTED_AT_LEAST, 4))) { | ||
54 | return error; | ||
55 | } else if (strcasecmp(argv[1], "to") == 0 | ||
56 | && strcasecmp(argv[2], "workspace") == 0) { | ||
57 | // move container to workspace x | ||
58 | if (current->type == C_WORKSPACE) { | ||
59 | // TODO: Wrap children in a container and move that | ||
60 | return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); | ||
61 | } else if (current->type != C_CONTAINER && current->type != C_VIEW) { | ||
62 | return cmd_results_new(CMD_FAILURE, "move", | ||
63 | "Can only move containers and views."); | ||
64 | } | ||
65 | struct sway_container *ws; | ||
66 | const char *num_name = NULL; | ||
67 | char *ws_name = NULL; | ||
68 | if (argc == 5 && strcasecmp(argv[3], "number") == 0) { | ||
69 | // move "container to workspace number x" | ||
70 | num_name = argv[4]; | ||
71 | ws = workspace_by_number(num_name); | ||
72 | } else { | ||
73 | ws_name = join_args(argv + 3, argc - 3); | ||
74 | ws = workspace_by_name(ws_name); | ||
75 | } | ||
76 | if (!ws) { | ||
77 | ws = workspace_create(ws_name ? ws_name : num_name); | ||
78 | } | ||
79 | free(ws_name); | ||
80 | struct sway_container *old_parent = current->parent; | ||
81 | struct sway_container *focus = seat_get_focus_inactive( | ||
82 | config->handler_context.seat, ws); | ||
83 | container_move_to(current, focus); | ||
84 | seat_set_focus(config->handler_context.seat, old_parent); | ||
85 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
86 | } else if (strcasecmp(argv[1], "to") == 0 | ||
87 | && strcasecmp(argv[2], "output") == 0) { | ||
88 | if (current->type == C_WORKSPACE) { | ||
89 | // TODO: Wrap children in a container and move that | ||
90 | return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); | ||
91 | } else if (current->type != C_CONTAINER | ||
92 | && current->type != C_VIEW) { | ||
93 | return cmd_results_new(CMD_FAILURE, "move", | ||
94 | "Can only move containers and views."); | ||
95 | } | ||
96 | struct sway_container *source = container_parent(current, C_OUTPUT); | ||
97 | struct sway_container *destination = output_in_direction(argv[3], | ||
98 | source->sway_output->wlr_output, current->x, current->y); | ||
99 | if (!destination) { | ||
100 | return cmd_results_new(CMD_FAILURE, "move workspace", | ||
101 | "Can't find output with name/direction '%s'", argv[3]); | ||
102 | } | ||
103 | struct sway_container *focus = seat_get_focus_inactive( | ||
104 | config->handler_context.seat, destination); | ||
105 | if (!focus) { | ||
106 | // We've never been to this output before | ||
107 | focus = destination->children->items[0]; | ||
108 | } | ||
109 | struct sway_container *old_parent = current->parent; | ||
110 | container_move_to(current, focus); | ||
111 | seat_set_focus(config->handler_context.seat, old_parent); | ||
112 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
113 | } | ||
114 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | ||
115 | } | ||
116 | |||
117 | static struct cmd_results *cmd_move_workspace(struct sway_container *current, | ||
118 | int argc, char **argv) { | ||
119 | struct cmd_results *error = NULL; | ||
120 | if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 4))) { | ||
121 | return error; | ||
122 | } else if (strcasecmp(argv[1], "to") != 0 | ||
123 | || strcasecmp(argv[2], "output") != 0) { | ||
124 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | ||
125 | } | ||
126 | struct sway_container *source = container_parent(current, C_OUTPUT); | ||
127 | int center_x = current->width / 2 + current->x, | ||
128 | center_y = current->height / 2 + current->y; | ||
129 | struct sway_container *destination = output_in_direction(argv[3], | ||
130 | source->sway_output->wlr_output, center_x, center_y); | ||
131 | if (!destination) { | ||
132 | return cmd_results_new(CMD_FAILURE, "move workspace", | ||
133 | "Can't find output with name/direction '%s'", argv[3]); | ||
134 | } | ||
135 | if (current->type != C_WORKSPACE) { | ||
136 | current = container_parent(current, C_WORKSPACE); | ||
137 | } | ||
138 | container_move_to(current, destination); | ||
139 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
140 | } | ||
141 | |||
142 | struct cmd_results *cmd_move(int argc, char **argv) { | ||
143 | struct cmd_results *error = NULL; | ||
144 | int move_amt = 10; | ||
145 | if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { | ||
146 | return error; | ||
147 | } | ||
148 | struct sway_container *current = config->handler_context.current_container; | ||
149 | |||
150 | if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0)) { | ||
151 | char *inv; | ||
152 | move_amt = (int)strtol(argv[1], &inv, 10); | ||
153 | if (*inv != '\0' && strcasecmp(inv, "px") != 0) { | ||
154 | return cmd_results_new(CMD_FAILURE, "move", | ||
155 | "Invalid distance specified"); | ||
156 | } | ||
157 | } | ||
158 | |||
159 | if (strcasecmp(argv[0], "left") == 0) { | ||
160 | container_move(current, MOVE_LEFT, move_amt); | ||
161 | } else if (strcasecmp(argv[0], "right") == 0) { | ||
162 | container_move(current, MOVE_RIGHT, move_amt); | ||
163 | } else if (strcasecmp(argv[0], "up") == 0) { | ||
164 | container_move(current, MOVE_UP, move_amt); | ||
165 | } else if (strcasecmp(argv[0], "down") == 0) { | ||
166 | container_move(current, MOVE_DOWN, move_amt); | ||
167 | } else if (strcasecmp(argv[0], "container") == 0 | ||
168 | || strcasecmp(argv[0], "window") == 0) { | ||
169 | return cmd_move_container(current, argc, argv); | ||
170 | } else if (strcasecmp(argv[0], "workspace") == 0) { | ||
171 | return cmd_move_workspace(current, argc, argv); | ||
172 | } else if (strcasecmp(argv[0], "scratchpad") == 0 | ||
173 | || (strcasecmp(argv[0], "to") == 0 | ||
174 | && strcasecmp(argv[1], "scratchpad") == 0)) { | ||
175 | // TODO: scratchpad | ||
176 | return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); | ||
177 | } else if (strcasecmp(argv[0], "position") == 0) { | ||
178 | // TODO: floating | ||
179 | return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); | ||
180 | } else { | ||
181 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | ||
182 | } | ||
183 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
184 | } | ||
diff --git a/sway/commands/seat.c b/sway/commands/seat.c index 45079616..819b769c 100644 --- a/sway/commands/seat.c +++ b/sway/commands/seat.c | |||
@@ -14,7 +14,8 @@ struct cmd_results *cmd_seat(int argc, char **argv) { | |||
14 | free_seat_config(config->handler_context.seat_config); | 14 | free_seat_config(config->handler_context.seat_config); |
15 | config->handler_context.seat_config = new_seat_config(argv[0]); | 15 | config->handler_context.seat_config = new_seat_config(argv[0]); |
16 | if (!config->handler_context.seat_config) { | 16 | if (!config->handler_context.seat_config) { |
17 | return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config"); | 17 | return cmd_results_new(CMD_FAILURE, NULL, |
18 | "Couldn't allocate config"); | ||
18 | } | 19 | } |
19 | wlr_log(L_DEBUG, "entering seat block: %s", argv[0]); | 20 | wlr_log(L_DEBUG, "entering seat block: %s", argv[0]); |
20 | return cmd_results_new(CMD_BLOCK_SEAT, NULL, NULL); | 21 | return cmd_results_new(CMD_BLOCK_SEAT, NULL, NULL); |
@@ -28,7 +29,8 @@ struct cmd_results *cmd_seat(int argc, char **argv) { | |||
28 | if (!has_context) { | 29 | if (!has_context) { |
29 | config->handler_context.seat_config = new_seat_config(argv[0]); | 30 | config->handler_context.seat_config = new_seat_config(argv[0]); |
30 | if (!config->handler_context.seat_config) { | 31 | if (!config->handler_context.seat_config) { |
31 | return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config"); | 32 | return cmd_results_new(CMD_FAILURE, NULL, |
33 | "Couldn't allocate config"); | ||
32 | } | 34 | } |
33 | } | 35 | } |
34 | 36 | ||
@@ -41,7 +43,10 @@ struct cmd_results *cmd_seat(int argc, char **argv) { | |||
41 | } else if (strcasecmp("fallback", argv[1]) == 0) { | 43 | } else if (strcasecmp("fallback", argv[1]) == 0) { |
42 | res = seat_cmd_fallback(argc_new, argv_new); | 44 | res = seat_cmd_fallback(argc_new, argv_new); |
43 | } else { | 45 | } else { |
44 | res = cmd_results_new(CMD_INVALID, "seat <name>", "Unknown command %s", argv[1]); | 46 | res = |
47 | cmd_results_new(CMD_INVALID, | ||
48 | "seat <name>", "Unknown command %s", | ||
49 | argv[1]); | ||
45 | } | 50 | } |
46 | 51 | ||
47 | if (!has_context) { | 52 | if (!has_context) { |
diff --git a/sway/commands/split.c b/sway/commands/split.c new file mode 100644 index 00000000..ab8565a9 --- /dev/null +++ b/sway/commands/split.c | |||
@@ -0,0 +1,76 @@ | |||
1 | #include <string.h> | ||
2 | #include <strings.h> | ||
3 | #include "sway/commands.h" | ||
4 | #include "sway/tree/container.h" | ||
5 | #include "sway/tree/layout.h" | ||
6 | #include "sway/tree/view.h" | ||
7 | #include "sway/input/input-manager.h" | ||
8 | #include "sway/input/seat.h" | ||
9 | #include "log.h" | ||
10 | |||
11 | static struct cmd_results *do_split(int layout) { | ||
12 | struct sway_container *con = config->handler_context.current_container; | ||
13 | struct sway_container *parent = container_split(con, layout); | ||
14 | arrange_windows(parent, -1, -1); | ||
15 | |||
16 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
17 | } | ||
18 | |||
19 | struct cmd_results *cmd_split(int argc, char **argv) { | ||
20 | struct cmd_results *error = NULL; | ||
21 | if ((error = checkarg(argc, "split", EXPECTED_EQUAL_TO, 1))) { | ||
22 | return error; | ||
23 | } | ||
24 | if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) { | ||
25 | do_split(L_VERT); | ||
26 | } else if (strcasecmp(argv[0], "h") == 0 || | ||
27 | strcasecmp(argv[0], "horizontal") == 0) { | ||
28 | do_split(L_HORIZ); | ||
29 | } else if (strcasecmp(argv[0], "t") == 0 || | ||
30 | strcasecmp(argv[0], "toggle") == 0) { | ||
31 | struct sway_container *focused = | ||
32 | config->handler_context.current_container; | ||
33 | |||
34 | if (focused->parent->layout == L_VERT) { | ||
35 | do_split(L_HORIZ); | ||
36 | } else { | ||
37 | do_split(L_VERT); | ||
38 | } | ||
39 | } else { | ||
40 | error = cmd_results_new(CMD_FAILURE, "split", | ||
41 | "Invalid split command (expected either horizontal or vertical)."); | ||
42 | return error; | ||
43 | } | ||
44 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
45 | } | ||
46 | |||
47 | struct cmd_results *cmd_splitv(int argc, char **argv) { | ||
48 | struct cmd_results *error = NULL; | ||
49 | if ((error = checkarg(argc, "splitv", EXPECTED_EQUAL_TO, 0))) { | ||
50 | return error; | ||
51 | } | ||
52 | return do_split(L_VERT); | ||
53 | } | ||
54 | |||
55 | struct cmd_results *cmd_splith(int argc, char **argv) { | ||
56 | struct cmd_results *error = NULL; | ||
57 | if ((error = checkarg(argc, "splitv", EXPECTED_EQUAL_TO, 0))) { | ||
58 | return error; | ||
59 | } | ||
60 | return do_split(L_HORIZ); | ||
61 | } | ||
62 | |||
63 | struct cmd_results *cmd_splitt(int argc, char **argv) { | ||
64 | struct cmd_results *error = NULL; | ||
65 | if ((error = checkarg(argc, "splitv", EXPECTED_EQUAL_TO, 0))) { | ||
66 | return error; | ||
67 | } | ||
68 | |||
69 | struct sway_container *con = config->handler_context.current_container; | ||
70 | |||
71 | if (con->parent->layout == L_VERT) { | ||
72 | return do_split(L_HORIZ); | ||
73 | } else { | ||
74 | return do_split(L_VERT); | ||
75 | } | ||
76 | } | ||
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index 8f39e5fc..aa4096f7 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c | |||
@@ -91,7 +91,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
91 | } | 91 | } |
92 | workspace_switch(ws); | 92 | workspace_switch(ws); |
93 | current_container = | 93 | current_container = |
94 | sway_seat_get_focus(config->handler_context.seat); | 94 | seat_get_focus(config->handler_context.seat); |
95 | struct sway_container *new_output = container_parent(current_container, C_OUTPUT); | 95 | struct sway_container *new_output = container_parent(current_container, C_OUTPUT); |
96 | 96 | ||
97 | if (config->mouse_warping && old_output != new_output) { | 97 | if (config->mouse_warping && old_output != new_output) { |
diff --git a/sway/config.c b/sway/config.c index 0eecf7f6..90b833ab 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -125,7 +125,7 @@ static void destroy_removed_seats(struct sway_config *old_config, | |||
125 | seat_name_cmp, seat_config->name) < 0) { | 125 | seat_name_cmp, seat_config->name) < 0) { |
126 | seat = input_manager_get_seat(input_manager, | 126 | seat = input_manager_get_seat(input_manager, |
127 | seat_config->name); | 127 | seat_config->name); |
128 | sway_seat_destroy(seat); | 128 | seat_destroy(seat); |
129 | } | 129 | } |
130 | } | 130 | } |
131 | } | 131 | } |
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index c18f51c7..3c7b45f7 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c | |||
@@ -7,6 +7,8 @@ | |||
7 | #include <wlr/types/wlr_output_damage.h> | 7 | #include <wlr/types/wlr_output_damage.h> |
8 | #include <wlr/types/wlr_output.h> | 8 | #include <wlr/types/wlr_output.h> |
9 | #include <wlr/util/log.h> | 9 | #include <wlr/util/log.h> |
10 | #include "sway/input/input-manager.h" | ||
11 | #include "sway/input/seat.h" | ||
10 | #include "sway/layers.h" | 12 | #include "sway/layers.h" |
11 | #include "sway/output.h" | 13 | #include "sway/output.h" |
12 | #include "sway/server.h" | 14 | #include "sway/server.h" |
@@ -187,6 +189,31 @@ void arrange_layers(struct sway_output *output) { | |||
187 | &usable_area, false); | 189 | &usable_area, false); |
188 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], | 190 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], |
189 | &usable_area, false); | 191 | &usable_area, false); |
192 | |||
193 | // Find topmost keyboard interactive layer, if such a layer exists | ||
194 | uint32_t layers_above_shell[] = { | ||
195 | ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, | ||
196 | ZWLR_LAYER_SHELL_V1_LAYER_TOP, | ||
197 | }; | ||
198 | size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]); | ||
199 | struct sway_layer_surface *layer, *topmost = NULL; | ||
200 | for (size_t i = 0; i < nlayers; ++i) { | ||
201 | wl_list_for_each_reverse(layer, | ||
202 | &output->layers[layers_above_shell[i]], link) { | ||
203 | if (layer->layer_surface->current.keyboard_interactive) { | ||
204 | topmost = layer; | ||
205 | break; | ||
206 | } | ||
207 | } | ||
208 | if (topmost != NULL) { | ||
209 | break; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | struct sway_seat *seat; | ||
214 | wl_list_for_each(seat, &input_manager->seats, link) { | ||
215 | seat_set_focus_layer(seat, topmost ? topmost->layer_surface : NULL); | ||
216 | } | ||
190 | } | 217 | } |
191 | 218 | ||
192 | static void handle_output_destroy(struct wl_listener *listener, void *data) { | 219 | static void handle_output_destroy(struct wl_listener *listener, void *data) { |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 0d706c52..10ed1f6d 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -39,6 +39,32 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh, | |||
39 | } | 39 | } |
40 | } | 40 | } |
41 | 41 | ||
42 | /** | ||
43 | * Checks whether a surface at (lx, ly) intersects an output. If `box` is not | ||
44 | * NULL, it populates it with the surface box in the output, in output-local | ||
45 | * coordinates. | ||
46 | */ | ||
47 | static bool surface_intersect_output(struct wlr_surface *surface, | ||
48 | struct wlr_output_layout *output_layout, struct wlr_output *wlr_output, | ||
49 | double lx, double ly, float rotation, struct wlr_box *box) { | ||
50 | double ox = lx, oy = ly; | ||
51 | wlr_output_layout_output_coords(output_layout, wlr_output, &ox, &oy); | ||
52 | |||
53 | if (box != NULL) { | ||
54 | box->x = ox * wlr_output->scale; | ||
55 | box->y = oy * wlr_output->scale; | ||
56 | box->width = surface->current->width * wlr_output->scale; | ||
57 | box->height = surface->current->height * wlr_output->scale; | ||
58 | } | ||
59 | |||
60 | struct wlr_box layout_box = { | ||
61 | .x = lx, .y = ly, | ||
62 | .width = surface->current->width, .height = surface->current->height, | ||
63 | }; | ||
64 | wlr_box_rotated_bounds(&layout_box, rotation, &layout_box); | ||
65 | return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box); | ||
66 | } | ||
67 | |||
42 | static void render_surface(struct wlr_surface *surface, | 68 | static void render_surface(struct wlr_surface *surface, |
43 | struct wlr_output *wlr_output, struct timespec *when, | 69 | struct wlr_output *wlr_output, struct timespec *when, |
44 | double lx, double ly, float rotation) { | 70 | double lx, double ly, float rotation) { |
@@ -48,29 +74,21 @@ static void render_surface(struct wlr_surface *surface, | |||
48 | if (!wlr_surface_has_buffer(surface)) { | 74 | if (!wlr_surface_has_buffer(surface)) { |
49 | return; | 75 | return; |
50 | } | 76 | } |
77 | |||
51 | struct wlr_output_layout *layout = root_container.sway_root->output_layout; | 78 | struct wlr_output_layout *layout = root_container.sway_root->output_layout; |
52 | int width = surface->current->width; | 79 | |
53 | int height = surface->current->height; | 80 | struct wlr_box box; |
54 | int render_width = width * wlr_output->scale; | 81 | bool intersects = surface_intersect_output(surface, layout, wlr_output, |
55 | int render_height = height * wlr_output->scale; | 82 | lx, ly, rotation, &box); |
56 | int owidth, oheight; | 83 | if (intersects) { |
57 | wlr_output_effective_resolution(wlr_output, &owidth, &oheight); | ||
58 | |||
59 | // FIXME: view coords are inconsistently assumed to be in output or layout coords | ||
60 | struct wlr_box layout_box = { | ||
61 | .x = lx + wlr_output->lx, .y = ly + wlr_output->ly, | ||
62 | .width = render_width, .height = render_height, | ||
63 | }; | ||
64 | if (wlr_output_layout_intersects(layout, wlr_output, &layout_box)) { | ||
65 | struct wlr_box render_box = { | ||
66 | .x = lx, .y = ly, | ||
67 | .width = render_width, .height = render_height | ||
68 | }; | ||
69 | float matrix[9]; | 84 | float matrix[9]; |
70 | wlr_matrix_project_box(matrix, &render_box, surface->current->transform, | 85 | enum wl_output_transform transform = |
71 | 0, wlr_output->transform_matrix); | 86 | wlr_output_transform_invert(surface->current->transform); |
72 | wlr_render_texture_with_matrix(renderer, surface->texture, matrix, | 87 | wlr_matrix_project_box(matrix, &box, transform, rotation, |
73 | 1.0f); // TODO: configurable alpha | 88 | wlr_output->transform_matrix); |
89 | |||
90 | // TODO: configurable alpha | ||
91 | wlr_render_texture_with_matrix(renderer, surface->texture, matrix, 1.0f); | ||
74 | 92 | ||
75 | wlr_surface_send_frame_done(surface, when); | 93 | wlr_surface_send_frame_done(surface, when); |
76 | } | 94 | } |
@@ -80,9 +98,8 @@ static void render_surface(struct wlr_surface *surface, | |||
80 | struct wlr_surface_state *state = subsurface->surface->current; | 98 | struct wlr_surface_state *state = subsurface->surface->current; |
81 | double sx = state->subsurface_position.x; | 99 | double sx = state->subsurface_position.x; |
82 | double sy = state->subsurface_position.y; | 100 | double sy = state->subsurface_position.y; |
83 | double sw = state->buffer_width / state->scale; | 101 | rotate_child_position(&sx, &sy, state->width, state->height, |
84 | double sh = state->buffer_height / state->scale; | 102 | surface->current->width, surface->current->height, rotation); |
85 | rotate_child_position(&sx, &sy, sw, sh, width, height, rotation); | ||
86 | 103 | ||
87 | render_surface(subsurface->surface, wlr_output, when, | 104 | render_surface(subsurface->surface, wlr_output, when, |
88 | lx + sx, ly + sy, rotation); | 105 | lx + sx, ly + sy, rotation); |
@@ -228,10 +245,13 @@ static void render_output(struct sway_output *output, struct timespec *when, | |||
228 | 245 | ||
229 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 246 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
230 | struct sway_container *focus = | 247 | struct sway_container *focus = |
231 | sway_seat_get_focus_inactive(seat, output->swayc); | 248 | seat_get_focus_inactive(seat, output->swayc); |
232 | struct sway_container *workspace = (focus->type == C_WORKSPACE ? | 249 | if (!focus) { |
233 | focus : | 250 | // We've never been to this output before |
234 | container_parent(focus, C_WORKSPACE)); | 251 | focus = output->swayc->children->items[0]; |
252 | } | ||
253 | struct sway_container *workspace = focus->type == C_WORKSPACE ? | ||
254 | focus : container_parent(focus, C_WORKSPACE); | ||
235 | 255 | ||
236 | struct render_data rdata = { | 256 | struct render_data rdata = { |
237 | .output = output, | 257 | .output = output, |
@@ -240,15 +260,15 @@ static void render_output(struct sway_output *output, struct timespec *when, | |||
240 | container_descendants(workspace, C_VIEW, render_view, &rdata); | 260 | container_descendants(workspace, C_VIEW, render_view, &rdata); |
241 | 261 | ||
242 | // render unmanaged views on top | 262 | // render unmanaged views on top |
243 | struct sway_view *view; | 263 | struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; |
244 | wl_list_for_each(view, &root_container.sway_root->unmanaged_views, | 264 | struct sway_xwayland_unmanaged *sway_surface; |
245 | unmanaged_view_link) { | 265 | wl_list_for_each(sway_surface, unmanaged, link) { |
246 | if (view->type != SWAY_XWAYLAND_VIEW) { | 266 | struct wlr_xwayland_surface *xsurface = |
267 | sway_surface->wlr_xwayland_surface; | ||
268 | if (xsurface->surface == NULL) { | ||
247 | continue; | 269 | continue; |
248 | } | 270 | } |
249 | 271 | ||
250 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | ||
251 | |||
252 | const struct wlr_box view_box = { | 272 | const struct wlr_box view_box = { |
253 | .x = xsurface->x, | 273 | .x = xsurface->x, |
254 | .y = xsurface->y, | 274 | .y = xsurface->y, |
@@ -260,7 +280,7 @@ static void render_output(struct sway_output *output, struct timespec *when, | |||
260 | continue; | 280 | continue; |
261 | } | 281 | } |
262 | 282 | ||
263 | render_surface(view->surface, wlr_output, &output->last_frame, | 283 | render_surface(xsurface->surface, wlr_output, &output->last_frame, |
264 | view_box.x - output_box->x, view_box.y - output_box->y, 0); | 284 | view_box.x - output_box->x, view_box.y - output_box->y, 0); |
265 | } | 285 | } |
266 | 286 | ||
@@ -338,6 +358,12 @@ static void handle_transform(struct wl_listener *listener, void *data) { | |||
338 | arrange_windows(output->swayc, -1, -1); | 358 | arrange_windows(output->swayc, -1, -1); |
339 | } | 359 | } |
340 | 360 | ||
361 | static void handle_scale(struct wl_listener *listener, void *data) { | ||
362 | struct sway_output *output = wl_container_of(listener, output, scale); | ||
363 | arrange_layers(output); | ||
364 | arrange_windows(output->swayc, -1, -1); | ||
365 | } | ||
366 | |||
341 | void handle_new_output(struct wl_listener *listener, void *data) { | 367 | void handle_new_output(struct wl_listener *listener, void *data) { |
342 | struct sway_server *server = wl_container_of(listener, server, new_output); | 368 | struct sway_server *server = wl_container_of(listener, server, new_output); |
343 | struct wlr_output *wlr_output = data; | 369 | struct wlr_output *wlr_output = data; |
@@ -370,7 +396,7 @@ void handle_new_output(struct wl_listener *listener, void *data) { | |||
370 | wl_list_init(&output->layers[i]); | 396 | wl_list_init(&output->layers[i]); |
371 | } | 397 | } |
372 | 398 | ||
373 | sway_input_manager_configure_xcursor(input_manager); | 399 | input_manager_configure_xcursor(input_manager); |
374 | 400 | ||
375 | wl_signal_add(&wlr_output->events.destroy, &output->destroy); | 401 | wl_signal_add(&wlr_output->events.destroy, &output->destroy); |
376 | output->destroy.notify = handle_destroy; | 402 | output->destroy.notify = handle_destroy; |
@@ -378,6 +404,8 @@ void handle_new_output(struct wl_listener *listener, void *data) { | |||
378 | output->mode.notify = handle_mode; | 404 | output->mode.notify = handle_mode; |
379 | wl_signal_add(&wlr_output->events.transform, &output->transform); | 405 | wl_signal_add(&wlr_output->events.transform, &output->transform); |
380 | output->transform.notify = handle_transform; | 406 | output->transform.notify = handle_transform; |
407 | wl_signal_add(&wlr_output->events.scale, &output->scale); | ||
408 | output->scale.notify = handle_scale; | ||
381 | 409 | ||
382 | wl_signal_add(&output->damage->events.frame, &output->damage_frame); | 410 | wl_signal_add(&output->damage->events.frame, &output->damage_frame); |
383 | output->damage_frame.notify = damage_handle_frame; | 411 | output->damage_frame.notify = damage_handle_frame; |
diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c index 4fcc6317..6528a397 100644 --- a/sway/desktop/wl_shell.c +++ b/sway/desktop/wl_shell.c | |||
@@ -30,28 +30,18 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { | |||
30 | } | 30 | } |
31 | } | 31 | } |
32 | 32 | ||
33 | static void set_size(struct sway_view *view, int width, int height) { | 33 | static void configure(struct sway_view *view, double ox, double oy, int width, |
34 | int height) { | ||
34 | if (!assert_wl_shell(view)) { | 35 | if (!assert_wl_shell(view)) { |
35 | return; | 36 | return; |
36 | } | 37 | } |
38 | view_update_position(view, ox, oy); | ||
37 | view->sway_wl_shell_surface->pending_width = width; | 39 | view->sway_wl_shell_surface->pending_width = width; |
38 | view->sway_wl_shell_surface->pending_height = height; | 40 | view->sway_wl_shell_surface->pending_height = height; |
39 | wlr_wl_shell_surface_configure(view->wlr_wl_shell_surface, 0, width, height); | 41 | wlr_wl_shell_surface_configure(view->wlr_wl_shell_surface, 0, width, height); |
40 | } | 42 | } |
41 | 43 | ||
42 | static void set_position(struct sway_view *view, double ox, double oy) { | 44 | static void _close(struct sway_view *view) { |
43 | if (!assert_wl_shell(view)) { | ||
44 | return; | ||
45 | } | ||
46 | view->swayc->x = ox; | ||
47 | view->swayc->y = oy; | ||
48 | } | ||
49 | |||
50 | static void set_activated(struct sway_view *view, bool activated) { | ||
51 | // no way to activate wl_shell | ||
52 | } | ||
53 | |||
54 | static void close(struct sway_view *view) { | ||
55 | if (!assert_wl_shell(view)) { | 45 | if (!assert_wl_shell(view)) { |
56 | return; | 46 | return; |
57 | } | 47 | } |
@@ -59,14 +49,20 @@ static void close(struct sway_view *view) { | |||
59 | wl_client_destroy(view->wlr_wl_shell_surface->client); | 49 | wl_client_destroy(view->wlr_wl_shell_surface->client); |
60 | } | 50 | } |
61 | 51 | ||
52 | static const struct sway_view_impl view_impl = { | ||
53 | .get_prop = get_prop, | ||
54 | .configure = configure, | ||
55 | .close = _close, | ||
56 | }; | ||
57 | |||
62 | static void handle_commit(struct wl_listener *listener, void *data) { | 58 | static void handle_commit(struct wl_listener *listener, void *data) { |
63 | struct sway_wl_shell_surface *sway_surface = | 59 | struct sway_wl_shell_surface *sway_surface = |
64 | wl_container_of(listener, sway_surface, commit); | 60 | wl_container_of(listener, sway_surface, commit); |
65 | struct sway_view *view = sway_surface->view; | 61 | struct sway_view *view = sway_surface->view; |
66 | // NOTE: We intentionally discard the view's desired width here | 62 | // NOTE: We intentionally discard the view's desired width here |
67 | // TODO: Let floating views do whatever | 63 | // TODO: Let floating views do whatever |
68 | view->width = sway_surface->pending_width; | 64 | view_update_size(view, sway_surface->pending_width, |
69 | view->height = sway_surface->pending_height; | 65 | sway_surface->pending_height); |
70 | view_damage_from(view); | 66 | view_damage_from(view); |
71 | } | 67 | } |
72 | 68 | ||
@@ -75,15 +71,13 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
75 | wl_container_of(listener, sway_surface, destroy); | 71 | wl_container_of(listener, sway_surface, destroy); |
76 | wl_list_remove(&sway_surface->commit.link); | 72 | wl_list_remove(&sway_surface->commit.link); |
77 | wl_list_remove(&sway_surface->destroy.link); | 73 | wl_list_remove(&sway_surface->destroy.link); |
78 | struct sway_container *parent = container_view_destroy(sway_surface->view->swayc); | 74 | view_destroy(sway_surface->view); |
79 | free(sway_surface->view); | ||
80 | free(sway_surface); | 75 | free(sway_surface); |
81 | arrange_windows(parent, -1, -1); | ||
82 | } | 76 | } |
83 | 77 | ||
84 | void handle_wl_shell_surface(struct wl_listener *listener, void *data) { | 78 | void handle_wl_shell_surface(struct wl_listener *listener, void *data) { |
85 | struct sway_server *server = wl_container_of( | 79 | struct sway_server *server = wl_container_of(listener, server, |
86 | listener, server, wl_shell_surface); | 80 | wl_shell_surface); |
87 | struct wlr_wl_shell_surface *shell_surface = data; | 81 | struct wlr_wl_shell_surface *shell_surface = data; |
88 | 82 | ||
89 | if (shell_surface->state == WLR_WL_SHELL_SURFACE_STATE_POPUP) { | 83 | if (shell_surface->state == WLR_WL_SHELL_SURFACE_STATE_POPUP) { |
@@ -103,20 +97,13 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { | |||
103 | return; | 97 | return; |
104 | } | 98 | } |
105 | 99 | ||
106 | struct sway_view *sway_view = calloc(1, sizeof(struct sway_view)); | 100 | struct sway_view *view = view_create(SWAY_WL_SHELL_VIEW, &view_impl); |
107 | if (!sway_assert(sway_view, "Failed to allocate view!")) { | 101 | if (!sway_assert(view, "Failed to allocate view")) { |
108 | return; | 102 | return; |
109 | } | 103 | } |
110 | sway_view->type = SWAY_WL_SHELL_VIEW; | 104 | view->wlr_wl_shell_surface = shell_surface; |
111 | sway_view->iface.get_prop = get_prop; | 105 | view->sway_wl_shell_surface = sway_surface; |
112 | sway_view->iface.set_size = set_size; | 106 | sway_surface->view = view; |
113 | sway_view->iface.set_position = set_position; | ||
114 | sway_view->iface.set_activated = set_activated; | ||
115 | sway_view->iface.close = close; | ||
116 | sway_view->wlr_wl_shell_surface = shell_surface; | ||
117 | sway_view->sway_wl_shell_surface = sway_surface; | ||
118 | sway_view->surface = shell_surface->surface; | ||
119 | sway_surface->view = sway_view; | ||
120 | 107 | ||
121 | // TODO: | 108 | // TODO: |
122 | // - Wire up listeners | 109 | // - Wire up listeners |
@@ -132,11 +119,5 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { | |||
132 | sway_surface->destroy.notify = handle_destroy; | 119 | sway_surface->destroy.notify = handle_destroy; |
133 | wl_signal_add(&shell_surface->events.destroy, &sway_surface->destroy); | 120 | wl_signal_add(&shell_surface->events.destroy, &sway_surface->destroy); |
134 | 121 | ||
135 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 122 | view_map(view, shell_surface->surface); |
136 | struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container); | ||
137 | struct sway_container *cont = container_view_create(focus, sway_view); | ||
138 | sway_view->swayc = cont; | ||
139 | |||
140 | arrange_windows(cont->parent, -1, -1); | ||
141 | sway_input_manager_set_focus(input_manager, cont); | ||
142 | } | 123 | } |
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 713437f2..49305b39 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -30,23 +30,18 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { | |||
30 | } | 30 | } |
31 | } | 31 | } |
32 | 32 | ||
33 | static void set_size(struct sway_view *view, int width, int height) { | 33 | static void configure(struct sway_view *view, double ox, double oy, int width, |
34 | int height) { | ||
34 | if (!assert_xdg(view)) { | 35 | if (!assert_xdg(view)) { |
35 | return; | 36 | return; |
36 | } | 37 | } |
38 | |||
39 | view_update_position(view, ox, oy); | ||
37 | view->sway_xdg_surface_v6->pending_width = width; | 40 | view->sway_xdg_surface_v6->pending_width = width; |
38 | view->sway_xdg_surface_v6->pending_height = height; | 41 | view->sway_xdg_surface_v6->pending_height = height; |
39 | wlr_xdg_toplevel_v6_set_size(view->wlr_xdg_surface_v6, width, height); | 42 | wlr_xdg_toplevel_v6_set_size(view->wlr_xdg_surface_v6, width, height); |
40 | } | 43 | } |
41 | 44 | ||
42 | static void set_position(struct sway_view *view, double ox, double oy) { | ||
43 | if (!assert_xdg(view)) { | ||
44 | return; | ||
45 | } | ||
46 | view->swayc->x = ox; | ||
47 | view->swayc->y = oy; | ||
48 | } | ||
49 | |||
50 | static void set_activated(struct sway_view *view, bool activated) { | 45 | static void set_activated(struct sway_view *view, bool activated) { |
51 | if (!assert_xdg(view)) { | 46 | if (!assert_xdg(view)) { |
52 | return; | 47 | return; |
@@ -57,7 +52,7 @@ static void set_activated(struct sway_view *view, bool activated) { | |||
57 | } | 52 | } |
58 | } | 53 | } |
59 | 54 | ||
60 | static void close(struct sway_view *view) { | 55 | static void _close(struct sway_view *view) { |
61 | if (!assert_xdg(view)) { | 56 | if (!assert_xdg(view)) { |
62 | return; | 57 | return; |
63 | } | 58 | } |
@@ -67,6 +62,13 @@ static void close(struct sway_view *view) { | |||
67 | } | 62 | } |
68 | } | 63 | } |
69 | 64 | ||
65 | static const struct sway_view_impl view_impl = { | ||
66 | .get_prop = get_prop, | ||
67 | .configure = configure, | ||
68 | .set_activated = set_activated, | ||
69 | .close = _close, | ||
70 | }; | ||
71 | |||
70 | static void handle_commit(struct wl_listener *listener, void *data) { | 72 | static void handle_commit(struct wl_listener *listener, void *data) { |
71 | struct sway_xdg_surface_v6 *sway_surface = | 73 | struct sway_xdg_surface_v6 *sway_surface = |
72 | wl_container_of(listener, sway_surface, commit); | 74 | wl_container_of(listener, sway_surface, commit); |
@@ -74,37 +76,22 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
74 | // NOTE: We intentionally discard the view's desired width here | 76 | // NOTE: We intentionally discard the view's desired width here |
75 | // TODO: Store this for restoration when moving to floating plane | 77 | // TODO: Store this for restoration when moving to floating plane |
76 | // TODO: Let floating views do whatever | 78 | // TODO: Let floating views do whatever |
77 | view->width = sway_surface->pending_width; | 79 | view_update_size(view, sway_surface->pending_width, |
78 | view->height = sway_surface->pending_height; | 80 | sway_surface->pending_height); |
79 | view_damage_from(view); | 81 | view_damage_from(view); |
80 | } | 82 | } |
81 | 83 | ||
82 | static void handle_unmap(struct wl_listener *listener, void *data) { | 84 | static void handle_unmap(struct wl_listener *listener, void *data) { |
83 | struct sway_xdg_surface_v6 *sway_surface = | 85 | struct sway_xdg_surface_v6 *sway_surface = |
84 | wl_container_of(listener, sway_surface, unmap); | 86 | wl_container_of(listener, sway_surface, unmap); |
85 | view_damage_whole(sway_surface->view); | 87 | view_unmap(sway_surface->view); |
86 | container_view_destroy(sway_surface->view->swayc); | ||
87 | sway_surface->view->swayc = NULL; | ||
88 | sway_surface->view->surface = NULL; | ||
89 | } | 88 | } |
90 | 89 | ||
91 | static void handle_map(struct wl_listener *listener, void *data) { | 90 | static void handle_map(struct wl_listener *listener, void *data) { |
92 | struct sway_xdg_surface_v6 *sway_surface = | 91 | struct sway_xdg_surface_v6 *sway_surface = |
93 | wl_container_of(listener, sway_surface, map); | 92 | wl_container_of(listener, sway_surface, map); |
94 | struct sway_view *view = sway_surface->view; | 93 | struct sway_view *view = sway_surface->view; |
95 | 94 | view_map(view, view->wlr_xdg_surface_v6->surface); | |
96 | sway_surface->view->surface = view->wlr_xdg_surface_v6->surface; | ||
97 | |||
98 | container_view_destroy(view->swayc); | ||
99 | |||
100 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
101 | struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container); | ||
102 | struct sway_container *cont = container_view_create(focus, view); | ||
103 | view->swayc = cont; | ||
104 | arrange_windows(cont->parent, -1, -1); | ||
105 | sway_input_manager_set_focus(input_manager, cont); | ||
106 | |||
107 | view_damage_whole(sway_surface->view); | ||
108 | } | 95 | } |
109 | 96 | ||
110 | static void handle_destroy(struct wl_listener *listener, void *data) { | 97 | static void handle_destroy(struct wl_listener *listener, void *data) { |
@@ -112,8 +99,9 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
112 | wl_container_of(listener, sway_xdg_surface, destroy); | 99 | wl_container_of(listener, sway_xdg_surface, destroy); |
113 | wl_list_remove(&sway_xdg_surface->commit.link); | 100 | wl_list_remove(&sway_xdg_surface->commit.link); |
114 | wl_list_remove(&sway_xdg_surface->destroy.link); | 101 | wl_list_remove(&sway_xdg_surface->destroy.link); |
115 | container_view_destroy(sway_xdg_surface->view->swayc); | 102 | wl_list_remove(&sway_xdg_surface->map.link); |
116 | free(sway_xdg_surface->view); | 103 | wl_list_remove(&sway_xdg_surface->unmap.link); |
104 | view_destroy(sway_xdg_surface->view); | ||
117 | free(sway_xdg_surface); | 105 | free(sway_xdg_surface); |
118 | } | 106 | } |
119 | 107 | ||
@@ -138,23 +126,16 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { | |||
138 | return; | 126 | return; |
139 | } | 127 | } |
140 | 128 | ||
141 | struct sway_view *sway_view = calloc(1, sizeof(struct sway_view)); | 129 | struct sway_view *view = view_create(SWAY_XDG_SHELL_V6_VIEW, &view_impl); |
142 | if (!sway_assert(sway_view, "Failed to allocate view!")) { | 130 | if (!sway_assert(view, "Failed to allocate view")) { |
143 | return; | 131 | return; |
144 | } | 132 | } |
145 | sway_view->type = SWAY_XDG_SHELL_V6_VIEW; | 133 | view->wlr_xdg_surface_v6 = xdg_surface; |
146 | sway_view->iface.get_prop = get_prop; | 134 | view->sway_xdg_surface_v6 = sway_surface; |
147 | sway_view->iface.set_size = set_size; | 135 | sway_surface->view = view; |
148 | sway_view->iface.set_position = set_position; | ||
149 | sway_view->iface.set_activated = set_activated; | ||
150 | sway_view->iface.close = close; | ||
151 | sway_view->wlr_xdg_surface_v6 = xdg_surface; | ||
152 | sway_view->sway_xdg_surface_v6 = sway_surface; | ||
153 | sway_surface->view = sway_view; | ||
154 | 136 | ||
155 | // TODO: | 137 | // TODO: |
156 | // - Look up pid and open on appropriate workspace | 138 | // - Look up pid and open on appropriate workspace |
157 | // - Set new view to maximized so it behaves nicely | ||
158 | // - Criteria | 139 | // - Criteria |
159 | 140 | ||
160 | sway_surface->commit.notify = handle_commit; | 141 | sway_surface->commit.notify = handle_commit; |
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 273ca2bf..bfef68cf 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -14,6 +14,33 @@ | |||
14 | #include "sway/input/input-manager.h" | 14 | #include "sway/input/input-manager.h" |
15 | #include "log.h" | 15 | #include "log.h" |
16 | 16 | ||
17 | static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { | ||
18 | struct sway_xwayland_unmanaged *sway_surface = | ||
19 | wl_container_of(listener, sway_surface, destroy); | ||
20 | wl_list_remove(&sway_surface->destroy.link); | ||
21 | wl_list_remove(&sway_surface->link); | ||
22 | free(sway_surface); | ||
23 | } | ||
24 | |||
25 | static void create_unmanaged(struct wlr_xwayland_surface *xsurface) { | ||
26 | struct sway_xwayland_unmanaged *sway_surface = | ||
27 | calloc(1, sizeof(struct sway_xwayland_unmanaged)); | ||
28 | if (!sway_assert(sway_surface, "Failed to allocate surface")) { | ||
29 | return; | ||
30 | } | ||
31 | |||
32 | sway_surface->wlr_xwayland_surface = xsurface; | ||
33 | |||
34 | wl_signal_add(&xsurface->events.destroy, &sway_surface->destroy); | ||
35 | sway_surface->destroy.notify = unmanaged_handle_destroy; | ||
36 | |||
37 | wl_list_insert(&root_container.sway_root->xwayland_unmanaged, | ||
38 | &sway_surface->link); | ||
39 | |||
40 | // TODO: damage tracking | ||
41 | } | ||
42 | |||
43 | |||
17 | static bool assert_xwayland(struct sway_view *view) { | 44 | static bool assert_xwayland(struct sway_view *view) { |
18 | return sway_assert(view->type == SWAY_XWAYLAND_VIEW, | 45 | return sway_assert(view->type == SWAY_XWAYLAND_VIEW, |
19 | "Expected xwayland view!"); | 46 | "Expected xwayland view!"); |
@@ -33,22 +60,13 @@ static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { | |||
33 | } | 60 | } |
34 | } | 61 | } |
35 | 62 | ||
36 | static void set_size(struct sway_view *view, int width, int height) { | 63 | static void configure(struct sway_view *view, double ox, double oy, int width, |
64 | int height) { | ||
37 | if (!assert_xwayland(view)) { | 65 | if (!assert_xwayland(view)) { |
38 | return; | 66 | return; |
39 | } | 67 | } |
40 | view->sway_xwayland_surface->pending_width = width; | ||
41 | view->sway_xwayland_surface->pending_height = height; | ||
42 | |||
43 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 68 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
44 | wlr_xwayland_surface_configure(xsurface, xsurface->x, xsurface->y, | ||
45 | width, height); | ||
46 | } | ||
47 | 69 | ||
48 | static void set_position(struct sway_view *view, double ox, double oy) { | ||
49 | if (!assert_xwayland(view)) { | ||
50 | return; | ||
51 | } | ||
52 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | 70 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); |
53 | if (!sway_assert(output, "view must be within tree to set position")) { | 71 | if (!sway_assert(output, "view must be within tree to set position")) { |
54 | return; | 72 | return; |
@@ -64,13 +82,12 @@ static void set_position(struct sway_view *view, double ox, double oy) { | |||
64 | return; | 82 | return; |
65 | } | 83 | } |
66 | 84 | ||
67 | view->swayc->x = ox; | 85 | view_update_position(view, ox, oy); |
68 | view->swayc->y = oy; | ||
69 | 86 | ||
70 | wlr_xwayland_surface_configure(view->wlr_xwayland_surface, | 87 | view->sway_xwayland_surface->pending_width = width; |
71 | ox + loutput->x, oy + loutput->y, | 88 | view->sway_xwayland_surface->pending_height = height; |
72 | view->wlr_xwayland_surface->width, | 89 | wlr_xwayland_surface_configure(xsurface, ox + loutput->x, oy + loutput->y, |
73 | view->wlr_xwayland_surface->height); | 90 | width, height); |
74 | } | 91 | } |
75 | 92 | ||
76 | static void set_activated(struct sway_view *view, bool activated) { | 93 | static void set_activated(struct sway_view *view, bool activated) { |
@@ -81,77 +98,58 @@ static void set_activated(struct sway_view *view, bool activated) { | |||
81 | wlr_xwayland_surface_activate(surface, activated); | 98 | wlr_xwayland_surface_activate(surface, activated); |
82 | } | 99 | } |
83 | 100 | ||
84 | static void close_view(struct sway_view *view) { | 101 | static void _close(struct sway_view *view) { |
85 | if (!assert_xwayland(view)) { | 102 | if (!assert_xwayland(view)) { |
86 | return; | 103 | return; |
87 | } | 104 | } |
88 | wlr_xwayland_surface_close(view->wlr_xwayland_surface); | 105 | wlr_xwayland_surface_close(view->wlr_xwayland_surface); |
89 | } | 106 | } |
90 | 107 | ||
108 | static const struct sway_view_impl view_impl = { | ||
109 | .get_prop = get_prop, | ||
110 | .configure = configure, | ||
111 | .set_activated = set_activated, | ||
112 | .close = _close, | ||
113 | }; | ||
114 | |||
91 | static void handle_commit(struct wl_listener *listener, void *data) { | 115 | static void handle_commit(struct wl_listener *listener, void *data) { |
92 | struct sway_xwayland_surface *sway_surface = | 116 | struct sway_xwayland_surface *sway_surface = |
93 | wl_container_of(listener, sway_surface, commit); | 117 | wl_container_of(listener, sway_surface, commit); |
94 | struct sway_view *view = sway_surface->view; | 118 | struct sway_view *view = sway_surface->view; |
95 | // NOTE: We intentionally discard the view's desired width here | 119 | // NOTE: We intentionally discard the view's desired width here |
96 | // TODO: Let floating views do whatever | 120 | // TODO: Let floating views do whatever |
97 | view->width = sway_surface->pending_width; | 121 | view_update_size(view, sway_surface->pending_width, |
98 | view->height = sway_surface->pending_height; | 122 | sway_surface->pending_height); |
99 | view_damage_from(view); | 123 | view_damage_from(view); |
100 | } | 124 | } |
101 | 125 | ||
102 | static void handle_destroy(struct wl_listener *listener, void *data) { | 126 | static void handle_destroy(struct wl_listener *listener, void *data) { |
103 | struct sway_xwayland_surface *sway_surface = | 127 | struct sway_xwayland_surface *sway_surface = |
104 | wl_container_of(listener, sway_surface, destroy); | 128 | wl_container_of(listener, sway_surface, destroy); |
105 | |||
106 | wl_list_remove(&sway_surface->commit.link); | 129 | wl_list_remove(&sway_surface->commit.link); |
107 | wl_list_remove(&sway_surface->destroy.link); | 130 | wl_list_remove(&sway_surface->destroy.link); |
108 | wl_list_remove(&sway_surface->request_configure.link); | 131 | wl_list_remove(&sway_surface->request_configure.link); |
109 | wl_list_remove(&sway_surface->view->unmanaged_view_link); | 132 | wl_list_remove(&sway_surface->map.link); |
110 | container_view_destroy(sway_surface->view->swayc); | 133 | wl_list_remove(&sway_surface->unmap.link); |
111 | sway_surface->view->swayc = NULL; | 134 | view_destroy(sway_surface->view); |
112 | sway_surface->view->surface = NULL; | 135 | free(sway_surface); |
113 | } | 136 | } |
114 | 137 | ||
115 | static void handle_unmap(struct wl_listener *listener, void *data) { | 138 | static void handle_unmap(struct wl_listener *listener, void *data) { |
116 | struct sway_xwayland_surface *sway_surface = | 139 | struct sway_xwayland_surface *sway_surface = |
117 | wl_container_of(listener, sway_surface, unmap); | 140 | wl_container_of(listener, sway_surface, unmap); |
118 | view_damage_whole(sway_surface->view); | 141 | view_unmap(sway_surface->view); |
119 | wl_list_remove(&sway_surface->view->unmanaged_view_link); | ||
120 | wl_list_init(&sway_surface->view->unmanaged_view_link); | ||
121 | container_view_destroy(sway_surface->view->swayc); | ||
122 | sway_surface->view->swayc = NULL; | ||
123 | sway_surface->view->surface = NULL; | ||
124 | } | 142 | } |
125 | 143 | ||
126 | static void handle_map(struct wl_listener *listener, void *data) { | 144 | static void handle_map(struct wl_listener *listener, void *data) { |
127 | struct sway_xwayland_surface *sway_surface = | 145 | struct sway_xwayland_surface *sway_surface = |
128 | wl_container_of(listener, sway_surface, map); | 146 | wl_container_of(listener, sway_surface, map); |
129 | struct wlr_xwayland_surface *xsurface = data; | 147 | struct wlr_xwayland_surface *xsurface = data; |
130 | 148 | struct sway_view *view = sway_surface->view; | |
131 | sway_surface->view->surface = xsurface->surface; | ||
132 | 149 | ||
133 | // put it back into the tree | 150 | // put it back into the tree |
134 | if (wlr_xwayland_surface_is_unmanaged(xsurface) || | 151 | wlr_xwayland_surface_set_maximized(xsurface, true); |
135 | xsurface->override_redirect) { | 152 | view_map(view, xsurface->surface); |
136 | wl_list_remove(&sway_surface->view->unmanaged_view_link); | ||
137 | wl_list_insert(&root_container.sway_root->unmanaged_views, | ||
138 | &sway_surface->view->unmanaged_view_link); | ||
139 | } else { | ||
140 | struct sway_view *view = sway_surface->view; | ||
141 | container_view_destroy(view->swayc); | ||
142 | |||
143 | wlr_xwayland_surface_set_maximized(xsurface, true); | ||
144 | |||
145 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
146 | struct sway_container *focus = sway_seat_get_focus_inactive(seat, | ||
147 | &root_container); | ||
148 | struct sway_container *cont = container_view_create(focus, view); | ||
149 | view->swayc = cont; | ||
150 | arrange_windows(cont->parent, -1, -1); | ||
151 | sway_input_manager_set_focus(input_manager, cont); | ||
152 | } | ||
153 | |||
154 | view_damage_whole(sway_surface->view); | ||
155 | } | 153 | } |
156 | 154 | ||
157 | static void handle_request_configure(struct wl_listener *listener, void *data) { | 155 | static void handle_request_configure(struct wl_listener *listener, void *data) { |
@@ -171,34 +169,32 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { | |||
171 | listener, server, xwayland_surface); | 169 | listener, server, xwayland_surface); |
172 | struct wlr_xwayland_surface *xsurface = data; | 170 | struct wlr_xwayland_surface *xsurface = data; |
173 | 171 | ||
172 | if (wlr_xwayland_surface_is_unmanaged(xsurface) || | ||
173 | xsurface->override_redirect) { | ||
174 | wlr_log(L_DEBUG, "New xwayland unmanaged surface"); | ||
175 | create_unmanaged(xsurface); | ||
176 | return; | ||
177 | } | ||
178 | |||
174 | wlr_log(L_DEBUG, "New xwayland surface title='%s' class='%s'", | 179 | wlr_log(L_DEBUG, "New xwayland surface title='%s' class='%s'", |
175 | xsurface->title, xsurface->class); | 180 | xsurface->title, xsurface->class); |
176 | 181 | ||
177 | struct sway_xwayland_surface *sway_surface = | 182 | struct sway_xwayland_surface *sway_surface = |
178 | calloc(1, sizeof(struct sway_xwayland_surface)); | 183 | calloc(1, sizeof(struct sway_xwayland_surface)); |
179 | if (!sway_assert(sway_surface, "Failed to allocate surface!")) { | 184 | if (!sway_assert(sway_surface, "Failed to allocate surface")) { |
180 | return; | 185 | return; |
181 | } | 186 | } |
182 | 187 | ||
183 | struct sway_view *sway_view = calloc(1, sizeof(struct sway_view)); | 188 | struct sway_view *view = view_create(SWAY_XWAYLAND_VIEW, &view_impl); |
184 | if (!sway_assert(sway_view, "Failed to allocate view!")) { | 189 | if (!sway_assert(view, "Failed to allocate view")) { |
185 | return; | 190 | return; |
186 | } | 191 | } |
187 | sway_view->type = SWAY_XWAYLAND_VIEW; | 192 | view->wlr_xwayland_surface = xsurface; |
188 | sway_view->iface.get_prop = get_prop; | 193 | view->sway_xwayland_surface = sway_surface; |
189 | sway_view->iface.set_size = set_size; | 194 | sway_surface->view = view; |
190 | sway_view->iface.set_position = set_position; | ||
191 | sway_view->iface.set_activated = set_activated; | ||
192 | sway_view->iface.close = close_view; | ||
193 | sway_view->wlr_xwayland_surface = xsurface; | ||
194 | sway_view->sway_xwayland_surface = sway_surface; | ||
195 | sway_surface->view = sway_view; | ||
196 | |||
197 | wl_list_init(&sway_view->unmanaged_view_link); | ||
198 | 195 | ||
199 | // TODO: | 196 | // TODO: |
200 | // - Look up pid and open on appropriate workspace | 197 | // - Look up pid and open on appropriate workspace |
201 | // - Set new view to maximized so it behaves nicely | ||
202 | // - Criteria | 198 | // - Criteria |
203 | 199 | ||
204 | wl_signal_add(&xsurface->surface->events.commit, &sway_surface->commit); | 200 | wl_signal_add(&xsurface->surface->events.commit, &sway_surface->commit); |
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index d608a9cf..9229e92d 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -47,14 +47,15 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output, | |||
47 | static struct sway_container *container_at_cursor(struct sway_cursor *cursor, | 47 | static struct sway_container *container_at_cursor(struct sway_cursor *cursor, |
48 | struct wlr_surface **surface, double *sx, double *sy) { | 48 | struct wlr_surface **surface, double *sx, double *sy) { |
49 | // check for unmanaged views first | 49 | // check for unmanaged views first |
50 | struct wl_list *unmanaged = &root_container.sway_root->unmanaged_views; | 50 | struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; |
51 | struct sway_view *view; | 51 | struct sway_xwayland_unmanaged *sway_surface; |
52 | wl_list_for_each_reverse(view, unmanaged, unmanaged_view_link) { | 52 | wl_list_for_each_reverse(sway_surface, unmanaged, link) { |
53 | if (view->type != SWAY_XWAYLAND_VIEW) { | 53 | struct wlr_xwayland_surface *xsurface = |
54 | sway_surface->wlr_xwayland_surface; | ||
55 | if (xsurface->surface == NULL) { | ||
54 | continue; | 56 | continue; |
55 | } | 57 | } |
56 | 58 | ||
57 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | ||
58 | struct wlr_box box = { | 59 | struct wlr_box box = { |
59 | .x = xsurface->x, | 60 | .x = xsurface->x, |
60 | .y = xsurface->y, | 61 | .y = xsurface->y, |
@@ -84,7 +85,7 @@ static struct sway_container *container_at_cursor(struct sway_cursor *cursor, | |||
84 | 85 | ||
85 | // find the focused workspace on the output for this seat | 86 | // find the focused workspace on the output for this seat |
86 | struct sway_container *ws = | 87 | struct sway_container *ws = |
87 | sway_seat_get_focus_inactive(cursor->seat, output->swayc); | 88 | seat_get_focus_inactive(cursor->seat, output->swayc); |
88 | if (ws && ws->type != C_WORKSPACE) { | 89 | if (ws && ws->type != C_WORKSPACE) { |
89 | ws = container_parent(ws, C_WORKSPACE); | 90 | ws = container_parent(ws, C_WORKSPACE); |
90 | } | 91 | } |
@@ -129,7 +130,7 @@ static void cursor_send_pointer_motion(struct sway_cursor *cursor, | |||
129 | double sx, sy; | 130 | double sx, sy; |
130 | struct sway_container *c = container_at_cursor(cursor, &surface, &sx, &sy); | 131 | struct sway_container *c = container_at_cursor(cursor, &surface, &sx, &sy); |
131 | if (c && config->focus_follows_mouse) { | 132 | if (c && config->focus_follows_mouse) { |
132 | sway_seat_set_focus_warp(cursor->seat, c, false); | 133 | seat_set_focus_warp(cursor->seat, c, false); |
133 | } | 134 | } |
134 | 135 | ||
135 | // reset cursor if switching between clients | 136 | // reset cursor if switching between clients |
@@ -179,27 +180,32 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) { | |||
179 | double sx, sy; | 180 | double sx, sy; |
180 | struct sway_container *cont = | 181 | struct sway_container *cont = |
181 | container_at_cursor(cursor, &surface, &sx, &sy); | 182 | container_at_cursor(cursor, &surface, &sx, &sy); |
183 | if (surface && wlr_surface_is_layer_surface(surface)) { | ||
184 | struct wlr_layer_surface *layer = | ||
185 | wlr_layer_surface_from_wlr_surface(surface); | ||
186 | if (layer->current.keyboard_interactive) { | ||
187 | seat_set_focus_layer(cursor->seat, layer); | ||
188 | return; | ||
189 | } | ||
190 | } | ||
182 | // Avoid moving keyboard focus from a surface that accepts it to one | 191 | // Avoid moving keyboard focus from a surface that accepts it to one |
183 | // that does not unless the change would move us to a new workspace. | 192 | // that does not unless the change would move us to a new workspace. |
184 | // | 193 | // |
185 | // This prevents, for example, losing focus when clicking on swaybar. | 194 | // This prevents, for example, losing focus when clicking on swaybar. |
186 | // | ||
187 | // TODO: Replace this condition with something like | ||
188 | // !surface_accepts_keyboard_input | ||
189 | if (surface && cont && cont->type != C_VIEW) { | 195 | if (surface && cont && cont->type != C_VIEW) { |
190 | struct sway_container *new_ws = cont; | 196 | struct sway_container *new_ws = cont; |
191 | if (new_ws && new_ws->type != C_WORKSPACE) { | 197 | if (new_ws && new_ws->type != C_WORKSPACE) { |
192 | new_ws = container_parent(new_ws, C_WORKSPACE); | 198 | new_ws = container_parent(new_ws, C_WORKSPACE); |
193 | } | 199 | } |
194 | struct sway_container *old_ws = sway_seat_get_focus(cursor->seat); | 200 | struct sway_container *old_ws = seat_get_focus(cursor->seat); |
195 | if (old_ws && old_ws->type != C_WORKSPACE) { | 201 | if (old_ws && old_ws->type != C_WORKSPACE) { |
196 | old_ws = container_parent(old_ws, C_WORKSPACE); | 202 | old_ws = container_parent(old_ws, C_WORKSPACE); |
197 | } | 203 | } |
198 | if (new_ws != old_ws) { | 204 | if (new_ws != old_ws) { |
199 | sway_seat_set_focus(cursor->seat, cont); | 205 | seat_set_focus(cursor->seat, cont); |
200 | } | 206 | } |
201 | } else { | 207 | } else { |
202 | sway_seat_set_focus(cursor->seat, cont); | 208 | seat_set_focus(cursor->seat, cont); |
203 | } | 209 | } |
204 | 210 | ||
205 | wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, event->time_msec, | 211 | wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, event->time_msec, |
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index d421a03f..c3507f65 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c | |||
@@ -26,7 +26,7 @@ struct seat_config *current_seat_config = NULL; | |||
26 | struct sway_seat *input_manager_current_seat(struct sway_input_manager *input) { | 26 | struct sway_seat *input_manager_current_seat(struct sway_input_manager *input) { |
27 | struct sway_seat *seat = config->handler_context.seat; | 27 | struct sway_seat *seat = config->handler_context.seat; |
28 | if (!seat) { | 28 | if (!seat) { |
29 | seat = sway_input_manager_get_default_seat(input_manager); | 29 | seat = input_manager_get_default_seat(input_manager); |
30 | } | 30 | } |
31 | return seat; | 31 | return seat; |
32 | } | 32 | } |
@@ -40,7 +40,7 @@ struct sway_seat *input_manager_get_seat( | |||
40 | } | 40 | } |
41 | } | 41 | } |
42 | 42 | ||
43 | return sway_seat_create(input, seat_name); | 43 | return seat_create(input, seat_name); |
44 | } | 44 | } |
45 | 45 | ||
46 | static char *get_device_identifier(struct wlr_input_device *device) { | 46 | static char *get_device_identifier(struct wlr_input_device *device) { |
@@ -83,7 +83,8 @@ static struct sway_input_device *input_sway_device_from_wlr( | |||
83 | static bool input_has_seat_configuration(struct sway_input_manager *input) { | 83 | static bool input_has_seat_configuration(struct sway_input_manager *input) { |
84 | struct sway_seat *seat = NULL; | 84 | struct sway_seat *seat = NULL; |
85 | wl_list_for_each(seat, &input->seats, link) { | 85 | wl_list_for_each(seat, &input->seats, link) { |
86 | if (seat->config) { | 86 | struct seat_config *seat_config = seat_get_config(seat); |
87 | if (seat_config) { | ||
87 | return true; | 88 | return true; |
88 | } | 89 | } |
89 | } | 90 | } |
@@ -91,9 +92,10 @@ static bool input_has_seat_configuration(struct sway_input_manager *input) { | |||
91 | return false; | 92 | return false; |
92 | } | 93 | } |
93 | 94 | ||
94 | static void sway_input_manager_libinput_config_pointer(struct sway_input_device *input_device) { | 95 | static void input_manager_libinput_config_pointer( |
96 | struct sway_input_device *input_device) { | ||
95 | struct wlr_input_device *wlr_device = input_device->wlr_device; | 97 | struct wlr_input_device *wlr_device = input_device->wlr_device; |
96 | struct input_config *ic = input_device->config; | 98 | struct input_config *ic = input_device_get_config(input_device); |
97 | struct libinput_device *libinput_device; | 99 | struct libinput_device *libinput_device; |
98 | 100 | ||
99 | if (!ic || !wlr_input_device_is_libinput(wlr_device)) { | 101 | if (!ic || !wlr_input_device_is_libinput(wlr_device)) { |
@@ -101,22 +103,27 @@ static void sway_input_manager_libinput_config_pointer(struct sway_input_device | |||
101 | } | 103 | } |
102 | 104 | ||
103 | libinput_device = wlr_libinput_get_device_handle(wlr_device); | 105 | libinput_device = wlr_libinput_get_device_handle(wlr_device); |
104 | wlr_log(L_DEBUG, "sway_input_manager_libinput_config_pointer(%s)", ic->identifier); | 106 | wlr_log(L_DEBUG, "input_manager_libinput_config_pointer(%s)", |
107 | ic->identifier); | ||
105 | 108 | ||
106 | if (ic->accel_profile != INT_MIN) { | 109 | if (ic->accel_profile != INT_MIN) { |
107 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_profile(%d)", | 110 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_profile(%d)", |
108 | ic->identifier, ic->accel_profile); | 111 | ic->identifier, ic->accel_profile); |
109 | libinput_device_config_accel_set_profile(libinput_device, ic->accel_profile); | 112 | libinput_device_config_accel_set_profile(libinput_device, |
113 | ic->accel_profile); | ||
110 | } | 114 | } |
111 | if (ic->click_method != INT_MIN) { | 115 | if (ic->click_method != INT_MIN) { |
112 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) click_set_method(%d)", | 116 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) click_set_method(%d)", |
113 | ic->identifier, ic->click_method); | 117 | ic->identifier, ic->click_method); |
114 | libinput_device_config_click_set_method(libinput_device, ic->click_method); | 118 | libinput_device_config_click_set_method(libinput_device, |
119 | ic->click_method); | ||
115 | } | 120 | } |
116 | if (ic->drag_lock != INT_MIN) { | 121 | if (ic->drag_lock != INT_MIN) { |
117 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)", | 122 | wlr_log(L_DEBUG, |
123 | "libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)", | ||
118 | ic->identifier, ic->click_method); | 124 | ic->identifier, ic->click_method); |
119 | libinput_device_config_tap_set_drag_lock_enabled(libinput_device, ic->drag_lock); | 125 | libinput_device_config_tap_set_drag_lock_enabled(libinput_device, |
126 | ic->drag_lock); | ||
120 | } | 127 | } |
121 | if (ic->dwt != INT_MIN) { | 128 | if (ic->dwt != INT_MIN) { |
122 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) dwt_set_enabled(%d)", | 129 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) dwt_set_enabled(%d)", |
@@ -124,34 +131,43 @@ static void sway_input_manager_libinput_config_pointer(struct sway_input_device | |||
124 | libinput_device_config_dwt_set_enabled(libinput_device, ic->dwt); | 131 | libinput_device_config_dwt_set_enabled(libinput_device, ic->dwt); |
125 | } | 132 | } |
126 | if (ic->left_handed != INT_MIN) { | 133 | if (ic->left_handed != INT_MIN) { |
127 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) left_handed_set_enabled(%d)", | 134 | wlr_log(L_DEBUG, |
135 | "libinput_config_pointer(%s) left_handed_set_enabled(%d)", | ||
128 | ic->identifier, ic->left_handed); | 136 | ic->identifier, ic->left_handed); |
129 | libinput_device_config_left_handed_set(libinput_device, ic->left_handed); | 137 | libinput_device_config_left_handed_set(libinput_device, |
138 | ic->left_handed); | ||
130 | } | 139 | } |
131 | if (ic->middle_emulation != INT_MIN) { | 140 | if (ic->middle_emulation != INT_MIN) { |
132 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) middle_emulation_set_enabled(%d)", | 141 | wlr_log(L_DEBUG, |
142 | "libinput_config_pointer(%s) middle_emulation_set_enabled(%d)", | ||
133 | ic->identifier, ic->middle_emulation); | 143 | ic->identifier, ic->middle_emulation); |
134 | libinput_device_config_middle_emulation_set_enabled(libinput_device, ic->middle_emulation); | 144 | libinput_device_config_middle_emulation_set_enabled(libinput_device, |
145 | ic->middle_emulation); | ||
135 | } | 146 | } |
136 | if (ic->natural_scroll != INT_MIN) { | 147 | if (ic->natural_scroll != INT_MIN) { |
137 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) natural_scroll_set_enabled(%d)", | 148 | wlr_log(L_DEBUG, |
149 | "libinput_config_pointer(%s) natural_scroll_set_enabled(%d)", | ||
138 | ic->identifier, ic->natural_scroll); | 150 | ic->identifier, ic->natural_scroll); |
139 | libinput_device_config_scroll_set_natural_scroll_enabled(libinput_device, ic->natural_scroll); | 151 | libinput_device_config_scroll_set_natural_scroll_enabled( |
152 | libinput_device, ic->natural_scroll); | ||
140 | } | 153 | } |
141 | if (ic->pointer_accel != FLT_MIN) { | 154 | if (ic->pointer_accel != FLT_MIN) { |
142 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_speed(%f)", | 155 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_speed(%f)", |
143 | ic->identifier, ic->pointer_accel); | 156 | ic->identifier, ic->pointer_accel); |
144 | libinput_device_config_accel_set_speed(libinput_device, ic->pointer_accel); | 157 | libinput_device_config_accel_set_speed(libinput_device, |
158 | ic->pointer_accel); | ||
145 | } | 159 | } |
146 | if (ic->scroll_method != INT_MIN) { | 160 | if (ic->scroll_method != INT_MIN) { |
147 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) scroll_set_method(%d)", | 161 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) scroll_set_method(%d)", |
148 | ic->identifier, ic->scroll_method); | 162 | ic->identifier, ic->scroll_method); |
149 | libinput_device_config_scroll_set_method(libinput_device, ic->scroll_method); | 163 | libinput_device_config_scroll_set_method(libinput_device, |
164 | ic->scroll_method); | ||
150 | } | 165 | } |
151 | if (ic->send_events != INT_MIN) { | 166 | if (ic->send_events != INT_MIN) { |
152 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) send_events_set_mode(%d)", | 167 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) send_events_set_mode(%d)", |
153 | ic->identifier, ic->send_events); | 168 | ic->identifier, ic->send_events); |
154 | libinput_device_config_send_events_set_mode(libinput_device, ic->send_events); | 169 | libinput_device_config_send_events_set_mode(libinput_device, |
170 | ic->send_events); | ||
155 | } | 171 | } |
156 | if (ic->tap != INT_MIN) { | 172 | if (ic->tap != INT_MIN) { |
157 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) tap_set_enabled(%d)", | 173 | wlr_log(L_DEBUG, "libinput_config_pointer(%s) tap_set_enabled(%d)", |
@@ -175,12 +191,11 @@ static void handle_device_destroy(struct wl_listener *listener, void *data) { | |||
175 | 191 | ||
176 | struct sway_seat *seat = NULL; | 192 | struct sway_seat *seat = NULL; |
177 | wl_list_for_each(seat, &input_manager->seats, link) { | 193 | wl_list_for_each(seat, &input_manager->seats, link) { |
178 | sway_seat_remove_device(seat, input_device); | 194 | seat_remove_device(seat, input_device); |
179 | } | 195 | } |
180 | 196 | ||
181 | wl_list_remove(&input_device->link); | 197 | wl_list_remove(&input_device->link); |
182 | wl_list_remove(&input_device->device_destroy.link); | 198 | wl_list_remove(&input_device->device_destroy.link); |
183 | free_input_config(input_device->config); | ||
184 | free(input_device->identifier); | 199 | free(input_device->identifier); |
185 | free(input_device); | 200 | free(input_device); |
186 | } | 201 | } |
@@ -203,44 +218,36 @@ static void handle_new_input(struct wl_listener *listener, void *data) { | |||
203 | wlr_log(L_DEBUG, "adding device: '%s'", | 218 | wlr_log(L_DEBUG, "adding device: '%s'", |
204 | input_device->identifier); | 219 | input_device->identifier); |
205 | 220 | ||
206 | // find config | ||
207 | for (int i = 0; i < config->input_configs->length; ++i) { | ||
208 | struct input_config *input_config = config->input_configs->items[i]; | ||
209 | if (strcmp(input_config->identifier, input_device->identifier) == 0) { | ||
210 | free_input_config(input_device->config); | ||
211 | input_device->config = copy_input_config(input_config); | ||
212 | break; | ||
213 | } | ||
214 | } | ||
215 | |||
216 | if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) { | 221 | if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) { |
217 | sway_input_manager_libinput_config_pointer(input_device); | 222 | input_manager_libinput_config_pointer(input_device); |
218 | } | 223 | } |
219 | 224 | ||
220 | struct sway_seat *seat = NULL; | 225 | struct sway_seat *seat = NULL; |
221 | if (!input_has_seat_configuration(input)) { | 226 | if (!input_has_seat_configuration(input)) { |
222 | wlr_log(L_DEBUG, "no seat configuration, using default seat"); | 227 | wlr_log(L_DEBUG, "no seat configuration, using default seat"); |
223 | seat = input_manager_get_seat(input, default_seat); | 228 | seat = input_manager_get_seat(input, default_seat); |
224 | sway_seat_add_device(seat, input_device); | 229 | seat_add_device(seat, input_device); |
225 | return; | 230 | return; |
226 | } | 231 | } |
227 | 232 | ||
228 | bool added = false; | 233 | bool added = false; |
229 | wl_list_for_each(seat, &input->seats, link) { | 234 | wl_list_for_each(seat, &input->seats, link) { |
230 | bool has_attachment = seat->config && | 235 | struct seat_config *seat_config = seat_get_config(seat); |
231 | (seat_config_get_attachment(seat->config, input_device->identifier) || | 236 | bool has_attachment = seat_config && |
232 | seat_config_get_attachment(seat->config, "*")); | 237 | (seat_config_get_attachment(seat_config, input_device->identifier) || |
238 | seat_config_get_attachment(seat_config, "*")); | ||
233 | 239 | ||
234 | if (has_attachment) { | 240 | if (has_attachment) { |
235 | sway_seat_add_device(seat, input_device); | 241 | seat_add_device(seat, input_device); |
236 | added = true; | 242 | added = true; |
237 | } | 243 | } |
238 | } | 244 | } |
239 | 245 | ||
240 | if (!added) { | 246 | if (!added) { |
241 | wl_list_for_each(seat, &input->seats, link) { | 247 | wl_list_for_each(seat, &input->seats, link) { |
242 | if (seat->config && seat->config->fallback == 1) { | 248 | struct seat_config *seat_config = seat_get_config(seat); |
243 | sway_seat_add_device(seat, input_device); | 249 | if (seat_config && seat_config->fallback == 1) { |
250 | seat_add_device(seat, input_device); | ||
244 | added = true; | 251 | added = true; |
245 | } | 252 | } |
246 | } | 253 | } |
@@ -256,7 +263,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) { | |||
256 | input_device->device_destroy.notify = handle_device_destroy; | 263 | input_device->device_destroy.notify = handle_device_destroy; |
257 | } | 264 | } |
258 | 265 | ||
259 | struct sway_input_manager *sway_input_manager_create( | 266 | struct sway_input_manager *input_manager_create( |
260 | struct sway_server *server) { | 267 | struct sway_server *server) { |
261 | struct sway_input_manager *input = | 268 | struct sway_input_manager *input = |
262 | calloc(1, sizeof(struct sway_input_manager)); | 269 | calloc(1, sizeof(struct sway_input_manager)); |
@@ -277,11 +284,11 @@ struct sway_input_manager *sway_input_manager_create( | |||
277 | return input; | 284 | return input; |
278 | } | 285 | } |
279 | 286 | ||
280 | bool sway_input_manager_has_focus(struct sway_input_manager *input, | 287 | bool input_manager_has_focus(struct sway_input_manager *input, |
281 | struct sway_container *container) { | 288 | struct sway_container *container) { |
282 | struct sway_seat *seat = NULL; | 289 | struct sway_seat *seat = NULL; |
283 | wl_list_for_each(seat, &input->seats, link) { | 290 | wl_list_for_each(seat, &input->seats, link) { |
284 | if (sway_seat_get_focus(seat) == container) { | 291 | if (seat_get_focus(seat) == container) { |
285 | return true; | 292 | return true; |
286 | } | 293 | } |
287 | } | 294 | } |
@@ -289,35 +296,32 @@ bool sway_input_manager_has_focus(struct sway_input_manager *input, | |||
289 | return false; | 296 | return false; |
290 | } | 297 | } |
291 | 298 | ||
292 | void sway_input_manager_set_focus(struct sway_input_manager *input, | 299 | void input_manager_set_focus(struct sway_input_manager *input, |
293 | struct sway_container *container) { | 300 | struct sway_container *container) { |
294 | struct sway_seat *seat ; | 301 | struct sway_seat *seat ; |
295 | wl_list_for_each(seat, &input->seats, link) { | 302 | wl_list_for_each(seat, &input->seats, link) { |
296 | sway_seat_set_focus(seat, container); | 303 | seat_set_focus(seat, container); |
297 | } | 304 | } |
298 | } | 305 | } |
299 | 306 | ||
300 | void sway_input_manager_apply_input_config(struct sway_input_manager *input, | 307 | void input_manager_apply_input_config(struct sway_input_manager *input, |
301 | struct input_config *input_config) { | 308 | struct input_config *input_config) { |
302 | struct sway_input_device *input_device = NULL; | 309 | struct sway_input_device *input_device = NULL; |
303 | wl_list_for_each(input_device, &input->devices, link) { | 310 | wl_list_for_each(input_device, &input->devices, link) { |
304 | if (strcmp(input_device->identifier, input_config->identifier) == 0) { | 311 | if (strcmp(input_device->identifier, input_config->identifier) == 0) { |
305 | free_input_config(input_device->config); | ||
306 | input_device->config = copy_input_config(input_config); | ||
307 | |||
308 | if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) { | 312 | if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) { |
309 | sway_input_manager_libinput_config_pointer(input_device); | 313 | input_manager_libinput_config_pointer(input_device); |
310 | } | 314 | } |
311 | 315 | ||
312 | struct sway_seat *seat = NULL; | 316 | struct sway_seat *seat = NULL; |
313 | wl_list_for_each(seat, &input->seats, link) { | 317 | wl_list_for_each(seat, &input->seats, link) { |
314 | sway_seat_configure_device(seat, input_device); | 318 | seat_configure_device(seat, input_device); |
315 | } | 319 | } |
316 | } | 320 | } |
317 | } | 321 | } |
318 | } | 322 | } |
319 | 323 | ||
320 | void sway_input_manager_apply_seat_config(struct sway_input_manager *input, | 324 | void input_manager_apply_seat_config(struct sway_input_manager *input, |
321 | struct seat_config *seat_config) { | 325 | struct seat_config *seat_config) { |
322 | wlr_log(L_DEBUG, "applying new seat config for seat %s", | 326 | wlr_log(L_DEBUG, "applying new seat config for seat %s", |
323 | seat_config->name); | 327 | seat_config->name); |
@@ -326,7 +330,7 @@ void sway_input_manager_apply_seat_config(struct sway_input_manager *input, | |||
326 | return; | 330 | return; |
327 | } | 331 | } |
328 | 332 | ||
329 | sway_seat_set_config(seat, seat_config); | 333 | seat_apply_config(seat, seat_config); |
330 | 334 | ||
331 | // for every device, try to add it to a seat and if no seat has it | 335 | // for every device, try to add it to a seat and if no seat has it |
332 | // attached, add it to the fallback seats. | 336 | // attached, add it to the fallback seats. |
@@ -335,11 +339,12 @@ void sway_input_manager_apply_seat_config(struct sway_input_manager *input, | |||
335 | list_t *seat_list = create_list(); | 339 | list_t *seat_list = create_list(); |
336 | struct sway_seat *seat = NULL; | 340 | struct sway_seat *seat = NULL; |
337 | wl_list_for_each(seat, &input->seats, link) { | 341 | wl_list_for_each(seat, &input->seats, link) { |
338 | if (!seat->config) { | 342 | struct seat_config *seat_config = seat_get_config(seat); |
343 | if (!seat_config) { | ||
339 | continue; | 344 | continue; |
340 | } | 345 | } |
341 | if (seat_config_get_attachment(seat->config, "*") || | 346 | if (seat_config_get_attachment(seat_config, "*") || |
342 | seat_config_get_attachment(seat->config, | 347 | seat_config_get_attachment(seat_config, |
343 | input_device->identifier)) { | 348 | input_device->identifier)) { |
344 | list_add(seat_list, seat); | 349 | list_add(seat_list, seat); |
345 | } | 350 | } |
@@ -355,17 +360,18 @@ void sway_input_manager_apply_seat_config(struct sway_input_manager *input, | |||
355 | } | 360 | } |
356 | } | 361 | } |
357 | if (attached) { | 362 | if (attached) { |
358 | sway_seat_add_device(seat, input_device); | 363 | seat_add_device(seat, input_device); |
359 | } else { | 364 | } else { |
360 | sway_seat_remove_device(seat, input_device); | 365 | seat_remove_device(seat, input_device); |
361 | } | 366 | } |
362 | } | 367 | } |
363 | } else { | 368 | } else { |
364 | wl_list_for_each(seat, &input->seats, link) { | 369 | wl_list_for_each(seat, &input->seats, link) { |
365 | if (seat->config && seat->config->fallback == 1) { | 370 | struct seat_config *seat_config = seat_get_config(seat); |
366 | sway_seat_add_device(seat, input_device); | 371 | if (seat_config && seat_config->fallback == 1) { |
372 | seat_add_device(seat, input_device); | ||
367 | } else { | 373 | } else { |
368 | sway_seat_remove_device(seat, input_device); | 374 | seat_remove_device(seat, input_device); |
369 | } | 375 | } |
370 | } | 376 | } |
371 | } | 377 | } |
@@ -373,14 +379,14 @@ void sway_input_manager_apply_seat_config(struct sway_input_manager *input, | |||
373 | } | 379 | } |
374 | } | 380 | } |
375 | 381 | ||
376 | void sway_input_manager_configure_xcursor(struct sway_input_manager *input) { | 382 | void input_manager_configure_xcursor(struct sway_input_manager *input) { |
377 | struct sway_seat *seat = NULL; | 383 | struct sway_seat *seat = NULL; |
378 | wl_list_for_each(seat, &input->seats, link) { | 384 | wl_list_for_each(seat, &input->seats, link) { |
379 | sway_seat_configure_xcursor(seat); | 385 | seat_configure_xcursor(seat); |
380 | } | 386 | } |
381 | } | 387 | } |
382 | 388 | ||
383 | struct sway_seat *sway_input_manager_get_default_seat( | 389 | struct sway_seat *input_manager_get_default_seat( |
384 | struct sway_input_manager *input) { | 390 | struct sway_input_manager *input) { |
385 | struct sway_seat *seat = NULL; | 391 | struct sway_seat *seat = NULL; |
386 | wl_list_for_each(seat, &input->seats, link) { | 392 | wl_list_for_each(seat, &input->seats, link) { |
@@ -390,3 +396,15 @@ struct sway_seat *sway_input_manager_get_default_seat( | |||
390 | } | 396 | } |
391 | return seat; | 397 | return seat; |
392 | } | 398 | } |
399 | |||
400 | struct input_config *input_device_get_config(struct sway_input_device *device) { | ||
401 | struct input_config *input_config = NULL; | ||
402 | for (int i = 0; i < config->input_configs->length; ++i) { | ||
403 | input_config = config->input_configs->items[i]; | ||
404 | if (strcmp(input_config->identifier, device->identifier) == 0) { | ||
405 | return input_config; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | return NULL; | ||
410 | } | ||
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 99685052..dbb0c359 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c | |||
@@ -97,8 +97,8 @@ static void keyboard_execute_command(struct sway_keyboard *keyboard, | |||
97 | config->handler_context.seat = keyboard->seat_device->sway_seat; | 97 | config->handler_context.seat = keyboard->seat_device->sway_seat; |
98 | struct cmd_results *results = execute_command(binding->command, NULL); | 98 | struct cmd_results *results = execute_command(binding->command, NULL); |
99 | if (results->status != CMD_SUCCESS) { | 99 | if (results->status != CMD_SUCCESS) { |
100 | wlr_log(L_DEBUG, "could not run command for binding: %s", | 100 | wlr_log(L_DEBUG, "could not run command for binding: %s (%s)", |
101 | binding->command); | 101 | binding->command, results->error); |
102 | } | 102 | } |
103 | free_cmd_results(results); | 103 | free_cmd_results(results); |
104 | } | 104 | } |
@@ -428,7 +428,7 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { | |||
428 | struct xkb_rule_names rules; | 428 | struct xkb_rule_names rules; |
429 | memset(&rules, 0, sizeof(rules)); | 429 | memset(&rules, 0, sizeof(rules)); |
430 | struct input_config *input_config = | 430 | struct input_config *input_config = |
431 | keyboard->seat_device->input_device->config; | 431 | input_device_get_config(keyboard->seat_device->input_device); |
432 | struct wlr_input_device *wlr_device = | 432 | struct wlr_input_device *wlr_device = |
433 | keyboard->seat_device->input_device->wlr_device; | 433 | keyboard->seat_device->input_device->wlr_device; |
434 | 434 | ||
diff --git a/sway/input/seat.c b/sway/input/seat.c index 9aa34aca..cf519a82 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #define _XOPEN_SOURCE 700 | 1 | #define _XOPEN_SOURCE 700 |
2 | #include <assert.h> | ||
2 | #include <wlr/types/wlr_cursor.h> | 3 | #include <wlr/types/wlr_cursor.h> |
3 | #include <wlr/types/wlr_output_layout.h> | 4 | #include <wlr/types/wlr_output_layout.h> |
4 | #include <wlr/types/wlr_xcursor_manager.h> | 5 | #include <wlr/types/wlr_xcursor_manager.h> |
@@ -25,7 +26,7 @@ static void seat_device_destroy(struct sway_seat_device *seat_device) { | |||
25 | free(seat_device); | 26 | free(seat_device); |
26 | } | 27 | } |
27 | 28 | ||
28 | void sway_seat_destroy(struct sway_seat *seat) { | 29 | void seat_destroy(struct sway_seat *seat) { |
29 | struct sway_seat_device *seat_device, *next; | 30 | struct sway_seat_device *seat_device, *next; |
30 | wl_list_for_each_safe(seat_device, next, &seat->devices, link) { | 31 | wl_list_for_each_safe(seat_device, next, &seat->devices, link) { |
31 | seat_device_destroy(seat_device); | 32 | seat_device_destroy(seat_device); |
@@ -35,30 +36,89 @@ void sway_seat_destroy(struct sway_seat *seat) { | |||
35 | wlr_seat_destroy(seat->wlr_seat); | 36 | wlr_seat_destroy(seat->wlr_seat); |
36 | } | 37 | } |
37 | 38 | ||
39 | static struct sway_seat_container *seat_container_from_container( | ||
40 | struct sway_seat *seat, struct sway_container *con); | ||
41 | |||
42 | static void seat_container_destroy(struct sway_seat_container *seat_con) { | ||
43 | struct sway_container *con = seat_con->container; | ||
44 | struct sway_container *child = NULL; | ||
45 | |||
46 | if (con->children != NULL) { | ||
47 | for (int i = 0; i < con->children->length; ++i) { | ||
48 | child = con->children->items[i]; | ||
49 | struct sway_seat_container *seat_child = | ||
50 | seat_container_from_container(seat_con->seat, child); | ||
51 | seat_container_destroy(seat_child); | ||
52 | } | ||
53 | } | ||
54 | |||
55 | wl_list_remove(&seat_con->destroy.link); | ||
56 | wl_list_remove(&seat_con->link); | ||
57 | free(seat_con); | ||
58 | } | ||
59 | |||
60 | static void seat_send_focus(struct sway_seat *seat, | ||
61 | struct sway_container *con) { | ||
62 | if (con->type != C_VIEW) { | ||
63 | return; | ||
64 | } | ||
65 | struct sway_view *view = con->sway_view; | ||
66 | if (view->type == SWAY_XWAYLAND_VIEW) { | ||
67 | struct wlr_xwayland *xwayland = | ||
68 | seat->input->server->xwayland; | ||
69 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); | ||
70 | } | ||
71 | view_set_activated(view, true); | ||
72 | struct wlr_keyboard *keyboard = | ||
73 | wlr_seat_get_keyboard(seat->wlr_seat); | ||
74 | if (keyboard) { | ||
75 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, | ||
76 | view->surface, keyboard->keycodes, | ||
77 | keyboard->num_keycodes, &keyboard->modifiers); | ||
78 | } else { | ||
79 | wlr_seat_keyboard_notify_enter( | ||
80 | seat->wlr_seat, view->surface, NULL, 0, NULL); | ||
81 | } | ||
82 | |||
83 | } | ||
84 | |||
38 | static void handle_seat_container_destroy(struct wl_listener *listener, | 85 | static void handle_seat_container_destroy(struct wl_listener *listener, |
39 | void *data) { | 86 | void *data) { |
40 | struct sway_seat_container *seat_con = | 87 | struct sway_seat_container *seat_con = |
41 | wl_container_of(listener, seat_con, destroy); | 88 | wl_container_of(listener, seat_con, destroy); |
42 | struct sway_seat *seat = seat_con->seat; | 89 | struct sway_seat *seat = seat_con->seat; |
43 | struct sway_container *con = seat_con->container; | 90 | struct sway_container *con = seat_con->container; |
91 | struct sway_container *parent = con->parent; | ||
92 | struct sway_container *focus = seat_get_focus(seat); | ||
44 | 93 | ||
45 | bool is_focus = (sway_seat_get_focus(seat) == con); | 94 | bool set_focus = |
95 | focus != NULL && | ||
96 | (focus == con || container_has_child(con, focus)) && | ||
97 | con->type != C_WORKSPACE; | ||
46 | 98 | ||
47 | wl_list_remove(&seat_con->link); | 99 | seat_container_destroy(seat_con); |
48 | 100 | ||
49 | if (is_focus) { | 101 | if (set_focus) { |
50 | // pick next focus | 102 | struct sway_container *next_focus = NULL; |
51 | sway_seat_set_focus(seat, NULL); | 103 | while (next_focus == NULL) { |
52 | struct sway_container *next = sway_seat_get_focus_inactive(seat, con->parent); | 104 | next_focus = seat_get_focus_by_type(seat, parent, C_VIEW); |
53 | if (next == NULL) { | ||
54 | next = con->parent; | ||
55 | } | ||
56 | sway_seat_set_focus(seat, next); | ||
57 | } | ||
58 | 105 | ||
59 | wl_list_remove(&seat_con->destroy.link); | 106 | if (next_focus == NULL && parent->type == C_WORKSPACE) { |
107 | next_focus = parent; | ||
108 | break; | ||
109 | } | ||
60 | 110 | ||
61 | free(seat_con); | 111 | parent = parent->parent; |
112 | } | ||
113 | |||
114 | // the structure change might have caused it to move up to the top of | ||
115 | // the focus stack without sending focus notifications to the view | ||
116 | if (seat_get_focus(seat) == next_focus) { | ||
117 | seat_send_focus(seat, next_focus); | ||
118 | } else { | ||
119 | seat_set_focus(seat, next_focus); | ||
120 | } | ||
121 | } | ||
62 | } | 122 | } |
63 | 123 | ||
64 | static struct sway_seat_container *seat_container_from_container( | 124 | static struct sway_seat_container *seat_container_from_container( |
@@ -110,7 +170,7 @@ static void collect_focus_iter(struct sway_container *con, void *data) { | |||
110 | wl_list_insert(&seat->focus_stack, &seat_con->link); | 170 | wl_list_insert(&seat->focus_stack, &seat_con->link); |
111 | } | 171 | } |
112 | 172 | ||
113 | struct sway_seat *sway_seat_create(struct sway_input_manager *input, | 173 | struct sway_seat *seat_create(struct sway_input_manager *input, |
114 | const char *seat_name) { | 174 | const char *seat_name) { |
115 | struct sway_seat *seat = calloc(1, sizeof(struct sway_seat)); | 175 | struct sway_seat *seat = calloc(1, sizeof(struct sway_seat)); |
116 | if (!seat) { | 176 | if (!seat) { |
@@ -133,7 +193,8 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input, | |||
133 | // init the focus stack | 193 | // init the focus stack |
134 | wl_list_init(&seat->focus_stack); | 194 | wl_list_init(&seat->focus_stack); |
135 | 195 | ||
136 | container_for_each_descendant_dfs(&root_container, collect_focus_iter, seat); | 196 | container_for_each_descendant_dfs(&root_container, |
197 | collect_focus_iter, seat); | ||
137 | 198 | ||
138 | wl_signal_add(&root_container.sway_root->events.new_container, | 199 | wl_signal_add(&root_container.sway_root->events.new_container, |
139 | &seat->new_container); | 200 | &seat->new_container); |
@@ -147,7 +208,7 @@ struct sway_seat *sway_seat_create(struct sway_input_manager *input, | |||
147 | WL_SEAT_CAPABILITY_POINTER | | 208 | WL_SEAT_CAPABILITY_POINTER | |
148 | WL_SEAT_CAPABILITY_TOUCH); | 209 | WL_SEAT_CAPABILITY_TOUCH); |
149 | 210 | ||
150 | sway_seat_configure_xcursor(seat); | 211 | seat_configure_xcursor(seat); |
151 | 212 | ||
152 | wl_list_insert(&input->seats, &seat->link); | 213 | wl_list_insert(&input->seats, &seat->link); |
153 | 214 | ||
@@ -165,11 +226,12 @@ static void seat_configure_keyboard(struct sway_seat *seat, | |||
165 | if (!seat_device->keyboard) { | 226 | if (!seat_device->keyboard) { |
166 | sway_keyboard_create(seat, seat_device); | 227 | sway_keyboard_create(seat, seat_device); |
167 | } | 228 | } |
168 | struct wlr_keyboard *wlr_keyboard = seat_device->input_device->wlr_device->keyboard; | 229 | struct wlr_keyboard *wlr_keyboard = |
230 | seat_device->input_device->wlr_device->keyboard; | ||
169 | sway_keyboard_configure(seat_device->keyboard); | 231 | sway_keyboard_configure(seat_device->keyboard); |
170 | wlr_seat_set_keyboard(seat->wlr_seat, | 232 | wlr_seat_set_keyboard(seat->wlr_seat, |
171 | seat_device->input_device->wlr_device); | 233 | seat_device->input_device->wlr_device); |
172 | struct sway_container *focus = sway_seat_get_focus(seat); | 234 | struct sway_container *focus = seat_get_focus(seat); |
173 | if (focus && focus->type == C_VIEW) { | 235 | if (focus && focus->type == C_VIEW) { |
174 | // force notify reenter to pick up the new configuration | 236 | // force notify reenter to pick up the new configuration |
175 | wlr_seat_keyboard_clear_focus(seat->wlr_seat); | 237 | wlr_seat_keyboard_clear_focus(seat->wlr_seat); |
@@ -179,7 +241,7 @@ static void seat_configure_keyboard(struct sway_seat *seat, | |||
179 | } | 241 | } |
180 | } | 242 | } |
181 | 243 | ||
182 | static struct sway_seat_device *sway_seat_get_device(struct sway_seat *seat, | 244 | static struct sway_seat_device *seat_get_device(struct sway_seat *seat, |
183 | struct sway_input_device *input_device) { | 245 | struct sway_input_device *input_device) { |
184 | struct sway_seat_device *seat_device = NULL; | 246 | struct sway_seat_device *seat_device = NULL; |
185 | wl_list_for_each(seat_device, &seat->devices, link) { | 247 | wl_list_for_each(seat_device, &seat->devices, link) { |
@@ -191,19 +253,14 @@ static struct sway_seat_device *sway_seat_get_device(struct sway_seat *seat, | |||
191 | return NULL; | 253 | return NULL; |
192 | } | 254 | } |
193 | 255 | ||
194 | void sway_seat_configure_device(struct sway_seat *seat, | 256 | void seat_configure_device(struct sway_seat *seat, |
195 | struct sway_input_device *input_device) { | 257 | struct sway_input_device *input_device) { |
196 | struct sway_seat_device *seat_device = | 258 | struct sway_seat_device *seat_device = |
197 | sway_seat_get_device(seat, input_device); | 259 | seat_get_device(seat, input_device); |
198 | if (!seat_device) { | 260 | if (!seat_device) { |
199 | return; | 261 | return; |
200 | } | 262 | } |
201 | 263 | ||
202 | if (seat->config) { | ||
203 | seat_device->attachment_config = | ||
204 | seat_config_get_attachment(seat->config, input_device->identifier); | ||
205 | } | ||
206 | |||
207 | switch (input_device->wlr_device->type) { | 264 | switch (input_device->wlr_device->type) { |
208 | case WLR_INPUT_DEVICE_POINTER: | 265 | case WLR_INPUT_DEVICE_POINTER: |
209 | seat_configure_pointer(seat, seat_device); | 266 | seat_configure_pointer(seat, seat_device); |
@@ -219,10 +276,10 @@ void sway_seat_configure_device(struct sway_seat *seat, | |||
219 | } | 276 | } |
220 | } | 277 | } |
221 | 278 | ||
222 | void sway_seat_add_device(struct sway_seat *seat, | 279 | void seat_add_device(struct sway_seat *seat, |
223 | struct sway_input_device *input_device) { | 280 | struct sway_input_device *input_device) { |
224 | if (sway_seat_get_device(seat, input_device)) { | 281 | if (seat_get_device(seat, input_device)) { |
225 | sway_seat_configure_device(seat, input_device); | 282 | seat_configure_device(seat, input_device); |
226 | return; | 283 | return; |
227 | } | 284 | } |
228 | 285 | ||
@@ -240,13 +297,13 @@ void sway_seat_add_device(struct sway_seat *seat, | |||
240 | seat_device->input_device = input_device; | 297 | seat_device->input_device = input_device; |
241 | wl_list_insert(&seat->devices, &seat_device->link); | 298 | wl_list_insert(&seat->devices, &seat_device->link); |
242 | 299 | ||
243 | sway_seat_configure_device(seat, input_device); | 300 | seat_configure_device(seat, input_device); |
244 | } | 301 | } |
245 | 302 | ||
246 | void sway_seat_remove_device(struct sway_seat *seat, | 303 | void seat_remove_device(struct sway_seat *seat, |
247 | struct sway_input_device *input_device) { | 304 | struct sway_input_device *input_device) { |
248 | struct sway_seat_device *seat_device = | 305 | struct sway_seat_device *seat_device = |
249 | sway_seat_get_device(seat, input_device); | 306 | seat_get_device(seat, input_device); |
250 | 307 | ||
251 | if (!seat_device) { | 308 | if (!seat_device) { |
252 | return; | 309 | return; |
@@ -258,7 +315,7 @@ void sway_seat_remove_device(struct sway_seat *seat, | |||
258 | seat_device_destroy(seat_device); | 315 | seat_device_destroy(seat_device); |
259 | } | 316 | } |
260 | 317 | ||
261 | void sway_seat_configure_xcursor(struct sway_seat *seat) { | 318 | void seat_configure_xcursor(struct sway_seat *seat) { |
262 | // TODO configure theme and size | 319 | // TODO configure theme and size |
263 | const char *cursor_theme = NULL; | 320 | const char *cursor_theme = NULL; |
264 | 321 | ||
@@ -273,7 +330,8 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) { | |||
273 | } | 330 | } |
274 | 331 | ||
275 | for (int i = 0; i < root_container.children->length; ++i) { | 332 | for (int i = 0; i < root_container.children->length; ++i) { |
276 | struct sway_container *output_container = root_container.children->items[i]; | 333 | struct sway_container *output_container = |
334 | root_container.children->items[i]; | ||
277 | struct wlr_output *output = | 335 | struct wlr_output *output = |
278 | output_container->sway_output->wlr_output; | 336 | output_container->sway_output->wlr_output; |
279 | bool result = | 337 | bool result = |
@@ -292,10 +350,13 @@ void sway_seat_configure_xcursor(struct sway_seat *seat) { | |||
292 | seat->cursor->cursor->y); | 350 | seat->cursor->cursor->y); |
293 | } | 351 | } |
294 | 352 | ||
295 | void sway_seat_set_focus_warp(struct sway_seat *seat, | 353 | void seat_set_focus_warp(struct sway_seat *seat, |
296 | struct sway_container *container, bool warp) { | 354 | struct sway_container *container, bool warp) { |
297 | struct sway_container *last_focus = sway_seat_get_focus(seat); | 355 | if (seat->focused_layer) { |
356 | return; | ||
357 | } | ||
298 | 358 | ||
359 | struct sway_container *last_focus = seat_get_focus(seat); | ||
299 | if (container && last_focus == container) { | 360 | if (container && last_focus == container) { |
300 | return; | 361 | return; |
301 | } | 362 | } |
@@ -311,23 +372,7 @@ void sway_seat_set_focus_warp(struct sway_seat *seat, | |||
311 | wl_list_insert(&seat->focus_stack, &seat_con->link); | 372 | wl_list_insert(&seat->focus_stack, &seat_con->link); |
312 | 373 | ||
313 | if (container->type == C_VIEW) { | 374 | if (container->type == C_VIEW) { |
314 | struct sway_view *view = container->sway_view; | 375 | seat_send_focus(seat, container); |
315 | view_set_activated(view, true); | ||
316 | if (view->type == SWAY_XWAYLAND_VIEW) { | ||
317 | struct wlr_xwayland *xwayland = | ||
318 | seat->input->server->xwayland; | ||
319 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); | ||
320 | } | ||
321 | struct wlr_keyboard *keyboard = | ||
322 | wlr_seat_get_keyboard(seat->wlr_seat); | ||
323 | if (keyboard) { | ||
324 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, | ||
325 | view->surface, keyboard->keycodes, | ||
326 | keyboard->num_keycodes, &keyboard->modifiers); | ||
327 | } else { | ||
328 | wlr_seat_keyboard_notify_enter( | ||
329 | seat->wlr_seat, view->surface, NULL, 0, NULL); | ||
330 | } | ||
331 | } | 376 | } |
332 | } | 377 | } |
333 | 378 | ||
@@ -364,7 +409,7 @@ void sway_seat_set_focus_warp(struct sway_seat *seat, | |||
364 | } | 409 | } |
365 | 410 | ||
366 | if (last_focus && last_focus->type == C_VIEW && | 411 | if (last_focus && last_focus->type == C_VIEW && |
367 | !sway_input_manager_has_focus(seat->input, last_focus)) { | 412 | !input_manager_has_focus(seat->input, last_focus)) { |
368 | struct sway_view *view = last_focus->sway_view; | 413 | struct sway_view *view = last_focus->sway_view; |
369 | view_set_activated(view, false); | 414 | view_set_activated(view, false); |
370 | } | 415 | } |
@@ -372,23 +417,69 @@ void sway_seat_set_focus_warp(struct sway_seat *seat, | |||
372 | seat->has_focus = (container != NULL); | 417 | seat->has_focus = (container != NULL); |
373 | } | 418 | } |
374 | 419 | ||
375 | void sway_seat_set_focus(struct sway_seat *seat, | 420 | void seat_set_focus(struct sway_seat *seat, |
376 | struct sway_container *container) { | 421 | struct sway_container *container) { |
377 | sway_seat_set_focus_warp(seat, container, true); | 422 | seat_set_focus_warp(seat, container, true); |
378 | } | 423 | } |
379 | 424 | ||
380 | struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, struct sway_container *container) { | 425 | void seat_set_focus_layer(struct sway_seat *seat, |
426 | struct wlr_layer_surface *layer) { | ||
427 | if (!layer) { | ||
428 | seat->focused_layer = NULL; | ||
429 | return; | ||
430 | } | ||
431 | if (seat->focused_layer == layer) { | ||
432 | return; | ||
433 | } | ||
434 | if (seat->has_focus) { | ||
435 | struct sway_container *focus = seat_get_focus(seat); | ||
436 | if (focus->type == C_VIEW) { | ||
437 | wlr_seat_keyboard_clear_focus(seat->wlr_seat); | ||
438 | view_set_activated(focus->sway_view, false); | ||
439 | } | ||
440 | } | ||
441 | if (layer->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { | ||
442 | seat->focused_layer = layer; | ||
443 | } | ||
444 | struct wlr_keyboard *keyboard = | ||
445 | wlr_seat_get_keyboard(seat->wlr_seat); | ||
446 | if (keyboard) { | ||
447 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, | ||
448 | layer->surface, keyboard->keycodes, | ||
449 | keyboard->num_keycodes, &keyboard->modifiers); | ||
450 | } else { | ||
451 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, | ||
452 | layer->surface, NULL, 0, NULL); | ||
453 | } | ||
454 | } | ||
455 | |||
456 | struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, | ||
457 | struct sway_container *container) { | ||
458 | return seat_get_focus_by_type(seat, container, C_TYPES); | ||
459 | } | ||
460 | |||
461 | struct sway_container *sway_seat_get_focus(struct sway_seat *seat) { | ||
462 | if (!seat->has_focus) { | ||
463 | return NULL; | ||
464 | } | ||
465 | return seat_get_focus_inactive(seat, &root_container); | ||
466 | } | ||
467 | |||
468 | struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, | ||
469 | struct sway_container *container, enum sway_container_type type) { | ||
381 | struct sway_seat_container *current = NULL; | 470 | struct sway_seat_container *current = NULL; |
382 | struct sway_container *parent = NULL; | 471 | struct sway_container *parent = NULL; |
383 | wl_list_for_each(current, &seat->focus_stack, link) { | 472 | wl_list_for_each(current, &seat->focus_stack, link) { |
384 | parent = current->container->parent; | 473 | parent = current->container->parent; |
385 | 474 | ||
386 | if (current->container == container) { | 475 | if (current->container == container && |
476 | (type == C_TYPES || container->type == type)) { | ||
387 | return current->container; | 477 | return current->container; |
388 | } | 478 | } |
389 | 479 | ||
390 | while (parent) { | 480 | while (parent) { |
391 | if (parent == container) { | 481 | if (parent == container && (type == C_TYPES || |
482 | current->container->type == type)) { | ||
392 | return current->container; | 483 | return current->container; |
393 | } | 484 | } |
394 | parent = parent->parent; | 485 | parent = parent->parent; |
@@ -398,42 +489,34 @@ struct sway_container *sway_seat_get_focus_inactive(struct sway_seat *seat, stru | |||
398 | return NULL; | 489 | return NULL; |
399 | } | 490 | } |
400 | 491 | ||
401 | struct sway_container *sway_seat_get_focus(struct sway_seat *seat) { | 492 | struct sway_container *seat_get_focus(struct sway_seat *seat) { |
402 | if (!seat->has_focus) { | 493 | if (!seat->has_focus) { |
403 | return NULL; | 494 | return NULL; |
404 | } | 495 | } |
405 | return sway_seat_get_focus_inactive(seat, &root_container); | 496 | return seat_get_focus_inactive(seat, &root_container); |
406 | } | 497 | } |
407 | 498 | ||
408 | struct sway_container *sway_seat_get_focus_by_type(struct sway_seat *seat, | 499 | void seat_apply_config(struct sway_seat *seat, |
409 | enum sway_container_type type) { | ||
410 | struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container); | ||
411 | if (focus->type == type) { | ||
412 | return focus; | ||
413 | } | ||
414 | |||
415 | return container_parent(focus, type); | ||
416 | } | ||
417 | |||
418 | void sway_seat_set_config(struct sway_seat *seat, | ||
419 | struct seat_config *seat_config) { | 500 | struct seat_config *seat_config) { |
420 | // clear configs | ||
421 | free_seat_config(seat->config); | ||
422 | seat->config = NULL; | ||
423 | |||
424 | struct sway_seat_device *seat_device = NULL; | 501 | struct sway_seat_device *seat_device = NULL; |
425 | wl_list_for_each(seat_device, &seat->devices, link) { | ||
426 | seat_device->attachment_config = NULL; | ||
427 | } | ||
428 | 502 | ||
429 | if (!seat_config) { | 503 | if (!seat_config) { |
430 | return; | 504 | return; |
431 | } | 505 | } |
432 | 506 | ||
433 | // add configs | ||
434 | seat->config = copy_seat_config(seat_config); | ||
435 | |||
436 | wl_list_for_each(seat_device, &seat->devices, link) { | 507 | wl_list_for_each(seat_device, &seat->devices, link) { |
437 | sway_seat_configure_device(seat, seat_device->input_device); | 508 | seat_configure_device(seat, seat_device->input_device); |
438 | } | 509 | } |
439 | } | 510 | } |
511 | |||
512 | struct seat_config *seat_get_config(struct sway_seat *seat) { | ||
513 | struct seat_config *seat_config = NULL; | ||
514 | for (int i = 0; i < config->seat_configs->length; ++i ) { | ||
515 | seat_config = config->seat_configs->items[i]; | ||
516 | if (strcmp(seat->wlr_seat->name, seat_config->name) == 0) { | ||
517 | return seat_config; | ||
518 | } | ||
519 | } | ||
520 | |||
521 | return NULL; | ||
522 | } | ||
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 7c5f7304..3427c8ec 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -88,11 +88,11 @@ static void ipc_json_describe_output(struct sway_container *container, json_obje | |||
88 | json_object_new_string( | 88 | json_object_new_string( |
89 | ipc_json_get_output_transform(wlr_output->transform))); | 89 | ipc_json_get_output_transform(wlr_output->transform))); |
90 | 90 | ||
91 | struct sway_seat *seat = sway_input_manager_get_default_seat(input_manager); | 91 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); |
92 | const char *ws = NULL; | 92 | const char *ws = NULL; |
93 | if (seat) { | 93 | if (seat) { |
94 | struct sway_container *focus = | 94 | struct sway_container *focus = |
95 | sway_seat_get_focus_inactive(seat, container); | 95 | seat_get_focus_inactive(seat, container); |
96 | if (focus && focus->type != C_WORKSPACE) { | 96 | if (focus && focus->type != C_WORKSPACE) { |
97 | focus = container_parent(focus, C_WORKSPACE); | 97 | focus = container_parent(focus, C_WORKSPACE); |
98 | } | 98 | } |
@@ -139,8 +139,8 @@ json_object *ipc_json_describe_container(struct sway_container *c) { | |||
139 | return NULL; | 139 | return NULL; |
140 | } | 140 | } |
141 | 141 | ||
142 | struct sway_seat *seat = sway_input_manager_get_default_seat(input_manager); | 142 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); |
143 | bool focused = sway_seat_get_focus(seat) == c; | 143 | bool focused = seat_get_focus(seat) == c; |
144 | 144 | ||
145 | json_object *object = json_object_new_object(); | 145 | json_object *object = json_object_new_object(); |
146 | 146 | ||
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 869f1ed0..df5fb699 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -388,8 +388,8 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace, | |||
388 | // override the default focused indicator because | 388 | // override the default focused indicator because |
389 | // it's set differently for the get_workspaces reply | 389 | // it's set differently for the get_workspaces reply |
390 | struct sway_seat *seat = | 390 | struct sway_seat *seat = |
391 | sway_input_manager_get_default_seat(input_manager); | 391 | input_manager_get_default_seat(input_manager); |
392 | struct sway_container *focused_ws = sway_seat_get_focus(seat); | 392 | struct sway_container *focused_ws = seat_get_focus(seat); |
393 | if (focused_ws != NULL && focused_ws->type != C_WORKSPACE) { | 393 | if (focused_ws != NULL && focused_ws->type != C_WORKSPACE) { |
394 | focused_ws = container_parent(focused_ws, C_WORKSPACE); | 394 | focused_ws = container_parent(focused_ws, C_WORKSPACE); |
395 | } | 395 | } |
@@ -399,7 +399,7 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace, | |||
399 | json_object_new_boolean(focused)); | 399 | json_object_new_boolean(focused)); |
400 | json_object_array_add((json_object *)data, workspace_json); | 400 | json_object_array_add((json_object *)data, workspace_json); |
401 | 401 | ||
402 | focused_ws = sway_seat_get_focus_inactive(seat, workspace->parent); | 402 | focused_ws = seat_get_focus_inactive(seat, workspace->parent); |
403 | if (focused_ws->type != C_WORKSPACE) { | 403 | if (focused_ws->type != C_WORKSPACE) { |
404 | focused_ws = container_parent(focused_ws, C_WORKSPACE); | 404 | focused_ws = container_parent(focused_ws, C_WORKSPACE); |
405 | } | 405 | } |
diff --git a/sway/main.c b/sway/main.c index ded922ee..e7f8ddd3 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -118,7 +118,7 @@ void run_as_ipc_client(char *command, char *socket_path) { | |||
118 | static void log_env() { | 118 | static void log_env() { |
119 | const char *log_vars[] = { | 119 | const char *log_vars[] = { |
120 | "PATH", | 120 | "PATH", |
121 | "LD_LOAD_PATH", | 121 | "LD_LIBRARY_PATH", |
122 | "LD_PRELOAD_PATH", | 122 | "LD_PRELOAD_PATH", |
123 | "LD_LIBRARY_PATH", | 123 | "LD_LIBRARY_PATH", |
124 | "SWAY_CURSOR_THEME", | 124 | "SWAY_CURSOR_THEME", |
diff --git a/sway/meson.build b/sway/meson.build index 0cc620ea..a6a633a0 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -19,6 +19,8 @@ sway_sources = files( | |||
19 | 'commands/input.c', | 19 | 'commands/input.c', |
20 | 'commands/layout.c', | 20 | 'commands/layout.c', |
21 | 'commands/mode.c', | 21 | 'commands/mode.c', |
22 | 'commands/split.c', | ||
23 | 'commands/move.c', | ||
22 | 'commands/seat.c', | 24 | 'commands/seat.c', |
23 | 'commands/seat/attach.c', | 25 | 'commands/seat/attach.c', |
24 | 'commands/seat/fallback.c', | 26 | 'commands/seat/fallback.c', |
diff --git a/sway/server.c b/sway/server.c index f5cc199c..54945312 100644 --- a/sway/server.c +++ b/sway/server.c | |||
@@ -109,7 +109,7 @@ bool server_init(struct sway_server *server) { | |||
109 | return false; | 109 | return false; |
110 | } | 110 | } |
111 | 111 | ||
112 | input_manager = sway_input_manager_create(server); | 112 | input_manager = input_manager_create(server); |
113 | return true; | 113 | return true; |
114 | } | 114 | } |
115 | 115 | ||
diff --git a/sway/tree/container.c b/sway/tree/container.c index 746dbf1f..4db93ce8 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -33,12 +33,29 @@ static list_t *get_bfs_queue() { | |||
33 | return bfs_queue; | 33 | return bfs_queue; |
34 | } | 34 | } |
35 | 35 | ||
36 | const char *container_type_to_str(enum sway_container_type type) { | ||
37 | switch (type) { | ||
38 | case C_ROOT: | ||
39 | return "C_ROOT"; | ||
40 | case C_OUTPUT: | ||
41 | return "C_OUTPUT"; | ||
42 | case C_WORKSPACE: | ||
43 | return "C_WORKSPACE"; | ||
44 | case C_CONTAINER: | ||
45 | return "C_CONTAINER"; | ||
46 | case C_VIEW: | ||
47 | return "C_VIEW"; | ||
48 | default: | ||
49 | return "C_UNKNOWN"; | ||
50 | } | ||
51 | } | ||
52 | |||
36 | static void notify_new_container(struct sway_container *container) { | 53 | static void notify_new_container(struct sway_container *container) { |
37 | wl_signal_emit(&root_container.sway_root->events.new_container, container); | 54 | wl_signal_emit(&root_container.sway_root->events.new_container, container); |
38 | ipc_event_window(container, "new"); | 55 | ipc_event_window(container, "new"); |
39 | } | 56 | } |
40 | 57 | ||
41 | static struct sway_container *container_create(enum sway_container_type type) { | 58 | struct sway_container *container_create(enum sway_container_type type) { |
42 | // next id starts at 1 because 0 is assigned to root_container in layout.c | 59 | // next id starts at 1 because 0 is assigned to root_container in layout.c |
43 | static size_t next_id = 1; | 60 | static size_t next_id = 1; |
44 | struct sway_container *c = calloc(1, sizeof(struct sway_container)); | 61 | struct sway_container *c = calloc(1, sizeof(struct sway_container)); |
@@ -54,11 +71,12 @@ static struct sway_container *container_create(enum sway_container_type type) { | |||
54 | } | 71 | } |
55 | 72 | ||
56 | wl_signal_init(&c->events.destroy); | 73 | wl_signal_init(&c->events.destroy); |
74 | wl_signal_init(&c->events.reparent); | ||
57 | 75 | ||
58 | return c; | 76 | return c; |
59 | } | 77 | } |
60 | 78 | ||
61 | struct sway_container *container_destroy(struct sway_container *cont) { | 79 | static struct sway_container *_container_destroy(struct sway_container *cont) { |
62 | if (cont == NULL) { | 80 | if (cont == NULL) { |
63 | return NULL; | 81 | return NULL; |
64 | } | 82 | } |
@@ -66,13 +84,14 @@ struct sway_container *container_destroy(struct sway_container *cont) { | |||
66 | wl_signal_emit(&cont->events.destroy, cont); | 84 | wl_signal_emit(&cont->events.destroy, cont); |
67 | 85 | ||
68 | struct sway_container *parent = cont->parent; | 86 | struct sway_container *parent = cont->parent; |
69 | if (cont->children) { | 87 | if (cont->children != NULL) { |
70 | // remove children until there are no more, container_destroy calls | 88 | // remove children until there are no more, container_destroy calls |
71 | // container_remove_child, which removes child from this container | 89 | // container_remove_child, which removes child from this container |
72 | while (cont->children->length) { | 90 | while (cont->children != NULL && cont->children->length != 0) { |
73 | container_destroy(cont->children->items[0]); | 91 | struct sway_container *child = cont->children->items[0]; |
92 | container_remove_child(child); | ||
93 | container_destroy(child); | ||
74 | } | 94 | } |
75 | list_free(cont->children); | ||
76 | } | 95 | } |
77 | if (cont->marks) { | 96 | if (cont->marks) { |
78 | list_foreach(cont->marks, free); | 97 | list_foreach(cont->marks, free); |
@@ -84,10 +103,19 @@ struct sway_container *container_destroy(struct sway_container *cont) { | |||
84 | if (cont->name) { | 103 | if (cont->name) { |
85 | free(cont->name); | 104 | free(cont->name); |
86 | } | 105 | } |
106 | list_free(cont->children); | ||
107 | cont->children = NULL; | ||
87 | free(cont); | 108 | free(cont); |
88 | return parent; | 109 | return parent; |
89 | } | 110 | } |
90 | 111 | ||
112 | struct sway_container *container_destroy(struct sway_container *cont) { | ||
113 | struct sway_container *parent = _container_destroy(cont); | ||
114 | parent = container_reap_empty(parent); | ||
115 | arrange_windows(&root_container, -1, -1); | ||
116 | return parent; | ||
117 | } | ||
118 | |||
91 | struct sway_container *container_output_create( | 119 | struct sway_container *container_output_create( |
92 | struct sway_output *sway_output) { | 120 | struct sway_output *sway_output) { |
93 | struct wlr_box size; | 121 | struct wlr_box size; |
@@ -144,7 +172,7 @@ struct sway_container *container_output_create( | |||
144 | struct sway_seat *seat = NULL; | 172 | struct sway_seat *seat = NULL; |
145 | wl_list_for_each(seat, &input_manager->seats, link) { | 173 | wl_list_for_each(seat, &input_manager->seats, link) { |
146 | if (!seat->has_focus) { | 174 | if (!seat->has_focus) { |
147 | sway_seat_set_focus(seat, ws); | 175 | seat_set_focus(seat, ws); |
148 | } | 176 | } |
149 | } | 177 | } |
150 | 178 | ||
@@ -395,3 +423,17 @@ bool container_has_anscestor(struct sway_container *descendant, | |||
395 | } | 423 | } |
396 | return false; | 424 | return false; |
397 | } | 425 | } |
426 | |||
427 | static bool find_child_func(struct sway_container *con, void *data) { | ||
428 | struct sway_container *child = data; | ||
429 | return con == child; | ||
430 | } | ||
431 | |||
432 | bool container_has_child(struct sway_container *con, | ||
433 | struct sway_container *child) { | ||
434 | if (child == NULL || child->type == C_VIEW || | ||
435 | child->children->length == 0) { | ||
436 | return false; | ||
437 | } | ||
438 | return container_find(con, find_child_func, child); | ||
439 | } | ||
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index ce0682dc..95a84d12 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <assert.h> | ||
2 | #include <ctype.h> | 3 | #include <ctype.h> |
3 | #include <math.h> | 4 | #include <math.h> |
4 | #include <stdbool.h> | 5 | #include <stdbool.h> |
@@ -57,7 +58,7 @@ void layout_init(void) { | |||
57 | 58 | ||
58 | root_container.sway_root = calloc(1, sizeof(*root_container.sway_root)); | 59 | root_container.sway_root = calloc(1, sizeof(*root_container.sway_root)); |
59 | root_container.sway_root->output_layout = wlr_output_layout_create(); | 60 | root_container.sway_root->output_layout = wlr_output_layout_create(); |
60 | wl_list_init(&root_container.sway_root->unmanaged_views); | 61 | wl_list_init(&root_container.sway_root->xwayland_unmanaged); |
61 | wl_signal_init(&root_container.sway_root->events.new_container); | 62 | wl_signal_init(&root_container.sway_root->events.new_container); |
62 | 63 | ||
63 | root_container.sway_root->output_layout_change.notify = | 64 | root_container.sway_root->output_layout_change.notify = |
@@ -103,11 +104,13 @@ void container_add_child(struct sway_container *parent, | |||
103 | } | 104 | } |
104 | 105 | ||
105 | struct sway_container *container_reap_empty(struct sway_container *container) { | 106 | struct sway_container *container_reap_empty(struct sway_container *container) { |
106 | if (!sway_assert(container, "reaping null container")) { | 107 | if (container == NULL) { |
107 | return NULL; | 108 | return NULL; |
108 | } | 109 | } |
109 | wlr_log(L_DEBUG, "reaping %p %s", container, container->name); | 110 | wlr_log(L_DEBUG, "Reaping %p %s '%s'", container, |
110 | while (container != &root_container && container->children->length == 0) { | 111 | container_type_to_str(container->type), container->name); |
112 | while (container->type != C_ROOT && container->type != C_OUTPUT | ||
113 | && container->children->length == 0) { | ||
111 | if (container->type == C_WORKSPACE) { | 114 | if (container->type == C_WORKSPACE) { |
112 | if (!workspace_is_visible(container)) { | 115 | if (!workspace_is_visible(container)) { |
113 | struct sway_container *parent = container->parent; | 116 | struct sway_container *parent = container->parent; |
@@ -135,25 +138,49 @@ struct sway_container *container_remove_child(struct sway_container *child) { | |||
135 | } | 138 | } |
136 | } | 139 | } |
137 | child->parent = NULL; | 140 | child->parent = NULL; |
138 | return container_reap_empty(parent); | 141 | return parent; |
139 | } | 142 | } |
140 | 143 | ||
141 | void container_move_to(struct sway_container* container, | 144 | void container_move_to(struct sway_container *container, |
142 | struct sway_container* destination) { | 145 | struct sway_container *destination) { |
143 | if (container == destination | 146 | if (container == destination |
144 | || container_has_anscestor(container, destination)) { | 147 | || container_has_anscestor(container, destination)) { |
145 | return; | 148 | return; |
146 | } | 149 | } |
147 | struct sway_container *old_parent = container_remove_child(container); | 150 | struct sway_container *old_parent = container_remove_child(container); |
148 | container->width = container->height = 0; | 151 | container->width = container->height = 0; |
149 | struct sway_container *new_parent = | 152 | struct sway_container *new_parent; |
150 | container_add_sibling(destination, container); | 153 | if (destination->type == C_VIEW) { |
154 | new_parent = container_add_sibling(destination, container); | ||
155 | } else { | ||
156 | new_parent = destination; | ||
157 | container_add_child(destination, container); | ||
158 | } | ||
159 | wl_signal_emit(&container->events.reparent, old_parent); | ||
160 | if (container->type == C_WORKSPACE) { | ||
161 | struct sway_seat *seat = input_manager_get_default_seat( | ||
162 | input_manager); | ||
163 | if (old_parent->children->length == 0) { | ||
164 | char *ws_name = workspace_next_name(old_parent->name); | ||
165 | struct sway_container *ws = | ||
166 | container_workspace_create(old_parent, ws_name); | ||
167 | free(ws_name); | ||
168 | seat_set_focus(seat, ws); | ||
169 | } | ||
170 | container_sort_workspaces(new_parent); | ||
171 | seat_set_focus(seat, new_parent); | ||
172 | } | ||
151 | if (old_parent) { | 173 | if (old_parent) { |
152 | arrange_windows(old_parent, -1, -1); | 174 | arrange_windows(old_parent, -1, -1); |
153 | } | 175 | } |
154 | arrange_windows(new_parent, -1, -1); | 176 | arrange_windows(new_parent, -1, -1); |
155 | } | 177 | } |
156 | 178 | ||
179 | void container_move(struct sway_container *container, | ||
180 | enum movement_direction dir, int move_amt) { | ||
181 | // TODO | ||
182 | } | ||
183 | |||
157 | enum sway_container_layout container_get_default_layout( | 184 | enum sway_container_layout container_get_default_layout( |
158 | struct sway_container *output) { | 185 | struct sway_container *output) { |
159 | if (config->default_layout != L_NONE) { | 186 | if (config->default_layout != L_NONE) { |
@@ -248,8 +275,8 @@ void arrange_windows(struct sway_container *container, | |||
248 | struct wlr_box *area = &output->sway_output->usable_area; | 275 | struct wlr_box *area = &output->sway_output->usable_area; |
249 | wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d", | 276 | wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d", |
250 | area->width, area->height, area->x, area->y); | 277 | area->width, area->height, area->x, area->y); |
251 | container->width = area->width; | 278 | container->width = width = area->width; |
252 | container->height = area->height; | 279 | container->height = height = area->height; |
253 | container->x = x = area->x; | 280 | container->x = x = area->x; |
254 | container->y = y = area->y; | 281 | container->y = y = area->y; |
255 | wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", | 282 | wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", |
@@ -261,7 +288,7 @@ void arrange_windows(struct sway_container *container, | |||
261 | { | 288 | { |
262 | container->width = width; | 289 | container->width = width; |
263 | container->height = height; | 290 | container->height = height; |
264 | view_set_size(container->sway_view, | 291 | view_configure(container->sway_view, container->x, container->y, |
265 | container->width, container->height); | 292 | container->width, container->height); |
266 | wlr_log(L_DEBUG, "Set view to %.f x %.f @ %.f, %.f", | 293 | wlr_log(L_DEBUG, "Set view to %.f x %.f @ %.f, %.f", |
267 | container->width, container->height, | 294 | container->width, container->height, |
@@ -322,7 +349,14 @@ static void apply_horiz_layout(struct sway_container *container, | |||
322 | wlr_log(L_DEBUG, | 349 | wlr_log(L_DEBUG, |
323 | "Calculating arrangement for %p:%d (will scale %f by %f)", | 350 | "Calculating arrangement for %p:%d (will scale %f by %f)", |
324 | child, child->type, width, scale); | 351 | child, child->type, width, scale); |
325 | view_set_position(child->sway_view, child_x, y); | 352 | |
353 | if (child->type == C_VIEW) { | ||
354 | view_configure(child->sway_view, child_x, y, child->width, | ||
355 | child->height); | ||
356 | } else { | ||
357 | child->x = child_x; | ||
358 | child->y = y; | ||
359 | } | ||
326 | 360 | ||
327 | if (i == end - 1) { | 361 | if (i == end - 1) { |
328 | double remaining_width = x + width - child_x; | 362 | double remaining_width = x + width - child_x; |
@@ -373,7 +407,13 @@ void apply_vert_layout(struct sway_container *container, | |||
373 | wlr_log(L_DEBUG, | 407 | wlr_log(L_DEBUG, |
374 | "Calculating arrangement for %p:%d (will scale %f by %f)", | 408 | "Calculating arrangement for %p:%d (will scale %f by %f)", |
375 | child, child->type, height, scale); | 409 | child, child->type, height, scale); |
376 | view_set_position(child->sway_view, x, child_y); | 410 | if (child->type == C_VIEW) { |
411 | view_configure(child->sway_view, x, child_y, child->width, | ||
412 | child->height); | ||
413 | } else { | ||
414 | child->x = x; | ||
415 | child->y = child_y; | ||
416 | } | ||
377 | 417 | ||
378 | if (i == end - 1) { | 418 | if (i == end - 1) { |
379 | double remaining_height = y + height - child_y; | 419 | double remaining_height = y + height - child_y; |
@@ -404,7 +444,7 @@ static struct sway_container *get_swayc_in_output_direction( | |||
404 | return NULL; | 444 | return NULL; |
405 | } | 445 | } |
406 | 446 | ||
407 | struct sway_container *ws = sway_seat_get_focus_inactive(seat, output); | 447 | struct sway_container *ws = seat_get_focus_inactive(seat, output); |
408 | if (ws->type != C_WORKSPACE) { | 448 | if (ws->type != C_WORKSPACE) { |
409 | ws = container_parent(ws, C_WORKSPACE); | 449 | ws = container_parent(ws, C_WORKSPACE); |
410 | } | 450 | } |
@@ -425,7 +465,7 @@ static struct sway_container *get_swayc_in_output_direction( | |||
425 | case MOVE_UP: | 465 | case MOVE_UP: |
426 | case MOVE_DOWN: { | 466 | case MOVE_DOWN: { |
427 | struct sway_container *focused = | 467 | struct sway_container *focused = |
428 | sway_seat_get_focus_inactive(seat, ws); | 468 | seat_get_focus_inactive(seat, ws); |
429 | if (focused && focused->parent) { | 469 | if (focused && focused->parent) { |
430 | struct sway_container *parent = focused->parent; | 470 | struct sway_container *parent = focused->parent; |
431 | if (parent->layout == L_VERT) { | 471 | if (parent->layout == L_VERT) { |
@@ -505,11 +545,11 @@ static struct sway_container *sway_output_from_wlr(struct wlr_output *output) { | |||
505 | return NULL; | 545 | return NULL; |
506 | } | 546 | } |
507 | 547 | ||
508 | static struct sway_container *get_swayc_in_direction_under( | 548 | struct sway_container *container_get_in_direction( |
509 | struct sway_container *container, enum movement_direction dir, | 549 | struct sway_container *container, struct sway_seat *seat, |
510 | struct sway_seat *seat, struct sway_container *limit) { | 550 | enum movement_direction dir) { |
511 | if (dir == MOVE_CHILD) { | 551 | if (dir == MOVE_CHILD) { |
512 | return sway_seat_get_focus_inactive(seat, container); | 552 | return seat_get_focus_inactive(seat, container); |
513 | } | 553 | } |
514 | 554 | ||
515 | struct sway_container *parent = container->parent; | 555 | struct sway_container *parent = container->parent; |
@@ -521,26 +561,6 @@ static struct sway_container *get_swayc_in_direction_under( | |||
521 | } | 561 | } |
522 | } | 562 | } |
523 | 563 | ||
524 | if (dir == MOVE_PREV || dir == MOVE_NEXT) { | ||
525 | int focused_idx = index_child(container); | ||
526 | if (focused_idx == -1) { | ||
527 | return NULL; | ||
528 | } else { | ||
529 | int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) % | ||
530 | parent->children->length; | ||
531 | if (desired < 0) { | ||
532 | desired += parent->children->length; | ||
533 | } | ||
534 | return parent->children->items[desired]; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | // If moving to an adjacent output we need a starting position (since this | ||
539 | // output might border to multiple outputs). | ||
540 | //struct wlc_point abs_pos; | ||
541 | //get_layout_center_position(container, &abs_pos); | ||
542 | |||
543 | |||
544 | // TODO WLR fullscreen | 564 | // TODO WLR fullscreen |
545 | /* | 565 | /* |
546 | if (container->type == C_VIEW && swayc_is_fullscreen(container)) { | 566 | if (container->type == C_VIEW && swayc_is_fullscreen(container)) { |
@@ -559,7 +579,6 @@ static struct sway_container *get_swayc_in_direction_under( | |||
559 | 579 | ||
560 | struct sway_container *wrap_candidate = NULL; | 580 | struct sway_container *wrap_candidate = NULL; |
561 | while (true) { | 581 | while (true) { |
562 | // Test if we can even make a difference here | ||
563 | bool can_move = false; | 582 | bool can_move = false; |
564 | int desired; | 583 | int desired; |
565 | int idx = index_child(container); | 584 | int idx = index_child(container); |
@@ -589,7 +608,7 @@ static struct sway_container *get_swayc_in_direction_under( | |||
589 | } | 608 | } |
590 | if (next->children && next->children->length) { | 609 | if (next->children && next->children->length) { |
591 | // TODO consider floating children as well | 610 | // TODO consider floating children as well |
592 | return sway_seat_get_focus_inactive(seat, next); | 611 | return seat_get_focus_by_type(seat, next, C_VIEW); |
593 | } else { | 612 | } else { |
594 | return next; | 613 | return next; |
595 | } | 614 | } |
@@ -619,21 +638,23 @@ static struct sway_container *get_swayc_in_direction_under( | |||
619 | wrap_candidate = parent->children->items[0]; | 638 | wrap_candidate = parent->children->items[0]; |
620 | } | 639 | } |
621 | if (config->force_focus_wrapping) { | 640 | if (config->force_focus_wrapping) { |
622 | return wrap_candidate; | 641 | return seat_get_focus_by_type(seat, |
642 | wrap_candidate, C_VIEW); | ||
623 | } | 643 | } |
624 | } | 644 | } |
625 | } else { | 645 | } else { |
626 | wlr_log(L_DEBUG, | 646 | wlr_log(L_DEBUG, |
627 | "cont %d-%p dir %i sibling %d: %p", idx, | 647 | "cont %d-%p dir %i sibling %d: %p", idx, |
628 | container, dir, desired, parent->children->items[desired]); | 648 | container, dir, desired, parent->children->items[desired]); |
629 | return parent->children->items[desired]; | 649 | return seat_get_focus_by_type(seat, |
650 | parent->children->items[desired], C_VIEW); | ||
630 | } | 651 | } |
631 | } | 652 | } |
632 | 653 | ||
633 | if (!can_move) { | 654 | if (!can_move) { |
634 | container = parent; | 655 | container = parent; |
635 | parent = parent->parent; | 656 | parent = parent->parent; |
636 | if (!parent || container == limit) { | 657 | if (!parent) { |
637 | // wrapping is the last chance | 658 | // wrapping is the last chance |
638 | return wrap_candidate; | 659 | return wrap_candidate; |
639 | } | 660 | } |
@@ -641,8 +662,70 @@ static struct sway_container *get_swayc_in_direction_under( | |||
641 | } | 662 | } |
642 | } | 663 | } |
643 | 664 | ||
644 | struct sway_container *container_get_in_direction( | 665 | struct sway_container *container_replace_child(struct sway_container *child, |
645 | struct sway_container *container, struct sway_seat *seat, | 666 | struct sway_container *new_child) { |
646 | enum movement_direction dir) { | 667 | struct sway_container *parent = child->parent; |
647 | return get_swayc_in_direction_under(container, dir, seat, NULL); | 668 | if (parent == NULL) { |
669 | return NULL; | ||
670 | } | ||
671 | int i = index_child(child); | ||
672 | |||
673 | // TODO floating | ||
674 | parent->children->items[i] = new_child; | ||
675 | new_child->parent = parent; | ||
676 | child->parent = NULL; | ||
677 | |||
678 | // Set geometry for new child | ||
679 | new_child->x = child->x; | ||
680 | new_child->y = child->y; | ||
681 | new_child->width = child->width; | ||
682 | new_child->height = child->height; | ||
683 | |||
684 | // reset geometry for child | ||
685 | child->width = 0; | ||
686 | child->height = 0; | ||
687 | |||
688 | return parent; | ||
689 | } | ||
690 | |||
691 | struct sway_container *container_split(struct sway_container *child, | ||
692 | enum sway_container_layout layout) { | ||
693 | // TODO floating: cannot split a floating container | ||
694 | if (!sway_assert(child, "child cannot be null")) { | ||
695 | return NULL; | ||
696 | } | ||
697 | struct sway_container *cont = container_create(C_CONTAINER); | ||
698 | |||
699 | wlr_log(L_DEBUG, "creating container %p around %p", cont, child); | ||
700 | |||
701 | cont->prev_layout = L_NONE; | ||
702 | cont->width = child->width; | ||
703 | cont->height = child->height; | ||
704 | cont->x = child->x; | ||
705 | cont->y = child->y; | ||
706 | |||
707 | if (child->type == C_WORKSPACE) { | ||
708 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); | ||
709 | struct sway_container *workspace = child; | ||
710 | bool set_focus = (seat_get_focus(seat) == workspace); | ||
711 | |||
712 | while (workspace->children->length) { | ||
713 | struct sway_container *ws_child = workspace->children->items[0]; | ||
714 | container_remove_child(ws_child); | ||
715 | container_add_child(cont, ws_child); | ||
716 | } | ||
717 | |||
718 | container_add_child(workspace, cont); | ||
719 | container_set_layout(workspace, layout); | ||
720 | |||
721 | if (set_focus) { | ||
722 | seat_set_focus(seat, cont); | ||
723 | } | ||
724 | } else { | ||
725 | cont->layout = layout; | ||
726 | container_replace_child(child, cont); | ||
727 | container_add_child(cont, child); | ||
728 | } | ||
729 | |||
730 | return cont; | ||
648 | } | 731 | } |
diff --git a/sway/tree/output.c b/sway/tree/output.c index 7248fd00..0509db23 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <strings.h> | ||
1 | #include "sway/tree/container.h" | 2 | #include "sway/tree/container.h" |
2 | #include "sway/tree/layout.h" | 3 | #include "sway/tree/layout.h" |
3 | #include "sway/output.h" | 4 | #include "sway/output.h" |
@@ -29,6 +30,7 @@ struct sway_container *container_output_destroy(struct sway_container *output) { | |||
29 | wl_list_remove(&output->sway_output->destroy.link); | 30 | wl_list_remove(&output->sway_output->destroy.link); |
30 | wl_list_remove(&output->sway_output->mode.link); | 31 | wl_list_remove(&output->sway_output->mode.link); |
31 | wl_list_remove(&output->sway_output->transform.link); | 32 | wl_list_remove(&output->sway_output->transform.link); |
33 | wl_list_remove(&output->sway_output->scale.link); | ||
32 | 34 | ||
33 | wl_list_remove(&output->sway_output->damage_destroy.link); | 35 | wl_list_remove(&output->sway_output->damage_destroy.link); |
34 | wl_list_remove(&output->sway_output->damage_frame.link); | 36 | wl_list_remove(&output->sway_output->damage_frame.link); |
@@ -37,3 +39,13 @@ struct sway_container *container_output_destroy(struct sway_container *output) { | |||
37 | container_destroy(output); | 39 | container_destroy(output); |
38 | return &root_container; | 40 | return &root_container; |
39 | } | 41 | } |
42 | |||
43 | struct sway_container *output_by_name(const char *name) { | ||
44 | for (int i = 0; i < root_container.children->length; ++i) { | ||
45 | struct sway_container *output = root_container.children->items[i]; | ||
46 | if (strcasecmp(output->name, name) == 0){ | ||
47 | return output; | ||
48 | } | ||
49 | } | ||
50 | return NULL; | ||
51 | } | ||
diff --git a/sway/tree/view.c b/sway/tree/view.c index b7d1a41b..09c804e4 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <stdlib.h> | ||
1 | #include <wayland-server.h> | 2 | #include <wayland-server.h> |
2 | #include <wlr/types/wlr_output_layout.h> | 3 | #include <wlr/types/wlr_output_layout.h> |
3 | #include "log.h" | 4 | #include "log.h" |
@@ -6,82 +7,117 @@ | |||
6 | #include "sway/tree/layout.h" | 7 | #include "sway/tree/layout.h" |
7 | #include "sway/tree/view.h" | 8 | #include "sway/tree/view.h" |
8 | 9 | ||
10 | struct sway_view *view_create(enum sway_view_type type, | ||
11 | const struct sway_view_impl *impl) { | ||
12 | struct sway_view *view = calloc(1, sizeof(struct sway_view)); | ||
13 | if (view == NULL) { | ||
14 | return NULL; | ||
15 | } | ||
16 | view->type = type; | ||
17 | view->impl = impl; | ||
18 | return view; | ||
19 | } | ||
20 | |||
21 | void view_destroy(struct sway_view *view) { | ||
22 | if (view == NULL) { | ||
23 | return; | ||
24 | } | ||
25 | |||
26 | if (view->surface != NULL) { | ||
27 | view_unmap(view); | ||
28 | } | ||
29 | |||
30 | container_view_destroy(view->swayc); | ||
31 | free(view); | ||
32 | } | ||
33 | |||
9 | const char *view_get_title(struct sway_view *view) { | 34 | const char *view_get_title(struct sway_view *view) { |
10 | if (view->iface.get_prop) { | 35 | if (view->impl->get_prop) { |
11 | return view->iface.get_prop(view, VIEW_PROP_TITLE); | 36 | return view->impl->get_prop(view, VIEW_PROP_TITLE); |
12 | } | 37 | } |
13 | return NULL; | 38 | return NULL; |
14 | } | 39 | } |
15 | 40 | ||
16 | const char *view_get_app_id(struct sway_view *view) { | 41 | const char *view_get_app_id(struct sway_view *view) { |
17 | if (view->iface.get_prop) { | 42 | if (view->impl->get_prop) { |
18 | return view->iface.get_prop(view, VIEW_PROP_APP_ID); | 43 | return view->impl->get_prop(view, VIEW_PROP_APP_ID); |
19 | } | 44 | } |
20 | return NULL; | 45 | return NULL; |
21 | } | 46 | } |
22 | 47 | ||
23 | const char *view_get_class(struct sway_view *view) { | 48 | const char *view_get_class(struct sway_view *view) { |
24 | if (view->iface.get_prop) { | 49 | if (view->impl->get_prop) { |
25 | return view->iface.get_prop(view, VIEW_PROP_CLASS); | 50 | return view->impl->get_prop(view, VIEW_PROP_CLASS); |
26 | } | 51 | } |
27 | return NULL; | 52 | return NULL; |
28 | } | 53 | } |
29 | 54 | ||
30 | const char *view_get_instance(struct sway_view *view) { | 55 | const char *view_get_instance(struct sway_view *view) { |
31 | if (view->iface.get_prop) { | 56 | if (view->impl->get_prop) { |
32 | return view->iface.get_prop(view, VIEW_PROP_INSTANCE); | 57 | return view->impl->get_prop(view, VIEW_PROP_INSTANCE); |
33 | } | 58 | } |
34 | return NULL; | 59 | return NULL; |
35 | } | 60 | } |
36 | 61 | ||
37 | void view_set_size(struct sway_view *view, int width, int height) { | 62 | void view_configure(struct sway_view *view, double ox, double oy, int width, |
38 | if (view->iface.set_size) { | 63 | int height) { |
39 | struct wlr_box box = { | 64 | if (view->impl->configure) { |
40 | .x = view->swayc->x, | 65 | view->impl->configure(view, ox, oy, width, height); |
41 | .y = view->swayc->y, | ||
42 | .width = view->width, | ||
43 | .height = view->height, | ||
44 | }; | ||
45 | view->iface.set_size(view, width, height); | ||
46 | view_update_outputs(view, &box); | ||
47 | } | 66 | } |
48 | } | 67 | } |
49 | 68 | ||
50 | // TODO make view coordinates in layout coordinates | 69 | void view_set_activated(struct sway_view *view, bool activated) { |
51 | void view_set_position(struct sway_view *view, double ox, double oy) { | 70 | if (view->impl->set_activated) { |
52 | if (view->iface.set_position) { | 71 | view->impl->set_activated(view, activated); |
53 | struct wlr_box box = { | ||
54 | .x = view->swayc->x, | ||
55 | .y = view->swayc->y, | ||
56 | .width = view->width, | ||
57 | .height = view->height, | ||
58 | }; | ||
59 | view->iface.set_position(view, ox, oy); | ||
60 | view_update_outputs(view, &box); | ||
61 | } | 72 | } |
62 | } | 73 | } |
63 | 74 | ||
64 | void view_set_activated(struct sway_view *view, bool activated) { | 75 | void view_close(struct sway_view *view) { |
65 | if (view->iface.set_activated) { | 76 | if (view->impl->close) { |
66 | view->iface.set_activated(view, activated); | 77 | view->impl->close(view); |
67 | } | 78 | } |
68 | } | 79 | } |
69 | 80 | ||
70 | void view_close(struct sway_view *view) { | 81 | struct sway_container *container_view_destroy(struct sway_container *view) { |
71 | if (view->iface.close) { | 82 | if (!view) { |
72 | view->iface.close(view); | 83 | return NULL; |
73 | } | 84 | } |
85 | wlr_log(L_DEBUG, "Destroying view '%s'", view->name); | ||
86 | struct sway_container *parent = container_destroy(view); | ||
87 | arrange_windows(parent, -1, -1); | ||
88 | return parent; | ||
89 | } | ||
90 | |||
91 | void view_damage_whole(struct sway_view *view) { | ||
92 | for (int i = 0; i < root_container.children->length; ++i) { | ||
93 | struct sway_container *cont = root_container.children->items[i]; | ||
94 | if (cont->type == C_OUTPUT) { | ||
95 | output_damage_whole_view(cont->sway_output, view); | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
100 | void view_damage_from(struct sway_view *view) { | ||
101 | // TODO | ||
102 | view_damage_whole(view); | ||
103 | } | ||
104 | |||
105 | static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) { | ||
106 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | ||
107 | |||
108 | box->x = output->x + view->swayc->x; | ||
109 | box->y = output->y + view->swayc->y; | ||
110 | box->width = view->width; | ||
111 | box->height = view->height; | ||
74 | } | 112 | } |
75 | 113 | ||
76 | void view_update_outputs(struct sway_view *view, const struct wlr_box *before) { | 114 | static void view_update_outputs(struct sway_view *view, |
115 | const struct wlr_box *before) { | ||
116 | struct wlr_box box; | ||
117 | view_get_layout_box(view, &box); | ||
118 | |||
77 | struct wlr_output_layout *output_layout = | 119 | struct wlr_output_layout *output_layout = |
78 | root_container.sway_root->output_layout; | 120 | root_container.sway_root->output_layout; |
79 | struct wlr_box box = { | ||
80 | .x = view->swayc->x, | ||
81 | .y = view->swayc->y, | ||
82 | .width = view->width, | ||
83 | .height = view->height, | ||
84 | }; | ||
85 | struct wlr_output_layout_output *layout_output; | 121 | struct wlr_output_layout_output *layout_output; |
86 | wl_list_for_each(layout_output, &output_layout->outputs, link) { | 122 | wl_list_for_each(layout_output, &output_layout->outputs, link) { |
87 | bool intersected = before != NULL && wlr_output_layout_intersects( | 123 | bool intersected = before != NULL && wlr_output_layout_intersects( |
@@ -97,27 +133,63 @@ void view_update_outputs(struct sway_view *view, const struct wlr_box *before) { | |||
97 | } | 133 | } |
98 | } | 134 | } |
99 | 135 | ||
100 | struct sway_container *container_view_destroy(struct sway_container *view) { | 136 | void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { |
101 | if (!view) { | 137 | if (!sway_assert(view->surface == NULL, "cannot map mapped view")) { |
102 | return NULL; | 138 | return; |
103 | } | 139 | } |
104 | wlr_log(L_DEBUG, "Destroying view '%s'", view->name); | 140 | |
105 | struct sway_container *parent = container_destroy(view); | 141 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
106 | arrange_windows(parent, -1, -1); | 142 | struct sway_container *focus = seat_get_focus_inactive(seat, |
107 | return parent; | 143 | &root_container); |
144 | struct sway_container *cont = container_view_create(focus, view); | ||
145 | |||
146 | view->surface = wlr_surface; | ||
147 | view->swayc = cont; | ||
148 | |||
149 | arrange_windows(cont->parent, -1, -1); | ||
150 | input_manager_set_focus(input_manager, cont); | ||
151 | |||
152 | view_damage_whole(view); | ||
153 | view_update_outputs(view, NULL); | ||
108 | } | 154 | } |
109 | 155 | ||
110 | void view_damage_whole(struct sway_view *view) { | 156 | void view_unmap(struct sway_view *view) { |
111 | struct sway_container *cont = NULL; | 157 | if (!sway_assert(view->surface != NULL, "cannot unmap unmapped view")) { |
112 | for (int i = 0; i < root_container.children->length; ++i) { | 158 | return; |
113 | cont = root_container.children->items[i]; | ||
114 | if (cont->type == C_OUTPUT) { | ||
115 | output_damage_whole_view(cont->sway_output, view); | ||
116 | } | ||
117 | } | 159 | } |
160 | |||
161 | view_damage_whole(view); | ||
162 | |||
163 | container_view_destroy(view->swayc); | ||
164 | |||
165 | view->swayc = NULL; | ||
166 | view->surface = NULL; | ||
118 | } | 167 | } |
119 | 168 | ||
120 | void view_damage_from(struct sway_view *view) { | 169 | void view_update_position(struct sway_view *view, double ox, double oy) { |
121 | // TODO | 170 | if (view->swayc->x == ox && view->swayc->y == oy) { |
171 | return; | ||
172 | } | ||
173 | |||
174 | struct wlr_box box; | ||
175 | view_get_layout_box(view, &box); | ||
176 | view_damage_whole(view); | ||
177 | view->swayc->x = ox; | ||
178 | view->swayc->y = oy; | ||
179 | view_update_outputs(view, &box); | ||
180 | view_damage_whole(view); | ||
181 | } | ||
182 | |||
183 | void view_update_size(struct sway_view *view, int width, int height) { | ||
184 | if (view->width == width && view->height == height) { | ||
185 | return; | ||
186 | } | ||
187 | |||
188 | struct wlr_box box; | ||
189 | view_get_layout_box(view, &box); | ||
190 | view_damage_whole(view); | ||
191 | view->width = width; | ||
192 | view->height = height; | ||
193 | view_update_outputs(view, &box); | ||
122 | view_damage_whole(view); | 194 | view_damage_whole(view); |
123 | } | 195 | } |
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index d6fd7c70..8077de2e 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -176,7 +176,7 @@ static bool _workspace_by_name(struct sway_container *view, void *data) { | |||
176 | struct sway_container *workspace_by_name(const char *name) { | 176 | struct sway_container *workspace_by_name(const char *name) { |
177 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 177 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
178 | struct sway_container *current_workspace = NULL, *current_output = NULL; | 178 | struct sway_container *current_workspace = NULL, *current_output = NULL; |
179 | struct sway_container *focus = sway_seat_get_focus(seat); | 179 | struct sway_container *focus = seat_get_focus(seat); |
180 | if (focus) { | 180 | if (focus) { |
181 | current_workspace = container_parent(focus, C_WORKSPACE); | 181 | current_workspace = container_parent(focus, C_WORKSPACE); |
182 | current_output = container_parent(focus, C_OUTPUT); | 182 | current_output = container_parent(focus, C_OUTPUT); |
@@ -218,7 +218,7 @@ struct sway_container *workspace_create(const char *name) { | |||
218 | // Otherwise create a new one | 218 | // Otherwise create a new one |
219 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 219 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
220 | struct sway_container *focus = | 220 | struct sway_container *focus = |
221 | sway_seat_get_focus_inactive(seat, &root_container); | 221 | seat_get_focus_inactive(seat, &root_container); |
222 | parent = focus; | 222 | parent = focus; |
223 | parent = container_parent(parent, C_OUTPUT); | 223 | parent = container_parent(parent, C_OUTPUT); |
224 | struct sway_container *new_ws = container_workspace_create(parent, name); | 224 | struct sway_container *new_ws = container_workspace_create(parent, name); |
@@ -278,7 +278,7 @@ struct sway_container *workspace_output_prev_next_impl( | |||
278 | } | 278 | } |
279 | 279 | ||
280 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 280 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
281 | struct sway_container *focus = sway_seat_get_focus_inactive(seat, output); | 281 | struct sway_container *focus = seat_get_focus_inactive(seat, output); |
282 | struct sway_container *workspace = (focus->type == C_WORKSPACE ? | 282 | struct sway_container *workspace = (focus->type == C_WORKSPACE ? |
283 | focus : | 283 | focus : |
284 | container_parent(focus, C_WORKSPACE)); | 284 | container_parent(focus, C_WORKSPACE)); |
@@ -363,13 +363,13 @@ bool workspace_switch(struct sway_container *workspace) { | |||
363 | } | 363 | } |
364 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 364 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
365 | struct sway_container *focus = | 365 | struct sway_container *focus = |
366 | sway_seat_get_focus_inactive(seat, &root_container); | 366 | seat_get_focus_inactive(seat, &root_container); |
367 | if (!seat || !focus) { | 367 | if (!seat || !focus) { |
368 | return false; | 368 | return false; |
369 | } | 369 | } |
370 | struct sway_container *active_ws = focus; | 370 | struct sway_container *active_ws = focus; |
371 | if (active_ws->type != C_WORKSPACE) { | 371 | if (active_ws->type != C_WORKSPACE) { |
372 | container_parent(focus, C_WORKSPACE); | 372 | active_ws = container_parent(focus, C_WORKSPACE); |
373 | } | 373 | } |
374 | 374 | ||
375 | if (config->auto_back_and_forth | 375 | if (config->auto_back_and_forth |
@@ -394,11 +394,11 @@ bool workspace_switch(struct sway_container *workspace) { | |||
394 | 394 | ||
395 | wlr_log(L_DEBUG, "Switching to workspace %p:%s", | 395 | wlr_log(L_DEBUG, "Switching to workspace %p:%s", |
396 | workspace, workspace->name); | 396 | workspace, workspace->name); |
397 | struct sway_container *next = sway_seat_get_focus_inactive(seat, workspace); | 397 | struct sway_container *next = seat_get_focus_inactive(seat, workspace); |
398 | if (next == NULL) { | 398 | if (next == NULL) { |
399 | next = workspace; | 399 | next = workspace; |
400 | } | 400 | } |
401 | sway_seat_set_focus(seat, next); | 401 | seat_set_focus(seat, next); |
402 | struct sway_container *output = container_parent(workspace, C_OUTPUT); | 402 | struct sway_container *output = container_parent(workspace, C_OUTPUT); |
403 | arrange_windows(output, -1, -1); | 403 | arrange_windows(output, -1, -1); |
404 | return true; | 404 | return true; |
@@ -407,7 +407,7 @@ bool workspace_switch(struct sway_container *workspace) { | |||
407 | bool workspace_is_visible(struct sway_container *ws) { | 407 | bool workspace_is_visible(struct sway_container *ws) { |
408 | struct sway_container *output = container_parent(ws, C_OUTPUT); | 408 | struct sway_container *output = container_parent(ws, C_OUTPUT); |
409 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 409 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
410 | struct sway_container *focus = sway_seat_get_focus_inactive(seat, output); | 410 | struct sway_container *focus = seat_get_focus_inactive(seat, output); |
411 | if (focus->type != C_WORKSPACE) { | 411 | if (focus->type != C_WORKSPACE) { |
412 | focus = container_parent(focus, C_WORKSPACE); | 412 | focus = container_parent(focus, C_WORKSPACE); |
413 | } | 413 | } |
diff --git a/swaybar/bar.c b/swaybar/bar.c index f743236c..fb417095 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c | |||
@@ -308,14 +308,14 @@ static void display_in(int fd, short mask, void *_bar) { | |||
308 | 308 | ||
309 | static void ipc_in(int fd, short mask, void *_bar) { | 309 | static void ipc_in(int fd, short mask, void *_bar) { |
310 | struct swaybar *bar = (struct swaybar *)_bar; | 310 | struct swaybar *bar = (struct swaybar *)_bar; |
311 | if (handle_ipc_event(bar)) { | 311 | if (handle_ipc_readable(bar)) { |
312 | render_all_frames(bar); | 312 | render_all_frames(bar); |
313 | } | 313 | } |
314 | } | 314 | } |
315 | 315 | ||
316 | static void status_in(int fd, short mask, void *_bar) { | 316 | static void status_in(int fd, short mask, void *_bar) { |
317 | struct swaybar *bar = (struct swaybar *)_bar; | 317 | struct swaybar *bar = (struct swaybar *)_bar; |
318 | if (handle_status_readable(bar->status)) { | 318 | if (status_handle_readable(bar->status)) { |
319 | render_all_frames(bar); | 319 | render_all_frames(bar); |
320 | } | 320 | } |
321 | } | 321 | } |
diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c new file mode 100644 index 00000000..ed134a01 --- /dev/null +++ b/swaybar/i3bar.c | |||
@@ -0,0 +1,211 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <json-c/json.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <string.h> | ||
5 | #include <unistd.h> | ||
6 | #include <wlr/util/log.h> | ||
7 | #include "swaybar/config.h" | ||
8 | #include "swaybar/status_line.h" | ||
9 | |||
10 | static void i3bar_block_free(struct i3bar_block *block) { | ||
11 | if (!block) { | ||
12 | return; | ||
13 | } | ||
14 | wl_list_remove(&block->link); | ||
15 | free(block->full_text); | ||
16 | free(block->short_text); | ||
17 | free(block->align); | ||
18 | free(block->name); | ||
19 | free(block->instance); | ||
20 | free(block->color); | ||
21 | } | ||
22 | |||
23 | static bool i3bar_parse_json(struct status_line *status, const char *text) { | ||
24 | struct i3bar_block *block, *tmp; | ||
25 | wl_list_for_each_safe(block, tmp, &status->blocks, link) { | ||
26 | i3bar_block_free(block); | ||
27 | } | ||
28 | json_object *results = json_tokener_parse(text); | ||
29 | if (!results) { | ||
30 | status_error(status, "[failed to parse i3bar json]"); | ||
31 | return false; | ||
32 | } | ||
33 | wlr_log(L_DEBUG, "Got i3bar json: '%s'", text); | ||
34 | for (size_t i = 0; i < json_object_array_length(results); ++i) { | ||
35 | json_object *full_text, *short_text, *color, *min_width, *align, *urgent; | ||
36 | json_object *name, *instance, *separator, *separator_block_width; | ||
37 | json_object *background, *border, *border_top, *border_bottom; | ||
38 | json_object *border_left, *border_right, *markup; | ||
39 | json_object *json = json_object_array_get_idx(results, i); | ||
40 | if (!json) { | ||
41 | continue; | ||
42 | } | ||
43 | json_object_object_get_ex(json, "full_text", &full_text); | ||
44 | json_object_object_get_ex(json, "short_text", &short_text); | ||
45 | json_object_object_get_ex(json, "color", &color); | ||
46 | json_object_object_get_ex(json, "min_width", &min_width); | ||
47 | json_object_object_get_ex(json, "align", &align); | ||
48 | json_object_object_get_ex(json, "urgent", &urgent); | ||
49 | json_object_object_get_ex(json, "name", &name); | ||
50 | json_object_object_get_ex(json, "instance", &instance); | ||
51 | json_object_object_get_ex(json, "markup", &markup); | ||
52 | json_object_object_get_ex(json, "separator", &separator); | ||
53 | json_object_object_get_ex(json, "separator_block_width", &separator_block_width); | ||
54 | json_object_object_get_ex(json, "background", &background); | ||
55 | json_object_object_get_ex(json, "border", &border); | ||
56 | json_object_object_get_ex(json, "border_top", &border_top); | ||
57 | json_object_object_get_ex(json, "border_bottom", &border_bottom); | ||
58 | json_object_object_get_ex(json, "border_left", &border_left); | ||
59 | json_object_object_get_ex(json, "border_right", &border_right); | ||
60 | |||
61 | struct i3bar_block *block = calloc(1, sizeof(struct i3bar_block)); | ||
62 | block->full_text = full_text ? | ||
63 | strdup(json_object_get_string(full_text)) : NULL; | ||
64 | block->short_text = short_text ? | ||
65 | strdup(json_object_get_string(short_text)) : NULL; | ||
66 | if (color) { | ||
67 | block->color = malloc(sizeof(uint32_t)); | ||
68 | *block->color = parse_color(json_object_get_string(color)); | ||
69 | } | ||
70 | if (min_width) { | ||
71 | json_type type = json_object_get_type(min_width); | ||
72 | if (type == json_type_int) { | ||
73 | block->min_width = json_object_get_int(min_width); | ||
74 | } else if (type == json_type_string) { | ||
75 | /* the width will be calculated when rendering */ | ||
76 | block->min_width = 0; | ||
77 | } | ||
78 | } | ||
79 | block->align = strdup(align ? json_object_get_string(align) : "left"); | ||
80 | block->urgent = urgent ? json_object_get_int(urgent) : false; | ||
81 | block->name = name ? strdup(json_object_get_string(name)) : NULL; | ||
82 | block->instance = instance ? | ||
83 | strdup(json_object_get_string(instance)) : NULL; | ||
84 | if (markup) { | ||
85 | block->markup = false; | ||
86 | const char *markup_str = json_object_get_string(markup); | ||
87 | if (strcmp(markup_str, "pango") == 0) { | ||
88 | block->markup = true; | ||
89 | } | ||
90 | } | ||
91 | block->separator = separator ? json_object_get_int(separator) : true; | ||
92 | block->separator_block_width = separator_block_width ? | ||
93 | json_object_get_int(separator_block_width) : 9; | ||
94 | // Airblader features | ||
95 | block->background = background ? | ||
96 | parse_color(json_object_get_string(background)) : 0; | ||
97 | block->border = border ? | ||
98 | parse_color(json_object_get_string(border)) : 0; | ||
99 | block->border_top = border_top ? json_object_get_int(border_top) : 1; | ||
100 | block->border_bottom = border_bottom ? | ||
101 | json_object_get_int(border_bottom) : 1; | ||
102 | block->border_left = border_left ? json_object_get_int(border_left) : 1; | ||
103 | block->border_right = border_right ? | ||
104 | json_object_get_int(border_right) : 1; | ||
105 | wl_list_insert(&status->blocks, &block->link); | ||
106 | } | ||
107 | return true; | ||
108 | } | ||
109 | |||
110 | bool i3bar_handle_readable(struct status_line *status) { | ||
111 | struct i3bar_protocol_state *state = &status->i3bar_state; | ||
112 | |||
113 | char *cur = &state->buffer[state->buffer_index]; | ||
114 | ssize_t n = read(status->read_fd, cur, | ||
115 | state->buffer_size - state->buffer_index); | ||
116 | if (n == 0) { | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | if (n == (ssize_t)(state->buffer_size - state->buffer_index)) { | ||
121 | state->buffer_size = state->buffer_size * 2; | ||
122 | char *new_buffer = realloc(state->buffer, state->buffer_size); | ||
123 | if (!new_buffer) { | ||
124 | free(state->buffer); | ||
125 | status_error(status, "[failed to allocate buffer]"); | ||
126 | return -1; | ||
127 | } | ||
128 | state->buffer = new_buffer; | ||
129 | } | ||
130 | |||
131 | bool redraw = false; | ||
132 | while (*cur) { | ||
133 | if (state->nodes[state->depth] == JSON_NODE_STRING) { | ||
134 | if (!state->escape && *cur == '"') { | ||
135 | --state->depth; | ||
136 | } | ||
137 | state->escape = !state->escape && *cur == '\\'; | ||
138 | } else { | ||
139 | switch (*cur) { | ||
140 | case '[': | ||
141 | ++state->depth; | ||
142 | if (state->depth > | ||
143 | sizeof(state->nodes) / sizeof(state->nodes[0])) { | ||
144 | status_error(status, "[i3bar json too deep]"); | ||
145 | return false; | ||
146 | } | ||
147 | state->nodes[state->depth] = JSON_NODE_ARRAY; | ||
148 | if (state->depth == 1) { | ||
149 | state->current_node = cur; | ||
150 | } | ||
151 | break; | ||
152 | case ']': | ||
153 | if (state->nodes[state->depth] != JSON_NODE_ARRAY) { | ||
154 | status_error(status, "[failed to parse i3bar json]"); | ||
155 | return false; | ||
156 | } | ||
157 | --state->depth; | ||
158 | if (state->depth == 0) { | ||
159 | // cur[1] is valid since cur[0] != '\0' | ||
160 | char p = cur[1]; | ||
161 | cur[1] = '\0'; | ||
162 | redraw = i3bar_parse_json( | ||
163 | status, state->current_node) || redraw; | ||
164 | cur[1] = p; | ||
165 | memmove(state->buffer, cur, | ||
166 | state->buffer_size - (cur - state->buffer)); | ||
167 | cur = state->buffer; | ||
168 | state->current_node = cur + 1; | ||
169 | } | ||
170 | break; | ||
171 | case '"': | ||
172 | ++state->depth; | ||
173 | if (state->depth > | ||
174 | sizeof(state->nodes) / sizeof(state->nodes[0])) { | ||
175 | status_error(status, "[i3bar json too deep]"); | ||
176 | return false; | ||
177 | } | ||
178 | state->nodes[state->depth] = JSON_NODE_STRING; | ||
179 | break; | ||
180 | } | ||
181 | } | ||
182 | ++cur; | ||
183 | } | ||
184 | state->buffer_index = cur - state->buffer; | ||
185 | return redraw; | ||
186 | } | ||
187 | |||
188 | void i3bar_block_send_click(struct status_line *status, | ||
189 | struct i3bar_block *block, int x, int y, uint32_t button) { | ||
190 | wlr_log(L_DEBUG, "block %s clicked", block->name ? block->name : "(nil)"); | ||
191 | if (!block->name || !status->i3bar_state.click_events) { | ||
192 | return; | ||
193 | } | ||
194 | |||
195 | struct json_object *event_json = json_object_new_object(); | ||
196 | json_object_object_add(event_json, "name", | ||
197 | json_object_new_string(block->name)); | ||
198 | if (block->instance) { | ||
199 | json_object_object_add(event_json, "instance", | ||
200 | json_object_new_string(block->instance)); | ||
201 | } | ||
202 | |||
203 | json_object_object_add(event_json, "button", json_object_new_int(button)); | ||
204 | json_object_object_add(event_json, "x", json_object_new_int(x)); | ||
205 | json_object_object_add(event_json, "y", json_object_new_int(y)); | ||
206 | if (dprintf(status->write_fd, "%s\n", | ||
207 | json_object_to_json_string(event_json)) < 0) { | ||
208 | status_error(status, "[failed to write click event]"); | ||
209 | } | ||
210 | json_object_put(event_json); | ||
211 | } | ||
diff --git a/swaybar/ipc.c b/swaybar/ipc.c index 64583df0..ed5d9a31 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c | |||
@@ -323,7 +323,7 @@ void ipc_initialize(struct swaybar *bar, const char *bar_id) { | |||
323 | IPC_SUBSCRIBE, subscribe, &len)); | 323 | IPC_SUBSCRIBE, subscribe, &len)); |
324 | } | 324 | } |
325 | 325 | ||
326 | bool handle_ipc_event(struct swaybar *bar) { | 326 | bool handle_ipc_readable(struct swaybar *bar) { |
327 | struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd); | 327 | struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd); |
328 | if (!resp) { | 328 | if (!resp) { |
329 | return false; | 329 | return false; |
diff --git a/swaybar/meson.build b/swaybar/meson.build index bf6f6d7a..d65edb11 100644 --- a/swaybar/meson.build +++ b/swaybar/meson.build | |||
@@ -3,6 +3,7 @@ executable( | |||
3 | 'bar.c', | 3 | 'bar.c', |
4 | 'config.c', | 4 | 'config.c', |
5 | 'event_loop.c', | 5 | 'event_loop.c', |
6 | 'i3bar.c', | ||
6 | 'ipc.c', | 7 | 'ipc.c', |
7 | 'main.c', | 8 | 'main.c', |
8 | 'render.c', | 9 | 'render.c', |
diff --git a/swaybar/render.c b/swaybar/render.c index c2358724..6f3b0788 100644 --- a/swaybar/render.c +++ b/swaybar/render.c | |||
@@ -18,10 +18,33 @@ static const int ws_horizontal_padding = 5; | |||
18 | static const double ws_vertical_padding = 1.5; | 18 | static const double ws_vertical_padding = 1.5; |
19 | static const double border_width = 1; | 19 | static const double border_width = 1; |
20 | 20 | ||
21 | static uint32_t render_status_line_error(cairo_t *cairo, | ||
22 | struct swaybar_config *config, const char *error, | ||
23 | double *x, uint32_t width, uint32_t height) { | ||
24 | if (!error) { | ||
25 | return 0; | ||
26 | } | ||
27 | cairo_set_source_u32(cairo, 0xFF0000FF); | ||
28 | static const int margin = 3; | ||
29 | int text_width, text_height; | ||
30 | get_text_size(cairo, config->font, | ||
31 | &text_width, &text_height, 1, false, "%s", error); | ||
32 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; | ||
33 | if (height < ideal_height) { | ||
34 | return ideal_height; | ||
35 | } | ||
36 | *x -= text_width + margin; | ||
37 | double text_y = height / 2.0 - text_height / 2.0; | ||
38 | cairo_move_to(cairo, *x, (int)floor(text_y)); | ||
39 | pango_printf(cairo, config->font, 1, false, "%s", error); | ||
40 | *x -= margin; | ||
41 | return ideal_height; | ||
42 | } | ||
43 | |||
21 | static uint32_t render_status_line_text(cairo_t *cairo, | 44 | static uint32_t render_status_line_text(cairo_t *cairo, |
22 | struct swaybar_config *config, struct status_line *status, | 45 | struct swaybar_config *config, const char *text, |
23 | bool focused, uint32_t width, uint32_t height) { | 46 | bool focused, double *x, uint32_t width, uint32_t height) { |
24 | if (!status->text) { | 47 | if (!text) { |
25 | return 0; | 48 | return 0; |
26 | } | 49 | } |
27 | cairo_set_source_u32(cairo, focused ? | 50 | cairo_set_source_u32(cairo, focused ? |
@@ -29,38 +52,211 @@ static uint32_t render_status_line_text(cairo_t *cairo, | |||
29 | static const int margin = 3; | 52 | static const int margin = 3; |
30 | int text_width, text_height; | 53 | int text_width, text_height; |
31 | get_text_size(cairo, config->font, &text_width, &text_height, | 54 | get_text_size(cairo, config->font, &text_width, &text_height, |
32 | 1, config->pango_markup, "%s", status->text); | 55 | 1, config->pango_markup, "%s", text); |
33 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; | 56 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; |
34 | if (height < ideal_height) { | 57 | if (height < ideal_height) { |
35 | return ideal_height; | 58 | return ideal_height; |
36 | } | 59 | } |
60 | *x -= text_width + margin; | ||
37 | double text_y = height / 2.0 - text_height / 2.0; | 61 | double text_y = height / 2.0 - text_height / 2.0; |
38 | cairo_move_to(cairo, width - text_width - margin, (int)floor(text_y)); | 62 | cairo_move_to(cairo, *x, (int)floor(text_y)); |
39 | pango_printf(cairo, config->font, 1, config->pango_markup, | 63 | pango_printf(cairo, config->font, 1, config->pango_markup, "%s", text); |
40 | "%s", status->text); | 64 | *x -= margin; |
65 | return ideal_height; | ||
66 | } | ||
67 | |||
68 | static void render_sharp_line(cairo_t *cairo, uint32_t color, | ||
69 | double x, double y, double width, double height) { | ||
70 | cairo_set_source_u32(cairo, color); | ||
71 | if (width > 1 && height > 1) { | ||
72 | cairo_rectangle(cairo, x, y, width, height); | ||
73 | cairo_fill(cairo); | ||
74 | } else { | ||
75 | if (width == 1) { | ||
76 | x += 0.5; | ||
77 | height += y; | ||
78 | width = x; | ||
79 | } | ||
80 | if (height == 1) { | ||
81 | y += 0.5; | ||
82 | width += x; | ||
83 | height = y; | ||
84 | } | ||
85 | cairo_move_to(cairo, x, y); | ||
86 | cairo_set_line_width(cairo, 1.0); | ||
87 | cairo_line_to(cairo, width, height); | ||
88 | cairo_stroke(cairo); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | static void block_hotspot_callback(struct swaybar_output *output, | ||
93 | int x, int y, uint32_t button, void *data) { | ||
94 | struct i3bar_block *block = data; | ||
95 | struct status_line *status = output->bar->status; | ||
96 | i3bar_block_send_click(status, block, x, y, button); | ||
97 | } | ||
98 | |||
99 | static uint32_t render_status_block(cairo_t *cairo, | ||
100 | struct swaybar_config *config, struct swaybar_output *output, | ||
101 | struct i3bar_block *block, double *x, | ||
102 | uint32_t height, bool focused, bool edge) { | ||
103 | static const int margin = 3; | ||
104 | if (!block->full_text || !*block->full_text) { | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | int text_width, text_height; | ||
109 | get_text_size(cairo, config->font, &text_width, &text_height, | ||
110 | 1, block->markup, "%s", block->full_text); | ||
111 | int width = text_width; | ||
112 | if (width < block->min_width) { | ||
113 | width = block->min_width; | ||
114 | } | ||
115 | double block_width = width; | ||
116 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; | ||
117 | if (height < ideal_height) { | ||
118 | return ideal_height; | ||
119 | } | ||
120 | |||
121 | *x -= width; | ||
122 | if (block->border && block->border_left > 0) { | ||
123 | *x -= (block->border_left + margin); | ||
124 | block_width += block->border_left + margin; | ||
125 | } | ||
126 | if (block->border && block->border_right > 0) { | ||
127 | *x -= (block->border_right + margin); | ||
128 | block_width += block->border_right + margin; | ||
129 | } | ||
130 | |||
131 | int sep_width; | ||
132 | if (!edge) { | ||
133 | if (config->sep_symbol) { | ||
134 | int _height; | ||
135 | get_text_size(cairo, config->font, &sep_width, &_height, | ||
136 | 1, false, "%s", config->sep_symbol); | ||
137 | uint32_t _ideal_height = _height + ws_vertical_padding * 2; | ||
138 | if (height < _ideal_height) { | ||
139 | return _height; | ||
140 | } | ||
141 | if (sep_width > block->separator_block_width) { | ||
142 | block->separator_block_width = sep_width + margin * 2; | ||
143 | } | ||
144 | } | ||
145 | *x -= block->separator_block_width; | ||
146 | } else { | ||
147 | *x -= margin; | ||
148 | } | ||
149 | |||
150 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); | ||
151 | hotspot->x = *x; | ||
152 | hotspot->y = 0; | ||
153 | hotspot->width = width; | ||
154 | hotspot->height = height; | ||
155 | hotspot->callback = block_hotspot_callback; | ||
156 | hotspot->destroy = NULL; | ||
157 | hotspot->data = block; | ||
158 | wl_list_insert(&output->hotspots, &hotspot->link); | ||
159 | |||
160 | double pos = *x; | ||
161 | if (block->background) { | ||
162 | cairo_set_source_u32(cairo, block->background); | ||
163 | cairo_rectangle(cairo, pos - 0.5, 1, block_width, height); | ||
164 | cairo_fill(cairo); | ||
165 | } | ||
166 | |||
167 | if (block->border && block->border_top > 0) { | ||
168 | render_sharp_line(cairo, block->border, | ||
169 | pos - 0.5, 1, block_width, block->border_top); | ||
170 | } | ||
171 | if (block->border && block->border_bottom > 0) { | ||
172 | render_sharp_line(cairo, block->border, | ||
173 | pos - 0.5, height - 1 - block->border_bottom, | ||
174 | block_width, block->border_bottom); | ||
175 | } | ||
176 | if (block->border != 0 && block->border_left > 0) { | ||
177 | render_sharp_line(cairo, block->border, | ||
178 | pos - 0.5, 1, block->border_left, height); | ||
179 | pos += block->border_left + margin; | ||
180 | } | ||
181 | |||
182 | double offset = 0; | ||
183 | if (strncmp(block->align, "left", 5) == 0) { | ||
184 | offset = pos; | ||
185 | } else if (strncmp(block->align, "right", 5) == 0) { | ||
186 | offset = pos + width - text_width; | ||
187 | } else if (strncmp(block->align, "center", 6) == 0) { | ||
188 | offset = pos + (width - text_width) / 2; | ||
189 | } | ||
190 | cairo_move_to(cairo, offset, height / 2.0 - text_height / 2.0); | ||
191 | uint32_t color = block->color ? *block->color : config->colors.statusline; | ||
192 | cairo_set_source_u32(cairo, color); | ||
193 | pango_printf(cairo, config->font, 1, block->markup, "%s", block->full_text); | ||
194 | pos += width; | ||
195 | |||
196 | if (block->border && block->border_right > 0) { | ||
197 | pos += margin; | ||
198 | render_sharp_line(cairo, block->border, | ||
199 | pos - 0.5, 1, block->border_right, height); | ||
200 | pos += block->border_right; | ||
201 | } | ||
202 | |||
203 | if (!edge && block->separator) { | ||
204 | if (focused) { | ||
205 | cairo_set_source_u32(cairo, config->colors.focused_separator); | ||
206 | } else { | ||
207 | cairo_set_source_u32(cairo, config->colors.separator); | ||
208 | } | ||
209 | if (config->sep_symbol) { | ||
210 | offset = pos + (block->separator_block_width - sep_width) / 2; | ||
211 | cairo_move_to(cairo, offset, margin); | ||
212 | pango_printf(cairo, config->font, 1, false, | ||
213 | "%s", config->sep_symbol); | ||
214 | } else { | ||
215 | cairo_set_line_width(cairo, 1); | ||
216 | cairo_move_to(cairo, | ||
217 | pos + block->separator_block_width / 2, margin); | ||
218 | cairo_line_to(cairo, | ||
219 | pos + block->separator_block_width / 2, height - margin); | ||
220 | cairo_stroke(cairo); | ||
221 | } | ||
222 | } | ||
41 | return ideal_height; | 223 | return ideal_height; |
42 | } | 224 | } |
43 | 225 | ||
44 | static uint32_t render_status_line_i3bar(cairo_t *cairo, | 226 | static uint32_t render_status_line_i3bar(cairo_t *cairo, |
45 | struct swaybar_config *config, struct status_line *status, | 227 | struct swaybar_config *config, struct swaybar_output *output, |
46 | bool focused, uint32_t width, uint32_t height) { | 228 | struct status_line *status, bool focused, |
47 | // TODO | 229 | double *x, uint32_t width, uint32_t height) { |
48 | return 0; | 230 | uint32_t max_height = 0; |
231 | bool edge = true; | ||
232 | struct i3bar_block *block; | ||
233 | wl_list_for_each(block, &status->blocks, link) { | ||
234 | uint32_t h = render_status_block(cairo, config, output, | ||
235 | block, x, height, focused, edge); | ||
236 | max_height = h > max_height ? h : max_height; | ||
237 | edge = false; | ||
238 | } | ||
239 | return max_height; | ||
49 | } | 240 | } |
50 | 241 | ||
51 | static uint32_t render_status_line(cairo_t *cairo, | 242 | static uint32_t render_status_line(cairo_t *cairo, |
52 | struct swaybar_config *config, struct status_line *status, | 243 | struct swaybar_config *config, struct swaybar_output *output, |
53 | bool focused, uint32_t width, uint32_t height) { | 244 | struct status_line *status, bool focused, |
245 | double *x, uint32_t width, uint32_t height) { | ||
54 | switch (status->protocol) { | 246 | switch (status->protocol) { |
247 | case PROTOCOL_ERROR: | ||
248 | return render_status_line_error(cairo, | ||
249 | config, status->text, x, width, height); | ||
55 | case PROTOCOL_TEXT: | 250 | case PROTOCOL_TEXT: |
56 | return render_status_line_text(cairo, | 251 | return render_status_line_text(cairo, |
57 | config, status, focused, width, height); | 252 | config, status->text, focused, x, width, height); |
58 | case PROTOCOL_I3BAR: | 253 | case PROTOCOL_I3BAR: |
59 | return render_status_line_i3bar(cairo, | 254 | return render_status_line_i3bar(cairo, config, output, status, |
60 | config, status, focused, width, height); | 255 | focused, x, width, height); |
61 | default: | 256 | case PROTOCOL_UNDEF: |
62 | return 0; | 257 | return 0; |
63 | } | 258 | } |
259 | return 0; | ||
64 | } | 260 | } |
65 | 261 | ||
66 | static uint32_t render_binding_mode_indicator(cairo_t *cairo, | 262 | static uint32_t render_binding_mode_indicator(cairo_t *cairo, |
@@ -166,8 +362,8 @@ static uint32_t render_workspace_button(cairo_t *cairo, | |||
166 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); | 362 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); |
167 | hotspot->x = *x; | 363 | hotspot->x = *x; |
168 | hotspot->y = 0; | 364 | hotspot->y = 0; |
169 | hotspot->height = height; | ||
170 | hotspot->width = width; | 365 | hotspot->width = width; |
366 | hotspot->height = height; | ||
171 | hotspot->callback = workspace_hotspot_callback; | 367 | hotspot->callback = workspace_hotspot_callback; |
172 | hotspot->destroy = free; | 368 | hotspot->destroy = free; |
173 | hotspot->data = strdup(name); | 369 | hotspot->data = strdup(name); |
@@ -180,6 +376,7 @@ static uint32_t render_workspace_button(cairo_t *cairo, | |||
180 | static uint32_t render_to_cairo(cairo_t *cairo, | 376 | static uint32_t render_to_cairo(cairo_t *cairo, |
181 | struct swaybar *bar, struct swaybar_output *output) { | 377 | struct swaybar *bar, struct swaybar_output *output) { |
182 | struct swaybar_config *config = bar->config; | 378 | struct swaybar_config *config = bar->config; |
379 | wlr_log(L_DEBUG, "output %p", output); | ||
183 | 380 | ||
184 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); | 381 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); |
185 | if (output->focused) { | 382 | if (output->focused) { |
@@ -211,9 +408,10 @@ static uint32_t render_to_cairo(cairo_t *cairo, | |||
211 | cairo, config, config->mode, x, output->height); | 408 | cairo, config, config->mode, x, output->height); |
212 | max_height = h > max_height ? h : max_height; | 409 | max_height = h > max_height ? h : max_height; |
213 | } | 410 | } |
411 | x = output->width; | ||
214 | if (bar->status) { | 412 | if (bar->status) { |
215 | uint32_t h = render_status_line(cairo, config, bar->status, | 413 | uint32_t h = render_status_line(cairo, config, output, bar->status, |
216 | output->focused, output->width, output->height); | 414 | output->focused, &x, output->width, output->height); |
217 | max_height = h > max_height ? h : max_height; | 415 | max_height = h > max_height ? h : max_height; |
218 | } | 416 | } |
219 | 417 | ||
diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 3454f207..8afe4707 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #define _POSIX_C_SOURCE | 1 | #define _POSIX_C_SOURCE |
2 | #include <fcntl.h> | 2 | #include <fcntl.h> |
3 | #include <json-c/json.h> | ||
3 | #include <stdlib.h> | 4 | #include <stdlib.h> |
4 | #include <string.h> | 5 | #include <string.h> |
5 | #include <stdio.h> | 6 | #include <stdio.h> |
@@ -9,35 +10,83 @@ | |||
9 | #include "swaybar/status_line.h" | 10 | #include "swaybar/status_line.h" |
10 | #include "readline.h" | 11 | #include "readline.h" |
11 | 12 | ||
12 | bool handle_status_readable(struct status_line *status) { | 13 | void status_error(struct status_line *status, const char *text) { |
13 | char *line = read_line_buffer(status->read, | 14 | close(status->read_fd); |
14 | status->buffer, status->buffer_size); | 15 | close(status->write_fd); |
16 | status->protocol = PROTOCOL_ERROR; | ||
17 | status->text = text; | ||
18 | } | ||
19 | |||
20 | bool status_handle_readable(struct status_line *status) { | ||
21 | char *line; | ||
15 | switch (status->protocol) { | 22 | switch (status->protocol) { |
23 | case PROTOCOL_ERROR: | ||
24 | return false; | ||
16 | case PROTOCOL_I3BAR: | 25 | case PROTOCOL_I3BAR: |
17 | // TODO | 26 | if (i3bar_handle_readable(status) > 0) { |
27 | return true; | ||
28 | } | ||
18 | break; | 29 | break; |
19 | case PROTOCOL_TEXT: | 30 | case PROTOCOL_TEXT: |
20 | status->text = line; | 31 | line = read_line_buffer(status->read, |
32 | status->text_state.buffer, status->text_state.buffer_size); | ||
33 | if (!line) { | ||
34 | status_error(status, "[error reading from status command]"); | ||
35 | } else { | ||
36 | status->text = line; | ||
37 | } | ||
21 | return true; | 38 | return true; |
22 | case PROTOCOL_UNDEF: | 39 | case PROTOCOL_UNDEF: |
40 | line = read_line_buffer(status->read, | ||
41 | status->text_state.buffer, status->text_state.buffer_size); | ||
23 | if (!line) { | 42 | if (!line) { |
43 | status_error(status, "[error reading from status command]"); | ||
24 | return false; | 44 | return false; |
25 | } | 45 | } |
26 | if (line[0] == '{') { | 46 | if (line[0] == '{') { |
27 | // TODO: JSON | 47 | json_object *proto = json_tokener_parse(line); |
48 | if (proto) { | ||
49 | json_object *version; | ||
50 | if (json_object_object_get_ex(proto, "version", &version) | ||
51 | && json_object_get_int(version) == 1) { | ||
52 | wlr_log(L_DEBUG, "Switched to i3bar protocol."); | ||
53 | status->protocol = PROTOCOL_I3BAR; | ||
54 | } | ||
55 | json_object *click_events; | ||
56 | if (json_object_object_get_ex( | ||
57 | proto, "click_events", &click_events) | ||
58 | && json_object_get_boolean(click_events)) { | ||
59 | wlr_log(L_DEBUG, "Enabled click events."); | ||
60 | status->i3bar_state.click_events = true; | ||
61 | const char *events_array = "[\n"; | ||
62 | ssize_t len = strlen(events_array); | ||
63 | if (write(status->write_fd, events_array, len) != len) { | ||
64 | status_error(status, | ||
65 | "[failed to write to status command]"); | ||
66 | } | ||
67 | } | ||
68 | json_object_put(proto); | ||
69 | } | ||
70 | |||
71 | status->protocol = PROTOCOL_I3BAR; | ||
72 | free(status->text_state.buffer); | ||
73 | wl_list_init(&status->blocks); | ||
74 | status->i3bar_state.buffer_size = 4096; | ||
75 | status->i3bar_state.buffer = | ||
76 | malloc(status->i3bar_state.buffer_size); | ||
28 | } else { | 77 | } else { |
29 | status->text = line; | ||
30 | status->protocol = PROTOCOL_TEXT; | 78 | status->protocol = PROTOCOL_TEXT; |
79 | status->text = line; | ||
31 | } | 80 | } |
32 | return false; | 81 | return true; |
33 | } | 82 | } |
34 | return false; | 83 | return false; |
35 | } | 84 | } |
36 | 85 | ||
37 | struct status_line *status_line_init(char *cmd) { | 86 | struct status_line *status_line_init(char *cmd) { |
38 | struct status_line *status = calloc(1, sizeof(struct status_line)); | 87 | struct status_line *status = calloc(1, sizeof(struct status_line)); |
39 | status->buffer_size = 4096; | 88 | status->text_state.buffer_size = 8192; |
40 | status->buffer = malloc(status->buffer_size); | 89 | status->text_state.buffer = malloc(status->text_state.buffer_size); |
41 | 90 | ||
42 | int pipe_read_fd[2]; | 91 | int pipe_read_fd[2]; |
43 | int pipe_write_fd[2]; | 92 | int pipe_write_fd[2]; |