summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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.h9
-rw-r--r--include/swaybar/bar.h1
-rw-r--r--include/swaylock/swaylock.h1
-rw-r--r--sway/commands.c16
-rw-r--r--sway/commands/bind.c2
-rw-r--r--sway/desktop/transaction.c11
-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/ipc-server.c2
-rw-r--r--sway/main.c2
-rw-r--r--sway/tree/container.c8
-rw-r--r--sway/tree/root.c6
-rw-r--r--sway/tree/view.c19
-rw-r--r--sway/tree/workspace.c10
-rw-r--r--swaybar/bar.c8
-rw-r--r--swaybar/render.c7
-rw-r--r--swaybar/status_line.c10
-rw-r--r--swaylock/main.c8
-rw-r--r--swaylock/render.c7
25 files changed, 130 insertions, 156 deletions
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) {
13 (color >> (0*8) & 0xFF) / 255.0); 13 (color >> (0*8) & 0xFF) / 255.0);
14} 14}
15 15
16cairo_subpixel_order_t to_cairo_subpixel_order(enum wl_output_subpixel subpixel) {
17 switch (subpixel) {
18 case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
19 return CAIRO_SUBPIXEL_ORDER_RGB;
20 case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
21 return CAIRO_SUBPIXEL_ORDER_BGR;
22 case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
23 return CAIRO_SUBPIXEL_ORDER_VRGB;
24 case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
25 return CAIRO_SUBPIXEL_ORDER_VBGR;
26 default:
27 return CAIRO_SUBPIXEL_ORDER_DEFAULT;
28 }
29 return CAIRO_SUBPIXEL_ORDER_DEFAULT;
30}
31
16cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image, 32cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image,
17 int width, int height) { 33 int width, int height) {
18 int image_width = cairo_image_surface_get_width(image); 34 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 @@
6#include <stdio.h> 6#include <stdio.h>
7#include <stdlib.h> 7#include <stdlib.h>
8#include <string.h> 8#include <string.h>
9#include "cairo.h"
9#include "log.h" 10#include "log.h"
11#include "stringop.h"
10 12
11int escape_markup_text(const char *src, char *dest, int dest_length) { 13size_t escape_markup_text(const char *src, char *dest) {
12 int length = 0; 14 size_t length = 0;
15 if (dest) {
16 dest[0] = '\0';
17 }
13 18
14 while (src[0]) { 19 while (src[0]) {
15 switch (src[0]) { 20 switch (src[0]) {
16 case '&': 21 case '&':
17 length += 5; 22 length += 5;
18 if (dest && dest_length - length >= 0) { 23 lenient_strcat(dest, "&amp;");
19 dest += sprintf(dest, "%s", "&amp;");
20 } else {
21 dest_length = -1;
22 }
23 break; 24 break;
24 case '<': 25 case '<':
25 length += 4; 26 length += 4;
26 if (dest && dest_length - length >= 0) { 27 lenient_strcat(dest, "&lt;");
27 dest += sprintf(dest, "%s", "&lt;");
28 } else {
29 dest_length = -1;
30 }
31 break; 28 break;
32 case '>': 29 case '>':
33 length += 4; 30 length += 4;
34 if (dest && dest_length - length >= 0) { 31 lenient_strcat(dest, "&gt;");
35 dest += sprintf(dest, "%s", "&gt;");
36 } else {
37 dest_length = -1;
38 }
39 break; 32 break;
40 case '\'': 33 case '\'':
41 length += 6; 34 length += 6;
42 if (dest && dest_length - length >= 0) { 35 lenient_strcat(dest, "&apos;");
43 dest += sprintf(dest, "%s", "&apos;");
44 } else {
45 dest_length = -1;
46 }
47 break; 36 break;
48 case '"': 37 case '"':
49 length += 6; 38 length += 6;
50 if (dest && dest_length - length >= 0) { 39 lenient_strcat(dest, "&quot;");
51 dest += sprintf(dest, "%s", "&quot;");
52 } else {
53 dest_length = -1;
54 }
55 break; 40 break;
56 default: 41 default:
57 length += 1; 42 if (dest) {
58 if (dest && dest_length - length >= 0) { 43 dest[length] = *src;
59 *(dest++) = *src; 44 dest[length + 1] = '\0';
60 } else {
61 dest_length = -1;
62 } 45 }
46 length += 1;
63 } 47 }
64 src++; 48 src++;
65 } 49 }
66 // if we could not fit the escaped string in dest, return -1
67 if (dest && dest_length == -1) {
68 return -1;
69 }
70 return length; 50 return length;
71} 51}
72 52
@@ -78,7 +58,7 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
78 char *buf; 58 char *buf;
79 GError *error = NULL; 59 GError *error = NULL;
80 if (pango_parse_markup(text, -1, 0, &attrs, &buf, NULL, &error)) { 60 if (pango_parse_markup(text, -1, 0, &attrs, &buf, NULL, &error)) {
81 pango_layout_set_markup(layout, buf, -1); 61 pango_layout_set_text(layout, buf, -1);
82 free(buf); 62 free(buf);
83 } else { 63 } else {
84 wlr_log(WLR_ERROR, "pango_parse_markup '%s' -> error %s", text, 64 wlr_log(WLR_ERROR, "pango_parse_markup '%s' -> error %s", text,
@@ -134,6 +114,10 @@ void pango_printf(cairo_t *cairo, const char *font,
134 va_end(args); 114 va_end(args);
135 115
136 PangoLayout *layout = get_pango_layout(cairo, font, buf, scale, markup); 116 PangoLayout *layout = get_pango_layout(cairo, font, buf, scale, markup);
117 cairo_font_options_t *fo = cairo_font_options_create();
118 cairo_get_font_options(cairo, fo);
119 pango_cairo_context_set_font_options(pango_layout_get_context(layout), fo);
120 cairo_font_options_destroy(fo);
137 pango_cairo_update_layout(cairo, layout); 121 pango_cairo_update_layout(cairo, layout);
138 pango_cairo_show_layout(cairo, layout); 122 pango_cairo_show_layout(cairo, layout);
139 g_object_unref(layout); 123 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 @@
1#
2# Replicate some of Awesome's default layout manipulation configuration for Sway
3#
4# Differences:
5# - Layout switching doesn't use the spacebar (i.e. i3/Sway behavior to switch to/from floating windows)
6# and uses the 'A' key instead (as in auto)
7# - Resizing windows uses i3/Sway's more versatile Mod4+r
8# - no tags
9# - no Maximize/Minize, alternatives to Maximize would be to switch to Stacked/Tabbed layouts
10# via Mod4+w or Mod4+s.
11# - kill focused client is available on Mod4+Shift+q (instead of Mod4+Shift+c, which maps to Sway's
12# config reload)
13# - probably many more ...
14
15# Awesome-style container traversal using Vim-like binding
16set $next j
17set $prev k
18
19#
20# Moving around:
21#
22 # Move your focus around
23 bindsym $mod+$next focus next
24 bindsym $mod+$prev focus prev
25
26 # _move_ the focused window with the same, but add Shift
27 bindsym $mod+Shift+$next move next
28 bindsym $mod+Shift+$prev move prev
29
30#
31# Layout:
32#
33 workspace_layout auto left
34
35 # This is usually bound to $mod+space, but this works well in practice by keeping
36 # all the layout switching keys grouped together.
37 bindsym $mod+a layout auto next
38 bindsym $mod+Shift+a layout auto prev
39
40 # Promote a child to master position in an auto layout
41 bindsym $mod+Control+Return move first
42
43 # Increase/decrease number of master elements in auto layout
44 bindsym $mod+Shift+h layout auto master inc 1
45 bindsym $mod+Shift+l layout auto master inc -1
46
47 # Increase/decrease number of slave element groups in auto layout
48 bindsym $mod+Control+h layout auto ncol inc 1
49 bindsym $mod+Control+l layout auto ncol inc -1
50
51#
52# Resizing containers:
53# Again, not really the way Awesome works well, but in spirit with i3/Sway and it works well.
54#
55mode "resize" {
56 bindsym Left resize shrink width 20 px
57 bindsym Down resize grow height 20 px
58 bindsym Up resize shrink height 20 px
59 bindsym Right resize grow width 20 px
60}
61bindsym $mod+r mode "resize"
62
63new_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 @@
2#define _SWAY_CAIRO_H 2#define _SWAY_CAIRO_H
3#include <stdint.h> 3#include <stdint.h>
4#include <cairo/cairo.h> 4#include <cairo/cairo.h>
5#include <wlr/types/wlr_output.h>
5 6
6void cairo_set_source_u32(cairo_t *cairo, uint32_t color); 7void cairo_set_source_u32(cairo_t *cairo, uint32_t color);
8cairo_subpixel_order_t to_cairo_subpixel_order(enum wl_output_subpixel subpixel);
7 9
8cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image, 10cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image,
9 int width, int height); 11 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 @@
6#include <cairo/cairo.h> 6#include <cairo/cairo.h>
7#include <pango/pangocairo.h> 7#include <pango/pangocairo.h>
8 8
9/* Utility function which escape characters a & < > ' ". 9/**
10 * Utility function which escape characters a & < > ' ".
10 * 11 *
11 * If the dest parameter is NULL, then the function returns the length of 12 * The function returns the length of the escaped string, optionally writing the
12 * of the escaped src string. The dest_length doesn't matter. 13 * escaped string to dest if provided.
13 *
14 * If the dest parameter is not NULL then the fuction escapes the src string
15 * an puts the escaped string in dest and returns the lenght of the escaped string.
16 * The dest_length parameter is the size of dest array. If the size of dest is not
17 * enough, then the function returns -1.
18 */ 14 */
19int escape_markup_text(const char *src, char *dest, int dest_length); 15size_t escape_markup_text(const char *src, char *dest);
20PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, 16PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
21 const char *text, double scale, bool markup); 17 const char *text, double scale, bool markup);
22void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, 18void 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..1654eb48 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -4,6 +4,8 @@
4#include <wlr/util/edges.h> 4#include <wlr/util/edges.h>
5#include "config.h" 5#include "config.h"
6 6
7struct sway_container;
8
7typedef struct cmd_results *sway_cmd(int argc, char **argv); 9typedef struct cmd_results *sway_cmd(int argc, char **argv);
8 10
9struct cmd_handler { 11struct cmd_handler {
@@ -50,8 +52,13 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers,
50 int handlers_size); 52 int handlers_size);
51/** 53/**
52 * Parse and executes a command. 54 * Parse and executes a command.
55 *
56 * If the command string contains criteria then the command will be executed on
57 * all matching containers. Otherwise, it'll run on the `con` container. If
58 * `con` is NULL then it'll run on the currently focused container.
53 */ 59 */
54struct cmd_results *execute_command(char *command, struct sway_seat *seat); 60struct cmd_results *execute_command(char *command, struct sway_seat *seat,
61 struct sway_container *con);
55/** 62/**
56 * Parse and handles a command during config file loading. 63 * Parse and handles a command during config file loading.
57 * 64 *
diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h
index 4065fb8b..29e96159 100644
--- a/include/swaybar/bar.h
+++ b/include/swaybar/bar.h
@@ -81,6 +81,7 @@ struct swaybar_output {
81 81
82 uint32_t width, height; 82 uint32_t width, height;
83 int32_t scale; 83 int32_t scale;
84 enum wl_output_subpixel subpixel;
84 struct pool_buffer buffers[2]; 85 struct pool_buffer buffers[2];
85 struct pool_buffer *current_buffer; 86 struct pool_buffer *current_buffer;
86}; 87};
diff --git a/include/swaylock/swaylock.h b/include/swaylock/swaylock.h
index 950cfaaf..2f0cd34d 100644
--- a/include/swaylock/swaylock.h
+++ b/include/swaylock/swaylock.h
@@ -82,6 +82,7 @@ struct swaylock_surface {
82 bool frame_pending, dirty; 82 bool frame_pending, dirty;
83 uint32_t width, height; 83 uint32_t width, height;
84 int32_t scale; 84 int32_t scale;
85 enum wl_output_subpixel subpixel;
85 char *output_name; 86 char *output_name;
86 struct wl_list link; 87 struct wl_list link;
87}; 88};
diff --git a/sway/commands.c b/sway/commands.c
index 07169f1e..5b61f73a 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -237,7 +237,8 @@ static void set_config_node(struct sway_node *node) {
237 } 237 }
238} 238}
239 239
240struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { 240struct cmd_results *execute_command(char *_exec, struct sway_seat *seat,
241 struct sway_container *con) {
241 // Even though this function will process multiple commands we will only 242 // Even though this function will process multiple commands we will only
242 // return the last error, if any (for now). (Since we have access to an 243 // return the last error, if any (for now). (Since we have access to an
243 // error string we could e.g. concatenate all errors there.) 244 // error string we could e.g. concatenate all errors there.)
@@ -256,6 +257,15 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
256 } 257 }
257 } 258 }
258 259
260 // This is the container or workspace which this command will run on.
261 // Ignored if the command string contains criteria.
262 struct sway_node *node;
263 if (con) {
264 node = &con->node;
265 } else {
266 node = seat_get_focus_inactive(seat, &root->node);
267 }
268
259 config->handler_context.seat = seat; 269 config->handler_context.seat = seat;
260 270
261 head = exec; 271 head = exec;
@@ -318,9 +328,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
318 } 328 }
319 329
320 if (!config->handler_context.using_criteria) { 330 if (!config->handler_context.using_criteria) {
321 // without criteria, the command acts upon the focused 331 set_config_node(node);
322 // container
323 set_config_node(seat_get_focus_inactive(seat, &root->node));
324 struct cmd_results *res = handler->handle(argc-1, argv+1); 332 struct cmd_results *res = handler->handle(argc-1, argv+1);
325 if (res->status != CMD_SUCCESS) { 333 if (res->status != CMD_SUCCESS) {
326 free_argv(argc, argv); 334 free_argv(argc, argv);
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)
321 } 321 }
322 322
323 config->handler_context.seat = seat; 323 config->handler_context.seat = seat;
324 struct cmd_results *results = execute_command(binding->command, NULL); 324 struct cmd_results *results = execute_command(binding->command, NULL, NULL);
325 if (results->status == CMD_SUCCESS) { 325 if (results->status == CMD_SUCCESS) {
326 ipc_event_binding(binding_copy); 326 ipc_event_binding(binding_copy);
327 } else { 327 } else {
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index d747e279..797f6b4c 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -6,6 +6,7 @@
6#include <string.h> 6#include <string.h>
7#include <time.h> 7#include <time.h>
8#include <wlr/types/wlr_buffer.h> 8#include <wlr/types/wlr_buffer.h>
9#include "sway/config.h"
9#include "sway/debug.h" 10#include "sway/debug.h"
10#include "sway/desktop.h" 11#include "sway/desktop.h"
11#include "sway/desktop/idle_inhibit_v1.h" 12#include "sway/desktop/idle_inhibit_v1.h"
@@ -390,6 +391,16 @@ static bool should_configure(struct sway_node *node,
390 } 391 }
391 struct sway_container_state *cstate = &node->sway_container->current; 392 struct sway_container_state *cstate = &node->sway_container->current;
392 struct sway_container_state *istate = instruction->container_state; 393 struct sway_container_state *istate = instruction->container_state;
394#ifdef HAVE_XWAYLAND
395 // Xwayland views are position-aware and need to be reconfigured
396 // when their position changes.
397 if (node->sway_container->view->type == SWAY_VIEW_XWAYLAND) {
398 if (cstate->view_x != istate->view_x ||
399 cstate->view_y != istate->view_y) {
400 return true;
401 }
402 }
403#endif
393 if (cstate->view_width == istate->view_width && 404 if (cstate->view_width == istate->view_width &&
394 cstate->view_height == istate->view_height) { 405 cstate->view_height == istate->view_height) {
395 return false; 406 return false;
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) {
401 } else { 401 } else {
402 if (view->container->parent) { 402 if (view->container->parent) {
403 arrange_container(view->container->parent); 403 arrange_container(view->container->parent);
404 } else { 404 } else if (view->container->workspace) {
405 arrange_workspace(view->container->workspace); 405 arrange_workspace(view->container->workspace);
406 } 406 }
407 } 407 }
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) {
398 } else { 398 } else {
399 if (view->container->parent) { 399 if (view->container->parent) {
400 arrange_container(view->container->parent); 400 arrange_container(view->container->parent);
401 } else { 401 } else if (view->container->workspace) {
402 arrange_workspace(view->container->workspace); 402 arrange_workspace(view->container->workspace);
403 } 403 }
404 } 404 }
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) {
394 } else { 394 } else {
395 if (view->container->parent) { 395 if (view->container->parent) {
396 arrange_container(view->container->parent); 396 arrange_container(view->container->parent);
397 } else { 397 } else if (view->container->workspace) {
398 arrange_workspace(view->container->workspace); 398 arrange_workspace(view->container->workspace);
399 } 399 }
400 } 400 }
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 8ae265f6..99959c97 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -580,7 +580,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
580 switch (client->current_command) { 580 switch (client->current_command) {
581 case IPC_COMMAND: 581 case IPC_COMMAND:
582 { 582 {
583 struct cmd_results *results = execute_command(buf, NULL); 583 struct cmd_results *results = execute_command(buf, NULL, NULL);
584 transaction_commit_dirty(); 584 transaction_commit_dirty();
585 char *json = cmd_results_to_json(results); 585 char *json = cmd_results_to_json(results);
586 int length = strlen(json); 586 int length = strlen(json);
diff --git a/sway/main.c b/sway/main.c
index 3d7cd158..990f5f3a 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -429,7 +429,7 @@ int main(int argc, char **argv) {
429 wlr_log(WLR_DEBUG, "Running deferred commands"); 429 wlr_log(WLR_DEBUG, "Running deferred commands");
430 while (config->cmd_queue->length) { 430 while (config->cmd_queue->length) {
431 char *line = config->cmd_queue->items[0]; 431 char *line = config->cmd_queue->items[0];
432 struct cmd_results *res = execute_command(line, NULL); 432 struct cmd_results *res = execute_command(line, NULL, NULL);
433 if (res->status != CMD_SUCCESS) { 433 if (res->status != CMD_SUCCESS) {
434 wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error); 434 wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error);
435 } 435 }
diff --git a/sway/tree/container.c b/sway/tree/container.c
index b8af7564..53b127b7 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -463,11 +463,17 @@ static void update_title_texture(struct sway_container *con,
463 cairo_surface_t *surface = cairo_image_surface_create( 463 cairo_surface_t *surface = cairo_image_surface_create(
464 CAIRO_FORMAT_ARGB32, width, height); 464 CAIRO_FORMAT_ARGB32, width, height);
465 cairo_t *cairo = cairo_create(surface); 465 cairo_t *cairo = cairo_create(surface);
466 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
467 cairo_font_options_t *fo = cairo_font_options_create();
468 cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
469 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
470 cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(output->wlr_output->subpixel));
471 cairo_set_font_options(cairo, fo);
472 cairo_font_options_destroy(fo);
466 cairo_set_source_rgba(cairo, class->background[0], class->background[1], 473 cairo_set_source_rgba(cairo, class->background[0], class->background[1],
467 class->background[2], class->background[3]); 474 class->background[2], class->background[3]);
468 cairo_paint(cairo); 475 cairo_paint(cairo);
469 PangoContext *pango = pango_cairo_create_context(cairo); 476 PangoContext *pango = pango_cairo_create_context(cairo);
470 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
471 cairo_set_source_rgba(cairo, class->text[0], class->text[1], 477 cairo_set_source_rgba(cairo, class->text[0], class->text[1],
472 class->text[2], class->text[3]); 478 class->text[2], class->text[3]);
473 cairo_move_to(cairo, 0, 0); 479 cairo_move_to(cairo, 0, 0);
diff --git a/sway/tree/root.c b/sway/tree/root.c
index ecc04ddb..d6f67bd7 100644
--- a/sway/tree/root.c
+++ b/sway/tree/root.c
@@ -265,10 +265,10 @@ void root_for_each_container(void (*f)(struct sway_container *con, void *data),
265 // Scratchpad 265 // Scratchpad
266 for (int i = 0; i < root->scratchpad->length; ++i) { 266 for (int i = 0; i < root->scratchpad->length; ++i) {
267 struct sway_container *container = root->scratchpad->items[i]; 267 struct sway_container *container = root->scratchpad->items[i];
268 // If the container has a parent then it's visible on a workspace 268 // If the container has a workspace then it's visible on a workspace
269 // and will have been iterated in the previous for loop. So we only 269 // and will have been iterated in the previous for loop. So we only
270 // iterate the hidden scratchpad containers here. 270 // iterate the hidden scratchpad containers here.
271 if (!container->parent) { 271 if (!container->workspace) {
272 f(container, data); 272 f(container, data);
273 container_for_each_child(container, f, data); 273 container_for_each_child(container, f, data);
274 } 274 }
@@ -311,7 +311,7 @@ struct sway_container *root_find_container(
311 // Scratchpad 311 // Scratchpad
312 for (int i = 0; i < root->scratchpad->length; ++i) { 312 for (int i = 0; i < root->scratchpad->length; ++i) {
313 struct sway_container *container = root->scratchpad->items[i]; 313 struct sway_container *container = root->scratchpad->items[i];
314 if (!container->parent) { 314 if (!container->workspace) {
315 if (test(container, data)) { 315 if (test(container, data)) {
316 return container; 316 return container;
317 } 317 }
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 4398f518..e370443c 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,
391} 391}
392 392
393void view_execute_criteria(struct sway_view *view) { 393void view_execute_criteria(struct sway_view *view) {
394 struct sway_seat *seat = input_manager_current_seat(input_manager);
395 struct sway_node *prior_focus = seat_get_focus(seat);
396 list_t *criterias = criteria_for_view(view, CT_COMMAND); 394 list_t *criterias = criteria_for_view(view, CT_COMMAND);
397 for (int i = 0; i < criterias->length; i++) { 395 for (int i = 0; i < criterias->length; i++) {
398 struct criteria *criteria = criterias->items[i]; 396 struct criteria *criteria = criterias->items[i];
@@ -403,16 +401,12 @@ void view_execute_criteria(struct sway_view *view) {
403 } 401 }
404 wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", 402 wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'",
405 criteria->raw, view, criteria->cmdlist); 403 criteria->raw, view, criteria->cmdlist);
406 seat_set_focus_container(seat, view->container);
407 list_add(view->executed_criteria, criteria); 404 list_add(view->executed_criteria, criteria);
408 struct cmd_results *res = execute_command(criteria->cmdlist, NULL); 405 struct cmd_results *res = execute_command(
409 if (res->status != CMD_SUCCESS) { 406 criteria->cmdlist, NULL, view->container);
410 wlr_log(WLR_ERROR, "Command '%s' failed: %s", res->input, res->error);
411 }
412 free_cmd_results(res); 407 free_cmd_results(res);
413 } 408 }
414 list_free(criterias); 409 list_free(criterias);
415 seat_set_focus(seat, prior_focus);
416} 410}
417 411
418static struct sway_workspace *select_workspace(struct sway_view *view) { 412static 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) {
785} 779}
786 780
787static char *escape_title(char *buffer) { 781static char *escape_title(char *buffer) {
788 int length = escape_markup_text(buffer, NULL, 0); 782 size_t length = escape_markup_text(buffer, NULL);
789 char *escaped_title = calloc(length + 1, sizeof(char)); 783 char *escaped_title = calloc(length + 1, sizeof(char));
790 int result = escape_markup_text(buffer, escaped_title, length); 784 escape_markup_text(buffer, escaped_title);
791 if (result != length) {
792 wlr_log(WLR_ERROR, "Could not escape title: %s", buffer);
793 free(escaped_title);
794 return buffer;
795 }
796 free(buffer); 785 free(buffer);
797 return escaped_title; 786 return escaped_title;
798} 787}
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 18746430..b0c440c1 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -389,13 +389,11 @@ bool workspace_switch(struct sway_workspace *workspace,
389 struct sway_output *next_output = workspace->output; 389 struct sway_output *next_output = workspace->output;
390 struct sway_workspace *next_output_prev_ws = 390 struct sway_workspace *next_output_prev_ws =
391 output_get_active_workspace(next_output); 391 output_get_active_workspace(next_output);
392 bool has_sticky = false;
393 if (workspace != next_output_prev_ws) { 392 if (workspace != next_output_prev_ws) {
394 for (int i = 0; i < next_output_prev_ws->floating->length; ++i) { 393 for (int i = 0; i < next_output_prev_ws->floating->length; ++i) {
395 struct sway_container *floater = 394 struct sway_container *floater =
396 next_output_prev_ws->floating->items[i]; 395 next_output_prev_ws->floating->items[i];
397 if (floater->is_sticky) { 396 if (floater->is_sticky) {
398 has_sticky = true;
399 container_detach(floater); 397 container_detach(floater);
400 workspace_add_floating(workspace, floater); 398 workspace_add_floating(workspace, floater);
401 if (&floater->node == focus) { 399 if (&floater->node == focus) {
@@ -414,14 +412,6 @@ bool workspace_switch(struct sway_workspace *workspace,
414 if (next == NULL) { 412 if (next == NULL) {
415 next = &workspace->node; 413 next = &workspace->node;
416 } 414 }
417 if (has_sticky) {
418 // If there's a sticky container, we might be setting focus to the same
419 // container that's already focused, so seat_set_focus is effectively a
420 // no op. We therefore need to send the IPC event and clean up the old
421 // workspace here.
422 ipc_event_workspace(active_ws, workspace, "focus");
423 workspace_consider_destroy(active_ws);
424 }
425 seat_set_focus(seat, next); 415 seat_set_focus(seat, next);
426 arrange_workspace(workspace); 416 arrange_workspace(workspace);
427 cursor_send_pointer_motion(seat->cursor, 0, true); 417 cursor_send_pointer_motion(seat->cursor, 0, true);
diff --git a/swaybar/bar.c b/swaybar/bar.c
index 69069f40..ab307fd4 100644
--- a/swaybar/bar.c
+++ b/swaybar/bar.c
@@ -319,10 +319,14 @@ static bool bar_uses_output(struct swaybar *bar, const char *name) {
319 return false; 319 return false;
320} 320}
321 321
322static void output_geometry(void *data, struct wl_output *output, int32_t x, 322static void output_geometry(void *data, struct wl_output *wl_output, int32_t x,
323 int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel, 323 int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel,
324 const char *make, const char *model, int32_t transform) { 324 const char *make, const char *model, int32_t transform) {
325 // Who cares 325 struct swaybar_output *output = data;
326 output->subpixel = subpixel;
327 if (output->surface) {
328 render_frame(output->bar, output);
329 }
326} 330}
327 331
328static void output_mode(void *data, struct wl_output *output, uint32_t flags, 332static void output_mode(void *data, struct wl_output *output, uint32_t flags,
diff --git a/swaybar/render.c b/swaybar/render.c
index 26db80cb..9413dc57 100644
--- a/swaybar/render.c
+++ b/swaybar/render.c
@@ -495,6 +495,13 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) {
495 cairo_surface_t *recorder = cairo_recording_surface_create( 495 cairo_surface_t *recorder = cairo_recording_surface_create(
496 CAIRO_CONTENT_COLOR_ALPHA, NULL); 496 CAIRO_CONTENT_COLOR_ALPHA, NULL);
497 cairo_t *cairo = cairo_create(recorder); 497 cairo_t *cairo = cairo_create(recorder);
498 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
499 cairo_font_options_t *fo = cairo_font_options_create();
500 cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
501 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
502 cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(output->subpixel));
503 cairo_set_font_options(cairo, fo);
504 cairo_font_options_destroy(fo);
498 cairo_save(cairo); 505 cairo_save(cairo);
499 cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); 506 cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR);
500 cairo_paint(cairo); 507 cairo_paint(cairo);
diff --git a/swaybar/status_line.c b/swaybar/status_line.c
index 401bf6f6..48b43248 100644
--- a/swaybar/status_line.c
+++ b/swaybar/status_line.c
@@ -67,9 +67,13 @@ bool status_handle_readable(struct status_line *status) {
67 67
68 wl_list_init(&status->blocks); 68 wl_list_init(&status->blocks);
69 status->tokener = json_tokener_new(); 69 status->tokener = json_tokener_new();
70 status->buffer_index = getdelim(&status->buffer, 70 read_bytes = getdelim(&status->buffer, &status->buffer_size, EOF, status->read);
71 &status->buffer_size, EOF, status->read); 71 if (read_bytes > 0) {
72 return i3bar_handle_readable(status); 72 status->buffer_index = read_bytes;
73 return i3bar_handle_readable(status);
74 } else {
75 return false;
76 }
73 } 77 }
74 78
75 wlr_log(WLR_DEBUG, "Using text protocol."); 79 wlr_log(WLR_DEBUG, "Using text protocol.");
diff --git a/swaylock/main.c b/swaylock/main.c
index 668a8742..c25c8eec 100644
--- a/swaylock/main.c
+++ b/swaylock/main.c
@@ -195,11 +195,15 @@ void damage_state(struct swaylock_state *state) {
195 } 195 }
196} 196}
197 197
198static void handle_wl_output_geometry(void *data, struct wl_output *output, 198static void handle_wl_output_geometry(void *data, struct wl_output *wl_output,
199 int32_t x, int32_t y, int32_t width_mm, int32_t height_mm, 199 int32_t x, int32_t y, int32_t width_mm, int32_t height_mm,
200 int32_t subpixel, const char *make, const char *model, 200 int32_t subpixel, const char *make, const char *model,
201 int32_t transform) { 201 int32_t transform) {
202 // Who cares 202 struct swaylock_surface *surface = data;
203 surface->subpixel = subpixel;
204 if (surface->state->run_display) {
205 damage_surface(surface);
206 }
203} 207}
204 208
205static void handle_wl_output_mode(void *data, struct wl_output *output, 209static void handle_wl_output_mode(void *data, struct wl_output *output,
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) {
39 } 39 }
40 40
41 cairo_t *cairo = surface->current_buffer->cairo; 41 cairo_t *cairo = surface->current_buffer->cairo;
42 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
43 cairo_font_options_t *fo = cairo_font_options_create();
44 cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
45 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
46 cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(surface->subpixel));
47 cairo_set_font_options(cairo, fo);
48 cairo_font_options_destroy(fo);
42 cairo_identity_matrix(cairo); 49 cairo_identity_matrix(cairo);
43 50
44 cairo_save(cairo); 51 cairo_save(cairo);