aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sway/commands.h1
-rw-r--r--include/sway/config.h7
-rw-r--r--sway/commands.c1
-rw-r--r--sway/commands/resize.c28
-rw-r--r--sway/commands/title_align.c30
-rw-r--r--sway/config.c1
-rw-r--r--sway/desktop/render.c101
-rw-r--r--sway/meson.build1
-rw-r--r--sway/sway.5.scd5
-rw-r--r--sway/tree/view.c13
-rw-r--r--swayidle/main.c77
11 files changed, 203 insertions, 62 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index e6036e51..eb446eae 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -172,6 +172,7 @@ sway_cmd cmd_swaybg_command;
sway_cmd cmd_swaynag_command;
sway_cmd cmd_swap;
sway_cmd cmd_tiling_drag;
+sway_cmd cmd_title_align;
sway_cmd cmd_title_format;
sway_cmd cmd_titlebar_border_thickness;
sway_cmd cmd_titlebar_padding;
diff --git a/include/sway/config.h b/include/sway/config.h
index a6920835..1ff9a104 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -357,6 +357,12 @@ enum mouse_warping_mode {
WARP_CONTAINER
};
+enum alignment {
+ ALIGN_LEFT,
+ ALIGN_CENTER,
+ ALIGN_RIGHT
+};
+
/**
* The configuration struct. The result of loading a config file.
*/
@@ -409,6 +415,7 @@ struct sway_config {
bool validating;
bool auto_back_and_forth;
bool show_marks;
+ enum alignment title_align;
bool tiling_drag;
bool smart_gaps;
diff --git a/sway/commands.c b/sway/commands.c
index d35658d5..bffc18f6 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -103,6 +103,7 @@ static struct cmd_handler handlers[] = {
{ "smart_borders", cmd_smart_borders },
{ "smart_gaps", cmd_smart_gaps },
{ "tiling_drag", cmd_tiling_drag },
+ { "title_align", cmd_title_align },
{ "titlebar_border_thickness", cmd_titlebar_border_thickness },
{ "titlebar_padding", cmd_titlebar_padding },
{ "workspace", cmd_workspace },
diff --git a/sway/commands/resize.c b/sway/commands/resize.c
index a90d578e..cf5dea02 100644
--- a/sway/commands/resize.c
+++ b/sway/commands/resize.c
@@ -512,34 +512,42 @@ static struct cmd_results *resize_set_floating(struct sway_container *con,
calculate_constraints(&min_width, &max_width, &min_height, &max_height);
if (width->amount) {
- if (width->unit == RESIZE_UNIT_PPT ||
- width->unit == RESIZE_UNIT_DEFAULT) {
+ switch (width->unit) {
+ case RESIZE_UNIT_PPT:
// Convert to px
width->amount = con->workspace->width * width->amount / 100;
width->unit = RESIZE_UNIT_PX;
- }
- if (width->unit == RESIZE_UNIT_PX) {
+ // Falls through
+ case RESIZE_UNIT_PX:
+ case RESIZE_UNIT_DEFAULT:
width->amount = fmax(min_width, fmin(width->amount, max_width));
grow_width = width->amount - con->width;
-
con->x -= grow_width / 2;
con->width = width->amount;
+ break;
+ case RESIZE_UNIT_INVALID:
+ sway_assert(false, "invalid width unit");
+ break;
}
}
if (height->amount) {
- if (height->unit == RESIZE_UNIT_PPT ||
- height->unit == RESIZE_UNIT_DEFAULT) {
+ switch (height->unit) {
+ case RESIZE_UNIT_PPT:
// Convert to px
height->amount = con->workspace->height * height->amount / 100;
height->unit = RESIZE_UNIT_PX;
- }
- if (height->unit == RESIZE_UNIT_PX) {
+ // Falls through
+ case RESIZE_UNIT_PX:
+ case RESIZE_UNIT_DEFAULT:
height->amount = fmax(min_height, fmin(height->amount, max_height));
grow_height = height->amount - con->height;
-
con->y -= grow_height / 2;
con->height = height->amount;
+ break;
+ case RESIZE_UNIT_INVALID:
+ sway_assert(false, "invalid height unit");
+ break;
}
}
diff --git a/sway/commands/title_align.c b/sway/commands/title_align.c
new file mode 100644
index 00000000..82578186
--- /dev/null
+++ b/sway/commands/title_align.c
@@ -0,0 +1,30 @@
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/output.h"
+#include "sway/tree/container.h"
+#include "sway/tree/root.h"
+
+struct cmd_results *cmd_title_align(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "title_align", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+
+ if (strcmp(argv[0], "left") == 0) {
+ config->title_align = ALIGN_LEFT;
+ } else if (strcmp(argv[0], "center") == 0) {
+ config->title_align = ALIGN_CENTER;
+ } else if (strcmp(argv[0], "right") == 0) {
+ config->title_align = ALIGN_RIGHT;
+ } else {
+ return cmd_results_new(CMD_INVALID, "title_align",
+ "Expected 'title_align left|center|right'");
+ }
+
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ output_damage_whole(output);
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/config.c b/sway/config.c
index da40ace6..ed288060 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -233,6 +233,7 @@ static void config_defaults(struct sway_config *config) {
config->auto_back_and_forth = false;
config->reading = false;
config->show_marks = true;
+ config->title_align = ALIGN_LEFT;
config->tiling_drag = true;
config->smart_gaps = false;
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 51cb8980..eeda496c 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -371,6 +371,7 @@ static void render_titlebar(struct sway_output *output,
int titlebar_border_thickness = config->titlebar_border_thickness;
int titlebar_h_padding = config->titlebar_h_padding;
int titlebar_v_padding = config->titlebar_v_padding;
+ enum alignment title_align = config->title_align;
// Single pixel bar above title
memcpy(&color, colors->border, sizeof(float) * 4);
@@ -420,19 +421,25 @@ static void render_titlebar(struct sway_output *output,
render_rect(output->wlr_output, output_damage, &box, color);
}
- size_t inner_width = width - titlebar_h_padding * 2;
+ int inner_x = x - output_x + titlebar_h_padding;
int bg_y = y + titlebar_border_thickness;
+ size_t inner_width = width - titlebar_h_padding * 2;
+
+ // output-buffer local
+ int ob_inner_x = round(inner_x * output_scale);
+ int ob_inner_width = scale_length(inner_width, inner_x, output_scale);
int ob_bg_height = scale_length(
(titlebar_v_padding - titlebar_border_thickness) * 2 +
config->font_height, bg_y, output_scale);
// Marks
- int marks_ob_width = 0; // output-buffer-local
+ int ob_marks_x = 0; // output-buffer-local
+ int ob_marks_width = 0; // output-buffer-local
if (config->show_marks && marks_texture) {
struct wlr_box texture_box;
wlr_texture_get_size(marks_texture,
&texture_box.width, &texture_box.height);
- marks_ob_width = texture_box.width;
+ ob_marks_width = texture_box.width;
// The marks texture might be shorter than the config->font_height, in
// which case we need to pad it as evenly as possible above and below.
@@ -440,9 +447,15 @@ static void render_titlebar(struct sway_output *output,
int ob_padding_above = floor(ob_padding_total / 2.0);
int ob_padding_below = ceil(ob_padding_total / 2.0);
- // Render texture
- texture_box.x = round((x - output_x + width - titlebar_h_padding)
- * output_scale) - texture_box.width;
+ // Render texture. If the title is on the right, the marks will be on
+ // the left. Otherwise, they will be on the right.
+ if (title_align == ALIGN_RIGHT || texture_box.width > ob_inner_width) {
+ texture_box.x = ob_inner_x;
+ } else {
+ texture_box.x = ob_inner_x + ob_inner_width - texture_box.width;
+ }
+ ob_marks_x = texture_box.x;
+
texture_box.y = round((bg_y - output_y) * output_scale) +
ob_padding_above;
@@ -451,8 +464,8 @@ static void render_titlebar(struct sway_output *output,
WL_OUTPUT_TRANSFORM_NORMAL,
0.0, output->wlr_output->transform_matrix);
- if (inner_width * output_scale < texture_box.width) {
- texture_box.width = inner_width * output_scale;
+ if (ob_inner_width < texture_box.width) {
+ texture_box.width = ob_inner_width;
}
render_texture(output->wlr_output, output_damage, marks_texture,
&texture_box, matrix, con->alpha);
@@ -473,12 +486,13 @@ static void render_titlebar(struct sway_output *output,
}
// Title text
- size_t title_ob_width = 0; // output-buffer-local
+ int ob_title_x = 0; // output-buffer-local
+ int ob_title_width = 0; // output-buffer-local
if (title_texture) {
struct wlr_box texture_box;
wlr_texture_get_size(title_texture,
&texture_box.width, &texture_box.height);
- title_ob_width = texture_box.width;
+ ob_title_width = texture_box.width;
// The title texture might be shorter than the config->font_height,
// in which case we need to pad it above and below.
@@ -489,8 +503,26 @@ static void render_titlebar(struct sway_output *output,
texture_box.height;
// Render texture
- texture_box.x =
- round((x - output_x + titlebar_h_padding) * output_scale);
+ if (texture_box.width > ob_inner_width - ob_marks_width) {
+ texture_box.x = (title_align == ALIGN_RIGHT && ob_marks_width)
+ ? ob_marks_x + ob_marks_width : ob_inner_x;
+ } else if (title_align == ALIGN_LEFT) {
+ texture_box.x = ob_inner_x;
+ } else if (title_align == ALIGN_CENTER) {
+ // If there are marks visible, center between the edge and marks.
+ // Otherwise, center in the inner area.
+ if (ob_marks_width) {
+ texture_box.x = (ob_inner_x + ob_marks_x) / 2
+ - texture_box.width / 2;
+ } else {
+ texture_box.x = ob_inner_x + ob_inner_width / 2
+ - texture_box.width / 2;
+ }
+ } else {
+ texture_box.x = ob_inner_x + ob_inner_width - texture_box.width;
+ }
+ ob_title_x = texture_box.x;
+
texture_box.y =
round((bg_y - output_y) * output_scale) + ob_padding_above;
@@ -499,11 +531,10 @@ static void render_titlebar(struct sway_output *output,
WL_OUTPUT_TRANSFORM_NORMAL,
0.0, output->wlr_output->transform_matrix);
- int inner_x = x - output_x + titlebar_h_padding;
- int ob_inner_width = scale_length(inner_width, inner_x, output_scale);
- if (ob_inner_width - marks_ob_width < texture_box.width) {
- texture_box.width = ob_inner_width - marks_ob_width;
+ if (ob_inner_width - ob_marks_width < texture_box.width) {
+ texture_box.width = ob_inner_width - ob_marks_width;
}
+
render_texture(output->wlr_output, output_damage, title_texture,
&texture_box, matrix, con->alpha);
@@ -522,17 +553,36 @@ static void render_titlebar(struct sway_output *output,
render_rect(output->wlr_output, output_damage, &box, color);
}
+ // Determine the left + right extends of the textures (output-buffer local)
+ int ob_left_x, ob_left_width, ob_right_x, ob_right_width;
+ if (ob_title_x < ob_marks_x) {
+ ob_left_x = ob_title_x;
+ ob_left_width = ob_title_width;
+ ob_right_x = ob_marks_x;
+ ob_right_width = ob_marks_width;
+ } else {
+ ob_left_x = ob_marks_x;
+ ob_left_width = ob_marks_width;
+ ob_right_x = ob_title_x;
+ ob_right_width = ob_title_width;
+ }
+ if (ob_left_x < ob_inner_x) {
+ ob_left_x = ob_inner_x;
+ } else if (ob_left_x + ob_left_width > ob_right_x + ob_right_width) {
+ ob_right_x = ob_left_x;
+ ob_right_width = ob_left_width;
+ }
+
// Filler between title and marks
- box.width =
- round(inner_width * output_scale) - title_ob_width - marks_ob_width;
+ box.width = ob_right_x - ob_left_x - ob_left_width;
if (box.width > 0) {
- box.x = round((x + titlebar_h_padding) * output_scale) + title_ob_width;
+ box.x = ob_left_x + ob_left_width + round(output_x * output_scale);
box.y = round(bg_y * output_scale);
box.height = ob_bg_height;
render_rect(output->wlr_output, output_damage, &box, color);
}
- // Padding left of title
+ // Padding on left side
left_offset = (layout == L_TABBED) * titlebar_border_thickness;
box.x = x + left_offset;
box.y = y + titlebar_border_thickness;
@@ -540,9 +590,13 @@ static void render_titlebar(struct sway_output *output,
box.height = (titlebar_v_padding - titlebar_border_thickness) * 2 +
config->font_height;
scale_box(&box, output_scale);
+ int left_x = ob_left_x + round(output_x * output_scale);
+ if (box.x + box.width < left_x) {
+ box.width += left_x - box.x - box.width;
+ }
render_rect(output->wlr_output, output_damage, &box, color);
- // Padding right of marks
+ // Padding on right side
right_offset = (layout == L_TABBED) * titlebar_border_thickness;
box.x = x + width - titlebar_h_padding;
box.y = y + titlebar_border_thickness;
@@ -550,6 +604,11 @@ static void render_titlebar(struct sway_output *output,
box.height = (titlebar_v_padding - titlebar_border_thickness) * 2 +
config->font_height;
scale_box(&box, output_scale);
+ int right_rx = ob_right_x + ob_right_width + round(output_x * output_scale);
+ if (right_rx < box.x) {
+ box.width += box.x - right_rx;
+ box.x = right_rx;
+ }
render_rect(output->wlr_output, output_damage, &box, color);
if (connects_sides) {
diff --git a/sway/meson.build b/sway/meson.build
index c8c95a96..75131891 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -88,6 +88,7 @@ sway_sources = files(
'commands/swaynag_command.c',
'commands/swap.c',
'commands/tiling_drag.c',
+ 'commands/title_align.c',
'commands/title_format.c',
'commands/titlebar_border_thickness.c',
'commands/titlebar_padding.c',
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index 6ccb1acf..4edd16bf 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -555,6 +555,11 @@ The default colors are:
Set the opacity of the window between 0 (completely transparent) and 1
(completely opaque).
+*title\_align* left|center|right
+ Sets the title alignment. If _right_ is selected and _show\_marks_ is set
+ to _yes_, the marks will be shown on the _left_ side instead of the
+ _right_ side.
+
*unmark* [<identifier>]
*unmark* will remove _identifier_ from the list of current marks on a
window. If _identifier_ is omitted, all marks are removed.
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 63bb8e26..febba3b9 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -835,11 +835,10 @@ static size_t append_prop(char *buffer, const char *value) {
if (!value) {
return 0;
}
- // if using pango_markup in font, we need to escape all markup char
- // from values to avoid messing with pango markup
- if (!config->pango_markup) {
+ // If using pango_markup in font, we need to escape all markup chars
+ // from values to make sure tags are not inserted by clients
+ if (config->pango_markup) {
char *escaped_value = escape_pango_markup(value);
-
lenient_strcat(buffer, escaped_value);
size_t len = strlen(escaped_value);
free(escaped_value);
@@ -856,11 +855,7 @@ static size_t append_prop(char *buffer, const char *value) {
*/
static size_t parse_title_format(struct sway_view *view, char *buffer) {
if (!view->title_format || strcmp(view->title_format, "%title") == 0) {
- const char *title = view_get_title(view);
- if (buffer && title) {
- strcpy(buffer, title);
- }
- return title ? strlen(title) : 0;
+ return append_prop(buffer, view_get_title(view));
}
size_t len = 0;
diff --git a/swayidle/main.c b/swayidle/main.c
index 2b185949..dd7d9de3 100644
--- a/swayidle/main.c
+++ b/swayidle/main.c
@@ -43,6 +43,12 @@ struct swayidle_timeout_cmd {
char *resume_cmd;
};
+void sway_terminate(int exit_code) {
+ wl_display_disconnect(state.display);
+ wl_event_loop_destroy(state.event_loop);
+ exit(exit_code);
+}
+
static void cmd_exec(char *param) {
wlr_log(WLR_DEBUG, "Cmd exec %s", param);
pid_t pid = fork();
@@ -81,16 +87,16 @@ static int release_lock(void *data) {
}
static void acquire_sleep_lock(void) {
- sd_bus_message *msg;
- sd_bus_error error;
+ sd_bus_message *msg = NULL;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
int ret = sd_bus_call_method(bus, "org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager", "Inhibit",
&error, &msg, "ssss", "sleep", "swayidle",
"Setup Up Lock Screen", "delay");
if (ret < 0) {
- wlr_log(WLR_ERROR, "Failed to send Inhibit signal: %s",
- strerror(-ret));
+ wlr_log(WLR_ERROR, "Failed to send Inhibit signal: %s", error.message);
+ sd_bus_error_free(&error);
return;
}
@@ -98,10 +104,11 @@ static void acquire_sleep_lock(void) {
if (ret < 0) {
wlr_log(WLR_ERROR, "Failed to parse D-Bus response for Inhibit: %s",
strerror(-ret));
- return;
+ } else {
+ wlr_log(WLR_INFO, "Got sleep lock: %d", lock_fd);
}
-
- wlr_log(WLR_INFO, "Got sleep lock: %d", lock_fd);
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(msg);
}
static int prepare_for_sleep(sd_bus_message *msg, void *userdata,
@@ -137,10 +144,28 @@ static int prepare_for_sleep(sd_bus_message *msg, void *userdata,
static int dbus_event(int fd, uint32_t mask, void *data) {
sd_bus *bus = data;
- while (sd_bus_process(bus, NULL) > 0) {
- // Do nothing.
+
+ if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
+ sway_terminate(0);
+ }
+
+ int count = 0;
+ if (mask & WL_EVENT_READABLE) {
+ count = sd_bus_process(bus, NULL);
}
- return 1;
+ if (mask & WL_EVENT_WRITABLE) {
+ sd_bus_flush(bus);
+ }
+ if (mask == 0) {
+ sd_bus_flush(bus);
+ }
+
+ if (count < 0) {
+ wlr_log_errno(WLR_ERROR, "sd_bus_process failed, exiting");
+ sway_terminate(0);
+ }
+
+ return count;
}
static void setup_sleep_listener(void) {
@@ -166,8 +191,9 @@ static void setup_sleep_listener(void) {
}
acquire_sleep_lock();
- wl_event_loop_add_fd(state.event_loop, sd_bus_get_fd(bus),
- WL_EVENT_READABLE, dbus_event, bus);
+ struct wl_event_source *source = wl_event_loop_add_fd(state.event_loop,
+ sd_bus_get_fd(bus), WL_EVENT_READABLE, dbus_event, bus);
+ wl_event_source_check(source);
}
#endif
@@ -339,12 +365,6 @@ static int parse_args(int argc, char *argv[]) {
return 0;
}
-void sway_terminate(int exit_code) {
- wl_display_disconnect(state.display);
- wl_event_loop_destroy(state.event_loop);
- exit(exit_code);
-}
-
static void register_zero_idle_timeout(void *item) {
struct swayidle_timeout_cmd *cmd = item;
register_timeout(cmd, 0);
@@ -365,15 +385,28 @@ static int handle_signal(int sig, void *data) {
}
static int display_event(int fd, uint32_t mask, void *data) {
- if (mask & WL_EVENT_HANGUP) {
+ if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
sway_terminate(0);
}
- if (wl_display_dispatch(state.display) < 0) {
+
+ int count = 0;
+ if (mask & WL_EVENT_READABLE) {
+ count = wl_display_dispatch(state.display);
+ }
+ if (mask & WL_EVENT_WRITABLE) {
+ wl_display_flush(state.display);
+ }
+ if (mask == 0) {
+ count = wl_display_dispatch_pending(state.display);
+ wl_display_flush(state.display);
+ }
+
+ if (count < 0) {
wlr_log_errno(WLR_ERROR, "wl_display_dispatch failed, exiting");
sway_terminate(0);
}
- wl_display_flush(state.display);
- return 0;
+
+ return count;
}
static void register_idle_timeout(void *item) {