aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--HACKING.md6
-rw-r--r--common/background-image.c8
-rw-r--r--common/ipc-client.c2
-rw-r--r--common/list.c15
-rw-r--r--common/log.c4
-rw-r--r--common/pango.c2
-rw-r--r--common/readline.c4
-rw-r--r--common/util.c2
-rw-r--r--completions/zsh/_swaymsg1
-rw-r--r--include/ipc.h5
-rw-r--r--include/list.h2
-rw-r--r--include/log.h10
-rw-r--r--include/sway/commands.h4
-rw-r--r--include/sway/config.h11
-rw-r--r--include/sway/criteria.h5
-rw-r--r--include/sway/debug.h8
-rw-r--r--include/sway/desktop.h4
-rw-r--r--include/sway/desktop/transaction.h33
-rw-r--r--include/sway/input/seat.h11
-rw-r--r--include/sway/server.h5
-rw-r--r--include/sway/tree/arrange.h22
-rw-r--r--include/sway/tree/container.h21
-rw-r--r--include/sway/tree/view.h10
-rw-r--r--include/sway/tree/workspace.h4
-rw-r--r--include/swaybar/bar.h15
-rw-r--r--include/swaybar/status_line.h4
-rw-r--r--include/swaylock/swaylock.h24
-rw-r--r--sway/commands.c21
-rw-r--r--sway/commands/assign.c2
-rw-r--r--sway/commands/bar.c6
-rw-r--r--sway/commands/bar/binding_mode_indicator.c4
-rw-r--r--sway/commands/bar/font.c2
-rw-r--r--sway/commands/bar/height.c2
-rw-r--r--sway/commands/bar/hidden_state.c2
-rw-r--r--sway/commands/bar/id.c2
-rw-r--r--sway/commands/bar/mode.c2
-rw-r--r--sway/commands/bar/modifier.c2
-rw-r--r--sway/commands/bar/output.c2
-rw-r--r--sway/commands/bar/pango_markup.c4
-rw-r--r--sway/commands/bar/position.c3
-rw-r--r--sway/commands/bar/separator_symbol.c2
-rw-r--r--sway/commands/bar/status_command.c2
-rw-r--r--sway/commands/bar/strip_workspace_numbers.c4
-rw-r--r--sway/commands/bar/swaybar_command.c2
-rw-r--r--sway/commands/bar/workspace_buttons.c4
-rw-r--r--sway/commands/bar/wrap_scroll.c4
-rw-r--r--sway/commands/bind.c4
-rw-r--r--sway/commands/border.c2
-rw-r--r--sway/commands/default_floating_border.c29
-rw-r--r--sway/commands/exec.c2
-rw-r--r--sway/commands/exec_always.c8
-rw-r--r--sway/commands/floating.c2
-rw-r--r--sway/commands/floating_minmax_size.c53
-rw-r--r--sway/commands/focus.c32
-rw-r--r--sway/commands/for_window.c2
-rw-r--r--sway/commands/fullscreen.c2
-rw-r--r--sway/commands/gaps.c8
-rw-r--r--sway/commands/input.c4
-rw-r--r--sway/commands/input/events.c2
-rw-r--r--sway/commands/input/scroll_button.c44
-rw-r--r--sway/commands/input/tap.c2
-rw-r--r--sway/commands/input/tap_button_map.c33
-rw-r--r--sway/commands/input/xkb_layout.c2
-rw-r--r--sway/commands/input/xkb_model.c2
-rw-r--r--sway/commands/input/xkb_options.c2
-rw-r--r--sway/commands/input/xkb_rules.c2
-rw-r--r--sway/commands/input/xkb_variant.c2
-rw-r--r--sway/commands/layout.c2
-rw-r--r--sway/commands/mode.c2
-rw-r--r--sway/commands/move.c147
-rw-r--r--sway/commands/no_focus.c26
-rw-r--r--sway/commands/output.c6
-rw-r--r--sway/commands/output/background.c8
-rw-r--r--sway/commands/reload.c4
-rw-r--r--sway/commands/rename.c2
-rw-r--r--sway/commands/resize.c410
-rw-r--r--sway/commands/set.c2
-rw-r--r--sway/commands/smart_gaps.c2
-rw-r--r--sway/commands/split.c2
-rw-r--r--sway/commands/swap.c9
-rw-r--r--sway/commands/swaybg_command.c2
-rw-r--r--sway/commands/urgent.c36
-rw-r--r--sway/commands/workspace.c2
-rw-r--r--sway/config.c127
-rw-r--r--sway/config/bar.c14
-rw-r--r--sway/config/input.c16
-rw-r--r--sway/config/output.c28
-rw-r--r--sway/config/seat.c6
-rw-r--r--sway/criteria.c48
-rw-r--r--sway/desktop/desktop.c9
-rw-r--r--sway/desktop/idle_inhibit_v1.c5
-rw-r--r--sway/desktop/layer_shell.c21
-rw-r--r--sway/desktop/output.c24
-rw-r--r--sway/desktop/render.c150
-rw-r--r--sway/desktop/transaction.c77
-rw-r--r--sway/desktop/xdg_shell.c33
-rw-r--r--sway/desktop/xdg_shell_v6.c33
-rw-r--r--sway/desktop/xwayland.c31
-rw-r--r--sway/input/cursor.c5
-rw-r--r--sway/input/input-manager.c50
-rw-r--r--sway/input/keyboard.c10
-rw-r--r--sway/input/seat.c73
-rw-r--r--sway/ipc-json.c9
-rw-r--r--sway/ipc-server.c90
-rw-r--r--sway/main.c68
-rw-r--r--sway/meson.build6
-rw-r--r--sway/server.c19
-rw-r--r--sway/sway-input.5.scd11
-rw-r--r--sway/sway.5.scd11
-rw-r--r--sway/tree/arrange.c102
-rw-r--r--sway/tree/container.c163
-rw-r--r--sway/tree/layout.c86
-rw-r--r--sway/tree/output.c6
-rw-r--r--sway/tree/view.c159
-rw-r--r--sway/tree/workspace.c27
-rw-r--r--swaybar/bar.c19
-rw-r--r--swaybar/i3bar.c36
-rw-r--r--swaybar/ipc.c16
-rw-r--r--swaybar/main.c8
-rw-r--r--swaybar/render.c7
-rw-r--r--swaybar/status_line.c6
-rw-r--r--swaybg/main.c9
-rw-r--r--swayidle/main.c93
-rw-r--r--swaylock/main.c462
-rw-r--r--swaylock/password.c10
-rw-r--r--swaylock/render.c74
-rw-r--r--swaylock/seat.c4
-rw-r--r--swaylock/swaylock.1.scd95
-rw-r--r--swaymsg/main.c51
-rw-r--r--swaymsg/swaymsg.1.scd10
131 files changed, 2642 insertions, 992 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8a6c0208..f450563a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -107,7 +107,7 @@ int main(int argc, const char **argv) {
}
int desired_output = atoi(argv[1]);
- sway_log(L_INFO, "Using output %d of %d", desired_output, registry->outputs->length);
+ sway_log(WLR_INFO, "Using output %d of %d", desired_output, registry->outputs->length);
int i;
struct output_state *output = registry->outputs->items[desired_output];
struct window *window = window_setup(registry, 100, 100, false);
diff --git a/HACKING.md b/HACKING.md
index 3600db24..8965d3ec 100644
--- a/HACKING.md
+++ b/HACKING.md
@@ -3,9 +3,9 @@
Use `sway_log(importance, fmt, ...)` to log. The following importances are
available:
-* `L_DEBUG`: Debug messages, only shows with `sway -d`
-* `L_INFO`: Informational messages
-* `L_ERROR`: Error messages
+* `WLR_DEBUG`: Debug messages, only shows with `sway -d`
+* `WLR_INFO`: Informational messages
+* `WLR_ERROR`: Error messages
`sway_log` is a macro that calls `_sway_log` with the current filename and line
number, which are written into the log with your message.
diff --git a/common/background-image.c b/common/background-image.c
index e5fb4433..f3d2551e 100644
--- a/common/background-image.c
+++ b/common/background-image.c
@@ -18,7 +18,7 @@ enum background_mode parse_background_mode(const char *mode) {
} else if (strcmp(mode, "solid_color") == 0) {
return BACKGROUND_MODE_SOLID_COLOR;
}
- wlr_log(L_ERROR, "Unsupported background mode: %s", mode);
+ wlr_log(WLR_ERROR, "Unsupported background mode: %s", mode);
return BACKGROUND_MODE_INVALID;
}
@@ -28,7 +28,7 @@ cairo_surface_t *load_background_image(const char *path) {
GError *err = NULL;
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &err);
if (!pixbuf) {
- wlr_log(L_ERROR, "Failed to load background image (%s).",
+ wlr_log(WLR_ERROR, "Failed to load background image (%s).",
err->message);
return false;
}
@@ -38,11 +38,11 @@ cairo_surface_t *load_background_image(const char *path) {
image = cairo_image_surface_create_from_png(path);
#endif //HAVE_GDK_PIXBUF
if (!image) {
- wlr_log(L_ERROR, "Failed to read background image.");
+ wlr_log(WLR_ERROR, "Failed to read background image.");
return NULL;
}
if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) {
- wlr_log(L_ERROR, "Failed to read background image: %s."
+ wlr_log(WLR_ERROR, "Failed to read background image: %s."
#ifndef HAVE_GDK_PIXBUF
"\nSway was compiled without gdk_pixbuf support, so only"
"\nPNG images can be loaded. This is the likely cause."
diff --git a/common/ipc-client.c b/common/ipc-client.c
index a88df080..4d2d88cc 100644
--- a/common/ipc-client.c
+++ b/common/ipc-client.c
@@ -97,7 +97,7 @@ struct ipc_response *ipc_recv_response(int socketfd) {
error_2:
free(response);
error_1:
- wlr_log(L_ERROR, "Unable to allocate memory for IPC response");
+ wlr_log(WLR_ERROR, "Unable to allocate memory for IPC response");
return NULL;
}
diff --git a/common/list.c b/common/list.c
index 39cc10e1..66d52f70 100644
--- a/common/list.c
+++ b/common/list.c
@@ -2,6 +2,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include "log.h"
list_t *create_list(void) {
list_t *list = malloc(sizeof(list_t));
@@ -82,6 +83,20 @@ void list_swap(list_t *list, int src, int dest) {
list->items[dest] = tmp;
}
+void list_move_to_end(list_t *list, void *item) {
+ int i;
+ for (i = 0; i < list->length; ++i) {
+ if (list->items[i] == item) {
+ break;
+ }
+ }
+ if (!sway_assert(i < list->length, "Item not found in list")) {
+ return;
+ }
+ list_del(list, i);
+ list_add(list, item);
+}
+
static void list_rotate(list_t *list, int from, int to) {
void *tmp = list->items[to];
diff --git a/common/log.c b/common/log.c
index 2cc7289c..847f3952 100644
--- a/common/log.c
+++ b/common/log.c
@@ -8,7 +8,7 @@ void sway_terminate(int code);
void _sway_abort(const char *format, ...) {
va_list args;
va_start(args, format);
- _wlr_vlog(L_ERROR, format, args);
+ _wlr_vlog(WLR_ERROR, format, args);
va_end(args);
sway_terminate(EXIT_FAILURE);
}
@@ -20,7 +20,7 @@ bool _sway_assert(bool condition, const char *format, ...) {
va_list args;
va_start(args, format);
- _wlr_vlog(L_ERROR, format, args);
+ _wlr_vlog(WLR_ERROR, format, args);
va_end(args);
#ifndef NDEBUG
diff --git a/common/pango.c b/common/pango.c
index c88e50ce..92703f80 100644
--- a/common/pango.c
+++ b/common/pango.c
@@ -81,7 +81,7 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
pango_layout_set_markup(layout, buf, -1);
free(buf);
} else {
- wlr_log(L_ERROR, "pango_parse_markup '%s' -> error %s", text,
+ wlr_log(WLR_ERROR, "pango_parse_markup '%s' -> error %s", text,
error->message);
g_error_free(error);
markup = false; // fallback to plain text
diff --git a/common/readline.c b/common/readline.c
index 1c396a90..a2c69018 100644
--- a/common/readline.c
+++ b/common/readline.c
@@ -9,7 +9,7 @@ char *read_line(FILE *file) {
char *string = malloc(size);
char lastChar = '\0';
if (!string) {
- wlr_log(L_ERROR, "Unable to allocate memory for read_line");
+ wlr_log(WLR_ERROR, "Unable to allocate memory for read_line");
return NULL;
}
while (1) {
@@ -30,7 +30,7 @@ char *read_line(FILE *file) {
char *new_string = realloc(string, size *= 2);
if (!new_string) {
free(string);
- wlr_log(L_ERROR, "Unable to allocate memory for read_line");
+ wlr_log(WLR_ERROR, "Unable to allocate memory for read_line");
return NULL;
}
string = new_string;
diff --git a/common/util.c b/common/util.c
index 678926ed..e8a88772 100644
--- a/common/util.c
+++ b/common/util.c
@@ -113,7 +113,7 @@ uint32_t parse_color(const char *color) {
int len = strlen(color);
if (len != 6 && len != 8) {
- wlr_log(L_DEBUG, "Invalid color %s, defaulting to color 0xFFFFFFFF", color);
+ wlr_log(WLR_DEBUG, "Invalid color %s, defaulting to color 0xFFFFFFFF", color);
return 0xFFFFFFFF;
}
uint32_t res = (uint32_t)strtoul(color, NULL, 16);
diff --git a/completions/zsh/_swaymsg b/completions/zsh/_swaymsg
index 6bb03279..2e39deb6 100644
--- a/completions/zsh/_swaymsg
+++ b/completions/zsh/_swaymsg
@@ -22,7 +22,6 @@ types=(
'get_marks'
'get_bar_config'
'get_version'
-'get_clipboard'
)
_arguments -s \
diff --git a/include/ipc.h b/include/ipc.h
index 8172c782..0010718b 100644
--- a/include/ipc.h
+++ b/include/ipc.h
@@ -13,11 +13,12 @@ enum ipc_command_type {
IPC_GET_MARKS = 5,
IPC_GET_BAR_CONFIG = 6,
IPC_GET_VERSION = 7,
+ IPC_GET_BINDING_MODES = 8,
+ IPC_GET_CONFIG = 9,
// sway-specific command types
IPC_GET_INPUTS = 100,
- IPC_GET_CLIPBOARD = 101,
- IPC_GET_SEATS = 102,
+ IPC_GET_SEATS = 101,
// Events sent from sway to clients. Events have the highest bits set.
IPC_EVENT_WORKSPACE = ((1<<31) | 0),
diff --git a/include/list.h b/include/list.h
index 7eead4ac..5a0d7d80 100644
--- a/include/list.h
+++ b/include/list.h
@@ -24,4 +24,6 @@ int list_seq_find(list_t *list, int compare(const void *item, const void *cmp_to
void list_stable_sort(list_t *list, int compare(const void *a, const void *b));
// swap two elements in a list
void list_swap(list_t *list, int src, int dest);
+// move item to end of list
+void list_move_to_end(list_t *list, void *item);
#endif
diff --git a/include/log.h b/include/log.h
index a9748127..dd526143 100644
--- a/include/log.h
+++ b/include/log.h
@@ -3,13 +3,19 @@
#include <stdbool.h>
#include <wlr/util/log.h>
+#ifdef __GNUC__
+#define ATTRIB_PRINTF(start, end) __attribute__((format(printf, start, end)))
+#else
+#define ATTRIB_PRINTF(start, end)
+#endif
+
void _sway_abort(const char *filename, ...) ATTRIB_PRINTF(1, 2);
#define sway_abort(FMT, ...) \
- _sway_abort("[%s:%d] " FMT, wlr_strip_path(__FILE__), __LINE__, ##__VA_ARGS__)
+ _sway_abort("[%s:%d] " FMT, _wlr_strip_path(__FILE__), __LINE__, ##__VA_ARGS__)
bool _sway_assert(bool condition, const char* format, ...) ATTRIB_PRINTF(2, 3);
#define sway_assert(COND, FMT, ...) \
- _sway_assert(COND, "[%s:%d] %s:" FMT, wlr_strip_path(__FILE__), __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)
+ _sway_assert(COND, "[%s:%d] %s:" FMT, _wlr_strip_path(__FILE__), __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)
void error_handler(int sig);
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 6d17144a..1e93e2a3 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -95,7 +95,6 @@ sway_cmd cmd_client_unfocused;
sway_cmd cmd_client_urgent;
sway_cmd cmd_client_placeholder;
sway_cmd cmd_client_background;
-sway_cmd cmd_clipboard;
sway_cmd cmd_commands;
sway_cmd cmd_debuglog;
sway_cmd cmd_default_border;
@@ -153,6 +152,7 @@ sway_cmd cmd_swaybg_command;
sway_cmd cmd_swap;
sway_cmd cmd_title_format;
sway_cmd cmd_unmark;
+sway_cmd cmd_urgent;
sway_cmd cmd_workspace;
sway_cmd cmd_ws_auto_back_and_forth;
sway_cmd cmd_workspace_layout;
@@ -208,8 +208,10 @@ sway_cmd input_cmd_natural_scroll;
sway_cmd input_cmd_pointer_accel;
sway_cmd input_cmd_repeat_delay;
sway_cmd input_cmd_repeat_rate;
+sway_cmd input_cmd_scroll_button;
sway_cmd input_cmd_scroll_method;
sway_cmd input_cmd_tap;
+sway_cmd input_cmd_tap_button_map;
sway_cmd input_cmd_xkb_layout;
sway_cmd input_cmd_xkb_model;
sway_cmd input_cmd_xkb_options;
diff --git a/include/sway/config.h b/include/sway/config.h
index ac668c24..f660a269 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -75,9 +75,11 @@ struct input_config {
float pointer_accel;
int repeat_delay;
int repeat_rate;
+ int scroll_button;
int scroll_method;
int send_events;
int tap;
+ int tap_button_map;
char *xkb_layout;
char *xkb_model;
@@ -271,11 +273,10 @@ enum ipc_feature {
IPC_FEATURE_EVENT_WINDOW = 2048,
IPC_FEATURE_EVENT_BINDING = 4096,
IPC_FEATURE_EVENT_INPUT = 8192,
- IPC_FEATURE_GET_CLIPBOARD = 16384,
- IPC_FEATURE_GET_SEATS = 32768,
+ IPC_FEATURE_GET_SEATS = 16384,
IPC_FEATURE_ALL_COMMANDS =
- 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 16384 | 32768,
+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 16384,
IPC_FEATURE_ALL_EVENTS = 256 | 512 | 1024 | 2048 | 4096 | 8192,
IPC_FEATURE_ALL = IPC_FEATURE_ALL_COMMANDS | IPC_FEATURE_ALL_EVENTS,
@@ -341,6 +342,7 @@ struct sway_config {
int gaps_outer;
list_t *config_chain;
+ const char *current_config_path;
const char *current_config;
enum sway_container_border border;
@@ -496,7 +498,4 @@ void config_update_font_height(bool recalculate);
/* Global config singleton. */
extern struct sway_config *config;
-/* Config file currently being read */
-extern const char *current_config_path;
-
#endif
diff --git a/include/sway/criteria.h b/include/sway/criteria.h
index bd3ca0ac..6a8337c5 100644
--- a/include/sway/criteria.h
+++ b/include/sway/criteria.h
@@ -6,9 +6,10 @@
#include "tree/view.h"
enum criteria_type {
- CT_COMMAND = 1 << 0,
- CT_ASSIGN_OUTPUT = 1 << 1,
+ CT_COMMAND = 1 << 0,
+ CT_ASSIGN_OUTPUT = 1 << 1,
CT_ASSIGN_WORKSPACE = 1 << 2,
+ CT_NO_FOCUS = 1 << 3,
};
struct criteria {
diff --git a/include/sway/debug.h b/include/sway/debug.h
index 2430d319..38d4eccd 100644
--- a/include/sway/debug.h
+++ b/include/sway/debug.h
@@ -1,7 +1,15 @@
#ifndef SWAY_DEBUG_H
#define SWAY_DEBUG_H
+// Tree
extern bool enable_debug_tree;
void update_debug_tree();
+// Damage
+extern const char *damage_debug;
+
+// Transactions
+extern int txn_timeout_ms;
+extern bool txn_debug;
+
#endif
diff --git a/include/sway/desktop.h b/include/sway/desktop.h
index f1ad759a..348fb187 100644
--- a/include/sway/desktop.h
+++ b/include/sway/desktop.h
@@ -1,4 +1,8 @@
#include <wlr/types/wlr_surface.h>
+struct sway_container;
+
void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
bool whole);
+
+void desktop_damage_whole_container(struct sway_container *con);
diff --git a/include/sway/desktop/transaction.h b/include/sway/desktop/transaction.h
index 7ab80eb8..cee4afed 100644
--- a/include/sway/desktop/transaction.h
+++ b/include/sway/desktop/transaction.h
@@ -6,34 +6,25 @@
/**
* Transactions enable us to perform atomic layout updates.
*
- * When we want to make adjustments to the layout, we create a transaction.
- * A transaction contains a list of affected containers and their new state.
+ * A transaction contains a list of containers and their new state.
* A state might contain a new size, or new border settings, or new parent/child
* relationships.
*
- * Calling transaction_commit() makes sway notify of all the affected clients
- * with their new sizes. We then wait for all the views to respond with their
- * new surface sizes. When all are ready, or when a timeout has passed, we apply
- * the updates all at the same time.
- */
-
-struct sway_transaction;
-
-/**
- * Create a new transaction.
- */
-struct sway_transaction *transaction_create(void);
-
-/**
- * Add a container's pending state to the transaction.
+ * Committing a transaction makes sway notify of all the affected clients with
+ * their new sizes. We then wait for all the views to respond with their new
+ * surface sizes. When all are ready, or when a timeout has passed, we apply the
+ * updates all at the same time.
+ *
+ * When we want to make adjustments to the layout, we change the pending state
+ * in containers, mark them as dirty and call transaction_commit_dirty(). This
+ * create and commits a transaction from the dirty containers.
*/
-void transaction_add_container(struct sway_transaction *transaction,
- struct sway_container *container);
/**
- * Submit a transaction to the client views for configuration.
+ * Find all dirty containers, create and commit a transaction containing them,
+ * and unmark them as dirty.
*/
-void transaction_commit(struct sway_transaction *transaction);
+void transaction_commit_dirty(void);
/**
* Notify the transaction system that a view is ready for the new layout.
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index 0e440701..1f7792ba 100644
--- a/include/sway/input/seat.h
+++ b/include/sway/input/seat.h
@@ -119,17 +119,6 @@ struct sway_container *seat_get_active_child(struct sway_seat *seat,
struct sway_container *container);
/**
- * Return the immediate child of container which was most recently focused, with
- * fallback to selecting the child in the parent's `current` (rendered) children
- * list.
- *
- * This is useful for when a tabbed container and its children are destroyed but
- * still being rendered, and we have to render an appropriate child.
- */
-struct sway_container *seat_get_active_current_child(struct sway_seat *seat,
- struct sway_container *container);
-
-/**
* Iterate over the focus-inactive children of the container calling the
* function on each.
*/
diff --git a/include/sway/server.h b/include/sway/server.h
index a3e32898..a017d1c4 100644
--- a/include/sway/server.h
+++ b/include/sway/server.h
@@ -47,10 +47,7 @@ struct sway_server {
bool debug_txn_timings;
list_t *transactions;
-
- // When a view is being destroyed and is waiting for a transaction to
- // complete it will be stored here.
- list_t *destroying_containers;
+ list_t *dirty_containers;
};
struct sway_server server;
diff --git a/include/sway/tree/arrange.h b/include/sway/tree/arrange.h
index 58235642..d6abcc81 100644
--- a/include/sway/tree/arrange.h
+++ b/include/sway/tree/arrange.h
@@ -11,26 +11,8 @@ void remove_gaps(struct sway_container *c);
void add_gaps(struct sway_container *c);
/**
- * Arrange layout for all the children of the given container, and add them to
- * the given transaction.
- *
- * Use this function if you need to arrange multiple sections of the tree in one
- * transaction.
- *
- * You must set the desired state of the container before calling
- * arrange_windows, then don't change any state-tracked properties in the
- * container until you've called transaction_commit.
+ * Arrange layout for all the children of the given container.
*/
-void arrange_windows(struct sway_container *container,
- struct sway_transaction *transaction);
-
-/**
- * Arrange layout for the given container and commit the transaction.
- *
- * This function is a wrapper around arrange_windows, and handles creating and
- * committing the transaction for you. Use this function if you're only doing
- * one arrange operation.
- */
-void arrange_and_commit(struct sway_container *container);
+void arrange_windows(struct sway_container *container);
#endif
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 728daa84..ca7a3288 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -68,6 +68,9 @@ struct sway_container_state {
struct sway_container *parent;
list_t *children;
+ struct sway_container *focused_inactive_child;
+ bool focused;
+
// View properties
double view_x, view_y;
double view_width, view_height;
@@ -144,6 +147,10 @@ struct sway_container {
bool destroying;
+ // If true, indicates that the container has pending state that differs from
+ // the current.
+ bool dirty;
+
struct {
struct wl_signal destroy;
// Raised after the tree updates, but before arrange_windows
@@ -297,4 +304,18 @@ bool container_is_floating(struct sway_container *container);
*/
void container_get_box(struct sway_container *container, struct wlr_box *box);
+/**
+ * Move a floating container to a new layout-local position.
+ */
+void container_floating_move_to(struct sway_container *con,
+ double lx, double ly);
+
+/**
+ * Mark a container as dirty if it isn't already. Dirty containers will be
+ * included in the next transaction then unmarked as dirty.
+ */
+void container_set_dirty(struct sway_container *container);
+
+bool container_has_urgent_child(struct sway_container *container);
+
#endif
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index 7dc8ac46..e270f851 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -35,6 +35,7 @@ struct sway_view_impl {
void (*set_tiled)(struct sway_view *view, bool tiled);
void (*set_fullscreen)(struct sway_view *view, bool fullscreen);
bool (*wants_floating)(struct sway_view *view);
+ bool (*has_client_side_decorations)(struct sway_view *view);
void (*for_each_surface)(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data);
void (*close)(struct sway_view *view);
@@ -68,6 +69,11 @@ struct sway_view {
bool border_bottom;
bool border_left;
bool border_right;
+ bool using_csd;
+
+ struct timespec urgent;
+ bool allow_request_urgent;
+ struct wl_event_source *urgent_timer;
bool destroying;
@@ -304,4 +310,8 @@ void view_update_marks_textures(struct sway_view *view);
*/
bool view_is_visible(struct sway_view *view);
+void view_set_urgent(struct sway_view *view, bool enable);
+
+bool view_is_urgent(struct sway_view *view);
+
#endif
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h
index c72a4ac0..bc95317a 100644
--- a/include/sway/tree/workspace.h
+++ b/include/sway/tree/workspace.h
@@ -10,6 +10,7 @@ struct sway_workspace {
struct sway_view *fullscreen;
struct sway_container *floating;
list_t *output_priority;
+ bool urgent;
};
extern char *prev_workspace_name;
@@ -42,4 +43,7 @@ void workspace_output_add_priority(struct sway_container *workspace,
struct sway_container *workspace_output_get_highest_available(
struct sway_container *ws, struct sway_container *exclude);
+
+void workspace_detect_urgent(struct sway_container *workspace);
+
#endif
diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h
index af478f33..f1ff25b2 100644
--- a/include/swaybar/bar.h
+++ b/include/swaybar/bar.h
@@ -16,11 +16,24 @@ struct swaybar_pointer {
int x, y;
};
+enum x11_button {
+ NONE,
+ LEFT,
+ MIDDLE,
+ RIGHT,
+ SCROLL_UP,
+ SCROLL_DOWN,
+ SCROLL_LEFT,
+ SCROLL_RIGHT,
+ BACK,
+ FORWARD,
+};
+
struct swaybar_hotspot {
struct wl_list link;
int x, y, width, height;
void (*callback)(struct swaybar_output *output,
- int x, int y, uint32_t button, void *data);
+ int x, int y, enum x11_button button, void *data);
void (*destroy)(void *data);
void *data;
};
diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h
index bf12a842..2eaf8140 100644
--- a/include/swaybar/status_line.h
+++ b/include/swaybar/status_line.h
@@ -72,7 +72,9 @@ bool status_handle_readable(struct status_line *status);
void status_line_free(struct status_line *status);
bool i3bar_handle_readable(struct status_line *status);
void i3bar_block_send_click(struct status_line *status,
- struct i3bar_block *block, int x, int y, uint32_t button);
+ struct i3bar_block *block, int x, int y, enum x11_button button);
void i3bar_block_free(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 cf80a6ba..950cfaaf 100644
--- a/include/swaylock/swaylock.h
+++ b/include/swaylock/swaylock.h
@@ -19,9 +19,31 @@ enum auth_state {
AUTH_STATE_INVALID,
};
+struct swaylock_colorset {
+ uint32_t input;
+ uint32_t cleared;
+ uint32_t verifying;
+ uint32_t wrong;
+};
+
+struct swaylock_colors {
+ uint32_t background;
+ uint32_t bs_highlight;
+ uint32_t key_highlight;
+ uint32_t separator;
+ struct swaylock_colorset inside;
+ struct swaylock_colorset line;
+ struct swaylock_colorset ring;
+ struct swaylock_colorset text;
+};
+
struct swaylock_args {
- uint32_t color;
+ struct swaylock_colors colors;
enum background_mode mode;
+ char *font;
+ uint32_t radius;
+ uint32_t thickness;
+ bool ignore_empty;
bool show_indicator;
bool daemonize;
};
diff --git a/sway/commands.c b/sway/commands.c
index ef477f38..a3e6a500 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -98,8 +98,11 @@ static struct cmd_handler handlers[] = {
{ "client.unfocused", cmd_client_unfocused },
{ "client.urgent", cmd_client_urgent },
{ "default_border", cmd_default_border },
+ { "default_floating_border", cmd_default_floating_border },
{ "exec", cmd_exec },
{ "exec_always", cmd_exec_always },
+ { "floating_maximum_size", cmd_floating_maximum_size },
+ { "floating_minimum_size", cmd_floating_minimum_size },
{ "focus_follows_mouse", cmd_focus_follows_mouse },
{ "focus_wrapping", cmd_focus_wrapping },
{ "font", cmd_font },
@@ -112,6 +115,7 @@ static struct cmd_handler handlers[] = {
{ "input", cmd_input },
{ "mode", cmd_mode },
{ "mouse_warping", cmd_mouse_warping },
+ { "no_focus", cmd_no_focus },
{ "output", cmd_output },
{ "seat", cmd_seat },
{ "set", cmd_set },
@@ -151,6 +155,7 @@ static struct cmd_handler command_handlers[] = {
{ "swap", cmd_swap },
{ "title_format", cmd_title_format },
{ "unmark", cmd_unmark },
+ { "urgent", cmd_urgent },
};
static int handler_compare(const void *_a, const void *_b) {
@@ -163,7 +168,7 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers,
int handlers_size) {
struct cmd_handler d = { .command=line };
struct cmd_handler *res = NULL;
- wlr_log(L_DEBUG, "find_handler(%s)", line);
+ wlr_log(WLR_DEBUG, "find_handler(%s)", line);
bool config_loading = config->reading || !config->active;
@@ -248,10 +253,10 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
cmd = argsep(&cmdlist, ",");
cmd += strspn(cmd, whitespace);
if (strcmp(cmd, "") == 0) {
- wlr_log(L_INFO, "Ignoring empty command.");
+ wlr_log(WLR_INFO, "Ignoring empty command.");
continue;
}
- wlr_log(L_INFO, "Handling command '%s'", cmd);
+ wlr_log(WLR_INFO, "Handling command '%s'", cmd);
//TODO better handling of argv
int argc;
char **argv = split_args(cmd, &argc);
@@ -344,7 +349,7 @@ struct cmd_results *config_command(char *exec) {
// Start block
if (argc > 1 && strcmp(argv[argc - 1], "{") == 0) {
- char *block = join_args(argv, argc - 1);
+ char *block = join_args(argv, argc - 1);
results = cmd_results_new(CMD_BLOCK, block, NULL);
free(block);
goto cleanup;
@@ -355,7 +360,7 @@ struct cmd_results *config_command(char *exec) {
results = cmd_results_new(CMD_BLOCK_END, NULL, NULL);
goto cleanup;
}
- wlr_log(L_INFO, "handling config command '%s'", exec);
+ wlr_log(WLR_INFO, "handling config command '%s'", exec);
struct cmd_handler *handler = find_handler(argv[0], NULL, 0);
if (!handler) {
char *input = argv[0] ? argv[0] : "(empty)";
@@ -388,7 +393,7 @@ cleanup:
struct cmd_results *config_subcommand(char **argv, int argc,
struct cmd_handler *handlers, size_t handlers_size) {
char *command = join_args(argv, argc);
- wlr_log(L_DEBUG, "Subcommand: %s", command);
+ wlr_log(WLR_DEBUG, "Subcommand: %s", command);
free(command);
struct cmd_handler *handler = find_handler(argv[0], handlers,
@@ -479,7 +484,7 @@ struct cmd_results *config_commands_command(char *exec) {
}
policy->context = context;
- wlr_log(L_INFO, "Set command policy for %s to %d",
+ wlr_log(WLR_INFO, "Set command policy for %s to %d",
policy->command, policy->context);
results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
@@ -493,7 +498,7 @@ struct cmd_results *cmd_results_new(enum cmd_status status,
const char *input, const char *format, ...) {
struct cmd_results *results = malloc(sizeof(struct cmd_results));
if (!results) {
- wlr_log(L_ERROR, "Unable to allocate command results");
+ wlr_log(WLR_ERROR, "Unable to allocate command results");
return NULL;
}
results->status = status;
diff --git a/sway/commands/assign.c b/sway/commands/assign.c
index a90498ce..0bc0929a 100644
--- a/sway/commands/assign.c
+++ b/sway/commands/assign.c
@@ -45,7 +45,7 @@ struct cmd_results *cmd_assign(int argc, char **argv) {
criteria->target = join_args(argv, target_len);
list_add(config->criteria, criteria);
- wlr_log(L_DEBUG, "assign: '%s' -> '%s' added", criteria->raw,
+ wlr_log(WLR_DEBUG, "assign: '%s' -> '%s' added", criteria->raw,
criteria->target);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/bar.c b/sway/commands/bar.c
index d84ce808..f6a70c17 100644
--- a/sway/commands/bar.c
+++ b/sway/commands/bar.c
@@ -63,13 +63,13 @@ struct cmd_results *cmd_bar(int argc, char **argv) {
for (int i = 0; i < config->bars->length; ++i) {
struct bar_config *item = config->bars->items[i];
if (strcmp(item->id, argv[0]) == 0) {
- wlr_log(L_DEBUG, "Selecting bar: %s", argv[0]);
+ wlr_log(WLR_DEBUG, "Selecting bar: %s", argv[0]);
bar = item;
break;
}
}
if (!bar) {
- wlr_log(L_DEBUG, "Creating bar: %s", argv[0]);
+ wlr_log(WLR_DEBUG, "Creating bar: %s", argv[0]);
bar = default_bar_config();
if (!bar) {
return cmd_results_new(CMD_FAILURE, "bar",
@@ -108,7 +108,7 @@ struct cmd_results *cmd_bar(int argc, char **argv) {
// Set current bar
config->current_bar = bar;
- wlr_log(L_DEBUG, "Creating bar %s", bar->id);
+ wlr_log(WLR_DEBUG, "Creating bar %s", bar->id);
}
return config_subcommand(argv, argc, bar_handlers, sizeof(bar_handlers));
diff --git a/sway/commands/bar/binding_mode_indicator.c b/sway/commands/bar/binding_mode_indicator.c
index 3ba5f33f..0c48bee9 100644
--- a/sway/commands/bar/binding_mode_indicator.c
+++ b/sway/commands/bar/binding_mode_indicator.c
@@ -15,11 +15,11 @@ struct cmd_results *bar_cmd_binding_mode_indicator(int argc, char **argv) {
}
if (strcasecmp("yes", argv[0]) == 0) {
config->current_bar->binding_mode_indicator = true;
- wlr_log(L_DEBUG, "Enabling binding mode indicator on bar: %s",
+ wlr_log(WLR_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",
+ wlr_log(WLR_DEBUG, "Disabling binding mode indicator on bar: %s",
config->current_bar->id);
}
return cmd_results_new(CMD_INVALID, "binding_mode_indicator",
diff --git a/sway/commands/bar/font.c b/sway/commands/bar/font.c
index f036cbc3..2aa4e895 100644
--- a/sway/commands/bar/font.c
+++ b/sway/commands/bar/font.c
@@ -15,7 +15,7 @@ struct cmd_results *bar_cmd_font(int argc, char **argv) {
char *font = join_args(argv, argc);
free(config->current_bar->font);
config->current_bar->font = font;
- wlr_log(L_DEBUG, "Settings font '%s' for bar: %s",
+ wlr_log(WLR_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
index 3160caed..18258526 100644
--- a/sway/commands/bar/height.c
+++ b/sway/commands/bar/height.c
@@ -14,7 +14,7 @@ struct cmd_results *bar_cmd_height(int argc, char **argv) {
"Invalid height value: %s", argv[0]);
}
config->current_bar->height = height;
- wlr_log(L_DEBUG, "Setting bar height to %d on bar: %s",
+ wlr_log(WLR_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
index 6641f184..502ce2c4 100644
--- a/sway/commands/bar/hidden_state.c
+++ b/sway/commands/bar/hidden_state.c
@@ -27,7 +27,7 @@ static struct cmd_results *bar_set_hidden_state(struct bar_config *bar,
if (!config->reading) {
ipc_event_barconfig_update(bar);
}
- wlr_log(L_DEBUG, "Setting hidden_state: '%s' for bar: %s",
+ wlr_log(WLR_DEBUG, "Setting hidden_state: '%s' for bar: %s",
bar->hidden_state, bar->id);
}
// free old mode
diff --git a/sway/commands/bar/id.c b/sway/commands/bar/id.c
index 6ce86fef..65fa69fd 100644
--- a/sway/commands/bar/id.c
+++ b/sway/commands/bar/id.c
@@ -24,7 +24,7 @@ struct cmd_results *bar_cmd_id(int argc, char **argv) {
}
}
- wlr_log(L_DEBUG, "Renaming bar: '%s' to '%s'", oldname, name);
+ wlr_log(WLR_DEBUG, "Renaming bar: '%s' to '%s'", oldname, name);
// free old bar id
free(config->current_bar->id);
diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c
index 34bb0a4f..28e2d77b 100644
--- a/sway/commands/bar/mode.c
+++ b/sway/commands/bar/mode.c
@@ -28,7 +28,7 @@ static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode
if (!config->reading) {
ipc_event_barconfig_update(bar);
}
- wlr_log(L_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id);
+ wlr_log(WLR_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id);
}
// free old mode
diff --git a/sway/commands/bar/modifier.c b/sway/commands/bar/modifier.c
index 02f845e6..09025fff 100644
--- a/sway/commands/bar/modifier.c
+++ b/sway/commands/bar/modifier.c
@@ -30,7 +30,7 @@ struct cmd_results *bar_cmd_modifier(int argc, char **argv) {
}
free_flat_list(split);
config->current_bar->modifier = mod;
- wlr_log(L_DEBUG,
+ wlr_log(WLR_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
index f7ca0aa4..72754e05 100644
--- a/sway/commands/bar/output.c
+++ b/sway/commands/bar/output.c
@@ -42,7 +42,7 @@ struct cmd_results *bar_cmd_output(int argc, char **argv) {
if (add_output) {
list_add(outputs, strdup(output));
- wlr_log(L_DEBUG, "Adding bar: '%s' to output '%s'",
+ wlr_log(WLR_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
index 480af724..857571fb 100644
--- a/sway/commands/bar/pango_markup.c
+++ b/sway/commands/bar/pango_markup.c
@@ -13,11 +13,11 @@ struct cmd_results *bar_cmd_pango_markup(int argc, char **argv) {
}
if (strcasecmp("enabled", argv[0]) == 0) {
config->current_bar->pango_markup = true;
- wlr_log(L_DEBUG, "Enabling pango markup for bar: %s",
+ wlr_log(WLR_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",
+ wlr_log(WLR_DEBUG, "Disabling pango markup for bar: %s",
config->current_bar->id);
} else {
error = cmd_results_new(CMD_INVALID, "pango_markup",
diff --git a/sway/commands/bar/position.c b/sway/commands/bar/position.c
index 9c580483..44bb4ae3 100644
--- a/sway/commands/bar/position.c
+++ b/sway/commands/bar/position.c
@@ -15,8 +15,9 @@ struct cmd_results *bar_cmd_position(int argc, char **argv) {
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",
+ wlr_log(WLR_DEBUG, "Setting bar position '%s' for bar: %s",
argv[0], config->current_bar->id);
+ free(config->current_bar->position);
config->current_bar->position = strdup(argv[0]);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/bar/separator_symbol.c b/sway/commands/bar/separator_symbol.c
index 1e08df6d..392ab730 100644
--- a/sway/commands/bar/separator_symbol.c
+++ b/sway/commands/bar/separator_symbol.c
@@ -14,7 +14,7 @@ struct cmd_results *bar_cmd_separator_symbol(int argc, char **argv) {
}
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",
+ wlr_log(WLR_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
index 5e199cde..6f6f81a3 100644
--- a/sway/commands/bar/status_command.c
+++ b/sway/commands/bar/status_command.c
@@ -14,7 +14,7 @@ struct cmd_results *bar_cmd_status_command(int argc, char **argv) {
}
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",
+ wlr_log(WLR_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
index 4f24a356..4e47d047 100644
--- a/sway/commands/bar/strip_workspace_numbers.c
+++ b/sway/commands/bar/strip_workspace_numbers.c
@@ -15,11 +15,11 @@ struct cmd_results *bar_cmd_strip_workspace_numbers(int argc, char **argv) {
}
if (strcasecmp("yes", argv[0]) == 0) {
config->current_bar->strip_workspace_numbers = true;
- wlr_log(L_DEBUG, "Stripping workspace numbers on bar: %s",
+ wlr_log(WLR_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",
+ wlr_log(WLR_DEBUG, "Enabling workspace numbers on bar: %s",
config->current_bar->id);
} else {
return cmd_results_new(CMD_INVALID,
diff --git a/sway/commands/bar/swaybar_command.c b/sway/commands/bar/swaybar_command.c
index 520cdd11..04e78e77 100644
--- a/sway/commands/bar/swaybar_command.c
+++ b/sway/commands/bar/swaybar_command.c
@@ -14,7 +14,7 @@ struct cmd_results *bar_cmd_swaybar_command(int argc, char **argv) {
}
free(config->current_bar->swaybar_command);
config->current_bar->swaybar_command = join_args(argv, argc);
- wlr_log(L_DEBUG, "Using custom swaybar command: %s",
+ wlr_log(WLR_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/workspace_buttons.c b/sway/commands/bar/workspace_buttons.c
index 6edc3a0d..a4079b2a 100644
--- a/sway/commands/bar/workspace_buttons.c
+++ b/sway/commands/bar/workspace_buttons.c
@@ -14,11 +14,11 @@ struct cmd_results *bar_cmd_workspace_buttons(int argc, char **argv) {
}
if (strcasecmp("yes", argv[0]) == 0) {
config->current_bar->workspace_buttons = true;
- wlr_log(L_DEBUG, "Enabling workspace buttons on bar: %s",
+ wlr_log(WLR_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",
+ wlr_log(WLR_DEBUG, "Disabling workspace buttons on bar: %s",
config->current_bar->id);
} else {
return cmd_results_new(CMD_INVALID, "workspace_buttons",
diff --git a/sway/commands/bar/wrap_scroll.c b/sway/commands/bar/wrap_scroll.c
index 7386f82c..701de00a 100644
--- a/sway/commands/bar/wrap_scroll.c
+++ b/sway/commands/bar/wrap_scroll.c
@@ -13,11 +13,11 @@ struct cmd_results *bar_cmd_wrap_scroll(int argc, char **argv) {
}
if (strcasecmp("yes", argv[0]) == 0) {
config->current_bar->wrap_scroll = true;
- wlr_log(L_DEBUG, "Enabling wrap scroll on bar: %s",
+ wlr_log(WLR_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",
+ wlr_log(WLR_DEBUG, "Disabling wrap scroll on bar: %s",
config->current_bar->id);
} else {
return cmd_results_new(CMD_INVALID,
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index 821f9cd1..83e9e432 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -184,7 +184,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
for (int i = 0; i < mode_bindings->length; ++i) {
struct sway_binding *config_binding = mode_bindings->items[i];
if (binding_key_compare(binding, config_binding)) {
- wlr_log(L_DEBUG, "overwriting old binding with command '%s'",
+ wlr_log(WLR_DEBUG, "overwriting old binding with command '%s'",
config_binding->command);
free_sway_binding(config_binding);
mode_bindings->items[i] = binding;
@@ -196,7 +196,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
list_add(mode_bindings, binding);
}
- wlr_log(L_DEBUG, "%s - Bound %s to command %s",
+ wlr_log(WLR_DEBUG, "%s - Bound %s to command %s",
bindtype, argv[0], binding->command);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/border.c b/sway/commands/border.c
index 6db85395..9c19e20a 100644
--- a/sway/commands/border.c
+++ b/sway/commands/border.c
@@ -42,7 +42,7 @@ struct cmd_results *cmd_border(int argc, char **argv) {
container_set_geometry_from_floating_view(view->swayc);
}
- arrange_and_commit(view->swayc);
+ arrange_windows(view->swayc);
struct sway_seat *seat = input_manager_current_seat(input_manager);
if (seat->cursor) {
diff --git a/sway/commands/default_floating_border.c b/sway/commands/default_floating_border.c
new file mode 100644
index 00000000..1bfc24af
--- /dev/null
+++ b/sway/commands/default_floating_border.c
@@ -0,0 +1,29 @@
+#include "log.h"
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/tree/container.h"
+
+struct cmd_results *cmd_default_floating_border(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "default_floating_border",
+ EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+
+ if (strcmp(argv[0], "none") == 0) {
+ config->floating_border = B_NONE;
+ } else if (strcmp(argv[0], "normal") == 0) {
+ config->floating_border = B_NORMAL;
+ } else if (strcmp(argv[0], "pixel") == 0) {
+ config->floating_border = B_PIXEL;
+ } else {
+ return cmd_results_new(CMD_INVALID, "default_floating_border",
+ "Expected 'default_floating_border <none|normal|pixel>' "
+ "or 'default_floating_border <normal|pixel> <px>'");
+ }
+ if (argc == 2) {
+ config->floating_border_thickness = atoi(argv[1]);
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/exec.c b/sway/commands/exec.c
index 363d5bef..7fc54123 100644
--- a/sway/commands/exec.c
+++ b/sway/commands/exec.c
@@ -8,7 +8,7 @@ struct cmd_results *cmd_exec(int argc, char **argv) {
if (!config->active) return cmd_results_new(CMD_DEFER, "exec", NULL);
if (config->reloading) {
char *args = join_args(argv, argc);
- wlr_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args);
+ wlr_log(WLR_DEBUG, "Ignoring 'exec %s' due to reload", args);
free(args);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c
index 1c99de97..c7727857 100644
--- a/sway/commands/exec_always.c
+++ b/sway/commands/exec_always.c
@@ -20,7 +20,7 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
char *tmp = NULL;
if (strcmp((char*)*argv, "--no-startup-id") == 0) {
- wlr_log(L_INFO, "exec switch '--no-startup-id' not supported, ignored.");
+ wlr_log(WLR_INFO, "exec switch '--no-startup-id' not supported, ignored.");
if ((error = checkarg(argc - 1, "exec_always", EXPECTED_MORE_THAN, 0))) {
return error;
}
@@ -35,11 +35,11 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
strncpy(cmd, tmp, sizeof(cmd) - 1);
cmd[sizeof(cmd) - 1] = 0;
free(tmp);
- wlr_log(L_DEBUG, "Executing %s", cmd);
+ wlr_log(WLR_DEBUG, "Executing %s", cmd);
int fd[2];
if (pipe(fd) != 0) {
- wlr_log(L_ERROR, "Unable to create pipe for fork");
+ wlr_log(WLR_ERROR, "Unable to create pipe for fork");
}
pid_t pid, child;
@@ -73,7 +73,7 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) {
// cleanup child process
waitpid(pid, NULL, 0);
if (child > 0) {
- wlr_log(L_DEBUG, "Child process created with pid %d", child);
+ wlr_log(WLR_DEBUG, "Child process created with pid %d", child);
// TODO: add PID to active workspace
} else {
return cmd_results_new(CMD_FAILURE, "exec_always",
diff --git a/sway/commands/floating.c b/sway/commands/floating.c
index e6003521..6ab56c3b 100644
--- a/sway/commands/floating.c
+++ b/sway/commands/floating.c
@@ -37,7 +37,7 @@ struct cmd_results *cmd_floating(int argc, char **argv) {
container_set_floating(container, wants_floating);
struct sway_container *workspace = container_parent(container, C_WORKSPACE);
- arrange_and_commit(workspace);
+ arrange_windows(workspace);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/floating_minmax_size.c b/sway/commands/floating_minmax_size.c
new file mode 100644
index 00000000..0af78908
--- /dev/null
+++ b/sway/commands/floating_minmax_size.c
@@ -0,0 +1,53 @@
+#include <errno.h>
+#include <math.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <wlr/util/log.h>
+#include "sway/commands.h"
+#include "log.h"
+
+static const char* min_usage =
+ "Expected 'floating_minimum_size <width> x <height>'";
+
+static const char* max_usage =
+ "Expected 'floating_maximum_size <width> x <height>'";
+
+static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
+ const char *usage, int *config_width, int *config_height) {
+ struct cmd_results *error;
+ if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 3))) {
+ return error;
+ }
+
+ char *err;
+ int width = (int)strtol(argv[0], &err, 10);
+ if (*err) {
+ return cmd_results_new(CMD_INVALID, cmd_name, usage);
+ }
+
+ if (strcmp(argv[1], "x") != 0) {
+ return cmd_results_new(CMD_INVALID, cmd_name, usage);
+ }
+
+ int height = (int)strtol(argv[2], &err, 10);
+ if (*err) {
+ return cmd_results_new(CMD_INVALID, cmd_name, usage);
+ }
+
+ *config_width = width;
+ *config_height = height;
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
+
+struct cmd_results *cmd_floating_minimum_size(int argc, char **argv) {
+ return handle_command(argc, argv, "floating_minimum_size", min_usage,
+ &config->floating_minimum_width, &config->floating_minimum_height);
+}
+
+struct cmd_results *cmd_floating_maximum_size(int argc, char **argv) {
+ return handle_command(argc, argv, "floating_maximum_size", max_usage,
+ &config->floating_maximum_width, &config->floating_maximum_height);
+}
diff --git a/sway/commands/focus.c b/sway/commands/focus.c
index 74d9d535..b24d5007 100644
--- a/sway/commands/focus.c
+++ b/sway/commands/focus.c
@@ -1,10 +1,12 @@
#include <strings.h>
#include <wlr/util/log.h>
#include "log.h"
+#include "sway/commands.h"
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
+#include "sway/tree/arrange.h"
#include "sway/tree/view.h"
-#include "sway/commands.h"
+#include "sway/tree/workspace.h"
static bool parse_movement_direction(const char *name,
enum movement_direction *out) {
@@ -27,6 +29,21 @@ static bool parse_movement_direction(const char *name,
return true;
}
+static struct cmd_results *focus_mode(struct sway_container *con,
+ struct sway_seat *seat, bool floating) {
+ struct sway_container *ws = con->type == C_WORKSPACE ?
+ con : container_parent(con, C_WORKSPACE);
+ struct sway_container *new_focus = ws;
+ if (floating) {
+ new_focus = ws->sway_workspace->floating;
+ if (new_focus->children->length == 0) {
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ }
+ }
+ seat_set_focus(seat, seat_get_active_child(seat, new_focus));
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
+
struct cmd_results *cmd_focus(int argc, char **argv) {
struct sway_container *con = config->handler_context.current_container;
struct sway_seat *seat = config->handler_context.seat;
@@ -40,11 +57,20 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
- // TODO mode_toggle
+ if (strcmp(argv[0], "floating") == 0) {
+ return focus_mode(con, seat, true);
+ } else if (strcmp(argv[0], "tiling") == 0) {
+ return focus_mode(con, seat, false);
+ } else if (strcmp(argv[0], "mode_toggle") == 0) {
+ return focus_mode(con, seat, !container_is_floating(con));
+ }
+
+ // TODO: focus output <direction|name>
enum movement_direction direction = 0;
if (!parse_movement_direction(argv[0], &direction)) {
return cmd_results_new(CMD_INVALID, "focus",
- "Expected 'focus <direction|parent|child|mode_toggle>' or 'focus output <direction|name>'");
+ "Expected 'focus <direction|parent|child|mode_toggle|floating|tiling>' "
+ "or 'focus output <direction|name>'");
}
struct sway_container *next_focus = container_get_in_direction(
diff --git a/sway/commands/for_window.c b/sway/commands/for_window.c
index 8c425a1d..ac4d6563 100644
--- a/sway/commands/for_window.c
+++ b/sway/commands/for_window.c
@@ -24,7 +24,7 @@ struct cmd_results *cmd_for_window(int argc, char **argv) {
criteria->cmdlist = join_args(argv + 1, argc - 1);
list_add(config->criteria, criteria);
- wlr_log(L_DEBUG, "for_window: '%s' -> '%s' added", criteria->raw, criteria->cmdlist);
+ wlr_log(WLR_DEBUG, "for_window: '%s' -> '%s' added", criteria->raw, criteria->cmdlist);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c
index 1a4d8b41..0b5beaa2 100644
--- a/sway/commands/fullscreen.c
+++ b/sway/commands/fullscreen.c
@@ -34,7 +34,7 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) {
view_set_fullscreen(view, wants_fullscreen);
struct sway_container *workspace = container_parent(container, C_WORKSPACE);
- arrange_and_commit(workspace->parent);
+ arrange_windows(workspace->parent);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c
index 801fb179..3906eb70 100644
--- a/sway/commands/gaps.c
+++ b/sway/commands/gaps.c
@@ -43,7 +43,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
return cmd_results_new(CMD_INVALID, "gaps",
"gaps edge_gaps on|off|toggle");
}
- arrange_and_commit(&root_container);
+ arrange_windows(&root_container);
} else {
int amount_idx = 0; // the current index in argv
enum gaps_op op = GAPS_OP_SET;
@@ -124,7 +124,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
if (amount_idx == 0) { // gaps <amount>
config->gaps_inner = val;
config->gaps_outer = val;
- arrange_and_commit(&root_container);
+ arrange_windows(&root_container);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
// Other variants. The middle-length variant (gaps inner|outer <amount>)
@@ -155,7 +155,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
} else {
config->gaps_outer = total;
}
- arrange_and_commit(&root_container);
+ arrange_windows(&root_container);
} else {
struct sway_container *c =
config->handler_context.current_container;
@@ -169,7 +169,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
c->gaps_outer = total;
}
- arrange_and_commit(c->parent ? c->parent : &root_container);
+ arrange_windows(c->parent ? c->parent : &root_container);
}
}
diff --git a/sway/commands/input.c b/sway/commands/input.c
index 678c57c4..5b203ea0 100644
--- a/sway/commands/input.c
+++ b/sway/commands/input.c
@@ -20,8 +20,10 @@ static struct cmd_handler input_handlers[] = {
{ "pointer_accel", input_cmd_pointer_accel },
{ "repeat_delay", input_cmd_repeat_delay },
{ "repeat_rate", input_cmd_repeat_rate },
+ { "scroll_button", input_cmd_scroll_button },
{ "scroll_method", input_cmd_scroll_method },
{ "tap", input_cmd_tap },
+ { "tap_button_map", input_cmd_tap_button_map },
{ "xkb_layout", input_cmd_xkb_layout },
{ "xkb_model", input_cmd_xkb_model },
{ "xkb_options", input_cmd_xkb_options },
@@ -35,7 +37,7 @@ struct cmd_results *cmd_input(int argc, char **argv) {
return error;
}
- wlr_log(L_DEBUG, "entering input block: %s", argv[0]);
+ wlr_log(WLR_DEBUG, "entering input block: %s", argv[0]);
config->handler_context.input_config = new_input_config(argv[0]);
if (!config->handler_context.input_config) {
diff --git a/sway/commands/input/events.c b/sway/commands/input/events.c
index e2ccdc94..abfe3b12 100644
--- a/sway/commands/input/events.c
+++ b/sway/commands/input/events.c
@@ -16,7 +16,7 @@ struct cmd_results *input_cmd_events(int argc, char **argv) {
return cmd_results_new(CMD_FAILURE, "events",
"No input device defined.");
}
- wlr_log(L_DEBUG, "events for device: %s",
+ wlr_log(WLR_DEBUG, "events for device: %s",
current_input_config->identifier);
struct input_config *new_config =
new_input_config(current_input_config->identifier);
diff --git a/sway/commands/input/scroll_button.c b/sway/commands/input/scroll_button.c
new file mode 100644
index 00000000..350fcca2
--- /dev/null
+++ b/sway/commands/input/scroll_button.c
@@ -0,0 +1,44 @@
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include "sway/config.h"
+#include "sway/commands.h"
+#include "sway/input/input-manager.h"
+
+struct cmd_results *input_cmd_scroll_button(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "scroll_button", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+ struct input_config *current_input_config =
+ config->handler_context.input_config;
+ if (!current_input_config) {
+ return cmd_results_new(CMD_FAILURE, "scroll_button",
+ "No input device defined.");
+ }
+ struct input_config *new_config =
+ new_input_config(current_input_config->identifier);
+
+ errno = 0;
+ char *endptr;
+ int scroll_button = strtol(*argv, &endptr, 10);
+ if (endptr == *argv && scroll_button == 0) {
+ free_input_config(new_config);
+ return cmd_results_new(CMD_INVALID, "scroll_button",
+ "Scroll button identifier must be an integer.");
+ }
+ if (errno == ERANGE) {
+ free_input_config(new_config);
+ return cmd_results_new(CMD_INVALID, "scroll_button",
+ "Scroll button identifier out of range.");
+ }
+ if (scroll_button < 0) {
+ free_input_config(new_config);
+ return cmd_results_new(CMD_INVALID, "scroll_button",
+ "Scroll button identifier cannot be negative.");
+ }
+ new_config->scroll_button = scroll_button;
+
+ apply_input_config(new_config);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/input/tap.c b/sway/commands/input/tap.c
index 7d027d5d..a8d1a10c 100644
--- a/sway/commands/input/tap.c
+++ b/sway/commands/input/tap.c
@@ -28,7 +28,7 @@ struct cmd_results *input_cmd_tap(int argc, char **argv) {
"Expected 'tap <enabled|disabled>'");
}
- wlr_log(L_DEBUG, "apply-tap for device: %s",
+ wlr_log(WLR_DEBUG, "apply-tap for device: %s",
current_input_config->identifier);
apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/input/tap_button_map.c b/sway/commands/input/tap_button_map.c
new file mode 100644
index 00000000..bdbba472
--- /dev/null
+++ b/sway/commands/input/tap_button_map.c
@@ -0,0 +1,33 @@
+#include <string.h>
+#include <strings.h>
+#include "sway/config.h"
+#include "sway/commands.h"
+#include "sway/input/input-manager.h"
+
+struct cmd_results *input_cmd_tap_button_map(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "tap_button_map", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+ struct input_config *current_input_config =
+ config->handler_context.input_config;
+ if (!current_input_config) {
+ return cmd_results_new(CMD_FAILURE, "tap_button_map",
+ "No input device defined.");
+ }
+ struct input_config *new_config =
+ new_input_config(current_input_config->identifier);
+
+ if (strcasecmp(argv[0], "lrm") == 0) {
+ new_config->tap_button_map = LIBINPUT_CONFIG_TAP_MAP_LRM;
+ } else if (strcasecmp(argv[0], "lmr") == 0) {
+ new_config->tap_button_map = LIBINPUT_CONFIG_TAP_MAP_LMR;
+ } else {
+ free_input_config(new_config);
+ return cmd_results_new(CMD_INVALID, "tap_button_map",
+ "Expected 'tap_button_map <lrm|lmr>'");
+ }
+
+ apply_input_config(new_config);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/input/xkb_layout.c b/sway/commands/input/xkb_layout.c
index 867e65d3..9fa5a344 100644
--- a/sway/commands/input/xkb_layout.c
+++ b/sway/commands/input/xkb_layout.c
@@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_layout(int argc, char **argv) {
new_config->xkb_layout = strdup(argv[0]);
- wlr_log(L_DEBUG, "apply-xkb_layout for device: %s layout: %s",
+ wlr_log(WLR_DEBUG, "apply-xkb_layout for device: %s layout: %s",
current_input_config->identifier, new_config->xkb_layout);
apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/input/xkb_model.c b/sway/commands/input/xkb_model.c
index e8c8e04e..0d082625 100644
--- a/sway/commands/input/xkb_model.c
+++ b/sway/commands/input/xkb_model.c
@@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_model(int argc, char **argv) {
new_config->xkb_model = strdup(argv[0]);
- wlr_log(L_DEBUG, "apply-xkb_model for device: %s model: %s",
+ wlr_log(WLR_DEBUG, "apply-xkb_model for device: %s model: %s",
current_input_config->identifier, new_config->xkb_model);
apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/input/xkb_options.c b/sway/commands/input/xkb_options.c
index e9ddd6e3..3059d941 100644
--- a/sway/commands/input/xkb_options.c
+++ b/sway/commands/input/xkb_options.c
@@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_options(int argc, char **argv) {
new_config->xkb_options = strdup(argv[0]);
- wlr_log(L_DEBUG, "apply-xkb_options for device: %s options: %s",
+ wlr_log(WLR_DEBUG, "apply-xkb_options for device: %s options: %s",
current_input_config->identifier, new_config->xkb_options);
apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/input/xkb_rules.c b/sway/commands/input/xkb_rules.c
index 926d0ac1..560f088e 100644
--- a/sway/commands/input/xkb_rules.c
+++ b/sway/commands/input/xkb_rules.c
@@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_rules(int argc, char **argv) {
new_config->xkb_rules = strdup(argv[0]);
- wlr_log(L_DEBUG, "apply-xkb_rules for device: %s rules: %s",
+ wlr_log(WLR_DEBUG, "apply-xkb_rules for device: %s rules: %s",
current_input_config->identifier, new_config->xkb_rules);
apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/input/xkb_variant.c b/sway/commands/input/xkb_variant.c
index 0e3ffd41..0aa03440 100644
--- a/sway/commands/input/xkb_variant.c
+++ b/sway/commands/input/xkb_variant.c
@@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_variant(int argc, char **argv) {
new_config->xkb_variant = strdup(argv[0]);
- wlr_log(L_DEBUG, "apply-xkb_variant for device: %s variant: %s",
+ wlr_log(WLR_DEBUG, "apply-xkb_variant for device: %s variant: %s",
current_input_config->identifier, new_config->xkb_variant);
apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/layout.c b/sway/commands/layout.c
index 9945fa5c..c446f1f9 100644
--- a/sway/commands/layout.c
+++ b/sway/commands/layout.c
@@ -49,7 +49,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
}
container_notify_subtree_changed(parent);
- arrange_and_commit(parent);
+ arrange_windows(parent);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/mode.c b/sway/commands/mode.c
index d2c14468..b460fcb5 100644
--- a/sway/commands/mode.c
+++ b/sway/commands/mode.c
@@ -65,7 +65,7 @@ struct cmd_results *cmd_mode(int argc, char **argv) {
return error;
}
if ((config->reading && argc > 1) || (!config->reading && argc == 1)) {
- wlr_log(L_DEBUG, "Switching to mode `%s' (pango=%d)",
+ wlr_log(WLR_DEBUG, "Switching to mode `%s' (pango=%d)",
mode->name, mode->pango);
}
// Set current mode
diff --git a/sway/commands/move.c b/sway/commands/move.c
index a4fae388..6ec050a8 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -1,11 +1,12 @@
#define _XOPEN_SOURCE 500
#include <string.h>
#include <strings.h>
+#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/util/log.h>
#include "sway/commands.h"
-#include "sway/desktop/transaction.h"
+#include "sway/input/cursor.h"
#include "sway/input/seat.h"
#include "sway/output.h"
#include "sway/tree/arrange.h"
@@ -103,10 +104,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
// TODO: Ideally we would arrange the surviving parent after reaping,
// but container_reap_empty does not return it, so we arrange the
// workspace instead.
- struct sway_transaction *txn = transaction_create();
- arrange_windows(old_ws, txn);
- arrange_windows(destination->parent, txn);
- transaction_commit(txn);
+ arrange_windows(old_ws);
+ arrange_windows(destination->parent);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
} else if (strcasecmp(argv[1], "to") == 0
@@ -142,10 +141,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
// TODO: Ideally we would arrange the surviving parent after reaping,
// but container_reap_empty does not return it, so we arrange the
// workspace instead.
- struct sway_transaction *txn = transaction_create();
- arrange_windows(old_ws, txn);
- arrange_windows(focus->parent, txn);
- transaction_commit(txn);
+ arrange_windows(old_ws);
+ arrange_windows(focus->parent);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
@@ -175,20 +172,56 @@ static struct cmd_results *cmd_move_workspace(struct sway_container *current,
}
container_move_to(current, destination);
- struct sway_transaction *txn = transaction_create();
- arrange_windows(source, txn);
- arrange_windows(destination, txn);
- transaction_commit(txn);
+ arrange_windows(source);
+ arrange_windows(destination);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
static struct cmd_results *move_in_direction(struct sway_container *container,
- enum movement_direction direction, int move_amt) {
+ enum movement_direction direction, int argc, char **argv) {
+ int move_amt = 10;
+ if (argc > 1) {
+ char *inv;
+ move_amt = (int)strtol(argv[1], &inv, 10);
+ if (*inv != '\0' && strcasecmp(inv, "px") != 0) {
+ return cmd_results_new(CMD_FAILURE, "move",
+ "Invalid distance specified");
+ }
+ }
+
if (container->type == C_WORKSPACE) {
return cmd_results_new(CMD_FAILURE, "move",
"Cannot move workspaces in a direction");
}
+ if (container_is_floating(container)) {
+ if (container->type == C_VIEW && container->sway_view->is_fullscreen) {
+ return cmd_results_new(CMD_FAILURE, "move",
+ "Cannot move fullscreen floating container");
+ }
+ double lx = container->x;
+ double ly = container->y;
+ switch (direction) {
+ case MOVE_LEFT:
+ lx -= move_amt;
+ break;
+ case MOVE_RIGHT:
+ lx += move_amt;
+ break;
+ case MOVE_UP:
+ ly -= move_amt;
+ break;
+ case MOVE_DOWN:
+ ly += move_amt;
+ break;
+ case MOVE_PARENT:
+ case MOVE_CHILD:
+ return cmd_results_new(CMD_FAILURE, "move",
+ "Cannot move floating container to parent or child");
+ }
+ container_floating_move_to(container, lx, ly);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ }
// For simplicity, we'll arrange the entire workspace. The reason for this
// is moving the container might reap the old parent, and container_move
// does not return a surviving parent.
@@ -198,41 +231,86 @@ static struct cmd_results *move_in_direction(struct sway_container *container,
container_move(container, direction, move_amt);
struct sway_container *new_ws = container_parent(container, C_WORKSPACE);
- struct sway_transaction *txn = transaction_create();
- arrange_windows(old_ws, txn);
+ arrange_windows(old_ws);
if (new_ws != old_ws) {
- arrange_windows(new_ws, txn);
+ arrange_windows(new_ws);
}
- transaction_commit(txn);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
+static const char* expected_position_syntax =
+ "Expected 'move [absolute] position <x> <y>' or "
+ "'move [absolute] position mouse'";
+
+static struct cmd_results *move_to_position(struct sway_container *container,
+ int argc, char **argv) {
+ if (!container_is_floating(container)) {
+ return cmd_results_new(CMD_FAILURE, "move",
+ "Only floating containers "
+ "can be moved to an absolute position");
+ }
+ if (!argc) {
+ return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax);
+ }
+ if (strcmp(argv[0], "absolute") == 0) {
+ --argc;
+ ++argv;
+ }
+ if (!argc) {
+ return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax);
+ }
+ if (strcmp(argv[0], "position") == 0) {
+ --argc;
+ ++argv;
+ }
+ if (!argc) {
+ return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax);
+ }
+ if (strcmp(argv[0], "mouse") == 0) {
+ struct sway_seat *seat = config->handler_context.seat;
+ if (!seat->cursor) {
+ return cmd_results_new(CMD_FAILURE, "move", "No cursor device");
+ }
+ double lx = seat->cursor->cursor->x - container->width / 2;
+ double ly = seat->cursor->cursor->y - container->height / 2;
+ container_floating_move_to(container, lx, ly);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ }
+ if (argc != 2) {
+ return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax);
+ }
+ double lx, ly;
+ char *inv;
+ lx = (double)strtol(argv[0], &inv, 10);
+ if (*inv != '\0' && strcasecmp(inv, "px") != 0) {
+ return cmd_results_new(CMD_FAILURE, "move",
+ "Invalid position specified");
+ }
+ ly = (double)strtol(argv[1], &inv, 10);
+ if (*inv != '\0' && strcasecmp(inv, "px") != 0) {
+ return cmd_results_new(CMD_FAILURE, "move",
+ "Invalid position specified");
+ }
+ container_floating_move_to(container, lx, ly);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
+
struct cmd_results *cmd_move(int argc, char **argv) {
struct cmd_results *error = NULL;
- int move_amt = 10;
if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct sway_container *current = config->handler_context.current_container;
- if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0)) {
- char *inv;
- move_amt = (int)strtol(argv[1], &inv, 10);
- if (*inv != '\0' && strcasecmp(inv, "px") != 0) {
- return cmd_results_new(CMD_FAILURE, "move",
- "Invalid distance specified");
- }
- }
-
if (strcasecmp(argv[0], "left") == 0) {
- return move_in_direction(current, MOVE_LEFT, move_amt);
+ return move_in_direction(current, MOVE_LEFT, argc, argv);
} else if (strcasecmp(argv[0], "right") == 0) {
- return move_in_direction(current, MOVE_RIGHT, move_amt);
+ return move_in_direction(current, MOVE_RIGHT, argc, argv);
} else if (strcasecmp(argv[0], "up") == 0) {
- return move_in_direction(current, MOVE_UP, move_amt);
+ return move_in_direction(current, MOVE_UP, argc, argv);
} else if (strcasecmp(argv[0], "down") == 0) {
- return move_in_direction(current, MOVE_DOWN, move_amt);
+ return move_in_direction(current, MOVE_DOWN, argc, argv);
} else if (strcasecmp(argv[0], "container") == 0
|| strcasecmp(argv[0], "window") == 0) {
return cmd_move_container(current, argc, argv);
@@ -244,8 +322,9 @@ struct cmd_results *cmd_move(int argc, char **argv) {
// TODO: scratchpad
return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
} else if (strcasecmp(argv[0], "position") == 0) {
- // TODO: floating
- return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
+ return move_to_position(current, argc, argv);
+ } else if (strcasecmp(argv[0], "absolute") == 0) {
+ return move_to_position(current, argc, argv);
} else {
return cmd_results_new(CMD_INVALID, "move", expected_syntax);
}
diff --git a/sway/commands/no_focus.c b/sway/commands/no_focus.c
new file mode 100644
index 00000000..61a8de7e
--- /dev/null
+++ b/sway/commands/no_focus.c
@@ -0,0 +1,26 @@
+#define _XOPEN_SOURCE 500
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/criteria.h"
+#include "list.h"
+#include "log.h"
+
+struct cmd_results *cmd_no_focus(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "no_focus", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+
+ char *err_str = NULL;
+ struct criteria *criteria = criteria_parse(argv[0], &err_str);
+ if (!criteria) {
+ error = cmd_results_new(CMD_INVALID, "no_focus", err_str);
+ free(err_str);
+ return error;
+ }
+
+ criteria->type = CT_NO_FOCUS;
+ list_add(config->criteria, criteria);
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/output.c b/sway/commands/output.c
index f955bf90..15bbd687 100644
--- a/sway/commands/output.c
+++ b/sway/commands/output.c
@@ -29,7 +29,7 @@ struct cmd_results *cmd_output(int argc, char **argv) {
struct output_config *output = new_output_config(argv[0]);
if (!output) {
- wlr_log(L_ERROR, "Failed to allocate output config");
+ wlr_log(WLR_ERROR, "Failed to allocate output config");
return NULL;
}
argc--; argv++;
@@ -71,7 +71,7 @@ struct cmd_results *cmd_output(int argc, char **argv) {
list_add(config->output_configs, output);
}
- wlr_log(L_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
+ wlr_log(WLR_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
"position %d,%d scale %f transform %d) (bg %s %s) (dpms %d)",
output->name, output->enabled, output->width, output->height,
output->refresh_rate, output->x, output->y, output->scale,
@@ -85,7 +85,7 @@ struct cmd_results *cmd_output(int argc, char **argv) {
struct sway_output *sway_output;
wl_list_for_each(sway_output, &root_container.sway_root->outputs, link) {
output_get_identifier(identifier, sizeof(identifier), sway_output);
- wlr_log(L_DEBUG, "Checking identifier %s", identifier);
+ wlr_log(WLR_DEBUG, "Checking identifier %s", identifier);
if (all || strcmp(sway_output->wlr_output->name, output->name) == 0
|| strcmp(identifier, output->name) == 0) {
if (!sway_output->swayc) {
diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c
index 65b5f902..4ed56c2a 100644
--- a/sway/commands/output/background.c
+++ b/sway/commands/output/background.c
@@ -72,7 +72,7 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
src = strdup(p.we_wordv[0]);
wordfree(&p);
if (!src) {
- wlr_log(L_ERROR, "Failed to duplicate string");
+ wlr_log(WLR_ERROR, "Failed to duplicate string");
return cmd_results_new(CMD_FAILURE, "output",
"Unable to allocate resource");
}
@@ -80,9 +80,9 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
if (config->reading && *src != '/') {
// src file is inside configuration dir
- char *conf = strdup(config->current_config);
+ char *conf = strdup(config->current_config_path);
if (!conf) {
- wlr_log(L_ERROR, "Failed to duplicate string");
+ wlr_log(WLR_ERROR, "Failed to duplicate string");
free(src);
return cmd_results_new(CMD_FAILURE, "output",
"Unable to allocate resources");
@@ -94,7 +94,7 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
if (!src) {
free(rel_path);
free(conf);
- wlr_log(L_ERROR, "Unable to allocate memory");
+ wlr_log(WLR_ERROR, "Unable to allocate memory");
return cmd_results_new(CMD_FAILURE, "output",
"Unable to allocate resources");
}
diff --git a/sway/commands/reload.c b/sway/commands/reload.c
index 9fc213c4..cea6a94b 100644
--- a/sway/commands/reload.c
+++ b/sway/commands/reload.c
@@ -7,11 +7,11 @@ struct cmd_results *cmd_reload(int argc, char **argv) {
if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) {
return error;
}
- if (!load_main_config(config->current_config, true)) {
+ if (!load_main_config(config->current_config_path, true)) {
return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config.");
}
load_swaybars();
- arrange_and_commit(&root_container);
+ arrange_windows(&root_container);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/rename.c b/sway/commands/rename.c
index 104a3392..a380ff9c 100644
--- a/sway/commands/rename.c
+++ b/sway/commands/rename.c
@@ -68,7 +68,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
"Workspace already exists");
}
- wlr_log(L_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name);
+ wlr_log(WLR_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name);
free(workspace->name);
workspace->name = new_name;
diff --git a/sway/commands/resize.c b/sway/commands/resize.c
index 6357343e..e657864c 100644
--- a/sway/commands/resize.c
+++ b/sway/commands/resize.c
@@ -1,4 +1,5 @@
#include <errno.h>
+#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
@@ -7,6 +8,7 @@
#include <wlr/util/log.h>
#include "sway/commands.h"
#include "sway/tree/arrange.h"
+#include "sway/tree/view.h"
#include "log.h"
static const int MIN_SANE_W = 100, MIN_SANE_H = 60;
@@ -21,9 +23,18 @@ enum resize_unit {
enum resize_axis {
RESIZE_AXIS_HORIZONTAL,
RESIZE_AXIS_VERTICAL,
+ RESIZE_AXIS_UP,
+ RESIZE_AXIS_DOWN,
+ RESIZE_AXIS_LEFT,
+ RESIZE_AXIS_RIGHT,
RESIZE_AXIS_INVALID,
};
+struct resize_amount {
+ int amount;
+ enum resize_unit unit;
+};
+
static enum resize_unit parse_resize_unit(const char *unit) {
if (strcasecmp(unit, "px") == 0) {
return RESIZE_UNIT_PX;
@@ -37,6 +48,69 @@ static enum resize_unit parse_resize_unit(const char *unit) {
return RESIZE_UNIT_INVALID;
}
+// Parse arguments such as "10", "10px" or "10 px".
+// Returns the number of arguments consumed.
+static int parse_resize_amount(int argc, char **argv,
+ struct resize_amount *amount) {
+ char *err;
+ amount->amount = (int)strtol(argv[0], &err, 10);
+ if (*err) {
+ // e.g. 10px
+ amount->unit = parse_resize_unit(err);
+ return 1;
+ }
+ if (argc == 1) {
+ amount->unit = RESIZE_UNIT_DEFAULT;
+ return 1;
+ }
+ // Try the second argument
+ amount->unit = parse_resize_unit(argv[1]);
+ if (amount->unit == RESIZE_UNIT_INVALID) {
+ amount->unit = RESIZE_UNIT_DEFAULT;
+ return 1;
+ }
+ return 2;
+}
+
+static void calculate_constraints(int *min_width, int *max_width,
+ int *min_height, int *max_height) {
+ struct sway_container *con = config->handler_context.current_container;
+
+ if (config->floating_minimum_width == -1) { // no minimum
+ *min_width = 0;
+ } else if (config->floating_minimum_width == 0) { // automatic
+ *min_width = 75;
+ } else {
+ *min_width = config->floating_minimum_width;
+ }
+
+ if (config->floating_minimum_height == -1) { // no minimum
+ *min_height = 0;
+ } else if (config->floating_minimum_height == 0) { // automatic
+ *min_height = 50;
+ } else {
+ *min_height = config->floating_minimum_height;
+ }
+
+ if (config->floating_maximum_width == -1) { // no maximum
+ *max_width = INT_MAX;
+ } else if (config->floating_maximum_width == 0) { // automatic
+ struct sway_container *ws = container_parent(con, C_WORKSPACE);
+ *max_width = ws->width;
+ } else {
+ *max_width = config->floating_maximum_width;
+ }
+
+ if (config->floating_maximum_height == -1) { // no maximum
+ *max_height = INT_MAX;
+ } else if (config->floating_maximum_height == 0) { // automatic
+ struct sway_container *ws = container_parent(con, C_WORKSPACE);
+ *max_height = ws->height;
+ } else {
+ *max_height = config->floating_maximum_height;
+ }
+}
+
static enum resize_axis parse_resize_axis(const char *axis) {
if (strcasecmp(axis, "width") == 0 || strcasecmp(axis, "horizontal") == 0) {
return RESIZE_AXIS_HORIZONTAL;
@@ -44,6 +118,18 @@ static enum resize_axis parse_resize_axis(const char *axis) {
if (strcasecmp(axis, "height") == 0 || strcasecmp(axis, "vertical") == 0) {
return RESIZE_AXIS_VERTICAL;
}
+ if (strcasecmp(axis, "up") == 0) {
+ return RESIZE_AXIS_UP;
+ }
+ if (strcasecmp(axis, "down") == 0) {
+ return RESIZE_AXIS_DOWN;
+ }
+ if (strcasecmp(axis, "left") == 0) {
+ return RESIZE_AXIS_LEFT;
+ }
+ if (strcasecmp(axis, "right") == 0) {
+ return RESIZE_AXIS_RIGHT;
+ }
return RESIZE_AXIS_INVALID;
}
@@ -95,7 +181,7 @@ static void resize_tiled(int amount, enum resize_axis axis) {
return;
}
- wlr_log(L_DEBUG,
+ wlr_log(WLR_DEBUG,
"Found the proper parent: %p. It has %d l conts, and %d r conts",
parent->parent, minor_weight, major_weight);
@@ -182,105 +268,315 @@ static void resize_tiled(int amount, enum resize_axis axis) {
}
}
- arrange_and_commit(parent->parent);
+ arrange_windows(parent->parent);
}
-static void resize(int amount, enum resize_axis axis, enum resize_unit unit) {
- struct sway_container *current = config->handler_context.current_container;
- if (unit == RESIZE_UNIT_DEFAULT) {
- // Default for tiling; TODO floating should be px
- unit = RESIZE_UNIT_PPT;
+/**
+ * Implement `resize <grow|shrink>` for a floating container.
+ */
+static struct cmd_results *resize_adjust_floating(enum resize_axis axis,
+ struct resize_amount *amount) {
+ struct sway_container *con = config->handler_context.current_container;
+ int grow_width = 0, grow_height = 0;
+ switch (axis) {
+ case RESIZE_AXIS_HORIZONTAL:
+ case RESIZE_AXIS_LEFT:
+ case RESIZE_AXIS_RIGHT:
+ grow_width = amount->amount;
+ break;
+ case RESIZE_AXIS_VERTICAL:
+ case RESIZE_AXIS_UP:
+ case RESIZE_AXIS_DOWN:
+ grow_height = amount->amount;
+ break;
+ case RESIZE_AXIS_INVALID:
+ return cmd_results_new(CMD_INVALID, "resize", "Invalid axis/direction");
+ }
+ // Make sure we're not adjusting beyond floating min/max size
+ int min_width, max_width, min_height, max_height;
+ calculate_constraints(&min_width, &max_width, &min_height, &max_height);
+ if (con->width + grow_width < min_width) {
+ grow_width = min_width - con->width;
+ } else if (con->width + grow_width > max_width) {
+ grow_width = max_width - con->width;
}
+ if (con->height + grow_height < min_height) {
+ grow_height = min_height - con->height;
+ } else if (con->height + grow_height > max_height) {
+ grow_height = max_height - con->height;
+ }
+ int grow_x = 0, grow_y = 0;
+ switch (axis) {
+ case RESIZE_AXIS_HORIZONTAL:
+ grow_x = -grow_width / 2;
+ break;
+ case RESIZE_AXIS_VERTICAL:
+ grow_y = -grow_height / 2;
+ break;
+ case RESIZE_AXIS_UP:
+ grow_y = -grow_height;
+ break;
+ case RESIZE_AXIS_LEFT:
+ grow_x = -grow_width;
+ break;
+ case RESIZE_AXIS_DOWN:
+ case RESIZE_AXIS_RIGHT:
+ break;
+ case RESIZE_AXIS_INVALID:
+ return cmd_results_new(CMD_INVALID, "resize", "Invalid axis/direction");
+ }
+ con->x += grow_x;
+ con->y += grow_y;
+ con->width += grow_width;
+ con->height += grow_height;
+
+ if (con->type == C_VIEW) {
+ struct sway_view *view = con->sway_view;
+ view->x += grow_x;
+ view->y += grow_y;
+ view->width += grow_width;
+ view->height += grow_height;
+ }
+
+ arrange_windows(con);
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
- if (unit == RESIZE_UNIT_PPT) {
- float pct = amount / 100.0f;
+/**
+ * Implement `resize <grow|shrink>` for a tiled container.
+ */
+static struct cmd_results *resize_adjust_tiled(enum resize_axis axis,
+ struct resize_amount *amount) {
+ struct sway_container *current = config->handler_context.current_container;
+
+ if (amount->unit == RESIZE_UNIT_DEFAULT) {
+ amount->unit = RESIZE_UNIT_PPT;
+ }
+ if (amount->unit == RESIZE_UNIT_PPT) {
+ float pct = amount->amount / 100.0f;
+ // TODO: Make left/right/up/down resize in that direction?
switch (axis) {
+ case RESIZE_AXIS_LEFT:
+ case RESIZE_AXIS_RIGHT:
case RESIZE_AXIS_HORIZONTAL:
- amount = (float)current->width * pct;
+ amount->amount = (float)current->width * pct;
break;
+ case RESIZE_AXIS_UP:
+ case RESIZE_AXIS_DOWN:
case RESIZE_AXIS_VERTICAL:
- amount = (float)current->height * pct;
+ amount->amount = (float)current->height * pct;
break;
- default:
- sway_assert(0, "invalid resize axis");
- return;
+ case RESIZE_AXIS_INVALID:
+ return cmd_results_new(CMD_INVALID, "resize",
+ "Invalid resize axis/direction");
}
}
- return resize_tiled(amount, axis);
+ resize_tiled(amount->amount, axis);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
-struct cmd_results *cmd_resize(int argc, char **argv) {
- struct sway_container *current = config->handler_context.current_container;
- if (!current) {
- return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing");
- }
- if (current->type != C_VIEW && current->type != C_CONTAINER) {
- return cmd_results_new(CMD_INVALID, "resize",
- "Can only resize views/containers");
+/**
+ * Implement `resize set` for a tiled container.
+ */
+static struct cmd_results *resize_set_tiled(struct sway_container *con,
+ struct resize_amount *width, struct resize_amount *height) {
+ return cmd_results_new(CMD_INVALID, "resize",
+ "'resize set' is not implemented for tiled views");
+}
+
+/**
+ * Implement `resize set` for a floating container.
+ */
+static struct cmd_results *resize_set_floating(struct sway_container *con,
+ struct resize_amount *width, struct resize_amount *height) {
+ int min_width, max_width, min_height, max_height;
+ calculate_constraints(&min_width, &max_width, &min_height, &max_height);
+ width->amount = fmax(min_width, fmin(width->amount, max_width));
+ height->amount = fmax(min_height, fmin(height->amount, max_height));
+ int grow_width = width->amount - con->width;
+ int grow_height = height->amount - con->height;
+ con->x -= grow_width / 2;
+ con->y -= grow_height / 2;
+ con->width = width->amount;
+ con->height = height->amount;
+
+ if (con->type == C_VIEW) {
+ struct sway_view *view = con->sway_view;
+ view->x -= grow_width / 2;
+ view->y -= grow_height / 2;
+ view->width += grow_width;
+ view->height += grow_height;
}
+ arrange_windows(con);
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
+
+/**
+ * resize set <args>
+ *
+ * args: <width> [px|ppt] <height> [px|ppt]
+ */
+static struct cmd_results *cmd_resize_set(int argc, char **argv) {
struct cmd_results *error;
if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) {
return error;
}
-
- if (strcasecmp(argv[0], "set") == 0) {
- // TODO
- //return cmd_resize_set(argc - 1, &argv[1]);
- return cmd_results_new(CMD_INVALID, "resize", "resize set unimplemented");
+ const char *usage = "Expected 'resize set <width> <height>'";
+
+ // Width
+ struct resize_amount width;
+ int num_consumed_args = parse_resize_amount(argc, argv, &width);
+ argc -= num_consumed_args;
+ argv += num_consumed_args;
+ if (width.unit == RESIZE_UNIT_INVALID) {
+ return cmd_results_new(CMD_INVALID, "resize", usage);
+ }
+ if (!argc) {
+ return cmd_results_new(CMD_INVALID, "resize", usage);
}
- // TODO: resize grow|shrink left|right|up|down
+ // Height
+ struct resize_amount height;
+ num_consumed_args = parse_resize_amount(argc, argv, &height);
+ argc -= num_consumed_args;
+ argv += num_consumed_args;
+ if (height.unit == RESIZE_UNIT_INVALID) {
+ return cmd_results_new(CMD_INVALID, "resize", usage);
+ }
- const char *usage = "Expected 'resize <shrink|grow> "
- "<width|height> [<amount>] [px|ppt]'";
+ // If 0, don't resize that dimension
+ struct sway_container *con = config->handler_context.current_container;
+ if (width.amount <= 0) {
+ width.amount = con->width;
+ }
+ if (height.amount <= 0) {
+ height.amount = con->height;
+ }
- int multiplier = 0;
- if (strcasecmp(*argv, "grow") == 0) {
- multiplier = 1;
- } else if (strcasecmp(*argv, "shrink") == 0) {
- multiplier = -1;
- } else {
- return cmd_results_new(CMD_INVALID, "resize", usage);
+ if (container_is_floating(con)) {
+ return resize_set_floating(con, &width, &height);
}
- --argc; ++argv;
+ return resize_set_tiled(con, &width, &height);
+}
+/**
+ * resize <grow|shrink> <args>
+ *
+ * args: <direction>
+ * args: <direction> <amount> <unit>
+ * args: <direction> <amount> <unit> or <amount> <other_unit>
+ */
+static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
+ int multiplier) {
+ const char *usage = "Expected 'resize grow|shrink <direction> "
+ "[<amount> px|ppt [or <amount> px|ppt]]'";
enum resize_axis axis = parse_resize_axis(*argv);
if (axis == RESIZE_AXIS_INVALID) {
return cmd_results_new(CMD_INVALID, "resize", usage);
}
--argc; ++argv;
- int amount = 10; // Default amount
- enum resize_unit unit = RESIZE_UNIT_DEFAULT;
-
+ // First amount
+ struct resize_amount first_amount;
if (argc) {
- char *err;
- amount = (int)strtol(*argv, &err, 10);
- if (*err) {
- // e.g. `resize grow width 10px`
- unit = parse_resize_unit(err);
- if (unit == RESIZE_UNIT_INVALID) {
- return cmd_results_new(CMD_INVALID, "resize", usage);
- }
+ int num_consumed_args = parse_resize_amount(argc, argv, &first_amount);
+ argc -= num_consumed_args;
+ argv += num_consumed_args;
+ if (first_amount.unit == RESIZE_UNIT_INVALID) {
+ return cmd_results_new(CMD_INVALID, "resize", usage);
}
- --argc; ++argv;
+ } else {
+ first_amount.amount = 10;
+ first_amount.unit = RESIZE_UNIT_DEFAULT;
}
+ // "or"
if (argc) {
- unit = parse_resize_unit(*argv);
- if (unit == RESIZE_UNIT_INVALID) {
+ if (strcmp(*argv, "or") != 0) {
return cmd_results_new(CMD_INVALID, "resize", usage);
}
--argc; ++argv;
}
+ // Second amount
+ struct resize_amount second_amount;
if (argc) {
- // Provied too many args, the bastard
- return cmd_results_new(CMD_INVALID, "resize", usage);
+ int num_consumed_args = parse_resize_amount(argc, argv, &second_amount);
+ argc -= num_consumed_args;
+ argv += num_consumed_args;
+ if (second_amount.unit == RESIZE_UNIT_INVALID) {
+ return cmd_results_new(CMD_INVALID, "resize", usage);
+ }
+ } else {
+ second_amount.unit = RESIZE_UNIT_INVALID;
}
- resize(amount * multiplier, axis, unit);
- return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ first_amount.amount *= multiplier;
+ second_amount.amount *= multiplier;
+
+ struct sway_container *con = config->handler_context.current_container;
+ if (container_is_floating(con)) {
+ // Floating containers can only resize in px. Choose an amount which
+ // uses px, with fallback to an amount that specified no unit.
+ if (first_amount.unit == RESIZE_UNIT_PX) {
+ return resize_adjust_floating(axis, &first_amount);
+ } else if (second_amount.unit == RESIZE_UNIT_PX) {
+ return resize_adjust_floating(axis, &second_amount);
+ } else if (first_amount.unit == RESIZE_UNIT_DEFAULT) {
+ return resize_adjust_floating(axis, &first_amount);
+ } else if (second_amount.unit == RESIZE_UNIT_DEFAULT) {
+ return resize_adjust_floating(axis, &second_amount);
+ } else {
+ return cmd_results_new(CMD_INVALID, "resize",
+ "Floating containers cannot use ppt measurements");
+ }
+ }
+
+ // For tiling, prefer ppt -> default -> px
+ if (first_amount.unit == RESIZE_UNIT_PPT) {
+ return resize_adjust_tiled(axis, &first_amount);
+ } else if (second_amount.unit == RESIZE_UNIT_PPT) {
+ return resize_adjust_tiled(axis, &second_amount);
+ } else if (first_amount.unit == RESIZE_UNIT_DEFAULT) {
+ return resize_adjust_tiled(axis, &first_amount);
+ } else if (second_amount.unit == RESIZE_UNIT_DEFAULT) {
+ return resize_adjust_tiled(axis, &second_amount);
+ } else {
+ return resize_adjust_tiled(axis, &first_amount);
+ }
+}
+
+struct cmd_results *cmd_resize(int argc, char **argv) {
+ struct sway_container *current = config->handler_context.current_container;
+ if (!current) {
+ return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing");
+ }
+ if (current->type != C_VIEW && current->type != C_CONTAINER) {
+ return cmd_results_new(CMD_INVALID, "resize",
+ "Can only resize views/containers");
+ }
+
+ struct cmd_results *error;
+ if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) {
+ return error;
+ }
+
+ if (strcasecmp(argv[0], "set") == 0) {
+ return cmd_resize_set(argc - 1, &argv[1]);
+ }
+ if (strcasecmp(argv[0], "grow") == 0) {
+ return cmd_resize_adjust(argc - 1, &argv[1], 1);
+ }
+ if (strcasecmp(argv[0], "shrink") == 0) {
+ return cmd_resize_adjust(argc - 1, &argv[1], -1);
+ }
+
+ const char *usage = "Expected 'resize <shrink|grow> "
+ "<width|height|up|down|left|right> [<amount>] [px|ppt]'";
+
+ return cmd_results_new(CMD_INVALID, "resize", usage);
}
diff --git a/sway/commands/set.c b/sway/commands/set.c
index 84e9b792..ea388d3b 100644
--- a/sway/commands/set.c
+++ b/sway/commands/set.c
@@ -32,7 +32,7 @@ struct cmd_results *cmd_set(int argc, char **argv) {
}
if (argv[0][0] != '$') {
- wlr_log(L_INFO, "Warning: variable '%s' doesn't start with $", argv[0]);
+ wlr_log(WLR_INFO, "Warning: variable '%s' doesn't start with $", argv[0]);
size_t size = snprintf(NULL, 0, "$%s", argv[0]);
tmp = malloc(size + 1);
diff --git a/sway/commands/smart_gaps.c b/sway/commands/smart_gaps.c
index f687e78e..7d27e571 100644
--- a/sway/commands/smart_gaps.c
+++ b/sway/commands/smart_gaps.c
@@ -23,7 +23,7 @@ struct cmd_results *cmd_smart_gaps(int argc, char **argv) {
"Expected 'smart_gaps <on|off>' ");
}
- arrange_and_commit(&root_container);
+ arrange_windows(&root_container);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/split.c b/sway/commands/split.c
index c40f4d9f..313799da 100644
--- a/sway/commands/split.c
+++ b/sway/commands/split.c
@@ -16,7 +16,7 @@ static struct cmd_results *do_split(int layout) {
}
struct sway_container *parent = container_split(con, layout);
container_create_notify(parent);
- arrange_and_commit(parent->parent);
+ arrange_windows(parent->parent);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/swap.c b/sway/commands/swap.c
index e052058f..2fc88308 100644
--- a/sway/commands/swap.c
+++ b/sway/commands/swap.c
@@ -1,7 +1,6 @@
#include <strings.h>
#include <wlr/util/log.h>
#include "sway/commands.h"
-#include "sway/desktop/transaction.h"
#include "sway/tree/arrange.h"
#include "sway/tree/layout.h"
#include "sway/tree/view.h"
@@ -79,14 +78,10 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
container_swap(current, other);
- struct sway_transaction *txn = transaction_create();
- arrange_windows(current->parent, txn);
-
+ arrange_windows(current->parent);
if (other->parent != current->parent) {
- arrange_windows(other->parent, txn);
+ arrange_windows(other->parent);
}
- transaction_commit(txn);
-
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/swaybg_command.c b/sway/commands/swaybg_command.c
index 770d4821..36f7fdcd 100644
--- a/sway/commands/swaybg_command.c
+++ b/sway/commands/swaybg_command.c
@@ -13,7 +13,7 @@ struct cmd_results *cmd_swaybg_command(int argc, char **argv) {
free(config->swaybg_command);
}
config->swaybg_command = join_args(argv, argc);
- wlr_log(L_DEBUG, "Using custom swaybg command: %s",
+ wlr_log(WLR_DEBUG, "Using custom swaybg command: %s",
config->swaybg_command);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/urgent.c b/sway/commands/urgent.c
new file mode 100644
index 00000000..d199858a
--- /dev/null
+++ b/sway/commands/urgent.c
@@ -0,0 +1,36 @@
+#include "log.h"
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/tree/arrange.h"
+#include "sway/tree/container.h"
+#include "sway/tree/view.h"
+#include "sway/tree/layout.h"
+
+struct cmd_results *cmd_urgent(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "urgent", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ struct sway_container *container =
+ config->handler_context.current_container;
+ if (container->type != C_VIEW) {
+ return cmd_results_new(CMD_INVALID, "urgent",
+ "Only views can be urgent");
+ }
+ struct sway_view *view = container->sway_view;
+
+ if (strcmp(argv[0], "enable") == 0) {
+ view_set_urgent(view, true);
+ } else if (strcmp(argv[0], "disable") == 0) {
+ view_set_urgent(view, false);
+ } else if (strcmp(argv[0], "allow") == 0) {
+ view->allow_request_urgent = true;
+ } else if (strcmp(argv[0], "deny") == 0) {
+ view->allow_request_urgent = false;
+ } else {
+ return cmd_results_new(CMD_INVALID, "urgent",
+ "Expected 'urgent <enable|disable|allow|deny>'");
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c
index d15be571..e8b37182 100644
--- a/sway/commands/workspace.c
+++ b/sway/commands/workspace.c
@@ -51,7 +51,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
free(old); // workspaces can only be assigned to a single output
list_del(config->workspace_outputs, i);
}
- wlr_log(L_DEBUG, "Assigning workspace %s to output %s", wso->workspace, wso->output);
+ wlr_log(WLR_DEBUG, "Assigning workspace %s to output %s", wso->workspace, wso->output);
list_add(config->workspace_outputs, wso);
} else {
if (config->reading || !config->active) {
diff --git a/sway/config.c b/sway/config.c
index 89b7d349..c620e4c7 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -24,6 +24,7 @@
#include "sway/input/seat.h"
#include "sway/commands.h"
#include "sway/config.h"
+#include "sway/criteria.h"
#include "sway/tree/arrange.h"
#include "sway/tree/layout.h"
#include "sway/tree/workspace.h"
@@ -105,7 +106,12 @@ void free_config(struct sway_config *config) {
}
list_free(config->seat_configs);
}
- list_free(config->criteria);
+ if (config->criteria) {
+ for (int i = 0; i < config->criteria->length; ++i) {
+ criteria_destroy(config->criteria->items[i]);
+ }
+ list_free(config->criteria);
+ }
list_free(config->no_focus);
list_free(config->active_bar_modifiers);
list_free(config->config_chain);
@@ -117,6 +123,7 @@ void free_config(struct sway_config *config) {
free(config->floating_scroll_left_cmd);
free(config->floating_scroll_right_cmd);
free(config->font);
+ free((char *)config->current_config_path);
free((char *)config->current_config);
free(config);
}
@@ -205,6 +212,7 @@ static void config_defaults(struct sway_config *config) {
if (!(config->active_bar_modifiers = create_list())) goto cleanup;
if (!(config->config_chain = create_list())) goto cleanup;
+ config->current_config_path = NULL;
config->current_config = NULL;
// borders
@@ -276,12 +284,12 @@ static char *get_config_path(void) {
char *home = getenv("HOME");
char *config_home = malloc(strlen(home) + strlen("/.config") + 1);
if (!config_home) {
- wlr_log(L_ERROR, "Unable to allocate $HOME/.config");
+ wlr_log(WLR_ERROR, "Unable to allocate $HOME/.config");
} else {
strcpy(config_home, home);
strcat(config_home, "/.config");
setenv("XDG_CONFIG_HOME", config_home, 1);
- wlr_log(L_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home);
+ wlr_log(WLR_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home);
free(config_home);
}
}
@@ -304,16 +312,13 @@ static char *get_config_path(void) {
return NULL; // Not reached
}
-const char *current_config_path;
-
static bool load_config(const char *path, struct sway_config *config) {
if (path == NULL) {
- wlr_log(L_ERROR, "Unable to find a config file!");
+ wlr_log(WLR_ERROR, "Unable to find a config file!");
return false;
}
- wlr_log(L_INFO, "Loading config from %s", path);
- current_config_path = path;
+ wlr_log(WLR_INFO, "Loading config from %s", path);
struct stat sb;
if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
@@ -322,7 +327,7 @@ static bool load_config(const char *path, struct sway_config *config) {
FILE *f = fopen(path, "r");
if (!f) {
- wlr_log(L_ERROR, "Unable to open %s for reading", path);
+ wlr_log(WLR_ERROR, "Unable to open %s for reading", path);
return false;
}
@@ -330,10 +335,9 @@ static bool load_config(const char *path, struct sway_config *config) {
fclose(f);
if (!config_load_success) {
- wlr_log(L_ERROR, "Error(s) loading config!");
+ wlr_log(WLR_ERROR, "Error(s) loading config!");
}
- current_config_path = NULL;
return true;
}
@@ -353,12 +357,12 @@ bool load_main_config(const char *file, bool is_active) {
config_defaults(config);
if (is_active) {
- wlr_log(L_DEBUG, "Performing configuration file reload");
+ wlr_log(WLR_DEBUG, "Performing configuration file reload");
config->reloading = true;
config->active = true;
}
- config->current_config = path;
+ config->current_config_path = path;
list_add(config->config_chain, path);
config->reading = true;
@@ -369,7 +373,7 @@ bool load_main_config(const char *file, bool is_active) {
/*
DIR *dir = opendir(SYSCONFDIR "/sway/security.d");
if (!dir) {
- wlr_log(L_ERROR,
+ wlr_log(WLR_ERROR,
"%s does not exist, sway will have no security configuration"
" and will probably be broken", SYSCONFDIR "/sway/security.d");
} else {
@@ -398,7 +402,7 @@ bool load_main_config(const char *file, bool is_active) {
if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 ||
(((s.st_mode & 0777) != 0644) &&
(s.st_mode & 0777) != 0444)) {
- wlr_log(L_ERROR,
+ wlr_log(WLR_ERROR,
"Refusing to load %s - it must be owned by root "
"and mode 644 or 444", _path);
success = false;
@@ -428,7 +432,7 @@ bool load_main_config(const char *file, bool is_active) {
static bool load_include_config(const char *path, const char *parent_dir,
struct sway_config *config) {
// save parent config
- const char *parent_config = config->current_config;
+ const char *parent_config = config->current_config_path;
char *full_path;
int len = strlen(path);
@@ -436,7 +440,7 @@ static bool load_include_config(const char *path, const char *parent_dir,
len = len + strlen(parent_dir) + 2;
full_path = malloc(len * sizeof(char));
if (!full_path) {
- wlr_log(L_ERROR,
+ wlr_log(WLR_ERROR,
"Unable to allocate full path to included config");
return false;
}
@@ -449,7 +453,7 @@ static bool load_include_config(const char *path, const char *parent_dir,
free(full_path);
if (real_path == NULL) {
- wlr_log(L_DEBUG, "%s not found.", path);
+ wlr_log(WLR_DEBUG, "%s not found.", path);
return false;
}
@@ -458,7 +462,7 @@ static bool load_include_config(const char *path, const char *parent_dir,
for (j = 0; j < config->config_chain->length; ++j) {
char *old_path = config->config_chain->items[j];
if (strcmp(real_path, old_path) == 0) {
- wlr_log(L_DEBUG,
+ wlr_log(WLR_DEBUG,
"%s already included once, won't be included again.",
real_path);
free(real_path);
@@ -466,25 +470,25 @@ static bool load_include_config(const char *path, const char *parent_dir,
}
}
- config->current_config = real_path;
+ config->current_config_path = real_path;
list_add(config->config_chain, real_path);
int index = config->config_chain->length - 1;
if (!load_config(real_path, config)) {
free(real_path);
- config->current_config = parent_config;
+ config->current_config_path = parent_config;
list_del(config->config_chain, index);
return false;
}
- // restore current_config
- config->current_config = parent_config;
+ // restore current_config_path
+ config->current_config_path = parent_config;
return true;
}
bool load_include_configs(const char *path, struct sway_config *config) {
char *wd = getcwd(NULL, 0);
- char *parent_path = strdup(config->current_config);
+ char *parent_path = strdup(config->current_config_path);
const char *parent_dir = dirname(parent_path);
if (chdir(parent_dir) < 0) {
@@ -512,7 +516,7 @@ bool load_include_configs(const char *path, struct sway_config *config) {
// restore wd
if (chdir(wd) < 0) {
free(wd);
- wlr_log(L_ERROR, "failed to restore working directory");
+ wlr_log(WLR_ERROR, "failed to restore working directory");
return false;
}
@@ -527,13 +531,13 @@ static int detect_brace_on_following_line(FILE *file, char *line,
char *peeked = NULL;
long position = 0;
do {
- wlr_log(L_DEBUG, "Peeking line %d", line_number + lines + 1);
+ wlr_log(WLR_DEBUG, "Peeking line %d", line_number + lines + 1);
free(peeked);
peeked = peek_line(file, lines, &position);
if (peeked) {
peeked = strip_whitespace(peeked);
}
- wlr_log(L_DEBUG, "Peeked line: `%s`", peeked);
+ wlr_log(WLR_DEBUG, "Peeked line: `%s`", peeked);
lines++;
} while (peeked && strlen(peeked) == 0);
@@ -552,7 +556,7 @@ static char *expand_line(const char *block, const char *line, bool add_brace) {
+ (add_brace ? 2 : 0) + 1;
char *expanded = calloc(1, size);
if (!expanded) {
- wlr_log(L_ERROR, "Cannot allocate expanded line buffer");
+ wlr_log(WLR_ERROR, "Cannot allocate expanded line buffer");
return NULL;
}
snprintf(expanded, size, "%s%s%s%s", block ? block : "",
@@ -561,10 +565,33 @@ static char *expand_line(const char *block, const char *line, bool add_brace) {
}
bool read_config(FILE *file, struct sway_config *config) {
+ bool reading_main_config = false;
+ char *this_config = NULL;
+ size_t config_size = 0;
+ if (config->current_config == NULL) {
+ reading_main_config = true;
+
+ int ret_seek = fseek(file, 0, SEEK_END);
+ long ret_tell = ftell(file);
+ if (ret_seek == -1 || ret_tell == -1) {
+ wlr_log(WLR_ERROR, "Unable to get size of config file");
+ return false;
+ }
+ config_size = ret_tell;
+ rewind(file);
+
+ config->current_config = this_config = calloc(1, config_size + 1);
+ if (this_config == NULL) {
+ wlr_log(WLR_ERROR, "Unable to allocate buffer for config contents");
+ return false;
+ }
+ }
+
bool success = true;
int line_number = 0;
char *line;
list_t *stack = create_list();
+ size_t read = 0;
while (!feof(file)) {
char *block = stack->length ? stack->items[0] : NULL;
line = read_line(file);
@@ -572,7 +599,26 @@ bool read_config(FILE *file, struct sway_config *config) {
continue;
}
line_number++;
- wlr_log(L_DEBUG, "Read line %d: %s", line_number, line);
+ wlr_log(WLR_DEBUG, "Read line %d: %s", line_number, line);
+
+ if (reading_main_config) {
+ size_t length = strlen(line);
+
+ if (read + length > config_size) {
+ wlr_log(WLR_ERROR, "Config file changed during reading");
+ list_foreach(stack, free);
+ list_free(stack);
+ free(line);
+ return false;
+ }
+
+ strcpy(this_config + read, line);
+ if (line_number != 1) {
+ this_config[read - 1] = '\n';
+ }
+ read += length + 1;
+ }
+
line = strip_whitespace(line);
if (line[0] == '#') {
free(line);
@@ -586,15 +632,16 @@ bool read_config(FILE *file, struct sway_config *config) {
line_number);
if (brace_detected > 0) {
line_number += brace_detected;
- wlr_log(L_DEBUG, "Detected open brace on line %d", line_number);
+ wlr_log(WLR_DEBUG, "Detected open brace on line %d", line_number);
}
char *expanded = expand_line(block, line, brace_detected > 0);
if (!expanded) {
list_foreach(stack, free);
list_free(stack);
+ free(line);
return false;
}
- wlr_log(L_DEBUG, "Expanded line: %s", expanded);
+ wlr_log(WLR_DEBUG, "Expanded line: %s", expanded);
struct cmd_results *res;
if (block && strcmp(block, "<commands>") == 0) {
// Special case
@@ -606,23 +653,23 @@ bool read_config(FILE *file, struct sway_config *config) {
switch(res->status) {
case CMD_FAILURE:
case CMD_INVALID:
- wlr_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number,
- line, res->error, config->current_config);
+ wlr_log(WLR_ERROR, "Error on line %i '%s': %s (%s)", line_number,
+ line, res->error, config->current_config_path);
success = false;
break;
case CMD_DEFER:
- wlr_log(L_DEBUG, "Deferring command `%s'", line);
+ wlr_log(WLR_DEBUG, "Deferring command `%s'", line);
list_add(config->cmd_queue, strdup(line));
break;
case CMD_BLOCK_COMMANDS:
- wlr_log(L_DEBUG, "Entering commands block");
+ wlr_log(WLR_DEBUG, "Entering commands block");
list_insert(stack, 0, "<commands>");
break;
case CMD_BLOCK:
- wlr_log(L_DEBUG, "Entering block '%s'", res->input);
+ wlr_log(WLR_DEBUG, "Entering block '%s'", res->input);
list_insert(stack, 0, strdup(res->input));
if (strcmp(res->input, "bar") == 0) {
config->current_bar = NULL;
@@ -631,7 +678,7 @@ bool read_config(FILE *file, struct sway_config *config) {
case CMD_BLOCK_END:
if (!block) {
- wlr_log(L_DEBUG, "Unmatched '}' on line %i", line_number);
+ wlr_log(WLR_DEBUG, "Unmatched '}' on line %i", line_number);
success = false;
break;
}
@@ -639,7 +686,7 @@ bool read_config(FILE *file, struct sway_config *config) {
config->current_bar = NULL;
}
- wlr_log(L_DEBUG, "Exiting block '%s'", block);
+ wlr_log(WLR_DEBUG, "Exiting block '%s'", block);
list_del(stack, 0);
free(block);
memset(&config->handler_context, 0,
@@ -682,7 +729,7 @@ char *do_var_replacement(char *str) {
int vvlen = strlen(var->value);
char *newstr = malloc(strlen(str) - vnlen + vvlen + 1);
if (!newstr) {
- wlr_log(L_ERROR,
+ wlr_log(WLR_ERROR,
"Unable to allocate replacement "
"during variable expansion");
break;
@@ -744,6 +791,6 @@ void config_update_font_height(bool recalculate) {
}
if (config->font_height != prev_max_height) {
- arrange_and_commit(&root_container);
+ arrange_windows(&root_container);
}
}
diff --git a/sway/config/bar.c b/sway/config/bar.c
index ee062c6a..3a74331e 100644
--- a/sway/config/bar.c
+++ b/sway/config/bar.c
@@ -16,10 +16,10 @@
#include "log.h"
static void terminate_swaybar(pid_t pid) {
- wlr_log(L_DEBUG, "Terminating swaybar %d", pid);
+ wlr_log(WLR_DEBUG, "Terminating swaybar %d", pid);
int ret = kill(-pid, SIGTERM);
if (ret != 0) {
- wlr_log_errno(L_ERROR, "Unable to terminate swaybar %d", pid);
+ wlr_log_errno(WLR_ERROR, "Unable to terminate swaybar %d", pid);
} else {
int status;
waitpid(pid, &status, 0);
@@ -167,7 +167,7 @@ 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");
+ wlr_log(WLR_ERROR, "Pipe setup failed! Cannot fork into bar");
return;
}
@@ -197,17 +197,17 @@ void invoke_swaybar(struct bar_config *bar) {
execvp(cmd[0], cmd);
exit(1);
}
- wlr_log(L_DEBUG, "Spawned swaybar %d", bar->pid);
+ wlr_log(WLR_DEBUG, "Spawned swaybar %d", bar->pid);
close(filedes[0]);
size_t len;
if (read(filedes[1], &len, sizeof(size_t)) == sizeof(size_t)) {
char *buf = malloc(len);
if(!buf) {
- wlr_log(L_ERROR, "Cannot allocate error string");
+ wlr_log(WLR_ERROR, "Cannot allocate error string");
return;
}
if (read(filedes[1], buf, len)) {
- wlr_log(L_ERROR, "%s", buf);
+ wlr_log(WLR_ERROR, "%s", buf);
}
free(buf);
}
@@ -244,7 +244,7 @@ void load_swaybars() {
if (bar->pid != 0) {
terminate_swaybar(bar->pid);
}
- wlr_log(L_DEBUG, "Invoking swaybar for bar id '%s'", bar->id);
+ wlr_log(WLR_DEBUG, "Invoking swaybar for bar id '%s'", bar->id);
invoke_swaybar(bar);
}
}
diff --git a/sway/config/input.c b/sway/config/input.c
index 17303ccc..8d687a6d 100644
--- a/sway/config/input.c
+++ b/sway/config/input.c
@@ -8,17 +8,18 @@
struct input_config *new_input_config(const char* identifier) {
struct input_config *input = calloc(1, sizeof(struct input_config));
if (!input) {
- wlr_log(L_DEBUG, "Unable to allocate input config");
+ wlr_log(WLR_DEBUG, "Unable to allocate input config");
return NULL;
}
- wlr_log(L_DEBUG, "new_input_config(%s)", identifier);
+ wlr_log(WLR_DEBUG, "new_input_config(%s)", identifier);
if (!(input->identifier = strdup(identifier))) {
free(input);
- wlr_log(L_DEBUG, "Unable to allocate input config");
+ wlr_log(WLR_DEBUG, "Unable to allocate input config");
return NULL;
}
input->tap = INT_MIN;
+ input->tap_button_map = INT_MIN;
input->drag_lock = INT_MIN;
input->dwt = INT_MIN;
input->send_events = INT_MIN;
@@ -27,6 +28,7 @@ struct input_config *new_input_config(const char* identifier) {
input->natural_scroll = INT_MIN;
input->accel_profile = INT_MIN;
input->pointer_accel = FLT_MIN;
+ input->scroll_button = INT_MIN;
input->scroll_method = INT_MIN;
input->left_handed = INT_MIN;
input->repeat_delay = INT_MIN;
@@ -70,12 +72,18 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
if (src->scroll_method != INT_MIN) {
dst->scroll_method = src->scroll_method;
}
+ if (src->scroll_button != INT_MIN) {
+ dst->scroll_button = src->scroll_button;
+ }
if (src->send_events != INT_MIN) {
dst->send_events = src->send_events;
}
if (src->tap != INT_MIN) {
dst->tap = src->tap;
}
+ if (src->tap_button_map != INT_MIN) {
+ dst->tap_button_map = src->tap_button_map;
+ }
if (src->xkb_layout) {
free(dst->xkb_layout);
dst->xkb_layout = strdup(src->xkb_layout);
@@ -112,7 +120,7 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
struct input_config *copy_input_config(struct input_config *ic) {
struct input_config *copy = calloc(1, sizeof(struct input_config));
if (copy == NULL) {
- wlr_log(L_ERROR, "could not allocate input config");
+ wlr_log(WLR_ERROR, "could not allocate input config");
return NULL;
}
merge_input_config(copy, ic);
diff --git a/sway/config/output.c b/sway/config/output.c
index 648ded27..1bf9e5f1 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -90,7 +90,7 @@ static void set_mode(struct wlr_output *output, int width, int height,
float refresh_rate) {
int mhz = (int)(refresh_rate * 1000);
if (wl_list_empty(&output->modes)) {
- wlr_log(L_DEBUG, "Assigning custom mode to %s", output->name);
+ wlr_log(WLR_DEBUG, "Assigning custom mode to %s", output->name);
wlr_output_set_custom_mode(output, width, height, mhz);
return;
}
@@ -106,9 +106,9 @@ static void set_mode(struct wlr_output *output, int width, int height,
}
}
if (!best) {
- wlr_log(L_ERROR, "Configured mode for %s not available", output->name);
+ wlr_log(WLR_ERROR, "Configured mode for %s not available", output->name);
} else {
- wlr_log(L_DEBUG, "Assigning configured mode to %s", output->name);
+ wlr_log(WLR_DEBUG, "Assigning configured mode to %s", output->name);
wlr_output_set_mode(output, best);
}
}
@@ -116,7 +116,7 @@ static void set_mode(struct wlr_output *output, int width, int height,
void terminate_swaybg(pid_t pid) {
int ret = kill(pid, SIGTERM);
if (ret != 0) {
- wlr_log(L_ERROR, "Unable to terminate swaybg [pid: %d]", pid);
+ wlr_log(WLR_ERROR, "Unable to terminate swaybg [pid: %d]", pid);
} else {
int status;
waitpid(pid, &status, 0);
@@ -144,22 +144,22 @@ void apply_output_config(struct output_config *oc, struct sway_container *output
}
if (oc && oc->width > 0 && oc->height > 0) {
- wlr_log(L_DEBUG, "Set %s mode to %dx%d (%f GHz)", oc->name, oc->width,
+ wlr_log(WLR_DEBUG, "Set %s mode to %dx%d (%f GHz)", oc->name, oc->width,
oc->height, oc->refresh_rate);
set_mode(wlr_output, oc->width, oc->height, oc->refresh_rate);
}
if (oc && oc->scale > 0) {
- wlr_log(L_DEBUG, "Set %s scale to %f", oc->name, oc->scale);
+ wlr_log(WLR_DEBUG, "Set %s scale to %f", oc->name, oc->scale);
wlr_output_set_scale(wlr_output, oc->scale);
}
if (oc && oc->transform >= 0) {
- wlr_log(L_DEBUG, "Set %s transform to %d", oc->name, oc->transform);
+ wlr_log(WLR_DEBUG, "Set %s transform to %d", oc->name, oc->transform);
wlr_output_set_transform(wlr_output, oc->transform);
}
// Find position for it
if (oc && (oc->x != -1 || oc->y != -1)) {
- wlr_log(L_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y);
+ wlr_log(WLR_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y);
wlr_output_layout_add(output_layout, wlr_output, oc->x, oc->y);
} else {
wlr_output_layout_add_auto(output_layout, wlr_output);
@@ -187,7 +187,7 @@ void apply_output_config(struct output_config *oc, struct sway_container *output
terminate_swaybg(output->sway_output->bg_pid);
}
- wlr_log(L_DEBUG, "Setting background for output %d to %s",
+ 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",
@@ -195,28 +195,30 @@ void apply_output_config(struct output_config *oc, struct sway_container *output
output_i, oc->background, oc->background_option);
char *command = malloc(len + 1);
if (!command) {
- wlr_log(L_DEBUG, "Unable to allocate swaybg command");
+ wlr_log(WLR_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);
+ wlr_log(WLR_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);
+ } else {
+ free(command);
}
}
if (oc && oc->dpms_state != DPMS_IGNORE) {
switch (oc->dpms_state) {
case DPMS_ON:
- wlr_log(L_DEBUG, "Turning on screen");
+ wlr_log(WLR_DEBUG, "Turning on screen");
wlr_output_enable(wlr_output, true);
break;
case DPMS_OFF:
- wlr_log(L_DEBUG, "Turning off screen");
+ wlr_log(WLR_DEBUG, "Turning off screen");
wlr_output_enable(wlr_output, false);
break;
case DPMS_IGNORE:
diff --git a/sway/config/seat.c b/sway/config/seat.c
index bd8b45c8..83dac4c0 100644
--- a/sway/config/seat.c
+++ b/sway/config/seat.c
@@ -7,11 +7,11 @@
struct seat_config *new_seat_config(const char* name) {
struct seat_config *seat = calloc(1, sizeof(struct seat_config));
if (!seat) {
- wlr_log(L_DEBUG, "Unable to allocate seat config");
+ wlr_log(WLR_DEBUG, "Unable to allocate seat config");
return NULL;
}
- wlr_log(L_DEBUG, "new_seat_config(%s)", name);
+ wlr_log(WLR_DEBUG, "new_seat_config(%s)", name);
seat->name = strdup(name);
if (!sway_assert(seat->name, "could not allocate name for seat")) {
free(seat);
@@ -34,7 +34,7 @@ struct seat_attachment_config *seat_attachment_config_new() {
struct seat_attachment_config *attachment =
calloc(1, sizeof(struct seat_attachment_config));
if (!attachment) {
- wlr_log(L_DEBUG, "cannot allocate attachment config");
+ wlr_log(WLR_DEBUG, "cannot allocate attachment config");
return NULL;
}
return attachment;
diff --git a/sway/criteria.c b/sway/criteria.c
index d9f09ecc..e2b248de 100644
--- a/sway/criteria.c
+++ b/sway/criteria.c
@@ -37,7 +37,7 @@ void criteria_destroy(struct criteria *criteria) {
pcre_free(criteria->con_mark);
pcre_free(criteria->window_role);
free(criteria->workspace);
-
+ free(criteria->cmdlist);
free(criteria->raw);
free(criteria);
}
@@ -46,6 +46,31 @@ static int regex_cmp(const char *item, const pcre *regex) {
return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0);
}
+static int cmp_urgent(const void *_a, const void *_b) {
+ struct sway_view *a = *(void **)_a;
+ struct sway_view *b = *(void **)_b;
+
+ if (a->urgent.tv_sec < b->urgent.tv_sec) {
+ return -1;
+ } else if (a->urgent.tv_sec > b->urgent.tv_sec) {
+ return 1;
+ }
+ if (a->urgent.tv_nsec < b->urgent.tv_nsec) {
+ return -1;
+ } else if (a->urgent.tv_nsec > b->urgent.tv_nsec) {
+ return 1;
+ }
+ return 0;
+}
+
+static void find_urgent_iterator(struct sway_container *swayc, void *data) {
+ if (swayc->type != C_VIEW || !view_is_urgent(swayc->sway_view)) {
+ return;
+ }
+ list_t *urgent_views = data;
+ list_add(urgent_views, swayc->sway_view);
+}
+
static bool criteria_matches_view(struct criteria *criteria,
struct sway_view *view) {
if (criteria->title) {
@@ -133,8 +158,23 @@ static bool criteria_matches_view(struct criteria *criteria,
}
if (criteria->urgent) {
- // TODO
- return false;
+ if (!view_is_urgent(view)) {
+ return false;
+ }
+ list_t *urgent_views = create_list();
+ container_for_each_descendant_dfs(&root_container,
+ find_urgent_iterator, urgent_views);
+ list_stable_sort(urgent_views, cmp_urgent);
+ struct sway_view *target;
+ if (criteria->urgent == 'o') { // oldest
+ target = urgent_views->items[0];
+ } else { // latest
+ target = urgent_views->items[urgent_views->length - 1];
+ }
+ list_free(urgent_views);
+ if (view != target) {
+ return false;
+ }
}
if (criteria->workspace) {
@@ -507,7 +547,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) {
}
unescape(value);
}
- wlr_log(L_DEBUG, "Found pair: %s=%s", name, value);
+ wlr_log(WLR_DEBUG, "Found pair: %s=%s", name, value);
if (!parse_token(criteria, name, value)) {
*error_arg = error;
goto cleanup;
diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c
index e495790c..6575519d 100644
--- a/sway/desktop/desktop.c
+++ b/sway/desktop/desktop.c
@@ -13,3 +13,12 @@ void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
}
}
}
+
+void desktop_damage_whole_container(struct sway_container *con) {
+ for (int i = 0; i < root_container.children->length; ++i) {
+ struct sway_container *cont = root_container.children->items[i];
+ if (cont->type == C_OUTPUT) {
+ output_damage_whole_container(cont->sway_output, con);
+ }
+ }
+}
diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c
index c02ca26e..da17d0f2 100644
--- a/sway/desktop/idle_inhibit_v1.c
+++ b/sway/desktop/idle_inhibit_v1.c
@@ -9,7 +9,7 @@
static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_idle_inhibitor_v1 *inhibitor =
wl_container_of(listener, inhibitor, destroy);
- wlr_log(L_DEBUG, "Sway idle inhibitor destroyed");
+ wlr_log(WLR_DEBUG, "Sway idle inhibitor destroyed");
wl_list_remove(&inhibitor->link);
wl_list_remove(&inhibitor->destroy.link);
idle_inhibit_v1_check_active(inhibitor->manager);
@@ -20,7 +20,7 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) {
struct wlr_idle_inhibitor_v1 *wlr_inhibitor = data;
struct sway_idle_inhibit_manager_v1 *manager =
wl_container_of(listener, manager, new_idle_inhibitor_v1);
- wlr_log(L_DEBUG, "New sway idle inhibitor");
+ wlr_log(WLR_DEBUG, "New sway idle inhibitor");
struct sway_idle_inhibitor_v1 *inhibitor =
calloc(1, sizeof(struct sway_idle_inhibitor_v1));
@@ -67,6 +67,7 @@ struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create(
manager->wlr_manager = wlr_idle_inhibit_v1_create(wl_display);
if (!manager->wlr_manager) {
+ free(manager);
return NULL;
}
manager->idle = idle;
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index de1fe349..a7d96717 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -12,7 +12,6 @@
#include "sway/layers.h"
#include "sway/output.h"
#include "sway/server.h"
-#include "sway/tree/arrange.h"
#include "sway/tree/layout.h"
#include "log.h"
@@ -174,9 +173,9 @@ void arrange_layers(struct sway_output *output) {
if (memcmp(&usable_area, &output->usable_area,
sizeof(struct wlr_box)) != 0) {
- wlr_log(L_DEBUG, "Usable area changed, rearranging output");
+ wlr_log(WLR_DEBUG, "Usable area changed, rearranging output");
memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box));
- arrange_and_commit(output->swayc);
+ container_set_dirty(output->swayc);
}
// Arrange non-exlusive surfaces from top->bottom
@@ -269,7 +268,7 @@ static void unmap(struct sway_layer_surface *sway_layer) {
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)",
+ wlr_log(WLR_DEBUG, "Layer surface destroyed (%s)",
sway_layer->layer_surface->namespace);
if (sway_layer->layer_surface->mapped) {
unmap(sway_layer);
@@ -316,7 +315,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
struct wlr_layer_surface *layer_surface = data;
struct sway_server *server =
wl_container_of(listener, server, layer_shell_surface);
- wlr_log(L_DEBUG, "new layer surface: namespace %s layer %d anchor %d "
+ wlr_log(WLR_DEBUG, "new layer surface: namespace %s layer %d anchor %d "
"size %dx%d margin %d,%d,%d,%d",
layer_surface->namespace, layer_surface->layer, layer_surface->layer,
layer_surface->client_pending.desired_width,
@@ -326,12 +325,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
layer_surface->client_pending.margin.bottom,
layer_surface->client_pending.margin.left);
- struct sway_layer_surface *sway_layer =
- calloc(1, sizeof(struct sway_layer_surface));
- if (!sway_layer) {
- return;
- }
-
if (!layer_surface->output) {
// Assign last active output
struct sway_container *output = NULL;
@@ -353,6 +346,12 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
layer_surface->output = output->sway_output->wlr_output;
}
+ struct sway_layer_surface *sway_layer =
+ calloc(1, sizeof(struct sway_layer_surface));
+ if (!sway_layer) {
+ return;
+ }
+
sway_layer->surface_commit.notify = handle_surface_commit;
wl_signal_add(&layer_surface->surface->events.commit,
&sway_layer->surface_commit);
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 8b50bc44..a9808406 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -204,11 +204,11 @@ bool output_has_opaque_lockscreen(struct sway_output *output,
};
pixman_region32_t surface_opaque_box;
pixman_region32_init(&surface_opaque_box);
- pixman_region32_copy(&surface_opaque_box, &wlr_surface->current.opaque);
+ pixman_region32_copy(&surface_opaque_box, &wlr_surface->opaque_region);
pixman_region32_translate(&surface_opaque_box,
- sway_layer_surface->geo.x, sway_layer_surface->geo.y);
- bool contains = pixman_region32_contains_rectangle(
- &wlr_surface->current.opaque, &output_box);
+ sway_layer_surface->geo.x, sway_layer_surface->geo.y);
+ bool contains = pixman_region32_contains_rectangle(&surface_opaque_box,
+ &output_box);
pixman_region32_fini(&surface_opaque_box);
if (contains) {
return true;
@@ -492,19 +492,21 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
output->wlr_output->data = NULL;
free(output);
- arrange_and_commit(&root_container);
+ arrange_windows(&root_container);
}
static void handle_mode(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, mode);
arrange_layers(output);
- arrange_and_commit(output->swayc);
+ arrange_windows(output->swayc);
+ transaction_commit_dirty();
}
static void handle_transform(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, transform);
arrange_layers(output);
- arrange_and_commit(output->swayc);
+ arrange_windows(output->swayc);
+ transaction_commit_dirty();
}
static void handle_scale_iterator(struct sway_container *view, void *data) {
@@ -515,7 +517,8 @@ static void handle_scale(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, scale);
arrange_layers(output);
container_descendants(output->swayc, C_VIEW, handle_scale_iterator, NULL);
- arrange_and_commit(output->swayc);
+ arrange_windows(output->swayc);
+ transaction_commit_dirty();
}
struct sway_output *output_from_wlr_output(struct wlr_output *wlr_output) {
@@ -525,7 +528,7 @@ struct sway_output *output_from_wlr_output(struct wlr_output *wlr_output) {
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;
- wlr_log(L_DEBUG, "New output %p: %s", wlr_output, wlr_output->name);
+ wlr_log(WLR_DEBUG, "New output %p: %s", wlr_output, wlr_output->name);
struct sway_output *output = calloc(1, sizeof(struct sway_output));
if (!output) {
@@ -584,5 +587,6 @@ void output_enable(struct sway_output *output) {
output->damage_destroy.notify = damage_handle_destroy;
arrange_layers(output);
- arrange_and_commit(&root_container);
+ arrange_windows(&root_container);
+ transaction_commit_dirty();
}
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 43948f29..4c85e516 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -15,6 +15,7 @@
#include <wlr/util/region.h>
#include "log.h"
#include "sway/config.h"
+#include "sway/debug.h"
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
#include "sway/layers.h"
@@ -255,6 +256,10 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,
render_view_surfaces(view, output, damage, view->swayc->alpha);
}
+ if (view->using_csd) {
+ return;
+ }
+
struct wlr_box box;
float output_scale = output->wlr_output->scale;
float color[4];
@@ -542,9 +547,6 @@ static void render_container(struct sway_output *output,
static void render_container_simple(struct sway_output *output,
pixman_region32_t *damage, struct sway_container *con,
bool parent_focused) {
- struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = seat_get_focus(seat);
-
for (int i = 0; i < con->current.children->length; ++i) {
struct sway_container *child = con->current.children->items[i];
@@ -555,11 +557,15 @@ static void render_container_simple(struct sway_output *output,
struct wlr_texture *marks_texture;
struct sway_container_state *state = &child->current;
- if (focus == child || parent_focused) {
+ if (view_is_urgent(view)) {
+ colors = &config->border_colors.urgent;
+ title_texture = child->title_urgent;
+ marks_texture = view->marks_urgent;
+ } else if (state->focused || parent_focused) {
colors = &config->border_colors.focused;
title_texture = child->title_focused;
marks_texture = view->marks_focused;
- } else if (seat_get_focus_inactive(seat, con) == child) {
+ } else if (con->current.focused_inactive_child == child) {
colors = &config->border_colors.focused_inactive;
title_texture = child->title_focused_inactive;
marks_texture = view->marks_focused_inactive;
@@ -569,17 +575,19 @@ static void render_container_simple(struct sway_output *output,
marks_texture = view->marks_unfocused;
}
- if (state->border == B_NORMAL) {
- render_titlebar(output, damage, child, state->swayc_x,
- state->swayc_y, state->swayc_width, colors,
- title_texture, marks_texture);
- } else {
- render_top_border(output, damage, child, colors);
+ if (!view->using_csd) {
+ if (state->border == B_NORMAL) {
+ render_titlebar(output, damage, child, state->swayc_x,
+ state->swayc_y, state->swayc_width, colors,
+ title_texture, marks_texture);
+ } else {
+ render_top_border(output, damage, child, colors);
+ }
}
render_view(output, damage, child, colors);
} else {
render_container(output, damage, child,
- parent_focused || focus == child);
+ parent_focused || child->current.focused);
}
}
}
@@ -593,26 +601,34 @@ static void render_container_tabbed(struct sway_output *output,
if (!con->current.children->length) {
return;
}
- struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = seat_get_focus(seat);
- struct sway_container *current = seat_get_active_current_child(seat, con);
- struct border_colors *current_colors = &config->border_colors.unfocused;
struct sway_container_state *pstate = &con->current;
+ struct sway_container *current = pstate->focused_inactive_child;
+ struct border_colors *current_colors = &config->border_colors.unfocused;
+
+ double width_gap_adjustment = 2 * pstate->current_gaps;
+ int tab_width =
+ (pstate->swayc_width - width_gap_adjustment) / pstate->children->length;
// Render tabs
- for (int i = 0; i < con->current.children->length; ++i) {
- struct sway_container *child = con->current.children->items[i];
+ for (int i = 0; i < pstate->children->length; ++i) {
+ struct sway_container *child = pstate->children->items[i];
struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL;
struct sway_container_state *cstate = &child->current;
struct border_colors *colors;
struct wlr_texture *title_texture;
struct wlr_texture *marks_texture;
-
- if (focus == child || parent_focused) {
+ bool urgent = view ?
+ view_is_urgent(view) : container_has_urgent_child(child);
+
+ if (urgent) {
+ colors = &config->border_colors.urgent;
+ title_texture = child->title_urgent;
+ marks_texture = view ? view->marks_urgent : NULL;
+ } else if (cstate->focused || parent_focused) {
colors = &config->border_colors.focused;
title_texture = child->title_focused;
marks_texture = view ? view->marks_focused : NULL;
- } else if (child == current) {
+ } else if (child == pstate->focused_inactive_child) {
colors = &config->border_colors.focused_inactive;
title_texture = child->title_focused_inactive;
marks_texture = view ? view->marks_focused_inactive : NULL;
@@ -622,11 +638,12 @@ static void render_container_tabbed(struct sway_output *output,
marks_texture = view ? view->marks_unfocused : NULL;
}
- int tab_width = pstate->swayc_width / pstate->children->length;
- int x = pstate->swayc_x + tab_width * i;
+ int x = cstate->swayc_x + tab_width * i;
+
// Make last tab use the remaining width of the parent
if (i == pstate->children->length - 1) {
- tab_width = pstate->swayc_width - tab_width * i;
+ tab_width =
+ pstate->swayc_width - width_gap_adjustment - tab_width * i;
}
render_titlebar(output, damage, child, x, cstate->swayc_y, tab_width,
@@ -638,13 +655,11 @@ static void render_container_tabbed(struct sway_output *output,
}
// Render surface and left/right/bottom borders
- if (current) {
- if (current->type == C_VIEW) {
- render_view(output, damage, current, current_colors);
- } else {
- render_container(output, damage, current,
- parent_focused || current == focus);
- }
+ if (current->type == C_VIEW) {
+ render_view(output, damage, current, current_colors);
+ } else {
+ render_container(output, damage, current,
+ parent_focused || current->current.focused);
}
}
@@ -657,26 +672,32 @@ static void render_container_stacked(struct sway_output *output,
if (!con->current.children->length) {
return;
}
- struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = seat_get_focus(seat);
- struct sway_container *current = seat_get_active_current_child(seat, con);
- struct border_colors *current_colors = &config->border_colors.unfocused;
struct sway_container_state *pstate = &con->current;
+ struct sway_container *current = pstate->focused_inactive_child;
+ struct border_colors *current_colors = &config->border_colors.unfocused;
+
+ size_t titlebar_height = container_titlebar_height();
// Render titles
- for (int i = 0; i < con->current.children->length; ++i) {
- struct sway_container *child = con->current.children->items[i];
+ for (int i = 0; i < pstate->children->length; ++i) {
+ struct sway_container *child = pstate->children->items[i];
struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL;
struct sway_container_state *cstate = &child->current;
struct border_colors *colors;
struct wlr_texture *title_texture;
struct wlr_texture *marks_texture;
-
- if (focus == child || parent_focused) {
+ bool urgent = view ?
+ view_is_urgent(view) : container_has_urgent_child(child);
+
+ if (urgent) {
+ colors = &config->border_colors.urgent;
+ title_texture = child->title_urgent;
+ marks_texture = view ? view->marks_urgent : NULL;
+ } else if (cstate->focused || parent_focused) {
colors = &config->border_colors.focused;
title_texture = child->title_focused;
marks_texture = view ? view->marks_focused : NULL;
- } else if (child == current) {
+ } else if (child == pstate->focused_inactive_child) {
colors = &config->border_colors.focused_inactive;
title_texture = child->title_focused_inactive;
marks_texture = view ? view->marks_focused_inactive : NULL;
@@ -686,7 +707,7 @@ static void render_container_stacked(struct sway_output *output,
marks_texture = view ? view->marks_unfocused : NULL;
}
- int y = pstate->swayc_y + container_titlebar_height() * i;
+ int y = cstate->swayc_y + titlebar_height * i;
render_titlebar(output, damage, child, cstate->swayc_x, y,
cstate->swayc_width, colors, title_texture, marks_texture);
@@ -696,13 +717,11 @@ static void render_container_stacked(struct sway_output *output,
}
// Render surface and left/right/bottom borders
- if (current) {
- if (current->type == C_VIEW) {
- render_view(output, damage, current, current_colors);
- } else {
- render_container(output, damage, current,
- parent_focused || current == focus);
- }
+ if (current->type == C_VIEW) {
+ render_view(output, damage, current, current_colors);
+ } else {
+ render_container(output, damage, current,
+ parent_focused || current->current.focused);
}
}
@@ -730,13 +749,15 @@ static void render_floating_container(struct sway_output *soutput,
pixman_region32_t *damage, struct sway_container *con) {
if (con->type == C_VIEW) {
struct sway_view *view = con->sway_view;
- struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = seat_get_focus(seat);
struct border_colors *colors;
struct wlr_texture *title_texture;
struct wlr_texture *marks_texture;
- if (focus == con) {
+ if (view_is_urgent(view)) {
+ colors = &config->border_colors.urgent;
+ title_texture = con->title_urgent;
+ marks_texture = view->marks_urgent;
+ } else if (con->current.focused) {
colors = &config->border_colors.focused;
title_texture = con->title_focused;
marks_texture = view->marks_focused;
@@ -746,12 +767,14 @@ static void render_floating_container(struct sway_output *soutput,
marks_texture = view->marks_unfocused;
}
- if (con->current.border == B_NORMAL) {
- render_titlebar(soutput, damage, con, con->current.swayc_x,
- con->current.swayc_y, con->current.swayc_width, colors,
- title_texture, marks_texture);
- } else if (con->current.border != B_NONE) {
- render_top_border(soutput, damage, con, colors);
+ if (!view->using_csd) {
+ if (con->current.border == B_NORMAL) {
+ render_titlebar(soutput, damage, con, con->current.swayc_x,
+ con->current.swayc_y, con->current.swayc_width, colors,
+ title_texture, marks_texture);
+ } else if (con->current.border != B_NONE) {
+ render_top_border(soutput, damage, con, colors);
+ }
}
render_view(soutput, damage, con, colors);
} else {
@@ -779,6 +802,8 @@ static void render_floating(struct sway_output *soutput,
}
}
+const char *damage_debug = NULL;
+
void output_render(struct sway_output *output, struct timespec *when,
pixman_region32_t *damage) {
struct wlr_output *wlr_output = output->wlr_output;
@@ -798,7 +823,6 @@ void output_render(struct sway_output *output, struct timespec *when,
goto renderer_end;
}
- const char *damage_debug = getenv("SWAY_DAMAGE_DEBUG");
if (damage_debug != NULL) {
if (strcmp(damage_debug, "highlight") == 0) {
wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1});
@@ -837,7 +861,11 @@ void output_render(struct sway_output *output, struct timespec *when,
}
// TODO: handle views smaller than the output
- render_view_surfaces(fullscreen_view, output, damage, 1.0f);
+ if (fullscreen_view->swayc->instructions->length) {
+ render_saved_view(fullscreen_view, output, damage, 1.0f);
+ } else {
+ render_view_surfaces(fullscreen_view, output, damage, 1.0f);
+ }
if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) {
render_unmanaged(output, damage,
@@ -858,9 +886,7 @@ void output_render(struct sway_output *output, struct timespec *when,
render_layer(output, damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
- struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_container *focus = seat_get_focus(seat);
- render_container(output, damage, workspace, focus == workspace);
+ render_container(output, damage, workspace, workspace->current.focused);
render_floating(output, damage);
render_unmanaged(output, damage,
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index 179af617..fcfb0b51 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -19,14 +19,14 @@
* How long we should wait for views to respond to the configure before giving
* up and applying the transaction anyway.
*/
-#define TIMEOUT_MS 200
+int txn_timeout_ms = 200;
/**
* If enabled, sway will always wait for the transaction timeout before
* applying it, rather than applying it when the views are ready. This allows us
* to observe the rendered state while a transaction is in progress.
*/
-#define TRANSACTION_DEBUG false
+bool txn_debug = false;
struct sway_transaction {
struct wl_event_source *timer;
@@ -47,7 +47,7 @@ struct sway_transaction_instruction {
bool ready;
};
-struct sway_transaction *transaction_create() {
+static struct sway_transaction *transaction_create() {
struct sway_transaction *transaction =
calloc(1, sizeof(struct sway_transaction));
transaction->instructions = create_list();
@@ -139,25 +139,18 @@ static void copy_pending_state(struct sway_container *container,
state->children = create_list();
list_cat(state->children, container->children);
}
-}
-static bool transaction_has_container(struct sway_transaction *transaction,
- struct sway_container *container) {
- for (int i = 0; i < transaction->instructions->length; ++i) {
- struct sway_transaction_instruction *instruction =
- transaction->instructions->items[i];
- if (instruction->container == container) {
- return true;
- }
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+ state->focused = seat_get_focus(seat) == container;
+
+ if (container->type != C_VIEW) {
+ state->focused_inactive_child =
+ seat_get_active_child(seat, container);
}
- return false;
}
-void transaction_add_container(struct sway_transaction *transaction,
+static void transaction_add_container(struct sway_transaction *transaction,
struct sway_container *container) {
- if (transaction_has_container(transaction, container)) {
- return;
- }
struct sway_transaction_instruction *instruction =
calloc(1, sizeof(struct sway_transaction_instruction));
instruction->transaction = transaction;
@@ -175,7 +168,7 @@ void transaction_add_container(struct sway_transaction *transaction,
* Apply a transaction to the "current" state of the tree.
*/
static void transaction_apply(struct sway_transaction *transaction) {
- wlr_log(L_DEBUG, "Applying transaction %p", transaction);
+ wlr_log(WLR_DEBUG, "Applying transaction %p", transaction);
if (server.debug_txn_timings) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
@@ -186,7 +179,7 @@ static void transaction_apply(struct sway_transaction *transaction) {
float ms_waiting = (now.tv_sec - commit->tv_sec) * 1000 +
(now.tv_nsec - commit->tv_nsec) / 1000000.0;
float ms_total = ms_arranging + ms_waiting;
- wlr_log(L_DEBUG, "Transaction %p: %.1fms arranging, %.1fms waiting, "
+ wlr_log(WLR_DEBUG, "Transaction %p: %.1fms arranging, %.1fms waiting, "
"%.1fms total (%.1f frames if 60Hz)", transaction,
ms_arranging, ms_waiting, ms_total, ms_total / (1000.0f / 60));
}
@@ -210,10 +203,12 @@ static void transaction_apply(struct sway_transaction *transaction) {
.width = instruction->state.swayc_width,
.height = instruction->state.swayc_height,
};
- for (int j = 0; j < root_container.children->length; ++j) {
- struct sway_container *output = root_container.children->items[j];
- output_damage_box(output->sway_output, &old_box);
- output_damage_box(output->sway_output, &new_box);
+ for (int j = 0; j < root_container.current.children->length; ++j) {
+ struct sway_container *output = root_container.current.children->items[j];
+ if (output->sway_output) {
+ output_damage_box(output->sway_output, &old_box);
+ output_damage_box(output->sway_output, &new_box);
+ }
}
// There are separate children lists for each instruction state, the
@@ -251,7 +246,7 @@ static void transaction_progress_queue() {
static int handle_timeout(void *data) {
struct sway_transaction *transaction = data;
- wlr_log(L_DEBUG, "Transaction %p timed out (%li waiting)",
+ wlr_log(WLR_DEBUG, "Transaction %p timed out (%li waiting)",
transaction, transaction->num_waiting);
transaction->num_waiting = 0;
transaction_progress_queue();
@@ -285,8 +280,8 @@ static bool should_configure(struct sway_container *con,
return true;
}
-void transaction_commit(struct sway_transaction *transaction) {
- wlr_log(L_DEBUG, "Transaction %p committing with %i instructions",
+static void transaction_commit(struct sway_transaction *transaction) {
+ wlr_log(WLR_DEBUG, "Transaction %p committing with %i instructions",
transaction, transaction->instructions->length);
transaction->num_waiting = 0;
for (int i = 0; i < transaction->instructions->length; ++i) {
@@ -319,7 +314,7 @@ void transaction_commit(struct sway_transaction *transaction) {
} else {
// There are no other transactions in progress, and this one has nothing
// to wait for, so we can skip the queue.
- wlr_log(L_DEBUG, "Transaction %p has nothing to wait for", transaction);
+ wlr_log(WLR_DEBUG, "Transaction %p has nothing to wait for", transaction);
transaction_apply(transaction);
transaction_destroy(transaction);
idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
@@ -330,7 +325,7 @@ void transaction_commit(struct sway_transaction *transaction) {
// Set up a timer which the views must respond within
transaction->timer = wl_event_loop_add_timer(server.wl_event_loop,
handle_timeout, transaction);
- wl_event_source_timer_update(transaction->timer, TIMEOUT_MS);
+ wl_event_source_timer_update(transaction->timer, txn_timeout_ms);
}
// The debug tree shows the pending/live tree. Here is a good place to
@@ -350,7 +345,7 @@ static void set_instruction_ready(
struct timespec *start = &transaction->commit_time;
float ms = (now.tv_sec - start->tv_sec) * 1000 +
(now.tv_nsec - start->tv_nsec) / 1000000.0;
- wlr_log(L_DEBUG, "Transaction %p: %li/%li ready in %.1fms (%s)",
+ wlr_log(WLR_DEBUG, "Transaction %p: %li/%li ready in %.1fms (%s)",
transaction,
transaction->num_configures - transaction->num_waiting + 1,
transaction->num_configures, ms,
@@ -361,11 +356,11 @@ static void set_instruction_ready(
// If all views are ready, apply the transaction.
// If the transaction has timed out then its num_waiting will be 0 already.
if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) {
-#if !TRANSACTION_DEBUG
- wlr_log(L_DEBUG, "Transaction %p is ready", transaction);
- wl_event_source_timer_update(transaction->timer, 0);
- transaction_progress_queue();
-#endif
+ if (!txn_debug) {
+ wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction);
+ wl_event_source_timer_update(transaction->timer, 0);
+ transaction_progress_queue();
+ }
}
}
@@ -418,3 +413,17 @@ struct wlr_texture *transaction_get_saved_texture(struct sway_view *view,
*height = instruction->saved_buffer_height;
return instruction->saved_buffer->texture;
}
+
+void transaction_commit_dirty(void) {
+ if (!server.dirty_containers->length) {
+ return;
+ }
+ struct sway_transaction *transaction = transaction_create();
+ for (int i = 0; i < server.dirty_containers->length; ++i) {
+ struct sway_container *container = server.dirty_containers->items[i];
+ transaction_add_container(transaction, container);
+ container->dirty = false;
+ }
+ server.dirty_containers->length = 0;
+ transaction_commit(transaction);
+}
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index ac35a8d1..98c16faf 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -45,6 +45,24 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) {
view_child_destroy(&popup->child);
}
+static void popup_unconstrain(struct sway_xdg_popup *popup) {
+ struct sway_view *view = popup->child.view;
+ struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup;
+
+ struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
+
+ // the output box expressed in the coordinate system of the toplevel parent
+ // of the popup
+ struct wlr_box output_toplevel_sx_box = {
+ .x = output->x - view->x,
+ .y = output->y - view->y,
+ .width = output->width,
+ .height = output->height,
+ };
+
+ wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
+}
+
static struct sway_xdg_popup *popup_create(
struct wlr_xdg_popup *wlr_popup, struct sway_view *view) {
struct wlr_xdg_surface *xdg_surface = wlr_popup->base;
@@ -55,12 +73,15 @@ static struct sway_xdg_popup *popup_create(
return NULL;
}
view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface);
+ popup->wlr_xdg_surface = xdg_surface;
wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup);
popup->new_popup.notify = popup_handle_new_popup;
wl_signal_add(&xdg_surface->events.destroy, &popup->destroy);
popup->destroy.notify = popup_handle_destroy;
+ popup_unconstrain(popup);
+
return popup;
}
@@ -223,7 +244,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
view_set_fullscreen(view, e->fullscreen);
struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
- arrange_and_commit(output);
+ arrange_windows(output);
+ transaction_commit_dirty();
}
static void handle_unmap(struct wl_listener *listener, void *data) {
@@ -260,10 +282,11 @@ static void handle_map(struct wl_listener *listener, void *data) {
if (xdg_surface->toplevel->client_pending.fullscreen) {
view_set_fullscreen(view, true);
struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
- arrange_and_commit(ws);
+ arrange_windows(ws);
} else {
- arrange_and_commit(view->swayc->parent);
+ arrange_windows(view->swayc->parent);
}
+ transaction_commit_dirty();
xdg_shell_view->commit.notify = handle_commit;
wl_signal_add(&xdg_surface->surface->events.commit,
@@ -304,11 +327,11 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
struct wlr_xdg_surface *xdg_surface = data;
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
- wlr_log(L_DEBUG, "New xdg_shell popup");
+ wlr_log(WLR_DEBUG, "New xdg_shell popup");
return;
}
- wlr_log(L_DEBUG, "New xdg_shell toplevel title='%s' app_id='%s'",
+ wlr_log(WLR_DEBUG, "New xdg_shell toplevel title='%s' app_id='%s'",
xdg_surface->toplevel->title, xdg_surface->toplevel->app_id);
wlr_xdg_surface_ping(xdg_surface);
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 56bbb244..4d76f0a7 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -44,6 +44,24 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) {
view_child_destroy(&popup->child);
}
+static void popup_unconstrain(struct sway_xdg_popup_v6 *popup) {
+ struct sway_view *view = popup->child.view;
+ struct wlr_xdg_popup_v6 *wlr_popup = popup->wlr_xdg_surface_v6->popup;
+
+ struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
+
+ // the output box expressed in the coordinate system of the toplevel parent
+ // of the popup
+ struct wlr_box output_toplevel_sx_box = {
+ .x = output->x - view->x,
+ .y = output->y - view->y,
+ .width = output->width,
+ .height = output->height,
+ };
+
+ wlr_xdg_popup_v6_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
+}
+
static struct sway_xdg_popup_v6 *popup_create(
struct wlr_xdg_popup_v6 *wlr_popup, struct sway_view *view) {
struct wlr_xdg_surface_v6 *xdg_surface = wlr_popup->base;
@@ -54,12 +72,15 @@ static struct sway_xdg_popup_v6 *popup_create(
return NULL;
}
view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface);
+ popup->wlr_xdg_surface_v6 = xdg_surface;
wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup);
popup->new_popup.notify = popup_handle_new_popup;
wl_signal_add(&xdg_surface->events.destroy, &popup->destroy);
popup->destroy.notify = popup_handle_destroy;
+ popup_unconstrain(popup);
+
return popup;
}
@@ -218,7 +239,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
view_set_fullscreen(view, e->fullscreen);
struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
- arrange_and_commit(output);
+ arrange_windows(output);
+ transaction_commit_dirty();
}
static void handle_unmap(struct wl_listener *listener, void *data) {
@@ -255,10 +277,11 @@ static void handle_map(struct wl_listener *listener, void *data) {
if (xdg_surface->toplevel->client_pending.fullscreen) {
view_set_fullscreen(view, true);
struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
- arrange_and_commit(ws);
+ arrange_windows(ws);
} else {
- arrange_and_commit(view->swayc->parent);
+ arrange_windows(view->swayc->parent);
}
+ transaction_commit_dirty();
xdg_shell_v6_view->commit.notify = handle_commit;
wl_signal_add(&xdg_surface->surface->events.commit,
@@ -295,11 +318,11 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
struct wlr_xdg_surface_v6 *xdg_surface = data;
if (xdg_surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) {
- wlr_log(L_DEBUG, "New xdg_shell_v6 popup");
+ wlr_log(WLR_DEBUG, "New xdg_shell_v6 popup");
return;
}
- wlr_log(L_DEBUG, "New xdg_shell_v6 toplevel title='%s' app_id='%s'",
+ wlr_log(WLR_DEBUG, "New xdg_shell_v6 toplevel title='%s' app_id='%s'",
xdg_surface->toplevel->title, xdg_surface->toplevel->app_id);
wlr_xdg_surface_v6_ping(xdg_surface);
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index b2874cfe..9df7977d 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -119,7 +119,7 @@ static struct sway_xwayland_unmanaged *create_unmanaged(
struct sway_xwayland_unmanaged *surface =
calloc(1, sizeof(struct sway_xwayland_unmanaged));
if (surface == NULL) {
- wlr_log(L_ERROR, "Allocation failed");
+ wlr_log(WLR_ERROR, "Allocation failed");
return NULL;
}
@@ -246,6 +246,14 @@ static bool wants_floating(struct sway_view *view) {
return false;
}
+static bool has_client_side_decorations(struct sway_view *view) {
+ if (xwayland_view_from_view(view) == NULL) {
+ return false;
+ }
+ struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
+ return surface->decorations != WLR_XWAYLAND_SURFACE_DECORATIONS_ALL;
+}
+
static void _close(struct sway_view *view) {
if (xwayland_view_from_view(view) == NULL) {
return;
@@ -269,6 +277,7 @@ static const struct sway_view_impl view_impl = {
.set_tiled = set_tiled,
.set_fullscreen = set_fullscreen,
.wants_floating = wants_floating,
+ .has_client_side_decorations = has_client_side_decorations,
.close = _close,
.destroy = destroy,
};
@@ -288,6 +297,10 @@ static void handle_commit(struct wl_listener *listener, void *data) {
}
view_damage_from(view);
+
+ if (view->allow_request_urgent) {
+ view_set_urgent(view, (bool)xsurface->hints_urgency);
+ }
}
static void handle_unmap(struct wl_listener *listener, void *data) {
@@ -324,10 +337,11 @@ static void handle_map(struct wl_listener *listener, void *data) {
if (xsurface->fullscreen) {
view_set_fullscreen(view, true);
struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
- arrange_and_commit(ws);
+ arrange_windows(ws);
} else {
- arrange_and_commit(view->swayc->parent);
+ arrange_windows(view->swayc->parent);
}
+ transaction_commit_dirty();
}
static void handle_destroy(struct wl_listener *listener, void *data) {
@@ -383,7 +397,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
view_set_fullscreen(view, xsurface->fullscreen);
struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
- arrange_and_commit(output);
+ arrange_windows(output);
+ transaction_commit_dirty();
}
static void handle_set_title(struct wl_listener *listener, void *data) {
@@ -432,12 +447,12 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
if (wlr_xwayland_surface_is_unmanaged(xsurface) ||
xsurface->override_redirect) {
- wlr_log(L_DEBUG, "New xwayland unmanaged surface");
+ wlr_log(WLR_DEBUG, "New xwayland unmanaged surface");
create_unmanaged(xsurface);
return;
}
- wlr_log(L_DEBUG, "New xwayland surface title='%s' class='%s'",
+ wlr_log(WLR_DEBUG, "New xwayland surface title='%s' class='%s'",
xsurface->title, xsurface->class);
struct sway_xwayland_view *xwayland_view =
@@ -490,7 +505,7 @@ void handle_xwayland_ready(struct wl_listener *listener, void *data) {
xcb_connection_t *xcb_conn = xcb_connect(NULL, NULL);
int err = xcb_connection_has_error(xcb_conn);
if (err) {
- wlr_log(L_ERROR, "XCB connect failed: %d", err);
+ wlr_log(WLR_ERROR, "XCB connect failed: %d", err);
return;
}
@@ -509,7 +524,7 @@ void handle_xwayland_ready(struct wl_listener *listener, void *data) {
free(reply);
if (error != NULL) {
- wlr_log(L_ERROR, "could not resolve atom %s, X11 error code %d",
+ wlr_log(WLR_ERROR, "could not resolve atom %s, X11 error code %d",
atom_map[i], error->error_code);
free(error);
break;
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index a2f11557..7a9f3ed7 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -10,6 +10,7 @@
#include <wlr/types/wlr_idle.h>
#include "list.h"
#include "log.h"
+#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
#include "sway/layers.h"
#include "sway/output.h"
@@ -219,6 +220,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
struct sway_drag_icon *drag_icon = wlr_drag_icon->data;
drag_icon_update_position(drag_icon);
}
+ transaction_commit_dirty();
}
static void handle_cursor_motion(struct wl_listener *listener, void *data) {
@@ -278,6 +280,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
wlr_seat_pointer_notify_button(cursor->seat->wlr_seat,
time_msec, button, state);
+ transaction_commit_dirty();
}
static void handle_cursor_button(struct wl_listener *listener, void *data) {
@@ -474,7 +477,7 @@ static void handle_request_set_cursor(struct wl_listener *listener,
// TODO: check cursor mode
if (focused_client == NULL ||
event->seat_client->client != focused_client) {
- wlr_log(L_DEBUG, "denying request to set cursor from unfocused client");
+ wlr_log(WLR_DEBUG, "denying request to set cursor from unfocused client");
return;
}
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
index 98f7d7cf..0b7cb766 100644
--- a/sway/input/input-manager.c
+++ b/sway/input/input-manager.c
@@ -61,7 +61,7 @@ static char *get_device_identifier(struct wlr_input_device *device) {
int len = snprintf(NULL, 0, fmt, vendor, product, name) + 1;
char *identifier = malloc(len);
if (!identifier) {
- wlr_log(L_ERROR, "Unable to allocate unique input device name");
+ wlr_log(WLR_ERROR, "Unable to allocate unique input device name");
return NULL;
}
@@ -104,77 +104,89 @@ static void input_manager_libinput_config_pointer(
}
libinput_device = wlr_libinput_get_device_handle(wlr_device);
- wlr_log(L_DEBUG, "input_manager_libinput_config_pointer(%s)",
+ wlr_log(WLR_DEBUG, "input_manager_libinput_config_pointer(%s)",
ic->identifier);
if (ic->accel_profile != INT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_profile(%d)",
+ wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) accel_set_profile(%d)",
ic->identifier, ic->accel_profile);
libinput_device_config_accel_set_profile(libinput_device,
ic->accel_profile);
}
if (ic->click_method != INT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) click_set_method(%d)",
+ wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) click_set_method(%d)",
ic->identifier, ic->click_method);
libinput_device_config_click_set_method(libinput_device,
ic->click_method);
}
if (ic->drag_lock != INT_MIN) {
- wlr_log(L_DEBUG,
+ wlr_log(WLR_DEBUG,
"libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)",
ic->identifier, ic->click_method);
libinput_device_config_tap_set_drag_lock_enabled(libinput_device,
ic->drag_lock);
}
if (ic->dwt != INT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) dwt_set_enabled(%d)",
+ wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) dwt_set_enabled(%d)",
ic->identifier, ic->dwt);
libinput_device_config_dwt_set_enabled(libinput_device, ic->dwt);
}
if (ic->left_handed != INT_MIN) {
- wlr_log(L_DEBUG,
+ wlr_log(WLR_DEBUG,
"libinput_config_pointer(%s) left_handed_set_enabled(%d)",
ic->identifier, ic->left_handed);
libinput_device_config_left_handed_set(libinput_device,
ic->left_handed);
}
if (ic->middle_emulation != INT_MIN) {
- wlr_log(L_DEBUG,
+ wlr_log(WLR_DEBUG,
"libinput_config_pointer(%s) middle_emulation_set_enabled(%d)",
ic->identifier, ic->middle_emulation);
libinput_device_config_middle_emulation_set_enabled(libinput_device,
ic->middle_emulation);
}
if (ic->natural_scroll != INT_MIN) {
- wlr_log(L_DEBUG,
+ wlr_log(WLR_DEBUG,
"libinput_config_pointer(%s) natural_scroll_set_enabled(%d)",
ic->identifier, ic->natural_scroll);
libinput_device_config_scroll_set_natural_scroll_enabled(
libinput_device, ic->natural_scroll);
}
if (ic->pointer_accel != FLT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_speed(%f)",
+ wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) accel_set_speed(%f)",
ic->identifier, ic->pointer_accel);
libinput_device_config_accel_set_speed(libinput_device,
ic->pointer_accel);
}
+ if (ic->scroll_button != INT_MIN) {
+ wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) scroll_set_button(%d)",
+ ic->identifier, ic->scroll_button);
+ libinput_device_config_scroll_set_button(libinput_device,
+ ic->scroll_button);
+ }
if (ic->scroll_method != INT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) scroll_set_method(%d)",
+ wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) scroll_set_method(%d)",
ic->identifier, ic->scroll_method);
libinput_device_config_scroll_set_method(libinput_device,
ic->scroll_method);
}
if (ic->send_events != INT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) send_events_set_mode(%d)",
+ wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) send_events_set_mode(%d)",
ic->identifier, ic->send_events);
libinput_device_config_send_events_set_mode(libinput_device,
ic->send_events);
}
if (ic->tap != INT_MIN) {
- wlr_log(L_DEBUG, "libinput_config_pointer(%s) tap_set_enabled(%d)",
+ wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) tap_set_enabled(%d)",
ic->identifier, ic->tap);
libinput_device_config_tap_set_enabled(libinput_device, ic->tap);
}
+ if (ic->tap_button_map != INT_MIN) {
+ wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) tap_set_button_map(%d)",
+ ic->identifier, ic->tap);
+ libinput_device_config_tap_set_button_map(libinput_device,
+ ic->tap_button_map);
+ }
}
static void handle_device_destroy(struct wl_listener *listener, void *data) {
@@ -187,7 +199,7 @@ static void handle_device_destroy(struct wl_listener *listener, void *data) {
return;
}
- wlr_log(L_DEBUG, "removing device: '%s'",
+ wlr_log(WLR_DEBUG, "removing device: '%s'",
input_device->identifier);
struct sway_seat *seat = NULL;
@@ -217,7 +229,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
input_device->identifier = get_device_identifier(device);
wl_list_insert(&input->devices, &input_device->link);
- wlr_log(L_DEBUG, "adding device: '%s'",
+ wlr_log(WLR_DEBUG, "adding device: '%s'",
input_device->identifier);
if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) {
@@ -229,7 +241,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
struct sway_seat *seat = NULL;
if (!input_has_seat_configuration(input)) {
- wlr_log(L_DEBUG, "no seat configuration, using default seat");
+ wlr_log(WLR_DEBUG, "no seat configuration, using default seat");
seat = input_manager_get_seat(input, default_seat);
seat_add_device(seat, input_device);
return;
@@ -259,7 +271,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
}
if (!added) {
- wlr_log(L_DEBUG,
+ wlr_log(WLR_DEBUG,
"device '%s' is not configured on any seats",
input_device->identifier);
}
@@ -282,7 +294,7 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data)
seat_set_exclusive_client(seat, NULL);
struct sway_container *previous = seat_get_focus(seat);
if (previous) {
- wlr_log(L_DEBUG, "Returning focus to %p %s '%s'", previous,
+ wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous,
container_type_to_str(previous->type), previous->name);
// Hack to get seat to re-focus the return value of get_focus
seat_set_focus(seat, previous->parent);
@@ -359,7 +371,7 @@ void input_manager_apply_input_config(struct sway_input_manager *input,
void input_manager_apply_seat_config(struct sway_input_manager *input,
struct seat_config *seat_config) {
- wlr_log(L_DEBUG, "applying new seat config for seat %s",
+ wlr_log(WLR_DEBUG, "applying new seat config for seat %s",
seat_config->name);
struct sway_seat *seat = input_manager_get_seat(input, seat_config->name);
if (!seat) {
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index 182536de..ede38519 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -3,6 +3,7 @@
#include <wlr/backend/multi.h>
#include <wlr/backend/session.h>
#include <wlr/types/wlr_idle.h>
+#include "sway/desktop/transaction.h"
#include "sway/input/seat.h"
#include "sway/input/keyboard.h"
#include "sway/input/input-manager.h"
@@ -108,7 +109,7 @@ static void get_active_binding(const struct sway_shortcut_state *state,
}
if (*current_binding && *current_binding != binding) {
- wlr_log(L_DEBUG, "encountered duplicate bindings %d and %d",
+ wlr_log(WLR_DEBUG, "encountered duplicate bindings %d and %d",
(*current_binding)->order, binding->order);
} else {
*current_binding = binding;
@@ -122,12 +123,13 @@ static void get_active_binding(const struct sway_shortcut_state *state,
*/
static void keyboard_execute_command(struct sway_keyboard *keyboard,
struct sway_binding *binding) {
- wlr_log(L_DEBUG, "running command for binding: %s",
+ wlr_log(WLR_DEBUG, "running command for binding: %s",
binding->command);
config->handler_context.seat = keyboard->seat_device->sway_seat;
struct cmd_results *results = execute_command(binding->command, NULL);
+ transaction_commit_dirty();
if (results->status != CMD_SUCCESS) {
- wlr_log(L_DEBUG, "could not run command for binding: %s (%s)",
+ wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
binding->command, results->error);
}
free_cmd_results(results);
@@ -386,7 +388,7 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!keymap) {
- wlr_log(L_DEBUG, "cannot configure keyboard: keymap does not exist");
+ wlr_log(WLR_DEBUG, "cannot configure keyboard: keymap does not exist");
xkb_context_unref(context);
return;
}
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 6c5abcd8..12b1fab5 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -75,7 +75,7 @@ static void seat_send_activate(struct sway_container *con,
struct sway_seat *seat) {
if (con->type == C_VIEW) {
if (!seat_is_input_allowed(seat, con->sway_view->surface)) {
- wlr_log(L_DEBUG, "Refusing to set focus, input is inhibited");
+ wlr_log(WLR_DEBUG, "Refusing to set focus, input is inhibited");
return;
}
view_set_activated(con->sway_view, true);
@@ -219,7 +219,7 @@ static struct sway_seat_container *seat_container_from_container(
seat_con = calloc(1, sizeof(struct sway_seat_container));
if (seat_con == NULL) {
- wlr_log(L_ERROR, "could not allocate seat container");
+ wlr_log(WLR_ERROR, "could not allocate seat container");
return NULL;
}
@@ -301,7 +301,7 @@ static void handle_new_drag_icon(struct wl_listener *listener, void *data) {
struct sway_drag_icon *icon = calloc(1, sizeof(struct sway_drag_icon));
if (icon == NULL) {
- wlr_log(L_ERROR, "Allocation failed");
+ wlr_log(WLR_ERROR, "Allocation failed");
return;
}
icon->seat = seat;
@@ -391,7 +391,7 @@ static void seat_apply_input_config(struct sway_seat *seat,
struct input_config *ic = input_device_get_config(
sway_device->input_device);
if (ic != NULL) {
- wlr_log(L_DEBUG, "Applying input config to %s",
+ wlr_log(WLR_DEBUG, "Applying input config to %s",
sway_device->input_device->identifier);
mapped_to_output = ic->mapped_to_output;
@@ -401,7 +401,7 @@ static void seat_apply_input_config(struct sway_seat *seat,
mapped_to_output = sway_device->input_device->wlr_device->output_name;
}
if (mapped_to_output != NULL) {
- wlr_log(L_DEBUG, "Mapping input device %s to output %s",
+ wlr_log(WLR_DEBUG, "Mapping input device %s to output %s",
sway_device->input_device->identifier, mapped_to_output);
struct sway_container *output = NULL;
for (int i = 0; i < root_container.children->length; ++i) {
@@ -415,7 +415,7 @@ static void seat_apply_input_config(struct sway_seat *seat,
wlr_cursor_map_input_to_output(seat->cursor->cursor,
sway_device->input_device->wlr_device,
output->sway_output->wlr_output);
- wlr_log(L_DEBUG, "Mapped to output %s", output->name);
+ wlr_log(WLR_DEBUG, "Mapped to output %s", output->name);
}
}
}
@@ -495,7 +495,7 @@ void seat_configure_device(struct sway_seat *seat,
seat_configure_tablet_tool(seat, seat_device);
break;
case WLR_INPUT_DEVICE_TABLET_PAD:
- wlr_log(L_DEBUG, "TODO: configure tablet pad");
+ wlr_log(WLR_DEBUG, "TODO: configure tablet pad");
break;
}
}
@@ -510,11 +510,11 @@ void seat_add_device(struct sway_seat *seat,
struct sway_seat_device *seat_device =
calloc(1, sizeof(struct sway_seat_device));
if (!seat_device) {
- wlr_log(L_DEBUG, "could not allocate seat device");
+ wlr_log(WLR_DEBUG, "could not allocate seat device");
return;
}
- wlr_log(L_DEBUG, "adding device %s to seat %s",
+ wlr_log(WLR_DEBUG, "adding device %s to seat %s",
input_device->identifier, seat->wlr_seat->name);
seat_device->sway_seat = seat;
@@ -533,7 +533,7 @@ void seat_remove_device(struct sway_seat *seat,
return;
}
- wlr_log(L_DEBUG, "removing device %s from seat %s",
+ wlr_log(WLR_DEBUG, "removing device %s from seat %s",
input_device->identifier, seat->wlr_seat->name);
seat_device_destroy(seat_device);
@@ -594,6 +594,12 @@ static void seat_send_unfocus(struct sway_container *container,
}
}
+static int handle_urgent_timeout(void *data) {
+ struct sway_view *view = data;
+ view_set_urgent(view, false);
+ return 0;
+}
+
void seat_set_focus_warp(struct sway_seat *seat,
struct sway_container *container, bool warp) {
if (seat->focused_layer) {
@@ -649,6 +655,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
while (parent) {
wl_list_remove(&parent->link);
wl_list_insert(&seat->focus_stack, &parent->link);
+ container_set_dirty(parent->container);
parent =
seat_container_from_container(seat,
@@ -661,9 +668,33 @@ void seat_set_focus_warp(struct sway_seat *seat,
if (last_focus) {
seat_send_unfocus(last_focus, seat);
}
-
seat_send_focus(container, seat);
- container_damage_whole(container->parent);
+
+ container_set_dirty(container);
+ container_set_dirty(container->parent); // for focused_inactive_child
+ if (last_focus) {
+ container_set_dirty(last_focus);
+ }
+ }
+
+ // If urgent, start a timer to unset it
+ if (container && container->type == C_VIEW &&
+ view_is_urgent(container->sway_view) &&
+ !container->sway_view->urgent_timer) {
+ struct sway_view *view = container->sway_view;
+ view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop,
+ handle_urgent_timeout, view);
+ wl_event_source_timer_update(view->urgent_timer, 1000);
+ }
+
+ // If we've focused a floating container, bring it to the front.
+ // We do this by putting it at the end of the floating list.
+ // This must happen for both the pending and current children lists.
+ if (container && container_is_floating(container)) {
+ list_move_to_end(container->parent->children, container);
+ if (container_has_ancestor(container, container->current.parent)) {
+ list_move_to_end(container->parent->current.children, container);
+ }
}
// clean up unfocused empty workspace on new output
@@ -707,10 +738,6 @@ void seat_set_focus_warp(struct sway_seat *seat,
}
}
- if (last_focus) {
- container_damage_whole(last_focus);
- }
-
if (last_workspace && last_workspace != new_workspace) {
cursor_send_pointer_motion(seat->cursor, 0, true);
}
@@ -752,7 +779,7 @@ void seat_set_focus_layer(struct sway_seat *seat,
struct sway_container *previous =
seat_get_focus_inactive(seat, &root_container);
if (previous) {
- wlr_log(L_DEBUG, "Returning focus to %p %s '%s'", previous,
+ wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous,
container_type_to_str(previous->type), previous->name);
// Hack to get seat to re-focus the return value of get_focus
seat_set_focus(seat, previous->parent);
@@ -830,18 +857,6 @@ struct sway_container *seat_get_active_child(struct sway_seat *seat,
return NULL;
}
-struct sway_container *seat_get_active_current_child(struct sway_seat *seat,
- struct sway_container *container) {
- struct sway_seat_container *current = NULL;
- wl_list_for_each(current, &seat->focus_stack, link) {
- if (current->container->current.parent == container &&
- current->container->current.layout != L_FLOATING) {
- return current->container;
- }
- }
- return NULL;
-}
-
struct sway_container *seat_get_focus(struct sway_seat *seat) {
if (!seat->has_focus) {
return NULL;
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index b9289e25..c49ea47e 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -2,6 +2,7 @@
#include <stdio.h>
#include <ctype.h>
#include "log.h"
+#include "sway/config.h"
#include "sway/ipc-json.h"
#include "sway/tree/container.h"
#include "sway/tree/workspace.h"
@@ -41,6 +42,7 @@ json_object *ipc_json_get_version() {
json_object_object_add(version, "major", json_object_new_int(major));
json_object_object_add(version, "minor", json_object_new_int(minor));
json_object_object_add(version, "patch", json_object_new_int(patch));
+ json_object_object_add(version, "loaded_config_file_name", json_object_new_string(config->current_config_path));
return version;
}
@@ -168,7 +170,8 @@ static void ipc_json_describe_workspace(struct sway_container *workspace,
json_object_object_add(object, "output", workspace->parent ?
json_object_new_string(workspace->parent->name) : NULL);
json_object_object_add(object, "type", json_object_new_string("workspace"));
- json_object_object_add(object, "urgent", json_object_new_boolean(false));
+ json_object_object_add(object, "urgent",
+ json_object_new_boolean(workspace->sway_workspace->urgent));
json_object_object_add(object, "representation", workspace->formatted_title ?
json_object_new_string(workspace->formatted_title) : NULL);
@@ -194,6 +197,10 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
json_object_object_add(object, "layout",
json_object_new_string(ipc_json_layout_description(c->layout)));
}
+
+ bool urgent = c->type == C_VIEW ?
+ view_is_urgent(c->sway_view) : container_has_urgent_child(c);
+ json_object_object_add(object, "urgent", json_object_new_boolean(urgent));
}
static void focus_inactive_children_iterator(struct sway_container *c, void *data) {
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index abdaa237..be703915 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -17,6 +17,8 @@
#include <unistd.h>
#include <wayland-server.h>
#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/desktop/transaction.h"
#include "sway/ipc-json.h"
#include "sway/ipc-server.h"
#include "sway/output.h"
@@ -138,32 +140,32 @@ struct sockaddr_un *ipc_user_sockaddr(void) {
int ipc_handle_connection(int fd, uint32_t mask, void *data) {
(void) fd;
struct sway_server *server = data;
- wlr_log(L_DEBUG, "Event on IPC listening socket");
+ wlr_log(WLR_DEBUG, "Event on IPC listening socket");
assert(mask == WL_EVENT_READABLE);
int client_fd = accept(ipc_socket, NULL, NULL);
if (client_fd == -1) {
- wlr_log_errno(L_ERROR, "Unable to accept IPC client connection");
+ wlr_log_errno(WLR_ERROR, "Unable to accept IPC client connection");
return 0;
}
int flags;
if ((flags = fcntl(client_fd, F_GETFD)) == -1
|| fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) {
- wlr_log_errno(L_ERROR, "Unable to set CLOEXEC on IPC client socket");
+ wlr_log_errno(WLR_ERROR, "Unable to set CLOEXEC on IPC client socket");
close(client_fd);
return 0;
}
if ((flags = fcntl(client_fd, F_GETFL)) == -1
|| fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) {
- wlr_log_errno(L_ERROR, "Unable to set NONBLOCK on IPC client socket");
+ wlr_log_errno(WLR_ERROR, "Unable to set NONBLOCK on IPC client socket");
close(client_fd);
return 0;
}
struct ipc_client *client = malloc(sizeof(struct ipc_client));
if (!client) {
- wlr_log(L_ERROR, "Unable to allocate ipc client");
+ wlr_log(WLR_ERROR, "Unable to allocate ipc client");
close(client_fd);
return 0;
}
@@ -179,12 +181,12 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) {
client->write_buffer_len = 0;
client->write_buffer = malloc(client->write_buffer_size);
if (!client->write_buffer) {
- wlr_log(L_ERROR, "Unable to allocate ipc client write buffer");
+ wlr_log(WLR_ERROR, "Unable to allocate ipc client write buffer");
close(client_fd);
return 0;
}
- wlr_log(L_DEBUG, "New client: fd %d", client_fd);
+ wlr_log(WLR_DEBUG, "New client: fd %d", client_fd);
list_add(ipc_client_list, client);
return 0;
}
@@ -195,22 +197,22 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
struct ipc_client *client = data;
if (mask & WL_EVENT_ERROR) {
- wlr_log(L_ERROR, "IPC Client socket error, removing client");
+ wlr_log(WLR_ERROR, "IPC Client socket error, removing client");
ipc_client_disconnect(client);
return 0;
}
if (mask & WL_EVENT_HANGUP) {
- wlr_log(L_DEBUG, "Client %d hung up", client->fd);
+ wlr_log(WLR_DEBUG, "Client %d hung up", client->fd);
ipc_client_disconnect(client);
return 0;
}
- wlr_log(L_DEBUG, "Client %d readable", client->fd);
+ wlr_log(WLR_DEBUG, "Client %d readable", client->fd);
int read_available;
if (ioctl(client_fd, FIONREAD, &read_available) == -1) {
- wlr_log_errno(L_INFO, "Unable to read IPC socket buffer size");
+ wlr_log_errno(WLR_INFO, "Unable to read IPC socket buffer size");
ipc_client_disconnect(client);
return 0;
}
@@ -232,13 +234,13 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
// Should be fully available, because read_available >= ipc_header_size
ssize_t received = recv(client_fd, buf, ipc_header_size, 0);
if (received == -1) {
- wlr_log_errno(L_INFO, "Unable to receive header from IPC client");
+ wlr_log_errno(WLR_INFO, "Unable to receive header from IPC client");
ipc_client_disconnect(client);
return 0;
}
if (memcmp(buf, ipc_magic, sizeof(ipc_magic)) != 0) {
- wlr_log(L_DEBUG, "IPC header check failed");
+ wlr_log(WLR_DEBUG, "IPC header check failed");
ipc_client_disconnect(client);
return 0;
}
@@ -272,7 +274,7 @@ static void ipc_send_event(const char *json_string, enum ipc_command_type event)
}
client->current_command = event;
if (!ipc_send_reply(client, json_string, (uint32_t) strlen(json_string))) {
- wlr_log_errno(L_INFO, "Unable to send reply to IPC client");
+ wlr_log_errno(WLR_INFO, "Unable to send reply to IPC client");
/* ipc_send_reply destroys client on error, which also
* removes it from the list, so we need to process
* current index again */
@@ -286,7 +288,7 @@ void ipc_event_workspace(struct sway_container *old,
if (!ipc_has_event_listeners(IPC_EVENT_WORKSPACE)) {
return;
}
- wlr_log(L_DEBUG, "Sending workspace::%s event", change);
+ wlr_log(WLR_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) {
@@ -314,7 +316,7 @@ void ipc_event_window(struct sway_container *window, const char *change) {
if (!ipc_has_event_listeners(IPC_EVENT_WINDOW)) {
return;
}
- wlr_log(L_DEBUG, "Sending window::%s event", change);
+ wlr_log(WLR_DEBUG, "Sending window::%s event", change);
json_object *obj = json_object_new_object();
json_object_object_add(obj, "change", json_object_new_string(change));
json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window));
@@ -328,7 +330,7 @@ void ipc_event_barconfig_update(struct bar_config *bar) {
if (!ipc_has_event_listeners(IPC_EVENT_BARCONFIG_UPDATE)) {
return;
}
- wlr_log(L_DEBUG, "Sending barconfig_update event");
+ wlr_log(WLR_DEBUG, "Sending barconfig_update event");
json_object *json = ipc_json_describe_bar_config(bar);
const char *json_string = json_object_to_json_string(json);
@@ -340,7 +342,7 @@ void ipc_event_mode(const char *mode, bool pango) {
if (!ipc_has_event_listeners(IPC_EVENT_MODE)) {
return;
}
- wlr_log(L_DEBUG, "Sending mode::%s event", mode);
+ wlr_log(WLR_DEBUG, "Sending mode::%s event", mode);
json_object *obj = json_object_new_object();
json_object_object_add(obj, "change", json_object_new_string(mode));
json_object_object_add(obj, "pango_markup",
@@ -355,13 +357,13 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
struct ipc_client *client = data;
if (mask & WL_EVENT_ERROR) {
- wlr_log(L_ERROR, "IPC Client socket error, removing client");
+ wlr_log(WLR_ERROR, "IPC Client socket error, removing client");
ipc_client_disconnect(client);
return 0;
}
if (mask & WL_EVENT_HANGUP) {
- wlr_log(L_DEBUG, "Client %d hung up", client->fd);
+ wlr_log(WLR_DEBUG, "Client %d hung up", client->fd);
ipc_client_disconnect(client);
return 0;
}
@@ -370,14 +372,14 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
return 0;
}
- wlr_log(L_DEBUG, "Client %d writable", client->fd);
+ wlr_log(WLR_DEBUG, "Client %d writable", client->fd);
ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len);
if (written == -1 && errno == EAGAIN) {
return 0;
} else if (written == -1) {
- wlr_log_errno(L_INFO, "Unable to send data from queue to IPC client");
+ wlr_log_errno(WLR_INFO, "Unable to send data from queue to IPC client");
ipc_client_disconnect(client);
return 0;
}
@@ -400,7 +402,7 @@ void ipc_client_disconnect(struct ipc_client *client) {
shutdown(client->fd, SHUT_RDWR);
- wlr_log(L_INFO, "IPC Client %d disconnected", client->fd);
+ wlr_log(WLR_INFO, "IPC Client %d disconnected", client->fd);
wl_event_source_remove(client->event_source);
if (client->writable_event_source) {
wl_event_source_remove(client->writable_event_source);
@@ -461,7 +463,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
char *buf = malloc(client->payload_length + 1);
if (!buf) {
- wlr_log_errno(L_INFO, "Unable to allocate IPC payload");
+ wlr_log_errno(WLR_INFO, "Unable to allocate IPC payload");
ipc_client_disconnect(client);
return;
}
@@ -470,7 +472,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
ssize_t received = recv(client->fd, buf, client->payload_length, 0);
if (received == -1)
{
- wlr_log_errno(L_INFO, "Unable to receive payload from IPC client");
+ wlr_log_errno(WLR_INFO, "Unable to receive payload from IPC client");
ipc_client_disconnect(client);
free(buf);
return;
@@ -483,6 +485,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
case IPC_COMMAND:
{
struct cmd_results *results = execute_command(buf, NULL);
+ transaction_commit_dirty();
char *json = cmd_results_to_json(results);
int length = strlen(json);
client_valid = ipc_send_reply(client, json, (uint32_t)length);
@@ -533,7 +536,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
struct json_object *request = json_tokener_parse(buf);
if (request == NULL) {
client_valid = ipc_send_reply(client, "{\"success\": false}", 18);
- wlr_log_errno(L_INFO, "Failed to read request");
+ wlr_log_errno(WLR_INFO, "Failed to read request");
goto exit_cleanup;
}
@@ -556,7 +559,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
client_valid =
ipc_send_reply(client, "{\"success\": false}", 18);
json_object_put(request);
- wlr_log_errno(L_INFO, "Failed to parse request");
+ wlr_log_errno(WLR_INFO, "Failed to parse request");
goto exit_cleanup;
}
}
@@ -667,8 +670,33 @@ void ipc_client_handle_command(struct ipc_client *client) {
goto exit_cleanup;
}
+ case IPC_GET_BINDING_MODES:
+ {
+ json_object *modes = json_object_new_array();
+ for (int i = 0; i < config->modes->length; i++) {
+ struct sway_mode *mode = config->modes->items[i];
+ json_object_array_add(modes, json_object_new_string(mode->name));
+ }
+ const char *json_string = json_object_to_json_string(modes);
+ client_valid =
+ ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
+ json_object_put(modes); // free
+ goto exit_cleanup;
+ }
+
+ case IPC_GET_CONFIG:
+ {
+ json_object *json = json_object_new_object();
+ json_object_object_add(json, "config", json_object_new_string(config->current_config));
+ const char *json_string = json_object_to_json_string(json);
+ client_valid =
+ 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);
+ wlr_log(WLR_INFO, "Unknown IPC command type %i", client->current_command);
goto exit_cleanup;
}
@@ -696,14 +724,14 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
}
if (client->write_buffer_size > 4e6) { // 4 MB
- wlr_log(L_ERROR, "Client write buffer too big, disconnecting client");
+ wlr_log(WLR_ERROR, "Client write buffer too big, disconnecting client");
ipc_client_disconnect(client);
return false;
}
char *new_buffer = realloc(client->write_buffer, client->write_buffer_size);
if (!new_buffer) {
- wlr_log(L_ERROR, "Unable to reallocate ipc client write buffer");
+ wlr_log(WLR_ERROR, "Unable to reallocate ipc client write buffer");
ipc_client_disconnect(client);
return false;
}
@@ -720,6 +748,6 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
ipc_client_handle_writable, client);
}
- wlr_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload);
+ wlr_log(WLR_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload);
return true;
}
diff --git a/sway/main.c b/sway/main.c
index ec7353be..1a55b519 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -20,6 +20,7 @@
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/debug.h"
+#include "sway/desktop/transaction.h"
#include "sway/server.h"
#include "sway/tree/layout.h"
#include "sway/ipc-server.h"
@@ -129,7 +130,7 @@ static void log_env() {
"SWAYSOCK"
};
for (size_t i = 0; i < sizeof(log_vars) / sizeof(char *); ++i) {
- wlr_log(L_INFO, "%s=%s", log_vars[i], getenv(log_vars[i]));
+ wlr_log(WLR_INFO, "%s=%s", log_vars[i], getenv(log_vars[i]));
}
}
@@ -144,14 +145,14 @@ static void log_distro() {
for (size_t i = 0; i < sizeof(paths) / sizeof(char *); ++i) {
FILE *f = fopen(paths[i], "r");
if (f) {
- wlr_log(L_INFO, "Contents of %s:", paths[i]);
+ wlr_log(WLR_INFO, "Contents of %s:", paths[i]);
while (!feof(f)) {
char *line;
if (!(line = read_line(f))) {
break;
}
if (*line) {
- wlr_log(L_INFO, "%s", line);
+ wlr_log(WLR_INFO, "%s", line);
}
free(line);
}
@@ -163,7 +164,7 @@ static void log_distro() {
static void log_kernel() {
FILE *f = popen("uname -a", "r");
if (!f) {
- wlr_log(L_INFO, "Unable to determine kernel version");
+ wlr_log(WLR_INFO, "Unable to determine kernel version");
return;
}
while (!feof(f)) {
@@ -172,7 +173,7 @@ static void log_kernel() {
break;
}
if (*line) {
- wlr_log(L_INFO, "%s", line);
+ wlr_log(WLR_INFO, "%s", line);
}
free(line);
}
@@ -183,14 +184,14 @@ static void security_sanity_check() {
// TODO: Notify users visually if this has issues
struct stat s;
if (stat("/proc", &s)) {
- wlr_log(L_ERROR,
+ wlr_log(WLR_ERROR,
"!! DANGER !! /proc is not available - sway CANNOT enforce security rules!");
}
#ifdef __linux__
cap_flag_value_t v;
cap_t cap = cap_get_proc();
if (!cap || cap_get_flag(cap, CAP_SYS_PTRACE, CAP_PERMITTED, &v) != 0 || v != CAP_SET) {
- wlr_log(L_ERROR,
+ wlr_log(WLR_ERROR,
"!! DANGER !! Sway does not have CAP_SYS_PTRACE and cannot enforce security rules for processes running as other users.");
}
if (cap) {
@@ -206,13 +207,13 @@ static void executable_sanity_check() {
stat(exe, &sb);
// We assume that cap_get_file returning NULL implies ENODATA
if (sb.st_mode & (S_ISUID|S_ISGID) && cap_get_file(exe)) {
- wlr_log(L_ERROR,
+ wlr_log(WLR_ERROR,
"sway executable has both the s(g)uid bit AND file caps set.");
- wlr_log(L_ERROR,
+ wlr_log(WLR_ERROR,
"This is strongly discouraged (and completely broken).");
- wlr_log(L_ERROR,
+ wlr_log(WLR_ERROR,
"Please clear one of them (either the suid bit, or the file caps).");
- wlr_log(L_ERROR,
+ wlr_log(WLR_ERROR,
"If unsure, strip the file caps.");
exit(EXIT_FAILURE);
}
@@ -223,16 +224,16 @@ static void executable_sanity_check() {
static void drop_permissions(bool keep_caps) {
if (getuid() != geteuid() || getgid() != getegid()) {
if (setgid(getgid()) != 0) {
- wlr_log(L_ERROR, "Unable to drop root");
+ wlr_log(WLR_ERROR, "Unable to drop root");
exit(EXIT_FAILURE);
}
if (setuid(getuid()) != 0) {
- wlr_log(L_ERROR, "Unable to drop root");
+ wlr_log(WLR_ERROR, "Unable to drop root");
exit(EXIT_FAILURE);
}
}
if (setuid(0) != -1) {
- wlr_log(L_ERROR, "Root privileges can be restored.");
+ wlr_log(WLR_ERROR, "Root privileges can be restored.");
exit(EXIT_FAILURE);
}
#ifdef __linux__
@@ -240,17 +241,29 @@ static void drop_permissions(bool keep_caps) {
// Drop every cap except CAP_SYS_PTRACE
cap_t caps = cap_init();
cap_value_t keep = CAP_SYS_PTRACE;
- wlr_log(L_INFO, "Dropping extra capabilities");
+ wlr_log(WLR_INFO, "Dropping extra capabilities");
if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) ||
cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) ||
cap_set_proc(caps)) {
- wlr_log(L_ERROR, "Failed to drop extra capabilities");
+ wlr_log(WLR_ERROR, "Failed to drop extra capabilities");
exit(EXIT_FAILURE);
}
}
#endif
}
+void enable_debug_flag(const char *flag) {
+ if (strcmp(flag, "render-tree") == 0) {
+ enable_debug_tree = true;
+ } else if (strncmp(flag, "damage=", 7) == 0) {
+ damage_debug = &flag[7];
+ } else if (strcmp(flag, "txn-debug") == 0) {
+ txn_debug = true;
+ } else if (strncmp(flag, "txn-timeout=", 12) == 0) {
+ txn_timeout_ms = atoi(&flag[12]);
+ }
+}
+
int main(int argc, char **argv) {
static int verbose = 0, debug = 0, validate = 0;
@@ -290,7 +303,7 @@ int main(int argc, char **argv) {
int c;
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "hCdDvVc:", long_options, &option_index);
+ c = getopt_long(argc, argv, "hCdD:vVc:", long_options, &option_index);
if (c == -1) {
break;
}
@@ -309,7 +322,7 @@ int main(int argc, char **argv) {
debug = 1;
break;
case 'D': // extended debug options
- enable_debug_tree = true;
+ enable_debug_flag(optarg);
break;
case 'v': // version
fprintf(stdout, "sway version " SWAY_VERSION "\n");
@@ -335,22 +348,22 @@ int main(int argc, char **argv) {
// TODO: switch logging over to wlroots?
if (debug) {
- wlr_log_init(L_DEBUG, NULL);
+ wlr_log_init(WLR_DEBUG, NULL);
} else if (verbose || validate) {
- wlr_log_init(L_INFO, NULL);
+ wlr_log_init(WLR_INFO, NULL);
} else {
- wlr_log_init(L_ERROR, NULL);
+ wlr_log_init(WLR_ERROR, NULL);
}
if (optind < argc) { // Behave as IPC client
if(optind != 1) {
- wlr_log(L_ERROR, "Don't use options with the IPC client");
+ wlr_log(WLR_ERROR, "Don't use options with the IPC client");
exit(EXIT_FAILURE);
}
drop_permissions(false);
char *socket_path = getenv("SWAYSOCK");
if (!socket_path) {
- wlr_log(L_ERROR, "Unable to retrieve socket path");
+ wlr_log(WLR_ERROR, "Unable to retrieve socket path");
exit(EXIT_FAILURE);
}
char *command = join_args(argv + optind, argc - optind);
@@ -369,7 +382,7 @@ int main(int argc, char **argv) {
if (getuid() != geteuid() || getgid() != getegid()) {
// Retain capabilities after setuid()
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
- wlr_log(L_ERROR, "Cannot keep caps after setuid()");
+ wlr_log(WLR_ERROR, "Cannot keep caps after setuid()");
exit(EXIT_FAILURE);
}
suid = true;
@@ -390,7 +403,7 @@ int main(int argc, char **argv) {
// prevent ipc from crashing sway
signal(SIGPIPE, SIG_IGN);
- wlr_log(L_INFO, "Starting sway version " SWAY_VERSION);
+ wlr_log(WLR_INFO, "Starting sway version " SWAY_VERSION);
layout_init();
@@ -423,18 +436,19 @@ int main(int argc, char **argv) {
char *line = config->cmd_queue->items[0];
struct cmd_results *res = execute_command(line, NULL);
if (res->status != CMD_SUCCESS) {
- wlr_log(L_ERROR, "Error on line '%s': %s", line, res->error);
+ wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error);
}
free_cmd_results(res);
free(line);
list_del(config->cmd_queue, 0);
}
+ transaction_commit_dirty();
if (!terminate_request) {
server_run(&server);
}
- wlr_log(L_INFO, "Shutting down sway");
+ wlr_log(WLR_INFO, "Shutting down sway");
server_fini(&server);
diff --git a/sway/meson.build b/sway/meson.build
index e492aeee..c58d3470 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -35,11 +35,13 @@ sway_sources = files(
'commands/border.c',
'commands/client.c',
'commands/default_border.c',
+ 'commands/default_floating_border.c',
'commands/default_orientation.c',
'commands/exit.c',
'commands/exec.c',
'commands/exec_always.c',
'commands/floating.c',
+ 'commands/floating_minmax_size.c',
'commands/focus.c',
'commands/focus_follows_mouse.c',
'commands/focus_wrapping.c',
@@ -58,6 +60,7 @@ sway_sources = files(
'commands/mode.c',
'commands/mouse_warping.c',
'commands/move.c',
+ 'commands/no_focus.c',
'commands/output.c',
'commands/reload.c',
'commands/rename.c',
@@ -75,6 +78,7 @@ sway_sources = files(
'commands/swap.c',
'commands/title_format.c',
'commands/unmark.c',
+ 'commands/urgent.c',
'commands/workspace.c',
'commands/workspace_layout.c',
'commands/ws_auto_back_and_forth.c',
@@ -117,8 +121,10 @@ sway_sources = files(
'commands/input/pointer_accel.c',
'commands/input/repeat_delay.c',
'commands/input/repeat_rate.c',
+ 'commands/input/scroll_button.c',
'commands/input/scroll_method.c',
'commands/input/tap.c',
+ 'commands/input/tap_button_map.c',
'commands/input/xkb_layout.c',
'commands/input/xkb_model.c',
'commands/input/xkb_options.c',
diff --git a/sway/server.c b/sway/server.c
index cd15f454..f904b177 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -14,7 +14,6 @@
#include <wlr/types/wlr_linux_dmabuf.h>
#include <wlr/types/wlr_primary_selection.h>
#include <wlr/types/wlr_screencopy_v1.h>
-#include <wlr/types/wlr_screenshooter.h>
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/types/wlr_xdg_output.h>
@@ -29,20 +28,20 @@
#include "sway/xwayland.h"
bool server_privileged_prepare(struct sway_server *server) {
- wlr_log(L_DEBUG, "Preparing Wayland server initialization");
+ wlr_log(WLR_DEBUG, "Preparing Wayland server initialization");
server->wl_display = wl_display_create();
server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
server->backend = wlr_backend_autocreate(server->wl_display, NULL);
if (!server->backend) {
- wlr_log(L_ERROR, "Unable to create backend");
+ wlr_log(WLR_ERROR, "Unable to create backend");
return false;
}
return true;
}
bool server_init(struct sway_server *server) {
- wlr_log(L_DEBUG, "Initializing Wayland server");
+ wlr_log(WLR_DEBUG, "Initializing Wayland server");
struct wlr_renderer *renderer = wlr_backend_get_renderer(server->backend);
assert(renderer);
@@ -53,7 +52,6 @@ bool server_init(struct sway_server *server) {
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);
wlr_primary_selection_device_manager_create(server->wl_display);
@@ -116,7 +114,7 @@ bool server_init(struct sway_server *server) {
server->socket = wl_display_add_socket_auto(server->wl_display);
if (!server->socket) {
- wlr_log(L_ERROR, "Unable to open wayland socket");
+ wlr_log(WLR_ERROR, "Unable to open wayland socket");
wlr_backend_destroy(server->backend);
return false;
}
@@ -125,8 +123,7 @@ bool server_init(struct sway_server *server) {
if (debug != NULL && strcmp(debug, "txn_timings") == 0) {
server->debug_txn_timings = true;
}
- server->destroying_containers = create_list();
-
+ server->dirty_containers = create_list();
server->transactions = create_list();
input_manager = input_manager_create(server);
@@ -136,15 +133,15 @@ bool server_init(struct sway_server *server) {
void server_fini(struct sway_server *server) {
// TODO: free sway-specific resources
wl_display_destroy(server->wl_display);
- list_free(server->destroying_containers);
+ list_free(server->dirty_containers);
list_free(server->transactions);
}
void server_run(struct sway_server *server) {
- wlr_log(L_INFO, "Running compositor on wayland display '%s'",
+ wlr_log(WLR_INFO, "Running compositor on wayland display '%s'",
server->socket);
if (!wlr_backend_start(server->backend)) {
- wlr_log(L_ERROR, "Failed to start backend");
+ wlr_log(WLR_ERROR, "Failed to start backend");
wlr_backend_destroy(server->backend);
return;
}
diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd
index cf7a6385..b6391431 100644
--- a/sway/sway-input.5.scd
+++ b/sway/sway-input.5.scd
@@ -92,9 +92,20 @@ For more information on these xkb configuration options, see
*input* <identifier> scroll\_method none|two\_finger|edge|on\_button\_down
Changes the scroll method for the specified input device.
+*input* <identifier> scroll\_button <button\_identifier>
+ Sets button used for scroll\_method on\_button\_down. The button identifier
+ can be obtained from `libinput debug-events`.
+ If set to 0, it disables the scroll\_button on\_button\_down.
+
*input* <identifier> tap enabled|disabled
Enables or disables tap for specified input device.
+*input* <identifier> tap_button_map lrm|lmr
+ Specifies which button mapping to use for tapping. _lrm_ treats 1 finger as
+ left click, 2 fingers as right click, and 3 fingers as middle click. _lmr_
+ treats 1 finger as left click, 2 fingers as middle click, and 3 fingers as
+ right click.
+
## SEAT CONFIGURATION
Configure options for multiseat mode. sway-seat commands must be used inside a
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index 7c553d3f..d369d7b6 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -92,6 +92,12 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
*focus* output <name>
Moves focus to the named output.
+*focus tiling*
+ Sets focus to the last focused tiling container.
+
+*focus floating*
+ Sets focus to the last focused floating container.
+
*focus* mode\_toggle
Moves focus between the floating and tiled layers.
@@ -493,6 +499,11 @@ config after the others, or it will be matched instead of the others.
*unmark* will remove _identifier_ from the list of current marks on a
window. If _identifier_ is omitted, all marks are removed.
+*urgent* enable|disable|allow|deny
+ Using _enable_ or _disable_ manually sets or unsets the window's urgent
+ state. Using _allow_ or _deny_ controls the window's ability to set itself
+ as urgent. By default, windows are allowed to set their own urgency.
+
*workspace* [number] <name>
Switches to the specified workspace. The string "number" is optional and is
used to sort workspaces.
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index 582b2891..533cf71c 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -47,11 +47,11 @@ static void apply_horiz_layout(struct sway_container *parent) {
double scale = parent->width / total_width;
// Resize windows
- wlr_log(L_DEBUG, "Arranging %p horizontally", parent);
+ wlr_log(WLR_DEBUG, "Arranging %p horizontally", parent);
double child_x = parent->x;
for (size_t i = 0; i < num_children; ++i) {
struct sway_container *child = parent->children->items[i];
- wlr_log(L_DEBUG,
+ wlr_log(WLR_DEBUG,
"Calculating arrangement for %p:%d (will scale %f by %f)",
child, child->type, child->width, scale);
child->x = child_x;
@@ -99,11 +99,11 @@ static void apply_vert_layout(struct sway_container *parent) {
double scale = parent_height / total_height;
// Resize
- wlr_log(L_DEBUG, "Arranging %p vertically", parent);
+ wlr_log(WLR_DEBUG, "Arranging %p vertically", parent);
double child_y = parent->y + parent_offset;
for (size_t i = 0; i < num_children; ++i) {
struct sway_container *child = parent->children->items[i];
- wlr_log(L_DEBUG,
+ wlr_log(WLR_DEBUG,
"Calculating arrangement for %p:%d (will scale %f by %f)",
child, child->type, child->height, scale);
child->x = parent->x;
@@ -144,42 +144,26 @@ static void apply_tabbed_or_stacked_layout(struct sway_container *parent) {
}
}
-/**
- * If a container has been deleted from the pending tree state, we must add it
- * to the transaction so it can be freed afterwards. To do this, we iterate the
- * server's destroying_containers list and add all of them. We may add more than
- * what we need to, but this is easy and has no negative consequences.
- */
-static void add_deleted_containers(struct sway_transaction *transaction) {
- for (int i = 0; i < server.destroying_containers->length; ++i) {
- struct sway_container *child = server.destroying_containers->items[i];
- transaction_add_container(transaction, child);
- }
-}
-
-static void arrange_children_of(struct sway_container *parent,
- struct sway_transaction *transaction);
+static void arrange_children_of(struct sway_container *parent);
-static void arrange_floating(struct sway_container *floating,
- struct sway_transaction *transaction) {
+static void arrange_floating(struct sway_container *floating) {
for (int i = 0; i < floating->children->length; ++i) {
struct sway_container *floater = floating->children->items[i];
if (floater->type == C_VIEW) {
view_autoconfigure(floater->sway_view);
} else {
- arrange_children_of(floater, transaction);
+ arrange_children_of(floater);
}
- transaction_add_container(transaction, floater);
+ container_set_dirty(floater);
}
- transaction_add_container(transaction, floating);
+ container_set_dirty(floating);
}
-static void arrange_children_of(struct sway_container *parent,
- struct sway_transaction *transaction) {
+static void arrange_children_of(struct sway_container *parent) {
if (config->reloading) {
return;
}
- wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", parent,
+ wlr_log(WLR_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", parent,
parent->name, parent->width, parent->height, parent->x, parent->y);
// Calculate x, y, width and height of children
@@ -198,7 +182,7 @@ static void arrange_children_of(struct sway_container *parent,
apply_horiz_layout(parent);
break;
case L_FLOATING:
- arrange_floating(parent, transaction);
+ arrange_floating(parent);
break;
}
@@ -213,20 +197,19 @@ static void arrange_children_of(struct sway_container *parent,
if (child->type == C_VIEW) {
view_autoconfigure(child->sway_view);
} else {
- arrange_children_of(child, transaction);
+ arrange_children_of(child);
}
- transaction_add_container(transaction, child);
+ container_set_dirty(child);
}
}
-static void arrange_workspace(struct sway_container *workspace,
- struct sway_transaction *transaction) {
+static void arrange_workspace(struct sway_container *workspace) {
if (config->reloading) {
return;
}
struct sway_container *output = workspace->parent;
struct wlr_box *area = &output->sway_output->usable_area;
- wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d",
+ wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d",
area->width, area->height, area->x, area->y);
remove_gaps(workspace);
workspace->width = area->width;
@@ -234,15 +217,14 @@ static void arrange_workspace(struct sway_container *workspace,
workspace->x = output->x + area->x;
workspace->y = output->y + area->y;
add_gaps(workspace);
- transaction_add_container(transaction, workspace);
- wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name,
+ container_set_dirty(workspace);
+ wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name,
workspace->x, workspace->y);
- arrange_floating(workspace->sway_workspace->floating, transaction);
- arrange_children_of(workspace, transaction);
+ arrange_floating(workspace->sway_workspace->floating);
+ arrange_children_of(workspace);
}
-static void arrange_output(struct sway_container *output,
- struct sway_transaction *transaction) {
+static void arrange_output(struct sway_container *output) {
if (config->reloading) {
return;
}
@@ -253,16 +235,16 @@ static void arrange_output(struct sway_container *output,
output->y = output_box->y;
output->width = output_box->width;
output->height = output_box->height;
- transaction_add_container(transaction, output);
- wlr_log(L_DEBUG, "Arranging output '%s' at %f,%f",
+ container_set_dirty(output);
+ wlr_log(WLR_DEBUG, "Arranging output '%s' at %f,%f",
output->name, output->x, output->y);
for (int i = 0; i < output->children->length; ++i) {
struct sway_container *workspace = output->children->items[i];
- arrange_workspace(workspace, transaction);
+ arrange_workspace(workspace);
}
}
-static void arrange_root(struct sway_transaction *transaction) {
+static void arrange_root() {
if (config->reloading) {
return;
}
@@ -274,48 +256,40 @@ static void arrange_root(struct sway_transaction *transaction) {
root_container.y = layout_box->y;
root_container.width = layout_box->width;
root_container.height = layout_box->height;
- transaction_add_container(transaction, &root_container);
+ container_set_dirty(&root_container);
for (int i = 0; i < root_container.children->length; ++i) {
struct sway_container *output = root_container.children->items[i];
- arrange_output(output, transaction);
+ arrange_output(output);
}
}
-void arrange_windows(struct sway_container *container,
- struct sway_transaction *transaction) {
+void arrange_windows(struct sway_container *container) {
switch (container->type) {
case C_ROOT:
- arrange_root(transaction);
+ arrange_root();
break;
case C_OUTPUT:
- arrange_output(container, transaction);
+ arrange_output(container);
break;
case C_WORKSPACE:
- arrange_workspace(container, transaction);
+ arrange_workspace(container);
break;
case C_CONTAINER:
- arrange_children_of(container, transaction);
- transaction_add_container(transaction, container);
+ arrange_children_of(container);
+ container_set_dirty(container);
break;
case C_VIEW:
view_autoconfigure(container->sway_view);
- transaction_add_container(transaction, container);
+ container_set_dirty(container);
break;
case C_TYPES:
break;
}
- add_deleted_containers(transaction);
-}
-
-void arrange_and_commit(struct sway_container *container) {
- struct sway_transaction *transaction = transaction_create();
- arrange_windows(container, transaction);
- transaction_commit(transaction);
}
void remove_gaps(struct sway_container *c) {
if (c->current_gaps == 0) {
- wlr_log(L_DEBUG, "Removing gaps: not gapped: %p", c);
+ wlr_log(WLR_DEBUG, "Removing gaps: not gapped: %p", c);
return;
}
@@ -326,12 +300,12 @@ void remove_gaps(struct sway_container *c) {
c->current_gaps = 0;
- wlr_log(L_DEBUG, "Removing gaps %p", c);
+ wlr_log(WLR_DEBUG, "Removing gaps %p", c);
}
void add_gaps(struct sway_container *c) {
if (c->current_gaps > 0 || c->type == C_CONTAINER) {
- wlr_log(L_DEBUG, "Not adding gaps: %p", c);
+ wlr_log(WLR_DEBUG, "Not adding gaps: %p", c);
return;
}
@@ -348,5 +322,5 @@ void add_gaps(struct sway_container *c) {
c->height -= 2 * gaps;
c->current_gaps = gaps;
- wlr_log(L_DEBUG, "Adding gaps: %p", c);
+ wlr_log(WLR_DEBUG, "Adding gaps: %p", c);
}
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 7cea43fa..02384199 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -11,11 +11,14 @@
#include "cairo.h"
#include "pango.h"
#include "sway/config.h"
+#include "sway/desktop.h"
+#include "sway/desktop/transaction.h"
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
#include "sway/ipc-server.h"
#include "sway/output.h"
#include "sway/server.h"
+#include "sway/tree/arrange.h"
#include "sway/tree/layout.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
@@ -28,7 +31,7 @@ static list_t *get_bfs_queue() {
if (!bfs_queue) {
bfs_queue = create_list();
if (!bfs_queue) {
- wlr_log(L_ERROR, "could not allocate list for bfs queue");
+ wlr_log(WLR_ERROR, "could not allocate list for bfs queue");
return NULL;
}
}
@@ -156,14 +159,6 @@ void container_free(struct sway_container *cont) {
wlr_texture_destroy(cont->title_focused_inactive);
wlr_texture_destroy(cont->title_unfocused);
wlr_texture_destroy(cont->title_urgent);
-
- for (int i = 0; i < server.destroying_containers->length; ++i) {
- if (server.destroying_containers->items[i] == cont) {
- list_del(server.destroying_containers, i);
- break;
- }
- }
-
list_free(cont->instructions);
list_free(cont->children);
list_free(cont->current.children);
@@ -218,7 +213,7 @@ static struct sway_container *container_workspace_destroy(
return NULL;
}
- wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name);
+ wlr_log(WLR_DEBUG, "destroying workspace '%s'", workspace->name);
if (!workspace_is_empty(workspace)) {
// Move children to a different workspace on this output
@@ -230,7 +225,7 @@ static struct sway_container *container_workspace_destroy(
}
}
- wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'",
+ wlr_log(WLR_DEBUG, "moving children to different workspace '%s' -> '%s'",
workspace->name, new_workspace->name);
for (int i = 0; i < workspace->children->length; i++) {
container_move_to(workspace->children->items[i], new_workspace);
@@ -296,7 +291,7 @@ static struct sway_container *container_output_destroy(
output->sway_output->swayc = NULL;
output->sway_output = NULL;
- wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name);
+ wlr_log(WLR_DEBUG, "OUTPUT: Destroying output '%s'", output->name);
return &root_container;
}
@@ -323,13 +318,13 @@ static struct sway_container *container_destroy_noreaping(
// Workspaces will refuse to be destroyed if they're the last workspace
// on their output.
if (!container_workspace_destroy(con)) {
- wlr_log(L_ERROR, "workspace doesn't want to destroy");
+ wlr_log(WLR_ERROR, "workspace doesn't want to destroy");
return NULL;
}
}
con->destroying = true;
- list_add(server.destroying_containers, con);
+ container_set_dirty(con);
if (!con->parent) {
return NULL;
@@ -350,7 +345,7 @@ bool container_reap_empty(struct sway_container *con) {
break;
case C_WORKSPACE:
if (!workspace_is_visible(con) && workspace_is_empty(con)) {
- wlr_log(L_DEBUG, "Destroying workspace via reaper");
+ wlr_log(WLR_DEBUG, "Destroying workspace via reaper");
container_destroy_noreaping(con);
return true;
}
@@ -443,7 +438,7 @@ struct sway_container *container_view_create(struct sway_container *sibling,
}
const char *title = view_get_title(sway_view);
struct sway_container *swayc = container_create(C_VIEW);
- wlr_log(L_DEBUG, "Adding new view %p:%s to container %p %d %s",
+ wlr_log(WLR_DEBUG, "Adding new view %p:%s to container %p %d %s",
swayc, title, sibling, sibling ? sibling->type : 0, sibling->name);
// Setup values
swayc->sway_view = sway_view;
@@ -686,16 +681,23 @@ struct sway_container *floating_container_at(double lx, double ly,
void container_for_each_descendant_dfs(struct sway_container *container,
void (*f)(struct sway_container *container, void *data),
void *data) {
- if (container) {
- if (container->children) {
- for (int i = 0; i < container->children->length; ++i) {
- struct sway_container *child =
- container->children->items[i];
- container_for_each_descendant_dfs(child, f, data);
- }
+ if (!container) {
+ return;
+ }
+ if (container->children) {
+ for (int i = 0; i < container->children->length; ++i) {
+ struct sway_container *child = container->children->items[i];
+ container_for_each_descendant_dfs(child, f, data);
+ }
+ }
+ if (container->type == C_WORKSPACE) {
+ struct sway_container *floating = container->sway_workspace->floating;
+ for (int i = 0; i < floating->children->length; ++i) {
+ struct sway_container *child = floating->children->items[i];
+ container_for_each_descendant_dfs(child, f, data);
}
- f(container, data);
}
+ f(container, data);
}
void container_for_each_descendant_bfs(struct sway_container *con,
@@ -706,7 +708,7 @@ void container_for_each_descendant_bfs(struct sway_container *con,
}
if (queue == NULL) {
- wlr_log(L_ERROR, "could not allocate list");
+ wlr_log(WLR_ERROR, "could not allocate list");
return;
}
@@ -972,9 +974,14 @@ void container_set_geometry_from_floating_view(struct sway_container *con) {
return;
}
struct sway_view *view = con->sway_view;
- size_t border_width = view->border_thickness * (view->border != B_NONE);
- size_t top =
- view->border == B_NORMAL ? container_titlebar_height() : border_width;
+ size_t border_width = 0;
+ size_t top = 0;
+
+ if (!view->using_csd) {
+ border_width = view->border_thickness * (view->border != B_NONE);
+ top = view->border == B_NORMAL ?
+ container_titlebar_height() : border_width;
+ }
con->x = view->x - border_width;
con->y = view->y - top;
@@ -996,3 +1003,103 @@ void container_get_box(struct sway_container *container, struct wlr_box *box) {
box->width = container->width;
box->height = container->height;
}
+
+/**
+ * Translate the container's position as well as all children.
+ */
+static void container_floating_translate(struct sway_container *con,
+ double x_amount, double y_amount) {
+ con->x += x_amount;
+ con->y += y_amount;
+ con->current.swayc_x += x_amount;
+ con->current.swayc_y += y_amount;
+ if (con->type == C_VIEW) {
+ con->sway_view->x += x_amount;
+ con->sway_view->y += y_amount;
+ con->current.view_x += x_amount;
+ con->current.view_y += y_amount;
+ } else {
+ for (int i = 0; i < con->children->length; ++i) {
+ struct sway_container *child = con->children->items[i];
+ container_floating_translate(child, x_amount, y_amount);
+ }
+ }
+}
+
+/**
+ * Choose an output for the floating container's new position.
+ *
+ * If the center of the container intersects an output then we'll choose that
+ * one, otherwise we'll choose whichever output is closest to the container's
+ * center.
+ */
+static struct sway_container *container_floating_find_output(
+ struct sway_container *con) {
+ double center_x = con->x + con->width / 2;
+ double center_y = con->y + con->height / 2;
+ struct sway_container *closest_output = NULL;
+ double closest_distance = DBL_MAX;
+ for (int i = 0; i < root_container.children->length; ++i) {
+ struct sway_container *output = root_container.children->items[i];
+ struct wlr_box output_box;
+ double closest_x, closest_y;
+ container_get_box(output, &output_box);
+ wlr_box_closest_point(&output_box, center_x, center_y,
+ &closest_x, &closest_y);
+ if (center_x == closest_x && center_y == closest_y) {
+ // The center of the floating container is on this output
+ return output;
+ }
+ double x_dist = closest_x - center_x;
+ double y_dist = closest_y - center_y;
+ double distance = x_dist * x_dist + y_dist * y_dist;
+ if (distance < closest_distance) {
+ closest_output = output;
+ closest_distance = distance;
+ }
+ }
+ return closest_output;
+}
+
+void container_floating_move_to(struct sway_container *con,
+ double lx, double ly) {
+ if (!sway_assert(container_is_floating(con),
+ "Expected a floating container")) {
+ return;
+ }
+ desktop_damage_whole_container(con);
+ container_floating_translate(con, lx - con->x, ly - con->y);
+ desktop_damage_whole_container(con);
+ struct sway_container *old_workspace = container_parent(con, C_WORKSPACE);
+ struct sway_container *new_output = container_floating_find_output(con);
+ if (!sway_assert(new_output, "Unable to find any output")) {
+ return;
+ }
+ struct sway_container *new_workspace =
+ output_get_active_workspace(new_output->sway_output);
+ if (old_workspace != new_workspace) {
+ container_remove_child(con);
+ container_add_child(new_workspace->sway_workspace->floating, con);
+ arrange_windows(old_workspace);
+ arrange_windows(new_workspace);
+ workspace_detect_urgent(old_workspace);
+ workspace_detect_urgent(new_workspace);
+ }
+}
+
+void container_set_dirty(struct sway_container *container) {
+ if (container->dirty) {
+ return;
+ }
+ container->dirty = true;
+ list_add(server.dirty_containers, container);
+}
+
+static bool find_urgent_iterator(struct sway_container *con,
+ void *data) {
+ return con->type == C_VIEW && view_is_urgent(con->sway_view);
+}
+
+bool container_has_urgent_child(struct sway_container *container) {
+ return container_find(container, find_urgent_iterator, NULL);
+}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 14631ad4..197a2fc8 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -22,7 +22,8 @@ struct sway_container root_container;
static void output_layout_handle_change(struct wl_listener *listener,
void *data) {
- arrange_and_commit(&root_container);
+ arrange_windows(&root_container);
+ transaction_commit_dirty();
}
void layout_init(void) {
@@ -101,7 +102,7 @@ void container_insert_child(struct sway_container *parent,
if (old_parent) {
container_remove_child(child);
}
- wlr_log(L_DEBUG, "Inserting id:%zd at index %d", child->id, i);
+ wlr_log(WLR_DEBUG, "Inserting id:%zd at index %d", child->id, i);
list_insert(parent->children, i, child);
child->parent = parent;
container_handle_fullscreen_reparent(child, old_parent);
@@ -127,7 +128,7 @@ struct sway_container *container_add_sibling(struct sway_container *fixed,
void container_add_child(struct sway_container *parent,
struct sway_container *child) {
- wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)",
+ wlr_log(WLR_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)",
child, child->type, child->width, child->height,
parent, parent->type, parent->width, parent->height);
struct sway_container *old_parent = child->parent;
@@ -168,7 +169,12 @@ void container_move_to(struct sway_container *container,
struct sway_container *old_parent = container_remove_child(container);
container->width = container->height = 0;
container->saved_width = container->saved_height = 0;
- struct sway_container *new_parent;
+
+ struct sway_container *new_parent, *new_parent_focus;
+ struct sway_seat *seat = input_manager_get_default_seat(input_manager);
+
+ // Get the focus of the destination before we change it.
+ new_parent_focus = seat_get_focus_inactive(seat, destination);
if (destination->type == C_VIEW) {
new_parent = container_add_sibling(destination, container);
} else {
@@ -176,17 +182,20 @@ void container_move_to(struct sway_container *container,
container_add_child(destination, container);
}
wl_signal_emit(&container->events.reparent, old_parent);
+
if (container->type == C_WORKSPACE) {
// If moving a workspace to a new output, maybe create a new workspace
// on the previous output
- struct sway_seat *seat = input_manager_get_default_seat(input_manager);
if (old_parent->children->length == 0) {
char *ws_name = workspace_next_name(old_parent->name);
- struct sway_container *ws =
- workspace_create(old_parent, ws_name);
+ struct sway_container *ws = workspace_create(old_parent, ws_name);
free(ws_name);
seat_set_focus(seat, ws);
}
+
+ // Try to remove an empty workspace from the destination output.
+ container_reap_empty_recursive(new_parent_focus);
+
container_sort_workspaces(new_parent);
seat_set_focus(seat, new_parent);
workspace_output_raise_priority(container, old_parent, new_parent);
@@ -216,6 +225,15 @@ void container_move_to(struct sway_container *container,
}
}
}
+ // Update workspace urgent state
+ struct sway_container *old_workspace = old_parent;
+ if (old_workspace->type != C_WORKSPACE) {
+ old_workspace = container_parent(old_workspace, C_WORKSPACE);
+ }
+ if (new_workspace != old_workspace) {
+ workspace_detect_urgent(new_workspace);
+ workspace_detect_urgent(old_workspace);
+ }
}
static bool sway_dir_to_wlr(enum movement_direction dir,
@@ -311,13 +329,13 @@ static void move_out_of_tabs_stacks(struct sway_container *container,
int offs) {
if (container->parent == current->parent
&& current->parent->children->length == 1) {
- wlr_log(L_DEBUG, "Changing layout of %zd", current->parent->id);
+ wlr_log(WLR_DEBUG, "Changing layout of %zd", current->parent->id);
current->parent->layout = move_dir ==
MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT;
return;
}
- wlr_log(L_DEBUG, "Moving out of tab/stack into a split");
+ wlr_log(WLR_DEBUG, "Moving out of tab/stack into a split");
bool is_workspace = current->parent->type == C_WORKSPACE;
struct sway_container *new_parent = container_split(current->parent,
move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT);
@@ -362,7 +380,7 @@ void container_move(struct sway_container *container,
}
parent = current->parent;
- wlr_log(L_DEBUG, "Visiting %p %s '%s'", current,
+ wlr_log(WLR_DEBUG, "Visiting %p %s '%s'", current,
container_type_to_str(current->type), current->name);
int index = index_child(current);
@@ -380,12 +398,12 @@ void container_move(struct sway_container *container,
root_container.sway_root->output_layout, wlr_dir,
current->sway_output->wlr_output, ref_lx, ref_ly);
if (!next) {
- wlr_log(L_DEBUG, "Hit edge of output, nowhere else to go");
+ wlr_log(WLR_DEBUG, "Hit edge of output, nowhere else to go");
return;
}
struct sway_output *next_output = next->data;
current = next_output->swayc;
- wlr_log(L_DEBUG, "Selected next output (%s)", current->name);
+ wlr_log(WLR_DEBUG, "Selected next output (%s)", current->name);
// Select workspace and get outta here
current = seat_get_focus_inactive(
config->handler_context.seat, current);
@@ -398,20 +416,20 @@ void container_move(struct sway_container *container,
case C_WORKSPACE:
if (!is_parallel(current->layout, move_dir)) {
if (current->children->length >= 2) {
- wlr_log(L_DEBUG, "Rejiggering the workspace (%d kiddos)",
+ wlr_log(WLR_DEBUG, "Rejiggering the workspace (%d kiddos)",
current->children->length);
workspace_rejigger(current, container, move_dir);
return;
} else {
- wlr_log(L_DEBUG, "Selecting output");
+ wlr_log(WLR_DEBUG, "Selecting output");
current = current->parent;
}
} else if (current->layout == L_TABBED
|| current->layout == L_STACKED) {
- wlr_log(L_DEBUG, "Rejiggering out of tabs/stacks");
+ wlr_log(WLR_DEBUG, "Rejiggering out of tabs/stacks");
workspace_rejigger(current, container, move_dir);
} else {
- wlr_log(L_DEBUG, "Selecting output");
+ wlr_log(WLR_DEBUG, "Selecting output");
current = current->parent;
}
break;
@@ -427,11 +445,11 @@ void container_move(struct sway_container *container,
move_dir, offs);
return;
} else {
- wlr_log(L_DEBUG, "Hit limit, selecting parent");
+ wlr_log(WLR_DEBUG, "Hit limit, selecting parent");
current = current->parent;
}
} else {
- wlr_log(L_DEBUG, "Hit limit, "
+ wlr_log(WLR_DEBUG, "Hit limit, "
"promoting descendant to sibling");
// Special case
container_insert_child(current->parent, container,
@@ -441,14 +459,14 @@ void container_move(struct sway_container *container,
}
} else {
sibling = parent->children->items[index + offs];
- wlr_log(L_DEBUG, "Selecting sibling id:%zd", sibling->id);
+ wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id);
}
} else if (parent->layout == L_TABBED
|| parent->layout == L_STACKED) {
move_out_of_tabs_stacks(container, current, move_dir, offs);
return;
} else {
- wlr_log(L_DEBUG, "Moving up to find a parallel container");
+ wlr_log(WLR_DEBUG, "Moving up to find a parallel container");
current = current->parent;
}
break;
@@ -467,11 +485,11 @@ void container_move(struct sway_container *container,
switch (sibling->type) {
case C_VIEW:
if (sibling->parent == container->parent) {
- wlr_log(L_DEBUG, "Swapping siblings");
+ wlr_log(WLR_DEBUG, "Swapping siblings");
sibling->parent->children->items[index + offs] = container;
sibling->parent->children->items[index] = sibling;
} else {
- wlr_log(L_DEBUG, "Promoting to sibling of cousin");
+ wlr_log(WLR_DEBUG, "Promoting to sibling of cousin");
container_insert_child(sibling->parent, container,
index_child(sibling) + (offs > 0 ? 0 : 1));
container->width = container->height = 0;
@@ -482,31 +500,31 @@ void container_move(struct sway_container *container,
case C_CONTAINER:
if (is_parallel(sibling->layout, move_dir)) {
int limit = container_limit(sibling, invert_movement(move_dir));
- wlr_log(L_DEBUG, "limit: %d", limit);
- wlr_log(L_DEBUG,
+ wlr_log(WLR_DEBUG, "limit: %d", limit);
+ wlr_log(WLR_DEBUG,
"Reparenting container (parallel) to index %d "
"(move dir: %d)", limit, move_dir);
container_insert_child(sibling, container, limit);
container->width = container->height = 0;
sibling = NULL;
} else {
- wlr_log(L_DEBUG, "Reparenting container (perpendicular)");
+ wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)");
struct sway_container *focus_inactive = seat_get_focus_inactive(
config->handler_context.seat, sibling);
if (focus_inactive && focus_inactive != sibling) {
while (focus_inactive->parent != sibling) {
focus_inactive = focus_inactive->parent;
}
- wlr_log(L_DEBUG, "Focus inactive: id:%zd",
+ wlr_log(WLR_DEBUG, "Focus inactive: id:%zd",
focus_inactive->id);
sibling = focus_inactive;
continue;
} else if (sibling->children->length) {
- wlr_log(L_DEBUG, "No focus-inactive, adding arbitrarily");
+ wlr_log(WLR_DEBUG, "No focus-inactive, adding arbitrarily");
container_remove_child(container);
container_add_sibling(sibling->children->items[0], container);
} else {
- wlr_log(L_DEBUG, "No kiddos, adding container alone");
+ wlr_log(WLR_DEBUG, "No kiddos, adding container alone");
container_remove_child(container);
container_add_child(sibling, container);
}
@@ -539,6 +557,8 @@ void container_move(struct sway_container *container,
}
if (last_ws && next_ws && last_ws != next_ws) {
ipc_event_workspace(last_ws, container, "focus");
+ workspace_detect_urgent(last_ws);
+ workspace_detect_urgent(next_ws);
}
}
@@ -603,7 +623,7 @@ static struct sway_container *get_swayc_in_output_direction(
}
if (ws == NULL) {
- wlr_log(L_ERROR, "got an output without a workspace");
+ wlr_log(WLR_ERROR, "got an output without a workspace");
return NULL;
}
@@ -775,7 +795,7 @@ struct sway_container *container_get_in_direction(
} else {
struct sway_container *desired_con =
parent->children->items[desired];
- wlr_log(L_DEBUG,
+ wlr_log(WLR_DEBUG,
"cont %d-%p dir %i sibling %d: %p", idx,
container, dir, desired, desired_con);
return seat_get_focus_inactive_view(seat, desired_con);
@@ -840,7 +860,7 @@ struct sway_container *container_split(struct sway_container *child,
struct sway_container *cont = container_create(C_CONTAINER);
- wlr_log(L_DEBUG, "creating container %p around %p", cont, child);
+ wlr_log(WLR_DEBUG, "creating container %p around %p", cont, child);
remove_gaps(child);
@@ -888,7 +908,7 @@ struct sway_container *container_split(struct sway_container *child,
void container_recursive_resize(struct sway_container *container,
double amount, enum resize_edge edge) {
bool layout_match = true;
- wlr_log(L_DEBUG, "Resizing %p with amount: %f", container, amount);
+ wlr_log(WLR_DEBUG, "Resizing %p with amount: %f", container, amount);
if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) {
container->width += amount;
layout_match = container->layout == L_HORIZ;
@@ -978,7 +998,7 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) {
return;
}
- wlr_log(L_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id);
+ wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id);
int fs1 = con1->type == C_VIEW && con1->sway_view->is_fullscreen;
int fs2 = con2->type == C_VIEW && con2->sway_view->is_fullscreen;
diff --git a/sway/tree/output.c b/sway/tree/output.c
index e2927cdb..da535c18 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -43,11 +43,11 @@ struct sway_container *output_create(
if (strcasecmp(name, cur->name) == 0 ||
strcasecmp(identifier, cur->name) == 0) {
- wlr_log(L_DEBUG, "Matched output config for %s", name);
+ wlr_log(WLR_DEBUG, "Matched output config for %s", name);
oc = cur;
}
if (strcasecmp("*", cur->name) == 0) {
- wlr_log(L_DEBUG, "Matched wildcard output config for %s", name);
+ wlr_log(WLR_DEBUG, "Matched wildcard output config for %s", name);
all = cur;
}
@@ -86,7 +86,7 @@ struct sway_container *output_create(
if (!output->children->length) {
// Create workspace
char *ws_name = workspace_next_name(output->name);
- wlr_log(L_DEBUG, "Creating default workspace %s", ws_name);
+ wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name);
struct sway_container *ws = workspace_create(output, ws_name);
// Set each seat's focus if not already set
struct sway_seat *seat = NULL;
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 3ef79fa8..fc31699c 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -25,6 +25,7 @@ void view_init(struct sway_view *view, enum sway_view_type type,
view->impl = impl;
view->executed_criteria = create_list();
view->marks = create_list();
+ view->allow_request_urgent = true;
wl_signal_init(&view->events.unmap);
}
@@ -150,12 +151,43 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width,
void view_init_floating(struct sway_view *view) {
struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
- int max_width = ws->width * 0.6666;
- int max_height = ws->height * 0.6666;
- view->width =
- view->natural_width > max_width ? max_width : view->natural_width;
- view->height =
- view->natural_height > max_height ? max_height : view->natural_height;
+ int min_width, min_height;
+ int max_width, max_height;
+
+ if (config->floating_minimum_width == -1) { // no minimum
+ min_width = 0;
+ } else if (config->floating_minimum_width == 0) { // automatic
+ min_width = 75;
+ } else {
+ min_width = config->floating_minimum_width;
+ }
+
+ if (config->floating_minimum_height == -1) { // no minimum
+ min_height = 0;
+ } else if (config->floating_minimum_height == 0) { // automatic
+ min_height = 50;
+ } else {
+ min_height = config->floating_minimum_height;
+ }
+
+ if (config->floating_maximum_width == -1) { // no maximum
+ max_width = INT_MAX;
+ } else if (config->floating_maximum_width == 0) { // automatic
+ max_width = ws->width * 0.6666;
+ } else {
+ max_width = config->floating_maximum_width;
+ }
+
+ if (config->floating_maximum_height == -1) { // no maximum
+ max_height = INT_MAX;
+ } else if (config->floating_maximum_height == 0) { // automatic
+ max_height = ws->height * 0.6666;
+ } else {
+ max_height = config->floating_maximum_height;
+ }
+
+ view->width = fmax(min_width, fmin(view->natural_width, max_width));
+ view->height = fmax(min_height, fmin(view->natural_height, max_height));
view->x = ws->x + (ws->width - view->width) / 2;
view->y = ws->y + (ws->height - view->height) / 2;
@@ -284,7 +316,15 @@ void view_set_activated(struct sway_view *view, bool activated) {
}
void view_set_tiled(struct sway_view *view, bool tiled) {
- view->border = tiled ? config->border : B_NONE;
+ if (!tiled) {
+ view->using_csd = true;
+ if (view->impl->has_client_side_decorations) {
+ view->using_csd = view->impl->has_client_side_decorations(view);
+ }
+ } else {
+ view->using_csd = false;
+ }
+
if (view->impl->set_tiled) {
view->impl->set_tiled(view, tiled);
}
@@ -462,27 +502,45 @@ void view_execute_criteria(struct sway_view *view) {
list_t *criterias = criteria_for_view(view, CT_COMMAND);
for (int i = 0; i < criterias->length; i++) {
struct criteria *criteria = criterias->items[i];
- wlr_log(L_DEBUG, "Checking criteria %s", criteria->raw);
+ wlr_log(WLR_DEBUG, "Checking criteria %s", criteria->raw);
if (view_has_executed_criteria(view, criteria)) {
- wlr_log(L_DEBUG, "Criteria already executed");
+ wlr_log(WLR_DEBUG, "Criteria already executed");
continue;
}
- wlr_log(L_DEBUG, "for_window '%s' matches view %p, cmd: '%s'",
+ wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'",
criteria->raw, view, criteria->cmdlist);
+ seat_set_focus(seat, view->swayc);
list_add(view->executed_criteria, criteria);
struct cmd_results *res = execute_command(criteria->cmdlist, NULL);
if (res->status != CMD_SUCCESS) {
- wlr_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error);
+ wlr_log(WLR_ERROR, "Command '%s' failed: %s", res->input, res->error);
}
free_cmd_results(res);
- // view must be focused for commands to affect it,
- // so always refocus in-between command lists
- seat_set_focus(seat, view->swayc);
}
list_free(criterias);
seat_set_focus(seat, prior_focus);
}
+static bool should_focus(struct sway_view *view) {
+ // If the view is the only one in the focused workspace, it'll get focus
+ // regardless of any no_focus criteria.
+ struct sway_container *parent = view->swayc->parent;
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+ if (parent->type == C_WORKSPACE && seat_get_focus(seat) == parent) {
+ size_t num_children = parent->children->length +
+ parent->sway_workspace->floating->children->length;
+ if (num_children == 1) {
+ return true;
+ }
+ }
+
+ // Check no_focus criteria
+ list_t *criterias = criteria_for_view(view, CT_NO_FOCUS);
+ size_t len = criterias->length;
+ list_free(criterias);
+ return len == 0;
+}
+
void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
if (!sway_assert(view->surface == NULL, "cannot map mapped view")) {
return;
@@ -519,8 +577,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
view->surface = wlr_surface;
view->swayc = cont;
- view->border = config->border;
- view->border_thickness = config->border_thickness;
view_init_subsurfaces(view, wlr_surface);
wl_signal_add(&wlr_surface->events.new_subsurface,
@@ -531,14 +587,20 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
view->container_reparent.notify = view_handle_container_reparent;
if (view->impl->wants_floating && view->impl->wants_floating(view)) {
+ view->border = config->floating_border;
+ view->border_thickness = config->floating_border_thickness;
container_set_floating(view->swayc, true);
} else {
+ view->border = config->border;
+ view->border_thickness = config->border_thickness;
view_set_tiled(view, true);
}
- input_manager_set_focus(input_manager, cont);
- if (workspace) {
- workspace_switch(workspace);
+ if (should_focus(view)) {
+ input_manager_set_focus(input_manager, cont);
+ if (workspace) {
+ workspace_switch(workspace);
+ }
}
view_update_title(view, false);
@@ -554,16 +616,27 @@ void view_unmap(struct sway_view *view) {
wl_list_remove(&view->surface_new_subsurface.link);
wl_list_remove(&view->container_reparent.link);
+ if (view->urgent_timer) {
+ wl_event_source_remove(view->urgent_timer);
+ view->urgent_timer = NULL;
+ }
+
+ struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
+
+ struct sway_container *parent;
if (view->is_fullscreen) {
- struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
ws->sway_workspace->fullscreen = NULL;
- container_destroy(view->swayc);
+ parent = container_destroy(view->swayc);
- arrange_and_commit(ws->parent);
+ arrange_windows(ws->parent);
} else {
- struct sway_container *parent = container_destroy(view->swayc);
- arrange_and_commit(parent);
+ parent = container_destroy(view->swayc);
+ arrange_windows(parent);
+ }
+ if (parent->type >= C_WORKSPACE) { // if the workspace still exists
+ workspace_detect_urgent(ws);
}
+ transaction_commit_dirty();
view->surface = NULL;
}
@@ -601,7 +674,7 @@ static void view_subsurface_create(struct sway_view *view,
struct wlr_subsurface *subsurface) {
struct sway_view_child *child = calloc(1, sizeof(struct sway_view_child));
if (child == NULL) {
- wlr_log(L_ERROR, "Allocation failed");
+ wlr_log(WLR_ERROR, "Allocation failed");
return;
}
view_child_init(child, NULL, view, subsurface->surface);
@@ -721,8 +794,9 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) {
return NULL;
}
- wlr_log(L_DEBUG, "Surface of unknown type (role %s): %p",
- wlr_surface->role, wlr_surface);
+ const char *role = wlr_surface->role ? wlr_surface->role->name : NULL;
+ wlr_log(WLR_DEBUG, "Surface of unknown type (role %s): %p",
+ role, wlr_surface);
return NULL;
}
@@ -789,7 +863,7 @@ static char *escape_title(char *buffer) {
char *escaped_title = calloc(length + 1, sizeof(char));
int result = escape_markup_text(buffer, escaped_title, length);
if (result != length) {
- wlr_log(L_ERROR, "Could not escape title: %s", buffer);
+ wlr_log(WLR_ERROR, "Could not escape title: %s", buffer);
free(escaped_title);
return buffer;
}
@@ -1010,3 +1084,32 @@ bool view_is_visible(struct sway_view *view) {
}
return true;
}
+
+void view_set_urgent(struct sway_view *view, bool enable) {
+ if (view_is_urgent(view) == enable) {
+ return;
+ }
+ if (enable) {
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+ if (seat_get_focus(seat) == view->swayc) {
+ return;
+ }
+ clock_gettime(CLOCK_MONOTONIC, &view->urgent);
+ } else {
+ view->urgent = (struct timespec){ 0 };
+ if (view->urgent_timer) {
+ wl_event_source_remove(view->urgent_timer);
+ view->urgent_timer = NULL;
+ }
+ }
+ container_damage_whole(view->swayc);
+
+ ipc_event_window(view->swayc, "urgent");
+
+ struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
+ workspace_detect_urgent(ws);
+}
+
+bool view_is_urgent(struct sway_view *view) {
+ return view->urgent.tv_sec || view->urgent.tv_nsec;
+}
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 51f0fcb4..622f01ec 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -11,6 +11,7 @@
#include "sway/ipc-server.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
+#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
#include "list.h"
#include "log.h"
@@ -49,7 +50,7 @@ struct sway_container *workspace_create(struct sway_container *output,
output = get_workspace_initial_output(name);
}
- wlr_log(L_DEBUG, "Added workspace %s for output %s", name, output->name);
+ wlr_log(WLR_DEBUG, "Added workspace %s for output %s", name, output->name);
struct sway_container *workspace = container_create(C_WORKSPACE);
workspace->x = output->x;
@@ -107,7 +108,7 @@ static bool workspace_valid_on_output(const char *output_name,
}
char *workspace_next_name(const char *output_name) {
- wlr_log(L_DEBUG, "Workspace: Generating new workspace name for output %s",
+ wlr_log(WLR_DEBUG, "Workspace: Generating new workspace name for output %s",
output_name);
// Scan all workspace bindings to find the next available workspace name,
// if none are found/available then default to a number
@@ -135,7 +136,7 @@ char *workspace_next_name(const char *output_name) {
while (isspace(*_target)) {
memmove(_target, _target+1, strlen(_target+1));
}
- wlr_log(L_DEBUG, "Got valid workspace command for target: '%s'",
+ wlr_log(WLR_DEBUG, "Got valid workspace command for target: '%s'",
_target);
// Make sure that the command references an actual workspace
@@ -161,7 +162,7 @@ char *workspace_next_name(const char *output_name) {
temp[length - 1] = '\0';
free(_target);
_target = temp;
- wlr_log(L_DEBUG, "Isolated name from workspace number: '%s'", _target);
+ wlr_log(WLR_DEBUG, "Isolated name from workspace number: '%s'", _target);
// Make sure the workspace number doesn't already exist
if (workspace_by_number(_target)) {
@@ -190,7 +191,7 @@ char *workspace_next_name(const char *output_name) {
order = binding->order;
free(target);
target = _target;
- wlr_log(L_DEBUG, "Workspace: Found free name %s", _target);
+ wlr_log(WLR_DEBUG, "Workspace: Found free name %s", _target);
} else {
free(_target);
}
@@ -387,7 +388,7 @@ bool workspace_switch(struct sway_container *workspace) {
free(prev_workspace_name);
prev_workspace_name = malloc(strlen(active_ws->name) + 1);
if (!prev_workspace_name) {
- wlr_log(L_ERROR, "Unable to allocate previous workspace name");
+ wlr_log(WLR_ERROR, "Unable to allocate previous workspace name");
return false;
}
strcpy(prev_workspace_name, active_ws->name);
@@ -409,7 +410,7 @@ bool workspace_switch(struct sway_container *workspace) {
}
}
- wlr_log(L_DEBUG, "Switching to workspace %p:%s",
+ wlr_log(WLR_DEBUG, "Switching to workspace %p:%s",
workspace, workspace->name);
struct sway_container *next = seat_get_focus_inactive(seat, workspace);
if (next == NULL) {
@@ -427,7 +428,7 @@ bool workspace_switch(struct sway_container *workspace) {
}
seat_set_focus(seat, next);
struct sway_container *output = container_parent(workspace, C_OUTPUT);
- arrange_and_commit(output);
+ arrange_windows(output);
return true;
}
@@ -518,3 +519,13 @@ struct sway_container *workspace_output_get_highest_available(
return NULL;
}
+
+void workspace_detect_urgent(struct sway_container *workspace) {
+ bool new_urgent = container_has_urgent_child(workspace);
+
+ if (workspace->sway_workspace->urgent != new_urgent) {
+ workspace->sway_workspace->urgent = new_urgent;
+ ipc_event_workspace(NULL, workspace, "urgent");
+ container_damage_whole(workspace);
+ }
+}
diff --git a/swaybar/bar.c b/swaybar/bar.c
index 5b8028e5..94bc48bc 100644
--- a/swaybar/bar.c
+++ b/swaybar/bar.c
@@ -46,7 +46,7 @@ static void swaybar_output_free(struct swaybar_output *output) {
if (!output) {
return;
}
- wlr_log(L_DEBUG, "Removing output %s", output->name);
+ wlr_log(WLR_DEBUG, "Removing output %s", output->name);
zwlr_layer_surface_v1_destroy(output->layer_surface);
wl_surface_destroy(output->surface);
wl_output_destroy(output->output);
@@ -147,7 +147,7 @@ static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
&& x < hotspot->x + hotspot->width
&& y < hotspot->y + hotspot->height) {
hotspot->callback(output, pointer->x, pointer->y,
- button, hotspot->data);
+ wl_button_to_x11_button(button), hotspot->data);
}
}
}
@@ -155,11 +155,26 @@ static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis, wl_fixed_t value) {
struct swaybar *bar = data;
+ struct swaybar_pointer *pointer = &bar->pointer;
struct swaybar_output *output = bar->pointer.current;
if (!sway_assert(output, "axis with no active output")) {
return;
}
+ struct swaybar_hotspot *hotspot;
+ wl_list_for_each(hotspot, &output->hotspots, link) {
+ double x = pointer->x * output->scale;
+ double y = pointer->y * output->scale;
+ if (x >= hotspot->x
+ && y >= hotspot->y
+ && x < hotspot->x + hotspot->width
+ && y < hotspot->y + hotspot->height) {
+ hotspot->callback(output, pointer->x, pointer->y,
+ wl_axis_to_x11_button(axis, value), hotspot->data);
+ return;
+ }
+ }
+
double amt = wl_fixed_to_double(value);
if (amt == 0.0) {
return;
diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c
index 141612a6..78b183ad 100644
--- a/swaybar/i3bar.c
+++ b/swaybar/i3bar.c
@@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE 200809L
#include <json-c/json.h>
+#include <linux/input-event-codes.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -31,7 +32,7 @@ static bool i3bar_parse_json(struct status_line *status, const char *text) {
status_error(status, "[failed to parse i3bar json]");
return false;
}
- wlr_log(L_DEBUG, "Got i3bar json: '%s'", text);
+ wlr_log(WLR_DEBUG, "Got i3bar json: '%s'", text);
for (size_t i = 0; i < json_object_array_length(results); ++i) {
json_object *full_text, *short_text, *color, *min_width, *align, *urgent;
json_object *name, *instance, *separator, *separator_block_width;
@@ -192,8 +193,8 @@ bool i3bar_handle_readable(struct status_line *status) {
}
void i3bar_block_send_click(struct status_line *status,
- struct i3bar_block *block, int x, int y, uint32_t button) {
- wlr_log(L_DEBUG, "block %s clicked", block->name ? block->name : "(nil)");
+ struct i3bar_block *block, int x, int y, enum x11_button button) {
+ wlr_log(WLR_DEBUG, "block %s clicked", block->name ? block->name : "(nil)");
if (!block->name || !status->i3bar_state.click_events) {
return;
}
@@ -215,3 +216,32 @@ void i3bar_block_send_click(struct status_line *status,
}
json_object_put(event_json);
}
+
+enum x11_button wl_button_to_x11_button(uint32_t button) {
+ switch (button) {
+ case BTN_LEFT:
+ return LEFT;
+ case BTN_MIDDLE:
+ return MIDDLE;
+ case BTN_RIGHT:
+ return RIGHT;
+ case BTN_SIDE:
+ return BACK;
+ case BTN_EXTRA:
+ return FORWARD;
+ default:
+ return NONE;
+ }
+}
+
+enum x11_button wl_axis_to_x11_button(uint32_t axis, wl_fixed_t value) {
+ switch (axis) {
+ case WL_POINTER_AXIS_VERTICAL_SCROLL:
+ return wl_fixed_to_double(value) < 0 ? SCROLL_UP : SCROLL_DOWN;
+ case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
+ return wl_fixed_to_double(value) < 0 ? SCROLL_LEFT : SCROLL_RIGHT;
+ default:
+ wlr_log(WLR_DEBUG, "Unexpected axis value on mouse scroll");
+ return NONE;
+ }
+}
diff --git a/swaybar/ipc.c b/swaybar/ipc.c
index 959fa095..c2d05920 100644
--- a/swaybar/ipc.c
+++ b/swaybar/ipc.c
@@ -115,6 +115,18 @@ static void ipc_parse_colors(
config->colors.inactive_workspace.text = parse_color(
json_object_get_string(inactive_workspace_text));
}
+ if (urgent_workspace_border) {
+ config->colors.urgent_workspace.border = parse_color(
+ json_object_get_string(urgent_workspace_border));
+ }
+ if (urgent_workspace_bg) {
+ config->colors.urgent_workspace.background = parse_color(
+ json_object_get_string(urgent_workspace_bg));
+ }
+ if (urgent_workspace_text) {
+ config->colors.urgent_workspace.text = parse_color(
+ json_object_get_string(urgent_workspace_text));
+ }
if (binding_mode_border) {
config->colors.binding_mode.border = parse_color(
json_object_get_string(binding_mode_border));
@@ -327,7 +339,7 @@ bool handle_ipc_readable(struct swaybar *bar) {
json_object *result = json_tokener_parse(resp->payload);
if (!result) {
free_ipc_response(resp);
- wlr_log(L_ERROR, "failed to parse payload as json");
+ wlr_log(WLR_ERROR, "failed to parse payload as json");
return false;
}
json_object *json_change, *json_pango_markup;
@@ -340,7 +352,7 @@ bool handle_ipc_readable(struct swaybar *bar) {
bar->config->mode = strdup(change);
}
} else {
- wlr_log(L_ERROR, "failed to parse response");
+ wlr_log(WLR_ERROR, "failed to parse response");
json_object_put(result);
free_ipc_response(resp);
return false;
diff --git a/swaybar/main.c b/swaybar/main.c
index c897e1c9..60e4b37c 100644
--- a/swaybar/main.c
+++ b/swaybar/main.c
@@ -75,13 +75,13 @@ int main(int argc, char **argv) {
}
if (debug) {
- wlr_log_init(L_DEBUG, NULL);
+ wlr_log_init(WLR_DEBUG, NULL);
} else {
- wlr_log_init(L_ERROR, NULL);
+ wlr_log_init(WLR_ERROR, NULL);
}
if (!bar_id) {
- wlr_log(L_ERROR, "No bar_id passed. "
+ wlr_log(WLR_ERROR, "No bar_id passed. "
"Provide --bar_id or let sway start swaybar");
return 1;
}
@@ -89,7 +89,7 @@ int main(int argc, char **argv) {
if (!socket_path) {
socket_path = get_socketpath();
if (!socket_path) {
- wlr_log(L_ERROR, "Unable to retrieve socket path");
+ wlr_log(WLR_ERROR, "Unable to retrieve socket path");
return 1;
}
}
diff --git a/swaybar/render.c b/swaybar/render.c
index 2ebd338e..d210e25a 100644
--- a/swaybar/render.c
+++ b/swaybar/render.c
@@ -109,7 +109,7 @@ static void render_sharp_line(cairo_t *cairo, uint32_t color,
}
static void block_hotspot_callback(struct swaybar_output *output,
- int x, int y, uint32_t button, void *data) {
+ int x, int y, enum x11_button button, void *data) {
struct i3bar_block *block = data;
struct status_line *status = output->bar->status;
i3bar_block_send_click(status, block, x, y, button);
@@ -349,7 +349,7 @@ static const char *strip_workspace_number(const char *ws_name) {
}
static void workspace_hotspot_callback(struct swaybar_output *output,
- int x, int y, uint32_t button, void *data) {
+ int x, int y, enum x11_button button, void *data) {
ipc_send_workspace_command(output->bar, (const char *)data);
}
@@ -503,6 +503,9 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) {
output->buffers,
output->width * output->scale,
output->height * output->scale);
+ if (!output->current_buffer) {
+ return;
+ }
cairo_t *shm = output->current_buffer->cairo;
cairo_save(shm);
diff --git a/swaybar/status_line.c b/swaybar/status_line.c
index e0e7414a..bc47580b 100644
--- a/swaybar/status_line.c
+++ b/swaybar/status_line.c
@@ -49,14 +49,14 @@ bool status_handle_readable(struct status_line *status) {
json_object *version;
if (json_object_object_get_ex(proto, "version", &version)
&& json_object_get_int(version) == 1) {
- wlr_log(L_DEBUG, "Switched to i3bar protocol.");
+ wlr_log(WLR_DEBUG, "Switched to i3bar protocol.");
status->protocol = PROTOCOL_I3BAR;
}
json_object *click_events;
if (json_object_object_get_ex(
proto, "click_events", &click_events)
&& json_object_get_boolean(click_events)) {
- wlr_log(L_DEBUG, "Enabled click events.");
+ wlr_log(WLR_DEBUG, "Enabled click events.");
status->i3bar_state.click_events = true;
const char *events_array = "[\n";
ssize_t len = strlen(events_array);
@@ -91,7 +91,7 @@ struct status_line *status_line_init(char *cmd) {
int pipe_read_fd[2];
int pipe_write_fd[2];
if (pipe(pipe_read_fd) != 0 || pipe(pipe_write_fd) != 0) {
- wlr_log(L_ERROR, "Unable to create pipes for status_command fork");
+ wlr_log(WLR_ERROR, "Unable to create pipes for status_command fork");
exit(1);
}
diff --git a/swaybg/main.c b/swaybg/main.c
index 5b6c378c..f8e7e7ef 100644
--- a/swaybg/main.c
+++ b/swaybg/main.c
@@ -48,7 +48,7 @@ struct swaybg_state {
bool is_valid_color(const char *color) {
int len = strlen(color);
if (len != 7 || color[0] != '#') {
- wlr_log(L_ERROR, "%s is not a valid color for swaybg. "
+ wlr_log(WLR_ERROR, "%s is not a valid color for swaybg. "
"Color should be specified as #rrggbb (no alpha).", color);
return false;
}
@@ -68,6 +68,9 @@ static void render_frame(struct swaybg_state *state) {
buffer_height = state->height * state->scale;
state->current_buffer = get_next_buffer(state->shm,
state->buffers, buffer_width, buffer_height);
+ if (!state->current_buffer) {
+ return;
+ }
cairo_t *cairo = state->current_buffer->cairo;
if (state->args->mode == BACKGROUND_MODE_SOLID_COLOR) {
cairo_set_source_u32(cairo, state->context.color);
@@ -185,10 +188,10 @@ int main(int argc, const char **argv) {
struct swaybg_args args = {0};
struct swaybg_state state = {0};
state.args = &args;
- wlr_log_init(L_DEBUG, NULL);
+ wlr_log_init(WLR_DEBUG, NULL);
if (argc != 4) {
- wlr_log(L_ERROR, "Do not run this program manually. "
+ wlr_log(WLR_ERROR, "Do not run this program manually. "
"See man 5 sway and look for output options.");
return 1;
}
diff --git a/swayidle/main.c b/swayidle/main.c
index 7666578f..678d622f 100644
--- a/swayidle/main.c
+++ b/swayidle/main.c
@@ -1,22 +1,21 @@
#define _XOPEN_SOURCE 500
+#include <errno.h>
#include <getopt.h>
-#include <signal.h>
#include <pthread.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <wayland-client-protocol.h>
#include <wayland-client.h>
+#include <wayland-server.h>
#include <wayland-util.h>
#include <wlr/config.h>
#include <wlr/util/log.h>
-#include <wlr/types/wlr_output_layout.h>
-#include <wlr/types/wlr_output.h>
-#include "idle-client-protocol.h"
#include "config.h"
+#include "idle-client-protocol.h"
#include "list.h"
#ifdef SWAY_IDLE_HAS_SYSTEMD
#include <systemd/sd-bus.h>
@@ -36,7 +35,6 @@ struct swayidle_state {
struct wl_display *display;
struct org_kde_kwin_idle_timeout *idle_timer;
struct org_kde_kwin_idle_timeout *lock_timer;
- struct wlr_output_layout *layout;
struct wl_event_loop *event_loop;
list_t *timeout_cmds;
} state;
@@ -59,24 +57,24 @@ static void cmd_exec(void *data) {
return;
}
char *param = (char *)data;
- wlr_log(L_DEBUG, "Cmd exec %s", param);
+ wlr_log(WLR_DEBUG, "Cmd exec %s", param);
pid_t pid = fork();
if (pid == 0) {
pid = fork();
if (pid == 0) {
char *const cmd[] = { "sh", "-c", param, NULL, };
execvp(cmd[0], cmd);
- wlr_log_errno(L_ERROR, "execve failed!");
+ wlr_log_errno(WLR_ERROR, "execve failed!");
exit(1);
} else if (pid < 0) {
- wlr_log_errno(L_ERROR, "fork failed");
+ wlr_log_errno(WLR_ERROR, "fork failed");
exit(1);
}
exit(0);
} else if (pid < 0) {
- wlr_log_errno(L_ERROR, "fork failed");
+ wlr_log_errno(WLR_ERROR, "fork failed");
} else {
- wlr_log(L_DEBUG, "Spawned process %s", param);
+ wlr_log(WLR_DEBUG, "Spawned process %s", param);
waitpid(pid, NULL, 0);
}
}
@@ -86,7 +84,7 @@ static int lock_fd = -1;
static int ongoing_fd = -1;
static int release_lock(void *data) {
- wlr_log(L_INFO, "Releasing sleep lock %d", ongoing_fd);
+ wlr_log(WLR_INFO, "Releasing sleep lock %d", ongoing_fd);
if (ongoing_fd >= 0) {
close(ongoing_fd);
}
@@ -101,7 +99,7 @@ void acquire_sleep_lock() {
int ret = sd_bus_default_system(&bus);
if (ret < 0) {
- wlr_log(L_ERROR, "Failed to open D-Bus connection: %s",
+ wlr_log(WLR_ERROR, "Failed to open D-Bus connection: %s",
strerror(-ret));
return;
}
@@ -112,17 +110,17 @@ void acquire_sleep_lock() {
&error, &msg, "ssss", "sleep", "swayidle",
"Setup Up Lock Screen", "delay");
if (ret < 0) {
- wlr_log(L_ERROR, "Failed to send Inhibit signal: %s",
+ wlr_log(WLR_ERROR, "Failed to send Inhibit signal: %s",
strerror(-ret));
} else {
ret = sd_bus_message_read(msg, "h", &lock_fd);
if (ret < 0) {
- wlr_log(L_ERROR,
+ wlr_log(WLR_ERROR,
"Failed to parse D-Bus response for Inhibit: %s",
strerror(-ret));
}
}
- wlr_log(L_INFO, "Got sleep lock: %d", lock_fd);
+ wlr_log(WLR_INFO, "Got sleep lock: %d", lock_fd);
}
static int prepare_for_sleep(sd_bus_message *msg, void *userdata,
@@ -131,10 +129,10 @@ static int prepare_for_sleep(sd_bus_message *msg, void *userdata,
int going_down = 1;
int ret = sd_bus_message_read(msg, "b", &going_down);
if (ret < 0) {
- wlr_log(L_ERROR, "Failed to parse D-Bus response for Inhibit: %s",
+ wlr_log(WLR_ERROR, "Failed to parse D-Bus response for Inhibit: %s",
strerror(-ret));
}
- wlr_log(L_DEBUG, "PrepareForSleep signal received %d", going_down);
+ wlr_log(WLR_DEBUG, "PrepareForSleep signal received %d", going_down);
if (!going_down) {
acquire_sleep_lock();
return 0;
@@ -151,7 +149,7 @@ static int prepare_for_sleep(sd_bus_message *msg, void *userdata,
wl_event_loop_add_timer(state.event_loop, release_lock, NULL);
wl_event_source_timer_update(source, 1000);
}
- wlr_log(L_DEBUG, "Prepare for sleep done");
+ wlr_log(WLR_DEBUG, "Prepare for sleep done");
return 0;
}
@@ -165,10 +163,10 @@ static int dbus_event(int fd, uint32_t mask, void *data) {
void setup_sleep_listener() {
struct sd_bus *bus;
-
+
int ret = sd_bus_default_system(&bus);
if (ret < 0) {
- wlr_log(L_ERROR, "Failed to open D-Bus connection: %s",
+ wlr_log(WLR_ERROR, "Failed to open D-Bus connection: %s",
strerror(-ret));
return;
}
@@ -183,7 +181,7 @@ void setup_sleep_listener() {
"/org/freedesktop/login1");
ret = sd_bus_add_match(bus, NULL, str, prepare_for_sleep, NULL);
if (ret < 0) {
- wlr_log(L_ERROR, "Failed to add D-Bus match: %s", strerror(-ret));
+ wlr_log(WLR_ERROR, "Failed to add D-Bus match: %s", strerror(-ret));
return;
}
acquire_sleep_lock();
@@ -214,7 +212,7 @@ static const struct wl_registry_listener registry_listener = {
static void handle_idle(void *data, struct org_kde_kwin_idle_timeout *timer) {
struct swayidle_timeout_cmd *cmd = data;
- wlr_log(L_DEBUG, "idle state");
+ wlr_log(WLR_DEBUG, "idle state");
if (cmd && cmd->idle_cmd && cmd->idle_cmd->callback) {
cmd->idle_cmd->callback(cmd->idle_cmd->param);
}
@@ -222,7 +220,7 @@ static void handle_idle(void *data, struct org_kde_kwin_idle_timeout *timer) {
static void handle_resume(void *data, struct org_kde_kwin_idle_timeout *timer) {
struct swayidle_timeout_cmd *cmd = data;
- wlr_log(L_DEBUG, "active state");
+ wlr_log(WLR_DEBUG, "active state");
if (cmd && cmd->resume_cmd && cmd->resume_cmd->callback) {
cmd->resume_cmd->callback(cmd->resume_cmd->param);
}
@@ -235,12 +233,12 @@ static const struct org_kde_kwin_idle_timeout_listener idle_timer_listener = {
struct swayidle_cmd *parse_command(int argc, char **argv) {
if (argc < 1) {
- wlr_log(L_ERROR, "Too few parameters for command in parse_command");
+ wlr_log(WLR_ERROR, "Too few parameters for command in parse_command");
return NULL;
}
struct swayidle_cmd *cmd = calloc(1, sizeof(struct swayidle_cmd));
- wlr_log(L_DEBUG, "Command: %s", argv[0]);
+ wlr_log(WLR_DEBUG, "Command: %s", argv[0]);
cmd->callback = cmd_exec;
cmd->param = argv[0];
return cmd;
@@ -248,7 +246,7 @@ struct swayidle_cmd *parse_command(int argc, char **argv) {
int parse_timeout(int argc, char **argv) {
if (argc < 3) {
- wlr_log(L_ERROR, "Too few parameters to timeout command. "
+ wlr_log(WLR_ERROR, "Too few parameters to timeout command. "
"Usage: timeout <seconds> <command>");
exit(-1);
}
@@ -256,7 +254,7 @@ int parse_timeout(int argc, char **argv) {
char *endptr;
int seconds = strtoul(argv[1], &endptr, 10);
if (errno != 0 || *endptr != '\0') {
- wlr_log(L_ERROR, "Invalid timeout parameter '%s', it should be a "
+ wlr_log(WLR_ERROR, "Invalid timeout parameter '%s', it should be a "
"numeric value representing seconds", optarg);
exit(-1);
}
@@ -264,13 +262,13 @@ int parse_timeout(int argc, char **argv) {
calloc(1, sizeof(struct swayidle_timeout_cmd));
cmd->timeout = seconds * 1000;
- wlr_log(L_DEBUG, "Register idle timeout at %d ms", cmd->timeout);
- wlr_log(L_DEBUG, "Setup idle");
+ wlr_log(WLR_DEBUG, "Register idle timeout at %d ms", cmd->timeout);
+ wlr_log(WLR_DEBUG, "Setup idle");
cmd->idle_cmd = parse_command(argc - 2, &argv[2]);
int result = 3;
if (argc >= 5 && !strcmp("resume", argv[3])) {
- wlr_log(L_DEBUG, "Setup resume");
+ wlr_log(WLR_DEBUG, "Setup resume");
cmd->resume_cmd = parse_command(argc - 4, &argv[4]);
result = 5;
}
@@ -280,14 +278,14 @@ int parse_timeout(int argc, char **argv) {
int parse_sleep(int argc, char **argv) {
if (argc < 2) {
- wlr_log(L_ERROR, "Too few parameters to before-sleep command. "
+ wlr_log(WLR_ERROR, "Too few parameters to before-sleep command. "
"Usage: before-sleep <command>");
exit(-1);
}
lock_cmd = parse_command(argc - 1, &argv[1]);
if (lock_cmd) {
- wlr_log(L_DEBUG, "Setup sleep lock: %s", lock_cmd->param);
+ wlr_log(WLR_DEBUG, "Setup sleep lock: %s", lock_cmd->param);
}
return 2;
@@ -314,10 +312,10 @@ int parse_args(int argc, char *argv[]) {
}
if (debug) {
- wlr_log_init(L_DEBUG, NULL);
- wlr_log(L_DEBUG, "Loglevel debug");
+ wlr_log_init(WLR_DEBUG, NULL);
+ wlr_log(WLR_DEBUG, "Loglevel debug");
} else {
- wlr_log_init(L_INFO, NULL);
+ wlr_log_init(WLR_INFO, NULL);
}
@@ -326,13 +324,13 @@ int parse_args(int argc, char *argv[]) {
int i = optind;
while (i < argc) {
if (!strcmp("timeout", argv[i])) {
- wlr_log(L_DEBUG, "Got timeout");
+ wlr_log(WLR_DEBUG, "Got timeout");
i += parse_timeout(argc - i, &argv[i]);
} else if (!strcmp("before-sleep", argv[i])) {
- wlr_log(L_DEBUG, "Got before-sleep");
+ wlr_log(WLR_DEBUG, "Got before-sleep");
i += parse_sleep(argc - i, &argv[i]);
} else {
- wlr_log(L_ERROR, "Unsupported command '%s'", argv[i]);
+ wlr_log(WLR_ERROR, "Unsupported command '%s'", argv[i]);
exit(-1);
}
}
@@ -358,16 +356,16 @@ static int display_event(int fd, uint32_t mask, void *data) {
sway_terminate(0);
}
if (wl_display_dispatch(state.display) < 0) {
- wlr_log_errno(L_ERROR, "wl_display_dispatch failed, exiting");
+ wlr_log_errno(WLR_ERROR, "wl_display_dispatch failed, exiting");
sway_terminate(0);
- };
+ }
return 0;
}
void register_idle_timeout(void *item) {
struct swayidle_timeout_cmd *cmd = item;
if (cmd == NULL || !cmd->timeout) {
- wlr_log(L_ERROR, "Invalid idle cmd, will not register");
+ wlr_log(WLR_ERROR, "Invalid idle cmd, will not register");
return;
}
state.idle_timer =
@@ -376,7 +374,7 @@ void register_idle_timeout(void *item) {
org_kde_kwin_idle_timeout_add_listener(state.idle_timer,
&idle_timer_listener, cmd);
} else {
- wlr_log(L_ERROR, "Could not create idle timer");
+ wlr_log(WLR_ERROR, "Could not create idle timer");
}
}
@@ -390,22 +388,21 @@ int main(int argc, char *argv[]) {
state.display = wl_display_connect(NULL);
if (state.display == NULL) {
- wlr_log(L_ERROR, "Failed to create display");
+ wlr_log(WLR_ERROR, "Failed to create display");
return -3;
}
struct wl_registry *registry = wl_display_get_registry(state.display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_roundtrip(state.display);
- state.layout = wlr_output_layout_create();
state.event_loop = wl_event_loop_create();
if (idle_manager == NULL) {
- wlr_log(L_ERROR, "Display doesn't support idle protocol");
+ wlr_log(WLR_ERROR, "Display doesn't support idle protocol");
return -4;
}
if (seat == NULL) {
- wlr_log(L_ERROR, "Seat error");
+ wlr_log(WLR_ERROR, "Seat error");
return -5;
}
@@ -417,7 +414,7 @@ int main(int argc, char *argv[]) {
}
#endif
if (!should_run) {
- wlr_log(L_INFO, "No command specified! Nothing to do, will exit");
+ wlr_log(WLR_INFO, "No command specified! Nothing to do, will exit");
sway_terminate(0);
}
list_foreach(state.timeout_cmds, register_idle_timeout);
diff --git a/swaylock/main.c b/swaylock/main.c
index 73c2b5d6..ae5b86b9 100644
--- a/swaylock/main.c
+++ b/swaylock/main.c
@@ -21,6 +21,7 @@
#include "pool-buffer.h"
#include "cairo.h"
#include "log.h"
+#include "readline.h"
#include "stringop.h"
#include "util.h"
#include "wlr-input-inhibitor-unstable-v1-client-protocol.h"
@@ -34,7 +35,7 @@ void sway_terminate(int exit_code) {
static void daemonize() {
int fds[2];
if (pipe(fds) != 0) {
- wlr_log(L_ERROR, "Failed to pipe");
+ wlr_log(WLR_ERROR, "Failed to pipe");
exit(1);
}
if (fork() == 0) {
@@ -58,7 +59,7 @@ static void daemonize() {
close(fds[1]);
uint8_t success;
if (read(fds[0], &success, 1) != 1 || !success) {
- wlr_log(L_ERROR, "Failed to daemonize");
+ wlr_log(WLR_ERROR, "Failed to daemonize");
exit(1);
}
close(fds[0]);
@@ -89,7 +90,7 @@ static bool surface_is_opaque(struct swaylock_surface *surface) {
if (surface->image) {
return cairo_surface_get_content(surface->image) == CAIRO_CONTENT_COLOR;
}
- return (surface->state->args.color & 0xff) == 0xff;
+ return (surface->state->args.colors.background & 0xff) == 0xff;
}
static void create_layer_surface(struct swaylock_surface *surface) {
@@ -238,7 +239,7 @@ static void handle_xdg_output_logical_position(void *data,
static void handle_xdg_output_name(void *data, struct zxdg_output_v1 *output,
const char *name) {
- wlr_log(L_DEBUG, "output name is %s", name);
+ wlr_log(WLR_DEBUG, "output name is %s", name);
struct swaylock_surface *surface = data;
surface->xdg_output = output;
surface->output_name = strdup(name);
@@ -354,10 +355,10 @@ static void load_image(char *arg, struct swaylock_state *state) {
}
if (exists) {
if (image->output_name) {
- wlr_log(L_ERROR, "Multiple images defined for output %s",
+ wlr_log(WLR_ERROR, "Multiple images defined for output %s",
image->output_name);
} else {
- wlr_log(L_ERROR, "Multiple default images defined");
+ wlr_log(WLR_ERROR, "Multiple default images defined");
}
}
@@ -377,71 +378,232 @@ static void load_image(char *arg, struct swaylock_state *state) {
}
wl_list_insert(&state->images, &image->link);
state->args.mode = BACKGROUND_MODE_FILL;
- wlr_log(L_DEBUG, "Loaded image %s for output %s",
+ wlr_log(WLR_DEBUG, "Loaded image %s for output %s",
image->path, image->output_name ? image->output_name : "*");
}
-static struct swaylock_state state;
+static void set_default_colors(struct swaylock_colors *colors) {
+ colors->background = 0xFFFFFFFF;
+ colors->bs_highlight = 0xDB3300FF;
+ colors->key_highlight = 0x33DB00FF;
+ colors->separator = 0x000000FF;
+ colors->inside = (struct swaylock_colorset){
+ .input = 0x000000C0,
+ .cleared = 0xE5A445C0,
+ .verifying = 0x0072FFC0,
+ .wrong = 0xFA0000C0,
+ };
+ colors->line = (struct swaylock_colorset){
+ .input = 0x000000FF,
+ .cleared = 0x000000FF,
+ .verifying = 0x000000FF,
+ .wrong = 0x000000FF,
+ };
+ colors->ring = (struct swaylock_colorset){
+ .input = 0x337D00FF,
+ .cleared = 0xE5A445FF,
+ .verifying = 0x3300FFFF,
+ .wrong = 0x7D3300FF,
+ };
+ colors->text = (struct swaylock_colorset){
+ .input = 0xE5A445FF,
+ .cleared = 0x000000FF,
+ .verifying = 0x000000FF,
+ .wrong = 0x000000FF,
+ };
+}
+
+enum line_mode {
+ LM_LINE,
+ LM_INSIDE,
+ LM_RING,
+};
+
+static int parse_options(int argc, char **argv, struct swaylock_state *state,
+ enum line_mode *line_mode) {
+ enum long_option_codes {
+ LO_BS_HL_COLOR = 256,
+ LO_FONT,
+ LO_IND_RADIUS,
+ LO_IND_THICKNESS,
+ LO_INSIDE_COLOR,
+ LO_INSIDE_CLEAR_COLOR,
+ LO_INSIDE_VER_COLOR,
+ LO_INSIDE_WRONG_COLOR,
+ LO_KEY_HL_COLOR,
+ LO_LINE_COLOR,
+ LO_LINE_CLEAR_COLOR,
+ LO_LINE_VER_COLOR,
+ LO_LINE_WRONG_COLOR,
+ LO_RING_COLOR,
+ LO_RING_CLEAR_COLOR,
+ LO_RING_VER_COLOR,
+ LO_RING_WRONG_COLOR,
+ LO_SEP_COLOR,
+ LO_TEXT_COLOR,
+ LO_TEXT_CLEAR_COLOR,
+ LO_TEXT_VER_COLOR,
+ LO_TEXT_WRONG_COLOR,
+ };
-int main(int argc, char **argv) {
static struct option long_options[] = {
- {"help", no_argument, NULL, 'h'},
+ {"config", required_argument, NULL, 'C'},
{"color", required_argument, NULL, 'c'},
+ {"ignore-empty-password", no_argument, NULL, 'e'},
+ {"daemonize", no_argument, NULL, 'f'},
+ {"help", no_argument, NULL, 'h'},
{"image", required_argument, NULL, 'i'},
+ {"line-uses-inside", no_argument, NULL, 'n'},
+ {"socket", required_argument, NULL, 'p'},
+ {"line-uses-ring", no_argument, NULL, 'r'},
{"scaling", required_argument, NULL, 's'},
{"tiling", no_argument, NULL, 't'},
- {"version", no_argument, NULL, 'v'},
- {"socket", required_argument, NULL, 'p'},
{"no-unlock-indicator", no_argument, NULL, 'u'},
- {"daemonize", no_argument, NULL, 'f'},
+ {"version", no_argument, NULL, 'v'},
+ {"bs-hl-color", required_argument, NULL, LO_BS_HL_COLOR},
+ {"font", required_argument, NULL, LO_FONT},
+ {"indicator-radius", required_argument, NULL, LO_IND_RADIUS},
+ {"indicator-thickness", required_argument, NULL, LO_IND_THICKNESS},
+ {"inside-color", required_argument, NULL, LO_INSIDE_COLOR},
+ {"inside-clear-color", required_argument, NULL, LO_INSIDE_CLEAR_COLOR},
+ {"inside-ver-color", required_argument, NULL, LO_INSIDE_VER_COLOR},
+ {"inside-wrong-color", required_argument, NULL, LO_INSIDE_WRONG_COLOR},
+ {"key-hl-color", required_argument, NULL, LO_KEY_HL_COLOR},
+ {"line-color", required_argument, NULL, LO_LINE_COLOR},
+ {"line-clear-color", required_argument, NULL, LO_LINE_CLEAR_COLOR},
+ {"line-ver-color", required_argument, NULL, LO_LINE_VER_COLOR},
+ {"line-wrong-color", required_argument, NULL, LO_LINE_WRONG_COLOR},
+ {"ring-color", required_argument, NULL, LO_RING_COLOR},
+ {"ring-clear-color", required_argument, NULL, LO_RING_CLEAR_COLOR},
+ {"ring-ver-color", required_argument, NULL, LO_RING_VER_COLOR},
+ {"ring-wrong-color", required_argument, NULL, LO_RING_WRONG_COLOR},
+ {"separator-color", required_argument, NULL, LO_SEP_COLOR},
+ {"text-color", required_argument, NULL, LO_TEXT_COLOR},
+ {"text-clear-color", required_argument, NULL, LO_TEXT_CLEAR_COLOR},
+ {"text-ver-color", required_argument, NULL, LO_TEXT_VER_COLOR},
+ {"text-wrong-color", required_argument, NULL, LO_TEXT_WRONG_COLOR},
{0, 0, 0, 0}
};
const char usage[] =
"Usage: swaylock [options...]\n"
"\n"
- " -h, --help Show help message and quit.\n"
- " -c, --color <rrggbb[aa]> Turn the screen into the given color instead of white.\n"
- " -s, --scaling Scaling mode: stretch, fill, fit, center, tile.\n"
- " -t, --tiling Same as --scaling=tile.\n"
- " -v, --version Show the version number and quit.\n"
- " -i, --image [<output>:]<path> Display the given image.\n"
- " -u, --no-unlock-indicator Disable the unlock indicator.\n"
- " -f, --daemonize Detach from the controlling terminal after locking.\n";
-
- state.args = (struct swaylock_args){
- .mode = BACKGROUND_MODE_SOLID_COLOR,
- .color = 0xFFFFFFFF,
- .show_indicator = true,
- };
- wl_list_init(&state.images);
-
- wlr_log_init(L_DEBUG, NULL);
+ " -C, --config <config_file> "
+ "Path to the config file.\n"
+ " -c, --color <color> "
+ "Turn the screen into the given color instead of white.\n"
+ " -e, --ignore-empty-password "
+ "When an empty password is provided, do not validate it.\n"
+ " -f, --daemonize "
+ "Detach from the controlling terminal after locking.\n"
+ " -h, --help "
+ "Show help message and quit.\n"
+ " -i, --image [<output>:]<path> "
+ "Display the given image.\n"
+ " -s, --scaling <mode> "
+ "Scaling mode: stretch, fill, fit, center, tile.\n"
+ " -t, --tiling "
+ "Same as --scaling=tile.\n"
+ " -u, --no-unlock-indicator "
+ "Disable the unlock indicator.\n"
+ " -v, --version "
+ "Show the version number and quit.\n"
+ " --bs-hl-color <color> "
+ "Sets the color of backspace highlight segments.\n"
+ " --font <font> "
+ "Sets the font of the text.\n"
+ " --indicator-radius <radius> "
+ "Sets the indicator radius.\n"
+ " --indicator-thickness <thick> "
+ "Sets the indicator thickness.\n"
+ " --inside-color <color> "
+ "Sets the color of the inside of the indicator.\n"
+ " --inside-clear-color <color> "
+ "Sets the color of the inside of the indicator when cleared.\n"
+ " --inside-ver-color <color> "
+ "Sets the color of the inside of the indicator when verifying.\n"
+ " --inside-wrong-color <color> "
+ "Sets the color of the inside of the indicator when invalid.\n"
+ " --key-hl-color <color> "
+ "Sets the color of the key press highlight segments.\n"
+ " --line-color <color> "
+ "Sets the color of the line between the inside and ring.\n"
+ " --line-clear-color <color> "
+ "Sets the color of the line between the inside and ring when "
+ "cleared.\n"
+ " --line-ver-color <color> "
+ "Sets the color of the line between the inside and ring when "
+ "verifying.\n"
+ " --line-wrong-color <color> "
+ "Sets the color of the line between the inside and ring when "
+ "invalid.\n"
+ " -n, --line-uses-inside "
+ "Use the inside color for the line between the inside and ring.\n"
+ " -r, --line-uses-ring "
+ "Use the ring color for the line between the inside and ring.\n"
+ " --ring-color <color> "
+ "Sets the color of the ring of the indicator.\n"
+ " --ring-clear-color <color> "
+ "Sets the color of the ring of the indicator when cleared.\n"
+ " --ring-ver-color <color> "
+ "Sets the color of the ring of the indicator when verifying.\n"
+ " --ring-wrong-color <color> "
+ "Sets the color of the ring of the indicator when invalid.\n"
+ " --separator-color <color> "
+ "Sets the color of the lines that separate highlight segments.\n"
+ " --text-color <color> "
+ "Sets the color of the text.\n"
+ " --text-clear-color <color> "
+ "Sets the color of the text when cleared.\n"
+ " --text-ver-color <color> "
+ "Sets the color of the text when verifying.\n"
+ " --text-wrong-color <color> "
+ "Sets the color of the text when invalid.\n"
+ "\n"
+ "All <color> options are of the form <rrggbb[aa]>.\n";
int c;
+ optind = 1;
while (1) {
- int option_index = 0;
- c = getopt_long(argc, argv, "hc:i:s:tvuf", long_options, &option_index);
+ int opt_idx = 0;
+ c = getopt_long(argc, argv, "c:efhi:nrs:tuvC:", long_options, &opt_idx);
if (c == -1) {
break;
}
switch (c) {
- case 'c': {
- state.args.color = parse_color(optarg);
- state.args.mode = BACKGROUND_MODE_SOLID_COLOR;
+ case 'C':
+ // Config file. This will have already been handled so just ignore.
+ break;
+ case 'c':
+ state->args.colors.background = parse_color(optarg);
+ state->args.mode = BACKGROUND_MODE_SOLID_COLOR;
+ break;
+ case 'e':
+ state->args.ignore_empty = true;
+ break;
+ case 'f':
+ state->args.daemonize = true;
break;
- }
case 'i':
- load_image(optarg, &state);
+ load_image(optarg, state);
+ break;
+ case 'n':
+ *line_mode = LM_INSIDE;
+ break;
+ case 'r':
+ *line_mode = LM_RING;
break;
case 's':
- state.args.mode = parse_background_mode(optarg);
- if (state.args.mode == BACKGROUND_MODE_INVALID) {
+ state->args.mode = parse_background_mode(optarg);
+ if (state->args.mode == BACKGROUND_MODE_INVALID) {
return 1;
}
break;
case 't':
- state.args.mode = BACKGROUND_MODE_TILE;
+ state->args.mode = BACKGROUND_MODE_TILE;
+ break;
+ case 'u':
+ state->args.show_indicator = false;
break;
case 'v':
#if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE
@@ -451,11 +613,72 @@ int main(int argc, char **argv) {
fprintf(stdout, "version unknown\n");
#endif
return 0;
- case 'u':
- state.args.show_indicator = false;
+ case LO_BS_HL_COLOR:
+ state->args.colors.bs_highlight = parse_color(optarg);
break;
- case 'f':
- state.args.daemonize = true;
+ case LO_FONT:
+ free(state->args.font);
+ state->args.font = strdup(optarg);
+ break;
+ case LO_IND_RADIUS:
+ state->args.radius = strtol(optarg, NULL, 0);
+ break;
+ case LO_IND_THICKNESS:
+ state->args.thickness = strtol(optarg, NULL, 0);
+ break;
+ case LO_INSIDE_COLOR:
+ state->args.colors.inside.input = parse_color(optarg);
+ break;
+ case LO_INSIDE_CLEAR_COLOR:
+ state->args.colors.inside.cleared = parse_color(optarg);
+ break;
+ case LO_INSIDE_VER_COLOR:
+ state->args.colors.inside.verifying = parse_color(optarg);
+ break;
+ case LO_INSIDE_WRONG_COLOR:
+ state->args.colors.inside.wrong = parse_color(optarg);
+ break;
+ case LO_KEY_HL_COLOR:
+ state->args.colors.key_highlight = parse_color(optarg);
+ break;
+ case LO_LINE_COLOR:
+ state->args.colors.line.input = parse_color(optarg);
+ break;
+ case LO_LINE_CLEAR_COLOR:
+ state->args.colors.line.cleared = parse_color(optarg);
+ break;
+ case LO_LINE_VER_COLOR:
+ state->args.colors.line.verifying = parse_color(optarg);
+ break;
+ case LO_LINE_WRONG_COLOR:
+ state->args.colors.line.wrong = parse_color(optarg);
+ break;
+ case LO_RING_COLOR:
+ state->args.colors.ring.input = parse_color(optarg);
+ break;
+ case LO_RING_CLEAR_COLOR:
+ state->args.colors.ring.cleared = parse_color(optarg);
+ break;
+ case LO_RING_VER_COLOR:
+ state->args.colors.ring.verifying = parse_color(optarg);
+ break;
+ case LO_RING_WRONG_COLOR:
+ state->args.colors.ring.wrong = parse_color(optarg);
+ break;
+ case LO_SEP_COLOR:
+ state->args.colors.separator = parse_color(optarg);
+ break;
+ case LO_TEXT_COLOR:
+ state->args.colors.text.input = parse_color(optarg);
+ break;
+ case LO_TEXT_CLEAR_COLOR:
+ state->args.colors.text.cleared = parse_color(optarg);
+ break;
+ case LO_TEXT_VER_COLOR:
+ state->args.colors.text.verifying = parse_color(optarg);
+ break;
+ case LO_TEXT_WRONG_COLOR:
+ state->args.colors.text.wrong = parse_color(optarg);
break;
default:
fprintf(stderr, "%s", usage);
@@ -463,6 +686,149 @@ int main(int argc, char **argv) {
}
}
+ return 0;
+}
+
+static bool file_exists(const char *path) {
+ return path && access(path, R_OK) != -1;
+}
+
+static char *get_config_path(void) {
+ static const char *config_paths[] = {
+ "$HOME/.swaylock/config",
+ "$XDG_CONFIG_HOME/swaylock/config",
+ SYSCONFDIR "/swaylock/config",
+ };
+
+ if (!getenv("XDG_CONFIG_HOME")) {
+ char *home = getenv("HOME");
+ char *config_home = malloc(strlen(home) + strlen("/.config") + 1);
+ if (!config_home) {
+ wlr_log(WLR_ERROR, "Unable to allocate $HOME/.config");
+ } else {
+ strcpy(config_home, home);
+ strcat(config_home, "/.config");
+ setenv("XDG_CONFIG_HOME", config_home, 1);
+ wlr_log(WLR_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home);
+ free(config_home);
+ }
+ }
+
+ wordexp_t p;
+ char *path;
+ for (size_t i = 0; i < sizeof(config_paths) / sizeof(char *); ++i) {
+ if (wordexp(config_paths[i], &p, 0) == 0) {
+ path = strdup(p.we_wordv[0]);
+ wordfree(&p);
+ if (file_exists(path)) {
+ return path;
+ }
+ free(path);
+ }
+ }
+
+ return NULL;
+}
+
+static int load_config(char *path, struct swaylock_state *state,
+ enum line_mode *line_mode) {
+ FILE *config = fopen(path, "r");
+ if (!config) {
+ wlr_log(WLR_ERROR, "Failed to read config. Running without it.");
+ return 0;
+ }
+ char *line;
+ int line_number = 0;
+ while (!feof(config)) {
+ line = read_line(config);
+ if (!line) {
+ continue;
+ }
+
+ line_number++;
+ if (line[0] == '#') {
+ free(line);
+ continue;
+ }
+ if (strlen(line) == 0) {
+ free(line);
+ continue;
+ }
+
+ wlr_log(WLR_DEBUG, "Config Line #%d: %s", line_number, line);
+ char flag[strlen(line) + 3];
+ sprintf(flag, "--%s", line);
+ char *argv[] = {"swaylock", flag};
+ int result = parse_options(2, argv, state, line_mode);
+ if (result != 0) {
+ free(line);
+ fclose(config);
+ return result;
+ }
+ free(line);
+ }
+ fclose(config);
+ return 0;
+}
+
+static struct swaylock_state state;
+
+int main(int argc, char **argv) {
+ enum line_mode line_mode = LM_LINE;
+ state.args = (struct swaylock_args){
+ .mode = BACKGROUND_MODE_SOLID_COLOR,
+ .font = strdup("sans-serif"),
+ .radius = 50,
+ .thickness = 10,
+ .ignore_empty = false,
+ .show_indicator = true,
+ };
+ wl_list_init(&state.images);
+ set_default_colors(&state.args.colors);
+
+ wlr_log_init(WLR_DEBUG, NULL);
+
+ char *config_path = NULL;
+ static struct option long_options[] = {
+ {"config", required_argument, NULL, 'C'},
+ {0, 0, 0, 0},
+ };
+ while (1) {
+ int c = getopt_long(argc, argv, "C:", long_options, NULL);
+ if (c == -1) {
+ break;
+ } else if (c == 'C') {
+ config_path = strdup(optarg);
+ break;
+ }
+ }
+ if (!config_path) {
+ config_path = get_config_path();
+ }
+
+ if (config_path) {
+ wlr_log(WLR_DEBUG, "Found config at %s", config_path);
+ int config_status = load_config(config_path, &state, &line_mode);
+ free(config_path);
+ if (config_status != 0) {
+ return config_status;
+ }
+ }
+
+ if (argc > 1) {
+ wlr_log(WLR_DEBUG, "Parsing CLI Args");
+ int result = parse_options(argc, argv, &state, &line_mode);
+ if (result != 0) {
+ return result;
+ }
+ }
+
+ if (line_mode == LM_INSIDE) {
+ state.args.colors.line = state.args.colors.inside;
+ } else if (line_mode == LM_RING) {
+ state.args.colors.line = state.args.colors.ring;
+ }
+
#ifdef __linux__
// Most non-linux platforms require root to mlock()
if (mlock(state.password.buffer, sizeof(state.password.buffer)) != 0) {
@@ -480,13 +846,13 @@ int main(int argc, char **argv) {
wl_display_roundtrip(state.display);
assert(state.compositor && state.layer_shell && state.shm);
if (!state.input_inhibit_manager) {
- wlr_log(L_ERROR, "Compositor does not support the input inhibitor "
+ wlr_log(WLR_ERROR, "Compositor does not support the input inhibitor "
"protocol, refusing to run insecurely");
return 1;
}
if (wl_list_empty(&state.surfaces)) {
- wlr_log(L_DEBUG, "Exiting - no outputs to show on.");
+ wlr_log(WLR_DEBUG, "Exiting - no outputs to show on.");
return 0;
}
@@ -502,7 +868,7 @@ int main(int argc, char **argv) {
}
wl_display_roundtrip(state.display);
} else {
- wlr_log(L_INFO, "Compositor does not support zxdg output manager, "
+ wlr_log(WLR_INFO, "Compositor does not support zxdg output manager, "
"images assigned to named outputs will not work");
}
@@ -520,5 +886,7 @@ int main(int argc, char **argv) {
while (wl_display_dispatch(state.display) != -1 && state.run_display) {
// This space intentionally left blank
}
+
+ free(state.args.font);
return 0;
}
diff --git a/swaylock/password.c b/swaylock/password.c
index d844ec98..7c686b34 100644
--- a/swaylock/password.c
+++ b/swaylock/password.c
@@ -53,15 +53,15 @@ static bool attempt_password(struct swaylock_password *pw) {
// 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(L_ERROR, "PAM returned error %d", pam_err);
+ wlr_log(WLR_ERROR, "PAM returned error %d", pam_err);
}
if ((pam_err = pam_authenticate(local_auth_handle, 0)) != PAM_SUCCESS) {
- wlr_log(L_ERROR, "pam_authenticate failed");
+ 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(L_ERROR, "pam_end failed");
+ wlr_log(WLR_ERROR, "pam_end failed");
goto fail;
}
clear_password_buffer(pw);
@@ -95,6 +95,10 @@ void swaylock_handle_key(struct swaylock_state *state,
switch (keysym) {
case XKB_KEY_KP_Enter: /* fallthrough */
case XKB_KEY_Return:
+ if (state->args.ignore_empty && state->password.len == 0) {
+ break;
+ }
+
state->auth_state = AUTH_STATE_VALIDATING;
damage_state(state);
while (wl_display_dispatch(state->display) != -1 && state->run_display) {
diff --git a/swaylock/render.c b/swaylock/render.c
index ea23d0d8..66c55965 100644
--- a/swaylock/render.c
+++ b/swaylock/render.c
@@ -7,11 +7,22 @@
#include "swaylock/swaylock.h"
#define M_PI 3.14159265358979323846
-const int ARC_RADIUS = 50;
-const int ARC_THICKNESS = 10;
const float TYPE_INDICATOR_RANGE = M_PI / 3.0f;
const float TYPE_INDICATOR_BORDER_THICKNESS = M_PI / 128.0f;
+static void set_color_for_state(cairo_t *cairo, struct swaylock_state *state,
+ struct swaylock_colorset *colorset) {
+ if (state->auth_state == AUTH_STATE_VALIDATING) {
+ cairo_set_source_u32(cairo, colorset->verifying);
+ } else if (state->auth_state == AUTH_STATE_INVALID) {
+ cairo_set_source_u32(cairo, colorset->wrong);
+ } else if (state->auth_state == AUTH_STATE_CLEAR) {
+ cairo_set_source_u32(cairo, colorset->cleared);
+ } else {
+ cairo_set_source_u32(cairo, colorset->input);
+ }
+}
+
void render_frame(struct swaylock_surface *surface) {
struct swaylock_state *state = surface->state;
@@ -33,7 +44,7 @@ void render_frame(struct swaylock_surface *surface) {
cairo_save(cairo);
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR || !surface->image) {
- cairo_set_source_u32(cairo, state->args.color);
+ cairo_set_source_u32(cairo, state->args.colors.background);
cairo_paint(cairo);
} else {
render_background_image(cairo, surface->image,
@@ -42,49 +53,25 @@ void render_frame(struct swaylock_surface *surface) {
cairo_restore(cairo);
cairo_identity_matrix(cairo);
- int arc_radius = ARC_RADIUS * surface->scale;
- int arc_thickness = ARC_THICKNESS * surface->scale;
+ int arc_radius = state->args.radius * surface->scale;
+ int arc_thickness = state->args.thickness * surface->scale;
float type_indicator_border_thickness =
TYPE_INDICATOR_BORDER_THICKNESS * surface->scale;
if (state->args.show_indicator && state->auth_state != AUTH_STATE_IDLE) {
// Draw circle
cairo_set_line_width(cairo, arc_thickness);
- cairo_arc(cairo, buffer_width / 2, buffer_height / 2, arc_radius, 0, 2 * M_PI);
- switch (state->auth_state) {
- case AUTH_STATE_INPUT:
- case AUTH_STATE_INPUT_NOP:
- case AUTH_STATE_BACKSPACE: {
- cairo_set_source_rgba(cairo, 0, 0, 0, 0.75);
- cairo_fill_preserve(cairo);
- cairo_set_source_rgb(cairo, 51.0 / 255, 125.0 / 255, 0);
- cairo_stroke(cairo);
- } break;
- case AUTH_STATE_VALIDATING: {
- cairo_set_source_rgba(cairo, 0, 114.0 / 255, 255.0 / 255, 0.75);
- cairo_fill_preserve(cairo);
- cairo_set_source_rgb(cairo, 51.0 / 255, 0, 250.0 / 255);
- cairo_stroke(cairo);
- } break;
- case AUTH_STATE_INVALID: {
- cairo_set_source_rgba(cairo, 250.0 / 255, 0, 0, 0.75);
- cairo_fill_preserve(cairo);
- cairo_set_source_rgb(cairo, 125.0 / 255, 51.0 / 255, 0);
- cairo_stroke(cairo);
- } break;
- case AUTH_STATE_CLEAR: {
- cairo_set_source_rgba(cairo, 229.0/255, 164.0/255, 69.0/255, 0.75);
- cairo_fill_preserve(cairo);
- cairo_set_source_rgb(cairo, 229.0/255, 164.0/255, 69.0/255);
- cairo_stroke(cairo);
- } break;
- default: break;
- }
+ cairo_arc(cairo, buffer_width / 2, buffer_height / 2, arc_radius,
+ 0, 2 * M_PI);
+ set_color_for_state(cairo, state, &state->args.colors.inside);
+ cairo_fill_preserve(cairo);
+ set_color_for_state(cairo, state, &state->args.colors.ring);
+ cairo_stroke(cairo);
// Draw a message
char *text = NULL;
- cairo_set_source_rgb(cairo, 0, 0, 0);
- cairo_select_font_face(cairo, "sans-serif",
+ set_color_for_state(cairo, state, &state->args.colors.text);
+ cairo_select_font_face(cairo, state->args.font,
CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cairo, arc_radius / 3.0f);
switch (state->auth_state) {
@@ -101,9 +88,10 @@ void render_frame(struct swaylock_surface *surface) {
case AUTH_STATE_INPUT_NOP:
if (state->xkb.caps_lock) {
text = "Caps Lock";
- cairo_set_source_rgb(cairo, 229.0/255, 164.0/255, 69.0/255);
}
- default: break;
+ break;
+ default:
+ break;
}
if (text) {
@@ -131,14 +119,14 @@ void render_frame(struct swaylock_surface *surface) {
arc_radius, highlight_start,
highlight_start + TYPE_INDICATOR_RANGE);
if (state->auth_state == AUTH_STATE_INPUT) {
- cairo_set_source_rgb(cairo, 51.0 / 255, 219.0 / 255, 0);
+ cairo_set_source_u32(cairo, state->args.colors.key_highlight);
} else {
- cairo_set_source_rgb(cairo, 219.0 / 255, 51.0 / 255, 0);
+ cairo_set_source_u32(cairo, state->args.colors.bs_highlight);
}
cairo_stroke(cairo);
// Draw borders
- cairo_set_source_rgb(cairo, 0, 0, 0);
+ cairo_set_source_u32(cairo, state->args.colors.separator);
cairo_arc(cairo, buffer_width / 2, buffer_height / 2,
arc_radius, highlight_start,
highlight_start + type_indicator_border_thickness);
@@ -152,7 +140,7 @@ void render_frame(struct swaylock_surface *surface) {
}
// Draw inner + outer border of the circle
- cairo_set_source_rgb(cairo, 0, 0, 0);
+ set_color_for_state(cairo, state, &state->args.colors.line);
cairo_set_line_width(cairo, 2.0 * surface->scale);
cairo_arc(cairo, buffer_width / 2, buffer_height / 2,
arc_radius - arc_thickness / 2, 0, 2 * M_PI);
diff --git a/swaylock/seat.c b/swaylock/seat.c
index 6c66d220..c2630d87 100644
--- a/swaylock/seat.c
+++ b/swaylock/seat.c
@@ -12,13 +12,13 @@ static void keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
struct swaylock_state *state = data;
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
close(fd);
- wlr_log(L_ERROR, "Unknown keymap format %d, aborting", format);
+ wlr_log(WLR_ERROR, "Unknown keymap format %d, aborting", format);
exit(1);
}
char *map_shm = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
if (map_shm == MAP_FAILED) {
close(fd);
- wlr_log(L_ERROR, "Unable to initialize keymap shm, aborting");
+ wlr_log(WLR_ERROR, "Unable to initialize keymap shm, aborting");
exit(1);
}
struct xkb_keymap *keymap = xkb_keymap_new_from_string(
diff --git a/swaylock/swaylock.1.scd b/swaylock/swaylock.1.scd
index 1b3366f0..3107124f 100644
--- a/swaylock/swaylock.1.scd
+++ b/swaylock/swaylock.1.scd
@@ -12,23 +12,34 @@ Locks your Wayland session.
# OPTIONS
-*-h, --help*
- Show help message and quit.
+*-C, --config* <path>
+ The config file to use. By default, the following paths are checked:
+ _$HOME/.swaylock/config_, _$XDG\_CONFIG\_HOME/swaylock/config_, and
+ _SYSCONFDIR/swaylock/config_. All flags aside from this one are valid
+ options in the configuration file using the format _long-option=value_.
+ For options such as _ignore-empty-password_, just supply the _long-option_.
+ All leading dashes should be omitted and the equals sign is required for
+ flags that take an argument.
*-c, --color* <rrggbb[aa]>
Turn the screen into the given color. If -i is used, this sets the
background of the image to the given color. Defaults to white (FFFFFF), or
transparent (00000000) if an image is in use.
+*-e, --ignore-empty-password*
+ When an empty password is provided by the user, do not validate it.
+
*-f, --daemonize*
- Fork into the background after spawning. Note: this is the default behavior
- of i3lock.
+ Detach from the controlling terminal after locking.
+
+*-h, --help*
+ Show help message and quit.
*-i, --image* [<output>:]<path>
Display the given image, optionally only on the given output. Use -c to set
a background color.
-*--scaling*
+*-s, --scaling*
Scaling mode for images: _stretch_, _fill_, _fit_, _center_, or _tile_.
*-t, --tiling*
@@ -37,37 +48,57 @@ Locks your Wayland session.
*-u, --no-unlock-indicator*
Disable the unlock indicator.
-*-f, --daemonize*
- Detach from the controlling terminal after locking.
-
*-v, --version*
Show the version number and quit.
# APPEARANCE
-*--bshlcolor* <rrggbb[aa]>
+*--bs-hl-color* <rrggbb[aa]>
Sets the color of backspace highlight segments.
*--font* <font>
Sets the font of the text inside the indicator.
-*--insidecolor* <rrggbb[aa]>
+*--indicator-radius* <radius>
+ Sets the radius of the indicator to _radius_ pixels. The default value is
+ 50.
+
+*--indicator-thickness* <thickness>
+ Sets the thickness of the indicator to _thickness_ pixels. The default value
+ is 10.
+
+*--inside-color* <rrggbb[aa]>
Sets the color of the inside of the indicator when typing or idle.
-*--insidevercolor* <rrggbb[aa]>
+*--inside-clear-color* <rrggbb[aa]>
+ Sets the color of the inside of the indicator when cleared.
+
+*--inside-ver-color* <rrggbb[aa]>
Sets the color of the inside of the indicator when verifying.
-*--insidewrongcolor* <rrggbb[aa]>
+*--inside-wrong-color* <rrggbb[aa]>
Sets the color of the inside of the indicator when invalid.
-*--keyhlcolor* <rrggbb[aa]>
- Sets the color of keypress highlight segments.
+*--key-hl-color* <rrggbb[aa]>
+ Sets the color of key press highlight segments.
+
+*--line-color* <rrggbb[aa]>
+ Sets the color of the lines that separate the inside and outside of the
+ indicator when typing or idle.
+
+*--line-clear-color* <rrggbb[aa]>
+ Sets the color of the lines that separate the inside and outside of the
+ indicator when cleared.
+
+*--line-ver-color* <rrggbb[aa]>
+ Sets the color of the lines that separate the inside and outside of the
+ indicator when verifying.
-*--linecolor* <rrggbb[aa]>
+*--line-wrong-color* <rrggbb[aa]>
Sets the color of the lines that separate the inside and outside of the
- indicator.
+ indicator when invalid.
-*-s, --line-uses-inside*
+*-n, --line-uses-inside*
Use the color of the inside of the indicator for the line separating the
inside and outside of the indicator.
@@ -75,28 +106,32 @@ Locks your Wayland session.
Use the outer ring's color for the line separating the inside and outside of
the indicator.
-*--ringcolor* <rrggbb[aa]>
+*--ring-color* <rrggbb[aa]>
Sets the color of the outside of the indicator when typing or idle.
-*--ringvercolor* <rrggbb[aa]>
+*--ring-clear-color* <rrggbb[aa]>
+ Sets the color of the outside of the indicator when cleared.
+
+*--ring-ver-color* <rrggbb[aa]>
Sets the color of the outside of the indicator when verifying.
-*--ringwrongcolor* <rrggbb[aa]>
+*--ring-wrong-color* <rrggbb[aa]>
Sets the color of the outside of the indicator when invalid.
-*--separatorcolor* <rrggbb[aa]>
- Sets the color of the lines that seperate highlight segments.
+*--separator-color* <rrggbb[aa]>
+ Sets the color of the lines that separate highlight segments.
-*--textcolor* <rrggbb[aa]>
- Sets the color of the text inside the indicator.
+*--text-color* <rrggbb[aa]>
+ Sets the color of the text inside the indicator when typing or idle.
-*--indicator-radius* <radius>
- Sets the radius of the indicator to _radius_ pixels. The default value is
- 50.
+*--text-clear-color* <rrggbb[aa]>
+ Sets the color of the text inside the indicator when cleared.
-*--indicator-thickness* <thickness>
- Sets the thickness of the indicator to _thickness_ pixels. The default value
- is 10.
+*--text-ver-color* <rrggbb[aa]>
+ Sets the color of the text inside the indicator when verifying.
+
+*--text-wrong-color* <rrggbb[aa]>
+ Sets the color of the text inside the indicator when invalid.
# AUTHORS
diff --git a/swaymsg/main.c b/swaymsg/main.c
index 4283bf00..c4141ca5 100644
--- a/swaymsg/main.c
+++ b/swaymsg/main.c
@@ -240,44 +240,17 @@ static void pretty_print_version(json_object *v) {
printf("sway version %s\n", json_object_get_string(ver));
}
-static void pretty_print_clipboard(json_object *v) {
- if (success(v, true)) {
- if (json_object_is_type(v, json_type_array)) {
- for (size_t i = 0; i < json_object_array_length(v); ++i) {
- json_object *o = json_object_array_get_idx(v, i);
- printf("%s\n", json_object_get_string(o));
- }
- } else {
- // NOTE: could be extended to print all received types
- // instead just the first one when sways ipc server
- // supports it
- struct json_object_iterator iter = json_object_iter_begin(v);
- struct json_object_iterator end = json_object_iter_end(v);
- if (!json_object_iter_equal(&iter, &end)) {
- json_object *obj = json_object_iter_peek_value(&iter);
- if (success(obj, false)) {
- json_object *content;
- json_object_object_get_ex(obj, "content", &content);
- printf("%s\n", json_object_get_string(content));
- } else {
- json_object *error;
- json_object_object_get_ex(obj, "error", &error);
- printf("Error: %s\n", json_object_get_string(error));
- }
- }
- }
- } else {
- json_object *error;
- json_object_object_get_ex(v, "error", &error);
- printf("Error: %s\n", json_object_get_string(error));
- }
+static void pretty_print_config(json_object *c) {
+ json_object *config;
+ json_object_object_get_ex(c, "config", &config);
+ printf("%s\n", json_object_get_string(config));
}
static void pretty_print(int type, json_object *resp) {
if (type != IPC_COMMAND && type != IPC_GET_WORKSPACES &&
type != IPC_GET_INPUTS && type != IPC_GET_OUTPUTS &&
- type != IPC_GET_VERSION && type != IPC_GET_CLIPBOARD &&
- type != IPC_GET_SEATS) {
+ type != IPC_GET_VERSION && type != IPC_GET_SEATS &&
+ type != IPC_GET_CONFIG) {
printf("%s\n", json_object_to_json_string_ext(resp,
JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED));
return;
@@ -288,8 +261,8 @@ static void pretty_print(int type, json_object *resp) {
return;
}
- if (type == IPC_GET_CLIPBOARD) {
- pretty_print_clipboard(resp);
+ if (type == IPC_GET_CONFIG) {
+ pretty_print_config(resp);
return;
}
@@ -323,7 +296,7 @@ int main(int argc, char **argv) {
char *socket_path = NULL;
char *cmdtype = NULL;
- wlr_log_init(L_INFO, NULL);
+ wlr_log_init(WLR_INFO, NULL);
static struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
@@ -407,8 +380,10 @@ int main(int argc, char **argv) {
type = IPC_GET_BAR_CONFIG;
} else if (strcasecmp(cmdtype, "get_version") == 0) {
type = IPC_GET_VERSION;
- } else if (strcasecmp(cmdtype, "get_clipboard") == 0) {
- type = IPC_GET_CLIPBOARD;
+ } else if (strcasecmp(cmdtype, "get_binding_modes") == 0) {
+ type = IPC_GET_BINDING_MODES;
+ } else if (strcasecmp(cmdtype, "get_config") == 0) {
+ type = IPC_GET_CONFIG;
} else {
sway_abort("Unknown message type %s", cmdtype);
}
diff --git a/swaymsg/swaymsg.1.scd b/swaymsg/swaymsg.1.scd
index 1aa6a1b0..a6e279da 100644
--- a/swaymsg/swaymsg.1.scd
+++ b/swaymsg/swaymsg.1.scd
@@ -59,8 +59,8 @@ _swaymsg_ [options...] [message]
*get\_version*
Get JSON-encoded version information for the running instance of sway.
-*get\_clipboard*
- Get JSON-encoded information about the clipboard.
- Returns the current clipboard mime-types if called without
- arguments, otherwise returns the clipboard data in the requested
- formats. Encodes the data using base64 for non-text mime types.
+*get\_binding\_modes*
+ Gets a JSON-encoded list of currently configured binding modes.
+
+*get\_config*
+ Gets a JSON-encoded copy of the current configuration.