summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.ja.md2
-rw-r--r--common/background-image.c2
-rw-r--r--common/cairo.c16
-rw-r--r--common/pango.c58
-rw-r--r--contrib/awesome.config63
-rw-r--r--include/cairo.h2
-rw-r--r--include/pango.h14
-rw-r--r--include/sway/commands.h12
-rw-r--r--include/sway/config.h28
-rw-r--r--include/sway/debug.h2
-rw-r--r--include/sway/ipc-json.h2
-rw-r--r--include/sway/tree/container.h3
-rw-r--r--include/sway/tree/workspace.h9
-rw-r--r--include/swaybar/bar.h8
-rw-r--r--include/swaybar/config.h2
-rw-r--r--include/swaybar/i3bar.h34
-rw-r--r--include/swaybar/ipc.h2
-rw-r--r--include/swaybar/render.h4
-rw-r--r--include/swaybar/status_line.h26
-rw-r--r--include/swaybar/tray/dbus.h18
-rw-r--r--include/swaybar/tray/sni_watcher.h10
-rw-r--r--include/swaybar/tray/tray.h32
-rw-r--r--include/swaylock/swaylock.h4
-rw-r--r--meson.build25
-rw-r--r--meson_options.txt3
-rw-r--r--sway/commands.c45
-rw-r--r--sway/commands/bar/binding_mode_indicator.c6
-rw-r--r--sway/commands/bind.c2
-rw-r--r--sway/commands/gaps.c306
-rw-r--r--sway/commands/input.c11
-rw-r--r--sway/commands/input/accel_profile.c13
-rw-r--r--sway/commands/input/click_method.c15
-rw-r--r--sway/commands/input/drag.c26
-rw-r--r--sway/commands/input/drag_lock.c12
-rw-r--r--sway/commands/input/dwt.c12
-rw-r--r--sway/commands/input/events.c17
-rw-r--r--sway/commands/input/left_handed.c10
-rw-r--r--sway/commands/input/map_from_region.c42
-rw-r--r--sway/commands/input/map_to_output.c10
-rw-r--r--sway/commands/input/middle_emulation.c13
-rw-r--r--sway/commands/input/natural_scroll.c10
-rw-r--r--sway/commands/input/pointer_accel.c11
-rw-r--r--sway/commands/input/repeat_delay.c11
-rw-r--r--sway/commands/input/repeat_rate.c11
-rw-r--r--sway/commands/input/scroll_button.c13
-rw-r--r--sway/commands/input/scroll_method.c17
-rw-r--r--sway/commands/input/tap.c14
-rw-r--r--sway/commands/input/tap_button_map.c13
-rw-r--r--sway/commands/input/xkb_capslock.c13
-rw-r--r--sway/commands/input/xkb_layout.c17
-rw-r--r--sway/commands/input/xkb_model.c17
-rw-r--r--sway/commands/input/xkb_numlock.c13
-rw-r--r--sway/commands/input/xkb_options.c17
-rw-r--r--sway/commands/input/xkb_rules.c17
-rw-r--r--sway/commands/input/xkb_variant.c17
-rw-r--r--sway/commands/layout.c3
-rw-r--r--sway/commands/move.c64
-rw-r--r--sway/commands/output/background.c18
-rw-r--r--sway/commands/resize.c30
-rw-r--r--sway/commands/workspace.c74
-rw-r--r--sway/config.c11
-rw-r--r--sway/config/bar.c26
-rw-r--r--sway/config/input.c62
-rw-r--r--sway/config/output.c4
-rw-r--r--sway/config/seat.c2
-rw-r--r--sway/debug-tree.c2
-rw-r--r--sway/desktop/transaction.c66
-rw-r--r--sway/desktop/xdg_shell.c2
-rw-r--r--sway/desktop/xdg_shell_v6.c2
-rw-r--r--sway/desktop/xwayland.c2
-rw-r--r--sway/input/cursor.c62
-rw-r--r--sway/input/input-manager.c22
-rw-r--r--sway/input/seat.c44
-rw-r--r--sway/ipc-json.c2
-rw-r--r--sway/ipc-server.c15
-rw-r--r--sway/main.c84
-rw-r--r--sway/meson.build3
-rw-r--r--sway/sway-bar.5.scd3
-rw-r--r--sway/sway-input.5.scd7
-rw-r--r--sway/sway.5.scd82
-rw-r--r--sway/tree/arrange.c3
-rw-r--r--sway/tree/container.c38
-rw-r--r--sway/tree/output.c30
-rw-r--r--sway/tree/root.c21
-rw-r--r--sway/tree/view.c29
-rw-r--r--sway/tree/workspace.c81
-rw-r--r--swaybar/bar.c161
-rw-r--r--swaybar/config.c2
-rw-r--r--swaybar/i3bar.c19
-rw-r--r--swaybar/ipc.c19
-rw-r--r--swaybar/main.c5
-rw-r--r--swaybar/meson.build1
-rw-r--r--swaybar/render.c146
-rw-r--r--swaybar/status_line.c36
-rw-r--r--swaybg/main.c4
-rw-r--r--swaybg/meson.build1
-rw-r--r--swayidle/main.c4
-rw-r--r--swayidle/meson.build1
-rw-r--r--swaylock/main.c15
-rw-r--r--swaylock/meson.build51
-rw-r--r--swaylock/pam.c62
-rw-r--r--swaylock/password.c51
-rw-r--r--swaylock/render.c7
-rw-r--r--swaylock/shadow.c128
-rw-r--r--swaymsg/meson.build1
-rw-r--r--swaynag/config.c2
-rw-r--r--swaynag/meson.build1
107 files changed, 1477 insertions, 1266 deletions
diff --git a/README.ja.md b/README.ja.md
index 75d29c73..b0488c53 100644
--- a/README.ja.md
+++ b/README.ja.md
@@ -5,7 +5,7 @@ i3互換な[Wayland](http://wayland.freedesktop.org/)コンポジタです。
[FAQ](https://github.com/swaywm/sway/wiki)も合わせてご覧ください。
[IRC チャンネル](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on irc.freenode.net)もあります。
-**注意**: Swayは現在*凍結中*であり、Swayとwlrootsの統合が完了するまで、新たな機能は追加されません。バグフィックスは行われます。詳しくは[この記事](https://drewdevault.com/2017/10/09/Future-of-sway.html)をご覧ください。wlrootsとの統合状況については、[このチケット](https://github.com/swaywm/sway/issues/1390)をご覧ください。
+**注意**: Swayは現在*凍結中*であり、wlcからwlrootsへの移植が完了するまで新たな機能は追加されません。2018年9月以降に発見されるバグは0.15では対応されません。詳しくは[この記事](https://drewdevault.com/2017/10/09/Future-of-sway.html)をご覧ください。wlrootsとの統合状況については、[このチケット](https://github.com/swaywm/sway/issues/1390)をご覧ください。
[![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png)
diff --git a/common/background-image.c b/common/background-image.c
index f3d2551e..5ede55e3 100644
--- a/common/background-image.c
+++ b/common/background-image.c
@@ -58,6 +58,7 @@ void render_background_image(cairo_t *cairo, cairo_surface_t *image,
double width = cairo_image_surface_get_width(image);
double height = cairo_image_surface_get_height(image);
+ cairo_save(cairo);
switch (mode) {
case BACKGROUND_MODE_STRETCH:
cairo_scale(cairo,
@@ -116,4 +117,5 @@ void render_background_image(cairo_t *cairo, cairo_surface_t *image,
break;
}
cairo_paint(cairo);
+ cairo_restore(cairo);
}
diff --git a/common/cairo.c b/common/cairo.c
index c267c77c..e8231484 100644
--- a/common/cairo.c
+++ b/common/cairo.c
@@ -13,6 +13,22 @@ void cairo_set_source_u32(cairo_t *cairo, uint32_t color) {
(color >> (0*8) & 0xFF) / 255.0);
}
+cairo_subpixel_order_t to_cairo_subpixel_order(enum wl_output_subpixel subpixel) {
+ switch (subpixel) {
+ case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
+ return CAIRO_SUBPIXEL_ORDER_RGB;
+ case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
+ return CAIRO_SUBPIXEL_ORDER_BGR;
+ case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
+ return CAIRO_SUBPIXEL_ORDER_VRGB;
+ case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
+ return CAIRO_SUBPIXEL_ORDER_VBGR;
+ default:
+ return CAIRO_SUBPIXEL_ORDER_DEFAULT;
+ }
+ return CAIRO_SUBPIXEL_ORDER_DEFAULT;
+}
+
cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image,
int width, int height) {
int image_width = cairo_image_surface_get_width(image);
diff --git a/common/pango.c b/common/pango.c
index ea71ac4a..ba74692e 100644
--- a/common/pango.c
+++ b/common/pango.c
@@ -6,67 +6,47 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include "cairo.h"
#include "log.h"
+#include "stringop.h"
-int escape_markup_text(const char *src, char *dest, int dest_length) {
- int length = 0;
+size_t escape_markup_text(const char *src, char *dest) {
+ size_t length = 0;
+ if (dest) {
+ dest[0] = '\0';
+ }
while (src[0]) {
switch (src[0]) {
case '&':
length += 5;
- if (dest && dest_length - length >= 0) {
- dest += sprintf(dest, "%s", "&amp;");
- } else {
- dest_length = -1;
- }
+ lenient_strcat(dest, "&amp;");
break;
case '<':
length += 4;
- if (dest && dest_length - length >= 0) {
- dest += sprintf(dest, "%s", "&lt;");
- } else {
- dest_length = -1;
- }
+ lenient_strcat(dest, "&lt;");
break;
case '>':
length += 4;
- if (dest && dest_length - length >= 0) {
- dest += sprintf(dest, "%s", "&gt;");
- } else {
- dest_length = -1;
- }
+ lenient_strcat(dest, "&gt;");
break;
case '\'':
length += 6;
- if (dest && dest_length - length >= 0) {
- dest += sprintf(dest, "%s", "&apos;");
- } else {
- dest_length = -1;
- }
+ lenient_strcat(dest, "&apos;");
break;
case '"':
length += 6;
- if (dest && dest_length - length >= 0) {
- dest += sprintf(dest, "%s", "&quot;");
- } else {
- dest_length = -1;
- }
+ lenient_strcat(dest, "&quot;");
break;
default:
- length += 1;
- if (dest && dest_length - length >= 0) {
- *(dest++) = *src;
- } else {
- dest_length = -1;
+ if (dest) {
+ dest[length] = *src;
+ dest[length + 1] = '\0';
}
+ length += 1;
}
src++;
}
- // if we could not fit the escaped string in dest, return -1
- if (dest && dest_length == -1) {
- return -1;
- }
return length;
}
@@ -78,7 +58,7 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
char *buf;
GError *error = NULL;
if (pango_parse_markup(text, -1, 0, &attrs, &buf, NULL, &error)) {
- pango_layout_set_markup(layout, buf, -1);
+ pango_layout_set_text(layout, buf, -1);
free(buf);
} else {
wlr_log(WLR_ERROR, "pango_parse_markup '%s' -> error %s", text,
@@ -134,6 +114,10 @@ void pango_printf(cairo_t *cairo, const char *font,
va_end(args);
PangoLayout *layout = get_pango_layout(cairo, font, buf, scale, markup);
+ cairo_font_options_t *fo = cairo_font_options_create();
+ cairo_get_font_options(cairo, fo);
+ pango_cairo_context_set_font_options(pango_layout_get_context(layout), fo);
+ cairo_font_options_destroy(fo);
pango_cairo_update_layout(cairo, layout);
pango_cairo_show_layout(cairo, layout);
g_object_unref(layout);
diff --git a/contrib/awesome.config b/contrib/awesome.config
deleted file mode 100644
index 41e17c91..00000000
--- a/contrib/awesome.config
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# Replicate some of Awesome's default layout manipulation configuration for Sway
-#
-# Differences:
-# - Layout switching doesn't use the spacebar (i.e. i3/Sway behavior to switch to/from floating windows)
-# and uses the 'A' key instead (as in auto)
-# - Resizing windows uses i3/Sway's more versatile Mod4+r
-# - no tags
-# - no Maximize/Minize, alternatives to Maximize would be to switch to Stacked/Tabbed layouts
-# via Mod4+w or Mod4+s.
-# - kill focused client is available on Mod4+Shift+q (instead of Mod4+Shift+c, which maps to Sway's
-# config reload)
-# - probably many more ...
-
-# Awesome-style container traversal using Vim-like binding
-set $next j
-set $prev k
-
-#
-# Moving around:
-#
- # Move your focus around
- bindsym $mod+$next focus next
- bindsym $mod+$prev focus prev
-
- # _move_ the focused window with the same, but add Shift
- bindsym $mod+Shift+$next move next
- bindsym $mod+Shift+$prev move prev
-
-#
-# Layout:
-#
- workspace_layout auto left
-
- # This is usually bound to $mod+space, but this works well in practice by keeping
- # all the layout switching keys grouped together.
- bindsym $mod+a layout auto next
- bindsym $mod+Shift+a layout auto prev
-
- # Promote a child to master position in an auto layout
- bindsym $mod+Control+Return move first
-
- # Increase/decrease number of master elements in auto layout
- bindsym $mod+Shift+h layout auto master inc 1
- bindsym $mod+Shift+l layout auto master inc -1
-
- # Increase/decrease number of slave element groups in auto layout
- bindsym $mod+Control+h layout auto ncol inc 1
- bindsym $mod+Control+l layout auto ncol inc -1
-
-#
-# Resizing containers:
-# Again, not really the way Awesome works well, but in spirit with i3/Sway and it works well.
-#
-mode "resize" {
- bindsym Left resize shrink width 20 px
- bindsym Down resize grow height 20 px
- bindsym Up resize shrink height 20 px
- bindsym Right resize grow width 20 px
-}
-bindsym $mod+r mode "resize"
-
-new_window pixel 1
diff --git a/include/cairo.h b/include/cairo.h
index 31672705..86530b60 100644
--- a/include/cairo.h
+++ b/include/cairo.h
@@ -2,8 +2,10 @@
#define _SWAY_CAIRO_H
#include <stdint.h>
#include <cairo/cairo.h>
+#include <wlr/types/wlr_output.h>
void cairo_set_source_u32(cairo_t *cairo, uint32_t color);
+cairo_subpixel_order_t to_cairo_subpixel_order(enum wl_output_subpixel subpixel);
cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image,
int width, int height);
diff --git a/include/pango.h b/include/pango.h
index 09a535a5..6ab83c16 100644
--- a/include/pango.h
+++ b/include/pango.h
@@ -6,17 +6,13 @@
#include <cairo/cairo.h>
#include <pango/pangocairo.h>
-/* Utility function which escape characters a & < > ' ".
+/**
+ * Utility function which escape characters a & < > ' ".
*
- * If the dest parameter is NULL, then the function returns the length of
- * of the escaped src string. The dest_length doesn't matter.
- *
- * If the dest parameter is not NULL then the fuction escapes the src string
- * an puts the escaped string in dest and returns the lenght of the escaped string.
- * The dest_length parameter is the size of dest array. If the size of dest is not
- * enough, then the function returns -1.
+ * The function returns the length of the escaped string, optionally writing the
+ * escaped string to dest if provided.
*/
-int escape_markup_text(const char *src, char *dest, int dest_length);
+size_t escape_markup_text(const char *src, char *dest);
PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
const char *text, double scale, bool markup);
void get_text_size(cairo_t *cairo, const char *font, int *width, int *height,
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 226cf932..afa65340 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -4,6 +4,8 @@
#include <wlr/util/edges.h>
#include "config.h"
+struct sway_container;
+
typedef struct cmd_results *sway_cmd(int argc, char **argv);
struct cmd_handler {
@@ -50,8 +52,13 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers,
int handlers_size);
/**
* Parse and executes a command.
+ *
+ * If the command string contains criteria then the command will be executed on
+ * all matching containers. Otherwise, it'll run on the `con` container. If
+ * `con` is NULL then it'll run on the currently focused container.
*/
-struct cmd_results *execute_command(char *command, struct sway_seat *seat);
+struct cmd_results *execute_command(char *command, struct sway_seat *seat,
+ struct sway_container *con);
/**
* Parse and handles a command during config file loading.
*
@@ -88,7 +95,7 @@ struct cmd_results *add_color(const char *name,
/**
* TODO: Move this function and its dependent functions to container.c.
*/
-void container_resize_tiled(struct sway_container *parent, enum wlr_edges edge,
+bool container_resize_tiled(struct sway_container *parent, enum wlr_edges edge,
int amount);
sway_cmd cmd_assign;
@@ -210,6 +217,7 @@ sway_cmd bar_colors_cmd_urgent_workspace;
sway_cmd input_cmd_seat;
sway_cmd input_cmd_accel_profile;
sway_cmd input_cmd_click_method;
+sway_cmd input_cmd_drag;
sway_cmd input_cmd_drag_lock;
sway_cmd input_cmd_dwt;
sway_cmd input_cmd_events;
diff --git a/include/sway/config.h b/include/sway/config.h
index b53c1f1f..eab48aed 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -93,6 +93,7 @@ struct input_config {
int accel_profile;
int click_method;
+ int drag;
int drag_lock;
int dwt;
int left_handed;
@@ -167,13 +168,14 @@ struct output_config {
};
/**
- * Maps a workspace name to an output name.
- *
- * Set via `workspace <x> output <y>`
+ * Stores configuration for a workspace, regardless of whether the workspace
+ * exists.
*/
-struct workspace_output {
- char *output;
+struct workspace_config {
char *workspace;
+ char *output;
+ int gaps_inner;
+ int gaps_outer;
};
struct bar_config {
@@ -327,7 +329,7 @@ struct sway_config {
list_t *modes;
list_t *bars;
list_t *cmd_queue;
- list_t *workspace_outputs;
+ list_t *workspace_configs;
list_t *output_configs;
list_t *input_configs;
list_t *seat_configs;
@@ -450,20 +452,16 @@ void free_sway_variable(struct sway_variable *var);
*/
char *do_var_replacement(char *str);
-struct cmd_results *check_security_config();
-
int input_identifier_cmp(const void *item, const void *data);
struct input_config *new_input_config(const char* identifier);
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 *store_input_config(struct input_config *ic);
void free_input_config(struct input_config *ic);
-void apply_input_config(struct input_config *input);
-
int seat_name_cmp(const void *item, const void *data);
struct seat_config *new_seat_config(const char* name);
@@ -474,7 +472,7 @@ struct seat_config *copy_seat_config(struct seat_config *seat);
void free_seat_config(struct seat_config *ic);
-struct seat_attachment_config *seat_attachment_config_new();
+struct seat_attachment_config *seat_attachment_config_new(void);
struct seat_attachment_config *seat_config_get_attachment(
struct seat_config *seat_config, char *identifier);
@@ -512,9 +510,7 @@ void free_sway_binding(struct sway_binding *sb);
void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding);
-void load_swaybars();
-
-void invoke_swaybar(struct bar_config *bar);
+void load_swaybars(void);
void terminate_swaybg(pid_t pid);
@@ -522,6 +518,8 @@ struct bar_config *default_bar_config(void);
void free_bar_config(struct bar_config *bar);
+void free_workspace_config(struct workspace_config *wsc);
+
/**
* Updates the value of config->font_height based on the max title height
* reported by each container. If recalculate is true, the containers will
diff --git a/include/sway/debug.h b/include/sway/debug.h
index bf3a5f6d..0e9bb056 100644
--- a/include/sway/debug.h
+++ b/include/sway/debug.h
@@ -17,6 +17,6 @@ struct sway_debug {
extern struct sway_debug debug;
-void update_debug_tree();
+void update_debug_tree(void);
#endif
diff --git a/include/sway/ipc-json.h b/include/sway/ipc-json.h
index fef243e3..1cbfd15d 100644
--- a/include/sway/ipc-json.h
+++ b/include/sway/ipc-json.h
@@ -4,7 +4,7 @@
#include "sway/tree/container.h"
#include "sway/input/input-manager.h"
-json_object *ipc_json_get_version();
+json_object *ipc_json_get_version(void);
json_object *ipc_json_describe_disabled_output(struct sway_output *o);
json_object *ipc_json_describe_node(struct sway_node *node);
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 5e281a2f..b865a0f2 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -94,9 +94,6 @@ struct sway_container {
// The gaps currently applied to the container.
double current_gaps;
- bool has_gaps;
- double gaps_inner;
- double gaps_outer;
struct sway_workspace *workspace; // NULL when hidden in the scratchpad
struct sway_container *parent; // NULL if container in root of workspace
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h
index e4b616d1..efdae5a1 100644
--- a/include/sway/tree/workspace.h
+++ b/include/sway/tree/workspace.h
@@ -32,10 +32,9 @@ struct sway_workspace {
enum sway_container_layout layout;
enum sway_container_layout prev_split_layout;
- double current_gaps;
- bool has_gaps;
- double gaps_inner;
- double gaps_outer;
+ int current_gaps;
+ int gaps_inner;
+ int gaps_outer;
struct sway_output *output; // NULL if no outputs are connected
list_t *floating; // struct sway_container
@@ -48,6 +47,8 @@ struct sway_workspace {
extern char *prev_workspace_name;
+struct workspace_config *workspace_find_config(const char *ws_name);
+
struct sway_output *workspace_get_initial_output(const char *name);
struct sway_workspace *workspace_create(struct sway_output *output,
diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h
index 4065fb8b..de234111 100644
--- a/include/swaybar/bar.h
+++ b/include/swaybar/bar.h
@@ -54,7 +54,6 @@ struct swaybar {
struct wl_seat *seat;
struct swaybar_config *config;
- struct swaybar_output *focused_output;
struct swaybar_pointer pointer;
struct status_line *status;
@@ -81,8 +80,11 @@ struct swaybar_output {
uint32_t width, height;
int32_t scale;
+ enum wl_output_subpixel subpixel;
struct pool_buffer buffers[2];
struct pool_buffer *current_buffer;
+ bool dirty;
+ bool frame_scheduled;
};
struct swaybar_workspace {
@@ -94,9 +96,7 @@ struct swaybar_workspace {
bool urgent;
};
-void bar_setup(struct swaybar *bar,
- const char *socket_path,
- const char *bar_id);
+bool bar_setup(struct swaybar *bar, const char *socket_path, const char *bar_id);
void bar_run(struct swaybar *bar);
void bar_teardown(struct swaybar *bar);
diff --git a/include/swaybar/config.h b/include/swaybar/config.h
index 6739c28a..5f5688cf 100644
--- a/include/swaybar/config.h
+++ b/include/swaybar/config.h
@@ -50,7 +50,7 @@ struct swaybar_config {
} colors;
};
-struct swaybar_config *init_config();
+struct swaybar_config *init_config(void);
void free_config(struct swaybar_config *config);
uint32_t parse_position(const char *position);
diff --git a/include/swaybar/i3bar.h b/include/swaybar/i3bar.h
new file mode 100644
index 00000000..12d9b317
--- /dev/null
+++ b/include/swaybar/i3bar.h
@@ -0,0 +1,34 @@
+#ifndef _SWAYBAR_I3BAR_H
+#define _SWAYBAR_I3BAR_H
+
+#include "bar.h"
+#include "status_line.h"
+
+struct i3bar_block {
+ struct wl_list link;
+ int ref_count;
+ char *full_text, *short_text, *align;
+ bool urgent;
+ uint32_t *color;
+ int min_width;
+ char *name, *instance;
+ bool separator;
+ int separator_block_width;
+ bool markup;
+ // Airblader features
+ uint32_t background;
+ uint32_t border;
+ int border_top;
+ int border_bottom;
+ int border_left;
+ int border_right;
+};
+
+void i3bar_block_unref(struct i3bar_block *block);
+bool i3bar_handle_readable(struct status_line *status);
+enum hotspot_event_handling i3bar_block_send_click(struct status_line *status,
+ struct i3bar_block *block, int x, int y, enum x11_button button);
+enum x11_button wl_button_to_x11_button(uint32_t button);
+enum x11_button wl_axis_to_x11_button(uint32_t axis, wl_fixed_t value);
+
+#endif
diff --git a/include/swaybar/ipc.h b/include/swaybar/ipc.h
index a1696bcf..81e48a6b 100644
--- a/include/swaybar/ipc.h
+++ b/include/swaybar/ipc.h
@@ -3,7 +3,7 @@
#include <stdbool.h>
#include "swaybar/bar.h"
-void ipc_initialize(struct swaybar *bar, const char *bar_id);
+bool ipc_initialize(struct swaybar *bar, const char *bar_id);
bool handle_ipc_readable(struct swaybar *bar);
void ipc_get_workspaces(struct swaybar *bar);
void ipc_send_workspace_command(struct swaybar *bar, const char *ws);
diff --git a/include/swaybar/render.h b/include/swaybar/render.h
index 071e2298..ebdc69e4 100644
--- a/include/swaybar/render.h
+++ b/include/swaybar/render.h
@@ -1,10 +1,8 @@
#ifndef _SWAYBAR_RENDER_H
#define _SWAYBAR_RENDER_H
-struct swaybar;
struct swaybar_output;
-struct swaybar_config;
-void render_frame(struct swaybar *bar, struct swaybar_output *output);
+void render_frame(struct swaybar_output *output);
#endif
diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h
index d3eabdf6..e6c7dac2 100644
--- a/include/swaybar/status_line.h
+++ b/include/swaybar/status_line.h
@@ -13,26 +13,6 @@ enum status_protocol {
PROTOCOL_I3BAR,
};
-struct i3bar_block {
- struct wl_list link;
- int ref_count;
- char *full_text, *short_text, *align;
- bool urgent;
- uint32_t *color;
- int min_width;
- char *name, *instance;
- bool separator;
- int separator_block_width;
- bool markup;
- // Airblader features
- uint32_t background;
- uint32_t border;
- int border_top;
- int border_bottom;
- int border_left;
- int border_right;
-};
-
struct status_line {
pid_t pid;
int read_fd, write_fd;
@@ -55,11 +35,5 @@ struct status_line *status_line_init(char *cmd);
void status_error(struct status_line *status, const char *text);
bool status_handle_readable(struct status_line *status);
void status_line_free(struct status_line *status);
-bool i3bar_handle_readable(struct status_line *status);
-enum hotspot_event_handling i3bar_block_send_click(struct status_line *status,
- struct i3bar_block *block, int x, int y, enum x11_button button);
-void i3bar_block_unref(struct i3bar_block *block);
-enum x11_button wl_button_to_x11_button(uint32_t button);
-enum x11_button wl_axis_to_x11_button(uint32_t axis, wl_fixed_t value);
#endif
diff --git a/include/swaybar/tray/dbus.h b/include/swaybar/tray/dbus.h
deleted file mode 100644
index eb9cfea7..00000000
--- a/include/swaybar/tray/dbus.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef _SWAYBAR_DBUS_H
-#define _SWAYBAR_DBUS_H
-
-#include <stdbool.h>
-#include <dbus/dbus.h>
-extern DBusConnection *conn;
-
-/**
- * Should be called in main loop to dispatch events
- */
-void dispatch_dbus();
-
-/**
- * Initializes async dbus communication
- */
-int dbus_init();
-
-#endif /* _SWAYBAR_DBUS_H */
diff --git a/include/swaybar/tray/sni_watcher.h b/include/swaybar/tray/sni_watcher.h
deleted file mode 100644
index 25ddfcd2..00000000
--- a/include/swaybar/tray/sni_watcher.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _SWAYBAR_SNI_WATCHER_H
-#define _SWAYBAR_SNI_WATCHER_H
-
-/**
- * Starts the sni_watcher, the watcher is practically a black box and should
- * only be accessed though functions described in its spec
- */
-int init_sni_watcher();
-
-#endif /* _SWAYBAR_SNI_WATCHER_H */
diff --git a/include/swaybar/tray/tray.h b/include/swaybar/tray/tray.h
deleted file mode 100644
index 2d0662be..00000000
--- a/include/swaybar/tray/tray.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef _SWAYBAR_TRAY_H
-#define _SWAYBAR_TRAY_H
-
-#include <stdint.h>
-#include <stdbool.h>
-#include "swaybar/tray/dbus.h"
-#include "swaybar/tray/sni.h"
-#include "swaybar/bar.h"
-#include "list.h"
-
-extern struct tray *tray;
-
-struct tray {
- list_t *items;
-};
-
-/**
- * Processes a mouse event on the bar
- */
-void tray_mouse_event(struct output *output, int x, int y,
- uint32_t button, uint32_t state);
-
-uint32_t tray_render(struct output *output, struct config *config);
-
-void tray_upkeep(struct bar *bar);
-
-/**
- * Initializes the tray with D-Bus
- */
-void init_tray(struct bar *bar);
-
-#endif /* _SWAYBAR_TRAY_H */
diff --git a/include/swaylock/swaylock.h b/include/swaylock/swaylock.h
index 950cfaaf..970e3cc9 100644
--- a/include/swaylock/swaylock.h
+++ b/include/swaylock/swaylock.h
@@ -82,6 +82,7 @@ struct swaylock_surface {
bool frame_pending, dirty;
uint32_t width, height;
int32_t scale;
+ enum wl_output_subpixel subpixel;
char *output_name;
struct wl_list link;
};
@@ -100,5 +101,8 @@ void render_frame(struct swaylock_surface *surface);
void render_frames(struct swaylock_state *state);
void damage_surface(struct swaylock_surface *surface);
void damage_state(struct swaylock_state *state);
+void initialize_pw_backend(void);
+bool attempt_password(struct swaylock_password *pw);
+void clear_password_buffer(struct swaylock_password *pw);
#endif
diff --git a/meson.build b/meson.build
index 253a4e96..1e7ce281 100644
--- a/meson.build
+++ b/meson.build
@@ -22,6 +22,10 @@ datadir = get_option('datadir')
sysconfdir = get_option('sysconfdir')
prefix = get_option('prefix')
+if is_freebsd
+ add_project_arguments('-D_C11_SOURCE', language: 'c')
+endif
+
swayidle_deps = []
jsonc = dependency('json-c', version: '>=0.13')
@@ -38,9 +42,8 @@ pango = dependency('pango')
pangocairo = dependency('pangocairo')
gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: false)
pixman = dependency('pixman-1')
-libcap = dependency('libcap', required: false)
libinput = dependency('libinput', version: '>=1.6.0')
-libpam = cc.find_library('pam')
+libpam = cc.find_library('pam', required: false)
systemd = dependency('libsystemd', required: false)
elogind = dependency('libelogind', required: false)
math = cc.find_library('m')
@@ -70,6 +73,11 @@ if elogind.found()
swayidle_deps += elogind
endif
+if not systemd.found() and not elogind.found()
+ warning('The sway binary must be setuid when compiled without (e)logind')
+ warning('You must do this manually post-install: chmod a+s /path/to/sway')
+endif
+
scdoc = find_program('scdoc', required: false)
if scdoc.found()
@@ -120,7 +128,16 @@ else
endif
add_project_arguments('-DSWAY_VERSION=@0@'.format(version), language: 'c')
-add_project_arguments('-D_LD_LIBRARY_PATH="@0@"'.format(get_option('ld-library-path')), language: 'c')
+if get_option('use_rpath')
+ if get_option('custom_rpath') == ''
+ # default to platform specific libdir, one level up from the binary
+ rpathdir = join_paths('$ORIGIN', '..', '$LIB')
+ else
+ rpathdir = get_option('custom_rpath')
+ endif
+else
+ rpathdir = ''
+endif
sway_inc = include_directories('include')
@@ -133,9 +150,9 @@ subdir('swaymsg')
subdir('client')
subdir('swaybg')
subdir('swaybar')
-subdir('swaylock')
subdir('swayidle')
subdir('swaynag')
+subdir('swaylock')
config = configuration_data()
config.set('sysconfdir', join_paths(prefix, sysconfdir))
diff --git a/meson_options.txt b/meson_options.txt
index 50d646fd..2db852fc 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,5 +1,6 @@
option('sway-version', type : 'string', description: 'The version string reported in `sway --version`.')
-option('ld-library-path', type: 'string', value: '', description: 'The LD_LIBRARY_PATH environment variable.')
+option('use_rpath', type: 'boolean', value: false, description: 'install binaries with rpath set')
+option('custom_rpath', type: 'string', value: '', description: 'override rpath with a custom one')
option('default-wallpaper', type: 'boolean', value: true, description: 'Install the default wallpaper.')
option('zsh-completions', type: 'boolean', value: true, description: 'Install zsh shell completions.')
option('bash-completions', type: 'boolean', value: true, description: 'Install bash shell completions.')
diff --git a/sway/commands.c b/sway/commands.c
index 07169f1e..03761c52 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -55,22 +55,6 @@ struct cmd_results *checkarg(int argc, const char *name, enum expected_args type
return error;
}
-void apply_input_config(struct input_config *input) {
- int i;
- i = list_seq_find(config->input_configs, input_identifier_cmp, input->identifier);
- if (i >= 0) {
- // merge existing config
- struct input_config *ic = config->input_configs->items[i];
- merge_input_config(ic, input);
- free_input_config(input);
- input = ic;
- } else {
- list_add(config->input_configs, input);
- }
-
- input_manager_apply_input_config(input_manager, input);
-}
-
void apply_seat_config(struct seat_config *seat_config) {
int i;
i = list_seq_find(config->seat_configs, seat_name_cmp, seat_config->name);
@@ -237,7 +221,8 @@ static void set_config_node(struct sway_node *node) {
}
}
-struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
+struct cmd_results *execute_command(char *_exec, struct sway_seat *seat,
+ struct sway_container *con) {
// Even though this function will process multiple commands we will only
// return the last error, if any (for now). (Since we have access to an
// error string we could e.g. concatenate all errors there.)
@@ -256,6 +241,15 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
}
}
+ // This is the container or workspace which this command will run on.
+ // Ignored if the command string contains criteria.
+ struct sway_node *node;
+ if (con) {
+ node = &con->node;
+ } else {
+ node = seat_get_focus_inactive(seat, &root->node);
+ }
+
config->handler_context.seat = seat;
head = exec;
@@ -318,9 +312,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
}
if (!config->handler_context.using_criteria) {
- // without criteria, the command acts upon the focused
- // container
- set_config_node(seat_get_focus_inactive(seat, &root->node));
+ set_config_node(node);
struct cmd_results *res = handler->handle(argc-1, argv+1);
if (res->status != CMD_SUCCESS) {
free_argv(argc, argv);
@@ -399,14 +391,12 @@ struct cmd_results *config_command(char *exec) {
// Var replacement, for all but first argument of set
// TODO commands
for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
+ if (*argv[i] == '\"' || *argv[i] == '\'') {
+ strip_quotes(argv[i]);
+ }
argv[i] = do_var_replacement(argv[i]);
unescape_string(argv[i]);
}
- // Strip quotes for first argument.
- // TODO This part needs to be handled much better
- if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) {
- strip_quotes(argv[1]);
- }
if (handler->handle) {
results = handler->handle(argc-1, argv+1);
} else {
@@ -430,11 +420,6 @@ struct cmd_results *config_subcommand(char **argv, int argc,
char *input = argv[0] ? argv[0] : "(empty)";
return cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
}
- // Strip quotes for first argument.
- // TODO This part needs to be handled much better
- if (argc > 1 && (*argv[1] == '\"' || *argv[1] == '\'')) {
- strip_quotes(argv[1]);
- }
if (handler->handle) {
return handler->handle(argc - 1, argv + 1);
}
diff --git a/sway/commands/bar/binding_mode_indicator.c b/sway/commands/bar/binding_mode_indicator.c
index 0c48bee9..f18b8d7c 100644
--- a/sway/commands/bar/binding_mode_indicator.c
+++ b/sway/commands/bar/binding_mode_indicator.c
@@ -21,7 +21,9 @@ struct cmd_results *bar_cmd_binding_mode_indicator(int argc, char **argv) {
config->current_bar->binding_mode_indicator = false;
wlr_log(WLR_DEBUG, "Disabling binding mode indicator on bar: %s",
config->current_bar->id);
+ } else {
+ return cmd_results_new(CMD_INVALID, "binding_mode_indicator",
+ "Invalid value %s", argv[0]);
}
- return cmd_results_new(CMD_INVALID, "binding_mode_indicator",
- "Invalid value %s", argv[0]);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index 047018e0..820c2a6a 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -321,7 +321,7 @@ void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding)
}
config->handler_context.seat = seat;
- struct cmd_results *results = execute_command(binding->command, NULL);
+ struct cmd_results *results = execute_command(binding->command, NULL, NULL);
if (results->status == CMD_SUCCESS) {
ipc_event_binding(binding_copy);
} else {
diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c
index d676e475..2e0876a9 100644
--- a/sway/commands/gaps.c
+++ b/sway/commands/gaps.c
@@ -1,4 +1,5 @@
#include <string.h>
+#include <strings.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/tree/arrange.h"
@@ -13,172 +14,173 @@ enum gaps_op {
GAPS_OP_SUBTRACT
};
-enum gaps_scope {
- GAPS_SCOPE_ALL,
- GAPS_SCOPE_WORKSPACE,
- GAPS_SCOPE_CURRENT
+struct gaps_data {
+ bool inner;
+ enum gaps_op operation;
+ int amount;
};
-struct cmd_results *cmd_gaps(int argc, char **argv) {
- struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1);
- if (error) {
+// gaps edge_gaps on|off|toggle
+static struct cmd_results *gaps_edge_gaps(int argc, char **argv) {
+ struct cmd_results *error;
+ if ((error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2))) {
return error;
}
- if (strcmp(argv[0], "edge_gaps") == 0) {
- if ((error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2))) {
- return error;
- }
-
- if (strcmp(argv[1], "on") == 0) {
- config->edge_gaps = true;
- } else if (strcmp(argv[1], "off") == 0) {
- config->edge_gaps = false;
- } else if (strcmp(argv[1], "toggle") == 0) {
- if (!config->active) {
- return cmd_results_new(CMD_INVALID, "gaps",
- "Cannot toggle gaps while not running.");
- }
- config->edge_gaps = !config->edge_gaps;
- } else {
+ if (strcmp(argv[1], "on") == 0) {
+ config->edge_gaps = true;
+ } else if (strcmp(argv[1], "off") == 0) {
+ config->edge_gaps = false;
+ } else if (strcmp(argv[1], "toggle") == 0) {
+ if (!config->active) {
return cmd_results_new(CMD_INVALID, "gaps",
- "gaps edge_gaps on|off|toggle");
+ "Cannot toggle gaps while not running.");
}
- arrange_root();
+ config->edge_gaps = !config->edge_gaps;
} else {
- int amount_idx = 0; // the current index in argv
- enum gaps_op op = GAPS_OP_SET;
- enum gaps_scope scope = GAPS_SCOPE_ALL;
- bool inner = true;
-
- if (strcmp(argv[0], "inner") == 0) {
- amount_idx++;
- inner = true;
- } else if (strcmp(argv[0], "outer") == 0) {
- amount_idx++;
- inner = false;
- }
+ return cmd_results_new(CMD_INVALID, "gaps",
+ "gaps edge_gaps on|off|toggle");
+ }
+ arrange_root();
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
- // If one of the long variants of the gaps command is used
- // (which starts with inner|outer) check the number of args
- if (amount_idx > 0) { // if we've seen inner|outer
- if (argc > 2) { // check the longest variant
- error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4);
- if (error) {
- return error;
- }
- } else { // check the next longest format
- error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 2);
- if (error) {
- return error;
- }
- }
- } else {
- error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 1);
- if (error) {
- return error;
- }
- }
+// gaps inner|outer <px>
+static struct cmd_results *gaps_set_defaults(int argc, char **argv) {
+ struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 2);
+ if (error) {
+ return error;
+ }
- if (argc == 4) {
- // Long format: all|workspace|current.
- if (strcmp(argv[amount_idx], "all") == 0) {
- amount_idx++;
- scope = GAPS_SCOPE_ALL;
- } else if (strcmp(argv[amount_idx], "workspace") == 0) {
- amount_idx++;
- scope = GAPS_SCOPE_WORKSPACE;
- } else if (strcmp(argv[amount_idx], "current") == 0) {
- amount_idx++;
- scope = GAPS_SCOPE_CURRENT;
- }
-
- // Long format: set|plus|minus
- if (strcmp(argv[amount_idx], "set") == 0) {
- amount_idx++;
- op = GAPS_OP_SET;
- } else if (strcmp(argv[amount_idx], "plus") == 0) {
- amount_idx++;
- op = GAPS_OP_ADD;
- } else if (strcmp(argv[amount_idx], "minus") == 0) {
- amount_idx++;
- op = GAPS_OP_SUBTRACT;
- }
- }
+ bool inner;
+ if (strcasecmp(argv[0], "inner") == 0) {
+ inner = true;
+ } else if (strcasecmp(argv[0], "outer") == 0) {
+ inner = false;
+ } else {
+ return cmd_results_new(CMD_INVALID, "gaps",
+ "Expected 'gaps inner|outer <px>'");
+ }
- char *end;
- double val = strtod(argv[amount_idx], &end);
-
- if (strlen(end) && val == 0.0) { // invalid <amount>
- // guess which variant of the command was attempted
- if (argc == 1) {
- return cmd_results_new(CMD_INVALID, "gaps", "gaps <amount>");
- }
- if (argc == 2) {
- return cmd_results_new(CMD_INVALID, "gaps",
- "gaps inner|outer <amount>");
- }
- return cmd_results_new(CMD_INVALID, "gaps",
- "gaps inner|outer all|workspace|current set|plus|minus <amount>");
- }
+ char *end;
+ int amount = strtol(argv[1], &end, 10);
+ if (strlen(end) && strcasecmp(end, "px") != 0) {
+ return cmd_results_new(CMD_INVALID, "gaps",
+ "Expected 'gaps inner|outer <px>'");
+ }
+ if (amount < 0) {
+ amount = 0;
+ }
- if (amount_idx == 0) { // gaps <amount>
- config->gaps_inner = val;
- config->gaps_outer = val;
- arrange_root();
- return cmd_results_new(CMD_SUCCESS, NULL, NULL);
- }
- // Other variants. The middle-length variant (gaps inner|outer <amount>)
- // just defaults the scope to "all" and defaults the op to "set".
-
- double total;
- switch (op) {
- case GAPS_OP_SUBTRACT: {
- total = (inner ? config->gaps_inner : config->gaps_outer) - val;
- if (total < 0) {
- total = 0;
- }
- break;
- }
- case GAPS_OP_ADD: {
- total = (inner ? config->gaps_inner : config->gaps_outer) + val;
- break;
- }
- case GAPS_OP_SET: {
- total = val;
- break;
- }
- }
+ if (inner) {
+ config->gaps_inner = amount;
+ } else {
+ config->gaps_outer = amount;
+ }
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
- if (scope == GAPS_SCOPE_ALL) {
- if (inner) {
- config->gaps_inner = total;
- } else {
- config->gaps_outer = total;
- }
- arrange_root();
- } else {
- if (scope == GAPS_SCOPE_WORKSPACE) {
- struct sway_workspace *ws = config->handler_context.workspace;
- ws->has_gaps = true;
- if (inner) {
- ws->gaps_inner = total;
- } else {
- ws->gaps_outer = total;
- }
- arrange_workspace(ws);
- } else {
- struct sway_container *c = config->handler_context.container;
- c->has_gaps = true;
- if (inner) {
- c->gaps_inner = total;
- } else {
- c->gaps_outer = total;
- }
- arrange_workspace(c->workspace);
- }
- }
+static void configure_gaps(struct sway_workspace *ws, void *_data) {
+ struct gaps_data *data = _data;
+ int *prop = data->inner ? &ws->gaps_inner : &ws->gaps_outer;
+
+ switch (data->operation) {
+ case GAPS_OP_SET:
+ *prop = data->amount;
+ break;
+ case GAPS_OP_ADD:
+ *prop += data->amount;
+ break;
+ case GAPS_OP_SUBTRACT:
+ *prop -= data->amount;
+ break;
+ }
+ if (*prop < 0) {
+ *prop = 0;
+ }
+ arrange_workspace(ws);
+}
+
+// gaps inner|outer current|all set|plus|minus <px>
+static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
+ struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4);
+ if (error) {
+ return error;
+ }
+
+ struct gaps_data data;
+
+ if (strcasecmp(argv[0], "inner") == 0) {
+ data.inner = true;
+ } else if (strcasecmp(argv[0], "outer") == 0) {
+ data.inner = false;
+ } else {
+ return cmd_results_new(CMD_INVALID, "gaps",
+ "Expected 'gaps inner|outer current|all set|plus|minus <px>'");
+ }
+
+ bool all;
+ if (strcasecmp(argv[1], "current") == 0) {
+ all = false;
+ } else if (strcasecmp(argv[1], "all") == 0) {
+ all = true;
+ } else {
+ return cmd_results_new(CMD_INVALID, "gaps",
+ "Expected 'gaps inner|outer current|all set|plus|minus <px>'");
+ }
+
+ if (strcasecmp(argv[2], "set") == 0) {
+ data.operation = GAPS_OP_SET;
+ } else if (strcasecmp(argv[2], "plus") == 0) {
+ data.operation = GAPS_OP_ADD;
+ } else if (strcasecmp(argv[2], "minus") == 0) {
+ data.operation = GAPS_OP_SUBTRACT;
+ } else {
+ return cmd_results_new(CMD_INVALID, "gaps",
+ "Expected 'gaps inner|outer current|all set|plus|minus <px>'");
+ }
+
+ char *end;
+ data.amount = strtol(argv[3], &end, 10);
+ if (strlen(end) && strcasecmp(end, "px") != 0) {
+ return cmd_results_new(CMD_INVALID, "gaps",
+ "Expected 'gaps inner|outer current|all set|plus|minus <px>'");
+ }
+
+ if (all) {
+ root_for_each_workspace(configure_gaps, &data);
+ } else {
+ configure_gaps(config->handler_context.workspace, &data);
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
+
+// gaps edge_gaps on|off|toggle
+// gaps inner|outer <px> - sets defaults for workspaces
+// gaps inner|outer current|all set|plus|minus <px> - runtime only
+struct cmd_results *cmd_gaps(int argc, char **argv) {
+ struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2);
+ if (error) {
+ return error;
+ }
+
+ if (strcmp(argv[0], "edge_gaps") == 0) {
+ return gaps_edge_gaps(argc, argv);
+ }
+
+ if (argc == 2) {
+ return gaps_set_defaults(argc, argv);
+ }
+ if (argc == 4) {
+ if (config->active) {
+ return gaps_set_runtime(argc, argv);
+ } else {
+ return cmd_results_new(CMD_INVALID, "gaps",
+ "This syntax can only be used when sway is running");
+ }
+ }
+ return cmd_results_new(CMD_INVALID, "gaps",
+ "Expected 'gaps inner|outer <px>' or "
+ "'gaps inner|outer current|all set|plus|minus <px>'");
+}
diff --git a/sway/commands/input.c b/sway/commands/input.c
index 84888fbb..2889d47d 100644
--- a/sway/commands/input.c
+++ b/sway/commands/input.c
@@ -9,6 +9,7 @@
static struct cmd_handler input_handlers[] = {
{ "accel_profile", input_cmd_accel_profile },
{ "click_method", input_cmd_click_method },
+ { "drag", input_cmd_drag },
{ "drag_lock", input_cmd_drag_lock },
{ "dwt", input_cmd_dwt },
{ "events", input_cmd_events },
@@ -66,7 +67,15 @@ struct cmd_results *cmd_input(int argc, char **argv) {
input_handlers, sizeof(input_handlers));
}
- free_input_config(config->handler_context.input_config);
+ if (!res || res->status == CMD_SUCCESS) {
+ struct input_config *ic =
+ store_input_config(config->handler_context.input_config);
+
+ input_manager_apply_input_config(input_manager, ic);
+ } else {
+ free_input_config(config->handler_context.input_config);
+ }
+
config->handler_context.input_config = NULL;
return res;
diff --git a/sway/commands/input/accel_profile.c b/sway/commands/input/accel_profile.c
index a4108ec3..f7016790 100644
--- a/sway/commands/input/accel_profile.c
+++ b/sway/commands/input/accel_profile.c
@@ -9,25 +9,20 @@ struct cmd_results *input_cmd_accel_profile(int argc, char **argv) {
if ((error = checkarg(argc, "accel_profile", EXPECTED_AT_LEAST, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE, "accel_profile",
"No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
if (strcasecmp(argv[0], "adaptive") == 0) {
- new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
+ ic->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
} else if (strcasecmp(argv[0], "flat") == 0) {
- new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT;
+ ic->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT;
} else {
- free_input_config(new_config);
return cmd_results_new(CMD_INVALID, "accel_profile",
"Expected 'accel_profile <adaptive|flat>'");
}
- apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/click_method.c b/sway/commands/input/click_method.c
index 5d0d8cc2..4d7e1c93 100644
--- a/sway/commands/input/click_method.c
+++ b/sway/commands/input/click_method.c
@@ -10,27 +10,22 @@ struct cmd_results *input_cmd_click_method(int argc, char **argv) {
if ((error = checkarg(argc, "click_method", EXPECTED_AT_LEAST, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE, "click_method",
"No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
if (strcasecmp(argv[0], "none") == 0) {
- new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE;
+ ic->click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE;
} else if (strcasecmp(argv[0], "button_areas") == 0) {
- new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
+ ic->click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
} else if (strcasecmp(argv[0], "clickfinger") == 0) {
- new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
+ ic->click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
} else {
- free_input_config(new_config);
return cmd_results_new(CMD_INVALID, "click_method",
"Expected 'click_method <none|button_areas|clickfinger'");
}
- apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/drag.c b/sway/commands/input/drag.c
new file mode 100644
index 00000000..e325df29
--- /dev/null
+++ b/sway/commands/input/drag.c
@@ -0,0 +1,26 @@
+#include <string.h>
+#include <strings.h>
+#include "sway/config.h"
+#include "sway/commands.h"
+#include "sway/input/input-manager.h"
+#include "util.h"
+
+struct cmd_results *input_cmd_drag(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "drag", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
+ return cmd_results_new(CMD_FAILURE,
+ "drag", "No input device defined.");
+ }
+
+ if (parse_boolean(argv[0], true)) {
+ ic->drag = LIBINPUT_CONFIG_DRAG_ENABLED;
+ } else {
+ ic->drag = LIBINPUT_CONFIG_DRAG_DISABLED;
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/input/drag_lock.c b/sway/commands/input/drag_lock.c
index f9ddeef2..db5d5afa 100644
--- a/sway/commands/input/drag_lock.c
+++ b/sway/commands/input/drag_lock.c
@@ -10,21 +10,17 @@ struct cmd_results *input_cmd_drag_lock(int argc, char **argv) {
if ((error = checkarg(argc, "drag_lock", EXPECTED_AT_LEAST, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE,
"drag_lock", "No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
if (parse_boolean(argv[0], true)) {
- new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED;
+ ic->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED;
} else {
- new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED;
+ ic->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED;
}
- apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/dwt.c b/sway/commands/input/dwt.c
index 15134268..0c3881dd 100644
--- a/sway/commands/input/dwt.c
+++ b/sway/commands/input/dwt.c
@@ -10,20 +10,16 @@ struct cmd_results *input_cmd_dwt(int argc, char **argv) {
if ((error = checkarg(argc, "dwt", EXPECTED_AT_LEAST, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE, "dwt", "No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
if (parse_boolean(argv[0], true)) {
- new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED;
+ ic->dwt = LIBINPUT_CONFIG_DWT_ENABLED;
} else {
- new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED;
+ ic->dwt = LIBINPUT_CONFIG_DWT_DISABLED;
}
- apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/events.c b/sway/commands/input/events.c
index abfe3b12..e7ed69c6 100644
--- a/sway/commands/input/events.c
+++ b/sway/commands/input/events.c
@@ -10,30 +10,23 @@ struct cmd_results *input_cmd_events(int argc, char **argv) {
if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE, "events",
"No input device defined.");
}
- wlr_log(WLR_DEBUG, "events for device: %s",
- current_input_config->identifier);
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
if (strcasecmp(argv[0], "enabled") == 0) {
- new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
+ ic->send_events = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
} else if (strcasecmp(argv[0], "disabled") == 0) {
- new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
+ ic->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
} else if (strcasecmp(argv[0], "disabled_on_external_mouse") == 0) {
- new_config->send_events =
+ ic->send_events =
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
} else {
- free_input_config(new_config);
return cmd_results_new(CMD_INVALID, "events",
"Expected 'events <enabled|disabled|disabled_on_external_mouse>'");
}
- apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/left_handed.c b/sway/commands/input/left_handed.c
index e770043a..2e0f757b 100644
--- a/sway/commands/input/left_handed.c
+++ b/sway/commands/input/left_handed.c
@@ -10,17 +10,13 @@ struct cmd_results *input_cmd_left_handed(int argc, char **argv) {
if ((error = checkarg(argc, "left_handed", EXPECTED_AT_LEAST, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE, "left_handed",
"No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
- new_config->left_handed = parse_boolean(argv[0], true);
+ ic->left_handed = parse_boolean(argv[0], true);
- apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/map_from_region.c b/sway/commands/input/map_from_region.c
index 40f04214..53608a67 100644
--- a/sway/commands/input/map_from_region.c
+++ b/sway/commands/input/map_from_region.c
@@ -38,50 +38,44 @@ struct cmd_results *input_cmd_map_from_region(int argc, char **argv) {
if ((error = checkarg(argc, "map_from_region", EXPECTED_EQUAL_TO, 2))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE, "map_from_region",
"No input device defined");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
-
- new_config->mapped_from_region =
+ ic->mapped_from_region =
calloc(1, sizeof(struct input_config_mapped_from_region));
bool mm1, mm2;
- if (!parse_coords(argv[0], &new_config->mapped_from_region->x1,
- &new_config->mapped_from_region->y1, &mm1)) {
- free(new_config->mapped_from_region);
- free_input_config(new_config);
+ if (!parse_coords(argv[0], &ic->mapped_from_region->x1,
+ &ic->mapped_from_region->y1, &mm1)) {
+ free(ic->mapped_from_region);
+ ic->mapped_from_region = NULL;
return cmd_results_new(CMD_FAILURE, "map_from_region",
"Invalid top-left coordinates");
}
- if (!parse_coords(argv[1], &new_config->mapped_from_region->x2,
- &new_config->mapped_from_region->y2, &mm2)) {
- free(new_config->mapped_from_region);
- free_input_config(new_config);
+ if (!parse_coords(argv[1], &ic->mapped_from_region->x2,
+ &ic->mapped_from_region->y2, &mm2)) {
+ free(ic->mapped_from_region);
+ ic->mapped_from_region = NULL;
return cmd_results_new(CMD_FAILURE, "map_from_region",
"Invalid bottom-right coordinates");
}
- if (new_config->mapped_from_region->x1 > new_config->mapped_from_region->x2 ||
- new_config->mapped_from_region->y1 > new_config->mapped_from_region->y2) {
- free(new_config->mapped_from_region);
- free_input_config(new_config);
+ if (ic->mapped_from_region->x1 > ic->mapped_from_region->x2 ||
+ ic->mapped_from_region->y1 > ic->mapped_from_region->y2) {
+ free(ic->mapped_from_region);
+ ic->mapped_from_region = NULL;
return cmd_results_new(CMD_FAILURE, "map_from_region",
"Invalid rectangle");
}
if (mm1 != mm2) {
- free(new_config->mapped_from_region);
- free_input_config(new_config);
+ free(ic->mapped_from_region);
+ ic->mapped_from_region = NULL;
return cmd_results_new(CMD_FAILURE, "map_from_region",
"Both coordinates must be in the same unit");
}
- new_config->mapped_from_region->mm = mm1;
-
- apply_input_config(new_config);
+ ic->mapped_from_region->mm = mm1;
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/map_to_output.c b/sway/commands/input/map_to_output.c
index 68439bec..8b16c557 100644
--- a/sway/commands/input/map_to_output.c
+++ b/sway/commands/input/map_to_output.c
@@ -11,17 +11,13 @@ struct cmd_results *input_cmd_map_to_output(int argc, char **argv) {
if ((error = checkarg(argc, "map_to_output", EXPECTED_EQUAL_TO, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE, "map_to_output",
"No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
- new_config->mapped_to_output = strdup(argv[0]);
- apply_input_config(new_config);
+ ic->mapped_to_output = strdup(argv[0]);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/middle_emulation.c b/sway/commands/input/middle_emulation.c
index 414d4d2b..80d26838 100644
--- a/sway/commands/input/middle_emulation.c
+++ b/sway/commands/input/middle_emulation.c
@@ -10,22 +10,17 @@ struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) {
if ((error = checkarg(argc, "middle_emulation", EXPECTED_AT_LEAST, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE, "middle_emulation",
"No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
if (parse_boolean(argv[0], true)) {
- new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED;
+ ic->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED;
} else {
- new_config->middle_emulation =
- LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED;
+ ic->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED;
}
- apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/natural_scroll.c b/sway/commands/input/natural_scroll.c
index 77c3ff00..e2a93500 100644
--- a/sway/commands/input/natural_scroll.c
+++ b/sway/commands/input/natural_scroll.c
@@ -10,17 +10,13 @@ struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) {
if ((error = checkarg(argc, "natural_scroll", EXPECTED_AT_LEAST, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE, "natural_scoll",
"No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
- new_config->natural_scroll = parse_boolean(argv[0], true);
+ ic->natural_scroll = parse_boolean(argv[0], true);
- apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/pointer_accel.c b/sway/commands/input/pointer_accel.c
index 8bbd0724..df487b1c 100644
--- a/sway/commands/input/pointer_accel.c
+++ b/sway/commands/input/pointer_accel.c
@@ -9,23 +9,18 @@ struct cmd_results *input_cmd_pointer_accel(int argc, char **argv) {
if ((error = checkarg(argc, "pointer_accel", EXPECTED_AT_LEAST, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE,
"pointer_accel", "No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
float pointer_accel = atof(argv[0]);
if (pointer_accel < -1 || pointer_accel > 1) {
- free_input_config(new_config);
return cmd_results_new(CMD_INVALID, "pointer_accel",
"Input out of range [-1, 1]");
}
- new_config->pointer_accel = pointer_accel;
+ ic->pointer_accel = pointer_accel;
- apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/repeat_delay.c b/sway/commands/input/repeat_delay.c
index c9ddbf0e..d94b3e4d 100644
--- a/sway/commands/input/repeat_delay.c
+++ b/sway/commands/input/repeat_delay.c
@@ -9,23 +9,18 @@ struct cmd_results *input_cmd_repeat_delay(int argc, char **argv) {
if ((error = checkarg(argc, "repeat_delay", EXPECTED_EQUAL_TO, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE,
"repeat_delay", "No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
int repeat_delay = atoi(argv[0]);
if (repeat_delay < 0) {
- free_input_config(new_config);
return cmd_results_new(CMD_INVALID, "repeat_delay",
"Repeat delay cannot be negative");
}
- new_config->repeat_delay = repeat_delay;
+ ic->repeat_delay = repeat_delay;
- apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/repeat_rate.c b/sway/commands/input/repeat_rate.c
index 56878176..ebec4cdb 100644
--- a/sway/commands/input/repeat_rate.c
+++ b/sway/commands/input/repeat_rate.c
@@ -9,23 +9,18 @@ struct cmd_results *input_cmd_repeat_rate(int argc, char **argv) {
if ((error = checkarg(argc, "repeat_rate", EXPECTED_EQUAL_TO, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE,
"repeat_rate", "No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
int repeat_rate = atoi(argv[0]);
if (repeat_rate < 0) {
- free_input_config(new_config);
return cmd_results_new(CMD_INVALID, "repeat_rate",
"Repeat rate cannot be negative");
}
- new_config->repeat_rate = repeat_rate;
+ ic->repeat_rate = repeat_rate;
- apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/scroll_button.c b/sway/commands/input/scroll_button.c
index 350fcca2..1958f23c 100644
--- a/sway/commands/input/scroll_button.c
+++ b/sway/commands/input/scroll_button.c
@@ -10,35 +10,28 @@ struct cmd_results *input_cmd_scroll_button(int argc, char **argv) {
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) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
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;
+ ic->scroll_button = scroll_button;
- apply_input_config(new_config);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/scroll_method.c b/sway/commands/input/scroll_method.c
index 4c6ac6b6..c116b052 100644
--- a/sway/commands/input/scroll_method.c
+++ b/sway/commands/input/scroll_method.c
@@ -9,29 +9,24 @@ struct cmd_results *input_cmd_scroll_method(int argc, char **argv) {
if ((error = checkarg(argc, "scroll_method", EXPECTED_AT_LEAST, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE, "scroll_method",
"No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
if (strcasecmp(argv[0], "none") == 0) {
- new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
+ ic->scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
} else if (strcasecmp(argv[0], "two_finger") == 0) {
- new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
+ ic->scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
} else if (strcasecmp(argv[0], "edge") == 0) {
- new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE;
+ ic->scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE;
} else if (strcasecmp(argv[0], "on_button_down") == 0) {
- new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
+ ic->scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
} else {
- free_input_config(new_config);
return cmd_results_new(CMD_INVALID, "scroll_method",
"Expected 'scroll_method <none|two_finger|edge|on_button_down>'");
}
- 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 ac3b8237..c455b696 100644
--- a/sway/commands/input/tap.c
+++ b/sway/commands/input/tap.c
@@ -11,22 +11,16 @@ struct cmd_results *input_cmd_tap(int argc, char **argv) {
if ((error = checkarg(argc, "tap", EXPECTED_AT_LEAST, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE, "tap", "No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
if (parse_boolean(argv[0], true)) {
- new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED;
+ ic->tap = LIBINPUT_CONFIG_TAP_ENABLED;
} else {
- new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED;
+ ic->tap = LIBINPUT_CONFIG_TAP_DISABLED;
}
- 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
index bdbba472..dff2985b 100644
--- a/sway/commands/input/tap_button_map.c
+++ b/sway/commands/input/tap_button_map.c
@@ -9,25 +9,20 @@ struct cmd_results *input_cmd_tap_button_map(int argc, char **argv) {
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) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
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;
+ ic->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;
+ ic->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_capslock.c b/sway/commands/input/xkb_capslock.c
index 5442c463..669b4ea9 100644
--- a/sway/commands/input/xkb_capslock.c
+++ b/sway/commands/input/xkb_capslock.c
@@ -9,25 +9,20 @@ struct cmd_results *input_cmd_xkb_capslock(int argc, char **argv) {
if ((error = checkarg(argc, "xkb_capslock", EXPECTED_AT_LEAST, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE, "xkb_capslock",
"No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
if (strcasecmp(argv[0], "enabled") == 0) {
- new_config->xkb_capslock = 1;
+ ic->xkb_capslock = 1;
} else if (strcasecmp(argv[0], "disabled") == 0) {
- new_config->xkb_capslock = 0;
+ ic->xkb_capslock = 0;
} else {
- free_input_config(new_config);
return cmd_results_new(CMD_INVALID, "xkb_capslock",
"Expected 'xkb_capslock <enabled|disabled>'");
}
- 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 9fa5a344..5fccd4a3 100644
--- a/sway/commands/input/xkb_layout.c
+++ b/sway/commands/input/xkb_layout.c
@@ -9,18 +9,15 @@ struct cmd_results *input_cmd_xkb_layout(int argc, char **argv) {
if ((error = checkarg(argc, "xkb_layout", EXPECTED_EQUAL_TO, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
- return cmd_results_new(CMD_FAILURE, "xkb_layout", "No input device defined.");
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
+ return cmd_results_new(CMD_FAILURE, "xkb_layout",
+ "No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
- new_config->xkb_layout = strdup(argv[0]);
+ ic->xkb_layout = strdup(argv[0]);
- 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);
+ wlr_log(WLR_DEBUG, "set-xkb_layout for config: %s layout: %s",
+ ic->identifier, ic->xkb_layout);
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 0d082625..c4d04638 100644
--- a/sway/commands/input/xkb_model.c
+++ b/sway/commands/input/xkb_model.c
@@ -9,18 +9,15 @@ struct cmd_results *input_cmd_xkb_model(int argc, char **argv) {
if ((error = checkarg(argc, "xkb_model", EXPECTED_EQUAL_TO, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
- return cmd_results_new(CMD_FAILURE, "xkb_model", "No input device defined.");
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
+ return cmd_results_new(CMD_FAILURE, "xkb_model",
+ "No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
- new_config->xkb_model = strdup(argv[0]);
+ ic->xkb_model = strdup(argv[0]);
- 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);
+ wlr_log(WLR_DEBUG, "set-xkb_model for config: %s model: %s",
+ ic->identifier, ic->xkb_model);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/xkb_numlock.c b/sway/commands/input/xkb_numlock.c
index 39675366..1367da44 100644
--- a/sway/commands/input/xkb_numlock.c
+++ b/sway/commands/input/xkb_numlock.c
@@ -9,25 +9,20 @@ struct cmd_results *input_cmd_xkb_numlock(int argc, char **argv) {
if ((error = checkarg(argc, "xkb_numlock", EXPECTED_AT_LEAST, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
return cmd_results_new(CMD_FAILURE, "xkb_numlock",
"No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
if (strcasecmp(argv[0], "enabled") == 0) {
- new_config->xkb_numlock = 1;
+ ic->xkb_numlock = 1;
} else if (strcasecmp(argv[0], "disabled") == 0) {
- new_config->xkb_numlock = 0;
+ ic->xkb_numlock = 0;
} else {
- free_input_config(new_config);
return cmd_results_new(CMD_INVALID, "xkb_numlock",
"Expected 'xkb_numlock <enabled|disabled>'");
}
- 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 3059d941..794ab6e9 100644
--- a/sway/commands/input/xkb_options.c
+++ b/sway/commands/input/xkb_options.c
@@ -9,18 +9,15 @@ struct cmd_results *input_cmd_xkb_options(int argc, char **argv) {
if ((error = checkarg(argc, "xkb_options", EXPECTED_EQUAL_TO, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
- return cmd_results_new(CMD_FAILURE, "xkb_options", "No input device defined.");
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
+ return cmd_results_new(CMD_FAILURE, "xkb_options",
+ "No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
- new_config->xkb_options = strdup(argv[0]);
+ ic->xkb_options = strdup(argv[0]);
- 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);
+ wlr_log(WLR_DEBUG, "set-xkb_options for config: %s options: %s",
+ ic->identifier, ic->xkb_options);
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 560f088e..257c3288 100644
--- a/sway/commands/input/xkb_rules.c
+++ b/sway/commands/input/xkb_rules.c
@@ -9,18 +9,15 @@ struct cmd_results *input_cmd_xkb_rules(int argc, char **argv) {
if ((error = checkarg(argc, "xkb_rules", EXPECTED_EQUAL_TO, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
- return cmd_results_new(CMD_FAILURE, "xkb_rules", "No input device defined.");
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
+ return cmd_results_new(CMD_FAILURE, "xkb_rules",
+ "No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
- new_config->xkb_rules = strdup(argv[0]);
+ ic->xkb_rules = strdup(argv[0]);
- 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);
+ wlr_log(WLR_DEBUG, "set-xkb_rules for config: %s rules: %s",
+ ic->identifier, ic->xkb_rules);
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 0aa03440..3832dc8e 100644
--- a/sway/commands/input/xkb_variant.c
+++ b/sway/commands/input/xkb_variant.c
@@ -9,18 +9,15 @@ struct cmd_results *input_cmd_xkb_variant(int argc, char **argv) {
if ((error = checkarg(argc, "xkb_variant", EXPECTED_EQUAL_TO, 1))) {
return error;
}
- struct input_config *current_input_config =
- config->handler_context.input_config;
- if (!current_input_config) {
- return cmd_results_new(CMD_FAILURE, "xkb_variant", "No input device defined.");
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
+ return cmd_results_new(CMD_FAILURE, "xkb_variant",
+ "No input device defined.");
}
- struct input_config *new_config =
- new_input_config(current_input_config->identifier);
- new_config->xkb_variant = strdup(argv[0]);
+ ic->xkb_variant = strdup(argv[0]);
- 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);
+ wlr_log(WLR_DEBUG, "set-xkb_variant for config: %s variant: %s",
+ ic->identifier, ic->xkb_variant);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/layout.c b/sway/commands/layout.c
index ef3ec1cb..c2ce2e78 100644
--- a/sway/commands/layout.c
+++ b/sway/commands/layout.c
@@ -138,15 +138,14 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
}
container->layout = new_layout;
container_update_representation(container);
- arrange_container(container);
} else {
if (old_layout != L_TABBED && old_layout != L_STACKED) {
workspace->prev_split_layout = old_layout;
}
workspace->layout = new_layout;
workspace_update_representation(workspace);
- arrange_workspace(workspace);
}
+ arrange_workspace(workspace);
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/move.c b/sway/commands/move.c
index 849a18ad..fc2f1cc1 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -259,50 +259,24 @@ static void container_move_to_container(struct sway_container *container,
* In other words, rejigger it. */
static void workspace_rejigger(struct sway_workspace *ws,
struct sway_container *child, enum movement_direction move_dir) {
+ if (!child->parent && ws->tiling->length == 1) {
+ ws->layout =
+ move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT;
+ workspace_update_representation(ws);
+ return;
+ }
container_detach(child);
- workspace_wrap_children(ws);
+ struct sway_container *new_parent = workspace_wrap_children(ws);
int index = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? 0 : 1;
workspace_insert_tiling(ws, child, index);
+ container_flatten(new_parent);
ws->layout =
move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT;
workspace_update_representation(ws);
child->width = child->height = 0;
}
-static void move_out_of_tabs_stacks(struct sway_container *container,
- struct sway_container *current, enum movement_direction move_dir,
- int offs) {
- enum sway_container_layout layout = move_dir ==
- MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT;
- list_t *siblings = container_get_siblings(container);
- if (container == current && siblings->length == 1) {
- wlr_log(WLR_DEBUG, "Changing layout of parent");
- if (container->parent) {
- container->parent->layout = layout;
- container_update_representation(container);
- } else {
- container->workspace->layout = layout;
- workspace_update_representation(container->workspace);
- }
- return;
- }
-
- wlr_log(WLR_DEBUG, "Moving out of tab/stack into a split");
- if (current->parent) {
- struct sway_container *new_parent =
- container_split(current->parent, layout);
- container_insert_child(new_parent, container, offs < 0 ? 0 : 1);
- container_reap_empty(new_parent);
- container_flatten(new_parent);
- } else {
- // Changing a workspace
- struct sway_workspace *workspace = container->workspace;
- workspace_split(workspace, layout);
- workspace_insert_tiling(workspace, container, offs < 0 ? 0 : 1);
- }
-}
-
// Returns true if moved
static bool container_move_in_direction(struct sway_container *container,
enum movement_direction move_dir) {
@@ -334,7 +308,6 @@ static bool container_move_in_direction(struct sway_container *container,
int offs = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1;
while (current) {
- struct sway_container *parent = current->parent;
list_t *siblings = container_get_siblings(current);
enum sway_container_layout layout = container_parent_layout(current);
int index = list_find(siblings, current);
@@ -343,15 +316,8 @@ static bool container_move_in_direction(struct sway_container *container,
if (is_parallel(layout, move_dir)) {
if (desired == -1 || desired == siblings->length) {
if (current->parent == container->parent) {
- if (!(parent && parent->is_fullscreen) &&
- (layout == L_TABBED || layout == L_STACKED)) {
- move_out_of_tabs_stacks(container, current,
- move_dir, offs);
- return true;
- } else {
- current = current->parent;
- continue;
- }
+ current = current->parent;
+ continue;
} else {
// Special case
if (current->parent) {
@@ -369,10 +335,6 @@ static bool container_move_in_direction(struct sway_container *container,
siblings->items[desired], move_dir);
return true;
}
- } else if (!(parent && parent->is_fullscreen) &&
- (layout == L_TABBED || layout == L_STACKED)) {
- move_out_of_tabs_stacks(container, current, move_dir, offs);
- return true;
}
current = current->parent;
@@ -388,10 +350,8 @@ static bool container_move_in_direction(struct sway_container *container,
// Maybe rejigger the workspace
struct sway_workspace *ws = container->workspace;
if (!is_parallel(ws->layout, move_dir)) {
- if (ws->tiling->length >= 2) {
- workspace_rejigger(ws, container, move_dir);
- return true;
- }
+ workspace_rejigger(ws, container, move_dir);
+ return true;
} else if (ws->layout == L_TABBED || ws->layout == L_STACKED) {
workspace_rejigger(ws, container, move_dir);
return true;
diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c
index 9e370d43..30fb47c4 100644
--- a/sway/commands/output/background.c
+++ b/sway/commands/output/background.c
@@ -123,19 +123,13 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
}
free(src);
} else {
- // Escape spaces and quotes in the final path for swaybg
+ // Escape double quotes in the final path for swaybg
for (size_t i = 0; i < strlen(src); i++) {
- switch (src[i]) {
- case ' ':
- case '\'':
- case '\"':
- src = realloc(src, strlen(src) + 2);
- memmove(src + i + 1, src + i, strlen(src + i) + 1);
- *(src + i) = '\\';
- i++;
- break;
- default:
- break;
+ if (src[i] == '"') {
+ src = realloc(src, strlen(src) + 2);
+ memmove(src + i + 1, src + i, strlen(src + i) + 1);
+ *(src + i) = '\\';
+ i++;
}
}
diff --git a/sway/commands/resize.c b/sway/commands/resize.c
index 99e9dbda..1343b165 100644
--- a/sway/commands/resize.c
+++ b/sway/commands/resize.c
@@ -179,11 +179,11 @@ static void container_recursive_resize(struct sway_container *container,
}
}
-static void resize_tiled(struct sway_container *parent, int amount,
+static bool resize_tiled(struct sway_container *parent, int amount,
enum resize_axis axis) {
struct sway_container *focused = parent;
if (!parent) {
- return;
+ return false;
}
enum sway_container_layout parallel_layout =
@@ -216,7 +216,7 @@ static void resize_tiled(struct sway_container *parent, int amount,
}
if (!parent) {
// Can't resize in this direction
- return;
+ return false;
}
// Implement up/down/left/right direction by zeroing one of the weights,
@@ -248,22 +248,22 @@ static void resize_tiled(struct sway_container *parent, int amount,
if (sibling_pos < parent_pos && minor_weight) {
double pixels = -amount / minor_weight;
if (major_weight && (sibling_size + pixels / 2) < min_sane) {
- return; // Too small
+ return false; // Too small
} else if (!major_weight && sibling_size + pixels < min_sane) {
- return; // Too small
+ return false; // Too small
}
} else if (sibling_pos > parent_pos && major_weight) {
double pixels = -amount / major_weight;
if (minor_weight && (sibling_size + pixels / 2) < min_sane) {
- return; // Too small
+ return false; // Too small
} else if (!minor_weight && sibling_size + pixels < min_sane) {
- return; // Too small
+ return false; // Too small
}
}
} else {
double pixels = amount;
if (parent_size + pixels < min_sane) {
- return; // Too small
+ return false; // Too small
}
}
}
@@ -317,9 +317,10 @@ static void resize_tiled(struct sway_container *parent, int amount,
} else {
arrange_workspace(parent->workspace);
}
+ return true;
}
-void container_resize_tiled(struct sway_container *parent,
+bool container_resize_tiled(struct sway_container *parent,
enum wlr_edges edge, int amount) {
enum resize_axis axis = RESIZE_AXIS_INVALID;
switch (edge) {
@@ -338,7 +339,7 @@ void container_resize_tiled(struct sway_container *parent,
case WLR_EDGE_NONE:
break;
}
- resize_tiled(parent, amount, axis);
+ return resize_tiled(parent, amount, axis);
}
/**
@@ -395,6 +396,10 @@ static struct cmd_results *resize_adjust_floating(enum resize_axis axis,
case RESIZE_AXIS_INVALID:
return cmd_results_new(CMD_INVALID, "resize", "Invalid axis/direction");
}
+ if (grow_x == 0 && grow_y == 0) {
+ return cmd_results_new(CMD_INVALID, "resize",
+ "Cannot resize any further");
+ }
con->x += grow_x;
con->y += grow_y;
con->width += grow_width;
@@ -442,7 +447,10 @@ static struct cmd_results *resize_adjust_tiled(enum resize_axis axis,
}
}
- resize_tiled(current, amount->amount, axis);
+ if (!resize_tiled(current, amount->amount, axis)) {
+ return cmd_results_new(CMD_INVALID, "resize",
+ "Cannot resize any further");
+ }
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c
index f026a39d..63f29641 100644
--- a/sway/commands/workspace.c
+++ b/sway/commands/workspace.c
@@ -10,6 +10,28 @@
#include "log.h"
#include "stringop.h"
+static struct workspace_config *workspace_config_find_or_create(char *ws_name) {
+ struct workspace_config *wsc = workspace_find_config(ws_name);
+ if (wsc) {
+ return wsc;
+ }
+ wsc = calloc(1, sizeof(struct workspace_config));
+ if (!wsc) {
+ return NULL;
+ }
+ wsc->workspace = strdup(ws_name);
+ wsc->gaps_inner = -1;
+ wsc->gaps_outer = -1;
+ list_add(config->workspace_configs, wsc);
+ return wsc;
+}
+
+void free_workspace_config(struct workspace_config *wsc) {
+ free(wsc->workspace);
+ free(wsc->output);
+ free(wsc);
+}
+
struct cmd_results *cmd_workspace(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1))) {
@@ -17,6 +39,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
}
int output_location = -1;
+ int gaps_location = -1;
for (int i = 0; i < argc; ++i) {
if (strcasecmp(argv[i], "output") == 0) {
@@ -24,25 +47,54 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
break;
}
}
+ for (int i = 0; i < argc; ++i) {
+ if (strcasecmp(argv[i], "gaps") == 0) {
+ gaps_location = i;
+ break;
+ }
+ }
if (output_location >= 0) {
if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, output_location + 2))) {
return error;
}
- struct workspace_output *wso = calloc(1, sizeof(struct workspace_output));
- if (!wso) {
+ char *ws_name = join_args(argv, argc - 2);
+ struct workspace_config *wsc = workspace_config_find_or_create(ws_name);
+ free(ws_name);
+ if (!wsc) {
return cmd_results_new(CMD_FAILURE, "workspace output",
"Unable to allocate workspace output");
}
- wso->workspace = join_args(argv, argc - 2);
- wso->output = strdup(argv[output_location + 1]);
- int i = -1;
- if ((i = list_seq_find(config->workspace_outputs, workspace_output_cmp_workspace, wso)) != -1) {
- struct workspace_output *old = config->workspace_outputs->items[i];
- free(old); // workspaces can only be assigned to a single output
- list_del(config->workspace_outputs, i);
+ free(wsc->output);
+ wsc->output = strdup(argv[output_location + 1]);
+ } else if (gaps_location >= 0) {
+ if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, gaps_location + 3))) {
+ return error;
+ }
+ char *ws_name = join_args(argv, argc - 3);
+ struct workspace_config *wsc = workspace_config_find_or_create(ws_name);
+ free(ws_name);
+ if (!wsc) {
+ return cmd_results_new(CMD_FAILURE, "workspace gaps",
+ "Unable to allocate workspace output");
+ }
+ int *prop = NULL;
+ if (strcasecmp(argv[gaps_location + 1], "inner") == 0) {
+ prop = &wsc->gaps_inner;
+ } else if (strcasecmp(argv[gaps_location + 1], "outer") == 0) {
+ prop = &wsc->gaps_outer;
+ } else {
+ return cmd_results_new(CMD_FAILURE, "workspace gaps",
+ "Expected 'workspace <ws> gaps inner|outer <px>'");
+ }
+ char *end;
+ int val = strtol(argv[gaps_location + 2], &end, 10);
+
+ if (strlen(end)) {
+ free(end);
+ return cmd_results_new(CMD_FAILURE, "workspace gaps",
+ "Expected 'workspace <ws> gaps inner|outer <px>'");
}
- wlr_log(WLR_DEBUG, "Assigning workspace %s to output %s", wso->workspace, wso->output);
- list_add(config->workspace_outputs, wso);
+ *prop = val >= 0 ? val : 0;
} else {
if (config->reading || !config->active) {
return cmd_results_new(CMD_DEFER, "workspace", NULL);
diff --git a/sway/config.c b/sway/config.c
index 830fb65f..1e08559d 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -95,7 +95,12 @@ void free_config(struct sway_config *config) {
list_free(config->bars);
}
list_free(config->cmd_queue);
- list_free(config->workspace_outputs);
+ if (config->workspace_configs) {
+ for (int i = 0; i < config->workspace_configs->length; i++) {
+ free_workspace_config(config->workspace_configs->items[i]);
+ }
+ list_free(config->workspace_configs);
+ }
if (config->output_configs) {
for (int i = 0; i < config->output_configs->length; i++) {
free_output_config(config->output_configs->items[i]);
@@ -175,7 +180,7 @@ static void config_defaults(struct sway_config *config) {
if (!(config->symbols = create_list())) goto cleanup;
if (!(config->modes = create_list())) goto cleanup;
if (!(config->bars = create_list())) goto cleanup;
- if (!(config->workspace_outputs = create_list())) goto cleanup;
+ if (!(config->workspace_configs = create_list())) goto cleanup;
if (!(config->criteria = create_list())) goto cleanup;
if (!(config->no_focus = create_list())) goto cleanup;
if (!(config->input_configs = create_list())) goto cleanup;
@@ -804,7 +809,7 @@ char *do_var_replacement(char *str) {
// would compare two structs in full, while this method only compares the
// workspace.
int workspace_output_cmp_workspace(const void *a, const void *b) {
- const struct workspace_output *wsa = a, *wsb = b;
+ const struct workspace_config *wsa = a, *wsb = b;
return lenient_strcmp(wsa->workspace, wsb->workspace);
}
diff --git a/sway/config/bar.c b/sway/config/bar.c
index f83b37d1..48a632fb 100644
--- a/sway/config/bar.c
+++ b/sway/config/bar.c
@@ -165,7 +165,7 @@ cleanup:
return NULL;
}
-void invoke_swaybar(struct bar_config *bar) {
+static void invoke_swaybar(struct bar_config *bar) {
// Pipe to communicate errors
int filedes[2];
if (pipe(filedes) == -1) {
@@ -219,27 +219,13 @@ void invoke_swaybar(struct bar_config *bar) {
close(filedes[1]);
}
-void load_swaybars() {
+void load_swaybars(void) {
for (int i = 0; i < config->bars->length; ++i) {
struct bar_config *bar = config->bars->items[i];
- bool apply = false;
- if (bar->outputs) {
- for (int j = 0; j < bar->outputs->length; ++j) {
- char *o = bar->outputs->items[j];
- if (!strcmp(o, "*") || output_by_name(o)) {
- apply = true;
- break;
- }
- }
- } else {
- apply = true;
- }
- if (apply) {
- if (bar->pid != 0) {
- terminate_swaybar(bar->pid);
- }
- wlr_log(WLR_DEBUG, "Invoking swaybar for bar id '%s'", bar->id);
- invoke_swaybar(bar);
+ if (bar->pid != 0) {
+ terminate_swaybar(bar->pid);
}
+ 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 ad5b96c8..794d5194 100644
--- a/sway/config/input.c
+++ b/sway/config/input.c
@@ -20,6 +20,7 @@ struct input_config *new_input_config(const char* identifier) {
input->tap = INT_MIN;
input->tap_button_map = INT_MIN;
+ input->drag = INT_MIN;
input->drag_lock = INT_MIN;
input->dwt = INT_MIN;
input->send_events = INT_MIN;
@@ -40,22 +41,24 @@ struct input_config *new_input_config(const char* identifier) {
}
void merge_input_config(struct input_config *dst, struct input_config *src) {
- if (src->identifier) {
- free(dst->identifier);
- dst->identifier = strdup(src->identifier);
- }
if (src->accel_profile != INT_MIN) {
dst->accel_profile = src->accel_profile;
}
if (src->click_method != INT_MIN) {
dst->click_method = src->click_method;
}
+ if (src->drag != INT_MIN) {
+ dst->drag = src->drag;
+ }
if (src->drag_lock != INT_MIN) {
dst->drag_lock = src->drag_lock;
}
if (src->dwt != INT_MIN) {
dst->dwt = src->dwt;
}
+ if (src->left_handed != INT_MIN) {
+ dst->left_handed = src->left_handed;
+ }
if (src->middle_emulation != INT_MIN) {
dst->middle_emulation = src->middle_emulation;
}
@@ -125,14 +128,51 @@ 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(WLR_ERROR, "could not allocate input config");
- return NULL;
+static void merge_wildcard_on_all(struct input_config *wildcard) {
+ for (int i = 0; i < config->input_configs->length; i++) {
+ struct input_config *ic = config->input_configs->items[i];
+ if (strcmp(wildcard->identifier, ic->identifier) != 0) {
+ wlr_log(WLR_DEBUG, "Merging input * config on %s", ic->identifier);
+ merge_input_config(ic, wildcard);
+ }
}
- merge_input_config(copy, ic);
- return copy;
+}
+
+struct input_config *store_input_config(struct input_config *ic) {
+ bool wildcard = strcmp(ic->identifier, "*") == 0;
+ if (wildcard) {
+ merge_wildcard_on_all(ic);
+ }
+
+ int i = list_seq_find(config->input_configs, input_identifier_cmp,
+ ic->identifier);
+ if (i >= 0) {
+ wlr_log(WLR_DEBUG, "Merging on top of existing input config");
+ struct input_config *current = config->input_configs->items[i];
+ merge_input_config(current, ic);
+ free_input_config(ic);
+ ic = current;
+ } else if (!wildcard) {
+ wlr_log(WLR_DEBUG, "Adding non-wildcard input config");
+ i = list_seq_find(config->input_configs, input_identifier_cmp, "*");
+ if (i >= 0) {
+ wlr_log(WLR_DEBUG, "Merging on top of input * config");
+ struct input_config *current = new_input_config(ic->identifier);
+ merge_input_config(current, config->input_configs->items[i]);
+ merge_input_config(current, ic);
+ free_input_config(ic);
+ ic = current;
+ }
+ list_add(config->input_configs, ic);
+ } else {
+ // New wildcard config. Just add it
+ wlr_log(WLR_DEBUG, "Adding input * config");
+ list_add(config->input_configs, ic);
+ }
+
+ wlr_log(WLR_DEBUG, "Config stored for input %s", ic->identifier);
+
+ return ic;
}
void free_input_config(struct input_config *ic) {
diff --git a/sway/config/output.c b/sway/config/output.c
index 74d79130..6f337b66 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -237,7 +237,7 @@ void apply_output_config(struct output_config *oc, struct sway_output *output) {
wlr_log(WLR_DEBUG, "Setting background for output %d to %s",
output_i, oc->background);
- size_t len = snprintf(NULL, 0, "%s %d %s %s %s",
+ size_t len = snprintf(NULL, 0, "%s %d \"%s\" %s %s",
config->swaybg_command ? config->swaybg_command : "swaybg",
output_i, oc->background, oc->background_option,
oc->background_fallback ? oc->background_fallback : "");
@@ -246,7 +246,7 @@ void apply_output_config(struct output_config *oc, struct sway_output *output) {
wlr_log(WLR_DEBUG, "Unable to allocate swaybg command");
return;
}
- snprintf(command, len + 1, "%s %d %s %s %s",
+ snprintf(command, len + 1, "%s %d \"%s\" %s %s",
config->swaybg_command ? config->swaybg_command : "swaybg",
output_i, oc->background, oc->background_option,
oc->background_fallback ? oc->background_fallback : "");
diff --git a/sway/config/seat.c b/sway/config/seat.c
index 83dac4c0..46456caf 100644
--- a/sway/config/seat.c
+++ b/sway/config/seat.c
@@ -30,7 +30,7 @@ struct seat_config *new_seat_config(const char* name) {
return seat;
}
-struct seat_attachment_config *seat_attachment_config_new() {
+struct seat_attachment_config *seat_attachment_config_new(void) {
struct seat_attachment_config *attachment =
calloc(1, sizeof(struct seat_attachment_config));
if (!attachment) {
diff --git a/sway/debug-tree.c b/sway/debug-tree.c
index 9644f4e5..16b479f9 100644
--- a/sway/debug-tree.c
+++ b/sway/debug-tree.c
@@ -120,7 +120,7 @@ static int draw_node(cairo_t *cairo, struct sway_node *node,
return height;
}
-void update_debug_tree() {
+void update_debug_tree(void) {
if (!debug.render_tree) {
return;
}
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index d747e279..34d99d52 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -6,6 +6,7 @@
#include <string.h>
#include <time.h>
#include <wlr/types/wlr_buffer.h>
+#include "sway/config.h"
#include "sway/debug.h"
#include "sway/desktop.h"
#include "sway/desktop/idle_inhibit_v1.h"
@@ -30,14 +31,14 @@ struct sway_transaction_instruction {
struct sway_transaction *transaction;
struct sway_node *node;
union {
- struct sway_output_state *output_state;
- struct sway_workspace_state *workspace_state;
- struct sway_container_state *container_state;
+ struct sway_output_state output_state;
+ struct sway_workspace_state workspace_state;
+ struct sway_container_state container_state;
};
uint32_t serial;
};
-static struct sway_transaction *transaction_create() {
+static struct sway_transaction *transaction_create(void) {
struct sway_transaction *transaction =
calloc(1, sizeof(struct sway_transaction));
if (!sway_assert(transaction, "Unable to allocate transaction")) {
@@ -85,14 +86,7 @@ static void transaction_destroy(struct sway_transaction *transaction) {
static void copy_output_state(struct sway_output *output,
struct sway_transaction_instruction *instruction) {
- struct sway_output_state *state =
- calloc(1, sizeof(struct sway_output_state));
- if (!state) {
- wlr_log(WLR_ERROR, "Could not allocate output state");
- return;
- }
- instruction->output_state = state;
-
+ struct sway_output_state *state = &instruction->output_state;
state->workspaces = create_list();
list_cat(state->workspaces, output->workspaces);
@@ -101,13 +95,7 @@ static void copy_output_state(struct sway_output *output,
static void copy_workspace_state(struct sway_workspace *ws,
struct sway_transaction_instruction *instruction) {
- struct sway_workspace_state *state =
- calloc(1, sizeof(struct sway_workspace_state));
- if (!state) {
- wlr_log(WLR_ERROR, "Could not allocate workspace state");
- return;
- }
- instruction->workspace_state = state;
+ struct sway_workspace_state *state = &instruction->workspace_state;
state->fullscreen = ws->fullscreen;
state->x = ws->x;
@@ -137,13 +125,7 @@ static void copy_workspace_state(struct sway_workspace *ws,
static void copy_container_state(struct sway_container *container,
struct sway_transaction_instruction *instruction) {
- struct sway_container_state *state =
- calloc(1, sizeof(struct sway_container_state));
- if (!state) {
- wlr_log(WLR_ERROR, "Could not allocate container state");
- return;
- }
- instruction->container_state = state;
+ struct sway_container_state *state = &instruction->container_state;
state->layout = container->layout;
state->con_x = container->x;
@@ -300,15 +282,15 @@ static void transaction_apply(struct sway_transaction *transaction) {
case N_ROOT:
break;
case N_OUTPUT:
- apply_output_state(node->sway_output, instruction->output_state);
+ apply_output_state(node->sway_output, &instruction->output_state);
break;
case N_WORKSPACE:
apply_workspace_state(node->sway_workspace,
- instruction->workspace_state);
+ &instruction->workspace_state);
break;
case N_CONTAINER:
apply_container_state(node->sway_container,
- instruction->container_state);
+ &instruction->container_state);
break;
}
@@ -334,7 +316,7 @@ static bool transaction_same_nodes(struct sway_transaction *a,
return true;
}
-static void transaction_progress_queue() {
+static void transaction_progress_queue(void) {
if (!server.transactions->length) {
return;
}
@@ -389,7 +371,17 @@ static bool should_configure(struct sway_node *node,
return false;
}
struct sway_container_state *cstate = &node->sway_container->current;
- struct sway_container_state *istate = instruction->container_state;
+ struct sway_container_state *istate = &instruction->container_state;
+#ifdef HAVE_XWAYLAND
+ // Xwayland views are position-aware and need to be reconfigured
+ // when their position changes.
+ if (node->sway_container->view->type == SWAY_VIEW_XWAYLAND) {
+ if (cstate->view_x != istate->view_x ||
+ cstate->view_y != istate->view_y) {
+ return true;
+ }
+ }
+#endif
if (cstate->view_width == istate->view_width &&
cstate->view_height == istate->view_height) {
return false;
@@ -407,10 +399,10 @@ static void transaction_commit(struct sway_transaction *transaction) {
struct sway_node *node = instruction->node;
if (should_configure(node, instruction)) {
instruction->serial = view_configure(node->sway_container->view,
- instruction->container_state->view_x,
- instruction->container_state->view_y,
- instruction->container_state->view_width,
- instruction->container_state->view_height);
+ instruction->container_state.view_x,
+ instruction->container_state.view_y,
+ instruction->container_state.view_width,
+ instruction->container_state.view_height);
++transaction->num_waiting;
// From here on we are rendering a saved buffer of the view, which
@@ -502,8 +494,8 @@ void transaction_notify_view_ready_by_size(struct sway_view *view,
int width, int height) {
struct sway_transaction_instruction *instruction =
view->container->node.instruction;
- if (instruction->container_state->view_width == width &&
- instruction->container_state->view_height == height) {
+ if (instruction->container_state.view_width == width &&
+ instruction->container_state.view_height == height) {
set_instruction_ready(instruction);
}
}
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index 00448be7..6d1ccdd7 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -401,7 +401,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
} else {
if (view->container->parent) {
arrange_container(view->container->parent);
- } else {
+ } else if (view->container->workspace) {
arrange_workspace(view->container->workspace);
}
}
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index d2c9a68b..95ca396c 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -398,7 +398,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
} else {
if (view->container->parent) {
arrange_container(view->container->parent);
- } else {
+ } else if (view->container->workspace) {
arrange_workspace(view->container->workspace);
}
}
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 3619f202..a12ac854 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -394,7 +394,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
} else {
if (view->container->parent) {
arrange_container(view->container->parent);
- } else {
+ } else if (view->container->workspace) {
arrange_workspace(view->container->workspace);
}
}
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 85951c09..3ddc27a0 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -30,7 +30,7 @@
// when dragging to the edge of a layout container.
#define DROP_LAYOUT_BORDER 30
-static uint32_t get_current_time_msec() {
+static uint32_t get_current_time_msec(void) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return now.tv_nsec / 1000;
@@ -897,7 +897,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
// Handle moving a tiling container
if (config->tiling_drag && mod_pressed && state == WLR_BUTTON_PRESSED &&
- !is_floating_or_child && !cont->is_fullscreen) {
+ !is_floating_or_child && cont && !cont->is_fullscreen) {
seat_pointer_notify_button(seat, time_msec, button, state);
seat_begin_move_tiling(seat, cont, button);
return;
@@ -911,9 +911,10 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
return;
}
- // Handle clicking a container surface
+ // Handle clicking a container surface or decorations
if (cont) {
- seat_set_focus_container(seat, cont);
+ node = seat_get_focus_inactive(seat, &cont->node);
+ seat_set_focus(seat, node);
seat_pointer_notify_button(seat, time_msec, button, state);
return;
}
@@ -930,12 +931,52 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) {
transaction_commit_dirty();
}
+static void dispatch_cursor_axis(struct sway_cursor *cursor,
+ struct wlr_event_pointer_axis *event) {
+ struct sway_seat *seat = cursor->seat;
+
+ // Determine what's under the cursor
+ struct wlr_surface *surface = NULL;
+ double sx, sy;
+ struct sway_node *node = node_at_coords(seat,
+ cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
+ struct sway_container *cont = node && node->type == N_CONTAINER ?
+ node->sway_container : NULL;
+ enum wlr_edges edge = cont ? find_edge(cont, cursor) : WLR_EDGE_NONE;
+ bool on_border = edge != WLR_EDGE_NONE;
+ bool on_titlebar = cont && !on_border && !surface;
+
+ // Scrolling on a tabbed or stacked title bar
+ if (on_titlebar) {
+ enum sway_container_layout layout = container_parent_layout(cont);
+ if (layout == L_TABBED || layout == L_STACKED) {
+ struct sway_node *active =
+ seat_get_active_tiling_child(seat, node_get_parent(node));
+ list_t *siblings = container_get_siblings(cont);
+ int desired = list_find(siblings, active->sway_container) +
+ event->delta_discrete;
+ if (desired < 0) {
+ desired = 0;
+ } else if (desired >= siblings->length) {
+ desired = siblings->length - 1;
+ }
+ struct sway_container *new_focus = siblings->items[desired];
+ node = seat_get_focus_inactive(seat, &new_focus->node);
+ seat_set_focus(seat, node);
+ return;
+ }
+ }
+
+ wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec,
+ event->orientation, event->delta, event->delta_discrete, event->source);
+}
+
static void handle_cursor_axis(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, axis);
wlr_idle_notify_activity(cursor->seat->input->server->idle, cursor->seat->wlr_seat);
struct wlr_event_pointer_axis *event = data;
- wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec,
- event->orientation, event->delta, event->delta_discrete, event->source);
+ dispatch_cursor_axis(cursor, event);
+ transaction_commit_dirty();
}
static void handle_touch_down(struct wl_listener *listener, void *data) {
@@ -965,8 +1006,7 @@ static void handle_touch_down(struct wl_listener *listener, void *data) {
if (seat_is_input_allowed(seat, surface)) {
wlr_seat_touch_notify_down(wlr_seat, surface, event->time_msec,
event->touch_id, sx, sy);
- cursor->image_client = NULL;
- wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0);
+ cursor_set_image(cursor, NULL, NULL);
}
}
@@ -1134,11 +1174,13 @@ static void handle_request_set_cursor(struct wl_listener *listener,
void cursor_set_image(struct sway_cursor *cursor, const char *image,
struct wl_client *client) {
- if (!cursor->image || strcmp(cursor->image, image) != 0) {
+ if (!image) {
+ wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0);
+ } else if (!cursor->image || strcmp(cursor->image, image) != 0) {
wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image,
cursor->cursor);
- cursor->image = image;
}
+ cursor->image = image;
cursor->image_client = client;
}
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
index b4352c6a..32f0355e 100644
--- a/sway/input/input-manager.c
+++ b/sway/input/input-manager.c
@@ -120,6 +120,13 @@ static void input_manager_libinput_config_pointer(
libinput_device_config_click_set_method(libinput_device,
ic->click_method);
}
+ if (ic->drag != INT_MIN) {
+ wlr_log(WLR_DEBUG,
+ "libinput_config_pointer(%s) tap_set_drag_enabled(%d)",
+ ic->identifier, ic->click_method);
+ libinput_device_config_tap_set_drag_enabled(libinput_device,
+ ic->drag);
+ }
if (ic->drag_lock != INT_MIN) {
wlr_log(WLR_DEBUG,
"libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)",
@@ -233,7 +240,8 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
wlr_log(WLR_DEBUG, "adding device: '%s'",
input_device->identifier);
- if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) {
+ if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER ||
+ input_device->wlr_device->type == WLR_INPUT_DEVICE_TABLET_TOOL) {
input_manager_libinput_config_pointer(input_device);
}
@@ -389,9 +397,12 @@ void input_manager_set_focus(struct sway_input_manager *input,
void input_manager_apply_input_config(struct sway_input_manager *input,
struct input_config *input_config) {
struct sway_input_device *input_device = NULL;
+ bool wildcard = strcmp(input_config->identifier, "*") == 0;
wl_list_for_each(input_device, &input->devices, link) {
- if (strcmp(input_device->identifier, input_config->identifier) == 0) {
- if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) {
+ if (strcmp(input_device->identifier, input_config->identifier) == 0
+ || wildcard) {
+ if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER ||
+ input_device->wlr_device->type == WLR_INPUT_DEVICE_TABLET_TOOL) {
input_manager_libinput_config_pointer(input_device);
}
@@ -480,13 +491,16 @@ struct sway_seat *input_manager_get_default_seat(
}
struct input_config *input_device_get_config(struct sway_input_device *device) {
+ struct input_config *wildcard_config = NULL;
struct input_config *input_config = NULL;
for (int i = 0; i < config->input_configs->length; ++i) {
input_config = config->input_configs->items[i];
if (strcmp(input_config->identifier, device->identifier) == 0) {
return input_config;
+ } else if (strcmp(input_config->identifier, "*") == 0) {
+ wildcard_config = input_config;
}
}
- return NULL;
+ return wildcard_config;
}
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 49fe46ba..4817eae7 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -348,17 +348,42 @@ struct sway_seat *seat_create(struct sway_input_manager *input,
seat->input = input;
wl_list_init(&seat->devices);
- wlr_seat_set_capabilities(seat->wlr_seat,
- WL_SEAT_CAPABILITY_KEYBOARD |
- WL_SEAT_CAPABILITY_POINTER |
- WL_SEAT_CAPABILITY_TOUCH);
-
-
wl_list_insert(&input->seats, &seat->link);
return seat;
}
+static void seat_update_capabilities(struct sway_seat *seat) {
+ uint32_t caps = 0;
+ struct sway_seat_device *seat_device;
+ wl_list_for_each(seat_device, &seat->devices, link) {
+ switch (seat_device->input_device->wlr_device->type) {
+ case WLR_INPUT_DEVICE_KEYBOARD:
+ caps |= WL_SEAT_CAPABILITY_KEYBOARD;
+ break;
+ case WLR_INPUT_DEVICE_POINTER:
+ caps |= WL_SEAT_CAPABILITY_POINTER;
+ break;
+ case WLR_INPUT_DEVICE_TOUCH:
+ caps |= WL_SEAT_CAPABILITY_TOUCH;
+ break;
+ case WLR_INPUT_DEVICE_TABLET_TOOL:
+ caps |= WL_SEAT_CAPABILITY_POINTER;
+ break;
+ case WLR_INPUT_DEVICE_TABLET_PAD:
+ break;
+ }
+ }
+ wlr_seat_set_capabilities(seat->wlr_seat, caps);
+
+ // Hide cursor if seat doesn't have pointer capability
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) == 0) {
+ cursor_set_image(seat->cursor, NULL, NULL);
+ } else {
+ cursor_set_image(seat->cursor, "left_ptr", NULL);
+ }
+}
+
static void seat_apply_input_config(struct sway_seat *seat,
struct sway_seat_device *sway_device) {
const char *mapped_to_output = NULL;
@@ -489,6 +514,8 @@ void seat_add_device(struct sway_seat *seat,
wl_list_insert(&seat->devices, &seat_device->link);
seat_configure_device(seat, input_device);
+
+ seat_update_capabilities(seat);
}
void seat_remove_device(struct sway_seat *seat,
@@ -503,6 +530,8 @@ void seat_remove_device(struct sway_seat *seat,
input_device->identifier, seat->wlr_seat->name);
seat_device_destroy(seat_device);
+
+ seat_update_capabilities(seat);
}
void seat_configure_xcursor(struct sway_seat *seat) {
@@ -532,8 +561,7 @@ void seat_configure_xcursor(struct sway_seat *seat) {
output->name, (double)output->scale);
}
- wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager,
- "left_ptr", seat->cursor->cursor);
+ cursor_set_image(seat->cursor, "left_ptr", NULL);
wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x,
seat->cursor->cursor->y);
}
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index f054ac9f..45915094 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -42,7 +42,7 @@ static const char *ipc_json_orientation_description(enum sway_container_layout l
return "none";
}
-json_object *ipc_json_get_version() {
+json_object *ipc_json_get_version(void) {
int major = 0, minor = 0, patch = 0;
json_object *version = json_object_new_object();
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 8ae265f6..2d915502 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -1,8 +1,5 @@
// See https://i3wm.org/docs/ipc.html for protocol information
-#ifndef __FreeBSD__
-// Any value will hide SOCK_CLOEXEC on FreeBSD (__BSD_VISIBLE=0)
-#define _XOPEN_SOURCE 700
-#endif
+#define _POSIX_C_SOURCE 200112L
#ifdef __linux__
#include <linux/input-event-codes.h>
#elif __FreeBSD__
@@ -89,10 +86,16 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
}
void ipc_init(struct sway_server *server) {
- ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
+ ipc_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (ipc_socket == -1) {
sway_abort("Unable to create IPC socket");
}
+ if (fcntl(ipc_socket, F_SETFD, FD_CLOEXEC) == -1) {
+ sway_abort("Unable to set CLOEXEC on IPC socket");
+ }
+ if (fcntl(ipc_socket, F_SETFL, O_NONBLOCK) == -1) {
+ sway_abort("Unable to set NONBLOCK on IPC socket");
+ }
ipc_sockaddr = ipc_user_sockaddr();
@@ -580,7 +583,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
switch (client->current_command) {
case IPC_COMMAND:
{
- struct cmd_results *results = execute_command(buf, NULL);
+ struct cmd_results *results = execute_command(buf, NULL, NULL);
transaction_commit_dirty();
char *json = cmd_results_to_json(results);
int length = strlen(json);
diff --git a/sway/main.c b/sway/main.c
index fb4f0d8c..dea4a31c 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -12,10 +12,6 @@
#include <sys/wait.h>
#include <sys/un.h>
#include <unistd.h>
-#ifdef __linux__
-#include <sys/capability.h>
-#include <sys/prctl.h>
-#endif
#include <wlr/util/log.h>
#include "sway/commands.h"
#include "sway/config.h"
@@ -45,7 +41,7 @@ void sig_handler(int signal) {
sway_terminate(EXIT_SUCCESS);
}
-void detect_raspi() {
+void detect_raspi(void) {
bool raspi = false;
FILE *f = fopen("/sys/firmware/devicetree/base/model", "r");
if (!f) {
@@ -85,7 +81,7 @@ void detect_raspi() {
}
}
-void detect_proprietary() {
+void detect_proprietary(void) {
FILE *f = fopen("/proc/modules", "r");
if (!f) {
return;
@@ -120,7 +116,7 @@ void run_as_ipc_client(char *command, char *socket_path) {
close(socketfd);
}
-static void log_env() {
+static void log_env(void) {
const char *log_vars[] = {
"PATH",
"LD_LIBRARY_PATH",
@@ -135,7 +131,7 @@ static void log_env() {
}
}
-static void log_distro() {
+static void log_distro(void) {
const char *paths[] = {
"/etc/lsb-release",
"/etc/os-release",
@@ -162,7 +158,7 @@ static void log_distro() {
}
}
-static void log_kernel() {
+static void log_kernel(void) {
FILE *f = popen("uname -a", "r");
if (!f) {
wlr_log(WLR_INFO, "Unable to determine kernel version");
@@ -181,28 +177,8 @@ static void log_kernel() {
pclose(f);
}
-static void executable_sanity_check() {
-#ifdef __linux__
- struct stat sb;
- char *exe = realpath("/proc/self/exe", NULL);
- 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(WLR_ERROR,
- "sway executable has both the s(g)uid bit AND file caps set.");
- wlr_log(WLR_ERROR,
- "This is strongly discouraged (and completely broken).");
- wlr_log(WLR_ERROR,
- "Please clear one of them (either the suid bit, or the file caps).");
- wlr_log(WLR_ERROR,
- "If unsure, strip the file caps.");
- exit(EXIT_FAILURE);
- }
- free(exe);
-#endif
-}
-static void drop_permissions(bool keep_caps) {
+static void drop_permissions(void) {
if (getuid() != geteuid() || getgid() != getegid()) {
if (setgid(getgid()) != 0) {
wlr_log(WLR_ERROR, "Unable to drop root");
@@ -217,20 +193,6 @@ static void drop_permissions(bool keep_caps) {
wlr_log(WLR_ERROR, "Root privileges can be restored.");
exit(EXIT_FAILURE);
}
-#ifdef __linux__
- if (keep_caps) {
- // Drop every cap except CAP_SYS_PTRACE
- cap_t caps = cap_init();
- cap_value_t keep = CAP_SYS_PTRACE;
- 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(WLR_ERROR, "Failed to drop extra capabilities");
- exit(EXIT_FAILURE);
- }
- }
-#endif
}
void enable_debug_flag(const char *flag) {
@@ -279,14 +241,6 @@ int main(int argc, char **argv) {
" --get-socketpath Gets the IPC socket path and prints it, then exits.\n"
"\n";
- // Security:
- unsetenv("LD_PRELOAD");
-#ifdef _LD_LIBRARY_PATH
- setenv("LD_LIBRARY_PATH", _LD_LIBRARY_PATH, 1);
-#else
- unsetenv("LD_LIBRARY_PATH");
-#endif
-
int c;
while (1) {
int option_index = 0;
@@ -347,7 +301,7 @@ int main(int argc, char **argv) {
wlr_log(WLR_ERROR, "Don't use options with the IPC client");
exit(EXIT_FAILURE);
}
- drop_permissions(false);
+ drop_permissions();
char *socket_path = getenv("SWAYSOCK");
if (!socket_path) {
wlr_log(WLR_ERROR, "Unable to retrieve socket path");
@@ -358,34 +312,17 @@ int main(int argc, char **argv) {
return 0;
}
- executable_sanity_check();
- bool suid = false;
-
if (!server_privileged_prepare(&server)) {
return 1;
}
-#if defined(__linux__) || defined(__FreeBSD__)
- if (getuid() != geteuid() || getgid() != getegid()) {
-#ifdef __linux__
- // Retain capabilities after setuid()
- if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
- wlr_log(WLR_ERROR, "Cannot keep caps after setuid()");
- exit(EXIT_FAILURE);
- }
-#endif
- suid = true;
- }
-#endif
-
log_kernel();
log_distro();
detect_proprietary();
detect_raspi();
-#if defined(__linux__) || defined(__FreeBSD__)
- drop_permissions(suid);
-#endif
+ drop_permissions();
+
// handle SIGTERM signals
signal(SIGTERM, sig_handler);
@@ -424,11 +361,12 @@ int main(int argc, char **argv) {
}
config->active = true;
+ load_swaybars();
// Execute commands until there are none left
wlr_log(WLR_DEBUG, "Running deferred commands");
while (config->cmd_queue->length) {
char *line = config->cmd_queue->items[0];
- struct cmd_results *res = execute_command(line, NULL);
+ struct cmd_results *res = execute_command(line, NULL, NULL);
if (res->status != CMD_SUCCESS) {
wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error);
}
diff --git a/sway/meson.build b/sway/meson.build
index d67a4c64..6eb9a9d7 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -119,6 +119,7 @@ sway_sources = files(
'commands/input/accel_profile.c',
'commands/input/click_method.c',
+ 'commands/input/drag.c',
'commands/input/drag_lock.c',
'commands/input/dwt.c',
'commands/input/events.c',
@@ -164,7 +165,6 @@ sway_deps = [
cairo,
gdk_pixbuf,
jsonc,
- libcap,
libinput,
math,
pango,
@@ -187,5 +187,6 @@ executable(
include_directories: [sway_inc],
dependencies: sway_deps,
link_with: [lib_sway_common],
+ install_rpath : rpathdir,
install: true
)
diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd
index a61e2829..00b9386e 100644
--- a/sway/sway-bar.5.scd
+++ b/sway/sway-bar.5.scd
@@ -6,8 +6,7 @@ sway-bar - bar configuration file and commands
# DESCRIPTION
-Sway allows configuring swaybar in the sway configuration file. Swaybar
-commands must be used inside a _bar { }_ block in the config file.
+Sway allows configuring swaybar in the sway configuration file.
# COMMANDS
diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd
index 707c36af..14f2a007 100644
--- a/sway/sway-input.5.scd
+++ b/sway/sway-input.5.scd
@@ -7,7 +7,6 @@ sway-input - input configuration file and commands
# DESCRIPTION
Sway allows for configuration of devices within the sway configuration file.
-sway-input commands must be used inside an _input { }_ block in the config.
To obtain a list of available device identifiers, run *swaymsg -t get\_inputs*.
# INPUT COMMANDS
@@ -68,6 +67,9 @@ The following commands may only be used in the configuration file.
*input* <identifier> click\_method none|button\_areas|clickfinger
Changes the click method for the specified device.
+*input* <identifier> drag enabled|disabled
+ Enables or disables tap-and-drag for specified input device.
+
*input* <identifier> drag\_lock enabled|disabled
Enables or disables drag lock for specified input device.
@@ -116,8 +118,7 @@ The following commands may only be used in the configuration file.
## SEAT CONFIGURATION
-Configure options for multiseat mode. sway-seat commands must be used inside a
-_seat { }_ block in the config.
+Configure options for multiseat mode.
A *seat* is a collection of input devices that act independently of each other.
Seats are identified by name and the default seat is _seat0_ if no seats are
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index 927bf55c..aa5b38ab 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -19,6 +19,24 @@ bindsym Shift+XF86AudioRaiseVolume exec \\
pactl set-sink-volume @DEFAULT_SINK@ -1%
```
+Commands can also be given as a block in the form *command { <subcommands...>
+}*. Anything before the opening *{* will be prepended to the lines inside the
+block. For example:
+
+```
+output eDP-1 {
+ background ~/wallpaper.png
+ resolution 1920x1080
+}
+```
+
+is identical to
+
+```
+output eDP-1 background ~/wallpaper.png
+output eDP-1 resolution 1920x1080
+```
+
These commands can be executed in your config file, via *swaymsg*(1), or via
the bindsym command.
@@ -37,10 +55,8 @@ which you may only select one. *[...]* is used for optional arguments, and
The following commands may only be used in the configuration file.
-*bar {* <commands...> *}*
- _commands..._ after *{* will be interpreted as bar commands. For
- details, see *sway-bar*(5). A newline is required between *{* and the
- first command, and *}* must be alone on a line.
+*bar* [<bar-id>] <bar-subcommands...>
+ For details on bar subcommands, see *sway-bar*(5).
*default\_orientation* horizontal|vertical|auto
Sets the default container layout for tiled containers.
@@ -51,10 +67,6 @@ The following commands may only be used in the configuration file.
*wordexp*(3) for details). The same include file can only be included once;
subsequent attempts will be ignored.
-*set* $<name> <value>
- Sets variable $_name_ to _value_. You can use the new variable in the
- arguments of future commands.
-
*swaybg\_command* <command>
Executes custom background _command_. Default is _swaybg_. Refer to
*output* below for more information.
@@ -407,37 +419,30 @@ The default colors are:
inner gap is nonzero. When _off_, gaps will only be added between views.
_toggle_ cannot be used in the configuration file.
-*gaps* <amount>
- Sets _amount_ pixels of gap between windows and around each workspace.
-
*gaps* inner|outer <amount>
- Sets default _amount_ pixels of _inner_ or _outer_ gap, where the former
- affects spacing between views and the latter affects the space around each
- workspace.
+ Sets default _amount_ pixels of _inner_ or _outer_ gap, where the inner
+ affects spacing around each view and outer affects the spacing around each
+ workspace. Outer gaps are in addition to inner gaps.
+
+ This affects new workspaces only, and is used when the workspace doesn't
+ have its own gaps settings (see: workspace <ws> gaps inner|outer <amount>).
-*gaps* inner|outer all|workspace|current set|plus|minus <amount>
- Changes the gaps for the _inner_ or _outer_ gap. _all_ changes the gaps for
- all views or workspace, _workspace_ changes gaps for all views in current
- workspace (or current workspace), and _current_ changes gaps for the current
- view or workspace.
+*gaps* inner|outer all|current set|plus|minus <amount>
+ Changes the _inner_ or _outer_ gaps for either _all_ workspaces or the
+ _current_ workspace.
*hide\_edge\_borders* none|vertical|horizontal|both|smart
Hides window borders adjacent to the screen edges. Default is _none_.
-*input* <input\_device> *{* <commands...> *}*
- _commands..._ after *{* will be interpreted as input commands applying to
- the specified input device. For details, see *sway-input*(5). A newline is
- required between *{* and the first command, and *}* must be alone on a
- line.
+*input* <input\_device> <input-subcommands...>
+ For details on input subcommands, see *sway-input*(5).
\* may be used in lieu of a specific device name to configure all input
devices. A list of input device names may be obtained via *swaymsg -t
get\_inputs*.
-*seat* <seat> *{* <commands...> *}*
- _commands..._ after *{* will be interpreted as seat commands applying to
- the specified seat. For details, see *sway-input*(5). A newline is required
- between *{* and the first command, and *}* must be alone on a line.
+*seat* <seat> <seat-subcommands...>
+ For details on seat subcommands, see *sway-input*(5).
*seat* <seat> cursor move|set <x> <y>
Move specified seat's cursor relative to current position or wrap to
@@ -465,10 +470,8 @@ The default colors are:
*mode* <mode>
Switches to the specified mode. The default mode _default_.
-*mode* [--pango\_markup] <mode> *{* <commands...> *}*
- _commands..._ after *{* will be added to the specified mode. A newline is
- required between *{* and the first command, and *}* must be alone on a
- line. Only *bindsym* and *bindcode* commands are permitted in mode blocks.
+*mode* [--pango\_markup] <mode> <mode-subcommands...>
+ The only two valid _mode-subcommands..._ are *bindsym* and *bindcode*.
If _--pango\_markup_ is given, then _mode_ will be interpreted as pango
markup.
@@ -533,8 +536,15 @@ You may combine output commands into one, like so:
output HDMI-A-1 mode 1920x1080 pos 1920,0 bg ~/wallpaper.png stretch
You can get a list of output names with *swaymsg -t get\_outputs*. You may also
-match any output by using the output name "\*". Be sure to add this output
-config after the others, or it will be matched instead of the others.
+match any output by using the output name "\*".
+
+*set* $<name> <value>
+ Sets variable $_name_ to _value_. You can use the new variable in the
+ arguments of future commands. When the variable is used, it can be escaped
+ with an additional $ (ie $$_name_) to have the replacement happen at run
+ time instead of when reading the config. However, it does not always make
+ sense for the variable to be replaced at run time since some arguments do
+ need to be known at config time.
*show\_marks* yes|no
If *show\_marks* is yes, marks will be displayed in the window borders.
@@ -568,6 +578,10 @@ config after the others, or it will be matched instead of the others.
*workspace* back_and_forth
Switches to the previously focused workspace.
+*workspace* <name> gaps inner|outer <amount>
+ Specifies that workspace _name_ should have the given gaps settings when it
+ is created.
+
*workspace* <name> output <output>
Specifies that workspace _name_ should be shown on the specified _output_.
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index d50be25d..373460a2 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -186,6 +186,7 @@ void arrange_workspace(struct sway_workspace *workspace) {
area->width, area->height, area->x, area->y);
workspace_remove_gaps(workspace);
+ bool first_arrange = workspace->width == 0 && workspace->height == 0;
double prev_x = workspace->x;
double prev_y = workspace->y;
workspace->width = area->width;
@@ -196,7 +197,7 @@ void arrange_workspace(struct sway_workspace *workspace) {
// Adjust any floating containers
double diff_x = workspace->x - prev_x;
double diff_y = workspace->y - prev_y;
- if (diff_x != 0 || diff_y != 0) {
+ if (!first_arrange && (diff_x != 0 || diff_y != 0)) {
for (int i = 0; i < workspace->floating->length; ++i) {
struct sway_container *floater = workspace->floating->items[i];
container_floating_translate(floater, diff_x, diff_y);
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 47687744..788300cc 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -67,12 +67,10 @@ void container_destroy(struct sway_container *con) {
list_free(con->outputs);
if (con->view) {
- struct sway_view *view = con->view;
- view->container = NULL;
- free(view->title_format);
- view->title_format = NULL;
-
- if (view->destroying) {
+ if (con->view->container == con) {
+ con->view->container = NULL;
+ }
+ if (con->view->destroying) {
view_destroy(con->view);
}
}
@@ -215,8 +213,7 @@ static struct sway_container *container_at_tabbed(struct sway_node *parent,
child_index = children->length - 1;
}
struct sway_container *child = children->items[child_index];
- struct sway_node *node = seat_get_focus_inactive(seat, &child->node);
- return node->sway_container;
+ return child;
}
// Surfaces
@@ -243,8 +240,7 @@ static struct sway_container *container_at_stacked(struct sway_node *parent,
int child_index = (ly - box.y) / title_height;
if (child_index < children->length) {
struct sway_container *child = children->items[child_index];
- struct sway_node *node = seat_get_focus_inactive(seat, &child->node);
- return node->sway_container;
+ return child;
}
// Surfaces
@@ -465,11 +461,17 @@ static void update_title_texture(struct sway_container *con,
cairo_surface_t *surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, width, height);
cairo_t *cairo = cairo_create(surface);
+ cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
+ cairo_font_options_t *fo = cairo_font_options_create();
+ cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
+ cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
+ cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(output->wlr_output->subpixel));
+ cairo_set_font_options(cairo, fo);
+ cairo_font_options_destroy(fo);
cairo_set_source_rgba(cairo, class->background[0], class->background[1],
class->background[2], class->background[3]);
cairo_paint(cairo);
PangoContext *pango = pango_cairo_create_context(cairo);
- cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
cairo_set_source_rgba(cairo, class->text[0], class->text[1],
class->text[2], class->text[3]);
cairo_move_to(cairo, 0, 0);
@@ -591,7 +593,7 @@ void container_update_representation(struct sway_container *con) {
}
}
-size_t container_titlebar_height() {
+size_t container_titlebar_height(void) {
return config->font_height + TITLEBAR_V_PADDING * 2;
}
@@ -821,9 +823,16 @@ void container_floating_move_to_center(struct sway_container *con) {
return;
}
struct sway_workspace *ws = con->workspace;
+ bool full = con->is_fullscreen;
+ if (full) {
+ container_set_fullscreen(con, false);
+ }
double new_lx = ws->x + (ws->width - con->width) / 2;
double new_ly = ws->y + (ws->height - con->height) / 2;
container_floating_translate(con, new_lx - con->x, new_ly - con->y);
+ if (full) {
+ container_set_fullscreen(con, true);
+ }
}
static bool find_urgent_iterator(struct sway_container *con, void *data) {
@@ -981,7 +990,8 @@ void container_discover_outputs(struct sway_container *con) {
}
}
struct sway_output *new_output = container_get_effective_output(con);
- double old_scale = old_output ? old_output->wlr_output->scale : -1;
+ double old_scale = old_output && old_output->enabled ?
+ old_output->wlr_output->scale : -1;
double new_scale = new_output ? new_output->wlr_output->scale : -1;
if (old_scale != new_scale) {
container_update_title_textures(con);
@@ -1019,7 +1029,7 @@ void container_add_gaps(struct sway_container *c) {
struct sway_workspace *ws = c->workspace;
- c->current_gaps = ws->has_gaps ? ws->gaps_inner : config->gaps_inner;
+ c->current_gaps = ws->gaps_inner;
c->x += c->current_gaps;
c->y += c->current_gaps;
c->width -= 2 * c->current_gaps;
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 1976ad51..c3176325 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -109,12 +109,24 @@ void output_enable(struct sway_output *output, struct output_config *oc) {
wl_signal_emit(&root->events.new_node, &output->node);
- load_swaybars();
-
arrange_layers(output);
arrange_root();
}
+static void evacuate_sticky(struct sway_workspace *old_ws,
+ struct sway_output *new_output) {
+ struct sway_workspace *new_ws = output_get_active_workspace(new_output);
+ while (old_ws->floating->length) {
+ struct sway_container *sticky = old_ws->floating->items[0];
+ container_detach(sticky);
+ workspace_add_floating(new_ws, sticky);
+ container_handle_fullscreen_reparent(sticky);
+ container_floating_move_to_center(sticky);
+ ipc_event_window(sticky, "move");
+ }
+ workspace_detect_urgent(new_ws);
+}
+
static void output_evacuate(struct sway_output *output) {
if (!output->workspaces->length) {
return;
@@ -132,17 +144,21 @@ static void output_evacuate(struct sway_output *output) {
workspace_detach(workspace);
- if (workspace_is_empty(workspace)) {
- workspace_begin_destroy(workspace);
- continue;
- }
-
struct sway_output *new_output =
workspace_output_get_highest_available(workspace, output);
if (!new_output) {
new_output = fallback_output;
}
+ if (workspace_is_empty(workspace)) {
+ // If floating is not empty, there are sticky containers to move
+ if (workspace->floating->length) {
+ evacuate_sticky(workspace, new_output);
+ }
+ workspace_begin_destroy(workspace);
+ continue;
+ }
+
if (new_output) {
workspace_output_add_priority(workspace, new_output);
output_add_workspace(new_output, workspace);
diff --git a/sway/tree/root.c b/sway/tree/root.c
index ecc04ddb..6748e9c9 100644
--- a/sway/tree/root.c
+++ b/sway/tree/root.c
@@ -265,14 +265,20 @@ void root_for_each_container(void (*f)(struct sway_container *con, void *data),
// Scratchpad
for (int i = 0; i < root->scratchpad->length; ++i) {
struct sway_container *container = root->scratchpad->items[i];
- // If the container has a parent then it's visible on a workspace
+ // If the container has a workspace then it's visible on a workspace
// and will have been iterated in the previous for loop. So we only
// iterate the hidden scratchpad containers here.
- if (!container->parent) {
+ if (!container->workspace) {
f(container, data);
container_for_each_child(container, f, data);
}
}
+
+ // Saved workspaces
+ for (int i = 0; i < root->saved_workspaces->length; ++i) {
+ struct sway_workspace *ws = root->saved_workspaces->items[i];
+ workspace_for_each_container(ws, f, data);
+ }
}
struct sway_output *root_find_output(
@@ -311,7 +317,7 @@ struct sway_container *root_find_container(
// Scratchpad
for (int i = 0; i < root->scratchpad->length; ++i) {
struct sway_container *container = root->scratchpad->items[i];
- if (!container->parent) {
+ if (!container->workspace) {
if (test(container, data)) {
return container;
}
@@ -320,6 +326,15 @@ struct sway_container *root_find_container(
}
}
}
+
+ // Saved workspaces
+ for (int i = 0; i < root->saved_workspaces->length; ++i) {
+ struct sway_workspace *ws = root->saved_workspaces->items[i];
+ if ((result = workspace_find_container(ws, test, data))) {
+ return result;
+ }
+ }
+
return NULL;
}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 4398f518..a024f325 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -391,8 +391,6 @@ static bool view_has_executed_criteria(struct sway_view *view,
}
void view_execute_criteria(struct sway_view *view) {
- struct sway_seat *seat = input_manager_current_seat(input_manager);
- struct sway_node *prior_focus = seat_get_focus(seat);
list_t *criterias = criteria_for_view(view, CT_COMMAND);
for (int i = 0; i < criterias->length; i++) {
struct criteria *criteria = criterias->items[i];
@@ -403,16 +401,12 @@ void view_execute_criteria(struct sway_view *view) {
}
wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'",
criteria->raw, view, criteria->cmdlist);
- seat_set_focus_container(seat, view->container);
list_add(view->executed_criteria, criteria);
- struct cmd_results *res = execute_command(criteria->cmdlist, NULL);
- if (res->status != CMD_SUCCESS) {
- wlr_log(WLR_ERROR, "Command '%s' failed: %s", res->input, res->error);
- }
+ struct cmd_results *res = execute_command(
+ criteria->cmdlist, NULL, view->container);
free_cmd_results(res);
}
list_free(criterias);
- seat_set_focus(seat, prior_focus);
}
static struct sway_workspace *select_workspace(struct sway_view *view) {
@@ -785,14 +779,9 @@ static size_t parse_title_format(struct sway_view *view, char *buffer) {
}
static char *escape_title(char *buffer) {
- int length = escape_markup_text(buffer, NULL, 0);
+ size_t length = escape_markup_text(buffer, NULL);
char *escaped_title = calloc(length + 1, sizeof(char));
- int result = escape_markup_text(buffer, escaped_title, length);
- if (result != length) {
- wlr_log(WLR_ERROR, "Could not escape title: %s", buffer);
- free(escaped_title);
- return buffer;
- }
+ escape_markup_text(buffer, escaped_title);
free(buffer);
return escaped_title;
}
@@ -1000,12 +989,16 @@ bool view_is_visible(struct sway_view *view) {
floater = floater->parent;
}
bool is_sticky = container_is_floating(floater) && floater->is_sticky;
+ if (!is_sticky && !workspace_is_visible(workspace)) {
+ return false;
+ }
// Check view isn't in a tabbed or stacked container on an inactive tab
struct sway_seat *seat = input_manager_current_seat(input_manager);
struct sway_container *con = view->container;
while (con) {
enum sway_container_layout layout = container_parent_layout(con);
- if (layout == L_TABBED || layout == L_STACKED) {
+ if ((layout == L_TABBED || layout == L_STACKED)
+ && !container_is_floating(con)) {
struct sway_node *parent = con->parent ?
&con->parent->node : &con->workspace->node;
if (seat_get_active_tiling_child(seat, parent) != &con->node) {
@@ -1019,10 +1012,6 @@ bool view_is_visible(struct sway_view *view) {
!container_is_fullscreen_or_child(view->container)) {
return false;
}
- // Check the workspace is visible
- if (!is_sticky) {
- return workspace_is_visible(workspace);
- }
return true;
}
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 18746430..9dd5c815 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -20,17 +20,23 @@
#include "log.h"
#include "util.h"
+struct workspace_config *workspace_find_config(const char *ws_name) {
+ for (int i = 0; i < config->workspace_configs->length; ++i) {
+ struct workspace_config *wsc = config->workspace_configs->items[i];
+ if (strcmp(wsc->workspace, ws_name) == 0) {
+ return wsc;
+ }
+ }
+ return NULL;
+}
+
struct sway_output *workspace_get_initial_output(const char *name) {
- // Search for workspace<->output pair
- for (int i = 0; i < config->workspace_outputs->length; ++i) {
- struct workspace_output *wso = config->workspace_outputs->items[i];
- if (strcasecmp(wso->workspace, name) == 0) {
- // Find output to use if it exists
- struct sway_output *output = output_by_name(wso->output);
- if (output) {
- return output;
- }
- break;
+ // Check workspace configs for a workspace<->output pair
+ struct workspace_config *wsc = workspace_find_config(name);
+ if (wsc && wsc->output) {
+ struct sway_output *output = output_by_name(wsc->output);
+ if (output) {
+ return output;
}
}
// Otherwise put it on the focused output
@@ -54,10 +60,6 @@ struct sway_workspace *workspace_create(struct sway_output *output,
return NULL;
}
node_init(&ws->node, N_WORKSPACE, ws);
- ws->x = output->lx;
- ws->y = output->ly;
- ws->width = output->width;
- ws->height = output->height;
ws->name = name ? strdup(name) : NULL;
ws->prev_split_layout = L_NONE;
ws->layout = output_get_default_layout(output);
@@ -66,6 +68,20 @@ struct sway_workspace *workspace_create(struct sway_output *output,
ws->output_priority = create_list();
workspace_output_add_priority(ws, output);
+ ws->gaps_outer = config->gaps_outer;
+ ws->gaps_inner = config->gaps_inner;
+ if (name) {
+ struct workspace_config *wsc = workspace_find_config(name);
+ if (wsc) {
+ if (wsc->gaps_outer != -1) {
+ ws->gaps_outer = wsc->gaps_outer;
+ }
+ if (wsc->gaps_inner != -1) {
+ ws->gaps_inner = wsc->gaps_inner;
+ }
+ }
+ }
+
output_add_workspace(output, ws);
output_sort_workspaces(output);
@@ -125,17 +141,8 @@ void next_name_map(struct sway_container *ws, void *data) {
static bool workspace_valid_on_output(const char *output_name,
const char *ws_name) {
- int i;
- for (i = 0; i < config->workspace_outputs->length; ++i) {
- struct workspace_output *wso = config->workspace_outputs->items[i];
- if (strcasecmp(wso->workspace, ws_name) == 0) {
- if (strcasecmp(wso->output, output_name) != 0) {
- return false;
- }
- }
- }
-
- return true;
+ struct workspace_config *wsc = workspace_find_config(ws_name);
+ return !wsc || !wsc->output || strcmp(wsc->output, output_name) == 0;
}
static void workspace_name_from_binding(const struct sway_binding * binding,
@@ -235,13 +242,13 @@ char *workspace_next_name(const char *output_name) {
workspace_name_from_binding(mode->keycode_bindings->items[i],
output_name, &order, &target);
}
- for (int i = 0; i < config->workspace_outputs->length; ++i) {
+ for (int i = 0; i < config->workspace_configs->length; ++i) {
// Unlike with bindings, this does not guarantee order
- const struct workspace_output *wso = config->workspace_outputs->items[i];
- if (strcmp(wso->output, output_name) == 0
- && workspace_by_name(wso->workspace) == NULL) {
+ const struct workspace_config *wsc = config->workspace_configs->items[i];
+ if (wsc->output && strcmp(wsc->output, output_name) == 0
+ && workspace_by_name(wsc->workspace) == NULL) {
free(target);
- target = strdup(wso->workspace);
+ target = strdup(wsc->workspace);
break;
}
}
@@ -389,13 +396,11 @@ bool workspace_switch(struct sway_workspace *workspace,
struct sway_output *next_output = workspace->output;
struct sway_workspace *next_output_prev_ws =
output_get_active_workspace(next_output);
- bool has_sticky = false;
if (workspace != next_output_prev_ws) {
for (int i = 0; i < next_output_prev_ws->floating->length; ++i) {
struct sway_container *floater =
next_output_prev_ws->floating->items[i];
if (floater->is_sticky) {
- has_sticky = true;
container_detach(floater);
workspace_add_floating(workspace, floater);
if (&floater->node == focus) {
@@ -414,14 +419,6 @@ bool workspace_switch(struct sway_workspace *workspace,
if (next == NULL) {
next = &workspace->node;
}
- if (has_sticky) {
- // If there's a sticky container, we might be setting focus to the same
- // container that's already focused, so seat_set_focus is effectively a
- // no op. We therefore need to send the IPC event and clean up the old
- // workspace here.
- ipc_event_workspace(active_ws, workspace, "focus");
- workspace_consider_destroy(active_ws);
- }
seat_set_focus(seat, next);
arrange_workspace(workspace);
cursor_send_pointer_motion(seat->cursor, 0, true);
@@ -649,13 +646,13 @@ void workspace_add_gaps(struct sway_workspace *ws) {
return;
}
- ws->current_gaps = ws->has_gaps ? ws->gaps_outer : config->gaps_outer;
+ ws->current_gaps = ws->gaps_outer;
if (ws->layout == L_TABBED || ws->layout == L_STACKED) {
// We have to add inner gaps for this, because children of tabbed and
// stacked containers don't apply their own gaps - they assume the
// tabbed/stacked container is using gaps.
- ws->current_gaps += ws->has_gaps ? ws->gaps_inner : config->gaps_inner;
+ ws->current_gaps += ws->gaps_inner;
}
ws->x += ws->current_gaps;
diff --git a/swaybar/bar.c b/swaybar/bar.c
index 3ae730f7..388c24c4 100644
--- a/swaybar/bar.c
+++ b/swaybar/bar.c
@@ -16,12 +16,13 @@
#else
#include <linux/input-event-codes.h>
#endif
-#include "swaybar/render.h"
+#include "swaybar/bar.h"
#include "swaybar/config.h"
#include "swaybar/event_loop.h"
-#include "swaybar/status_line.h"
-#include "swaybar/bar.h"
+#include "swaybar/i3bar.h"
#include "swaybar/ipc.h"
+#include "swaybar/status_line.h"
+#include "swaybar/render.h"
#include "ipc-client.h"
#include "list.h"
#include "log.h"
@@ -48,8 +49,13 @@ static void swaybar_output_free(struct swaybar_output *output) {
return;
}
wlr_log(WLR_DEBUG, "Removing output %s", output->name);
- zwlr_layer_surface_v1_destroy(output->layer_surface);
- wl_surface_destroy(output->surface);
+ if (output->layer_surface != NULL) {
+ zwlr_layer_surface_v1_destroy(output->layer_surface);
+ }
+ if (output->surface != NULL) {
+ wl_surface_destroy(output->surface);
+ }
+ zxdg_output_v1_destroy(output->xdg_output);
wl_output_destroy(output->output);
destroy_buffer(&output->buffers[0]);
destroy_buffer(&output->buffers[1]);
@@ -66,6 +72,16 @@ static void swaybar_output_free(struct swaybar_output *output) {
free(output);
}
+static void set_output_dirty(struct swaybar_output *output) {
+ if (output->frame_scheduled) {
+ output->dirty = true;
+ return;
+ }
+ if (output->surface) {
+ render_frame(output);
+ }
+}
+
static void layer_surface_configure(void *data,
struct zwlr_layer_surface_v1 *surface,
uint32_t serial, uint32_t width, uint32_t height) {
@@ -73,7 +89,7 @@ static void layer_surface_configure(void *data,
output->width = width;
output->height = height;
zwlr_layer_surface_v1_ack_configure(surface, serial);
- render_frame(output->bar, output);
+ set_output_dirty(output);
}
static void layer_surface_closed(void *_output,
@@ -283,28 +299,58 @@ const struct wl_seat_listener seat_listener = {
.name = seat_handle_name,
};
-static void output_geometry(void *data, struct wl_output *output, int32_t x,
+static void add_layer_surface(struct swaybar_output *output) {
+ if (output->surface != NULL) {
+ return;
+ }
+ struct swaybar *bar = output->bar;
+
+ output->surface = wl_compositor_create_surface(bar->compositor);
+ assert(output->surface);
+ output->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
+ bar->layer_shell, output->surface, output->output,
+ ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel");
+ assert(output->layer_surface);
+ zwlr_layer_surface_v1_add_listener(output->layer_surface,
+ &layer_surface_listener, output);
+ zwlr_layer_surface_v1_set_anchor(output->layer_surface,
+ bar->config->position);
+}
+
+static bool bar_uses_output(struct swaybar *bar, const char *name) {
+ if (bar->config->all_outputs) {
+ return true;
+ }
+ struct config_output *coutput;
+ wl_list_for_each(coutput, &bar->config->outputs, link) {
+ if (strcmp(coutput->name, name) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void output_geometry(void *data, struct wl_output *wl_output, int32_t x,
int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel,
const char *make, const char *model, int32_t transform) {
- // Who cares
+ struct swaybar_output *output = data;
+ output->subpixel = subpixel;
}
-static void output_mode(void *data, struct wl_output *output, uint32_t flags,
+static void output_mode(void *data, struct wl_output *wl_output, uint32_t flags,
int32_t width, int32_t height, int32_t refresh) {
// Who cares
}
-static void output_done(void *data, struct wl_output *output) {
- // Who cares
+static void output_done(void *data, struct wl_output *wl_output) {
+ struct swaybar_output *output = data;
+ set_output_dirty(output);
}
static void output_scale(void *data, struct wl_output *wl_output,
int32_t factor) {
struct swaybar_output *output = data;
output->scale = factor;
- if (output->surface) {
- render_frame(output->bar, output);
- }
}
struct wl_output_listener output_listener = {
@@ -326,7 +372,22 @@ static void xdg_output_handle_logical_size(void *data,
static void xdg_output_handle_done(void *data,
struct zxdg_output_v1 *xdg_output) {
- // Who cares
+ struct swaybar_output *output = data;
+ struct swaybar *bar = output->bar;
+
+ assert(output->name != NULL);
+ if (!bar_uses_output(bar, output->name)) {
+ swaybar_output_free(output);
+ return;
+ }
+
+ if (wl_list_empty(&output->link)) {
+ wl_list_remove(&output->link);
+ wl_list_insert(&bar->outputs, &output->link);
+
+ add_layer_surface(output);
+ set_output_dirty(output);
+ }
}
static void xdg_output_handle_name(void *data,
@@ -349,17 +410,15 @@ struct zxdg_output_v1_listener xdg_output_listener = {
.description = xdg_output_handle_description,
};
-static bool bar_uses_output(struct swaybar *bar, const char *name) {
- if (bar->config->all_outputs) {
- return true;
- }
- struct config_output *coutput;
- wl_list_for_each(coutput, &bar->config->outputs, link) {
- if (strcmp(coutput->name, name) == 0) {
- return true;
- }
+static void add_xdg_output(struct swaybar_output *output) {
+ if (output->xdg_output != NULL) {
+ return;
}
- return false;
+ assert(output->bar->xdg_output_manager != NULL);
+ output->xdg_output = zxdg_output_manager_v1_get_xdg_output(
+ output->bar->xdg_output_manager, output->output);
+ zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener,
+ output);
}
static void handle_global(void *data, struct wl_registry *registry,
@@ -386,7 +445,10 @@ static void handle_global(void *data, struct wl_registry *registry,
output->wl_name = name;
wl_list_init(&output->workspaces);
wl_list_init(&output->hotspots);
- wl_list_insert(&bar->outputs, &output->link);
+ wl_list_init(&output->link);
+ if (bar->xdg_output_manager != NULL) {
+ add_xdg_output(output);
+ }
} else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
bar->layer_shell = wl_registry_bind(
registry, name, &zwlr_layer_shell_v1_interface, 1);
@@ -413,21 +475,23 @@ static const struct wl_registry_listener registry_listener = {
.global_remove = handle_global_remove,
};
-static void render_all_frames(struct swaybar *bar) {
+static void set_bar_dirty(struct swaybar *bar) {
struct swaybar_output *output;
wl_list_for_each(output, &bar->outputs, link) {
- render_frame(bar, output);
+ set_output_dirty(output);
}
}
-void bar_setup(struct swaybar *bar,
+bool bar_setup(struct swaybar *bar,
const char *socket_path, const char *bar_id) {
bar_init(bar);
init_event_loop();
bar->ipc_socketfd = ipc_open_socket(socket_path);
bar->ipc_event_socketfd = ipc_open_socket(socket_path);
- ipc_initialize(bar, bar_id);
+ if (!ipc_initialize(bar, bar_id)) {
+ return false;
+ }
if (bar->config->status_command) {
bar->status = status_line_init(bar->config->status_command);
}
@@ -443,23 +507,10 @@ void bar_setup(struct swaybar *bar,
struct swaybar_output *output;
wl_list_for_each(output, &bar->outputs, link) {
- output->xdg_output = zxdg_output_manager_v1_get_xdg_output(
- bar->xdg_output_manager, output->output);
- zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener,
- output);
+ add_xdg_output(output);
}
wl_display_roundtrip(bar->display);
- struct swaybar_output *output_tmp;
- wl_list_for_each_safe(output, output_tmp, &bar->outputs, link) {
- if (!bar_uses_output(bar, output->name)) {
- zxdg_output_v1_destroy(output->xdg_output);
- wl_output_destroy(output->output);
- wl_list_remove(&output->link);
- free(output);
- }
- }
-
struct swaybar_pointer *pointer = &bar->pointer;
int max_scale = 1;
@@ -479,20 +530,9 @@ void bar_setup(struct swaybar *bar,
pointer->cursor_surface = wl_compositor_create_surface(bar->compositor);
assert(pointer->cursor_surface);
- wl_list_for_each(output, &bar->outputs, link) {
- output->surface = wl_compositor_create_surface(bar->compositor);
- assert(output->surface);
- output->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
- bar->layer_shell, output->surface, output->output,
- ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel");
- assert(output->layer_surface);
- zwlr_layer_surface_v1_add_listener(output->layer_surface,
- &layer_surface_listener, output);
- zwlr_layer_surface_v1_set_anchor(output->layer_surface,
- bar->config->position);
- }
ipc_get_workspaces(bar);
- render_all_frames(bar);
+ set_bar_dirty(bar);
+ return true;
}
static void display_in(int fd, short mask, void *data) {
@@ -506,7 +546,7 @@ static void display_in(int fd, short mask, void *data) {
static void ipc_in(int fd, short mask, void *data) {
struct swaybar *bar = data;
if (handle_ipc_readable(bar)) {
- render_all_frames(bar);
+ set_bar_dirty(bar);
}
}
@@ -514,10 +554,10 @@ static void status_in(int fd, short mask, void *data) {
struct swaybar *bar = data;
if (mask & (POLLHUP | POLLERR)) {
status_error(bar->status, "[error reading from status command]");
- render_all_frames(bar);
+ set_bar_dirty(bar);
remove_event(fd);
} else if (status_handle_readable(bar->status)) {
- render_all_frames(bar);
+ set_bar_dirty(bar);
}
}
@@ -529,6 +569,7 @@ void bar_run(struct swaybar *bar) {
}
while (1) {
event_loop_poll();
+ wl_display_flush(bar->display);
}
}
diff --git a/swaybar/config.c b/swaybar/config.c
index db7b0db6..4e851cca 100644
--- a/swaybar/config.c
+++ b/swaybar/config.c
@@ -22,7 +22,7 @@ uint32_t parse_position(const char *position) {
}
}
-struct swaybar_config *init_config() {
+struct swaybar_config *init_config(void) {
struct swaybar_config *config = calloc(1, sizeof(struct swaybar_config));
config->status_command = NULL;
config->pango_markup = false;
diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c
index 88404703..8e9b038b 100644
--- a/swaybar/i3bar.c
+++ b/swaybar/i3bar.c
@@ -6,7 +6,9 @@
#include <string.h>
#include <unistd.h>
#include <wlr/util/log.h>
+#include "swaybar/bar.h"
#include "swaybar/config.h"
+#include "swaybar/i3bar.h"
#include "swaybar/status_line.h"
void i3bar_block_unref(struct i3bar_block *block) {
@@ -117,7 +119,9 @@ bool i3bar_handle_readable(struct status_line *status) {
memmove(status->buffer, &status->buffer[c], status->buffer_index);
break;
} else if (!isspace(status->buffer[c])) {
- status_error(status, "[invalid json]");
+ wlr_log(WLR_DEBUG, "Invalid i3bar json: expected '[' but encountered '%c'",
+ status->buffer[c]);
+ status_error(status, "[invalid i3bar json]");
return true;
}
}
@@ -155,6 +159,8 @@ bool i3bar_handle_readable(struct status_line *status) {
++buffer_pos;
break;
} else if (!isspace(status->buffer[buffer_pos])) {
+ wlr_log(WLR_DEBUG, "Invalid i3bar json: expected ',' but encountered '%c'",
+ status->buffer[buffer_pos]);
status_error(status, "[invalid i3bar json]");
return true;
}
@@ -166,7 +172,8 @@ bool i3bar_handle_readable(struct status_line *status) {
} else {
test_object = json_tokener_parse_ex(status->tokener,
&status->buffer[buffer_pos], status->buffer_index - buffer_pos);
- if (json_tokener_get_error(status->tokener) == json_tokener_success) {
+ enum json_tokener_error err = json_tokener_get_error(status->tokener);
+ if (err == json_tokener_success) {
if (json_object_get_type(test_object) == json_type_array) {
if (last_object) {
json_object_put(last_object);
@@ -198,12 +205,14 @@ bool i3bar_handle_readable(struct status_line *status) {
continue; // look for comma without reading more input
}
buffer_pos = status->buffer_index = 0;
- } else if (json_tokener_get_error(status->tokener) == json_tokener_continue) {
+ } else if (err == json_tokener_continue) {
+ json_tokener_reset(status->tokener);
if (status->buffer_index < status->buffer_size) {
// move the object to the start of the buffer
status->buffer_index -= buffer_pos;
memmove(status->buffer, &status->buffer[buffer_pos],
status->buffer_index);
+ buffer_pos = 0;
} else {
// expand buffer
status->buffer_size *= 2;
@@ -217,6 +226,10 @@ bool i3bar_handle_readable(struct status_line *status) {
}
}
} else {
+ char last_char = status->buffer[status->buffer_index - 1];
+ status->buffer[status->buffer_index - 1] = '\0';
+ wlr_log(WLR_DEBUG, "Failed to parse i3bar json - %s: '%s%c'",
+ json_tokener_error_desc(err), &status->buffer[buffer_pos], last_char);
status_error(status, "[failed to parse i3bar json]");
return true;
}
diff --git a/swaybar/ipc.c b/swaybar/ipc.c
index 0e60c10c..7c53a44f 100644
--- a/swaybar/ipc.c
+++ b/swaybar/ipc.c
@@ -141,9 +141,16 @@ static void ipc_parse_colors(
}
}
-static void ipc_parse_config(
+static bool ipc_parse_config(
struct swaybar_config *config, const char *payload) {
json_object *bar_config = json_tokener_parse(payload);
+ json_object *success;
+ if (json_object_object_get_ex(bar_config, "success", &success)
+ && !json_object_get_boolean(success)) {
+ wlr_log(WLR_ERROR, "No bar with that ID. Use 'swaymsg -t get_bar_config to get the available bar configs.");
+ json_object_put(bar_config);
+ return false;
+ }
json_object *markup, *mode, *hidden_bar, *position, *status_command;
json_object *font, *bar_height, *wrap_scroll, *workspace_buttons, *strip_workspace_numbers;
json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs;
@@ -226,10 +233,10 @@ static void ipc_parse_config(
}
json_object_put(bar_config);
+ return true;
}
void ipc_get_workspaces(struct swaybar *bar) {
- bar->focused_output = NULL;
struct swaybar_output *output;
wl_list_for_each(output, &bar->outputs, link) {
free_workspaces(&output->workspaces);
@@ -312,11 +319,14 @@ static void ipc_get_outputs(struct swaybar *bar) {
free(res);
}
-void ipc_initialize(struct swaybar *bar, const char *bar_id) {
+bool ipc_initialize(struct swaybar *bar, const char *bar_id) {
uint32_t len = strlen(bar_id);
char *res = ipc_single_command(bar->ipc_socketfd,
IPC_GET_BAR_CONFIG, bar_id, &len);
- ipc_parse_config(bar->config, res);
+ if (!ipc_parse_config(bar->config, res)) {
+ free(res);
+ return false;
+ }
free(res);
ipc_get_outputs(bar);
@@ -324,6 +334,7 @@ void ipc_initialize(struct swaybar *bar, const char *bar_id) {
len = strlen(subscribe);
free(ipc_single_command(bar->ipc_event_socketfd,
IPC_SUBSCRIBE, subscribe, &len));
+ return true;
}
bool handle_ipc_readable(struct swaybar *bar) {
diff --git a/swaybar/main.c b/swaybar/main.c
index 60e4b37c..d2c579db 100644
--- a/swaybar/main.c
+++ b/swaybar/main.c
@@ -96,7 +96,10 @@ int main(int argc, char **argv) {
signal(SIGTERM, sig_handler);
- bar_setup(&swaybar, socket_path, bar_id);
+ if (!bar_setup(&swaybar, socket_path, bar_id)) {
+ free(socket_path);
+ return 1;
+ }
free(socket_path);
free(bar_id);
diff --git a/swaybar/meson.build b/swaybar/meson.build
index d65edb11..7a02a33f 100644
--- a/swaybar/meson.build
+++ b/swaybar/meson.build
@@ -24,5 +24,6 @@ executable(
wlroots,
],
link_with: [lib_sway_common, lib_sway_client],
+ install_rpath : rpathdir,
install: true
)
diff --git a/swaybar/render.c b/swaybar/render.c
index 97690338..dc31a5ea 100644
--- a/swaybar/render.c
+++ b/swaybar/render.c
@@ -1,4 +1,5 @@
#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <stdint.h>
@@ -9,6 +10,7 @@
#include "pool-buffer.h"
#include "swaybar/bar.h"
#include "swaybar/config.h"
+#include "swaybar/i3bar.h"
#include "swaybar/ipc.h"
#include "swaybar/render.h"
#include "swaybar/status_line.h"
@@ -19,47 +21,47 @@ static const double WS_VERTICAL_PADDING = 1.5;
static const double BORDER_WIDTH = 1;
static uint32_t render_status_line_error(cairo_t *cairo,
- struct swaybar_output *output, struct swaybar_config *config,
- const char *error, double *x, uint32_t surface_height) {
+ struct swaybar_output *output, double *x) {
+ const char *error = output->bar->status->text;
if (!error) {
return 0;
}
- uint32_t height = surface_height * output->scale;
+ uint32_t height = output->height * output->scale;
cairo_set_source_u32(cairo, 0xFF0000FF);
int margin = 3 * output->scale;
int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale;
+ char *font = output->bar->config->font;
int text_width, text_height;
- get_text_size(cairo, config->font, &text_width, &text_height, NULL,
+ get_text_size(cairo, font, &text_width, &text_height, NULL,
output->scale, false, "%s", error);
uint32_t ideal_height = text_height + ws_vertical_padding * 2;
uint32_t ideal_surface_height = ideal_height / output->scale;
- if (surface_height < ideal_surface_height) {
+ if (output->height < ideal_surface_height) {
return ideal_surface_height;
}
*x -= text_width + margin;
double text_y = height / 2.0 - text_height / 2.0;
cairo_move_to(cairo, *x, (int)floor(text_y));
- pango_printf(cairo, config->font, output->scale, false, "%s", error);
+ pango_printf(cairo, font, output->scale, false, "%s", error);
*x -= margin;
- return surface_height;
+ return output->height;
}
static uint32_t render_status_line_text(cairo_t *cairo,
- struct swaybar_output *output, struct swaybar_config *config,
- const char *text, bool focused, double *x, uint32_t surface_height) {
+ struct swaybar_output *output, double *x) {
+ const char *text = output->bar->status->text;
if (!text) {
return 0;
}
- uint32_t height = surface_height * output->scale;
-
- cairo_set_source_u32(cairo, focused ?
+ struct swaybar_config *config = output->bar->config;
+ cairo_set_source_u32(cairo, output->focused ?
config->colors.focused_statusline : config->colors.statusline);
int text_width, text_height;
@@ -71,17 +73,18 @@ static uint32_t render_status_line_text(cairo_t *cairo,
uint32_t ideal_height = text_height + ws_vertical_padding * 2;
uint32_t ideal_surface_height = ideal_height / output->scale;
- if (surface_height < ideal_surface_height) {
+ if (output->height < ideal_surface_height) {
return ideal_surface_height;
}
*x -= text_width + margin;
+ uint32_t height = output->height * output->scale;
double text_y = height / 2.0 - text_height / 2.0;
cairo_move_to(cairo, *x, (int)floor(text_y));
pango_printf(cairo, config->font, output->scale,
config->pango_markup, "%s", text);
*x -= margin;
- return surface_height;
+ return output->height;
}
static void render_sharp_line(cairo_t *cairo, uint32_t color,
@@ -121,12 +124,11 @@ static void i3bar_block_unref_callback(void *data) {
static uint32_t render_status_block(cairo_t *cairo,
struct swaybar_output *output, struct i3bar_block *block, double *x,
- uint32_t surface_height, bool focused, bool edge) {
+ bool edge) {
if (!block->full_text || !*block->full_text) {
return 0;
}
- uint32_t height = surface_height * output->scale;
struct swaybar_config *config = output->bar->config;
int text_width, text_height;
@@ -144,7 +146,7 @@ static uint32_t render_status_block(cairo_t *cairo,
double block_width = width;
uint32_t ideal_height = text_height + ws_vertical_padding * 2;
uint32_t ideal_surface_height = ideal_height / output->scale;
- if (surface_height < ideal_surface_height) {
+ if (output->height < ideal_surface_height) {
return ideal_surface_height;
}
@@ -165,7 +167,7 @@ static uint32_t render_status_block(cairo_t *cairo,
output->scale, false, "%s", config->sep_symbol);
uint32_t _ideal_height = sep_height + ws_vertical_padding * 2;
uint32_t _ideal_surface_height = _ideal_height / output->scale;
- if (surface_height < _ideal_surface_height) {
+ if (output->height < _ideal_surface_height) {
return _ideal_surface_height;
}
if (sep_width > block->separator_block_width) {
@@ -177,6 +179,7 @@ static uint32_t render_status_block(cairo_t *cairo,
*x -= margin;
}
+ uint32_t height = output->height * output->scale;
if (output->bar->status->click_events) {
struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
hotspot->x = *x;
@@ -240,7 +243,7 @@ static uint32_t render_status_block(cairo_t *cairo,
}
if (!edge && block->separator) {
- if (focused) {
+ if (output->focused) {
cairo_set_source_u32(cairo, config->colors.focused_separator);
} else {
cairo_set_source_u32(cairo, config->colors.separator);
@@ -259,19 +262,16 @@ static uint32_t render_status_block(cairo_t *cairo,
cairo_stroke(cairo);
}
}
- return surface_height;
+ return output->height;
}
static uint32_t render_status_line_i3bar(cairo_t *cairo,
- struct swaybar_config *config, struct swaybar_output *output,
- struct status_line *status, bool focused,
- double *x, uint32_t surface_height) {
+ struct swaybar_output *output, double *x) {
uint32_t max_height = 0;
bool edge = true;
struct i3bar_block *block;
- wl_list_for_each(block, &status->blocks, link) {
- uint32_t h = render_status_block(cairo, output,
- block, x, surface_height, focused, edge);
+ wl_list_for_each(block, &output->bar->status->blocks, link) {
+ uint32_t h = render_status_block(cairo, output, block, x, edge);
max_height = h > max_height ? h : max_height;
edge = false;
}
@@ -279,19 +279,15 @@ static uint32_t render_status_line_i3bar(cairo_t *cairo,
}
static uint32_t render_status_line(cairo_t *cairo,
- struct swaybar_config *config, struct swaybar_output *output,
- struct status_line *status, bool focused,
- double *x, uint32_t surface_height) {
+ struct swaybar_output *output, double *x) {
+ struct status_line *status = output->bar->status;
switch (status->protocol) {
case PROTOCOL_ERROR:
- return render_status_line_error(cairo, output, config,
- status->text, x, surface_height);
+ return render_status_line_error(cairo, output, x);
case PROTOCOL_TEXT:
- return render_status_line_text(cairo, output, config,
- status->text, focused, x, surface_height);
+ return render_status_line_text(cairo, output, x);
case PROTOCOL_I3BAR:
- return render_status_line_i3bar(cairo, config, output,
- status, focused, x, surface_height);
+ return render_status_line_i3bar(cairo, output, x);
case PROTOCOL_UNDEF:
return 0;
}
@@ -299,10 +295,9 @@ static uint32_t render_status_line(cairo_t *cairo,
}
static uint32_t render_binding_mode_indicator(cairo_t *cairo,
- struct swaybar_output *output, struct swaybar_config *config,
- const char *mode, double x, uint32_t surface_height) {
- uint32_t height = surface_height * output->scale;
-
+ struct swaybar_output *output, double x) {
+ struct swaybar_config *config = output->bar->config;
+ const char *mode = config->mode;
int text_width, text_height;
get_text_size(cairo, config->font, &text_width, &text_height, NULL,
output->scale, config->mode_pango_markup,
@@ -315,11 +310,12 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo,
uint32_t ideal_height = text_height + ws_vertical_padding * 2
+ border_width * 2;
uint32_t ideal_surface_height = ideal_height / output->scale;
- if (surface_height < ideal_surface_height) {
+ if (output->height < ideal_surface_height) {
return ideal_surface_height;
}
uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2;
+ uint32_t height = output->height * output->scale;
cairo_set_source_u32(cairo, config->colors.binding_mode.background);
cairo_rectangle(cairo, x, 0, width, height);
cairo_fill(cairo);
@@ -339,7 +335,7 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo,
cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y));
pango_printf(cairo, config->font, output->scale, config->mode_pango_markup,
"%s", mode);
- return surface_height;
+ return output->height;
}
static const char *strip_workspace_number(const char *ws_name) {
@@ -365,8 +361,9 @@ static enum hotspot_event_handling workspace_hotspot_callback(struct swaybar_out
}
static uint32_t render_workspace_button(cairo_t *cairo,
- struct swaybar_output *output, struct swaybar_config *config,
- struct swaybar_workspace *ws, double *x, uint32_t surface_height) {
+ struct swaybar_output *output,
+ struct swaybar_workspace *ws, double *x) {
+ struct swaybar_config *config = output->bar->config;
const char *name = ws->name;
if (config->strip_workspace_numbers) {
name = strip_workspace_number(ws->name);
@@ -383,7 +380,7 @@ static uint32_t render_workspace_button(cairo_t *cairo,
box_colors = config->colors.inactive_workspace;
}
- uint32_t height = surface_height * output->scale;
+ uint32_t height = output->height * output->scale;
int text_width, text_height;
get_text_size(cairo, config->font, &text_width, &text_height, NULL,
@@ -396,7 +393,7 @@ static uint32_t render_workspace_button(cairo_t *cairo,
uint32_t ideal_height = ws_vertical_padding * 2 + text_height
+ border_width * 2;
uint32_t ideal_surface_height = ideal_height / output->scale;
- if (surface_height < ideal_surface_height) {
+ if (output->height < ideal_surface_height) {
return ideal_surface_height;
}
@@ -433,11 +430,11 @@ static uint32_t render_workspace_button(cairo_t *cairo,
wl_list_insert(&output->hotspots, &hotspot->link);
*x += width;
- return surface_height;
+ return output->height;
}
-static uint32_t render_to_cairo(cairo_t *cairo,
- struct swaybar *bar, struct swaybar_output *output) {
+static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) {
+ struct swaybar *bar = output->bar;
struct swaybar_config *config = bar->config;
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
if (output->focused) {
@@ -457,29 +454,43 @@ static uint32_t render_to_cairo(cairo_t *cairo,
*/
double x = output->width * output->scale;
if (bar->status) {
- uint32_t h = render_status_line(cairo, config, output,
- bar->status, output->focused, &x, output->height);
+ uint32_t h = render_status_line(cairo, output, &x);
max_height = h > max_height ? h : max_height;
}
x = 0;
if (config->workspace_buttons) {
struct swaybar_workspace *ws;
wl_list_for_each_reverse(ws, &output->workspaces, link) {
- uint32_t h = render_workspace_button(cairo,
- output, config, ws, &x, output->height);
+ uint32_t h = render_workspace_button(cairo, output, ws, &x);
max_height = h > max_height ? h : max_height;
}
}
if (config->binding_mode_indicator && config->mode) {
- uint32_t h = render_binding_mode_indicator(cairo,
- output, config, config->mode, x, output->height);
+ uint32_t h = render_binding_mode_indicator(cairo, output, x);
max_height = h > max_height ? h : max_height;
}
return max_height > output->height ? max_height : output->height;
}
-void render_frame(struct swaybar *bar, struct swaybar_output *output) {
+static void output_frame_handle_done(void *data, struct wl_callback *callback,
+ uint32_t time) {
+ wl_callback_destroy(callback);
+ struct swaybar_output *output = data;
+ output->frame_scheduled = false;
+ if (output->dirty) {
+ render_frame(output);
+ output->dirty = false;
+ }
+}
+
+static const struct wl_callback_listener output_frame_listener = {
+ .done = output_frame_handle_done
+};
+
+void render_frame(struct swaybar_output *output) {
+ assert(output->surface != NULL);
+
struct swaybar_hotspot *hotspot, *tmp;
wl_list_for_each_safe(hotspot, tmp, &output->hotspots, link) {
if (hotspot->destroy) {
@@ -492,13 +503,21 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) {
cairo_surface_t *recorder = cairo_recording_surface_create(
CAIRO_CONTENT_COLOR_ALPHA, NULL);
cairo_t *cairo = cairo_create(recorder);
+ cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
+ cairo_font_options_t *fo = cairo_font_options_create();
+ cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
+ cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
+ cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(output->subpixel));
+ cairo_set_font_options(cairo, fo);
+ cairo_font_options_destroy(fo);
cairo_save(cairo);
cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR);
cairo_paint(cairo);
cairo_restore(cairo);
- uint32_t height = render_to_cairo(cairo, bar, output);
- if (bar->config->height >= 0 && height < (uint32_t)bar->config->height) {
- height = bar->config->height;
+ uint32_t height = render_to_cairo(cairo, output);
+ int config_height = output->bar->config->height;
+ if (config_height >= 0 && height < (uint32_t)config_height) {
+ height = config_height;
}
if (height != output->height) {
// Reconfigure surface
@@ -507,14 +526,15 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) {
// TODO: this could infinite loop if the compositor assigns us a
// different height than what we asked for
wl_surface_commit(output->surface);
- wl_display_roundtrip(bar->display);
} else if (height > 0) {
// Replay recording into shm and send it off
- output->current_buffer = get_next_buffer(bar->shm,
+ output->current_buffer = get_next_buffer(output->bar->shm,
output->buffers,
output->width * output->scale,
output->height * output->scale);
if (!output->current_buffer) {
+ cairo_surface_destroy(recorder);
+ cairo_destroy(cairo);
return;
}
cairo_t *shm = output->current_buffer->cairo;
@@ -532,8 +552,12 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) {
output->current_buffer->buffer, 0, 0);
wl_surface_damage(output->surface, 0, 0,
output->width, output->height);
+
+ struct wl_callback *frame_callback = wl_surface_frame(output->surface);
+ wl_callback_add_listener(frame_callback, &output_frame_listener, output);
+ output->frame_scheduled = true;
+
wl_surface_commit(output->surface);
- wl_display_roundtrip(bar->display);
}
cairo_surface_destroy(recorder);
cairo_destroy(cairo);
diff --git a/swaybar/status_line.c b/swaybar/status_line.c
index 401bf6f6..ed6dc7c8 100644
--- a/swaybar/status_line.c
+++ b/swaybar/status_line.c
@@ -1,12 +1,15 @@
#define _POSIX_C_SOURCE 200809L
#include <fcntl.h>
+#include <sys/ioctl.h>
#include <json-c/json.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <wlr/util/log.h>
+#include "swaybar/bar.h"
#include "swaybar/config.h"
+#include "swaybar/i3bar.h"
#include "swaybar/event_loop.h"
#include "swaybar/status_line.h"
#include "readline.h"
@@ -34,18 +37,35 @@ bool status_handle_readable(struct status_line *status) {
switch (status->protocol) {
case PROTOCOL_UNDEF:
errno = 0;
- read_bytes = getline(&status->buffer,
- &status->buffer_size, status->read);
- if (errno == EAGAIN) {
- clearerr(status->read);
- } else if (errno) {
+ int available_bytes;
+ if (ioctl(status->read_fd, FIONREAD, &available_bytes) == -1) {
+ wlr_log(WLR_ERROR, "Unable to read status command output size");
status_error(status, "[error reading from status command]");
return true;
}
+ if ((size_t)available_bytes + 1 > status->buffer_size) {
+ // need room for leading '\0' too
+ status->buffer_size = available_bytes + 1;
+ status->buffer = realloc(status->buffer, status->buffer_size);
+ }
+ if (status->buffer == NULL) {
+ wlr_log_errno(WLR_ERROR, "Unable to read status line");
+ status_error(status, "[error reading from status command]");
+ return true;
+ }
+
+ read_bytes = read(status->read_fd, status->buffer, available_bytes);
+ if (read_bytes != available_bytes) {
+ status_error(status, "[error reading from status command]");
+ return true;
+ }
+ status->buffer[available_bytes] = 0;
+
// the header must be sent completely the first time round
+ char *newline = strchr(status->buffer, '\n');
json_object *header, *version;
- if (status->buffer[read_bytes - 1] == '\n'
+ if (newline != NULL
&& (header = json_tokener_parse(status->buffer))
&& json_object_object_get_ex(header, "version", &version)
&& json_object_get_int(version) == 1) {
@@ -67,8 +87,8 @@ bool status_handle_readable(struct status_line *status) {
wl_list_init(&status->blocks);
status->tokener = json_tokener_new();
- status->buffer_index = getdelim(&status->buffer,
- &status->buffer_size, EOF, status->read);
+ status->buffer_index = strlen(newline + 1);
+ memmove(status->buffer, newline + 1, status->buffer_index + 1);
return i3bar_handle_readable(status);
}
diff --git a/swaybg/main.c b/swaybg/main.c
index 5b0d0458..742669ef 100644
--- a/swaybg/main.c
+++ b/swaybg/main.c
@@ -73,6 +73,10 @@ static void render_frame(struct swaybg_state *state) {
return;
}
cairo_t *cairo = state->current_buffer->cairo;
+ cairo_save(cairo);
+ cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR);
+ cairo_paint(cairo);
+ cairo_restore(cairo);
if (state->args->mode == BACKGROUND_MODE_SOLID_COLOR) {
cairo_set_source_u32(cairo, state->context.color);
cairo_paint(cairo);
diff --git a/swaybg/meson.build b/swaybg/meson.build
index 8704de6d..095c5488 100644
--- a/swaybg/meson.build
+++ b/swaybg/meson.build
@@ -14,5 +14,6 @@ executable(
wlroots,
],
link_with: [lib_sway_common, lib_sway_client],
+ install_rpath : rpathdir,
install: true
)
diff --git a/swayidle/main.c b/swayidle/main.c
index 678d622f..5b6c95a7 100644
--- a/swayidle/main.c
+++ b/swayidle/main.c
@@ -92,7 +92,7 @@ static int release_lock(void *data) {
return 0;
}
-void acquire_sleep_lock() {
+void acquire_sleep_lock(void) {
sd_bus_message *msg = NULL;
sd_bus_error error = SD_BUS_ERROR_NULL;
struct sd_bus *bus;
@@ -161,7 +161,7 @@ static int dbus_event(int fd, uint32_t mask, void *data) {
return 1;
}
-void setup_sleep_listener() {
+void setup_sleep_listener(void) {
struct sd_bus *bus;
int ret = sd_bus_default_system(&bus);
diff --git a/swayidle/meson.build b/swayidle/meson.build
index f62545f8..6c3ac119 100644
--- a/swayidle/meson.build
+++ b/swayidle/meson.build
@@ -14,5 +14,6 @@ executable(
swayidle_deps,
],
link_with: [lib_sway_common, lib_sway_client],
+ install_rpath : rpathdir,
install: true
)
diff --git a/swaylock/main.c b/swaylock/main.c
index 668a8742..ed8c5607 100644
--- a/swaylock/main.c
+++ b/swaylock/main.c
@@ -32,7 +32,7 @@ void sway_terminate(int exit_code) {
exit(exit_code);
}
-static void daemonize() {
+static void daemonize(void) {
int fds[2];
if (pipe(fds) != 0) {
wlr_log(WLR_ERROR, "Failed to pipe");
@@ -195,11 +195,15 @@ void damage_state(struct swaylock_state *state) {
}
}
-static void handle_wl_output_geometry(void *data, struct wl_output *output,
+static void handle_wl_output_geometry(void *data, struct wl_output *wl_output,
int32_t x, int32_t y, int32_t width_mm, int32_t height_mm,
int32_t subpixel, const char *make, const char *model,
int32_t transform) {
- // Who cares
+ struct swaylock_surface *surface = data;
+ surface->subpixel = subpixel;
+ if (surface->state->run_display) {
+ damage_surface(surface);
+ }
}
static void handle_wl_output_mode(void *data, struct wl_output *output,
@@ -841,6 +845,9 @@ static int load_config(char *path, struct swaylock_state *state,
static struct swaylock_state state;
int main(int argc, char **argv) {
+ wlr_log_init(WLR_DEBUG, NULL);
+ initialize_pw_backend();
+
enum line_mode line_mode = LM_LINE;
state.args = (struct swaylock_args){
.mode = BACKGROUND_MODE_SOLID_COLOR,
@@ -853,8 +860,6 @@ int main(int argc, char **argv) {
wl_list_init(&state.images);
set_default_colors(&state.args.colors);
- wlr_log_init(WLR_DEBUG, NULL);
-
char *config_path = NULL;
int result = parse_options(argc, argv, NULL, NULL, &config_path);
if (result != 0) {
diff --git a/swaylock/meson.build b/swaylock/meson.build
index 675b8c69..6605340b 100644
--- a/swaylock/meson.build
+++ b/swaylock/meson.build
@@ -1,26 +1,39 @@
sysconfdir = get_option('sysconfdir')
-executable(
- 'swaylock', [
- 'main.c',
- 'password.c',
- 'render.c',
- 'seat.c'
- ],
+dependencies = [
+ cairo,
+ client_protos,
+ gdk_pixbuf,
+ math,
+ pango,
+ pangocairo,
+ xkbcommon,
+ wayland_client,
+ wlroots,
+]
+
+sources = [
+ 'main.c',
+ 'password.c',
+ 'render.c',
+ 'seat.c'
+]
+
+if libpam.found()
+ sources += ['pam.c']
+ dependencies += [libpam]
+else
+ warning('The swaylock binary must be setuid when compiled without libpam')
+ warning('You must do this manually post-install: chmod a+s /path/to/swaylock')
+ sources += ['shadow.c']
+endif
+
+executable('swaylock',
+ sources,
include_directories: [sway_inc],
- dependencies: [
- cairo,
- client_protos,
- gdk_pixbuf,
- libpam,
- math,
- pango,
- pangocairo,
- xkbcommon,
- wayland_client,
- wlroots,
- ],
+ dependencies: dependencies,
link_with: [lib_sway_common, lib_sway_client],
+ install_rpath : rpathdir,
install: true
)
diff --git a/swaylock/pam.c b/swaylock/pam.c
new file mode 100644
index 00000000..cac95a85
--- /dev/null
+++ b/swaylock/pam.c
@@ -0,0 +1,62 @@
+#define _XOPEN_SOURCE 500
+#include <pwd.h>
+#include <security/pam_appl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wlr/util/log.h>
+#include "swaylock/swaylock.h"
+
+void initialize_pw_backend(void) {
+ // TODO: only call pam_start once. keep the same handle the whole time
+}
+
+static int function_conversation(int num_msg, const struct pam_message **msg,
+ struct pam_response **resp, void *data) {
+ struct swaylock_password *pw = data;
+ /* PAM expects an array of responses, one for each message */
+ struct pam_response *pam_reply = calloc(
+ num_msg, sizeof(struct pam_response));
+ *resp = pam_reply;
+ for (int i = 0; i < num_msg; ++i) {
+ switch (msg[i]->msg_style) {
+ case PAM_PROMPT_ECHO_OFF:
+ case PAM_PROMPT_ECHO_ON:
+ pam_reply[i].resp = strdup(pw->buffer); // PAM clears and frees this
+ break;
+ case PAM_ERROR_MSG:
+ case PAM_TEXT_INFO:
+ break;
+ }
+ }
+ return PAM_SUCCESS;
+}
+
+bool attempt_password(struct swaylock_password *pw) {
+ struct passwd *passwd = getpwuid(getuid());
+ char *username = passwd->pw_name;
+ const struct pam_conv local_conversation = {
+ function_conversation, pw
+ };
+ pam_handle_t *local_auth_handle = NULL;
+ int pam_err;
+ if ((pam_err = pam_start("swaylock", username,
+ &local_conversation, &local_auth_handle)) != PAM_SUCCESS) {
+ wlr_log(WLR_ERROR, "PAM returned error %d", pam_err);
+ }
+ if ((pam_err = pam_authenticate(local_auth_handle, 0)) != PAM_SUCCESS) {
+ wlr_log(WLR_ERROR, "pam_authenticate failed");
+ goto fail;
+ }
+ // TODO: only call pam_end once we succeed at authing. refresh tokens beforehand
+ if ((pam_err = pam_end(local_auth_handle, pam_err)) != PAM_SUCCESS) {
+ wlr_log(WLR_ERROR, "pam_end failed");
+ goto fail;
+ }
+ clear_password_buffer(pw);
+ return true;
+fail:
+ clear_password_buffer(pw);
+ return false;
+}
diff --git a/swaylock/password.c b/swaylock/password.c
index 7c686b34..6a956bcb 100644
--- a/swaylock/password.c
+++ b/swaylock/password.c
@@ -1,7 +1,6 @@
#define _XOPEN_SOURCE 500
#include <assert.h>
#include <pwd.h>
-#include <security/pam_appl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -11,27 +10,6 @@
#include "swaylock/seat.h"
#include "unicode.h"
-static int function_conversation(int num_msg, const struct pam_message **msg,
- struct pam_response **resp, void *data) {
- struct swaylock_password *pw = data;
- /* PAM expects an array of responses, one for each message */
- struct pam_response *pam_reply = calloc(
- num_msg, sizeof(struct pam_response));
- *resp = pam_reply;
- for (int i = 0; i < num_msg; ++i) {
- switch (msg[i]->msg_style) {
- case PAM_PROMPT_ECHO_OFF:
- case PAM_PROMPT_ECHO_ON:
- pam_reply[i].resp = strdup(pw->buffer); // PAM clears and frees this
- break;
- case PAM_ERROR_MSG:
- case PAM_TEXT_INFO:
- break;
- }
- }
- return PAM_SUCCESS;
-}
-
void clear_password_buffer(struct swaylock_password *pw) {
// Use volatile keyword so so compiler can't optimize this out.
volatile char *buffer = pw->buffer;
@@ -42,35 +20,6 @@ void clear_password_buffer(struct swaylock_password *pw) {
pw->len = 0;
}
-static bool attempt_password(struct swaylock_password *pw) {
- struct passwd *passwd = getpwuid(getuid());
- char *username = passwd->pw_name;
- const struct pam_conv local_conversation = {
- function_conversation, pw
- };
- pam_handle_t *local_auth_handle = NULL;
- int pam_err;
- // TODO: only call pam_start once. keep the same handle the whole time
- if ((pam_err = pam_start("swaylock", username,
- &local_conversation, &local_auth_handle)) != PAM_SUCCESS) {
- wlr_log(WLR_ERROR, "PAM returned error %d", pam_err);
- }
- if ((pam_err = pam_authenticate(local_auth_handle, 0)) != PAM_SUCCESS) {
- wlr_log(WLR_ERROR, "pam_authenticate failed");
- goto fail;
- }
- // TODO: only call pam_end once we succeed at authing. refresh tokens beforehand
- if ((pam_err = pam_end(local_auth_handle, pam_err)) != PAM_SUCCESS) {
- wlr_log(WLR_ERROR, "pam_end failed");
- goto fail;
- }
- clear_password_buffer(pw);
- return true;
-fail:
- clear_password_buffer(pw);
- return false;
-}
-
static bool backspace(struct swaylock_password *pw) {
if (pw->len != 0) {
pw->buffer[--pw->len] = 0;
diff --git a/swaylock/render.c b/swaylock/render.c
index 66c55965..fa8832bd 100644
--- a/swaylock/render.c
+++ b/swaylock/render.c
@@ -39,6 +39,13 @@ void render_frame(struct swaylock_surface *surface) {
}
cairo_t *cairo = surface->current_buffer->cairo;
+ cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
+ cairo_font_options_t *fo = cairo_font_options_create();
+ cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
+ cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
+ cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(surface->subpixel));
+ cairo_set_font_options(cairo, fo);
+ cairo_font_options_destroy(fo);
cairo_identity_matrix(cairo);
cairo_save(cairo);
diff --git a/swaylock/shadow.c b/swaylock/shadow.c
new file mode 100644
index 00000000..1f10514c
--- /dev/null
+++ b/swaylock/shadow.c
@@ -0,0 +1,128 @@
+#define _XOPEN_SOURCE
+#include <pwd.h>
+#include <shadow.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <wlr/util/log.h>
+#include "swaylock/swaylock.h"
+
+static int comm[2][2];
+
+void run_child(void) {
+ /* This code runs as root */
+ struct passwd *pwent = getpwuid(getuid());
+ if (!pwent) {
+ wlr_log_errno(WLR_ERROR, "failed to getpwuid");
+ exit(EXIT_FAILURE);
+ }
+ char *encpw = pwent->pw_passwd;
+ if (strcmp(encpw, "x") == 0) {
+ struct spwd *swent = getspnam(pwent->pw_name);
+ if (!swent) {
+ wlr_log_errno(WLR_ERROR, "failed to getspnam");
+ exit(EXIT_FAILURE);
+ }
+ encpw = swent->sp_pwdp;
+ }
+ wlr_log(WLR_DEBUG, "prepared to authorize user %s", pwent->pw_name);
+
+ size_t size;
+ char *buf;
+ while (1) {
+ ssize_t amt;
+ amt = read(comm[0][0], &size, sizeof(size));
+ if (amt == 0) {
+ break;
+ } else if (amt < 0) {
+ wlr_log_errno(WLR_ERROR, "read pw request");
+ }
+ wlr_log(WLR_DEBUG, "received pw check request");
+ buf = malloc(size);
+ if (!buf) {
+ wlr_log_errno(WLR_ERROR, "failed to malloc pw buffer");
+ exit(EXIT_FAILURE);
+ }
+ size_t offs = 0;
+ do {
+ amt = read(comm[0][0], &buf[offs], size - offs);
+ if (amt <= 0) {
+ wlr_log_errno(WLR_ERROR, "failed to read pw");
+ exit(EXIT_FAILURE);
+ }
+ offs += (size_t)amt;
+ } while (offs < size);
+ bool result = false;
+ char *c = crypt(buf, encpw);
+ if (c == NULL) {
+ wlr_log_errno(WLR_ERROR, "crypt");
+ }
+ result = strcmp(c, encpw) == 0;
+ if (write(comm[1][1], &result, sizeof(result)) != sizeof(result)) {
+ wlr_log_errno(WLR_ERROR, "failed to write pw check result");
+ exit(EXIT_FAILURE);
+ }
+ free(buf);
+ }
+ exit(EXIT_SUCCESS);
+}
+
+void initialize_pw_backend(void) {
+ if (geteuid() != 0) {
+ wlr_log(WLR_ERROR, "swaylock needs to be setuid to read /etc/shadow");
+ exit(EXIT_FAILURE);
+ }
+ if (pipe(comm[0]) != 0) {
+ wlr_log_errno(WLR_ERROR, "failed to create pipe");
+ exit(EXIT_FAILURE);
+ }
+ if (pipe(comm[1]) != 0) {
+ wlr_log_errno(WLR_ERROR, "failed to create pipe");
+ exit(EXIT_FAILURE);
+ }
+ pid_t child = fork();
+ if (child == 0) {
+ close(comm[0][1]);
+ close(comm[1][0]);
+ run_child();
+ } else if (child < 0) {
+ wlr_log_errno(WLR_ERROR, "failed to fork");
+ exit(EXIT_FAILURE);
+ }
+ close(comm[0][0]);
+ close(comm[1][1]);
+ if (setgid(getgid()) != 0) {
+ wlr_log_errno(WLR_ERROR, "Unable to drop root");
+ exit(EXIT_FAILURE);
+ }
+ if (setuid(getuid()) != 0) {
+ wlr_log_errno(WLR_ERROR, "Unable to drop root");
+ exit(EXIT_FAILURE);
+ }
+}
+
+bool attempt_password(struct swaylock_password *pw) {
+ bool result = false;
+ size_t len = pw->len + 1;
+ size_t offs = 0;
+ if (write(comm[0][1], &len, sizeof(len)) < 0) {
+ wlr_log_errno(WLR_ERROR, "Failed to request pw check");
+ goto ret;
+ }
+ do {
+ ssize_t amt = write(comm[0][1], &pw->buffer[offs], len - offs);
+ if (amt < 0) {
+ wlr_log_errno(WLR_ERROR, "Failed to write pw buffer");
+ goto ret;
+ }
+ offs += amt;
+ } while (offs < len);
+ if (read(comm[1][0], &result, sizeof(result)) != sizeof(result)) {
+ wlr_log_errno(WLR_ERROR, "Failed to read pw result");
+ goto ret;
+ }
+ wlr_log(WLR_DEBUG, "pw result: %d", result);
+ret:
+ clear_password_buffer(pw);
+ return result;
+}
diff --git a/swaymsg/meson.build b/swaymsg/meson.build
index 8638b838..7318349d 100644
--- a/swaymsg/meson.build
+++ b/swaymsg/meson.build
@@ -4,5 +4,6 @@ executable(
include_directories: [sway_inc],
dependencies: [jsonc, wlroots],
link_with: [lib_sway_common],
+ install_rpath : rpathdir,
install: true
)
diff --git a/swaynag/config.c b/swaynag/config.c
index 4d0824c9..cd34dcc2 100644
--- a/swaynag/config.c
+++ b/swaynag/config.c
@@ -11,7 +11,7 @@
#include "util.h"
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
-static char *read_from_stdin() {
+static char *read_from_stdin(void) {
char *buffer = NULL;
while (!feof(stdin)) {
char *line = read_line(stdin);
diff --git a/swaynag/meson.build b/swaynag/meson.build
index 2ba3ed95..223a0bc7 100644
--- a/swaynag/meson.build
+++ b/swaynag/meson.build
@@ -19,5 +19,6 @@ executable(
wlroots,
],
link_with: [lib_sway_common, lib_sway_client],
+ install_rpath : rpathdir,
install: true
)