diff options
-rw-r--r-- | completions/bash/swaymsg | 4 | ||||
-rw-r--r-- | completions/zsh/_swaymsg | 3 | ||||
-rw-r--r-- | include/ipc.h | 5 | ||||
-rw-r--r-- | include/sway/config.h | 2 | ||||
-rw-r--r-- | include/sway/input/seat.h | 2 | ||||
-rw-r--r-- | include/sway/ipc-server.h | 2 | ||||
-rw-r--r-- | include/sway/output.h | 8 | ||||
-rw-r--r-- | include/sway/tree/container.h | 11 | ||||
-rw-r--r-- | include/sway/tree/view.h | 16 | ||||
-rw-r--r-- | sway/commands/bind.c | 52 | ||||
-rw-r--r-- | sway/commands/mark.c | 2 | ||||
-rw-r--r-- | sway/commands/move.c | 4 | ||||
-rw-r--r-- | sway/commands/reload.c | 29 | ||||
-rw-r--r-- | sway/desktop/output.c | 19 | ||||
-rw-r--r-- | sway/desktop/render.c | 37 | ||||
-rw-r--r-- | sway/desktop/xdg_shell.c | 22 | ||||
-rw-r--r-- | sway/desktop/xdg_shell_v6.c | 23 | ||||
-rw-r--r-- | sway/input/cursor.c | 9 | ||||
-rw-r--r-- | sway/input/seat.c | 21 | ||||
-rw-r--r-- | sway/ipc-json.c | 9 | ||||
-rw-r--r-- | sway/ipc-server.c | 136 | ||||
-rw-r--r-- | sway/main.c | 1 | ||||
-rw-r--r-- | sway/tree/container.c | 148 | ||||
-rw-r--r-- | sway/tree/layout.c | 14 | ||||
-rw-r--r-- | sway/tree/output.c | 2 | ||||
-rw-r--r-- | sway/tree/view.c | 31 | ||||
-rw-r--r-- | swaymsg/main.c | 8 | ||||
-rw-r--r-- | swaymsg/swaymsg.1.scd | 3 |
28 files changed, 529 insertions, 94 deletions
diff --git a/completions/bash/swaymsg b/completions/bash/swaymsg index 8ec90b6f..20092bdc 100644 --- a/completions/bash/swaymsg +++ b/completions/bash/swaymsg | |||
@@ -14,7 +14,9 @@ _swaymsg() | |||
14 | 'get_marks' | 14 | 'get_marks' |
15 | 'get_bar_config' | 15 | 'get_bar_config' |
16 | 'get_version' | 16 | 'get_version' |
17 | 'get_clipboard' | 17 | 'get_binding_modes' |
18 | 'get_config' | ||
19 | 'send_tick' | ||
18 | ) | 20 | ) |
19 | 21 | ||
20 | short=( | 22 | short=( |
diff --git a/completions/zsh/_swaymsg b/completions/zsh/_swaymsg index 2e39deb6..a7a1c8e0 100644 --- a/completions/zsh/_swaymsg +++ b/completions/zsh/_swaymsg | |||
@@ -22,6 +22,9 @@ types=( | |||
22 | 'get_marks' | 22 | 'get_marks' |
23 | 'get_bar_config' | 23 | 'get_bar_config' |
24 | 'get_version' | 24 | 'get_version' |
25 | 'get_binding_modes' | ||
26 | 'get_config' | ||
27 | 'send_tick' | ||
25 | ) | 28 | ) |
26 | 29 | ||
27 | _arguments -s \ | 30 | _arguments -s \ |
diff --git a/include/ipc.h b/include/ipc.h index 0010718b..a3f60e19 100644 --- a/include/ipc.h +++ b/include/ipc.h | |||
@@ -15,6 +15,7 @@ enum ipc_command_type { | |||
15 | IPC_GET_VERSION = 7, | 15 | IPC_GET_VERSION = 7, |
16 | IPC_GET_BINDING_MODES = 8, | 16 | IPC_GET_BINDING_MODES = 8, |
17 | IPC_GET_CONFIG = 9, | 17 | IPC_GET_CONFIG = 9, |
18 | IPC_SEND_TICK = 10, | ||
18 | 19 | ||
19 | // sway-specific command types | 20 | // sway-specific command types |
20 | IPC_GET_INPUTS = 100, | 21 | IPC_GET_INPUTS = 100, |
@@ -27,8 +28,8 @@ enum ipc_command_type { | |||
27 | IPC_EVENT_WINDOW = ((1<<31) | 3), | 28 | IPC_EVENT_WINDOW = ((1<<31) | 3), |
28 | IPC_EVENT_BARCONFIG_UPDATE = ((1<<31) | 4), | 29 | IPC_EVENT_BARCONFIG_UPDATE = ((1<<31) | 4), |
29 | IPC_EVENT_BINDING = ((1<<31) | 5), | 30 | IPC_EVENT_BINDING = ((1<<31) | 5), |
30 | IPC_EVENT_MODIFIER = ((1<<31) | 6), | 31 | IPC_EVENT_SHUTDOWN = ((1<<31) | 6), |
31 | IPC_EVENT_INPUT = ((1<<31) | 7), | 32 | IPC_EVENT_TICK = ((1<<31) | 7), |
32 | }; | 33 | }; |
33 | 34 | ||
34 | #endif | 35 | #endif |
diff --git a/include/sway/config.h b/include/sway/config.h index 0f74b439..909b6827 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -488,8 +488,6 @@ int sway_binding_cmp_keys(const void *a, const void *b); | |||
488 | 488 | ||
489 | void free_sway_binding(struct sway_binding *sb); | 489 | void free_sway_binding(struct sway_binding *sb); |
490 | 490 | ||
491 | struct sway_binding *sway_binding_dup(struct sway_binding *sb); | ||
492 | |||
493 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding); | 491 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding); |
494 | 492 | ||
495 | void load_swaybars(); | 493 | void load_swaybars(); |
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 07febe2c..92387601 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h | |||
@@ -99,7 +99,7 @@ void seat_configure_xcursor(struct sway_seat *seat); | |||
99 | void seat_set_focus(struct sway_seat *seat, struct sway_container *container); | 99 | void seat_set_focus(struct sway_seat *seat, struct sway_container *container); |
100 | 100 | ||
101 | void seat_set_focus_warp(struct sway_seat *seat, | 101 | void seat_set_focus_warp(struct sway_seat *seat, |
102 | struct sway_container *container, bool warp); | 102 | struct sway_container *container, bool warp, bool notify); |
103 | 103 | ||
104 | void seat_set_focus_surface(struct sway_seat *seat, | 104 | void seat_set_focus_surface(struct sway_seat *seat, |
105 | struct wlr_surface *surface, bool unfocus); | 105 | struct wlr_surface *surface, bool unfocus); |
diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h index 6469f097..4b6d0e25 100644 --- a/include/sway/ipc-server.h +++ b/include/sway/ipc-server.h | |||
@@ -16,5 +16,7 @@ void ipc_event_workspace(struct sway_container *old, | |||
16 | void ipc_event_window(struct sway_container *window, const char *change); | 16 | void ipc_event_window(struct sway_container *window, const char *change); |
17 | void ipc_event_barconfig_update(struct bar_config *bar); | 17 | void ipc_event_barconfig_update(struct bar_config *bar); |
18 | void ipc_event_mode(const char *mode, bool pango); | 18 | void ipc_event_mode(const char *mode, bool pango); |
19 | void ipc_event_shutdown(const char *reason); | ||
20 | void ipc_event_binding(struct sway_binding *binding); | ||
19 | 21 | ||
20 | #endif | 22 | #endif |
diff --git a/include/sway/output.h b/include/sway/output.h index 6283db68..80dcd37b 100644 --- a/include/sway/output.h +++ b/include/sway/output.h | |||
@@ -67,10 +67,18 @@ struct sway_container *output_get_active_workspace(struct sway_output *output); | |||
67 | void output_render(struct sway_output *output, struct timespec *when, | 67 | void output_render(struct sway_output *output, struct timespec *when, |
68 | pixman_region32_t *damage); | 68 | pixman_region32_t *damage); |
69 | 69 | ||
70 | void output_surface_for_each_surface(struct sway_output *output, | ||
71 | struct wlr_surface *surface, double ox, double oy, | ||
72 | sway_surface_iterator_func_t iterator, void *user_data); | ||
73 | |||
70 | void output_view_for_each_surface(struct sway_output *output, | 74 | void output_view_for_each_surface(struct sway_output *output, |
71 | struct sway_view *view, sway_surface_iterator_func_t iterator, | 75 | struct sway_view *view, sway_surface_iterator_func_t iterator, |
72 | void *user_data); | 76 | void *user_data); |
73 | 77 | ||
78 | void output_view_for_each_popup(struct sway_output *output, | ||
79 | struct sway_view *view, sway_surface_iterator_func_t iterator, | ||
80 | void *user_data); | ||
81 | |||
74 | void output_layer_for_each_surface(struct sway_output *output, | 82 | void output_layer_for_each_surface(struct sway_output *output, |
75 | struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator, | 83 | struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator, |
76 | void *user_data); | 84 | void *user_data); |
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index d4a42a71..12ff8a5a 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -230,18 +230,11 @@ struct sway_container *container_parent(struct sway_container *container, | |||
230 | * surface-local coordinates of the given layout coordinates if the container | 230 | * surface-local coordinates of the given layout coordinates if the container |
231 | * is a view and the view contains a surface at those coordinates. | 231 | * is a view and the view contains a surface at those coordinates. |
232 | */ | 232 | */ |
233 | struct sway_container *container_at(struct sway_container *container, | 233 | struct sway_container *container_at(struct sway_container *workspace, |
234 | double ox, double oy, struct wlr_surface **surface, | 234 | double lx, double ly, struct wlr_surface **surface, |
235 | double *sx, double *sy); | 235 | double *sx, double *sy); |
236 | 236 | ||
237 | /** | 237 | /** |
238 | * Same as container_at, but only checks floating views and expects coordinates | ||
239 | * to be layout coordinates, as that's what floating views use. | ||
240 | */ | ||
241 | struct sway_container *floating_container_at(double lx, double ly, | ||
242 | struct wlr_surface **surface, double *sx, double *sy); | ||
243 | |||
244 | /** | ||
245 | * Apply the function for each descendant of the container breadth first. | 238 | * Apply the function for each descendant of the container breadth first. |
246 | */ | 239 | */ |
247 | void container_for_each_descendant_bfs(struct sway_container *container, | 240 | void container_for_each_descendant_bfs(struct sway_container *container, |
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 0f9b0bb2..37fd02bc 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -47,7 +47,10 @@ struct sway_view_impl { | |||
47 | bool (*has_client_side_decorations)(struct sway_view *view); | 47 | bool (*has_client_side_decorations)(struct sway_view *view); |
48 | void (*for_each_surface)(struct sway_view *view, | 48 | void (*for_each_surface)(struct sway_view *view, |
49 | wlr_surface_iterator_func_t iterator, void *user_data); | 49 | wlr_surface_iterator_func_t iterator, void *user_data); |
50 | void (*for_each_popup)(struct sway_view *view, | ||
51 | wlr_surface_iterator_func_t iterator, void *user_data); | ||
50 | void (*close)(struct sway_view *view); | 52 | void (*close)(struct sway_view *view); |
53 | void (*close_popups)(struct sway_view *view); | ||
51 | void (*destroy)(struct sway_view *view); | 54 | void (*destroy)(struct sway_view *view); |
52 | }; | 55 | }; |
53 | 56 | ||
@@ -249,11 +252,22 @@ void view_set_tiled(struct sway_view *view, bool tiled); | |||
249 | 252 | ||
250 | void view_close(struct sway_view *view); | 253 | void view_close(struct sway_view *view); |
251 | 254 | ||
255 | void view_close_popups(struct sway_view *view); | ||
256 | |||
252 | void view_damage_from(struct sway_view *view); | 257 | void view_damage_from(struct sway_view *view); |
253 | 258 | ||
259 | /** | ||
260 | * Iterate all surfaces of a view (toplevels + popups). | ||
261 | */ | ||
254 | void view_for_each_surface(struct sway_view *view, | 262 | void view_for_each_surface(struct sway_view *view, |
255 | wlr_surface_iterator_func_t iterator, void *user_data); | 263 | wlr_surface_iterator_func_t iterator, void *user_data); |
256 | 264 | ||
265 | /** | ||
266 | * Iterate all popups recursively. | ||
267 | */ | ||
268 | void view_for_each_popup(struct sway_view *view, | ||
269 | wlr_surface_iterator_func_t iterator, void *user_data); | ||
270 | |||
257 | // view implementation | 271 | // view implementation |
258 | 272 | ||
259 | void view_init(struct sway_view *view, enum sway_view_type type, | 273 | void view_init(struct sway_view *view, enum sway_view_type type, |
@@ -314,6 +328,8 @@ void view_clear_marks(struct sway_view *view); | |||
314 | 328 | ||
315 | bool view_has_mark(struct sway_view *view, char *mark); | 329 | bool view_has_mark(struct sway_view *view, char *mark); |
316 | 330 | ||
331 | void view_add_mark(struct sway_view *view, char *mark); | ||
332 | |||
317 | void view_update_marks_textures(struct sway_view *view); | 333 | void view_update_marks_textures(struct sway_view *view); |
318 | 334 | ||
319 | /** | 335 | /** |
diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 133fd089..8270b958 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #define _XOPEN_SOURCE 500 | ||
1 | #ifdef __linux__ | 2 | #ifdef __linux__ |
2 | #include <linux/input-event-codes.h> | 3 | #include <linux/input-event-codes.h> |
3 | #elif __FreeBSD__ | 4 | #elif __FreeBSD__ |
@@ -5,9 +6,11 @@ | |||
5 | #endif | 6 | #endif |
6 | #include <xkbcommon/xkbcommon.h> | 7 | #include <xkbcommon/xkbcommon.h> |
7 | #include <xkbcommon/xkbcommon-names.h> | 8 | #include <xkbcommon/xkbcommon-names.h> |
9 | #include <string.h> | ||
8 | #include <strings.h> | 10 | #include <strings.h> |
9 | #include "sway/commands.h" | 11 | #include "sway/commands.h" |
10 | #include "sway/config.h" | 12 | #include "sway/config.h" |
13 | #include "sway/ipc-server.h" | ||
11 | #include "list.h" | 14 | #include "list.h" |
12 | #include "log.h" | 15 | #include "log.h" |
13 | #include "stringop.h" | 16 | #include "stringop.h" |
@@ -27,6 +30,33 @@ void free_sway_binding(struct sway_binding *binding) { | |||
27 | free(binding); | 30 | free(binding); |
28 | } | 31 | } |
29 | 32 | ||
33 | static struct sway_binding *sway_binding_dup(struct sway_binding *sb) { | ||
34 | struct sway_binding *new_sb = calloc(1, sizeof(struct sway_binding)); | ||
35 | if (!new_sb) { | ||
36 | return NULL; | ||
37 | } | ||
38 | |||
39 | new_sb->type = sb->type; | ||
40 | new_sb->order = sb->order; | ||
41 | new_sb->flags = sb->flags; | ||
42 | new_sb->modifiers = sb->modifiers; | ||
43 | new_sb->command = strdup(sb->command); | ||
44 | |||
45 | new_sb->keys = create_list(); | ||
46 | int i; | ||
47 | for (i = 0; i < sb->keys->length; ++i) { | ||
48 | xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); | ||
49 | if (!key) { | ||
50 | free_sway_binding(new_sb); | ||
51 | return NULL; | ||
52 | } | ||
53 | *key = *(xkb_keysym_t *)sb->keys->items[i]; | ||
54 | list_add(new_sb->keys, key); | ||
55 | } | ||
56 | |||
57 | return new_sb; | ||
58 | } | ||
59 | |||
30 | /** | 60 | /** |
31 | * Returns true if the bindings have the same key and modifier combinations. | 61 | * Returns true if the bindings have the same key and modifier combinations. |
32 | * Note that keyboard layout is not considered, so the bindings might actually | 62 | * Note that keyboard layout is not considered, so the bindings might actually |
@@ -275,11 +305,31 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) { | |||
275 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { | 305 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { |
276 | wlr_log(WLR_DEBUG, "running command for binding: %s", | 306 | wlr_log(WLR_DEBUG, "running command for binding: %s", |
277 | binding->command); | 307 | binding->command); |
308 | |||
309 | struct sway_binding *binding_copy = binding; | ||
310 | bool reload = false; | ||
311 | // if this is a reload command we need to make a duplicate of the | ||
312 | // binding since it will be gone after the reload has completed. | ||
313 | if (strcasecmp(binding->command, "reload") == 0) { | ||
314 | reload = true; | ||
315 | binding_copy = sway_binding_dup(binding); | ||
316 | if (!binding_copy) { | ||
317 | wlr_log(WLR_ERROR, "Failed to duplicate binding during reload"); | ||
318 | return; | ||
319 | } | ||
320 | } | ||
321 | |||
278 | config->handler_context.seat = seat; | 322 | config->handler_context.seat = seat; |
279 | struct cmd_results *results = execute_command(binding->command, NULL); | 323 | struct cmd_results *results = execute_command(binding->command, NULL); |
280 | if (results->status != CMD_SUCCESS) { | 324 | if (results->status == CMD_SUCCESS) { |
325 | ipc_event_binding(binding_copy); | ||
326 | } else { | ||
281 | wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", | 327 | wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", |
282 | binding->command, results->error); | 328 | binding->command, results->error); |
283 | } | 329 | } |
330 | |||
331 | if (reload) { // free the binding if we made a copy | ||
332 | free_sway_binding(binding_copy); | ||
333 | } | ||
284 | free_cmd_results(results); | 334 | free_cmd_results(results); |
285 | } | 335 | } |
diff --git a/sway/commands/mark.c b/sway/commands/mark.c index 5a897e69..9ea8c301 100644 --- a/sway/commands/mark.c +++ b/sway/commands/mark.c | |||
@@ -58,7 +58,7 @@ struct cmd_results *cmd_mark(int argc, char **argv) { | |||
58 | view_find_and_unmark(mark); | 58 | view_find_and_unmark(mark); |
59 | 59 | ||
60 | if (!toggle || !had_mark) { | 60 | if (!toggle || !had_mark) { |
61 | list_add(view->marks, strdup(mark)); | 61 | view_add_mark(view, mark); |
62 | } | 62 | } |
63 | 63 | ||
64 | free(mark); | 64 | free(mark); |
diff --git a/sway/commands/move.c b/sway/commands/move.c index 1aae3838..46ebcd83 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -98,7 +98,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
98 | container_move_to(current, destination); | 98 | container_move_to(current, destination); |
99 | struct sway_container *focus = seat_get_focus_inactive( | 99 | struct sway_container *focus = seat_get_focus_inactive( |
100 | config->handler_context.seat, old_parent); | 100 | config->handler_context.seat, old_parent); |
101 | seat_set_focus(config->handler_context.seat, focus); | 101 | seat_set_focus_warp(config->handler_context.seat, focus, true, false); |
102 | container_reap_empty(old_parent); | 102 | container_reap_empty(old_parent); |
103 | container_reap_empty(destination->parent); | 103 | container_reap_empty(destination->parent); |
104 | 104 | ||
@@ -135,7 +135,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
135 | struct sway_container *old_parent = current->parent; | 135 | struct sway_container *old_parent = current->parent; |
136 | struct sway_container *old_ws = container_parent(current, C_WORKSPACE); | 136 | struct sway_container *old_ws = container_parent(current, C_WORKSPACE); |
137 | container_move_to(current, focus); | 137 | container_move_to(current, focus); |
138 | seat_set_focus(config->handler_context.seat, old_parent); | 138 | seat_set_focus_warp(config->handler_context.seat, old_parent, true, false); |
139 | container_reap_empty(old_parent); | 139 | container_reap_empty(old_parent); |
140 | container_reap_empty(focus->parent); | 140 | container_reap_empty(focus->parent); |
141 | 141 | ||
diff --git a/sway/commands/reload.c b/sway/commands/reload.c index cea6a94b..5c1b19b4 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c | |||
@@ -1,17 +1,46 @@ | |||
1 | #define _XOPEN_SOURCE 500 | ||
2 | #include <string.h> | ||
1 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
2 | #include "sway/config.h" | 4 | #include "sway/config.h" |
5 | #include "sway/ipc-server.h" | ||
3 | #include "sway/tree/arrange.h" | 6 | #include "sway/tree/arrange.h" |
7 | #include "list.h" | ||
4 | 8 | ||
5 | struct cmd_results *cmd_reload(int argc, char **argv) { | 9 | struct cmd_results *cmd_reload(int argc, char **argv) { |
6 | struct cmd_results *error = NULL; | 10 | struct cmd_results *error = NULL; |
7 | if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { | 11 | if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { |
8 | return error; | 12 | return error; |
9 | } | 13 | } |
14 | |||
15 | // store bar ids to check against new bars for barconfig_update events | ||
16 | list_t *bar_ids = create_list(); | ||
17 | for (int i = 0; i < config->bars->length; ++i) { | ||
18 | struct bar_config *bar = config->bars->items[i]; | ||
19 | list_add(bar_ids, strdup(bar->id)); | ||
20 | } | ||
21 | |||
10 | if (!load_main_config(config->current_config_path, true)) { | 22 | if (!load_main_config(config->current_config_path, true)) { |
11 | return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config."); | 23 | return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config."); |
12 | } | 24 | } |
25 | ipc_event_workspace(NULL, NULL, "reload"); | ||
13 | 26 | ||
14 | load_swaybars(); | 27 | load_swaybars(); |
28 | |||
29 | for (int i = 0; i < config->bars->length; ++i) { | ||
30 | struct bar_config *bar = config->bars->items[i]; | ||
31 | for (int j = 0; j < bar_ids->length; ++j) { | ||
32 | if (strcmp(bar->id, bar_ids->items[j]) == 0) { | ||
33 | ipc_event_barconfig_update(bar); | ||
34 | break; | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | |||
39 | for (int i = 0; i < bar_ids->length; ++i) { | ||
40 | free(bar_ids->items[i]); | ||
41 | } | ||
42 | list_free(bar_ids); | ||
43 | |||
15 | arrange_windows(&root_container); | 44 | arrange_windows(&root_container); |
16 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 45 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
17 | } | 46 | } |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 31b53213..66747a3f 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -119,7 +119,7 @@ static void output_for_each_surface_iterator(struct wlr_surface *surface, | |||
119 | data->user_data); | 119 | data->user_data); |
120 | } | 120 | } |
121 | 121 | ||
122 | static void output_surface_for_each_surface(struct sway_output *output, | 122 | void output_surface_for_each_surface(struct sway_output *output, |
123 | struct wlr_surface *surface, double ox, double oy, | 123 | struct wlr_surface *surface, double ox, double oy, |
124 | sway_surface_iterator_func_t iterator, void *user_data) { | 124 | sway_surface_iterator_func_t iterator, void *user_data) { |
125 | struct surface_iterator_data data = { | 125 | struct surface_iterator_data data = { |
@@ -155,6 +155,23 @@ void output_view_for_each_surface(struct sway_output *output, | |||
155 | output_for_each_surface_iterator, &data); | 155 | output_for_each_surface_iterator, &data); |
156 | } | 156 | } |
157 | 157 | ||
158 | void output_view_for_each_popup(struct sway_output *output, | ||
159 | struct sway_view *view, sway_surface_iterator_func_t iterator, | ||
160 | void *user_data) { | ||
161 | struct surface_iterator_data data = { | ||
162 | .user_iterator = iterator, | ||
163 | .user_data = user_data, | ||
164 | .output = output, | ||
165 | .ox = view->swayc->current.view_x - output->swayc->current.swayc_x, | ||
166 | .oy = view->swayc->current.view_y - output->swayc->current.swayc_y, | ||
167 | .width = view->swayc->current.view_width, | ||
168 | .height = view->swayc->current.view_height, | ||
169 | .rotation = 0, // TODO | ||
170 | }; | ||
171 | |||
172 | view_for_each_popup(view, output_for_each_surface_iterator, &data); | ||
173 | } | ||
174 | |||
158 | void output_layer_for_each_surface(struct sway_output *output, | 175 | void output_layer_for_each_surface(struct sway_output *output, |
159 | struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator, | 176 | struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator, |
160 | void *user_data) { | 177 | void *user_data) { |
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index f0e47c95..1f374740 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c | |||
@@ -186,13 +186,36 @@ static void premultiply_alpha(float color[4], float opacity) { | |||
186 | color[2] *= color[3]; | 186 | color[2] *= color[3]; |
187 | } | 187 | } |
188 | 188 | ||
189 | static void render_view_surfaces(struct sway_view *view, | 189 | static void render_view_toplevels(struct sway_view *view, |
190 | struct sway_output *output, pixman_region32_t *damage, float alpha) { | 190 | struct sway_output *output, pixman_region32_t *damage, float alpha) { |
191 | struct render_data data = { | 191 | struct render_data data = { |
192 | .damage = damage, | 192 | .damage = damage, |
193 | .alpha = alpha, | 193 | .alpha = alpha, |
194 | }; | 194 | }; |
195 | output_view_for_each_surface(output, view, render_surface_iterator, &data); | 195 | // Render all toplevels without descending into popups |
196 | output_surface_for_each_surface(output, view->surface, | ||
197 | view->swayc->current.view_x, view->swayc->current.view_y, | ||
198 | render_surface_iterator, &data); | ||
199 | } | ||
200 | |||
201 | static void render_popup_iterator(struct sway_output *output, | ||
202 | struct wlr_surface *surface, struct wlr_box *box, float rotation, | ||
203 | void *data) { | ||
204 | // Render this popup's surface | ||
205 | render_surface_iterator(output, surface, box, rotation, data); | ||
206 | |||
207 | // Render this popup's child toplevels | ||
208 | output_surface_for_each_surface(output, surface, box->x, box->y, | ||
209 | render_surface_iterator, data); | ||
210 | } | ||
211 | |||
212 | static void render_view_popups(struct sway_view *view, | ||
213 | struct sway_output *output, pixman_region32_t *damage, float alpha) { | ||
214 | struct render_data data = { | ||
215 | .damage = damage, | ||
216 | .alpha = alpha, | ||
217 | }; | ||
218 | output_view_for_each_popup(output, view, render_popup_iterator, &data); | ||
196 | } | 219 | } |
197 | 220 | ||
198 | static void render_saved_view(struct sway_view *view, | 221 | static void render_saved_view(struct sway_view *view, |
@@ -239,7 +262,7 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, | |||
239 | if (view->saved_buffer) { | 262 | if (view->saved_buffer) { |
240 | render_saved_view(view, output, damage, view->swayc->alpha); | 263 | render_saved_view(view, output, damage, view->swayc->alpha); |
241 | } else { | 264 | } else { |
242 | render_view_surfaces(view, output, damage, view->swayc->alpha); | 265 | render_view_toplevels(view, output, damage, view->swayc->alpha); |
243 | } | 266 | } |
244 | 267 | ||
245 | if (view->using_csd) { | 268 | if (view->using_csd) { |
@@ -843,7 +866,7 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
843 | render_saved_view(fullscreen_con->sway_view, | 866 | render_saved_view(fullscreen_con->sway_view, |
844 | output, damage, 1.0f); | 867 | output, damage, 1.0f); |
845 | } else { | 868 | } else { |
846 | render_view_surfaces(fullscreen_con->sway_view, | 869 | render_view_toplevels(fullscreen_con->sway_view, |
847 | output, damage, 1.0f); | 870 | output, damage, 1.0f); |
848 | } | 871 | } |
849 | } else { | 872 | } else { |
@@ -879,6 +902,12 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
879 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); | 902 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); |
880 | } | 903 | } |
881 | 904 | ||
905 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
906 | struct sway_container *focus = seat_get_focus(seat); | ||
907 | if (focus && focus->type == C_VIEW) { | ||
908 | render_view_popups(focus->sway_view, output, damage, focus->alpha); | ||
909 | } | ||
910 | |||
882 | render_overlay: | 911 | render_overlay: |
883 | render_layer(output, damage, | 912 | render_layer(output, damage, |
884 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); | 913 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); |
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index e6e1527e..b364663d 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -179,6 +179,14 @@ static void for_each_surface(struct sway_view *view, | |||
179 | user_data); | 179 | user_data); |
180 | } | 180 | } |
181 | 181 | ||
182 | static void for_each_popup(struct sway_view *view, | ||
183 | wlr_surface_iterator_func_t iterator, void *user_data) { | ||
184 | if (xdg_shell_view_from_view(view) == NULL) { | ||
185 | return; | ||
186 | } | ||
187 | wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface, iterator, user_data); | ||
188 | } | ||
189 | |||
182 | static void _close(struct sway_view *view) { | 190 | static void _close(struct sway_view *view) { |
183 | if (xdg_shell_view_from_view(view) == NULL) { | 191 | if (xdg_shell_view_from_view(view) == NULL) { |
184 | return; | 192 | return; |
@@ -189,6 +197,18 @@ static void _close(struct sway_view *view) { | |||
189 | } | 197 | } |
190 | } | 198 | } |
191 | 199 | ||
200 | static void close_popups_iterator(struct wlr_surface *surface, | ||
201 | int sx, int sy, void *data) { | ||
202 | struct wlr_xdg_surface *xdg_surface = | ||
203 | wlr_xdg_surface_from_wlr_surface(surface); | ||
204 | wlr_xdg_surface_send_close(xdg_surface); | ||
205 | } | ||
206 | |||
207 | static void close_popups(struct sway_view *view) { | ||
208 | wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface, | ||
209 | close_popups_iterator, NULL); | ||
210 | } | ||
211 | |||
192 | static void destroy(struct sway_view *view) { | 212 | static void destroy(struct sway_view *view) { |
193 | struct sway_xdg_shell_view *xdg_shell_view = | 213 | struct sway_xdg_shell_view *xdg_shell_view = |
194 | xdg_shell_view_from_view(view); | 214 | xdg_shell_view_from_view(view); |
@@ -207,7 +227,9 @@ static const struct sway_view_impl view_impl = { | |||
207 | .set_fullscreen = set_fullscreen, | 227 | .set_fullscreen = set_fullscreen, |
208 | .wants_floating = wants_floating, | 228 | .wants_floating = wants_floating, |
209 | .for_each_surface = for_each_surface, | 229 | .for_each_surface = for_each_surface, |
230 | .for_each_popup = for_each_popup, | ||
210 | .close = _close, | 231 | .close = _close, |
232 | .close_popups = close_popups, | ||
211 | .destroy = destroy, | 233 | .destroy = destroy, |
212 | }; | 234 | }; |
213 | 235 | ||
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 5feee3e4..ffea03ad 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -175,6 +175,15 @@ static void for_each_surface(struct sway_view *view, | |||
175 | user_data); | 175 | user_data); |
176 | } | 176 | } |
177 | 177 | ||
178 | static void for_each_popup(struct sway_view *view, | ||
179 | wlr_surface_iterator_func_t iterator, void *user_data) { | ||
180 | if (xdg_shell_v6_view_from_view(view) == NULL) { | ||
181 | return; | ||
182 | } | ||
183 | wlr_xdg_surface_v6_for_each_popup(view->wlr_xdg_surface_v6, iterator, | ||
184 | user_data); | ||
185 | } | ||
186 | |||
178 | static void _close(struct sway_view *view) { | 187 | static void _close(struct sway_view *view) { |
179 | if (xdg_shell_v6_view_from_view(view) == NULL) { | 188 | if (xdg_shell_v6_view_from_view(view) == NULL) { |
180 | return; | 189 | return; |
@@ -185,6 +194,18 @@ static void _close(struct sway_view *view) { | |||
185 | } | 194 | } |
186 | } | 195 | } |
187 | 196 | ||
197 | static void close_popups_iterator(struct wlr_surface *surface, | ||
198 | int sx, int sy, void *data) { | ||
199 | struct wlr_xdg_surface_v6 *xdg_surface_v6 = | ||
200 | wlr_xdg_surface_v6_from_wlr_surface(surface); | ||
201 | wlr_xdg_surface_v6_send_close(xdg_surface_v6); | ||
202 | } | ||
203 | |||
204 | static void close_popups(struct sway_view *view) { | ||
205 | wlr_xdg_surface_v6_for_each_popup(view->wlr_xdg_surface_v6, | ||
206 | close_popups_iterator, NULL); | ||
207 | } | ||
208 | |||
188 | static void destroy(struct sway_view *view) { | 209 | static void destroy(struct sway_view *view) { |
189 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = | 210 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = |
190 | xdg_shell_v6_view_from_view(view); | 211 | xdg_shell_v6_view_from_view(view); |
@@ -203,7 +224,9 @@ static const struct sway_view_impl view_impl = { | |||
203 | .set_fullscreen = set_fullscreen, | 224 | .set_fullscreen = set_fullscreen, |
204 | .wants_floating = wants_floating, | 225 | .wants_floating = wants_floating, |
205 | .for_each_surface = for_each_surface, | 226 | .for_each_surface = for_each_surface, |
227 | .for_each_popup = for_each_popup, | ||
206 | .close = _close, | 228 | .close = _close, |
229 | .close_popups = close_popups, | ||
207 | .destroy = destroy, | 230 | .destroy = destroy, |
208 | }; | 231 | }; |
209 | 232 | ||
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 96ac7b33..79f6ec46 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -109,9 +109,6 @@ static struct sway_container *container_at_coords( | |||
109 | } | 109 | } |
110 | 110 | ||
111 | struct sway_container *c; | 111 | struct sway_container *c; |
112 | if ((c = floating_container_at(lx, ly, surface, sx, sy))) { | ||
113 | return c; | ||
114 | } | ||
115 | if ((c = container_at(ws, lx, ly, surface, sx, sy))) { | 112 | if ((c = container_at(ws, lx, ly, surface, sx, sy))) { |
116 | return c; | 113 | return c; |
117 | } | 114 | } |
@@ -349,7 +346,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, | |||
349 | output = container_parent(c, C_OUTPUT); | 346 | output = container_parent(c, C_OUTPUT); |
350 | } | 347 | } |
351 | if (output != focus) { | 348 | if (output != focus) { |
352 | seat_set_focus_warp(seat, c, false); | 349 | seat_set_focus_warp(seat, c, false, true); |
353 | } | 350 | } |
354 | } else if (c->type == C_VIEW) { | 351 | } else if (c->type == C_VIEW) { |
355 | // Focus c if the following are true: | 352 | // Focus c if the following are true: |
@@ -359,13 +356,13 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, | |||
359 | if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) && | 356 | if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) && |
360 | c != prev_c && | 357 | c != prev_c && |
361 | view_is_visible(c->sway_view)) { | 358 | view_is_visible(c->sway_view)) { |
362 | seat_set_focus_warp(seat, c, false); | 359 | seat_set_focus_warp(seat, c, false, true); |
363 | } else { | 360 | } else { |
364 | struct sway_container *next_focus = | 361 | struct sway_container *next_focus = |
365 | seat_get_focus_inactive(seat, &root_container); | 362 | seat_get_focus_inactive(seat, &root_container); |
366 | if (next_focus && next_focus->type == C_VIEW && | 363 | if (next_focus && next_focus->type == C_VIEW && |
367 | view_is_visible(next_focus->sway_view)) { | 364 | view_is_visible(next_focus->sway_view)) { |
368 | seat_set_focus_warp(seat, next_focus, false); | 365 | seat_set_focus_warp(seat, next_focus, false, true); |
369 | } | 366 | } |
370 | } | 367 | } |
371 | } | 368 | } |
diff --git a/sway/input/seat.c b/sway/input/seat.c index 53a92989..869560af 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -393,7 +393,6 @@ struct sway_seat *seat_create(struct sway_input_manager *input, | |||
393 | WL_SEAT_CAPABILITY_POINTER | | 393 | WL_SEAT_CAPABILITY_POINTER | |
394 | WL_SEAT_CAPABILITY_TOUCH); | 394 | WL_SEAT_CAPABILITY_TOUCH); |
395 | 395 | ||
396 | seat_configure_xcursor(seat); | ||
397 | 396 | ||
398 | wl_list_insert(&input->seats, &seat->link); | 397 | wl_list_insert(&input->seats, &seat->link); |
399 | 398 | ||
@@ -438,6 +437,7 @@ static void seat_apply_input_config(struct sway_seat *seat, | |||
438 | 437 | ||
439 | static void seat_configure_pointer(struct sway_seat *seat, | 438 | static void seat_configure_pointer(struct sway_seat *seat, |
440 | struct sway_seat_device *sway_device) { | 439 | struct sway_seat_device *sway_device) { |
440 | seat_configure_xcursor(seat); | ||
441 | wlr_cursor_attach_input_device(seat->cursor->cursor, | 441 | wlr_cursor_attach_input_device(seat->cursor->cursor, |
442 | sway_device->input_device->wlr_device); | 442 | sway_device->input_device->wlr_device); |
443 | seat_apply_input_config(seat, sway_device); | 443 | seat_apply_input_config(seat, sway_device); |
@@ -617,7 +617,7 @@ static int handle_urgent_timeout(void *data) { | |||
617 | } | 617 | } |
618 | 618 | ||
619 | void seat_set_focus_warp(struct sway_seat *seat, | 619 | void seat_set_focus_warp(struct sway_seat *seat, |
620 | struct sway_container *container, bool warp) { | 620 | struct sway_container *container, bool warp, bool notify) { |
621 | if (seat->focused_layer) { | 621 | if (seat->focused_layer) { |
622 | return; | 622 | return; |
623 | } | 623 | } |
@@ -737,9 +737,18 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
737 | } | 737 | } |
738 | } | 738 | } |
739 | 739 | ||
740 | // Close any popups on the old focus | ||
741 | if (last_focus && last_focus != container) { | ||
742 | if (last_focus->type == C_VIEW) { | ||
743 | view_close_popups(last_focus->sway_view); | ||
744 | } | ||
745 | } | ||
746 | |||
740 | if (last_focus) { | 747 | if (last_focus) { |
741 | if (last_workspace) { | 748 | if (last_workspace) { |
742 | ipc_event_workspace(last_workspace, container, "focus"); | 749 | if (notify && last_workspace != new_workspace) { |
750 | ipc_event_workspace(last_workspace, new_workspace, "focus"); | ||
751 | } | ||
743 | if (!workspace_is_visible(last_workspace) | 752 | if (!workspace_is_visible(last_workspace) |
744 | && workspace_is_empty(last_workspace)) { | 753 | && workspace_is_empty(last_workspace)) { |
745 | if (last_workspace == last_focus) { | 754 | if (last_workspace == last_focus) { |
@@ -766,6 +775,10 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
766 | } | 775 | } |
767 | } | 776 | } |
768 | 777 | ||
778 | if (container->type == C_VIEW) { | ||
779 | ipc_event_window(container, "focus"); | ||
780 | } | ||
781 | |||
769 | seat->has_focus = (container != NULL); | 782 | seat->has_focus = (container != NULL); |
770 | 783 | ||
771 | update_debug_tree(); | 784 | update_debug_tree(); |
@@ -773,7 +786,7 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
773 | 786 | ||
774 | void seat_set_focus(struct sway_seat *seat, | 787 | void seat_set_focus(struct sway_seat *seat, |
775 | struct sway_container *container) { | 788 | struct sway_container *container) { |
776 | seat_set_focus_warp(seat, container, true); | 789 | seat_set_focus_warp(seat, container, true, true); |
777 | } | 790 | } |
778 | 791 | ||
779 | void seat_set_focus_surface(struct sway_seat *seat, | 792 | void seat_set_focus_surface(struct sway_seat *seat, |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index c49ea47e..4c2bcc98 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -201,6 +201,15 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object | |||
201 | bool urgent = c->type == C_VIEW ? | 201 | bool urgent = c->type == C_VIEW ? |
202 | view_is_urgent(c->sway_view) : container_has_urgent_child(c); | 202 | view_is_urgent(c->sway_view) : container_has_urgent_child(c); |
203 | json_object_object_add(object, "urgent", json_object_new_boolean(urgent)); | 203 | json_object_object_add(object, "urgent", json_object_new_boolean(urgent)); |
204 | |||
205 | if (c->type == C_VIEW) { | ||
206 | json_object *marks = json_object_new_array(); | ||
207 | list_t *view_marks = c->sway_view->marks; | ||
208 | for (int i = 0; i < view_marks->length; ++i) { | ||
209 | json_object_array_add(marks, json_object_new_string(view_marks->items[i])); | ||
210 | } | ||
211 | json_object_object_add(object, "marks", marks); | ||
212 | } | ||
204 | } | 213 | } |
205 | 214 | ||
206 | static void focus_inactive_children_iterator(struct sway_container *c, void *data) { | 215 | static void focus_inactive_children_iterator(struct sway_container *c, void *data) { |
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index be703915..7d2d8969 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -3,12 +3,18 @@ | |||
3 | // Any value will hide SOCK_CLOEXEC on FreeBSD (__BSD_VISIBLE=0) | 3 | // Any value will hide SOCK_CLOEXEC on FreeBSD (__BSD_VISIBLE=0) |
4 | #define _XOPEN_SOURCE 700 | 4 | #define _XOPEN_SOURCE 700 |
5 | #endif | 5 | #endif |
6 | #ifdef __linux__ | ||
7 | #include <linux/input-event-codes.h> | ||
8 | #elif __FreeBSD__ | ||
9 | #include <dev/evdev/input-event-codes.h> | ||
10 | #endif | ||
6 | #include <assert.h> | 11 | #include <assert.h> |
7 | #include <errno.h> | 12 | #include <errno.h> |
8 | #include <fcntl.h> | 13 | #include <fcntl.h> |
9 | #include <json-c/json.h> | 14 | #include <json-c/json.h> |
10 | #include <stdbool.h> | 15 | #include <stdbool.h> |
11 | #include <stdint.h> | 16 | #include <stdint.h> |
17 | #include <stdio.h> | ||
12 | #include <stdlib.h> | 18 | #include <stdlib.h> |
13 | #include <string.h> | 19 | #include <string.h> |
14 | #include <sys/socket.h> | 20 | #include <sys/socket.h> |
@@ -28,6 +34,7 @@ | |||
28 | #include "sway/tree/view.h" | 34 | #include "sway/tree/view.h" |
29 | #include "list.h" | 35 | #include "list.h" |
30 | #include "log.h" | 36 | #include "log.h" |
37 | #include "util.h" | ||
31 | 38 | ||
32 | static int ipc_socket = -1; | 39 | static int ipc_socket = -1; |
33 | static struct wl_event_source *ipc_event_source = NULL; | 40 | static struct wl_event_source *ipc_event_source = NULL; |
@@ -291,13 +298,11 @@ void ipc_event_workspace(struct sway_container *old, | |||
291 | wlr_log(WLR_DEBUG, "Sending workspace::%s event", change); | 298 | wlr_log(WLR_DEBUG, "Sending workspace::%s event", change); |
292 | json_object *obj = json_object_new_object(); | 299 | json_object *obj = json_object_new_object(); |
293 | json_object_object_add(obj, "change", json_object_new_string(change)); | 300 | json_object_object_add(obj, "change", json_object_new_string(change)); |
294 | if (strcmp("focus", change) == 0) { | 301 | if (old) { |
295 | if (old) { | 302 | json_object_object_add(obj, "old", |
296 | json_object_object_add(obj, "old", | 303 | ipc_json_describe_container_recursive(old)); |
297 | ipc_json_describe_container_recursive(old)); | 304 | } else { |
298 | } else { | 305 | json_object_object_add(obj, "old", NULL); |
299 | json_object_object_add(obj, "old", NULL); | ||
300 | } | ||
301 | } | 306 | } |
302 | 307 | ||
303 | if (new) { | 308 | if (new) { |
@@ -353,6 +358,104 @@ void ipc_event_mode(const char *mode, bool pango) { | |||
353 | json_object_put(obj); | 358 | json_object_put(obj); |
354 | } | 359 | } |
355 | 360 | ||
361 | void ipc_event_shutdown(const char *reason) { | ||
362 | if (!ipc_has_event_listeners(IPC_EVENT_SHUTDOWN)) { | ||
363 | return; | ||
364 | } | ||
365 | wlr_log(WLR_DEBUG, "Sending shutdown::%s event", reason); | ||
366 | |||
367 | json_object *json = json_object_new_object(); | ||
368 | json_object_object_add(json, "change", json_object_new_string(reason)); | ||
369 | |||
370 | const char *json_string = json_object_to_json_string(json); | ||
371 | ipc_send_event(json_string, IPC_EVENT_SHUTDOWN); | ||
372 | json_object_put(json); | ||
373 | } | ||
374 | |||
375 | void ipc_event_binding(struct sway_binding *binding) { | ||
376 | if (!ipc_has_event_listeners(IPC_EVENT_BINDING)) { | ||
377 | return; | ||
378 | } | ||
379 | wlr_log(WLR_DEBUG, "Sending binding event"); | ||
380 | |||
381 | json_object *json_binding = json_object_new_object(); | ||
382 | json_object_object_add(json_binding, "command", json_object_new_string(binding->command)); | ||
383 | |||
384 | const char *names[10]; | ||
385 | int len = get_modifier_names(names, binding->modifiers); | ||
386 | json_object *modifiers = json_object_new_array(); | ||
387 | for (int i = 0; i < len; ++i) { | ||
388 | json_object_array_add(modifiers, json_object_new_string(names[i])); | ||
389 | } | ||
390 | json_object_object_add(json_binding, "event_state_mask", modifiers); | ||
391 | |||
392 | json_object *input_codes = json_object_new_array(); | ||
393 | int input_code = 0; | ||
394 | json_object *symbols = json_object_new_array(); | ||
395 | json_object *symbol = NULL; | ||
396 | |||
397 | if (binding->type == BINDING_KEYCODE) { // bindcode: populate input_codes | ||
398 | uint32_t keycode; | ||
399 | for (int i = 0; i < binding->keys->length; ++i) { | ||
400 | keycode = *(uint32_t *)binding->keys->items[i]; | ||
401 | json_object_array_add(input_codes, json_object_new_int(keycode)); | ||
402 | if (i == 0) { | ||
403 | input_code = keycode; | ||
404 | } | ||
405 | } | ||
406 | } else { // bindsym/mouse: populate symbols | ||
407 | uint32_t keysym; | ||
408 | char buffer[64]; | ||
409 | for (int i = 0; i < binding->keys->length; ++i) { | ||
410 | keysym = *(uint32_t *)binding->keys->items[i]; | ||
411 | if (keysym >= BTN_LEFT && keysym <= BTN_LEFT + 8) { | ||
412 | snprintf(buffer, 64, "button%u", keysym - BTN_LEFT + 1); | ||
413 | } else if (xkb_keysym_get_name(keysym, buffer, 64) < 0) { | ||
414 | continue; | ||
415 | } | ||
416 | |||
417 | json_object *str = json_object_new_string(buffer); | ||
418 | if (i == 0) { | ||
419 | // str is owned by both symbol and symbols. Make sure | ||
420 | // to bump the ref count. | ||
421 | json_object_array_add(symbols, json_object_get(str)); | ||
422 | symbol = str; | ||
423 | } else { | ||
424 | json_object_array_add(symbols, str); | ||
425 | } | ||
426 | } | ||
427 | } | ||
428 | |||
429 | json_object_object_add(json_binding, "input_codes", input_codes); | ||
430 | json_object_object_add(json_binding, "input_code", json_object_new_int(input_code)); | ||
431 | json_object_object_add(json_binding, "symbols", symbols); | ||
432 | json_object_object_add(json_binding, "symbol", symbol); | ||
433 | json_object_object_add(json_binding, "input_type", binding->type == BINDING_MOUSE ? | ||
434 | json_object_new_string("mouse") : json_object_new_string("keyboard")); | ||
435 | |||
436 | json_object *json = json_object_new_object(); | ||
437 | json_object_object_add(json, "change", json_object_new_string("run")); | ||
438 | json_object_object_add(json, "binding", json_binding); | ||
439 | const char *json_string = json_object_to_json_string(json); | ||
440 | ipc_send_event(json_string, IPC_EVENT_BINDING); | ||
441 | json_object_put(json); | ||
442 | } | ||
443 | |||
444 | static void ipc_event_tick(const char *payload) { | ||
445 | if (!ipc_has_event_listeners(IPC_EVENT_TICK)) { | ||
446 | return; | ||
447 | } | ||
448 | wlr_log(WLR_DEBUG, "Sending tick event"); | ||
449 | |||
450 | json_object *json = json_object_new_object(); | ||
451 | json_object_object_add(json, "first", json_object_new_boolean(false)); | ||
452 | json_object_object_add(json, "payload", json_object_new_string(payload)); | ||
453 | |||
454 | const char *json_string = json_object_to_json_string(json); | ||
455 | ipc_send_event(json_string, IPC_EVENT_TICK); | ||
456 | json_object_put(json); | ||
457 | } | ||
458 | |||
356 | int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { | 459 | int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { |
357 | struct ipc_client *client = data; | 460 | struct ipc_client *client = data; |
358 | 461 | ||
@@ -494,6 +597,13 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
494 | goto exit_cleanup; | 597 | goto exit_cleanup; |
495 | } | 598 | } |
496 | 599 | ||
600 | case IPC_SEND_TICK: | ||
601 | { | ||
602 | ipc_event_tick(buf); | ||
603 | ipc_send_reply(client, "{\"success\": true}", 17); | ||
604 | goto exit_cleanup; | ||
605 | } | ||
606 | |||
497 | case IPC_GET_OUTPUTS: | 607 | case IPC_GET_OUTPUTS: |
498 | { | 608 | { |
499 | json_object *outputs = json_object_new_array(); | 609 | json_object *outputs = json_object_new_array(); |
@@ -540,6 +650,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
540 | goto exit_cleanup; | 650 | goto exit_cleanup; |
541 | } | 651 | } |
542 | 652 | ||
653 | bool is_tick = false; | ||
543 | // parse requested event types | 654 | // parse requested event types |
544 | for (size_t i = 0; i < json_object_array_length(request); i++) { | 655 | for (size_t i = 0; i < json_object_array_length(request); i++) { |
545 | const char *event_type = json_object_get_string(json_object_array_get_idx(request, i)); | 656 | const char *event_type = json_object_get_string(json_object_array_get_idx(request, i)); |
@@ -549,12 +660,15 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
549 | client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE); | 660 | client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE); |
550 | } else if (strcmp(event_type, "mode") == 0) { | 661 | } else if (strcmp(event_type, "mode") == 0) { |
551 | client->subscribed_events |= event_mask(IPC_EVENT_MODE); | 662 | client->subscribed_events |= event_mask(IPC_EVENT_MODE); |
663 | } else if (strcmp(event_type, "shutdown") == 0) { | ||
664 | client->subscribed_events |= event_mask(IPC_EVENT_SHUTDOWN); | ||
552 | } else if (strcmp(event_type, "window") == 0) { | 665 | } else if (strcmp(event_type, "window") == 0) { |
553 | client->subscribed_events |= event_mask(IPC_EVENT_WINDOW); | 666 | client->subscribed_events |= event_mask(IPC_EVENT_WINDOW); |
554 | } else if (strcmp(event_type, "modifier") == 0) { | ||
555 | client->subscribed_events |= event_mask(IPC_EVENT_MODIFIER); | ||
556 | } else if (strcmp(event_type, "binding") == 0) { | 667 | } else if (strcmp(event_type, "binding") == 0) { |
557 | client->subscribed_events |= event_mask(IPC_EVENT_BINDING); | 668 | client->subscribed_events |= event_mask(IPC_EVENT_BINDING); |
669 | } else if (strcmp(event_type, "tick") == 0) { | ||
670 | client->subscribed_events |= event_mask(IPC_EVENT_TICK); | ||
671 | is_tick = true; | ||
558 | } else { | 672 | } else { |
559 | client_valid = | 673 | client_valid = |
560 | ipc_send_reply(client, "{\"success\": false}", 18); | 674 | ipc_send_reply(client, "{\"success\": false}", 18); |
@@ -566,6 +680,10 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
566 | 680 | ||
567 | json_object_put(request); | 681 | json_object_put(request); |
568 | client_valid = ipc_send_reply(client, "{\"success\": true}", 17); | 682 | client_valid = ipc_send_reply(client, "{\"success\": true}", 17); |
683 | if (is_tick) { | ||
684 | client->current_command = IPC_EVENT_TICK; | ||
685 | ipc_send_reply(client, "{\"first\": true, \"payload\": \"\"}", 30); | ||
686 | } | ||
569 | goto exit_cleanup; | 687 | goto exit_cleanup; |
570 | } | 688 | } |
571 | 689 | ||
diff --git a/sway/main.c b/sway/main.c index a20f1dac..477ffa5a 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -36,6 +36,7 @@ struct sway_server server; | |||
36 | void sway_terminate(int exit_code) { | 36 | void sway_terminate(int exit_code) { |
37 | terminate_request = true; | 37 | terminate_request = true; |
38 | exit_value = exit_code; | 38 | exit_value = exit_code; |
39 | ipc_event_shutdown("exit"); | ||
39 | wl_display_terminate(server.wl_display); | 40 | wl_display_terminate(server.wl_display); |
40 | } | 41 | } |
41 | 42 | ||
diff --git a/sway/tree/container.c b/sway/tree/container.c index 4e85021d..b980c5e9 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -62,8 +62,10 @@ void container_create_notify(struct sway_container *container) { | |||
62 | // TODO send ipc event type based on the container type | 62 | // TODO send ipc event type based on the container type |
63 | wl_signal_emit(&root_container.sway_root->events.new_container, container); | 63 | wl_signal_emit(&root_container.sway_root->events.new_container, container); |
64 | 64 | ||
65 | if (container->type == C_VIEW || container->type == C_CONTAINER) { | 65 | if (container->type == C_VIEW) { |
66 | ipc_event_window(container, "new"); | 66 | ipc_event_window(container, "new"); |
67 | } else if (container->type == C_WORKSPACE) { | ||
68 | ipc_event_workspace(NULL, container, "init"); | ||
67 | } | 69 | } |
68 | } | 70 | } |
69 | 71 | ||
@@ -281,7 +283,7 @@ static struct sway_container *container_output_destroy( | |||
281 | container_remove_child(workspace); | 283 | container_remove_child(workspace); |
282 | if (!workspace_is_empty(workspace)) { | 284 | if (!workspace_is_empty(workspace)) { |
283 | container_add_child(new_output, workspace); | 285 | container_add_child(new_output, workspace); |
284 | ipc_event_workspace(workspace, NULL, "move"); | 286 | ipc_event_workspace(NULL, workspace, "move"); |
285 | } else { | 287 | } else { |
286 | container_destroy(workspace); | 288 | container_destroy(workspace); |
287 | } | 289 | } |
@@ -319,7 +321,13 @@ static struct sway_container *container_destroy_noreaping( | |||
319 | } | 321 | } |
320 | 322 | ||
321 | wl_signal_emit(&con->events.destroy, con); | 323 | wl_signal_emit(&con->events.destroy, con); |
322 | ipc_event_window(con, "close"); | 324 | |
325 | // emit IPC event | ||
326 | if (con->type == C_VIEW) { | ||
327 | ipc_event_window(con, "close"); | ||
328 | } else if (con->type == C_WORKSPACE) { | ||
329 | ipc_event_workspace(NULL, con, "empty"); | ||
330 | } | ||
323 | 331 | ||
324 | // The below functions move their children to somewhere else. | 332 | // The below functions move their children to somewhere else. |
325 | if (con->type == C_OUTPUT) { | 333 | if (con->type == C_OUTPUT) { |
@@ -561,10 +569,15 @@ static struct sway_container *container_at_view(struct sway_container *swayc, | |||
561 | *sx = _sx; | 569 | *sx = _sx; |
562 | *sy = _sy; | 570 | *sy = _sy; |
563 | *surface = _surface; | 571 | *surface = _surface; |
572 | return swayc; | ||
564 | } | 573 | } |
565 | return swayc; | 574 | return NULL; |
566 | } | 575 | } |
567 | 576 | ||
577 | static struct sway_container *tiling_container_at( | ||
578 | struct sway_container *con, double lx, double ly, | ||
579 | struct wlr_surface **surface, double *sx, double *sy); | ||
580 | |||
568 | /** | 581 | /** |
569 | * container_at for a container with layout L_TABBED. | 582 | * container_at for a container with layout L_TABBED. |
570 | */ | 583 | */ |
@@ -591,7 +604,7 @@ static struct sway_container *container_at_tabbed(struct sway_container *parent, | |||
591 | // Surfaces | 604 | // Surfaces |
592 | struct sway_container *current = seat_get_active_child(seat, parent); | 605 | struct sway_container *current = seat_get_active_child(seat, parent); |
593 | 606 | ||
594 | return container_at(current, lx, ly, surface, sx, sy); | 607 | return tiling_container_at(current, lx, ly, surface, sx, sy); |
595 | } | 608 | } |
596 | 609 | ||
597 | /** | 610 | /** |
@@ -616,7 +629,7 @@ static struct sway_container *container_at_stacked( | |||
616 | // Surfaces | 629 | // Surfaces |
617 | struct sway_container *current = seat_get_active_child(seat, parent); | 630 | struct sway_container *current = seat_get_active_child(seat, parent); |
618 | 631 | ||
619 | return container_at(current, lx, ly, surface, sx, sy); | 632 | return tiling_container_at(current, lx, ly, surface, sx, sy); |
620 | } | 633 | } |
621 | 634 | ||
622 | /** | 635 | /** |
@@ -634,45 +647,13 @@ static struct sway_container *container_at_linear(struct sway_container *parent, | |||
634 | .height = child->height, | 647 | .height = child->height, |
635 | }; | 648 | }; |
636 | if (wlr_box_contains_point(&box, lx, ly)) { | 649 | if (wlr_box_contains_point(&box, lx, ly)) { |
637 | return container_at(child, lx, ly, surface, sx, sy); | 650 | return tiling_container_at(child, lx, ly, surface, sx, sy); |
638 | } | 651 | } |
639 | } | 652 | } |
640 | return NULL; | 653 | return NULL; |
641 | } | 654 | } |
642 | 655 | ||
643 | struct sway_container *container_at(struct sway_container *parent, | 656 | static struct sway_container *floating_container_at(double lx, double ly, |
644 | double lx, double ly, | ||
645 | struct wlr_surface **surface, double *sx, double *sy) { | ||
646 | if (!sway_assert(parent->type >= C_WORKSPACE, | ||
647 | "Expected workspace or deeper")) { | ||
648 | return NULL; | ||
649 | } | ||
650 | if (parent->type == C_VIEW) { | ||
651 | return container_at_view(parent, lx, ly, surface, sx, sy); | ||
652 | } | ||
653 | if (!parent->children->length) { | ||
654 | return NULL; | ||
655 | } | ||
656 | |||
657 | switch (parent->layout) { | ||
658 | case L_HORIZ: | ||
659 | case L_VERT: | ||
660 | return container_at_linear(parent, lx, ly, surface, sx, sy); | ||
661 | case L_TABBED: | ||
662 | return container_at_tabbed(parent, lx, ly, surface, sx, sy); | ||
663 | case L_STACKED: | ||
664 | return container_at_stacked(parent, lx, ly, surface, sx, sy); | ||
665 | case L_FLOATING: | ||
666 | sway_assert(false, "Didn't expect to see floating here"); | ||
667 | return NULL; | ||
668 | case L_NONE: | ||
669 | return NULL; | ||
670 | } | ||
671 | |||
672 | return NULL; | ||
673 | } | ||
674 | |||
675 | struct sway_container *floating_container_at(double lx, double ly, | ||
676 | struct wlr_surface **surface, double *sx, double *sy) { | 657 | struct wlr_surface **surface, double *sx, double *sy) { |
677 | for (int i = 0; i < root_container.children->length; ++i) { | 658 | for (int i = 0; i < root_container.children->length; ++i) { |
678 | struct sway_container *output = root_container.children->items[i]; | 659 | struct sway_container *output = root_container.children->items[i]; |
@@ -694,7 +675,8 @@ struct sway_container *floating_container_at(double lx, double ly, | |||
694 | .height = floater->height, | 675 | .height = floater->height, |
695 | }; | 676 | }; |
696 | if (wlr_box_contains_point(&box, lx, ly)) { | 677 | if (wlr_box_contains_point(&box, lx, ly)) { |
697 | return container_at(floater, lx, ly, surface, sx, sy); | 678 | return tiling_container_at(floater, lx, ly, |
679 | surface, sx, sy); | ||
698 | } | 680 | } |
699 | } | 681 | } |
700 | } | 682 | } |
@@ -702,6 +684,90 @@ struct sway_container *floating_container_at(double lx, double ly, | |||
702 | return NULL; | 684 | return NULL; |
703 | } | 685 | } |
704 | 686 | ||
687 | static struct sway_container *tiling_container_at( | ||
688 | struct sway_container *con, double lx, double ly, | ||
689 | struct wlr_surface **surface, double *sx, double *sy) { | ||
690 | if (con->type == C_VIEW) { | ||
691 | return container_at_view(con, lx, ly, surface, sx, sy); | ||
692 | } | ||
693 | if (!con->children->length) { | ||
694 | return NULL; | ||
695 | } | ||
696 | |||
697 | switch (con->layout) { | ||
698 | case L_HORIZ: | ||
699 | case L_VERT: | ||
700 | return container_at_linear(con, lx, ly, surface, sx, sy); | ||
701 | case L_TABBED: | ||
702 | return container_at_tabbed(con, lx, ly, surface, sx, sy); | ||
703 | case L_STACKED: | ||
704 | return container_at_stacked(con, lx, ly, surface, sx, sy); | ||
705 | case L_FLOATING: | ||
706 | sway_assert(false, "Didn't expect to see floating here"); | ||
707 | return NULL; | ||
708 | case L_NONE: | ||
709 | return NULL; | ||
710 | } | ||
711 | return NULL; | ||
712 | } | ||
713 | |||
714 | static bool surface_is_popup(struct wlr_surface *surface) { | ||
715 | if (wlr_surface_is_xdg_surface(surface)) { | ||
716 | struct wlr_xdg_surface *xdg_surface = | ||
717 | wlr_xdg_surface_from_wlr_surface(surface); | ||
718 | while (xdg_surface) { | ||
719 | if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { | ||
720 | return true; | ||
721 | } | ||
722 | xdg_surface = xdg_surface->toplevel->parent; | ||
723 | } | ||
724 | return false; | ||
725 | } | ||
726 | |||
727 | if (wlr_surface_is_xdg_surface_v6(surface)) { | ||
728 | struct wlr_xdg_surface_v6 *xdg_surface_v6 = | ||
729 | wlr_xdg_surface_v6_from_wlr_surface(surface); | ||
730 | while (xdg_surface_v6) { | ||
731 | if (xdg_surface_v6->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) { | ||
732 | return true; | ||
733 | } | ||
734 | xdg_surface_v6 = xdg_surface_v6->toplevel->parent; | ||
735 | } | ||
736 | return false; | ||
737 | } | ||
738 | |||
739 | return false; | ||
740 | } | ||
741 | |||
742 | struct sway_container *container_at(struct sway_container *workspace, | ||
743 | double lx, double ly, | ||
744 | struct wlr_surface **surface, double *sx, double *sy) { | ||
745 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | ||
746 | return NULL; | ||
747 | } | ||
748 | struct sway_container *c; | ||
749 | // Focused view's popups | ||
750 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
751 | struct sway_container *focus = | ||
752 | seat_get_focus_inactive(seat, &root_container); | ||
753 | if (focus && focus->type == C_VIEW) { | ||
754 | container_at_view(focus, lx, ly, surface, sx, sy); | ||
755 | if (*surface && surface_is_popup(*surface)) { | ||
756 | return focus; | ||
757 | } | ||
758 | *surface = NULL; | ||
759 | } | ||
760 | // Floating | ||
761 | if ((c = floating_container_at(lx, ly, surface, sx, sy))) { | ||
762 | return c; | ||
763 | } | ||
764 | // Tiling | ||
765 | if ((c = tiling_container_at(workspace, lx, ly, surface, sx, sy))) { | ||
766 | return c; | ||
767 | } | ||
768 | return NULL; | ||
769 | } | ||
770 | |||
705 | void container_for_each_descendant_dfs(struct sway_container *container, | 771 | void container_for_each_descendant_dfs(struct sway_container *container, |
706 | void (*f)(struct sway_container *container, void *data), | 772 | void (*f)(struct sway_container *container, void *data), |
707 | void *data) { | 773 | void *data) { |
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index a0764a54..1f82e534 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -217,7 +217,9 @@ void container_move_to(struct sway_container *container, | |||
217 | container_sort_workspaces(new_parent); | 217 | container_sort_workspaces(new_parent); |
218 | seat_set_focus(seat, new_parent); | 218 | seat_set_focus(seat, new_parent); |
219 | workspace_output_raise_priority(container, old_parent, new_parent); | 219 | workspace_output_raise_priority(container, old_parent, new_parent); |
220 | ipc_event_workspace(container, NULL, "move"); | 220 | ipc_event_workspace(NULL, container, "move"); |
221 | } else if (container->type == C_VIEW) { | ||
222 | ipc_event_window(container, "move"); | ||
221 | } | 223 | } |
222 | container_notify_subtree_changed(old_parent); | 224 | container_notify_subtree_changed(old_parent); |
223 | container_notify_subtree_changed(new_parent); | 225 | container_notify_subtree_changed(new_parent); |
@@ -578,6 +580,10 @@ void container_move(struct sway_container *container, | |||
578 | container_notify_subtree_changed(old_parent); | 580 | container_notify_subtree_changed(old_parent); |
579 | container_notify_subtree_changed(container->parent); | 581 | container_notify_subtree_changed(container->parent); |
580 | 582 | ||
583 | if (container->type == C_VIEW) { | ||
584 | ipc_event_window(container, "move"); | ||
585 | } | ||
586 | |||
581 | if (old_parent) { | 587 | if (old_parent) { |
582 | seat_set_focus(config->handler_context.seat, old_parent); | 588 | seat_set_focus(config->handler_context.seat, old_parent); |
583 | seat_set_focus(config->handler_context.seat, container); | 589 | seat_set_focus(config->handler_context.seat, container); |
@@ -592,7 +598,7 @@ void container_move(struct sway_container *container, | |||
592 | next_ws = container_parent(next_ws, C_WORKSPACE); | 598 | next_ws = container_parent(next_ws, C_WORKSPACE); |
593 | } | 599 | } |
594 | if (last_ws && next_ws && last_ws != next_ws) { | 600 | if (last_ws && next_ws && last_ws != next_ws) { |
595 | ipc_event_workspace(last_ws, container, "focus"); | 601 | ipc_event_workspace(last_ws, next_ws, "focus"); |
596 | workspace_detect_urgent(last_ws); | 602 | workspace_detect_urgent(last_ws); |
597 | workspace_detect_urgent(next_ws); | 603 | workspace_detect_urgent(next_ws); |
598 | } | 604 | } |
@@ -995,13 +1001,13 @@ static void swap_focus(struct sway_container *con1, | |||
995 | if (focus == con1 && (con2->parent->layout == L_TABBED | 1001 | if (focus == con1 && (con2->parent->layout == L_TABBED |
996 | || con2->parent->layout == L_STACKED)) { | 1002 | || con2->parent->layout == L_STACKED)) { |
997 | if (workspace_is_visible(ws2)) { | 1003 | if (workspace_is_visible(ws2)) { |
998 | seat_set_focus_warp(seat, con2, false); | 1004 | seat_set_focus_warp(seat, con2, false, true); |
999 | } | 1005 | } |
1000 | seat_set_focus(seat, ws1 != ws2 ? con2 : con1); | 1006 | seat_set_focus(seat, ws1 != ws2 ? con2 : con1); |
1001 | } else if (focus == con2 && (con1->parent->layout == L_TABBED | 1007 | } else if (focus == con2 && (con1->parent->layout == L_TABBED |
1002 | || con1->parent->layout == L_STACKED)) { | 1008 | || con1->parent->layout == L_STACKED)) { |
1003 | if (workspace_is_visible(ws1)) { | 1009 | if (workspace_is_visible(ws1)) { |
1004 | seat_set_focus_warp(seat, con1, false); | 1010 | seat_set_focus_warp(seat, con1, false, true); |
1005 | } | 1011 | } |
1006 | seat_set_focus(seat, ws1 != ws2 ? con1 : con2); | 1012 | seat_set_focus(seat, ws1 != ws2 ? con1 : con2); |
1007 | } else if (ws1 != ws2) { | 1013 | } else if (ws1 != ws2) { |
diff --git a/sway/tree/output.c b/sway/tree/output.c index da535c18..31e3bf9b 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c | |||
@@ -22,7 +22,7 @@ static void restore_workspaces(struct sway_container *output) { | |||
22 | if (highest == output) { | 22 | if (highest == output) { |
23 | container_remove_child(ws); | 23 | container_remove_child(ws); |
24 | container_add_child(output, ws); | 24 | container_add_child(output, ws); |
25 | ipc_event_workspace(ws, NULL, "move"); | 25 | ipc_event_workspace(NULL, ws, "move"); |
26 | j--; | 26 | j--; |
27 | } | 27 | } |
28 | } | 28 | } |
diff --git a/sway/tree/view.c b/sway/tree/view.c index 0dbd3812..051b93ce 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -303,6 +303,12 @@ void view_close(struct sway_view *view) { | |||
303 | } | 303 | } |
304 | } | 304 | } |
305 | 305 | ||
306 | void view_close_popups(struct sway_view *view) { | ||
307 | if (view->impl->close_popups) { | ||
308 | view->impl->close_popups(view); | ||
309 | } | ||
310 | } | ||
311 | |||
306 | void view_damage_from(struct sway_view *view) { | 312 | void view_damage_from(struct sway_view *view) { |
307 | for (int i = 0; i < root_container.children->length; ++i) { | 313 | for (int i = 0; i < root_container.children->length; ++i) { |
308 | struct sway_container *cont = root_container.children->items[i]; | 314 | struct sway_container *cont = root_container.children->items[i]; |
@@ -333,6 +339,16 @@ void view_for_each_surface(struct sway_view *view, | |||
333 | } | 339 | } |
334 | } | 340 | } |
335 | 341 | ||
342 | void view_for_each_popup(struct sway_view *view, | ||
343 | wlr_surface_iterator_func_t iterator, void *user_data) { | ||
344 | if (!view->surface) { | ||
345 | return; | ||
346 | } | ||
347 | if (view->impl->for_each_popup) { | ||
348 | view->impl->for_each_popup(view, iterator, user_data); | ||
349 | } | ||
350 | } | ||
351 | |||
336 | static void view_subsurface_create(struct sway_view *view, | 352 | static void view_subsurface_create(struct sway_view *view, |
337 | struct wlr_subsurface *subsurface); | 353 | struct wlr_subsurface *subsurface); |
338 | 354 | ||
@@ -865,6 +881,8 @@ void view_update_title(struct sway_view *view, bool force) { | |||
865 | 881 | ||
866 | // Update title after the global font height is updated | 882 | // Update title after the global font height is updated |
867 | container_update_title_textures(view->swayc); | 883 | container_update_title_textures(view->swayc); |
884 | |||
885 | ipc_event_window(view->swayc, "title"); | ||
868 | } | 886 | } |
869 | 887 | ||
870 | static bool find_by_mark_iterator(struct sway_container *con, | 888 | static bool find_by_mark_iterator(struct sway_container *con, |
@@ -887,6 +905,7 @@ bool view_find_and_unmark(char *mark) { | |||
887 | free(view_mark); | 905 | free(view_mark); |
888 | list_del(view->marks, i); | 906 | list_del(view->marks, i); |
889 | view_update_marks_textures(view); | 907 | view_update_marks_textures(view); |
908 | ipc_event_window(container, "mark"); | ||
890 | return true; | 909 | return true; |
891 | } | 910 | } |
892 | } | 911 | } |
@@ -894,11 +913,10 @@ bool view_find_and_unmark(char *mark) { | |||
894 | } | 913 | } |
895 | 914 | ||
896 | void view_clear_marks(struct sway_view *view) { | 915 | void view_clear_marks(struct sway_view *view) { |
897 | for (int i = 0; i < view->marks->length; ++i) { | 916 | while (view->marks->length) { |
898 | free(view->marks->items[i]); | 917 | list_del(view->marks, 0); |
918 | ipc_event_window(view->swayc, "mark"); | ||
899 | } | 919 | } |
900 | list_free(view->marks); | ||
901 | view->marks = create_list(); | ||
902 | } | 920 | } |
903 | 921 | ||
904 | bool view_has_mark(struct sway_view *view, char *mark) { | 922 | bool view_has_mark(struct sway_view *view, char *mark) { |
@@ -911,6 +929,11 @@ bool view_has_mark(struct sway_view *view, char *mark) { | |||
911 | return false; | 929 | return false; |
912 | } | 930 | } |
913 | 931 | ||
932 | void view_add_mark(struct sway_view *view, char *mark) { | ||
933 | list_add(view->marks, strdup(mark)); | ||
934 | ipc_event_window(view->swayc, "mark"); | ||
935 | } | ||
936 | |||
914 | static void update_marks_texture(struct sway_view *view, | 937 | static void update_marks_texture(struct sway_view *view, |
915 | struct wlr_texture **texture, struct border_colors *class) { | 938 | struct wlr_texture **texture, struct border_colors *class) { |
916 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | 939 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); |
diff --git a/swaymsg/main.c b/swaymsg/main.c index c4141ca5..3767daf3 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c | |||
@@ -250,12 +250,16 @@ static void pretty_print(int type, json_object *resp) { | |||
250 | if (type != IPC_COMMAND && type != IPC_GET_WORKSPACES && | 250 | if (type != IPC_COMMAND && type != IPC_GET_WORKSPACES && |
251 | type != IPC_GET_INPUTS && type != IPC_GET_OUTPUTS && | 251 | type != IPC_GET_INPUTS && type != IPC_GET_OUTPUTS && |
252 | type != IPC_GET_VERSION && type != IPC_GET_SEATS && | 252 | type != IPC_GET_VERSION && type != IPC_GET_SEATS && |
253 | type != IPC_GET_CONFIG) { | 253 | type != IPC_GET_CONFIG && type != IPC_SEND_TICK) { |
254 | printf("%s\n", json_object_to_json_string_ext(resp, | 254 | printf("%s\n", json_object_to_json_string_ext(resp, |
255 | JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); | 255 | JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); |
256 | return; | 256 | return; |
257 | } | 257 | } |
258 | 258 | ||
259 | if (type == IPC_SEND_TICK) { | ||
260 | return; | ||
261 | } | ||
262 | |||
259 | if (type == IPC_GET_VERSION) { | 263 | if (type == IPC_GET_VERSION) { |
260 | pretty_print_version(resp); | 264 | pretty_print_version(resp); |
261 | return; | 265 | return; |
@@ -384,6 +388,8 @@ int main(int argc, char **argv) { | |||
384 | type = IPC_GET_BINDING_MODES; | 388 | type = IPC_GET_BINDING_MODES; |
385 | } else if (strcasecmp(cmdtype, "get_config") == 0) { | 389 | } else if (strcasecmp(cmdtype, "get_config") == 0) { |
386 | type = IPC_GET_CONFIG; | 390 | type = IPC_GET_CONFIG; |
391 | } else if (strcasecmp(cmdtype, "send_tick") == 0) { | ||
392 | type = IPC_SEND_TICK; | ||
387 | } else { | 393 | } else { |
388 | sway_abort("Unknown message type %s", cmdtype); | 394 | sway_abort("Unknown message type %s", cmdtype); |
389 | } | 395 | } |
diff --git a/swaymsg/swaymsg.1.scd b/swaymsg/swaymsg.1.scd index a6e279da..8cf1b222 100644 --- a/swaymsg/swaymsg.1.scd +++ b/swaymsg/swaymsg.1.scd | |||
@@ -64,3 +64,6 @@ _swaymsg_ [options...] [message] | |||
64 | 64 | ||
65 | *get\_config* | 65 | *get\_config* |
66 | Gets a JSON-encoded copy of the current configuration. | 66 | Gets a JSON-encoded copy of the current configuration. |
67 | |||
68 | *send\_tick* | ||
69 | Sends a tick event to all subscribed clients. | ||