swayfx/sway/commands/bar/mode.c
Rouven Czerwinski 605e515a93 fix double free for mode toggle if bar was invisible
If the bar was set to "invisible" and subsequently "toggle" was send twice, the
new mode was never set and the bar->mode was double freed.
Fix this by not requiring the bar->mode to be "hide" and instead show it
unconditionally, because it was either hidden or invisible.

Fixes #3637
2019-02-10 17:13:11 +01:00

71 lines
1.9 KiB
C

#define _POSIX_C_SOURCE 200809L
#include <string.h>
#include <strings.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/ipc-server.h"
#include "log.h"
static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode) {
char *old_mode = bar->mode;
if (strcasecmp("toggle", mode) == 0 && !config->reading) {
if (strcasecmp("dock", bar->mode) == 0) {
bar->mode = strdup("hide");
} else{
bar->mode = strdup("dock");
}
} else if (strcasecmp("dock", mode) == 0) {
bar->mode = strdup("dock");
} else if (strcasecmp("hide", mode) == 0) {
bar->mode = strdup("hide");
} else if (strcasecmp("invisible", mode) == 0) {
bar->mode = strdup("invisible");
} else {
return cmd_results_new(CMD_INVALID, "Invalid value %s", mode);
}
if (strcmp(old_mode, bar->mode) != 0) {
if (!config->reading) {
ipc_event_barconfig_update(bar);
}
sway_log(SWAY_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id);
}
// free old mode
free(old_mode);
return NULL;
}
struct cmd_results *bar_cmd_mode(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "mode", EXPECTED_AT_LEAST, 1))) {
return error;
}
if ((error = checkarg(argc, "mode", EXPECTED_AT_MOST, 2))) {
return error;
}
if (config->reading && argc > 1) {
return cmd_results_new(CMD_INVALID,
"Unexpected value %s in config mode", argv[1]);
}
const char *mode = argv[0];
if (config->reading) {
error = bar_set_mode(config->current_bar, mode);
} else {
const char *id = argc == 2 ? argv[1] : NULL;
for (int i = 0; i < config->bars->length; ++i) {
struct bar_config *bar = config->bars->items[i];
if (id) {
if (strcmp(id, bar->id) == 0) {
error = bar_set_mode(bar, mode);
break;
}
} else if ((error = bar_set_mode(bar, mode))) {
break;
}
}
}
return error ? error : cmd_results_new(CMD_SUCCESS, NULL);
}