aboutsummaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c137
-rw-r--r--sway/commands/bar.c57
-rw-r--r--sway/commands/bar/activate_button.c8
-rw-r--r--sway/commands/bar/binding_mode_indicator.c27
-rw-r--r--sway/commands/bar/bindsym.c11
-rw-r--r--sway/commands/bar/colors.c124
-rw-r--r--sway/commands/bar/context_button.c8
-rw-r--r--sway/commands/bar/font.c21
-rw-r--r--sway/commands/bar/height.c20
-rw-r--r--sway/commands/bar/hidden_state.c73
-rw-r--r--sway/commands/bar/icon_theme.c8
-rw-r--r--sway/commands/bar/id.c30
-rw-r--r--sway/commands/bar/mode.c74
-rw-r--r--sway/commands/bar/modifier.c35
-rw-r--r--sway/commands/bar/output.c49
-rw-r--r--sway/commands/bar/pango_markup.c28
-rw-r--r--sway/commands/bar/position.c26
-rw-r--r--sway/commands/bar/secondary_button.c8
-rw-r--r--sway/commands/bar/separator_symbol.c20
-rw-r--r--sway/commands/bar/status_command.c20
-rw-r--r--sway/commands/bar/strip_workspace_numbers.c29
-rw-r--r--sway/commands/bar/swaybar_command.c20
-rw-r--r--sway/commands/bar/tray_output.c8
-rw-r--r--sway/commands/bar/tray_padding.c9
-rw-r--r--sway/commands/bar/workspace_buttons.c28
-rw-r--r--sway/commands/bar/wrap_scroll.c27
-rw-r--r--sway/commands/mode.c59
-rw-r--r--sway/commands/reload.c3
-rw-r--r--sway/commands/swaybg_command.c20
-rw-r--r--sway/config.c6
-rw-r--r--sway/config/bar.c238
-rw-r--r--sway/config/output.c25
-rw-r--r--sway/desktop/layer_shell.c35
-rw-r--r--sway/desktop/output.c8
-rw-r--r--sway/input/seat.c25
-rw-r--r--sway/ipc-json.c134
-rw-r--r--sway/ipc-server.c138
-rw-r--r--sway/meson.build28
-rw-r--r--sway/server.c6
-rw-r--r--sway/sway.5.txt3
-rw-r--r--sway/tree/container.c2
41 files changed, 1505 insertions, 130 deletions
diff --git a/sway/commands.c b/sway/commands.c
index b52eb200..bcc777ed 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -91,68 +91,69 @@ void apply_seat_config(struct seat_config *seat) {
sway_input_manager_apply_seat_config(input_manager, seat);
}
-/**
- * Check and add color to buffer.
- *
- * return error object, or NULL if color is valid.
- */
-struct cmd_results *add_color(const char *name, char *buffer, const char *color) {
- int len = strlen(color);
- if (len != 7 && len != 9) {
- return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color);
- }
-
- if (color[0] != '#') {
- return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color);
- }
-
- int i;
- for (i = 1; i < len; ++i) {
- if (!isxdigit(color[i])) {
- return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color);
- }
- }
-
- // copy color to buffer
- strncpy(buffer, color, len);
- // add default alpha channel if color was defined without it
- if (len == 7) {
- buffer[7] = 'f';
- buffer[8] = 'f';
- }
- buffer[9] = '\0';
-
- return NULL;
-}
-
-/**
- * handlers that can run in either config or command context
- * Keep alphabetized
- */
+/* Keep alphabetized */
static struct cmd_handler handlers[] = {
+ { "bar", cmd_bar },
{ "bindcode", cmd_bindcode },
{ "bindsym", cmd_bindsym },
{ "exec", cmd_exec },
{ "exec_always", cmd_exec_always },
{ "include", cmd_include },
{ "input", cmd_input },
+ { "mode", cmd_mode },
{ "output", cmd_output },
{ "seat", cmd_seat },
{ "workspace", cmd_workspace },
};
-/**
- * Commands that can *only* run in the config loading context
- * Keep alphabetized
- */
+static struct cmd_handler bar_handlers[] = {
+ { "activate_button", bar_cmd_activate_button },
+ { "binding_mode_indicator", bar_cmd_binding_mode_indicator },
+ { "bindsym", bar_cmd_bindsym },
+ { "colors", bar_cmd_colors },
+ { "context_button", bar_cmd_context_button },
+ { "font", bar_cmd_font },
+ { "height", bar_cmd_height },
+ { "hidden_state", bar_cmd_hidden_state },
+ { "icon_theme", bar_cmd_icon_theme },
+ { "id", bar_cmd_id },
+ { "mode", bar_cmd_mode },
+ { "modifier", bar_cmd_modifier },
+ { "output", bar_cmd_output },
+ { "pango_markup", bar_cmd_pango_markup },
+ { "position", bar_cmd_position },
+ { "secondary_button", bar_cmd_secondary_button },
+ { "separator_symbol", bar_cmd_separator_symbol },
+ { "status_command", bar_cmd_status_command },
+ { "strip_workspace_numbers", bar_cmd_strip_workspace_numbers },
+ { "swaybar_command", bar_cmd_swaybar_command },
+ { "tray_output", bar_cmd_tray_output },
+ { "tray_padding", bar_cmd_tray_padding },
+ { "workspace_buttons", bar_cmd_workspace_buttons },
+ { "wrap_scroll", bar_cmd_wrap_scroll },
+};
+
+static struct cmd_handler bar_colors_handlers[] = {
+ { "active_workspace", bar_colors_cmd_active_workspace },
+ { "background", bar_colors_cmd_background },
+ { "binding_mode", bar_colors_cmd_binding_mode },
+ { "focused_background", bar_colors_cmd_focused_background },
+ { "focused_separator", bar_colors_cmd_focused_separator },
+ { "focused_statusline", bar_colors_cmd_focused_statusline },
+ { "focused_workspace", bar_colors_cmd_focused_workspace },
+ { "inactive_workspace", bar_colors_cmd_inactive_workspace },
+ { "separator", bar_colors_cmd_separator },
+ { "statusline", bar_colors_cmd_statusline },
+ { "urgent_workspace", bar_colors_cmd_urgent_workspace },
+};
+
+/* Config-time only commands. Keep alphabetized */
static struct cmd_handler config_handlers[] = {
{ "set", cmd_set },
+ { "swaybg_command", cmd_swaybg_command },
};
-/**
- * Commands that can *not* run in the config loading context
- * Keep alphabetized
- */
+/* Runtime-only commands. Keep alphabetized */
static struct cmd_handler command_handlers[] = {
{ "exit", cmd_exit },
{ "focus", cmd_focus },
@@ -200,13 +201,19 @@ static struct cmd_handler *find_handler(char *line, enum cmd_status block) {
bool config_loading = config->reading || !config->active;
- if (block == CMD_BLOCK_INPUT) {
- // input commands can run in either context
+ if (block == CMD_BLOCK_BAR) {
+ return bsearch(&d, bar_handlers,
+ sizeof(bar_handlers) / sizeof(struct cmd_handler),
+ sizeof(struct cmd_handler), handler_compare);
+ } else if (block == CMD_BLOCK_BAR_COLORS) {
+ return bsearch(&d, bar_colors_handlers,
+ sizeof(bar_colors_handlers) / sizeof(struct cmd_handler),
+ sizeof(struct cmd_handler), handler_compare);
+ } else if (block == CMD_BLOCK_INPUT) {
return bsearch(&d, input_handlers,
sizeof(input_handlers) / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
} else if (block == CMD_BLOCK_SEAT) {
- // seat commands can run in either context
return bsearch(&d, seat_handlers,
sizeof(seat_handlers) / sizeof(struct cmd_handler),
sizeof(struct cmd_handler), handler_compare);
@@ -558,3 +565,35 @@ const char *cmd_results_to_json(struct cmd_results *results) {
free(root);
return json;
}
+
+/**
+ * Check and add color to buffer.
+ *
+ * return error object, or NULL if color is valid.
+ */
+struct cmd_results *add_color(const char *name,
+ char *buffer, const char *color) {
+ int len = strlen(color);
+ if (len != 7 && len != 9) {
+ return cmd_results_new(CMD_INVALID, name,
+ "Invalid color definition %s", color);
+ }
+ if (color[0] != '#') {
+ return cmd_results_new(CMD_INVALID, name,
+ "Invalid color definition %s", color);
+ }
+ for (int i = 1; i < len; ++i) {
+ if (!isxdigit(color[i])) {
+ return cmd_results_new(CMD_INVALID, name,
+ "Invalid color definition %s", color);
+ }
+ }
+ strncpy(buffer, color, len);
+ // add default alpha channel if color was defined without it
+ if (len == 7) {
+ buffer[7] = 'f';
+ buffer[8] = 'f';
+ }
+ buffer[9] = '\0';
+ return NULL;
+}
diff --git a/sway/commands/bar.c b/sway/commands/bar.c
new file mode 100644
index 00000000..ff111163
--- /dev/null
+++ b/sway/commands/bar.c
@@ -0,0 +1,57 @@
+#include <string.h>
+#include <strings.h>
+#include <wlr/util/log.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "util.h"
+
+struct cmd_results *cmd_bar(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+
+ if (config->reading && strcmp("{", argv[0]) != 0) {
+ return cmd_results_new(CMD_INVALID, "bar",
+ "Expected '{' at start of bar config definition.");
+ }
+
+ if (!config->reading) {
+ if (argc > 1) {
+ if (strcasecmp("mode", argv[0]) == 0) {
+ return bar_cmd_mode(argc-1, argv + 1);
+ }
+
+ if (strcasecmp("hidden_state", argv[0]) == 0) {
+ return bar_cmd_hidden_state(argc-1, argv + 1);
+ }
+ }
+ return cmd_results_new(CMD_FAILURE, "bar", "Can only be used in config file.");
+ }
+
+ // Create new bar with default values
+ struct bar_config *bar = default_bar_config();
+ if (!bar) {
+ return cmd_results_new(CMD_FAILURE, "bar", "Unable to allocate bar state");
+ }
+
+ // set bar id
+ for (int i = 0; i < config->bars->length; ++i) {
+ if (bar == config->bars->items[i]) {
+ const int len = 5 + numlen(i); // "bar-" + i + \0
+ bar->id = malloc(len * sizeof(char));
+ if (bar->id) {
+ snprintf(bar->id, len, "bar-%d", i);
+ } else {
+ return cmd_results_new(CMD_FAILURE,
+ "bar", "Unable to allocate bar ID");
+ }
+ break;
+ }
+ }
+
+ // Set current bar
+ config->current_bar = bar;
+ wlr_log(L_DEBUG, "Configuring bar %s", bar->id);
+ return cmd_results_new(CMD_BLOCK_BAR, NULL, NULL);
+}
diff --git a/sway/commands/bar/activate_button.c b/sway/commands/bar/activate_button.c
new file mode 100644
index 00000000..7310e7ec
--- /dev/null
+++ b/sway/commands/bar/activate_button.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_activate_button(int argc, char **argv) {
+ // TODO TRAY
+ return cmd_results_new(CMD_INVALID, "activate_button", "TODO TRAY");
+}
diff --git a/sway/commands/bar/binding_mode_indicator.c b/sway/commands/bar/binding_mode_indicator.c
new file mode 100644
index 00000000..3ba5f33f
--- /dev/null
+++ b/sway/commands/bar/binding_mode_indicator.c
@@ -0,0 +1,27 @@
+#include <string.h>
+#include <strings.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_binding_mode_indicator(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc,
+ "binding_mode_indicator", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE,
+ "binding_mode_indicator", "No bar defined.");
+ }
+ if (strcasecmp("yes", argv[0]) == 0) {
+ config->current_bar->binding_mode_indicator = true;
+ wlr_log(L_DEBUG, "Enabling binding mode indicator on bar: %s",
+ config->current_bar->id);
+ } else if (strcasecmp("no", argv[0]) == 0) {
+ config->current_bar->binding_mode_indicator = false;
+ wlr_log(L_DEBUG, "Disabling binding mode indicator on bar: %s",
+ config->current_bar->id);
+ }
+ return cmd_results_new(CMD_INVALID, "binding_mode_indicator",
+ "Invalid value %s", argv[0]);
+}
diff --git a/sway/commands/bar/bindsym.c b/sway/commands/bar/bindsym.c
new file mode 100644
index 00000000..ac09a03f
--- /dev/null
+++ b/sway/commands/bar/bindsym.c
@@ -0,0 +1,11 @@
+#include <stdlib.h>
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "list.h"
+#include "log.h"
+#include "stringop.h"
+
+struct cmd_results *bar_cmd_bindsym(int argc, char **argv) {
+ return cmd_results_new(CMD_FAILURE, "bindsym", "TODO"); // TODO
+}
diff --git a/sway/commands/bar/colors.c b/sway/commands/bar/colors.c
new file mode 100644
index 00000000..17ba9b7c
--- /dev/null
+++ b/sway/commands/bar/colors.c
@@ -0,0 +1,124 @@
+#include <string.h>
+#include "sway/commands.h"
+
+static struct cmd_results *parse_single_color(char **color,
+ const char *cmd_name, int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ if (!*color && !(*color = malloc(10))) {
+ return NULL;
+ }
+ error = add_color(cmd_name, *color, argv[0]);
+ if (error) {
+ return error;
+ }
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
+
+static struct cmd_results *parse_three_colors(char ***colors,
+ const char *cmd_name, int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if (argc != 3) {
+ return cmd_results_new(CMD_INVALID,
+ cmd_name, "Requires exactly three color values");
+ }
+ for (size_t i = 0; i < 3; i++) {
+ if (!*colors[i] && !(*(colors[i]) = malloc(10))) {
+ return NULL;
+ }
+ error = add_color(cmd_name, *(colors[i]), argv[i]);
+ if (error) {
+ return error;
+ }
+ }
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
+
+struct cmd_results *bar_cmd_colors(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "colors", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ if (strcmp("{", argv[0]) != 0) {
+ return cmd_results_new(CMD_INVALID, "colors",
+ "Expected '{' at the start of colors config definition.");
+ }
+ return cmd_results_new(CMD_BLOCK_BAR_COLORS, NULL, NULL);
+}
+
+struct cmd_results *bar_colors_cmd_active_workspace(int argc, char **argv) {
+ char **colors[3] = {
+ &(config->current_bar->colors.active_workspace_border),
+ &(config->current_bar->colors.active_workspace_bg),
+ &(config->current_bar->colors.active_workspace_text)
+ };
+ return parse_three_colors(colors, "active_workspace", argc, argv);
+}
+
+struct cmd_results *bar_colors_cmd_background(int argc, char **argv) {
+ return parse_single_color(&(config->current_bar->colors.background),
+ "background", argc, argv);
+}
+
+struct cmd_results *bar_colors_cmd_focused_background(int argc, char **argv) {
+ return parse_single_color(&(config->current_bar->colors.focused_background),
+ "focused_background", argc, argv);
+}
+
+struct cmd_results *bar_colors_cmd_binding_mode(int argc, char **argv) {
+ char **colors[3] = {
+ &(config->current_bar->colors.binding_mode_border),
+ &(config->current_bar->colors.binding_mode_bg),
+ &(config->current_bar->colors.binding_mode_text)
+ };
+ return parse_three_colors(colors, "binding_mode", argc, argv);
+}
+
+struct cmd_results *bar_colors_cmd_focused_workspace(int argc, char **argv) {
+ char **colors[3] = {
+ &(config->current_bar->colors.focused_workspace_border),
+ &(config->current_bar->colors.focused_workspace_bg),
+ &(config->current_bar->colors.focused_workspace_text)
+ };
+ return parse_three_colors(colors, "focused_workspace", argc, argv);
+}
+
+struct cmd_results *bar_colors_cmd_inactive_workspace(int argc, char **argv) {
+ char **colors[3] = {
+ &(config->current_bar->colors.inactive_workspace_border),
+ &(config->current_bar->colors.inactive_workspace_bg),
+ &(config->current_bar->colors.inactive_workspace_text)
+ };
+ return parse_three_colors(colors, "inactive_workspace", argc, argv);
+}
+
+struct cmd_results *bar_colors_cmd_separator(int argc, char **argv) {
+ return parse_single_color(&(config->current_bar->colors.separator),
+ "separator", argc, argv);
+}
+
+struct cmd_results *bar_colors_cmd_focused_separator(int argc, char **argv) {
+ return parse_single_color(&(config->current_bar->colors.focused_separator),
+ "focused_separator", argc, argv);
+}
+
+struct cmd_results *bar_colors_cmd_statusline(int argc, char **argv) {
+ return parse_single_color(&(config->current_bar->colors.statusline),
+ "statusline", argc, argv);
+}
+
+struct cmd_results *bar_colors_cmd_focused_statusline(int argc, char **argv) {
+ return parse_single_color(&(config->current_bar->colors.focused_separator),
+ "focused_separator", argc, argv);
+}
+
+struct cmd_results *bar_colors_cmd_urgent_workspace(int argc, char **argv) {
+ char **colors[3] = {
+ &(config->current_bar->colors.urgent_workspace_border),
+ &(config->current_bar->colors.urgent_workspace_bg),
+ &(config->current_bar->colors.urgent_workspace_text)
+ };
+ return parse_three_colors(colors, "urgent_workspace", argc, argv);
+}
diff --git a/sway/commands/bar/context_button.c b/sway/commands/bar/context_button.c
new file mode 100644
index 00000000..3b76885a
--- /dev/null
+++ b/sway/commands/bar/context_button.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_context_button(int argc, char **argv) {
+ // TODO TRAY
+ return cmd_results_new(CMD_INVALID, "context_button", "TODO TRAY");
+}
diff --git a/sway/commands/bar/font.c b/sway/commands/bar/font.c
new file mode 100644
index 00000000..80b7a593
--- /dev/null
+++ b/sway/commands/bar/font.c
@@ -0,0 +1,21 @@
+#define _POSIX_C_SOURCE 200809L
+#include <string.h>
+#include "sway/commands.h"
+#include "log.h"
+#include "stringop.h"
+
+struct cmd_results *bar_cmd_font(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "font", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE, "font", "No bar defined.");
+ }
+ char *font = join_args(argv, argc);
+ free(config->current_bar->font);
+ config->current_bar->font = strdup(font);
+ wlr_log(L_DEBUG, "Settings font '%s' for bar: %s",
+ config->current_bar->font, config->current_bar->id);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/height.c b/sway/commands/bar/height.c
new file mode 100644
index 00000000..3160caed
--- /dev/null
+++ b/sway/commands/bar/height.c
@@ -0,0 +1,20 @@
+#include <stdlib.h>
+#include <string.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_height(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "height", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ int height = atoi(argv[0]);
+ if (height < 0) {
+ return cmd_results_new(CMD_INVALID, "height",
+ "Invalid height value: %s", argv[0]);
+ }
+ config->current_bar->height = height;
+ wlr_log(L_DEBUG, "Setting bar height to %d on bar: %s",
+ height, config->current_bar->id);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/hidden_state.c b/sway/commands/bar/hidden_state.c
new file mode 100644
index 00000000..6641f184
--- /dev/null
+++ b/sway/commands/bar/hidden_state.c
@@ -0,0 +1,73 @@
+#define _XOPEN_SOURCE 500
+#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_hidden_state(struct bar_config *bar,
+ const char *hidden_state) {
+ char *old_state = bar->hidden_state;
+ if (strcasecmp("toggle", hidden_state) == 0 && !config->reading) {
+ if (strcasecmp("hide", bar->hidden_state) == 0) {
+ bar->hidden_state = strdup("show");
+ } else if (strcasecmp("show", bar->hidden_state) == 0) {
+ bar->hidden_state = strdup("hide");
+ }
+ } else if (strcasecmp("hide", hidden_state) == 0) {
+ bar->hidden_state = strdup("hide");
+ } else if (strcasecmp("show", hidden_state) == 0) {
+ bar->hidden_state = strdup("show");
+ } else {
+ return cmd_results_new(CMD_INVALID, "hidden_state",
+ "Invalid value %s", hidden_state);
+ }
+ if (strcmp(old_state, bar->hidden_state) != 0) {
+ if (!config->reading) {
+ ipc_event_barconfig_update(bar);
+ }
+ wlr_log(L_DEBUG, "Setting hidden_state: '%s' for bar: %s",
+ bar->hidden_state, bar->id);
+ }
+ // free old mode
+ free(old_state);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
+
+struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "hidden_state", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+ if ((error = checkarg(argc, "hidden_state", EXPECTED_LESS_THAN, 3))) {
+ return error;
+ }
+ if (config->reading && argc > 1) {
+ return cmd_results_new(CMD_INVALID, "hidden_state",
+ "Unexpected value %s in config mode", argv[1]);
+ }
+
+ const char *state = argv[0];
+ if (config->reading) {
+ return bar_set_hidden_state(config->current_bar, state);
+ }
+
+ const char *id = NULL;
+ if (argc == 2) {
+ id = argv[1];
+ }
+ struct bar_config *bar;
+ for (int i = 0; i < config->bars->length; ++i) {
+ bar = config->bars->items[i];
+ if (id && strcmp(id, bar->id) == 0) {
+ return bar_set_hidden_state(bar, state);
+ }
+
+ error = bar_set_hidden_state(bar, state);
+ if (error) {
+ return error;
+ }
+ }
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/icon_theme.c b/sway/commands/bar/icon_theme.c
new file mode 100644
index 00000000..44cd3076
--- /dev/null
+++ b/sway/commands/bar/icon_theme.c
@@ -0,0 +1,8 @@
+#define _XOPEN_SOURCE 500
+#include <string.h>
+#include "sway/commands.h"
+
+struct cmd_results *bar_cmd_icon_theme(int argc, char **argv) {
+ // TODO TRAY
+ return cmd_results_new(CMD_INVALID, "icon_theme", "TODO TRAY");
+}
diff --git a/sway/commands/bar/id.c b/sway/commands/bar/id.c
new file mode 100644
index 00000000..c1e56f03
--- /dev/null
+++ b/sway/commands/bar/id.c
@@ -0,0 +1,30 @@
+#define _XOPEN_SOURCE 500
+#include <string.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_id(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "id", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+
+ const char *name = argv[0];
+ const char *oldname = config->current_bar->id;
+ // check if id is used by a previously defined bar
+ for (int i = 0; i < config->bars->length; ++i) {
+ struct bar_config *find = config->bars->items[i];
+ if (strcmp(name, find->id) == 0 && config->current_bar != find) {
+ return cmd_results_new(CMD_FAILURE, "id",
+ "Id '%s' already defined for another bar. Id unchanged (%s).",
+ name, oldname);
+ }
+ }
+
+ wlr_log(L_DEBUG, "Renaming bar: '%s' to '%s'", oldname, name);
+
+ // free old bar id
+ free(config->current_bar->id);
+ config->current_bar->id = strdup(name);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c
new file mode 100644
index 00000000..34bb0a4f
--- /dev/null
+++ b/sway/commands/bar/mode.c
@@ -0,0 +1,74 @@
+#define _XOPEN_SOURCE 500
+#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 if (strcasecmp("hide", bar->mode) == 0) {
+ 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, "mode", "Invalid value %s", mode);
+ }
+
+ if (strcmp(old_mode, bar->mode) != 0) {
+ if (!config->reading) {
+ ipc_event_barconfig_update(bar);
+ }
+ wlr_log(L_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id);
+ }
+
+ // free old mode
+ free(old_mode);
+ return cmd_results_new(CMD_SUCCESS, NULL, 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_LESS_THAN, 3))) {
+ return error;
+ }
+ if (config->reading && argc > 1) {
+ return cmd_results_new(CMD_INVALID,
+ "mode", "Unexpected value %s in config mode", argv[1]);
+ }
+
+ const char *mode = argv[0];
+ if (config->reading) {
+ return bar_set_mode(config->current_bar, mode);
+ }
+
+ const char *id = NULL;
+ if (argc == 2) {
+ id = argv[1];
+ }
+
+ struct bar_config *bar;
+ for (int i = 0; i < config->bars->length; ++i) {
+ bar = config->bars->items[i];
+ if (id && strcmp(id, bar->id) == 0) {
+ return bar_set_mode(bar, mode);
+ }
+ error = bar_set_mode(bar, mode);
+ if (error) {
+ return error;
+ }
+ }
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/modifier.c b/sway/commands/bar/modifier.c
new file mode 100644
index 00000000..7ba4b125
--- /dev/null
+++ b/sway/commands/bar/modifier.c
@@ -0,0 +1,35 @@
+#include <string.h>
+#include "sway/commands.h"
+#include "log.h"
+#include "stringop.h"
+#include "util.h"
+
+struct cmd_results *bar_cmd_modifier(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "modifier", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE, "modifier", "No bar defined.");
+ }
+
+ uint32_t mod = 0;
+ list_t *split = split_string(argv[0], "+");
+ for (int i = 0; i < split->length; ++i) {
+ uint32_t tmp_mod;
+ if ((tmp_mod = get_modifier_mask_by_name(split->items[i])) > 0) {
+ mod |= tmp_mod;
+ continue;
+ } else {
+ free_flat_list(split);
+ return cmd_results_new(CMD_INVALID, "modifier",
+ "Unknown modifier '%s'", split->items[i]);
+ }
+ }
+ free_flat_list(split);
+ config->current_bar->modifier = mod;
+ wlr_log(L_DEBUG,
+ "Show/Hide the bar when pressing '%s' in hide mode.", argv[0]);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/output.c b/sway/commands/bar/output.c
new file mode 100644
index 00000000..f7ca0aa4
--- /dev/null
+++ b/sway/commands/bar/output.c
@@ -0,0 +1,49 @@
+#define _XOPEN_SOURCE 500
+#include <stdbool.h>
+#include <string.h>
+#include "sway/commands.h"
+#include "list.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_output(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "output", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE, "output", "No bar defined.");
+ }
+
+ const char *output = argv[0];
+ list_t *outputs = config->current_bar->outputs;
+ if (!outputs) {
+ outputs = create_list();
+ config->current_bar->outputs = outputs;
+ }
+
+ bool add_output = true;
+ if (strcmp("*", output) == 0) {
+ // remove all previous defined outputs and replace with '*'
+ for (int i = 0; i < outputs->length; ++i) {
+ free(outputs->items[i]);
+ list_del(outputs, i);
+ }
+ } else {
+ // only add output if not already defined with either the same
+ // name or as '*'
+ for (int i = 0; i < outputs->length; ++i) {
+ const char *find = outputs->items[i];
+ if (strcmp("*", find) == 0 || strcmp(output, find) == 0) {
+ add_output = false;
+ break;
+ }
+ }
+ }
+
+ if (add_output) {
+ list_add(outputs, strdup(output));
+ wlr_log(L_DEBUG, "Adding bar: '%s' to output '%s'",
+ config->current_bar->id, output);
+ }
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/pango_markup.c b/sway/commands/bar/pango_markup.c
new file mode 100644
index 00000000..480af724
--- /dev/null
+++ b/sway/commands/bar/pango_markup.c
@@ -0,0 +1,28 @@
+#include <string.h>
+#include <strings.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_pango_markup(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "pango_markup", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE, "pango_markup", "No bar defined.");
+ }
+ if (strcasecmp("enabled", argv[0]) == 0) {
+ config->current_bar->pango_markup = true;
+ wlr_log(L_DEBUG, "Enabling pango markup for bar: %s",
+ config->current_bar->id);
+ } else if (strcasecmp("disabled", argv[0]) == 0) {
+ config->current_bar->pango_markup = false;
+ wlr_log(L_DEBUG, "Disabling pango markup for bar: %s",
+ config->current_bar->id);
+ } else {
+ error = cmd_results_new(CMD_INVALID, "pango_markup",
+ "Invalid value %s", argv[0]);
+ return error;
+ }
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/position.c b/sway/commands/bar/position.c
new file mode 100644
index 00000000..9c580483
--- /dev/null
+++ b/sway/commands/bar/position.c
@@ -0,0 +1,26 @@
+#define _POSIX_C_SOURCE 200809L
+#include <string.h>
+#include <strings.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_position(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "position", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE, "position", "No bar defined.");
+ }
+ char *valid[] = { "top", "bottom", "left", "right" };
+ for (size_t i = 0; i < sizeof(valid) / sizeof(valid[0]); ++i) {
+ if (strcasecmp(valid[i], argv[0]) == 0) {
+ wlr_log(L_DEBUG, "Setting bar position '%s' for bar: %s",
+ argv[0], config->current_bar->id);
+ config->current_bar->position = strdup(argv[0]);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ }
+ }
+ return cmd_results_new(CMD_INVALID,
+ "position", "Invalid value %s", argv[0]);
+}
diff --git a/sway/commands/bar/secondary_button.c b/sway/commands/bar/secondary_button.c
new file mode 100644
index 00000000..449124cb
--- /dev/null
+++ b/sway/commands/bar/secondary_button.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_secondary_button(int argc, char **argv) {
+ // TODO TRAY
+ return cmd_results_new(CMD_INVALID, "secondary_button", "TODO TRAY");
+}
diff --git a/sway/commands/bar/separator_symbol.c b/sway/commands/bar/separator_symbol.c
new file mode 100644
index 00000000..1e08df6d
--- /dev/null
+++ b/sway/commands/bar/separator_symbol.c
@@ -0,0 +1,20 @@
+#define _XOPEN_SOURCE 500
+#include <string.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_separator_symbol(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "separator_symbol", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE,
+ "separator_symbol", "No bar defined.");
+ }
+ free(config->current_bar->separator_symbol);
+ config->current_bar->separator_symbol = strdup(argv[0]);
+ wlr_log(L_DEBUG, "Settings separator_symbol '%s' for bar: %s",
+ config->current_bar->separator_symbol, config->current_bar->id);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/status_command.c b/sway/commands/bar/status_command.c
new file mode 100644
index 00000000..5e199cde
--- /dev/null
+++ b/sway/commands/bar/status_command.c
@@ -0,0 +1,20 @@
+#include <string.h>
+#include "sway/commands.h"
+#include "log.h"
+#include "stringop.h"
+
+struct cmd_results *bar_cmd_status_command(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "status_command", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE,
+ "status_command", "No bar defined.");
+ }
+ free(config->current_bar->status_command);
+ config->current_bar->status_command = join_args(argv, argc);
+ wlr_log(L_DEBUG, "Feeding bar with status command: %s",
+ config->current_bar->status_command);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/strip_workspace_numbers.c b/sway/commands/bar/strip_workspace_numbers.c
new file mode 100644
index 00000000..4f24a356
--- /dev/null
+++ b/sway/commands/bar/strip_workspace_numbers.c
@@ -0,0 +1,29 @@
+#include <string.h>
+#include <strings.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_strip_workspace_numbers(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc,
+ "strip_workspace_numbers", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE,
+ "strip_workspace_numbers", "No bar defined.");
+ }
+ if (strcasecmp("yes", argv[0]) == 0) {
+ config->current_bar->strip_workspace_numbers = true;
+ wlr_log(L_DEBUG, "Stripping workspace numbers on bar: %s",
+ config->current_bar->id);
+ } else if (strcasecmp("no", argv[0]) == 0) {
+ config->current_bar->strip_workspace_numbers = false;
+ wlr_log(L_DEBUG, "Enabling workspace numbers on bar: %s",
+ config->current_bar->id);
+ } else {
+ return cmd_results_new(CMD_INVALID,
+ "strip_workspace_numbers", "Invalid value %s", argv[0]);
+ }
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/swaybar_command.c b/sway/commands/bar/swaybar_command.c
new file mode 100644
index 00000000..520cdd11
--- /dev/null
+++ b/sway/commands/bar/swaybar_command.c
@@ -0,0 +1,20 @@
+#include <string.h>
+#include "sway/commands.h"
+#include "log.h"
+#include "stringop.h"
+
+struct cmd_results *bar_cmd_swaybar_command(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "swaybar_command", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE,
+ "swaybar_command", "No bar defined.");
+ }
+ free(config->current_bar->swaybar_command);
+ config->current_bar->swaybar_command = join_args(argv, argc);
+ wlr_log(L_DEBUG, "Using custom swaybar command: %s",
+ config->current_bar->swaybar_command);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/tray_output.c b/sway/commands/bar/tray_output.c
new file mode 100644
index 00000000..6ab16731
--- /dev/null
+++ b/sway/commands/bar/tray_output.c
@@ -0,0 +1,8 @@
+#define _XOPEN_SOURCE 500
+#include <string.h>
+#include "sway/commands.h"
+
+struct cmd_results *bar_cmd_tray_output(int argc, char **argv) {
+ // TODO TRAY
+ return cmd_results_new(CMD_INVALID, "tray_output", "TODO TRAY");
+}
diff --git a/sway/commands/bar/tray_padding.c b/sway/commands/bar/tray_padding.c
new file mode 100644
index 00000000..91c56f19
--- /dev/null
+++ b/sway/commands/bar/tray_padding.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+#include <strings.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_tray_padding(int argc, char **argv) {
+ // TODO TRAY
+ return cmd_results_new(CMD_INVALID, "tray_padding", "TODO TRAY");
+}
diff --git a/sway/commands/bar/workspace_buttons.c b/sway/commands/bar/workspace_buttons.c
new file mode 100644
index 00000000..6edc3a0d
--- /dev/null
+++ b/sway/commands/bar/workspace_buttons.c
@@ -0,0 +1,28 @@
+#include <string.h>
+#include <strings.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_workspace_buttons(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "workspace_buttons", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE,
+ "workspace_buttons", "No bar defined.");
+ }
+ if (strcasecmp("yes", argv[0]) == 0) {
+ config->current_bar->workspace_buttons = true;
+ wlr_log(L_DEBUG, "Enabling workspace buttons on bar: %s",
+ config->current_bar->id);
+ } else if (strcasecmp("no", argv[0]) == 0) {
+ config->current_bar->workspace_buttons = false;
+ wlr_log(L_DEBUG, "Disabling workspace buttons on bar: %s",
+ config->current_bar->id);
+ } else {
+ return cmd_results_new(CMD_INVALID, "workspace_buttons",
+ "Invalid value %s", argv[0]);
+ }
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/wrap_scroll.c b/sway/commands/bar/wrap_scroll.c
new file mode 100644
index 00000000..7386f82c
--- /dev/null
+++ b/sway/commands/bar/wrap_scroll.c
@@ -0,0 +1,27 @@
+#include <string.h>
+#include <strings.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_wrap_scroll(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "wrap_scroll", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE, "wrap_scroll", "No bar defined.");
+ }
+ if (strcasecmp("yes", argv[0]) == 0) {
+ config->current_bar->wrap_scroll = true;
+ wlr_log(L_DEBUG, "Enabling wrap scroll on bar: %s",
+ config->current_bar->id);
+ } else if (strcasecmp("no", argv[0]) == 0) {
+ config->current_bar->wrap_scroll = false;
+ wlr_log(L_DEBUG, "Disabling wrap scroll on bar: %s",
+ config->current_bar->id);
+ } else {
+ return cmd_results_new(CMD_INVALID,
+ "wrap_scroll", "Invalid value %s", argv[0]);
+ }
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/mode.c b/sway/commands/mode.c
new file mode 100644
index 00000000..c30a8bac
--- /dev/null
+++ b/sway/commands/mode.c
@@ -0,0 +1,59 @@
+#define _XOPEN_SOURCE 500
+#include <stdbool.h>
+#include <string.h>
+#include <strings.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/ipc-server.h"
+#include "list.h"
+#include "log.h"
+
+struct cmd_results *cmd_mode(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "mode", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+
+ const char *mode_name = argv[0];
+ bool new_mode = (argc == 2 && strcmp(argv[1], "{") == 0);
+ if (new_mode && !config->reading) {
+ return cmd_results_new(CMD_FAILURE,
+ "mode", "Can only be used in config file.");
+ }
+ struct sway_mode *mode = NULL;
+ // Find mode
+ for (int i = 0; i < config->modes->length; ++i) {
+ struct sway_mode *test = config->modes->items[i];
+ if (strcasecmp(test->name, mode_name) == 0) {
+ mode = test;
+ break;
+ }
+ }
+ // Create mode if it doesn't exist
+ if (!mode && new_mode) {
+ mode = calloc(1, sizeof(struct sway_mode));
+ if (!mode) {
+ return cmd_results_new(CMD_FAILURE,
+ "mode", "Unable to allocate mode");
+ }
+ mode->name = strdup(mode_name);
+ mode->keysym_bindings = create_list();
+ mode->keycode_bindings = create_list();
+ list_add(config->modes, mode);
+ }
+ if (!mode) {
+ error = cmd_results_new(CMD_INVALID,
+ "mode", "Unknown mode `%s'", mode_name);
+ return error;
+ }
+ if ((config->reading && new_mode) || (!config->reading && !new_mode)) {
+ wlr_log(L_DEBUG, "Switching to mode `%s'",mode->name);
+ }
+ // Set current mode
+ config->current_mode = mode;
+ if (!new_mode) {
+ // trigger IPC mode event
+ ipc_event_mode(config->current_mode->name);
+ }
+ return cmd_results_new(new_mode ? CMD_BLOCK_MODE : CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/reload.c b/sway/commands/reload.c
index 8cef789b..5bca6cde 100644
--- a/sway/commands/reload.c
+++ b/sway/commands/reload.c
@@ -11,8 +11,7 @@ struct cmd_results *cmd_reload(int argc, char **argv) {
return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config.");
}
- /* load_swaybars(); -- for when it's implemented */
-
+ load_swaybars();
arrange_windows(&root_container, -1, -1);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/swaybg_command.c b/sway/commands/swaybg_command.c
new file mode 100644
index 00000000..770d4821
--- /dev/null
+++ b/sway/commands/swaybg_command.c
@@ -0,0 +1,20 @@
+#include <string.h>
+#include "sway/commands.h"
+#include "log.h"
+#include "stringop.h"
+
+struct cmd_results *cmd_swaybg_command(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "swaybg_command", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+
+ if (config->swaybg_command) {
+ free(config->swaybg_command);
+ }
+ config->swaybg_command = join_args(argv, argc);
+ wlr_log(L_DEBUG, "Using custom swaybg command: %s",
+ config->swaybg_command);
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/config.c b/sway/config.c
index 0b29735a..347d9e73 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -403,12 +403,6 @@ bool load_main_config(const char *file, bool is_active) {
free_config(old_config);
}
config->reading = false;
-
- if (success) {
- // TODO: bar
- //update_active_bar_modifiers();
- }
-
return success;
}
diff --git a/sway/config/bar.c b/sway/config/bar.c
new file mode 100644
index 00000000..48b2fc7c
--- /dev/null
+++ b/sway/config/bar.c
@@ -0,0 +1,238 @@
+#define _POSIX_C_SOURCE 200809L
+#define _XOPEN_SOURCE 700
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <wordexp.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <strings.h>
+#include "sway/config.h"
+#include "stringop.h"
+#include "list.h"
+#include "log.h"
+
+static void terminate_swaybar(pid_t pid) {
+ int ret = kill(pid, SIGTERM);
+ if (ret != 0) {
+ wlr_log_errno(L_ERROR, "Unable to terminate swaybar %d", pid);
+ } else {
+ int status;
+ waitpid(pid, &status, 0);
+ }
+}
+
+void free_bar_config(struct bar_config *bar) {
+ if (!bar) {
+ return;
+ }
+ free(bar->mode);
+ free(bar->position);
+ free(bar->hidden_state);
+ free(bar->status_command);
+ free(bar->font);
+ free(bar->separator_symbol);
+ // TODO: Free mouse bindings
+ list_free(bar->bindings);
+ if (bar->outputs) {
+ free_flat_list(bar->outputs);
+ }
+ if (bar->pid != 0) {
+ terminate_swaybar(bar->pid);
+ }
+ free(bar->colors.background);
+ free(bar->colors.statusline);
+ free(bar->colors.separator);
+ free(bar->colors.focused_background);
+ free(bar->colors.focused_statusline);
+ free(bar->colors.focused_separator);
+ free(bar->colors.focused_workspace_border);
+ free(bar->colors.focused_workspace_bg);
+ free(bar->colors.focused_workspace_text);
+ free(bar->colors.active_workspace_border);
+ free(bar->colors.active_workspace_bg);
+ free(bar->colors.active_workspace_text);
+ free(bar->colors.inactive_workspace_border);
+ free(bar->colors.inactive_workspace_bg);
+ free(bar->colors.inactive_workspace_text);
+ free(bar->colors.urgent_workspace_border);
+ free(bar->colors.urgent_workspace_bg);
+ free(bar->colors.urgent_workspace_text);
+ free(bar->colors.binding_mode_border);
+ free(bar->colors.binding_mode_bg);
+ free(bar->colors.binding_mode_text);
+ free(bar);
+}
+
+struct bar_config *default_bar_config(void) {
+ struct bar_config *bar = NULL;
+ bar = malloc(sizeof(struct bar_config));
+ if (!bar) {
+ return NULL;
+ }
+ if (!(bar->mode = strdup("dock"))) goto cleanup;
+ if (!(bar->hidden_state = strdup("hide"))) goto cleanup;
+ bar->outputs = NULL;
+ bar->position = strdup("bottom");
+ if (!(bar->bindings = create_list())) goto cleanup;
+ if (!(bar->status_command = strdup("while :; do date +'%Y-%m-%d %l:%M:%S %p'; sleep 1; done"))) goto cleanup;
+ bar->pango_markup = false;
+ bar->swaybar_command = NULL;
+ bar->font = NULL;
+ bar->height = -1;
+ bar->workspace_buttons = true;
+ bar->wrap_scroll = false;
+ bar->separator_symbol = NULL;
+ bar->strip_workspace_numbers = false;
+ bar->binding_mode_indicator = true;
+ bar->verbose = false;
+ bar->pid = 0;
+ // set default colors
+ if (!(bar->colors.background = strndup("#000000ff", 9))) {
+ goto cleanup;
+ }
+ if (!(bar->colors.statusline = strndup("#ffffffff", 9))) {
+ goto cleanup;
+ }
+ if (!(bar->colors.separator = strndup("#666666ff", 9))) {
+ goto cleanup;
+ }
+ if (!(bar->colors.focused_workspace_border = strndup("#4c7899ff", 9))) {
+ goto cleanup;
+ }
+ if (!(bar->colors.focused_workspace_bg = strndup("#285577ff", 9))) {
+ goto cleanup;
+ }
+ if (!(bar->colors.focused_workspace_text = strndup("#ffffffff", 9))) {
+ goto cleanup;
+ }
+ if (!(bar->colors.active_workspace_border = strndup("#333333ff", 9))) {
+ goto cleanup;
+ }
+ if (!(bar->colors.active_workspace_bg = strndup("#5f676aff", 9))) {
+ goto cleanup;
+ }
+ if (!(bar->colors.active_workspace_text = strndup("#ffffffff", 9))) {
+ goto cleanup;
+ }
+ if (!(bar->colors.inactive_workspace_border = strndup("#333333ff", 9))) {
+ goto cleanup;
+ }
+ if (!(bar->colors.inactive_workspace_bg = strndup("#222222ff", 9))) {
+ goto cleanup;
+ }
+ if (!(bar->colors.inactive_workspace_text = strndup("#888888ff", 9))) {
+ goto cleanup;
+ }
+ if (!(bar->colors.urgent_workspace_border = strndup("#2f343aff", 9))) {
+ goto cleanup;
+ }
+ if (!(bar->colors.urgent_workspace_bg = strndup("#900000ff", 9))) {
+ goto cleanup;
+ }
+ if (!(bar->colors.urgent_workspace_text = strndup("#ffffffff", 9))) {
+ goto cleanup;
+ }
+ // if the following colors stay undefined, they fall back to background,
+ // statusline, separator and urgent_workspace_*.
+ bar->colors.focused_background = NULL;
+ bar->colors.focused_statusline = NULL;
+ bar->colors.focused_separator = NULL;
+ bar->colors.binding_mode_border = NULL;
+ bar->colors.binding_mode_bg = NULL;
+ bar->colors.binding_mode_text = NULL;
+
+ list_add(config->bars, bar);
+ return bar;
+cleanup:
+ free_bar_config(bar);
+ return NULL;
+}
+
+void invoke_swaybar(struct bar_config *bar) {
+ // Pipe to communicate errors
+ int filedes[2];
+ if (pipe(filedes) == -1) {
+ wlr_log(L_ERROR, "Pipe setup failed! Cannot fork into bar");
+ return;
+ }
+
+ bar->pid = fork();
+ if (bar->pid == 0) {
+ close(filedes[0]);
+
+ // run custom swaybar
+ size_t len = snprintf(NULL, 0, "%s -b %s",
+ bar->swaybar_command ? bar->swaybar_command : "swaybar",
+ bar->id);
+ char *command = malloc(len + 1);
+ if (!command) {
+ const char msg[] = "Unable to allocate swaybar command string";
+ size_t len = sizeof(msg);
+ if (write(filedes[1], &len, sizeof(int))) {};
+ if (write(filedes[1], msg, len)) {};
+ close(filedes[1]);
+ exit(1);
+ }
+ snprintf(command, len + 1, "%s -b %s",
+ bar->swaybar_command ? bar->swaybar_command : "swaybar",
+ bar->id);
+ char *const cmd[] = { "sh", "-c", command, NULL, };
+ close(filedes[1]);
+ execvp(cmd[0], cmd);
+ exit(1);
+ }
+ close(filedes[0]);
+ ssize_t len;
+ if (read(filedes[1], &len, sizeof(int)) == sizeof(int)) {
+ char *buf = malloc(len);
+ if(!buf) {
+ wlr_log(L_ERROR, "Cannot allocate error string");
+ return;
+ }
+ if (read(filedes[1], buf, len)) {
+ wlr_log(L_ERROR, "%s", buf);
+ }
+ free(buf);
+ }
+ close(filedes[1]);
+}
+
+static bool active_output(const char *name) {
+ struct sway_container *cont = NULL;
+ for (int i = 0; i < root_container.children->length; ++i) {
+ cont = root_container.children->items[i];
+ if (cont->type == C_OUTPUT && strcasecmp(name, cont->name) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void load_swaybars() {
+ for (int i = 0; i < config->bars->length; ++i) {
+ struct bar_config *bar = config->bars->items[i];
+ bool apply = false;
+ if (bar->outputs) {
+ for (int j = 0; j < bar->outputs->length; ++j) {
+ char *o = bar->outputs->items[j];
+ if (!strcmp(o, "*") || active_output(o)) {
+ apply = true;
+ break;
+ }
+ }
+ } else {
+ apply = true;
+ }
+ if (apply) {
+ if (bar->pid != 0) {
+ terminate_swaybar(bar->pid);
+ }
+ wlr_log(L_DEBUG, "Invoking swaybar for bar id '%s'", bar->id);
+ invoke_swaybar(bar);
+ }
+ }
+}
diff --git a/sway/config/output.c b/sway/config/output.c
index 7fc79739..b4e56efa 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -180,19 +180,20 @@ void apply_output_config(struct output_config *oc, struct sway_container *output
wlr_log(L_DEBUG, "Setting background for output %d to %s",
output_i, oc->background);
- size_t bufsize = 12;
- char output_id[bufsize];
- snprintf(output_id, bufsize, "%d", output_i);
- output_id[bufsize-1] = 0;
-
- char *const cmd[] = {
- "./swaybg/swaybg",
- output_id,
- oc->background,
- oc->background_option,
- NULL,
- };
+ size_t len = snprintf(NULL, 0, "%s %d %s %s",
+ config->swaybg_command ? config->swaybg_command : "swaybg",
+ output_i, oc->background, oc->background_option);
+ char *command = malloc(len + 1);
+ if (!command) {
+ wlr_log(L_DEBUG, "Unable to allocate swaybg command");
+ return;
+ }
+ snprintf(command, len + 1, "%s %d %s %s",
+ config->swaybg_command ? config->swaybg_command : "swaybg",
+ output_i, oc->background, oc->background_option);
+ wlr_log(L_DEBUG, "-> %s", command);
+ char *const cmd[] = { "sh", "-c", command, NULL };
output->sway_output->bg_pid = fork();
if (output->sway_output->bg_pid == 0) {
execvp(cmd[0], cmd);
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index 137b3260..f7e5d19c 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -156,7 +156,6 @@ void arrange_layers(struct sway_output *output) {
struct wlr_box usable_area = { 0 };
wlr_output_effective_resolution(output->wlr_output,
&usable_area.width, &usable_area.height);
- struct wlr_box usable_area_before = output->usable_area;
// Arrange exclusive surfaces from top->bottom
arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
@@ -167,11 +166,11 @@ void arrange_layers(struct sway_output *output) {
&usable_area, true);
arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
&usable_area, true);
- memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box));
- if (memcmp(&usable_area_before,
- &usable_area, sizeof(struct wlr_box)) != 0) {
- wlr_log(L_DEBUG, "arrange");
+ if (memcmp(&usable_area, &output->usable_area,
+ sizeof(struct wlr_box)) != 0) {
+ wlr_log(L_DEBUG, "Usable area changed, rearranging output");
+ memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box));
arrange_windows(output->swayc, -1, -1);
}
@@ -193,22 +192,10 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) {
struct sway_layer_surface *sway_layer =
wl_container_of(listener, sway_layer, output_destroy);
wl_list_remove(&sway_layer->output_destroy.link);
- wl_list_remove(&sway_layer->output_mode.link);
- wl_list_remove(&sway_layer->output_transform.link);
sway_layer->layer_surface->output = NULL;
wlr_layer_surface_close(sway_layer->layer_surface);
}
-static void handle_output_mode(struct wl_listener *listener, void *data) {
- struct wlr_output *output = data;
- arrange_layers((struct sway_output *)output->data);
-}
-
-static void handle_output_transform(struct wl_listener *listener, void *data) {
- struct wlr_output *output = data;
- arrange_layers((struct sway_output *)output->data);
-}
-
static void handle_surface_commit(struct wl_listener *listener, void *data) {
struct sway_layer_surface *layer =
wl_container_of(listener, layer, surface_commit);
@@ -233,6 +220,8 @@ static void unmap(struct wlr_layer_surface *layer_surface) {
static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_layer_surface *sway_layer = wl_container_of(
listener, sway_layer, destroy);
+ wlr_log(L_DEBUG, "Layer surface destroyed (%s)",
+ sway_layer->layer_surface->namespace);
if (sway_layer->layer_surface->mapped) {
unmap(sway_layer->layer_surface);
}
@@ -243,12 +232,10 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&sway_layer->surface_commit.link);
if (sway_layer->layer_surface->output != NULL) {
wl_list_remove(&sway_layer->output_destroy.link);
- wl_list_remove(&sway_layer->output_mode.link);
- wl_list_remove(&sway_layer->output_transform.link);
}
struct sway_output *output = sway_layer->layer_surface->output->data;
- arrange_layers(output);
free(sway_layer);
+ arrange_layers(output);
}
static void handle_map(struct wl_listener *listener, void *data) {
@@ -289,14 +276,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
wl_signal_add(&layer_surface->output->events.destroy,
&sway_layer->output_destroy);
- sway_layer->output_mode.notify = handle_output_mode;
- wl_signal_add(&layer_surface->output->events.mode,
- &sway_layer->output_mode);
-
- sway_layer->output_transform.notify = handle_output_transform;
- wl_signal_add(&layer_surface->output->events.transform,
- &sway_layer->output_transform);
-
sway_layer->destroy.notify = handle_destroy;
wl_signal_add(&layer_surface->events.destroy, &sway_layer->destroy);
sway_layer->map.notify = handle_map;
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 1273df59..a9c59684 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -268,6 +268,12 @@ static void handle_output_mode(struct wl_listener *listener, void *data) {
arrange_windows(output->swayc, -1, -1);
}
+static void handle_output_transform(struct wl_listener *listener, void *data) {
+ struct sway_output *output = wl_container_of(listener, output, transform);
+ arrange_layers(output);
+ arrange_windows(output->swayc, -1, -1);
+}
+
void handle_new_output(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server, new_output);
struct wlr_output *wlr_output = data;
@@ -306,6 +312,8 @@ void handle_new_output(struct wl_listener *listener, void *data) {
output->destroy.notify = handle_output_destroy;
wl_signal_add(&wlr_output->events.mode, &output->mode);
output->mode.notify = handle_output_mode;
+ wl_signal_add(&wlr_output->events.transform, &output->transform);
+ output->transform.notify = handle_output_transform;
arrange_layers(output);
arrange_windows(&root_container, -1, -1);
diff --git a/sway/input/seat.c b/sway/input/seat.c
index aa0b1d50..7cf0dd08 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -6,6 +6,7 @@
#include "sway/input/cursor.h"
#include "sway/input/input-manager.h"
#include "sway/input/keyboard.h"
+#include "sway/ipc-server.h"
#include "sway/output.h"
#include "sway/tree/view.h"
#include "log.h"
@@ -309,18 +310,30 @@ void sway_seat_set_focus(struct sway_seat *seat, struct sway_container *containe
if (container->type == C_VIEW) {
struct sway_view *view = container->sway_view;
view_set_activated(view, true);
- struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
+ struct wlr_keyboard *keyboard =
+ wlr_seat_get_keyboard(seat->wlr_seat);
if (keyboard) {
- wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface,
- keyboard->keycodes, keyboard->num_keycodes,
- &keyboard->modifiers);
+ wlr_seat_keyboard_notify_enter(seat->wlr_seat,
+ view->surface, keyboard->keycodes,
+ keyboard->num_keycodes, &keyboard->modifiers);
} else {
- wlr_seat_keyboard_notify_enter(seat->wlr_seat, view->surface,
- NULL, 0, NULL);
+ wlr_seat_keyboard_notify_enter(
+ seat->wlr_seat, view->surface, NULL, 0, NULL);
}
}
}
+ if (last_focus) {
+ struct sway_container *last_ws = last_focus;
+ if (last_ws && last_ws->type != C_WORKSPACE) {
+ last_ws = container_parent(last_focus, C_WORKSPACE);
+ }
+ if (last_ws) {
+ wlr_log(L_DEBUG, "sending workspace event");
+ ipc_event_workspace(last_ws, container, "focus");
+ }
+ }
+
if (last_focus && last_focus->type == C_VIEW &&
!sway_input_manager_has_focus(seat->input, last_focus)) {
struct sway_view *view = last_focus->sway_view;
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index 7caa2457..eab6399f 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -9,6 +9,7 @@
#include "sway/input/seat.h"
#include <wlr/types/wlr_box.h>
#include <wlr/types/wlr_output.h>
+#include "wlr-layer-shell-unstable-v1-protocol.h"
json_object *ipc_json_get_version() {
int major = 0, minor = 0, patch = 0;
@@ -198,3 +199,136 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) {
return object;
}
+
+json_object *ipc_json_describe_bar_config(struct bar_config *bar) {
+ if (!sway_assert(bar, "Bar must not be NULL")) {
+ return NULL;
+ }
+
+ json_object *json = json_object_new_object();
+ json_object_object_add(json, "id", json_object_new_string(bar->id));
+ json_object_object_add(json, "mode", json_object_new_string(bar->mode));
+ json_object_object_add(json, "hidden_state",
+ json_object_new_string(bar->hidden_state));
+ json_object_object_add(json, "position",
+ json_object_new_string(bar->position));
+ json_object_object_add(json, "status_command",
+ json_object_new_string(bar->status_command));
+ json_object_object_add(json, "font",
+ json_object_new_string((bar->font) ? bar->font : config->font));
+ if (bar->separator_symbol) {
+ json_object_object_add(json, "separator_symbol",
+ json_object_new_string(bar->separator_symbol));
+ }
+ json_object_object_add(json, "bar_height",
+ json_object_new_int(bar->height));
+ json_object_object_add(json, "wrap_scroll",
+ json_object_new_boolean(bar->wrap_scroll));
+ json_object_object_add(json, "workspace_buttons",
+ json_object_new_boolean(bar->workspace_buttons));
+ json_object_object_add(json, "strip_workspace_numbers",
+ json_object_new_boolean(bar->strip_workspace_numbers));
+ json_object_object_add(json, "binding_mode_indicator",
+ json_object_new_boolean(bar->binding_mode_indicator));
+ json_object_object_add(json, "verbose",
+ json_object_new_boolean(bar->verbose));
+ json_object_object_add(json, "pango_markup",
+ json_object_new_boolean(bar->pango_markup));
+
+ json_object *colors = json_object_new_object();
+ json_object_object_add(colors, "background",
+ json_object_new_string(bar->colors.background));
+ json_object_object_add(colors, "statusline",
+ json_object_new_string(bar->colors.statusline));
+ json_object_object_add(colors, "separator",
+ json_object_new_string(bar->colors.separator));
+
+ if (bar->colors.focused_background) {
+ json_object_object_add(colors, "focused_background",
+ json_object_new_string(bar->colors.focused_background));
+ } else {
+ json_object_object_add(colors, "focused_background",
+ json_object_new_string(bar->colors.background));
+ }
+
+ if (bar->colors.focused_statusline) {
+ json_object_object_add(colors, "focused_statusline",
+ json_object_new_string(bar->colors.focused_statusline));
+ } else {
+ json_object_object_add(colors, "focused_statusline",
+ json_object_new_string(bar->colors.statusline));
+ }
+
+ if (bar->colors.focused_separator) {
+ json_object_object_add(colors, "focused_separator",
+ json_object_new_string(bar->colors.focused_separator));
+ } else {
+ json_object_object_add(colors, "focused_separator",
+ json_object_new_string(bar->colors.separator));
+ }
+
+ json_object_object_add(colors, "focused_workspace_border",
+ json_object_new_string(bar->colors.focused_workspace_border));
+ json_object_object_add(colors, "focused_workspace_bg",
+ json_object_new_string(bar->colors.focused_workspace_bg));
+ json_object_object_add(colors, "focused_workspace_text",
+ json_object_new_string(bar->colors.focused_workspace_text));
+
+ json_object_object_add(colors, "inactive_workspace_border",
+ json_object_new_string(bar->colors.inactive_workspace_border));
+ json_object_object_add(colors, "inactive_workspace_bg",
+ json_object_new_string(bar->colors.inactive_workspace_bg));
+ json_object_object_add(colors, "inactive_workspace_text",
+ json_object_new_string(bar->colors.inactive_workspace_text));
+
+ json_object_object_add(colors, "active_workspace_border",
+ json_object_new_string(bar->colors.active_workspace_border));
+ json_object_object_add(colors, "active_workspace_bg",
+ json_object_new_string(bar->colors.active_workspace_bg));
+ json_object_object_add(colors, "active_workspace_text",
+ json_object_new_string(bar->colors.active_workspace_text));
+
+ json_object_object_add(colors, "urgent_workspace_border",
+ json_object_new_string(bar->colors.urgent_workspace_border));
+ json_object_object_add(colors, "urgent_workspace_bg",
+ json_object_new_string(bar->colors.urgent_workspace_bg));
+ json_object_object_add(colors, "urgent_workspace_text",
+ json_object_new_string(bar->colors.urgent_workspace_text));
+
+ if (bar->colors.binding_mode_border) {
+ json_object_object_add(colors, "binding_mode_border",
+ json_object_new_string(bar->colors.binding_mode_border));
+ } else {
+ json_object_object_add(colors, "binding_mode_border",
+ json_object_new_string(bar->colors.urgent_workspace_border));
+ }
+
+ if (bar->colors.binding_mode_bg) {
+ json_object_object_add(colors, "binding_mode_bg",
+ json_object_new_string(bar->colors.binding_mode_bg));
+ } else {
+ json_object_object_add(colors, "binding_mode_bg",
+ json_object_new_string(bar->colors.urgent_workspace_bg));
+ }
+
+ if (bar->colors.binding_mode_text) {
+ json_object_object_add(colors, "binding_mode_text",
+ json_object_new_string(bar->colors.binding_mode_text));
+ } else {
+ json_object_object_add(colors, "binding_mode_text",
+ json_object_new_string(bar->colors.urgent_workspace_text));
+ }
+
+ json_object_object_add(json, "colors", colors);
+
+ // Add outputs if defined
+ if (bar->outputs && bar->outputs->length > 0) {
+ json_object *outputs = json_object_new_array();
+ for (int i = 0; i < bar->outputs->length; ++i) {
+ const char *name = bar->outputs->items[i];
+ json_object_array_add(outputs, json_object_new_string(name));
+ }
+ json_object_object_add(json, "outputs", outputs);
+ }
+ return json;
+}
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 50d0bcf3..394161af 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -21,6 +21,7 @@
#include "sway/ipc-server.h"
#include "sway/server.h"
#include "sway/input/input-manager.h"
+#include "sway/input/seat.h"
#include "list.h"
#include "log.h"
@@ -241,33 +242,10 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
}
static void ipc_send_event(const char *json_string, enum ipc_command_type event) {
- static struct {
- enum ipc_command_type event;
- enum ipc_feature feature;
- } security_mappings[] = {
- { IPC_EVENT_WORKSPACE, IPC_FEATURE_EVENT_WORKSPACE },
- { IPC_EVENT_OUTPUT, IPC_FEATURE_EVENT_OUTPUT },
- { IPC_EVENT_MODE, IPC_FEATURE_EVENT_MODE },
- { IPC_EVENT_WINDOW, IPC_FEATURE_EVENT_WINDOW },
- { IPC_EVENT_BINDING, IPC_FEATURE_EVENT_BINDING },
- { IPC_EVENT_INPUT, IPC_FEATURE_EVENT_INPUT }
- };
-
- uint32_t security_mask = 0;
- for (size_t i = 0; i < sizeof(security_mappings) / sizeof(security_mappings[0]); ++i) {
- if (security_mappings[i].event == event) {
- security_mask = security_mappings[i].feature;
- break;
- }
- }
-
int i;
struct ipc_client *client;
for (i = 0; i < ipc_client_list->length; i++) {
client = ipc_client_list->items[i];
- if (!(client->security_policy & security_mask)) {
- continue;
- }
if ((client->subscribed_events & event_mask(event)) == 0) {
continue;
}
@@ -279,6 +257,32 @@ static void ipc_send_event(const char *json_string, enum ipc_command_type event)
}
}
+void ipc_event_workspace(struct sway_container *old,
+ struct sway_container *new, const char *change) {
+ wlr_log(L_DEBUG, "Sending workspace::%s event", change);
+ json_object *obj = json_object_new_object();
+ json_object_object_add(obj, "change", json_object_new_string(change));
+ if (strcmp("focus", change) == 0) {
+ if (old) {
+ json_object_object_add(obj, "old",
+ ipc_json_describe_container_recursive(old));
+ } else {
+ json_object_object_add(obj, "old", NULL);
+ }
+ }
+
+ if (new) {
+ json_object_object_add(obj, "current",
+ ipc_json_describe_container_recursive(new));
+ } else {
+ json_object_object_add(obj, "current", NULL);
+ }
+
+ const char *json_string = json_object_to_json_string(obj);
+ ipc_send_event(json_string, IPC_EVENT_WORKSPACE);
+ json_object_put(obj);
+}
+
void ipc_event_window(struct sway_container *window, const char *change) {
wlr_log(L_DEBUG, "Sending window::%s event", change);
json_object *obj = json_object_new_object();
@@ -287,8 +291,26 @@ void ipc_event_window(struct sway_container *window, const char *change) {
const char *json_string = json_object_to_json_string(obj);
ipc_send_event(json_string, IPC_EVENT_WINDOW);
+ json_object_put(obj);
+}
- json_object_put(obj); // free
+void ipc_event_barconfig_update(struct bar_config *bar) {
+ wlr_log(L_DEBUG, "Sending barconfig_update event");
+ json_object *json = ipc_json_describe_bar_config(bar);
+
+ const char *json_string = json_object_to_json_string(json);
+ ipc_send_event(json_string, IPC_EVENT_BARCONFIG_UPDATE);
+ json_object_put(json);
+}
+
+void ipc_event_mode(const char *mode) {
+ wlr_log(L_DEBUG, "Sending mode::%s event", mode);
+ json_object *obj = json_object_new_object();
+ json_object_object_add(obj, "change", json_object_new_string(mode));
+
+ const char *json_string = json_object_to_json_string(obj);
+ ipc_send_event(json_string, IPC_EVENT_MODE);
+ json_object_put(obj);
}
int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
@@ -357,6 +379,27 @@ void ipc_client_disconnect(struct ipc_client *client) {
free(client);
}
+static void ipc_get_workspaces_callback(struct sway_container *workspace,
+ void *data) {
+ if (workspace->type != C_WORKSPACE) {
+ return;
+ }
+ json_object *workspace_json = ipc_json_describe_container(workspace);
+ // override the default focused indicator because
+ // it's set differently for the get_workspaces reply
+ struct sway_seat *seat =
+ sway_input_manager_get_default_seat(input_manager);
+ struct sway_container *focused_ws = sway_seat_get_focus(seat);
+ if (focused_ws->type != C_WORKSPACE) {
+ focused_ws = container_parent(focused_ws, C_WORKSPACE);
+ }
+ bool focused = workspace == focused_ws;
+ json_object_object_del(workspace_json, "focused");
+ json_object_object_add(workspace_json, "focused",
+ json_object_new_boolean(focused));
+ json_object_array_add((json_object *)data, workspace_json);
+}
+
void ipc_client_handle_command(struct ipc_client *client) {
if (!sway_assert(client != NULL, "client != NULL")) {
return;
@@ -412,6 +455,17 @@ void ipc_client_handle_command(struct ipc_client *client) {
goto exit_cleanup;
}
+ case IPC_GET_WORKSPACES:
+ {
+ json_object *workspaces = json_object_new_array();
+ container_for_each_descendant_dfs(&root_container,
+ ipc_get_workspaces_callback, workspaces);
+ const char *json_string = json_object_to_json_string(workspaces);
+ ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
+ json_object_put(workspaces); // free
+ goto exit_cleanup;
+ }
+
case IPC_SUBSCRIBE:
{
// TODO: Check if they're permitted to use these events
@@ -446,7 +500,6 @@ void ipc_client_handle_command(struct ipc_client *client) {
}
json_object_put(request);
-
ipc_send_reply(client, "{\"success\": true}", 17);
goto exit_cleanup;
}
@@ -483,6 +536,41 @@ void ipc_client_handle_command(struct ipc_client *client) {
goto exit_cleanup;
}
+ case IPC_GET_BAR_CONFIG:
+ {
+ if (!buf[0]) {
+ // Send list of configured bar IDs
+ json_object *bars = json_object_new_array();
+ for (int i = 0; i < config->bars->length; ++i) {
+ struct bar_config *bar = config->bars->items[i];
+ json_object_array_add(bars, json_object_new_string(bar->id));
+ }
+ const char *json_string = json_object_to_json_string(bars);
+ ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
+ json_object_put(bars); // free
+ } else {
+ // Send particular bar's details
+ struct bar_config *bar = NULL;
+ for (int i = 0; i < config->bars->length; ++i) {
+ bar = config->bars->items[i];
+ if (strcmp(buf, bar->id) == 0) {
+ break;
+ }
+ bar = NULL;
+ }
+ if (!bar) {
+ const char *error = "{ \"success\": false, \"error\": \"No bar with that ID\" }";
+ ipc_send_reply(client, error, (uint32_t)strlen(error));
+ goto exit_cleanup;
+ }
+ json_object *json = ipc_json_describe_bar_config(bar);
+ const char *json_string = json_object_to_json_string(json);
+ ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
+ json_object_put(json); // free
+ }
+ goto exit_cleanup;
+ }
+
default:
wlr_log(L_INFO, "Unknown IPC command type %i", client->current_command);
goto exit_cleanup;
diff --git a/sway/meson.build b/sway/meson.build
index 8bddb11b..1e7ee7ae 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -6,6 +6,7 @@ sway_sources = files(
'input/seat.c',
'input/cursor.c',
'input/keyboard.c',
+ 'commands/bar.c',
'commands/bind.c',
'commands/exit.c',
'commands/exec.c',
@@ -15,10 +16,36 @@ sway_sources = files(
'commands/include.c',
'commands/input.c',
'commands/layout.c',
+ 'commands/mode.c',
'commands/seat.c',
'commands/seat/attach.c',
'commands/seat/fallback.c',
'commands/set.c',
+ 'commands/swaybg_command.c',
+ 'commands/bar/activate_button.c',
+ 'commands/bar/binding_mode_indicator.c',
+ 'commands/bar/bindsym.c',
+ 'commands/bar/colors.c',
+ 'commands/bar/context_button.c',
+ 'commands/bar/font.c',
+ 'commands/bar/height.c',
+ 'commands/bar/hidden_state.c',
+ 'commands/bar/icon_theme.c',
+ 'commands/bar/id.c',
+ 'commands/bar/mode.c',
+ 'commands/bar/modifier.c',
+ 'commands/bar/output.c',
+ 'commands/bar/pango_markup.c',
+ 'commands/bar/position.c',
+ 'commands/bar/secondary_button.c',
+ 'commands/bar/separator_symbol.c',
+ 'commands/bar/status_command.c',
+ 'commands/bar/strip_workspace_numbers.c',
+ 'commands/bar/swaybar_command.c',
+ 'commands/bar/tray_output.c',
+ 'commands/bar/tray_padding.c',
+ 'commands/bar/workspace_buttons.c',
+ 'commands/bar/wrap_scroll.c',
'commands/input/accel_profile.c',
'commands/input/click_method.c',
'commands/input/drag_lock.c',
@@ -39,6 +66,7 @@ sway_sources = files(
'commands/reload.c',
'commands/workspace.c',
'config.c',
+ 'config/bar.c',
'config/output.c',
'config/seat.c',
'config/input.c',
diff --git a/sway/server.c b/sway/server.c
index 92f72f13..75202df2 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -8,6 +8,8 @@
#include <wlr/render/gles2.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_layer_shell.h>
+#include <wlr/types/wlr_screenshooter.h>
+#include <wlr/types/wlr_gamma_control.h>
#include <wlr/types/wlr_wl_shell.h>
// TODO WLR: make Xwayland optional
#include <wlr/xwayland.h>
@@ -45,10 +47,12 @@ bool server_init(struct sway_server *server) {
server->compositor = wlr_compositor_create(
server->wl_display, server->renderer);
-
server->data_device_manager =
wlr_data_device_manager_create(server->wl_display);
+ wlr_screenshooter_create(server->wl_display);
+ wlr_gamma_control_manager_create(server->wl_display);
+
server->new_output.notify = handle_new_output;
wl_signal_add(&server->backend->events.new_output, &server->new_output);
diff --git a/sway/sway.5.txt b/sway/sway.5.txt
index 6c9bce7a..900e499a 100644
--- a/sway/sway.5.txt
+++ b/sway/sway.5.txt
@@ -43,6 +43,9 @@ The following commands may only be used in the configuration file.
Sets variable $name to _value_. You can use the new variable in the arguments
of future commands.
+**swaybg_command** <command>::
+ Executes custom bg command, default is _swaybg_.
+
The following commands cannot be used directly in the configuration file.
They are expected to be used with **bindsym** or at runtime through **swaymsg**(1).
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 6a6861f3..2eac812e 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -131,8 +131,8 @@ struct sway_container *container_output_create(
}
apply_output_config(oc, output);
-
container_add_child(&root_container, output);
+ load_swaybars();
// Create workspace
char *ws_name = workspace_next_name(output->name);