aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sway/commands.h2
-rw-r--r--include/sway/config.h13
-rw-r--r--include/sway/tree/workspace.h2
-rw-r--r--include/swaybar/bar.h5
-rw-r--r--include/swaybar/i3bar.h34
-rw-r--r--include/swaybar/ipc.h2
-rw-r--r--include/swaybar/status_line.h26
-rw-r--r--include/swaylock/swaylock.h3
-rw-r--r--meson.build13
-rw-r--r--sway/commands.c13
-rw-r--r--sway/commands/bar/binding_mode_indicator.c6
-rw-r--r--sway/commands/output/background.c18
-rw-r--r--sway/commands/resize.c30
-rw-r--r--sway/commands/workspace.c38
-rw-r--r--sway/config.c11
-rw-r--r--sway/config/input.c3
-rw-r--r--sway/config/output.c4
-rw-r--r--sway/desktop/transaction.c55
-rw-r--r--sway/input/cursor.c2
-rw-r--r--sway/input/input-manager.c6
-rw-r--r--sway/ipc-server.c13
-rw-r--r--sway/sway-bar.5.scd3
-rw-r--r--sway/sway-input.5.scd4
-rw-r--r--sway/sway.5.scd58
-rw-r--r--sway/tree/container.c13
-rw-r--r--sway/tree/view.c10
-rw-r--r--sway/tree/workspace.c49
-rw-r--r--swaybar/bar.c14
-rw-r--r--swaybar/i3bar.c2
-rw-r--r--swaybar/ipc.c19
-rw-r--r--swaybar/main.c5
-rw-r--r--swaybar/render.c110
-rw-r--r--swaybar/status_line.c42
-rw-r--r--swaylock/main.c5
-rw-r--r--swaylock/meson.build50
-rw-r--r--swaylock/pam.c62
-rw-r--r--swaylock/password.c51
-rw-r--r--swaylock/shadow.c128
38 files changed, 568 insertions, 356 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 1654eb48..370a1f7a 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -95,7 +95,7 @@ struct cmd_results *add_color(const char *name,
/**
* TODO: Move this function and its dependent functions to container.c.
*/
-void container_resize_tiled(struct sway_container *parent, enum wlr_edges edge,
+bool container_resize_tiled(struct sway_container *parent, enum wlr_edges edge,
int amount);
sway_cmd cmd_assign;
diff --git a/include/sway/config.h b/include/sway/config.h
index 35f0e708..af5c7a18 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -167,13 +167,12 @@ struct output_config {
};
/**
- * Maps a workspace name to an output name.
- *
- * Set via `workspace <x> output <y>`
+ * Stores configuration for a workspace, regardless of whether the workspace
+ * exists.
*/
-struct workspace_output {
- char *output;
+struct workspace_config {
char *workspace;
+ char *output;
};
struct bar_config {
@@ -327,7 +326,7 @@ struct sway_config {
list_t *modes;
list_t *bars;
list_t *cmd_queue;
- list_t *workspace_outputs;
+ list_t *workspace_configs;
list_t *output_configs;
list_t *input_configs;
list_t *seat_configs;
@@ -518,6 +517,8 @@ struct bar_config *default_bar_config(void);
void free_bar_config(struct bar_config *bar);
+void free_workspace_config(struct workspace_config *wsc);
+
/**
* Updates the value of config->font_height based on the max title height
* reported by each container. If recalculate is true, the containers will
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h
index e4b616d1..c8220b39 100644
--- a/include/sway/tree/workspace.h
+++ b/include/sway/tree/workspace.h
@@ -48,6 +48,8 @@ struct sway_workspace {
extern char *prev_workspace_name;
+struct workspace_config *workspace_find_config(const char *ws_name);
+
struct sway_output *workspace_get_initial_output(const char *name);
struct sway_workspace *workspace_create(struct sway_output *output,
diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h
index 29e96159..20992014 100644
--- a/include/swaybar/bar.h
+++ b/include/swaybar/bar.h
@@ -54,7 +54,6 @@ struct swaybar {
struct wl_seat *seat;
struct swaybar_config *config;
- struct swaybar_output *focused_output;
struct swaybar_pointer pointer;
struct status_line *status;
@@ -95,9 +94,7 @@ struct swaybar_workspace {
bool urgent;
};
-void bar_setup(struct swaybar *bar,
- const char *socket_path,
- const char *bar_id);
+bool bar_setup(struct swaybar *bar, const char *socket_path, const char *bar_id);
void bar_run(struct swaybar *bar);
void bar_teardown(struct swaybar *bar);
diff --git a/include/swaybar/i3bar.h b/include/swaybar/i3bar.h
new file mode 100644
index 00000000..12d9b317
--- /dev/null
+++ b/include/swaybar/i3bar.h
@@ -0,0 +1,34 @@
+#ifndef _SWAYBAR_I3BAR_H
+#define _SWAYBAR_I3BAR_H
+
+#include "bar.h"
+#include "status_line.h"
+
+struct i3bar_block {
+ struct wl_list link;
+ int ref_count;
+ char *full_text, *short_text, *align;
+ bool urgent;
+ uint32_t *color;
+ int min_width;
+ char *name, *instance;
+ bool separator;
+ int separator_block_width;
+ bool markup;
+ // Airblader features
+ uint32_t background;
+ uint32_t border;
+ int border_top;
+ int border_bottom;
+ int border_left;
+ int border_right;
+};
+
+void i3bar_block_unref(struct i3bar_block *block);
+bool i3bar_handle_readable(struct status_line *status);
+enum hotspot_event_handling i3bar_block_send_click(struct status_line *status,
+ struct i3bar_block *block, int x, int y, enum x11_button button);
+enum x11_button wl_button_to_x11_button(uint32_t button);
+enum x11_button wl_axis_to_x11_button(uint32_t axis, wl_fixed_t value);
+
+#endif
diff --git a/include/swaybar/ipc.h b/include/swaybar/ipc.h
index a1696bcf..81e48a6b 100644
--- a/include/swaybar/ipc.h
+++ b/include/swaybar/ipc.h
@@ -3,7 +3,7 @@
#include <stdbool.h>
#include "swaybar/bar.h"
-void ipc_initialize(struct swaybar *bar, const char *bar_id);
+bool ipc_initialize(struct swaybar *bar, const char *bar_id);
bool handle_ipc_readable(struct swaybar *bar);
void ipc_get_workspaces(struct swaybar *bar);
void ipc_send_workspace_command(struct swaybar *bar, const char *ws);
diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h
index d3eabdf6..e6c7dac2 100644
--- a/include/swaybar/status_line.h
+++ b/include/swaybar/status_line.h
@@ -13,26 +13,6 @@ enum status_protocol {
PROTOCOL_I3BAR,
};
-struct i3bar_block {
- struct wl_list link;
- int ref_count;
- char *full_text, *short_text, *align;
- bool urgent;
- uint32_t *color;
- int min_width;
- char *name, *instance;
- bool separator;
- int separator_block_width;
- bool markup;
- // Airblader features
- uint32_t background;
- uint32_t border;
- int border_top;
- int border_bottom;
- int border_left;
- int border_right;
-};
-
struct status_line {
pid_t pid;
int read_fd, write_fd;
@@ -55,11 +35,5 @@ struct status_line *status_line_init(char *cmd);
void status_error(struct status_line *status, const char *text);
bool status_handle_readable(struct status_line *status);
void status_line_free(struct status_line *status);
-bool i3bar_handle_readable(struct status_line *status);
-enum hotspot_event_handling i3bar_block_send_click(struct status_line *status,
- struct i3bar_block *block, int x, int y, enum x11_button button);
-void i3bar_block_unref(struct i3bar_block *block);
-enum x11_button wl_button_to_x11_button(uint32_t button);
-enum x11_button wl_axis_to_x11_button(uint32_t axis, wl_fixed_t value);
#endif
diff --git a/include/swaylock/swaylock.h b/include/swaylock/swaylock.h
index 2f0cd34d..970e3cc9 100644
--- a/include/swaylock/swaylock.h
+++ b/include/swaylock/swaylock.h
@@ -101,5 +101,8 @@ void render_frame(struct swaylock_surface *surface);
void render_frames(struct swaylock_state *state);
void damage_surface(struct swaylock_surface *surface);
void damage_state(struct swaylock_state *state);
+void initialize_pw_backend(void);
+bool attempt_password(struct swaylock_password *pw);
+void clear_password_buffer(struct swaylock_password *pw);
#endif
diff --git a/meson.build b/meson.build
index 253a4e96..de6573ea 100644
--- a/meson.build
+++ b/meson.build
@@ -22,6 +22,10 @@ datadir = get_option('datadir')
sysconfdir = get_option('sysconfdir')
prefix = get_option('prefix')
+if is_freebsd
+ add_project_arguments('-D_C11_SOURCE', language: 'c')
+endif
+
swayidle_deps = []
jsonc = dependency('json-c', version: '>=0.13')
@@ -40,7 +44,7 @@ gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: false)
pixman = dependency('pixman-1')
libcap = dependency('libcap', required: false)
libinput = dependency('libinput', version: '>=1.6.0')
-libpam = cc.find_library('pam')
+libpam = cc.find_library('pam', required: false)
systemd = dependency('libsystemd', required: false)
elogind = dependency('libelogind', required: false)
math = cc.find_library('m')
@@ -70,6 +74,11 @@ if elogind.found()
swayidle_deps += elogind
endif
+if not systemd.found() and not elogind.found()
+ warning('The sway binary must be setuid when compiled without (e)logind')
+ warning('You must do this manually post-install: chmod a+s /path/to/sway')
+endif
+
scdoc = find_program('scdoc', required: false)
if scdoc.found()
@@ -133,9 +142,9 @@ subdir('swaymsg')
subdir('client')
subdir('swaybg')
subdir('swaybar')
-subdir('swaylock')
subdir('swayidle')
subdir('swaynag')
+subdir('swaylock')
config = configuration_data()
config.set('sysconfdir', join_paths(prefix, sysconfdir))
diff --git a/sway/commands.c b/sway/commands.c
index bff230f7..03761c52 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -391,14 +391,12 @@ struct cmd_results *config_command(char *exec) {
// Var replacement, for all but first argument of set
// TODO commands
for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
+ if (*argv[i] == '\"' || *argv[i] == '\'') {
+ strip_quotes(argv[i]);
+ }
argv[i] = do_var_replacement(argv[i]);
unescape_string(argv[i]);
}
- // Strip quotes for first argument.
- // TODO This part needs to be handled much better
- if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) {
- strip_quotes(argv[1]);
- }
if (handler->handle) {
results = handler->handle(argc-1, argv+1);
} else {
@@ -422,11 +420,6 @@ struct cmd_results *config_subcommand(char **argv, int argc,
char *input = argv[0] ? argv[0] : "(empty)";
return cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
}
- // Strip quotes for first argument.
- // TODO This part needs to be handled much better
- if (argc > 1 && (*argv[1] == '\"' || *argv[1] == '\'')) {
- strip_quotes(argv[1]);
- }
if (handler->handle) {
return handler->handle(argc - 1, argv + 1);
}
diff --git a/sway/commands/bar/binding_mode_indicator.c b/sway/commands/bar/binding_mode_indicator.c
index 0c48bee9..f18b8d7c 100644
--- a/sway/commands/bar/binding_mode_indicator.c
+++ b/sway/commands/bar/binding_mode_indicator.c
@@ -21,7 +21,9 @@ struct cmd_results *bar_cmd_binding_mode_indicator(int argc, char **argv) {
config->current_bar->binding_mode_indicator = false;
wlr_log(WLR_DEBUG, "Disabling binding mode indicator on bar: %s",
config->current_bar->id);
+ } else {
+ return cmd_results_new(CMD_INVALID, "binding_mode_indicator",
+ "Invalid value %s", argv[0]);
}
- return cmd_results_new(CMD_INVALID, "binding_mode_indicator",
- "Invalid value %s", argv[0]);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c
index 9e370d43..30fb47c4 100644
--- a/sway/commands/output/background.c
+++ b/sway/commands/output/background.c
@@ -123,19 +123,13 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
}
free(src);
} else {
- // Escape spaces and quotes in the final path for swaybg
+ // Escape double quotes in the final path for swaybg
for (size_t i = 0; i < strlen(src); i++) {
- switch (src[i]) {
- case ' ':
- case '\'':
- case '\"':
- src = realloc(src, strlen(src) + 2);
- memmove(src + i + 1, src + i, strlen(src + i) + 1);
- *(src + i) = '\\';
- i++;
- break;
- default:
- break;
+ if (src[i] == '"') {
+ src = realloc(src, strlen(src) + 2);
+ memmove(src + i + 1, src + i, strlen(src + i) + 1);
+ *(src + i) = '\\';
+ i++;
}
}
diff --git a/sway/commands/resize.c b/sway/commands/resize.c
index 99e9dbda..1343b165 100644
--- a/sway/commands/resize.c
+++ b/sway/commands/resize.c
@@ -179,11 +179,11 @@ static void container_recursive_resize(struct sway_container *container,
}
}
-static void resize_tiled(struct sway_container *parent, int amount,
+static bool resize_tiled(struct sway_container *parent, int amount,
enum resize_axis axis) {
struct sway_container *focused = parent;
if (!parent) {
- return;
+ return false;
}
enum sway_container_layout parallel_layout =
@@ -216,7 +216,7 @@ static void resize_tiled(struct sway_container *parent, int amount,
}
if (!parent) {
// Can't resize in this direction
- return;
+ return false;
}
// Implement up/down/left/right direction by zeroing one of the weights,
@@ -248,22 +248,22 @@ static void resize_tiled(struct sway_container *parent, int amount,
if (sibling_pos < parent_pos && minor_weight) {
double pixels = -amount / minor_weight;
if (major_weight && (sibling_size + pixels / 2) < min_sane) {
- return; // Too small
+ return false; // Too small
} else if (!major_weight && sibling_size + pixels < min_sane) {
- return; // Too small
+ return false; // Too small
}
} else if (sibling_pos > parent_pos && major_weight) {
double pixels = -amount / major_weight;
if (minor_weight && (sibling_size + pixels / 2) < min_sane) {
- return; // Too small
+ return false; // Too small
} else if (!minor_weight && sibling_size + pixels < min_sane) {
- return; // Too small
+ return false; // Too small
}
}
} else {
double pixels = amount;
if (parent_size + pixels < min_sane) {
- return; // Too small
+ return false; // Too small
}
}
}
@@ -317,9 +317,10 @@ static void resize_tiled(struct sway_container *parent, int amount,
} else {
arrange_workspace(parent->workspace);
}
+ return true;
}
-void container_resize_tiled(struct sway_container *parent,
+bool container_resize_tiled(struct sway_container *parent,
enum wlr_edges edge, int amount) {
enum resize_axis axis = RESIZE_AXIS_INVALID;
switch (edge) {
@@ -338,7 +339,7 @@ void container_resize_tiled(struct sway_container *parent,
case WLR_EDGE_NONE:
break;
}
- resize_tiled(parent, amount, axis);
+ return resize_tiled(parent, amount, axis);
}
/**
@@ -395,6 +396,10 @@ static struct cmd_results *resize_adjust_floating(enum resize_axis axis,
case RESIZE_AXIS_INVALID:
return cmd_results_new(CMD_INVALID, "resize", "Invalid axis/direction");
}
+ if (grow_x == 0 && grow_y == 0) {
+ return cmd_results_new(CMD_INVALID, "resize",
+ "Cannot resize any further");
+ }
con->x += grow_x;
con->y += grow_y;
con->width += grow_width;
@@ -442,7 +447,10 @@ static struct cmd_results *resize_adjust_tiled(enum resize_axis axis,
}
}
- resize_tiled(current, amount->amount, axis);
+ if (!resize_tiled(current, amount->amount, axis)) {
+ return cmd_results_new(CMD_INVALID, "resize",
+ "Cannot resize any further");
+ }
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c
index f026a39d..2ce7872d 100644
--- a/sway/commands/workspace.c
+++ b/sway/commands/workspace.c
@@ -10,6 +10,26 @@
#include "log.h"
#include "stringop.h"
+static struct workspace_config *workspace_config_find_or_create(char *ws_name) {
+ struct workspace_config *wsc = workspace_find_config(ws_name);
+ if (wsc) {
+ return wsc;
+ }
+ wsc = calloc(1, sizeof(struct workspace_config));
+ if (!wsc) {
+ return NULL;
+ }
+ wsc->workspace = strdup(ws_name);
+ list_add(config->workspace_configs, wsc);
+ return wsc;
+}
+
+void free_workspace_config(struct workspace_config *wsc) {
+ free(wsc->workspace);
+ free(wsc->output);
+ free(wsc);
+}
+
struct cmd_results *cmd_workspace(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1))) {
@@ -28,21 +48,15 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, output_location + 2))) {
return error;
}
- struct workspace_output *wso = calloc(1, sizeof(struct workspace_output));
- if (!wso) {
+ char *ws_name = join_args(argv, argc - 2);
+ struct workspace_config *wsc = workspace_config_find_or_create(ws_name);
+ free(ws_name);
+ if (!wsc) {
return cmd_results_new(CMD_FAILURE, "workspace output",
"Unable to allocate workspace output");
}
- wso->workspace = join_args(argv, argc - 2);
- wso->output = strdup(argv[output_location + 1]);
- int i = -1;
- if ((i = list_seq_find(config->workspace_outputs, workspace_output_cmp_workspace, wso)) != -1) {
- struct workspace_output *old = config->workspace_outputs->items[i];
- free(old); // workspaces can only be assigned to a single output
- list_del(config->workspace_outputs, i);
- }
- wlr_log(WLR_DEBUG, "Assigning workspace %s to output %s", wso->workspace, wso->output);
- list_add(config->workspace_outputs, wso);
+ free(wsc->output);
+ wsc->output = strdup(argv[output_location + 1]);
} else {
if (config->reading || !config->active) {
return cmd_results_new(CMD_DEFER, "workspace", NULL);
diff --git a/sway/config.c b/sway/config.c
index 830fb65f..1e08559d 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -95,7 +95,12 @@ void free_config(struct sway_config *config) {
list_free(config->bars);
}
list_free(config->cmd_queue);
- list_free(config->workspace_outputs);
+ if (config->workspace_configs) {
+ for (int i = 0; i < config->workspace_configs->length; i++) {
+ free_workspace_config(config->workspace_configs->items[i]);
+ }
+ list_free(config->workspace_configs);
+ }
if (config->output_configs) {
for (int i = 0; i < config->output_configs->length; i++) {
free_output_config(config->output_configs->items[i]);
@@ -175,7 +180,7 @@ static void config_defaults(struct sway_config *config) {
if (!(config->symbols = create_list())) goto cleanup;
if (!(config->modes = create_list())) goto cleanup;
if (!(config->bars = create_list())) goto cleanup;
- if (!(config->workspace_outputs = create_list())) goto cleanup;
+ if (!(config->workspace_configs = create_list())) goto cleanup;
if (!(config->criteria = create_list())) goto cleanup;
if (!(config->no_focus = create_list())) goto cleanup;
if (!(config->input_configs = create_list())) goto cleanup;
@@ -804,7 +809,7 @@ char *do_var_replacement(char *str) {
// would compare two structs in full, while this method only compares the
// workspace.
int workspace_output_cmp_workspace(const void *a, const void *b) {
- const struct workspace_output *wsa = a, *wsb = b;
+ const struct workspace_config *wsa = a, *wsb = b;
return lenient_strcmp(wsa->workspace, wsb->workspace);
}
diff --git a/sway/config/input.c b/sway/config/input.c
index fffc8518..6b43a5b9 100644
--- a/sway/config/input.c
+++ b/sway/config/input.c
@@ -52,6 +52,9 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
if (src->dwt != INT_MIN) {
dst->dwt = src->dwt;
}
+ if (src->left_handed != INT_MIN) {
+ dst->left_handed = src->left_handed;
+ }
if (src->middle_emulation != INT_MIN) {
dst->middle_emulation = src->middle_emulation;
}
diff --git a/sway/config/output.c b/sway/config/output.c
index 74d79130..6f337b66 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -237,7 +237,7 @@ void apply_output_config(struct output_config *oc, struct sway_output *output) {
wlr_log(WLR_DEBUG, "Setting background for output %d to %s",
output_i, oc->background);
- size_t len = snprintf(NULL, 0, "%s %d %s %s %s",
+ size_t len = snprintf(NULL, 0, "%s %d \"%s\" %s %s",
config->swaybg_command ? config->swaybg_command : "swaybg",
output_i, oc->background, oc->background_option,
oc->background_fallback ? oc->background_fallback : "");
@@ -246,7 +246,7 @@ void apply_output_config(struct output_config *oc, struct sway_output *output) {
wlr_log(WLR_DEBUG, "Unable to allocate swaybg command");
return;
}
- snprintf(command, len + 1, "%s %d %s %s %s",
+ snprintf(command, len + 1, "%s %d \"%s\" %s %s",
config->swaybg_command ? config->swaybg_command : "swaybg",
output_i, oc->background, oc->background_option,
oc->background_fallback ? oc->background_fallback : "");
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index 797f6b4c..34d99d52 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -31,14 +31,14 @@ struct sway_transaction_instruction {
struct sway_transaction *transaction;
struct sway_node *node;
union {
- struct sway_output_state *output_state;
- struct sway_workspace_state *workspace_state;
- struct sway_container_state *container_state;
+ struct sway_output_state output_state;
+ struct sway_workspace_state workspace_state;
+ struct sway_container_state container_state;
};
uint32_t serial;
};
-static struct sway_transaction *transaction_create() {
+static struct sway_transaction *transaction_create(void) {
struct sway_transaction *transaction =
calloc(1, sizeof(struct sway_transaction));
if (!sway_assert(transaction, "Unable to allocate transaction")) {
@@ -86,14 +86,7 @@ static void transaction_destroy(struct sway_transaction *transaction) {
static void copy_output_state(struct sway_output *output,
struct sway_transaction_instruction *instruction) {
- struct sway_output_state *state =
- calloc(1, sizeof(struct sway_output_state));
- if (!state) {
- wlr_log(WLR_ERROR, "Could not allocate output state");
- return;
- }
- instruction->output_state = state;
-
+ struct sway_output_state *state = &instruction->output_state;
state->workspaces = create_list();
list_cat(state->workspaces, output->workspaces);
@@ -102,13 +95,7 @@ static void copy_output_state(struct sway_output *output,
static void copy_workspace_state(struct sway_workspace *ws,
struct sway_transaction_instruction *instruction) {
- struct sway_workspace_state *state =
- calloc(1, sizeof(struct sway_workspace_state));
- if (!state) {
- wlr_log(WLR_ERROR, "Could not allocate workspace state");
- return;
- }
- instruction->workspace_state = state;
+ struct sway_workspace_state *state = &instruction->workspace_state;
state->fullscreen = ws->fullscreen;
state->x = ws->x;
@@ -138,13 +125,7 @@ static void copy_workspace_state(struct sway_workspace *ws,
static void copy_container_state(struct sway_container *container,
struct sway_transaction_instruction *instruction) {
- struct sway_container_state *state =
- calloc(1, sizeof(struct sway_container_state));
- if (!state) {
- wlr_log(WLR_ERROR, "Could not allocate container state");
- return;
- }
- instruction->container_state = state;
+ struct sway_container_state *state = &instruction->container_state;
state->layout = container->layout;
state->con_x = container->x;
@@ -301,15 +282,15 @@ static void transaction_apply(struct sway_transaction *transaction) {
case N_ROOT:
break;
case N_OUTPUT:
- apply_output_state(node->sway_output, instruction->output_state);
+ apply_output_state(node->sway_output, &instruction->output_state);
break;
case N_WORKSPACE:
apply_workspace_state(node->sway_workspace,
- instruction->workspace_state);
+ &instruction->workspace_state);
break;
case N_CONTAINER:
apply_container_state(node->sway_container,
- instruction->container_state);
+ &instruction->container_state);
break;
}
@@ -335,7 +316,7 @@ static bool transaction_same_nodes(struct sway_transaction *a,
return true;
}
-static void transaction_progress_queue() {
+static void transaction_progress_queue(void) {
if (!server.transactions->length) {
return;
}
@@ -390,7 +371,7 @@ static bool should_configure(struct sway_node *node,
return false;
}
struct sway_container_state *cstate = &node->sway_container->current;
- struct sway_container_state *istate = instruction->container_state;
+ struct sway_container_state *istate = &instruction->container_state;
#ifdef HAVE_XWAYLAND
// Xwayland views are position-aware and need to be reconfigured
// when their position changes.
@@ -418,10 +399,10 @@ static void transaction_commit(struct sway_transaction *transaction) {
struct sway_node *node = instruction->node;
if (should_configure(node, instruction)) {
instruction->serial = view_configure(node->sway_container->view,
- instruction->container_state->view_x,
- instruction->container_state->view_y,
- instruction->container_state->view_width,
- instruction->container_state->view_height);
+ instruction->container_state.view_x,
+ instruction->container_state.view_y,
+ instruction->container_state.view_width,
+ instruction->container_state.view_height);
++transaction->num_waiting;
// From here on we are rendering a saved buffer of the view, which
@@ -513,8 +494,8 @@ void transaction_notify_view_ready_by_size(struct sway_view *view,
int width, int height) {
struct sway_transaction_instruction *instruction =
view->container->node.instruction;
- if (instruction->container_state->view_width == width &&
- instruction->container_state->view_height == height) {
+ if (instruction->container_state.view_width == width &&
+ instruction->container_state.view_height == height) {
set_instruction_ready(instruction);
}
}
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 8c9f65ab..2d5d351f 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -897,7 +897,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
// Handle moving a tiling container
if (config->tiling_drag && mod_pressed && state == WLR_BUTTON_PRESSED &&
- !is_floating_or_child && !cont->is_fullscreen) {
+ !is_floating_or_child && cont && !cont->is_fullscreen) {
seat_pointer_notify_button(seat, time_msec, button, state);
seat_begin_move_tiling(seat, cont, button);
return;
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
index f696646f..f39fe29c 100644
--- a/sway/input/input-manager.c
+++ b/sway/input/input-manager.c
@@ -233,7 +233,8 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
wlr_log(WLR_DEBUG, "adding device: '%s'",
input_device->identifier);
- if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) {
+ if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER ||
+ input_device->wlr_device->type == WLR_INPUT_DEVICE_TABLET_TOOL) {
input_manager_libinput_config_pointer(input_device);
}
@@ -393,7 +394,8 @@ void input_manager_apply_input_config(struct sway_input_manager *input,
wl_list_for_each(input_device, &input->devices, link) {
if (strcmp(input_device->identifier, input_config->identifier) == 0
|| wildcard) {
- if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) {
+ if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER ||
+ input_device->wlr_device->type == WLR_INPUT_DEVICE_TABLET_TOOL) {
input_manager_libinput_config_pointer(input_device);
}
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 99959c97..2d915502 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -1,8 +1,5 @@
// See https://i3wm.org/docs/ipc.html for protocol information
-#ifndef __FreeBSD__
-// Any value will hide SOCK_CLOEXEC on FreeBSD (__BSD_VISIBLE=0)
-#define _XOPEN_SOURCE 700
-#endif
+#define _POSIX_C_SOURCE 200112L
#ifdef __linux__
#include <linux/input-event-codes.h>
#elif __FreeBSD__
@@ -89,10 +86,16 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
}
void ipc_init(struct sway_server *server) {
- ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
+ ipc_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (ipc_socket == -1) {
sway_abort("Unable to create IPC socket");
}
+ if (fcntl(ipc_socket, F_SETFD, FD_CLOEXEC) == -1) {
+ sway_abort("Unable to set CLOEXEC on IPC socket");
+ }
+ if (fcntl(ipc_socket, F_SETFL, O_NONBLOCK) == -1) {
+ sway_abort("Unable to set NONBLOCK on IPC socket");
+ }
ipc_sockaddr = ipc_user_sockaddr();
diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd
index a61e2829..00b9386e 100644
--- a/sway/sway-bar.5.scd
+++ b/sway/sway-bar.5.scd
@@ -6,8 +6,7 @@ sway-bar - bar configuration file and commands
# DESCRIPTION
-Sway allows configuring swaybar in the sway configuration file. Swaybar
-commands must be used inside a _bar { }_ block in the config file.
+Sway allows configuring swaybar in the sway configuration file.
# COMMANDS
diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd
index 707c36af..5736d70a 100644
--- a/sway/sway-input.5.scd
+++ b/sway/sway-input.5.scd
@@ -7,7 +7,6 @@ sway-input - input configuration file and commands
# DESCRIPTION
Sway allows for configuration of devices within the sway configuration file.
-sway-input commands must be used inside an _input { }_ block in the config.
To obtain a list of available device identifiers, run *swaymsg -t get\_inputs*.
# INPUT COMMANDS
@@ -116,8 +115,7 @@ The following commands may only be used in the configuration file.
## SEAT CONFIGURATION
-Configure options for multiseat mode. sway-seat commands must be used inside a
-_seat { }_ block in the config.
+Configure options for multiseat mode.
A *seat* is a collection of input devices that act independently of each other.
Seats are identified by name and the default seat is _seat0_ if no seats are
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index 927bf55c..1526eee3 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -19,6 +19,24 @@ bindsym Shift+XF86AudioRaiseVolume exec \\
pactl set-sink-volume @DEFAULT_SINK@ -1%
```
+Commands can also be given as a block in the form *command { <subcommands...>
+}*. Anything before the opening *{* will be prepended to the lines inside the
+block. For example:
+
+```
+output eDP-1 {
+ background ~/wallpaper.png
+ resolution 1920x1080
+}
+```
+
+is identical to
+
+```
+output eDP-1 background ~/wallpaper.png
+output eDP-1 resolution 1920x1080
+```
+
These commands can be executed in your config file, via *swaymsg*(1), or via
the bindsym command.
@@ -37,10 +55,8 @@ which you may only select one. *[...]* is used for optional arguments, and
The following commands may only be used in the configuration file.
-*bar {* <commands...> *}*
- _commands..._ after *{* will be interpreted as bar commands. For
- details, see *sway-bar*(5). A newline is required between *{* and the
- first command, and *}* must be alone on a line.
+*bar* [<bar-id>] <bar-subcommands...>
+ For details on bar subcommands, see *sway-bar*(5).
*default\_orientation* horizontal|vertical|auto
Sets the default container layout for tiled containers.
@@ -51,10 +67,6 @@ The following commands may only be used in the configuration file.
*wordexp*(3) for details). The same include file can only be included once;
subsequent attempts will be ignored.
-*set* $<name> <value>
- Sets variable $_name_ to _value_. You can use the new variable in the
- arguments of future commands.
-
*swaybg\_command* <command>
Executes custom background _command_. Default is _swaybg_. Refer to
*output* below for more information.
@@ -424,20 +436,15 @@ The default colors are:
*hide\_edge\_borders* none|vertical|horizontal|both|smart
Hides window borders adjacent to the screen edges. Default is _none_.
-*input* <input\_device> *{* <commands...> *}*
- _commands..._ after *{* will be interpreted as input commands applying to
- the specified input device. For details, see *sway-input*(5). A newline is
- required between *{* and the first command, and *}* must be alone on a
- line.
+*input* <input\_device> <input-subcommands...>
+ For details on input subcommands, see *sway-input*(5).
\* may be used in lieu of a specific device name to configure all input
devices. A list of input device names may be obtained via *swaymsg -t
get\_inputs*.
-*seat* <seat> *{* <commands...> *}*
- _commands..._ after *{* will be interpreted as seat commands applying to
- the specified seat. For details, see *sway-input*(5). A newline is required
- between *{* and the first command, and *}* must be alone on a line.
+*seat* <seat> <seat-subcommands...>
+ For details on seat subcommands, see *sway-input*(5).
*seat* <seat> cursor move|set <x> <y>
Move specified seat's cursor relative to current position or wrap to
@@ -465,10 +472,8 @@ The default colors are:
*mode* <mode>
Switches to the specified mode. The default mode _default_.
-*mode* [--pango\_markup] <mode> *{* <commands...> *}*
- _commands..._ after *{* will be added to the specified mode. A newline is
- required between *{* and the first command, and *}* must be alone on a
- line. Only *bindsym* and *bindcode* commands are permitted in mode blocks.
+*mode* [--pango\_markup] <mode> <mode-subcommands...>
+ The only two valid _mode-subcommands..._ are *bindsym* and *bindcode*.
If _--pango\_markup_ is given, then _mode_ will be interpreted as pango
markup.
@@ -533,8 +538,15 @@ You may combine output commands into one, like so:
output HDMI-A-1 mode 1920x1080 pos 1920,0 bg ~/wallpaper.png stretch
You can get a list of output names with *swaymsg -t get\_outputs*. You may also
-match any output by using the output name "\*". Be sure to add this output
-config after the others, or it will be matched instead of the others.
+match any output by using the output name "\*".
+
+*set* $<name> <value>
+ Sets variable $_name_ to _value_. You can use the new variable in the
+ arguments of future commands. When the variable is used, it can be escaped
+ with an additional $ (ie $$_name_) to have the replacement happen at run
+ time instead of when reading the config. However, it does not always make
+ sense for the variable to be replaced at run time since some arguments do
+ need to be known at config time.
*show\_marks* yes|no
If *show\_marks* is yes, marks will be displayed in the window borders.
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 53b127b7..baaa82fd 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -67,12 +67,10 @@ void container_destroy(struct sway_container *con) {
list_free(con->outputs);
if (con->view) {
- struct sway_view *view = con->view;
- view->container = NULL;
- free(view->title_format);
- view->title_format = NULL;
-
- if (view->destroying) {
+ if (con->view->container == con) {
+ con->view->container = NULL;
+ }
+ if (con->view->destroying) {
view_destroy(con->view);
}
}
@@ -985,7 +983,8 @@ void container_discover_outputs(struct sway_container *con) {
}
}
struct sway_output *new_output = container_get_effective_output(con);
- double old_scale = old_output ? old_output->wlr_output->scale : -1;
+ double old_scale = old_output && old_output->enabled ?
+ old_output->wlr_output->scale : -1;
double new_scale = new_output ? new_output->wlr_output->scale : -1;
if (old_scale != new_scale) {
container_update_title_textures(con);
diff --git a/sway/tree/view.c b/sway/tree/view.c
index e370443c..a024f325 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -989,12 +989,16 @@ bool view_is_visible(struct sway_view *view) {
floater = floater->parent;
}
bool is_sticky = container_is_floating(floater) && floater->is_sticky;
+ if (!is_sticky && !workspace_is_visible(workspace)) {
+ return false;
+ }
// Check view isn't in a tabbed or stacked container on an inactive tab
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *con = view->container;
while (con) {
enum sway_container_layout layout = container_parent_layout(con);
- if (layout == L_TABBED || layout == L_STACKED) {
+ if ((layout == L_TABBED || layout == L_STACKED)
+ && !container_is_floating(con)) {
struct sway_node *parent = con->parent ?
&con->parent->node : &con->workspace->node;
if (seat_get_active_tiling_child(seat, parent) != &con->node) {
@@ -1008,10 +1012,6 @@ bool view_is_visible(struct sway_view *view) {
!container_is_fullscreen_or_child(view->container)) {
return false;
}
- // Check the workspace is visible
- if (!is_sticky) {
- return workspace_is_visible(workspace);
- }
return true;
}
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 16031e87..d65a3e4c 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -20,17 +20,23 @@
#include "log.h"
#include "util.h"
+struct workspace_config *workspace_find_config(const char *ws_name) {
+ for (int i = 0; i < config->workspace_configs->length; ++i) {
+ struct workspace_config *wsc = config->workspace_configs->items[i];
+ if (strcmp(wsc->workspace, ws_name) == 0) {
+ return wsc;
+ }
+ }
+ return NULL;
+}
+
struct sway_output *workspace_get_initial_output(const char *name) {
- // Search for workspace<->output pair
- for (int i = 0; i < config->workspace_outputs->length; ++i) {
- struct workspace_output *wso = config->workspace_outputs->items[i];
- if (strcasecmp(wso->workspace, name) == 0) {
- // Find output to use if it exists
- struct sway_output *output = output_by_name(wso->output);
- if (output) {
- return output;
- }
- break;
+ // Check workspace configs for a workspace<->output pair
+ struct workspace_config *wsc = workspace_find_config(name);
+ if (wsc && wsc->output) {
+ struct sway_output *output = output_by_name(wsc->output);
+ if (output) {
+ return output;
}
}
// Otherwise put it on the focused output
@@ -121,17 +127,8 @@ void next_name_map(struct sway_container *ws, void *data) {
static bool workspace_valid_on_output(const char *output_name,
const char *ws_name) {
- int i;
- for (i = 0; i < config->workspace_outputs->length; ++i) {
- struct workspace_output *wso = config->workspace_outputs->items[i];
- if (strcasecmp(wso->workspace, ws_name) == 0) {
- if (strcasecmp(wso->output, output_name) != 0) {
- return false;
- }
- }
- }
-
- return true;
+ struct workspace_config *wsc = workspace_find_config(ws_name);
+ return !wsc || !wsc->output || strcmp(wsc->output, output_name) == 0;
}
static void workspace_name_from_binding(const struct sway_binding * binding,
@@ -231,13 +228,13 @@ char *workspace_next_name(const char *output_name) {
workspace_name_from_binding(mode->keycode_bindings->items[i],
output_name, &order, &target);
}
- for (int i = 0; i < config->workspace_outputs->length; ++i) {
+ for (int i = 0; i < config->workspace_configs->length; ++i) {
// Unlike with bindings, this does not guarantee order
- const struct workspace_output *wso = config->workspace_outputs->items[i];
- if (strcmp(wso->output, output_name) == 0
- && workspace_by_name(wso->workspace) == NULL) {
+ const struct workspace_config *wsc = config->workspace_configs->items[i];
+ if (wsc->output && strcmp(wsc->output, output_name) == 0
+ && workspace_by_name(wsc->workspace) == NULL) {
free(target);
- target = strdup(wso->workspace);
+ target = strdup(wsc->workspace);
break;
}
}
diff --git a/swaybar/bar.c b/swaybar/bar.c
index ab307fd4..15e81976 100644
--- a/swaybar/bar.c
+++ b/swaybar/bar.c
@@ -16,12 +16,13 @@
#else
#include <linux/input-event-codes.h>
#endif
-#include "swaybar/render.h"
+#include "swaybar/bar.h"
#include "swaybar/config.h"
#include "swaybar/event_loop.h"
-#include "swaybar/status_line.h"
-#include "swaybar/bar.h"
+#include "swaybar/i3bar.h"
#include "swaybar/ipc.h"
+#include "swaybar/status_line.h"
+#include "swaybar/render.h"
#include "ipc-client.h"
#include "list.h"
#include "log.h"
@@ -478,14 +479,16 @@ static void render_all_frames(struct swaybar *bar) {
}
}
-void bar_setup(struct swaybar *bar,
+bool bar_setup(struct swaybar *bar,
const char *socket_path, const char *bar_id) {
bar_init(bar);
init_event_loop();
bar->ipc_socketfd = ipc_open_socket(socket_path);
bar->ipc_event_socketfd = ipc_open_socket(socket_path);
- ipc_initialize(bar, bar_id);
+ if (!ipc_initialize(bar, bar_id)) {
+ return false;
+ }
if (bar->config->status_command) {
bar->status = status_line_init(bar->config->status_command);
}
@@ -526,6 +529,7 @@ void bar_setup(struct swaybar *bar,
ipc_get_workspaces(bar);
render_all_frames(bar);
+ return true;
}
static void display_in(int fd, short mask, void *data) {
diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c
index 325aa61a..8e9b038b 100644
--- a/swaybar/i3bar.c
+++ b/swaybar/i3bar.c
@@ -6,7 +6,9 @@
#include <string.h>
#include <unistd.h>
#include <wlr/util/log.h>
+#include "swaybar/bar.h"
#include "swaybar/config.h"
+#include "swaybar/i3bar.h"
#include "swaybar/status_line.h"
void i3bar_block_unref(struct i3bar_block *block) {
diff --git a/swaybar/ipc.c b/swaybar/ipc.c
index 0e60c10c..7c53a44f 100644
--- a/swaybar/ipc.c
+++ b/swaybar/ipc.c
@@ -141,9 +141,16 @@ static void ipc_parse_colors(
}
}
-static void ipc_parse_config(
+static bool ipc_parse_config(
struct swaybar_config *config, const char *payload) {
json_object *bar_config = json_tokener_parse(payload);
+ json_object *success;
+ if (json_object_object_get_ex(bar_config, "success", &success)
+ && !json_object_get_boolean(success)) {
+ wlr_log(WLR_ERROR, "No bar with that ID. Use 'swaymsg -t get_bar_config to get the available bar configs.");
+ json_object_put(bar_config);
+ return false;
+ }
json_object *markup, *mode, *hidden_bar, *position, *status_command;
json_object *font, *bar_height, *wrap_scroll, *workspace_buttons, *strip_workspace_numbers;
json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs;
@@ -226,10 +233,10 @@ static void ipc_parse_config(
}
json_object_put(bar_config);
+ return true;
}
void ipc_get_workspaces(struct swaybar *bar) {
- bar->focused_output = NULL;
struct swaybar_output *output;
wl_list_for_each(output, &bar->outputs, link) {
free_workspaces(&output->workspaces);
@@ -312,11 +319,14 @@ static void ipc_get_outputs(struct swaybar *bar) {
free(res);
}
-void ipc_initialize(struct swaybar *bar, const char *bar_id) {
+bool ipc_initialize(struct swaybar *bar, const char *bar_id) {
uint32_t len = strlen(bar_id);
char *res = ipc_single_command(bar->ipc_socketfd,
IPC_GET_BAR_CONFIG, bar_id, &len);
- ipc_parse_config(bar->config, res);
+ if (!ipc_parse_config(bar->config, res)) {
+ free(res);
+ return false;
+ }
free(res);
ipc_get_outputs(bar);
@@ -324,6 +334,7 @@ void ipc_initialize(struct swaybar *bar, const char *bar_id) {
len = strlen(subscribe);
free(ipc_single_command(bar->ipc_event_socketfd,
IPC_SUBSCRIBE, subscribe, &len));
+ return true;
}
bool handle_ipc_readable(struct swaybar *bar) {
diff --git a/swaybar/main.c b/swaybar/main.c
index 60e4b37c..d2c579db 100644
--- a/swaybar/main.c
+++ b/swaybar/main.c
@@ -96,7 +96,10 @@ int main(int argc, char **argv) {
signal(SIGTERM, sig_handler);
- bar_setup(&swaybar, socket_path, bar_id);
+ if (!bar_setup(&swaybar, socket_path, bar_id)) {
+ free(socket_path);
+ return 1;
+ }
free(socket_path);
free(bar_id);
diff --git a/swaybar/render.c b/swaybar/render.c
index 9413dc57..90e5bac7 100644
--- a/swaybar/render.c
+++ b/swaybar/render.c
@@ -10,6 +10,7 @@
#include "pool-buffer.h"
#include "swaybar/bar.h"
#include "swaybar/config.h"
+#include "swaybar/i3bar.h"
#include "swaybar/ipc.h"
#include "swaybar/render.h"
#include "swaybar/status_line.h"
@@ -20,47 +21,47 @@ static const double WS_VERTICAL_PADDING = 1.5;
static const double BORDER_WIDTH = 1;
static uint32_t render_status_line_error(cairo_t *cairo,
- struct swaybar_output *output, struct swaybar_config *config,
- const char *error, double *x, uint32_t surface_height) {
+ struct swaybar_output *output, double *x) {
+ const char *error = output->bar->status->text;
if (!error) {
return 0;
}
- uint32_t height = surface_height * output->scale;
+ uint32_t height = output->height * output->scale;
cairo_set_source_u32(cairo, 0xFF0000FF);
int margin = 3 * output->scale;
int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale;
+ char *font = output->bar->config->font;
int text_width, text_height;
- get_text_size(cairo, config->font, &text_width, &text_height, NULL,
+ get_text_size(cairo, font, &text_width, &text_height, NULL,
output->scale, false, "%s", error);
uint32_t ideal_height = text_height + ws_vertical_padding * 2;
uint32_t ideal_surface_height = ideal_height / output->scale;
- if (surface_height < ideal_surface_height) {
+ if (output->height < ideal_surface_height) {
return ideal_surface_height;
}
*x -= text_width + margin;
double text_y = height / 2.0 - text_height / 2.0;
cairo_move_to(cairo, *x, (int)floor(text_y));
- pango_printf(cairo, config->font, output->scale, false, "%s", error);
+ pango_printf(cairo, font, output->scale, false, "%s", error);
*x -= margin;
- return surface_height;
+ return output->height;
}
static uint32_t render_status_line_text(cairo_t *cairo,
- struct swaybar_output *output, struct swaybar_config *config,
- const char *text, bool focused, double *x, uint32_t surface_height) {
+ struct swaybar_output *output, double *x) {
+ const char *text = output->bar->status->text;
if (!text) {
return 0;
}
- uint32_t height = surface_height * output->scale;
-
- cairo_set_source_u32(cairo, focused ?
+ struct swaybar_config *config = output->bar->config;
+ cairo_set_source_u32(cairo, output->focused ?
config->colors.focused_statusline : config->colors.statusline);
int text_width, text_height;
@@ -72,17 +73,18 @@ static uint32_t render_status_line_text(cairo_t *cairo,
uint32_t ideal_height = text_height + ws_vertical_padding * 2;
uint32_t ideal_surface_height = ideal_height / output->scale;
- if (surface_height < ideal_surface_height) {
+ if (output->height < ideal_surface_height) {
return ideal_surface_height;
}
*x -= text_width + margin;
+ uint32_t height = output->height * output->scale;
double text_y = height / 2.0 - text_height / 2.0;
cairo_move_to(cairo, *x, (int)floor(text_y));
pango_printf(cairo, config->font, output->scale,
config->pango_markup, "%s", text);
*x -= margin;
- return surface_height;
+ return output->height;
}
static void render_sharp_line(cairo_t *cairo, uint32_t color,
@@ -122,12 +124,11 @@ static void i3bar_block_unref_callback(void *data) {
static uint32_t render_status_block(cairo_t *cairo,
struct swaybar_output *output, struct i3bar_block *block, double *x,
- uint32_t surface_height, bool focused, bool edge) {
+ bool edge) {
if (!block->full_text || !*block->full_text) {
return 0;
}
- uint32_t height = surface_height * output->scale;
struct swaybar_config *config = output->bar->config;
int text_width, text_height;
@@ -145,7 +146,7 @@ static uint32_t render_status_block(cairo_t *cairo,
double block_width = width;
uint32_t ideal_height = text_height + ws_vertical_padding * 2;
uint32_t ideal_surface_height = ideal_height / output->scale;
- if (surface_height < ideal_surface_height) {
+ if (output->height < ideal_surface_height) {
return ideal_surface_height;
}
@@ -166,7 +167,7 @@ static uint32_t render_status_block(cairo_t *cairo,
output->scale, false, "%s", config->sep_symbol);
uint32_t _ideal_height = sep_height + ws_vertical_padding * 2;
uint32_t _ideal_surface_height = _ideal_height / output->scale;
- if (surface_height < _ideal_surface_height) {
+ if (output->height < _ideal_surface_height) {
return _ideal_surface_height;
}
if (sep_width > block->separator_block_width) {
@@ -178,6 +179,7 @@ static uint32_t render_status_block(cairo_t *cairo,
*x -= margin;
}
+ uint32_t height = output->height * output->scale;
if (output->bar->status->click_events) {
struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
hotspot->x = *x;
@@ -241,7 +243,7 @@ static uint32_t render_status_block(cairo_t *cairo,
}
if (!edge && block->separator) {
- if (focused) {
+ if (output->focused) {
cairo_set_source_u32(cairo, config->colors.focused_separator);
} else {
cairo_set_source_u32(cairo, config->colors.separator);
@@ -260,19 +262,16 @@ static uint32_t render_status_block(cairo_t *cairo,
cairo_stroke(cairo);
}
}
- return surface_height;
+ return output->height;
}
static uint32_t render_status_line_i3bar(cairo_t *cairo,
- struct swaybar_config *config, struct swaybar_output *output,
- struct status_line *status, bool focused,
- double *x, uint32_t surface_height) {
+ struct swaybar_output *output, double *x) {
uint32_t max_height = 0;
bool edge = true;
struct i3bar_block *block;
- wl_list_for_each(block, &status->blocks, link) {
- uint32_t h = render_status_block(cairo, output,
- block, x, surface_height, focused, edge);
+ wl_list_for_each(block, &output->bar->status->blocks, link) {
+ uint32_t h = render_status_block(cairo, output, block, x, edge);
max_height = h > max_height ? h : max_height;
edge = false;
}
@@ -280,19 +279,15 @@ static uint32_t render_status_line_i3bar(cairo_t *cairo,
}
static uint32_t render_status_line(cairo_t *cairo,
- struct swaybar_config *config, struct swaybar_output *output,
- struct status_line *status, bool focused,
- double *x, uint32_t surface_height) {
+ struct swaybar_output *output, double *x) {
+ struct status_line *status = output->bar->status;
switch (status->protocol) {
case PROTOCOL_ERROR:
- return render_status_line_error(cairo, output, config,
- status->text, x, surface_height);
+ return render_status_line_error(cairo, output, x);
case PROTOCOL_TEXT:
- return render_status_line_text(cairo, output, config,
- status->text, focused, x, surface_height);
+ return render_status_line_text(cairo, output, x);
case PROTOCOL_I3BAR:
- return render_status_line_i3bar(cairo, config, output,
- status, focused, x, surface_height);
+ return render_status_line_i3bar(cairo, output, x);
case PROTOCOL_UNDEF:
return 0;
}
@@ -300,10 +295,9 @@ static uint32_t render_status_line(cairo_t *cairo,
}
static uint32_t render_binding_mode_indicator(cairo_t *cairo,
- struct swaybar_output *output, struct swaybar_config *config,
- const char *mode, double x, uint32_t surface_height) {
- uint32_t height = surface_height * output->scale;
-
+ struct swaybar_output *output, double x) {
+ struct swaybar_config *config = output->bar->config;
+ const char *mode = config->mode;
int text_width, text_height;
get_text_size(cairo, config->font, &text_width, &text_height, NULL,
output->scale, config->mode_pango_markup,
@@ -316,11 +310,12 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo,
uint32_t ideal_height = text_height + ws_vertical_padding * 2
+ border_width * 2;
uint32_t ideal_surface_height = ideal_height / output->scale;
- if (surface_height < ideal_surface_height) {
+ if (output->height < ideal_surface_height) {
return ideal_surface_height;
}
uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2;
+ uint32_t height = output->height * output->scale;
cairo_set_source_u32(cairo, config->colors.binding_mode.background);
cairo_rectangle(cairo, x, 0, width, height);
cairo_fill(cairo);
@@ -340,7 +335,7 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo,
cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y));
pango_printf(cairo, config->font, output->scale, config->mode_pango_markup,
"%s", mode);
- return surface_height;
+ return output->height;
}
static const char *strip_workspace_number(const char *ws_name) {
@@ -366,8 +361,9 @@ static enum hotspot_event_handling workspace_hotspot_callback(struct swaybar_out
}
static uint32_t render_workspace_button(cairo_t *cairo,
- struct swaybar_output *output, struct swaybar_config *config,
- struct swaybar_workspace *ws, double *x, uint32_t surface_height) {
+ struct swaybar_output *output,
+ struct swaybar_workspace *ws, double *x) {
+ struct swaybar_config *config = output->bar->config;
const char *name = ws->name;
if (config->strip_workspace_numbers) {
name = strip_workspace_number(ws->name);
@@ -384,7 +380,7 @@ static uint32_t render_workspace_button(cairo_t *cairo,
box_colors = config->colors.inactive_workspace;
}
- uint32_t height = surface_height * output->scale;
+ uint32_t height = output->height * output->scale;
int text_width, text_height;
get_text_size(cairo, config->font, &text_width, &text_height, NULL,
@@ -397,7 +393,7 @@ static uint32_t render_workspace_button(cairo_t *cairo,
uint32_t ideal_height = ws_vertical_padding * 2 + text_height
+ border_width * 2;
uint32_t ideal_surface_height = ideal_height / output->scale;
- if (surface_height < ideal_surface_height) {
+ if (output->height < ideal_surface_height) {
return ideal_surface_height;
}
@@ -434,11 +430,11 @@ static uint32_t render_workspace_button(cairo_t *cairo,
wl_list_insert(&output->hotspots, &hotspot->link);
*x += width;
- return surface_height;
+ return output->height;
}
-static uint32_t render_to_cairo(cairo_t *cairo,
- struct swaybar *bar, struct swaybar_output *output) {
+static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) {
+ struct swaybar *bar = output->bar;
struct swaybar_config *config = bar->config;
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
if (output->focused) {
@@ -458,22 +454,19 @@ static uint32_t render_to_cairo(cairo_t *cairo,
*/
double x = output->width * output->scale;
if (bar->status) {
- uint32_t h = render_status_line(cairo, config, output,
- bar->status, output->focused, &x, output->height);
+ uint32_t h = render_status_line(cairo, output, &x);
max_height = h > max_height ? h : max_height;
}
x = 0;
if (config->workspace_buttons) {
struct swaybar_workspace *ws;
wl_list_for_each_reverse(ws, &output->workspaces, link) {
- uint32_t h = render_workspace_button(cairo,
- output, config, ws, &x, output->height);
+ uint32_t h = render_workspace_button(cairo, output, ws, &x);
max_height = h > max_height ? h : max_height;
}
}
if (config->binding_mode_indicator && config->mode) {
- uint32_t h = render_binding_mode_indicator(cairo,
- output, config, config->mode, x, output->height);
+ uint32_t h = render_binding_mode_indicator(cairo, output, x);
max_height = h > max_height ? h : max_height;
}
@@ -506,9 +499,10 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) {
cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR);
cairo_paint(cairo);
cairo_restore(cairo);
- uint32_t height = render_to_cairo(cairo, bar, output);
- if (bar->config->height >= 0 && height < (uint32_t)bar->config->height) {
- height = bar->config->height;
+ uint32_t height = render_to_cairo(cairo, output);
+ int config_height = output->bar->config->height;
+ if (config_height >= 0 && height < (uint32_t)config_height) {
+ height = config_height;
}
if (height != output->height) {
// Reconfigure surface
@@ -519,7 +513,7 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) {
wl_surface_commit(output->surface);
} else if (height > 0) {
// Replay recording into shm and send it off
- output->current_buffer = get_next_buffer(bar->shm,
+ output->current_buffer = get_next_buffer(output->bar->shm,
output->buffers,
output->width * output->scale,
output->height * output->scale);
diff --git a/swaybar/status_line.c b/swaybar/status_line.c
index 48b43248..ed6dc7c8 100644
--- a/swaybar/status_line.c
+++ b/swaybar/status_line.c
@@ -1,12 +1,15 @@
#define _POSIX_C_SOURCE 200809L
#include <fcntl.h>
+#include <sys/ioctl.h>
#include <json-c/json.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <wlr/util/log.h>
+#include "swaybar/bar.h"
#include "swaybar/config.h"
+#include "swaybar/i3bar.h"
#include "swaybar/event_loop.h"
#include "swaybar/status_line.h"
#include "readline.h"
@@ -34,18 +37,35 @@ bool status_handle_readable(struct status_line *status) {
switch (status->protocol) {
case PROTOCOL_UNDEF:
errno = 0;
- read_bytes = getline(&status->buffer,
- &status->buffer_size, status->read);
- if (errno == EAGAIN) {
- clearerr(status->read);
- } else if (errno) {
+ int available_bytes;
+ if (ioctl(status->read_fd, FIONREAD, &available_bytes) == -1) {
+ wlr_log(WLR_ERROR, "Unable to read status command output size");
status_error(status, "[error reading from status command]");
return true;
}
+ if ((size_t)available_bytes + 1 > status->buffer_size) {
+ // need room for leading '\0' too
+ status->buffer_size = available_bytes + 1;
+ status->buffer = realloc(status->buffer, status->buffer_size);
+ }
+ if (status->buffer == NULL) {
+ wlr_log_errno(WLR_ERROR, "Unable to read status line");
+ status_error(status, "[error reading from status command]");
+ return true;
+ }
+
+ read_bytes = read(status->read_fd, status->buffer, available_bytes);
+ if (read_bytes != available_bytes) {
+ status_error(status, "[error reading from status command]");
+ return true;
+ }
+ status->buffer[available_bytes] = 0;
+
// the header must be sent completely the first time round
+ char *newline = strchr(status->buffer, '\n');
json_object *header, *version;
- if (status->buffer[read_bytes - 1] == '\n'
+ if (newline != NULL
&& (header = json_tokener_parse(status->buffer))
&& json_object_object_get_ex(header, "version", &version)
&& json_object_get_int(version) == 1) {
@@ -67,13 +87,9 @@ bool status_handle_readable(struct status_line *status) {
wl_list_init(&status->blocks);
status->tokener = json_tokener_new();
- read_bytes = getdelim(&status->buffer, &status->buffer_size, EOF, status->read);
- if (read_bytes > 0) {
- status->buffer_index = read_bytes;
- return i3bar_handle_readable(status);
- } else {
- return false;
- }
+ status->buffer_index = strlen(newline + 1);
+ memmove(status->buffer, newline + 1, status->buffer_index + 1);
+ return i3bar_handle_readable(status);
}
wlr_log(WLR_DEBUG, "Using text protocol.");
diff --git a/swaylock/main.c b/swaylock/main.c
index c25c8eec..693cbc10 100644
--- a/swaylock/main.c
+++ b/swaylock/main.c
@@ -845,6 +845,9 @@ static int load_config(char *path, struct swaylock_state *state,
static struct swaylock_state state;
int main(int argc, char **argv) {
+ wlr_log_init(WLR_DEBUG, NULL);
+ initialize_pw_backend();
+
enum line_mode line_mode = LM_LINE;
state.args = (struct swaylock_args){
.mode = BACKGROUND_MODE_SOLID_COLOR,
@@ -857,8 +860,6 @@ int main(int argc, char **argv) {
wl_list_init(&state.images);
set_default_colors(&state.args.colors);
- wlr_log_init(WLR_DEBUG, NULL);
-
char *config_path = NULL;
int result = parse_options(argc, argv, NULL, NULL, &config_path);
if (result != 0) {
diff --git a/swaylock/meson.build b/swaylock/meson.build
index 675b8c69..6c87d173 100644
--- a/swaylock/meson.build
+++ b/swaylock/meson.build
@@ -1,25 +1,37 @@
sysconfdir = get_option('sysconfdir')
-executable(
- 'swaylock', [
- 'main.c',
- 'password.c',
- 'render.c',
- 'seat.c'
- ],
+dependencies = [
+ cairo,
+ client_protos,
+ gdk_pixbuf,
+ math,
+ pango,
+ pangocairo,
+ xkbcommon,
+ wayland_client,
+ wlroots,
+]
+
+sources = [
+ 'main.c',
+ 'password.c',
+ 'render.c',
+ 'seat.c'
+]
+
+if libpam.found()
+ sources += ['pam.c']
+ dependencies += [libpam]
+else
+ warning('The swaylock binary must be setuid when compiled without libpam')
+ warning('You must do this manually post-install: chmod a+s /path/to/swaylock')
+ sources += ['shadow.c']
+endif
+
+executable('swaylock',
+ sources,
include_directories: [sway_inc],
- dependencies: [
- cairo,
- client_protos,
- gdk_pixbuf,
- libpam,
- math,
- pango,
- pangocairo,
- xkbcommon,
- wayland_client,
- wlroots,
- ],
+ dependencies: dependencies,
link_with: [lib_sway_common, lib_sway_client],
install: true
)
diff --git a/swaylock/pam.c b/swaylock/pam.c
new file mode 100644
index 00000000..cac95a85
--- /dev/null
+++ b/swaylock/pam.c
@@ -0,0 +1,62 @@
+#define _XOPEN_SOURCE 500
+#include <pwd.h>
+#include <security/pam_appl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wlr/util/log.h>
+#include "swaylock/swaylock.h"
+
+void initialize_pw_backend(void) {
+ // TODO: only call pam_start once. keep the same handle the whole time
+}
+
+static int function_conversation(int num_msg, const struct pam_message **msg,
+ struct pam_response **resp, void *data) {
+ struct swaylock_password *pw = data;
+ /* PAM expects an array of responses, one for each message */
+ struct pam_response *pam_reply = calloc(
+ num_msg, sizeof(struct pam_response));
+ *resp = pam_reply;
+ for (int i = 0; i < num_msg; ++i) {
+ switch (msg[i]->msg_style) {
+ case PAM_PROMPT_ECHO_OFF:
+ case PAM_PROMPT_ECHO_ON:
+ pam_reply[i].resp = strdup(pw->buffer); // PAM clears and frees this
+ break;
+ case PAM_ERROR_MSG:
+ case PAM_TEXT_INFO:
+ break;
+ }
+ }
+ return PAM_SUCCESS;
+}
+
+bool attempt_password(struct swaylock_password *pw) {
+ struct passwd *passwd = getpwuid(getuid());
+ char *username = passwd->pw_name;
+ const struct pam_conv local_conversation = {
+ function_conversation, pw
+ };
+ pam_handle_t *local_auth_handle = NULL;
+ int pam_err;
+ if ((pam_err = pam_start("swaylock", username,
+ &local_conversation, &local_auth_handle)) != PAM_SUCCESS) {
+ wlr_log(WLR_ERROR, "PAM returned error %d", pam_err);
+ }
+ if ((pam_err = pam_authenticate(local_auth_handle, 0)) != PAM_SUCCESS) {
+ wlr_log(WLR_ERROR, "pam_authenticate failed");
+ goto fail;
+ }
+ // TODO: only call pam_end once we succeed at authing. refresh tokens beforehand
+ if ((pam_err = pam_end(local_auth_handle, pam_err)) != PAM_SUCCESS) {
+ wlr_log(WLR_ERROR, "pam_end failed");
+ goto fail;
+ }
+ clear_password_buffer(pw);
+ return true;
+fail:
+ clear_password_buffer(pw);
+ return false;
+}
diff --git a/swaylock/password.c b/swaylock/password.c
index 7c686b34..6a956bcb 100644
--- a/swaylock/password.c
+++ b/swaylock/password.c
@@ -1,7 +1,6 @@
#define _XOPEN_SOURCE 500
#include <assert.h>
#include <pwd.h>
-#include <security/pam_appl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -11,27 +10,6 @@
#include "swaylock/seat.h"
#include "unicode.h"
-static int function_conversation(int num_msg, const struct pam_message **msg,
- struct pam_response **resp, void *data) {
- struct swaylock_password *pw = data;
- /* PAM expects an array of responses, one for each message */
- struct pam_response *pam_reply = calloc(
- num_msg, sizeof(struct pam_response));
- *resp = pam_reply;
- for (int i = 0; i < num_msg; ++i) {
- switch (msg[i]->msg_style) {
- case PAM_PROMPT_ECHO_OFF:
- case PAM_PROMPT_ECHO_ON:
- pam_reply[i].resp = strdup(pw->buffer); // PAM clears and frees this
- break;
- case PAM_ERROR_MSG:
- case PAM_TEXT_INFO:
- break;
- }
- }
- return PAM_SUCCESS;
-}
-
void clear_password_buffer(struct swaylock_password *pw) {
// Use volatile keyword so so compiler can't optimize this out.
volatile char *buffer = pw->buffer;
@@ -42,35 +20,6 @@ void clear_password_buffer(struct swaylock_password *pw) {
pw->len = 0;
}
-static bool attempt_password(struct swaylock_password *pw) {
- struct passwd *passwd = getpwuid(getuid());
- char *username = passwd->pw_name;
- const struct pam_conv local_conversation = {
- function_conversation, pw
- };
- pam_handle_t *local_auth_handle = NULL;
- int pam_err;
- // TODO: only call pam_start once. keep the same handle the whole time
- if ((pam_err = pam_start("swaylock", username,
- &local_conversation, &local_auth_handle)) != PAM_SUCCESS) {
- wlr_log(WLR_ERROR, "PAM returned error %d", pam_err);
- }
- if ((pam_err = pam_authenticate(local_auth_handle, 0)) != PAM_SUCCESS) {
- wlr_log(WLR_ERROR, "pam_authenticate failed");
- goto fail;
- }
- // TODO: only call pam_end once we succeed at authing. refresh tokens beforehand
- if ((pam_err = pam_end(local_auth_handle, pam_err)) != PAM_SUCCESS) {
- wlr_log(WLR_ERROR, "pam_end failed");
- goto fail;
- }
- clear_password_buffer(pw);
- return true;
-fail:
- clear_password_buffer(pw);
- return false;
-}
-
static bool backspace(struct swaylock_password *pw) {
if (pw->len != 0) {
pw->buffer[--pw->len] = 0;
diff --git a/swaylock/shadow.c b/swaylock/shadow.c
new file mode 100644
index 00000000..1f10514c
--- /dev/null
+++ b/swaylock/shadow.c
@@ -0,0 +1,128 @@
+#define _XOPEN_SOURCE
+#include <pwd.h>
+#include <shadow.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <wlr/util/log.h>
+#include "swaylock/swaylock.h"
+
+static int comm[2][2];
+
+void run_child(void) {
+ /* This code runs as root */
+ struct passwd *pwent = getpwuid(getuid());
+ if (!pwent) {
+ wlr_log_errno(WLR_ERROR, "failed to getpwuid");
+ exit(EXIT_FAILURE);
+ }
+ char *encpw = pwent->pw_passwd;
+ if (strcmp(encpw, "x") == 0) {
+ struct spwd *swent = getspnam(pwent->pw_name);
+ if (!swent) {
+ wlr_log_errno(WLR_ERROR, "failed to getspnam");
+ exit(EXIT_FAILURE);
+ }
+ encpw = swent->sp_pwdp;
+ }
+ wlr_log(WLR_DEBUG, "prepared to authorize user %s", pwent->pw_name);
+
+ size_t size;
+ char *buf;
+ while (1) {
+ ssize_t amt;
+ amt = read(comm[0][0], &size, sizeof(size));
+ if (amt == 0) {
+ break;
+ } else if (amt < 0) {
+ wlr_log_errno(WLR_ERROR, "read pw request");
+ }
+ wlr_log(WLR_DEBUG, "received pw check request");
+ buf = malloc(size);
+ if (!buf) {
+ wlr_log_errno(WLR_ERROR, "failed to malloc pw buffer");
+ exit(EXIT_FAILURE);
+ }
+ size_t offs = 0;
+ do {
+ amt = read(comm[0][0], &buf[offs], size - offs);
+ if (amt <= 0) {
+ wlr_log_errno(WLR_ERROR, "failed to read pw");
+ exit(EXIT_FAILURE);
+ }
+ offs += (size_t)amt;
+ } while (offs < size);
+ bool result = false;
+ char *c = crypt(buf, encpw);
+ if (c == NULL) {
+ wlr_log_errno(WLR_ERROR, "crypt");
+ }
+ result = strcmp(c, encpw) == 0;
+ if (write(comm[1][1], &result, sizeof(result)) != sizeof(result)) {
+ wlr_log_errno(WLR_ERROR, "failed to write pw check result");
+ exit(EXIT_FAILURE);
+ }
+ free(buf);
+ }
+ exit(EXIT_SUCCESS);
+}
+
+void initialize_pw_backend(void) {
+ if (geteuid() != 0) {
+ wlr_log(WLR_ERROR, "swaylock needs to be setuid to read /etc/shadow");
+ exit(EXIT_FAILURE);
+ }
+ if (pipe(comm[0]) != 0) {
+ wlr_log_errno(WLR_ERROR, "failed to create pipe");
+ exit(EXIT_FAILURE);
+ }
+ if (pipe(comm[1]) != 0) {
+ wlr_log_errno(WLR_ERROR, "failed to create pipe");
+ exit(EXIT_FAILURE);
+ }
+ pid_t child = fork();
+ if (child == 0) {
+ close(comm[0][1]);
+ close(comm[1][0]);
+ run_child();
+ } else if (child < 0) {
+ wlr_log_errno(WLR_ERROR, "failed to fork");
+ exit(EXIT_FAILURE);
+ }
+ close(comm[0][0]);
+ close(comm[1][1]);
+ if (setgid(getgid()) != 0) {
+ wlr_log_errno(WLR_ERROR, "Unable to drop root");
+ exit(EXIT_FAILURE);
+ }
+ if (setuid(getuid()) != 0) {
+ wlr_log_errno(WLR_ERROR, "Unable to drop root");
+ exit(EXIT_FAILURE);
+ }
+}
+
+bool attempt_password(struct swaylock_password *pw) {
+ bool result = false;
+ size_t len = pw->len + 1;
+ size_t offs = 0;
+ if (write(comm[0][1], &len, sizeof(len)) < 0) {
+ wlr_log_errno(WLR_ERROR, "Failed to request pw check");
+ goto ret;
+ }
+ do {
+ ssize_t amt = write(comm[0][1], &pw->buffer[offs], len - offs);
+ if (amt < 0) {
+ wlr_log_errno(WLR_ERROR, "Failed to write pw buffer");
+ goto ret;
+ }
+ offs += amt;
+ } while (offs < len);
+ if (read(comm[1][0], &result, sizeof(result)) != sizeof(result)) {
+ wlr_log_errno(WLR_ERROR, "Failed to read pw result");
+ goto ret;
+ }
+ wlr_log(WLR_DEBUG, "pw result: %d", result);
+ret:
+ clear_password_buffer(pw);
+ return result;
+}