aboutsummaryrefslogtreecommitdiffstats
path: root/sway
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-10-08 19:28:53 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-10-08 19:28:53 +1000
commit82423991a8512ab97fbc41d1e190e709c58bc346 (patch)
tree837e45f94240e02e2ab0f8f931227943e00819b3 /sway
parentMerge pull request #2786 from swaywm/no-op-client-commands (diff)
downloadsway-82423991a8512ab97fbc41d1e190e709c58bc346.tar.gz
sway-82423991a8512ab97fbc41d1e190e709c58bc346.tar.zst
sway-82423991a8512ab97fbc41d1e190e709c58bc346.zip
Reload config using idle event
This patch makes it so when you run reload, the actual reloading is deferred to the next time the event loop becomes idle. This avoids several use-after-frees and removes the workarounds we have to avoid them. When you run reload, we validate the config before creating the idle event. This is so the reload command will still return an error if there are validation errors. To allow this, load_main_config has been adjusted so it doesn't apply the config if validating is true rather than applying it unconditionally. This also fixes a memory leak in the reload command where if the config failed to load, the bar_ids list would not be freed.
Diffstat (limited to 'sway')
-rw-r--r--sway/commands/bind.c49
-rw-r--r--sway/commands/reload.c36
-rw-r--r--sway/config.c6
-rw-r--r--sway/input/keyboard.c4
4 files changed, 34 insertions, 61 deletions
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index 820c2a6a..701d9746 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -30,33 +30,6 @@ void free_sway_binding(struct sway_binding *binding) {
30 free(binding); 30 free(binding);
31} 31}
32 32
33static 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
60/** 33/**
61 * Returns true if the bindings have the same key and modifier combinations. 34 * Returns true if the bindings have the same key and modifier combinations.
62 * Note that keyboard layout is not considered, so the bindings might actually 35 * Note that keyboard layout is not considered, so the bindings might actually
@@ -214,9 +187,6 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
214 } 187 }
215 188
216 binding->command = join_args(argv + 1, argc - 1); 189 binding->command = join_args(argv + 1, argc - 1);
217 if (strcasestr(binding->command, "reload")) {
218 binding->flags |= BINDING_RELOAD;
219 }
220 190
221 list_t *split = split_string(argv[0], "+"); 191 list_t *split = split_string(argv[0], "+");
222 for (int i = 0; i < split->length; ++i) { 192 for (int i = 0; i < split->length; ++i) {
@@ -306,31 +276,16 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) {
306 * Execute the command associated to a binding 276 * Execute the command associated to a binding
307 */ 277 */
308void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { 278void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) {
309 wlr_log(WLR_DEBUG, "running command for binding: %s", 279 wlr_log(WLR_DEBUG, "running command for binding: %s", binding->command);
310 binding->command);
311
312 struct sway_binding *binding_copy = binding;
313 // if this is a reload command we need to make a duplicate of the
314 // binding since it will be gone after the reload has completed.
315 if (binding->flags & BINDING_RELOAD) {
316 binding_copy = sway_binding_dup(binding);
317 if (!binding_copy) {
318 wlr_log(WLR_ERROR, "Failed to duplicate binding during reload");
319 return;
320 }
321 }
322 280
323 config->handler_context.seat = seat; 281 config->handler_context.seat = seat;
324 struct cmd_results *results = execute_command(binding->command, NULL, NULL); 282 struct cmd_results *results = execute_command(binding->command, NULL, NULL);
325 if (results->status == CMD_SUCCESS) { 283 if (results->status == CMD_SUCCESS) {
326 ipc_event_binding(binding_copy); 284 ipc_event_binding(binding);
327 } else { 285 } else {
328 wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", 286 wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
329 binding->command, results->error); 287 binding->command, results->error);
330 } 288 }
331 289
332 if (binding_copy->flags & BINDING_RELOAD) {
333 free_sway_binding(binding_copy);
334 }
335 free_cmd_results(results); 290 free_cmd_results(results);
336} 291}
diff --git a/sway/commands/reload.c b/sway/commands/reload.c
index 36fb9092..9e136d48 100644
--- a/sway/commands/reload.c
+++ b/sway/commands/reload.c
@@ -3,15 +3,12 @@
3#include "sway/commands.h" 3#include "sway/commands.h"
4#include "sway/config.h" 4#include "sway/config.h"
5#include "sway/ipc-server.h" 5#include "sway/ipc-server.h"
6#include "sway/server.h"
6#include "sway/tree/arrange.h" 7#include "sway/tree/arrange.h"
7#include "list.h" 8#include "list.h"
9#include "log.h"
8 10
9struct cmd_results *cmd_reload(int argc, char **argv) { 11static void do_reload(void *data) {
10 struct cmd_results *error = NULL;
11 if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) {
12 return error;
13 }
14
15 // store bar ids to check against new bars for barconfig_update events 12 // store bar ids to check against new bars for barconfig_update events
16 list_t *bar_ids = create_list(); 13 list_t *bar_ids = create_list();
17 for (int i = 0; i < config->bars->length; ++i) { 14 for (int i = 0; i < config->bars->length; ++i) {
@@ -20,9 +17,12 @@ struct cmd_results *cmd_reload(int argc, char **argv) {
20 } 17 }
21 18
22 if (!load_main_config(config->current_config_path, true, false)) { 19 if (!load_main_config(config->current_config_path, true, false)) {
23 return cmd_results_new(CMD_FAILURE, "reload", 20 wlr_log(WLR_ERROR, "Error(s) reloading config");
24 "Error(s) reloading config."); 21 list_foreach(bar_ids, free);
22 list_free(bar_ids);
23 return;
25 } 24 }
25
26 ipc_event_workspace(NULL, NULL, "reload"); 26 ipc_event_workspace(NULL, NULL, "reload");
27 27
28 load_swaybars(); 28 load_swaybars();
@@ -37,12 +37,26 @@ struct cmd_results *cmd_reload(int argc, char **argv) {
37 } 37 }
38 } 38 }
39 39
40 for (int i = 0; i < bar_ids->length; ++i) { 40 list_foreach(bar_ids, free);
41 free(bar_ids->items[i]);
42 }
43 list_free(bar_ids); 41 list_free(bar_ids);
44 42
45 arrange_root(); 43 arrange_root();
44}
45
46struct cmd_results *cmd_reload(int argc, char **argv) {
47 struct cmd_results *error = NULL;
48 if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) {
49 return error;
50 }
51
52 if (!load_main_config(config->current_config_path, true, true)) {
53 return cmd_results_new(CMD_FAILURE, "reload",
54 "Error(s) reloading config.");
55 }
56
57 // The reload command frees a lot of stuff, so to avoid use-after-frees
58 // we schedule the reload to happen using an idle event.
59 wl_event_loop_add_idle(server.wl_event_loop, do_reload, NULL);
46 60
47 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 61 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
48} 62}
diff --git a/sway/config.c b/sway/config.c
index b56c4f71..8f8ed438 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -457,6 +457,12 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
457 success = success && load_config(path, config, 457 success = success && load_config(path, config,
458 &config->swaynag_config_errors); 458 &config->swaynag_config_errors);
459 459
460 if (validating) {
461 free_config(config);
462 config = old_config;
463 return success;
464 }
465
460 if (is_active) { 466 if (is_active) {
461 for (int i = 0; i < config->output_configs->length; i++) { 467 for (int i = 0; i < config->output_configs->length; i++) {
462 apply_output_config_to_outputs(config->output_configs->items[i]); 468 apply_output_config_to_outputs(config->output_configs->items[i]);
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index 5fc8a806..0e14c036 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -278,9 +278,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
278 raw_modifiers, false, input_inhibited); 278 raw_modifiers, false, input_inhibited);
279 279
280 if (binding_pressed) { 280 if (binding_pressed) {
281 if ((binding_pressed->flags & BINDING_RELOAD) == 0) { 281 next_repeat_binding = binding_pressed;
282 next_repeat_binding = binding_pressed;
283 }
284 seat_execute_command(seat, binding_pressed); 282 seat_execute_command(seat, binding_pressed);
285 handled = true; 283 handled = true;
286 } 284 }