aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/stringop.c14
-rw-r--r--include/stringop.h5
-rw-r--r--include/sway/tree/container.h17
-rw-r--r--include/swaylock/swaylock.h15
-rw-r--r--sway/commands/layout.c3
-rw-r--r--sway/desktop/output.c602
-rw-r--r--sway/input/cursor.c4
-rw-r--r--sway/ipc-server.c22
-rw-r--r--sway/tree/arrange.c33
-rw-r--r--sway/tree/container.c115
-rw-r--r--sway/tree/layout.c44
-rw-r--r--sway/tree/view.c68
-rw-r--r--swaylock/main.c99
-rw-r--r--swaylock/render.c3
14 files changed, 559 insertions, 485 deletions
diff --git a/common/stringop.c b/common/stringop.c
index 4a37543d..d9ae9925 100644
--- a/common/stringop.c
+++ b/common/stringop.c
@@ -55,6 +55,20 @@ void strip_quotes(char *str) {
*end = '\0';
}
+char *lenient_strcat(char *dest, const char *src) {
+ if (dest && src) {
+ return strcat(dest, src);
+ }
+ return dest;
+}
+
+char *lenient_strncat(char *dest, const char *src, size_t len) {
+ if (dest && src) {
+ return strncat(dest, src, len);
+ }
+ return dest;
+}
+
// strcmp that also handles null pointers.
int lenient_strcmp(char *a, char *b) {
if (a == b) {
diff --git a/include/stringop.h b/include/stringop.h
index 7c29a745..e7f58011 100644
--- a/include/stringop.h
+++ b/include/stringop.h
@@ -1,5 +1,6 @@
#ifndef _SWAY_STRINGOP_H
#define _SWAY_STRINGOP_H
+#include <stdlib.h>
#include "list.h"
#if !HAVE_DECL_SETENV
@@ -14,6 +15,10 @@ char *strip_whitespace(char *str);
char *strip_comments(char *str);
void strip_quotes(char *str);
+// strcat that does nothing if dest or src is NULL
+char *lenient_strcat(char *dest, const char *src);
+char *lenient_strncat(char *dest, const char *src, size_t len);
+
// strcmp that also handles null pointers.
int lenient_strcmp(char *a, char *b);
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 598a4f3d..a5f591ce 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -11,6 +11,12 @@ extern struct sway_container root_container;
struct sway_view;
struct sway_seat;
+#define TITLEBAR_BORDER_THICKNESS 1
+
+// Padding includes titlebar border
+#define TITLEBAR_H_PADDING 3
+#define TITLEBAR_V_PADDING 4
+
/**
* Different kinds of containers.
*
@@ -210,6 +216,15 @@ void container_update_title_textures(struct sway_container *container);
*/
void container_calculate_title_height(struct sway_container *container);
-void container_notify_child_title_changed(struct sway_container *container);
+/**
+ * Notify a container that a tree modification has changed in its children,
+ * so the container can update its tree representation.
+ */
+void container_notify_subtree_changed(struct sway_container *container);
+
+/**
+ * Return the height of a regular title bar.
+ */
+size_t container_titlebar_height(void);
#endif
diff --git a/include/swaylock/swaylock.h b/include/swaylock/swaylock.h
index e161ada9..dae823b8 100644
--- a/include/swaylock/swaylock.h
+++ b/include/swaylock/swaylock.h
@@ -10,13 +10,13 @@
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
enum auth_state {
- AUTH_STATE_IDLE,
- AUTH_STATE_CLEAR,
- AUTH_STATE_INPUT,
- AUTH_STATE_INPUT_NOP,
- AUTH_STATE_BACKSPACE,
- AUTH_STATE_VALIDATING,
- AUTH_STATE_INVALID,
+ AUTH_STATE_IDLE,
+ AUTH_STATE_CLEAR,
+ AUTH_STATE_INPUT,
+ AUTH_STATE_INPUT_NOP,
+ AUTH_STATE_BACKSPACE,
+ AUTH_STATE_VALIDATING,
+ AUTH_STATE_INVALID,
};
struct swaylock_args {
@@ -50,6 +50,7 @@ struct swaylock_surface {
cairo_surface_t *image;
struct swaylock_state *state;
struct wl_output *output;
+ uint32_t output_global_name;
struct zxdg_output_v1 *xdg_output;
struct wl_surface *surface;
struct zwlr_layer_surface_v1 *layer_surface;
diff --git a/sway/commands/layout.c b/sway/commands/layout.c
index 8aa321ae..6b44b001 100644
--- a/sway/commands/layout.c
+++ b/sway/commands/layout.c
@@ -41,6 +41,8 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
parent->layout = L_VERT;
} else if (strcasecmp(argv[0], "tabbed") == 0) {
parent->layout = L_TABBED;
+ } else if (strcasecmp(argv[0], "stacking") == 0) {
+ parent->layout = L_STACKED;
} else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) {
if (parent->layout == L_HORIZ) {
parent->layout = L_VERT;
@@ -50,6 +52,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
}
}
+ container_notify_subtree_changed(parent);
arrange_children_of(parent);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 551e96fc..765647fd 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -269,17 +269,6 @@ static void render_unmanaged(struct sway_output *output,
render_surface_iterator, &data);
}
-static void render_view(struct sway_view *view, struct sway_output *output,
- pixman_region32_t *damage) {
- struct render_data data = {
- .output = output,
- .damage = damage,
- .alpha = view->swayc->alpha,
- };
- output_view_for_each_surface(
- view, &data.root_geo, render_surface_iterator, &data);
-}
-
static void render_rect(struct wlr_output *wlr_output,
pixman_region32_t *output_damage, const struct wlr_box *_box,
float color[static 4]) {
@@ -317,108 +306,161 @@ static void premultiply_alpha(float color[4], float opacity) {
color[2] *= color[3];
}
+static void render_view_surfaces(struct sway_view *view,
+ struct sway_output *output, pixman_region32_t *damage) {
+ struct render_data data = {
+ .output = output,
+ .damage = damage,
+ .alpha = view->swayc->alpha,
+ };
+ output_view_for_each_surface(
+ view, &data.root_geo, render_surface_iterator, &data);
+}
+
/**
- * Render decorations for a view with "border normal".
- *
- * Care must be taken not to render over the same pixel multiple times,
- * otherwise the colors will be incorrect when using opacity.
+ * Render a view's surface and left/bottom/right borders.
*/
-static void render_container_simple_border_normal(struct sway_output *output,
- pixman_region32_t *output_damage,
- struct sway_container *con, struct border_colors *colors,
- struct wlr_texture *title_texture, struct wlr_texture *marks_texture) {
- struct wlr_box box;
- float color[4];
+static void render_view(struct sway_output *output, pixman_region32_t *damage,
+ struct sway_container *con, struct border_colors *colors) {
struct sway_view *view = con->sway_view;
- float output_scale = output->wlr_output->scale;
+ render_view_surfaces(view, output, damage);
- if (view->border_left) {
- // Child border - left edge
- memcpy(&color, colors->child_border, sizeof(float) * 4);
- premultiply_alpha(color, con->alpha);
- box.x = con->x;
- box.y = con->y + 1;
- box.width = view->border_thickness;
- box.height = con->height - 1
- - view->border_thickness * view->border_bottom;
- scale_box(&box, output_scale);
- render_rect(output->wlr_output, output_damage, &box, color);
- }
+ struct wlr_box box;
+ float output_scale = output->wlr_output->scale;
+ float color[4];
- if (view->border_right) {
- // Child border - right edge
- if (con->parent->children->length == 1
- && con->parent->layout == L_HORIZ) {
- memcpy(&color, colors->indicator, sizeof(float) * 4);
- } else {
+ if (view->border != B_NONE) {
+ if (view->border_left) {
memcpy(&color, colors->child_border, sizeof(float) * 4);
+ premultiply_alpha(color, con->alpha);
+ box.x = con->x;
+ box.y = view->y;
+ box.width = view->border_thickness;
+ box.height = view->height;
+ scale_box(&box, output_scale);
+ render_rect(output->wlr_output, damage, &box, color);
}
- premultiply_alpha(color, con->alpha);
- box.x = con->x + con->width - view->border_thickness;
- box.y = con->y + 1;
- box.width = view->border_thickness;
- box.height = con->height - 1
- - view->border_thickness * view->border_bottom;
- scale_box(&box, output_scale);
- render_rect(output->wlr_output, output_damage, &box, color);
- }
- if (view->border_bottom) {
- // Child border - bottom edge
- if (con->parent->children->length == 1
- && con->parent->layout == L_VERT) {
- memcpy(&color, colors->indicator, sizeof(float) * 4);
- } else {
- memcpy(&color, colors->child_border, sizeof(float) * 4);
+ if (view->border_right) {
+ if (con->parent->children->length == 1
+ && con->parent->layout == L_HORIZ) {
+ memcpy(&color, colors->indicator, sizeof(float) * 4);
+ } else {
+ memcpy(&color, colors->child_border, sizeof(float) * 4);
+ }
+ premultiply_alpha(color, con->alpha);
+ box.x = view->x + view->width;
+ box.y = view->y;
+ box.width = view->border_thickness;
+ box.height = view->height;
+ scale_box(&box, output_scale);
+ render_rect(output->wlr_output, damage, &box, color);
+ }
+
+ if (view->border_bottom) {
+ if (con->parent->children->length == 1
+ && con->parent->layout == L_VERT) {
+ memcpy(&color, colors->indicator, sizeof(float) * 4);
+ } else {
+ memcpy(&color, colors->child_border, sizeof(float) * 4);
+ }
+ premultiply_alpha(color, con->alpha);
+ box.x = con->x;
+ box.y = view->y + view->height;
+ box.width = con->width;
+ box.height = view->border_thickness;
+ scale_box(&box, output_scale);
+ render_rect(output->wlr_output, damage, &box, color);
}
- premultiply_alpha(color, con->alpha);
- box.x = con->x;
- box.y = con->y + con->height - view->border_thickness;
- box.width = con->width;
- box.height = view->border_thickness;
- scale_box(&box, output_scale);
- render_rect(output->wlr_output, output_damage, &box, color);
}
+}
+
+/**
+ * Render a titlebar.
+ *
+ * Care must be taken not to render over the same pixel multiple times,
+ * otherwise the colors will be incorrect when using opacity.
+ *
+ * The height is: 1px border, 3px padding, font height, 3px padding, 1px border
+ * The left side for L_TABBED is: 1px border, 2px padding, title
+ * The left side for other layouts is: 3px padding, title
+ */
+static void render_titlebar(struct sway_output *output,
+ pixman_region32_t *output_damage, struct sway_container *con,
+ int x, int y, int width,
+ struct border_colors *colors, struct wlr_texture *title_texture,
+ struct wlr_texture *marks_texture) {
+ struct wlr_box box;
+ float color[4];
+ struct sway_view *view = con->type == C_VIEW ? con->sway_view : NULL;
+ float output_scale = output->wlr_output->scale;
+ enum sway_container_layout layout = con->parent->layout;
+ bool is_last_child =
+ con->parent->children->items[con->parent->children->length - 1] == con;
// Single pixel bar above title
memcpy(&color, colors->border, sizeof(float) * 4);
premultiply_alpha(color, con->alpha);
- box.x = con->x;
- box.y = con->y;
- box.width = con->width;
- box.height = 1;
+ box.x = x;
+ box.y = y;
+ box.width = width;
+ box.height = TITLEBAR_BORDER_THICKNESS;
scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
- // Setting these makes marks and title easier
- size_t inner_x = con->x + view->border_thickness * view->border_left;
- size_t inner_width = con->width - view->border_thickness * view->border_left
- - view->border_thickness * view->border_right;
-
// Single pixel bar below title
- memcpy(&color, colors->border, sizeof(float) * 4);
- premultiply_alpha(color, con->alpha);
- box.x = inner_x;
- box.y = view->y - 1;
- box.width = inner_width;
- box.height = 1;
+ size_t left_offset = 0, right_offset = 0;
+ bool connects_sides = false;
+ if (layout == L_HORIZ || layout == L_VERT ||
+ (layout == L_STACKED && is_last_child)) {
+ if (view) {
+ left_offset = view->border_left * view->border_thickness;
+ right_offset = view->border_right * view->border_thickness;
+ connects_sides = true;
+ }
+ }
+ box.x = x + left_offset;
+ box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
+ box.width = width - left_offset - right_offset;
+ box.height = TITLEBAR_BORDER_THICKNESS;
scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
+ if (layout == L_TABBED) {
+ // Single pixel left edge
+ box.x = x;
+ box.y = y + TITLEBAR_BORDER_THICKNESS;
+ box.width = TITLEBAR_BORDER_THICKNESS;
+ box.height =
+ container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2;
+ scale_box(&box, output_scale);
+ render_rect(output->wlr_output, output_damage, &box, color);
+
+ // Single pixel right edge
+ box.x = (x + width - TITLEBAR_BORDER_THICKNESS) * output_scale;
+ render_rect(output->wlr_output, output_damage, &box, color);
+ }
+
+ size_t inner_width = width - TITLEBAR_H_PADDING * 2;
+
// Marks
size_t marks_width = 0;
if (config->show_marks && marks_texture) {
struct wlr_box texture_box;
wlr_texture_get_size(marks_texture,
&texture_box.width, &texture_box.height);
- texture_box.x = (inner_x + inner_width) * output_scale - texture_box.width;
- texture_box.y = (con->y + view->border_thickness) * output_scale;
+ texture_box.x =
+ (x + width - TITLEBAR_H_PADDING) * output_scale - texture_box.width;
+ texture_box.y = (y + TITLEBAR_V_PADDING) * output_scale;
float matrix[9];
wlr_matrix_project_box(matrix, &texture_box,
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;
+ }
render_texture(output->wlr_output, output_damage, marks_texture,
&texture_box, matrix, con->alpha);
marks_width = texture_box.width;
@@ -430,8 +472,8 @@ static void render_container_simple_border_normal(struct sway_output *output,
struct wlr_box texture_box;
wlr_texture_get_size(title_texture,
&texture_box.width, &texture_box.height);
- texture_box.x = inner_x * output_scale;
- texture_box.y = (con->y + view->border_thickness) * output_scale;
+ texture_box.x = (x + TITLEBAR_H_PADDING) * output_scale;
+ texture_box.y = (y + TITLEBAR_V_PADDING) * output_scale;
float matrix[9];
wlr_matrix_project_box(matrix, &texture_box,
@@ -446,104 +488,89 @@ static void render_container_simple_border_normal(struct sway_output *output,
title_width = texture_box.width;
}
- // Title background - above the text
+ // Padding above title
memcpy(&color, colors->background, sizeof(float) * 4);
premultiply_alpha(color, con->alpha);
- box.x = inner_x;
- box.y = con->y + 1;
- box.width = inner_width;
- box.height = view->border_thickness - 1;
+ box.x = x + (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
+ box.y = y + TITLEBAR_BORDER_THICKNESS;
+ box.width = width - (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS * 2;
+ box.height = TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS;
scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
- // Title background - below the text
- box.y = (con->y + view->border_thickness + config->font_height)
- * output_scale;
+ // Padding below title
+ box.y = (y + TITLEBAR_V_PADDING + config->font_height) * output_scale;
render_rect(output->wlr_output, output_damage, &box, color);
- // Title background - filler between title and marks
+ // Filler between title and marks
box.width = inner_width * output_scale - title_width - marks_width;
if (box.width > 0) {
- box.x = inner_x * output_scale + title_width;
- box.y = (con->y + view->border_thickness) * output_scale;
+ box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_width;
+ box.y = (y + TITLEBAR_V_PADDING) * output_scale;
box.height = config->font_height * output_scale;
render_rect(output->wlr_output, output_damage, &box, color);
}
-}
-/**
- * Render decorations for a view with "border pixel".
- *
- * Care must be taken not to render over the same pixel multiple times,
- * otherwise the colors will be incorrect when using opacity.
- */
-static void render_container_simple_border_pixel(struct sway_output *output,
- pixman_region32_t *output_damage, struct sway_container *con,
- struct border_colors *colors) {
- struct wlr_box box;
- float color[4];
- struct sway_view *view = con->sway_view;
- float output_scale = output->wlr_output->scale;
+ // Padding left of title
+ left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
+ box.x = x + left_offset;
+ box.y = y + TITLEBAR_V_PADDING;
+ box.width = TITLEBAR_H_PADDING - left_offset;
+ box.height = config->font_height;
+ scale_box(&box, output_scale);
+ render_rect(output->wlr_output, output_damage, &box, color);
- if (view->border_left) {
- // Child border - left edge
- memcpy(&color, colors->child_border, sizeof(float) * 4);
- premultiply_alpha(color, con->alpha);
- box.x = con->x;
- box.y = con->y + view->border_thickness * view->border_top;
- box.width = view->border_thickness;
- box.height = con->height - view->border_thickness
- * (view->border_top + view->border_bottom);
- scale_box(&box, output_scale);
- render_rect(output->wlr_output, output_damage, &box, color);
- }
+ // Padding right of marks
+ right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
+ box.x = x + width - TITLEBAR_H_PADDING;
+ box.y = y + TITLEBAR_V_PADDING;
+ box.width = TITLEBAR_H_PADDING - right_offset;
+ box.height = config->font_height;
+ scale_box(&box, output_scale);
+ render_rect(output->wlr_output, output_damage, &box, color);
- if (view->border_right) {
- // Child border - right edge
- if (con->parent->children->length == 1
- && con->parent->layout == L_HORIZ) {
- memcpy(&color, colors->indicator, sizeof(float) * 4);
- } else {
- memcpy(&color, colors->child_border, sizeof(float) * 4);
- }
- premultiply_alpha(color, con->alpha);
- box.x = con->x + con->width - view->border_thickness;
- box.y = con->y + view->border_thickness * view->border_top;
- box.width = view->border_thickness;
- box.height = con->height - view->border_thickness
- * (view->border_top + view->border_bottom);
+ if (connects_sides) {
+ // Left pixel in line with bottom bar
+ box.x = x;
+ box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
+ box.width = view->border_thickness * view->border_left;
+ box.height = TITLEBAR_BORDER_THICKNESS;
scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
- }
- if (view->border_top) {
- // Child border - top edge
- memcpy(&color, colors->child_border, sizeof(float) * 4);
- premultiply_alpha(color, con->alpha);
- box.x = con->x;
- box.y = con->y;
- box.width = con->width;
- box.height = view->border_thickness;
+ // Right pixel in line with bottom bar
+ box.x = x + width - view->border_thickness * view->border_right;
+ box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
+ box.width = view->border_thickness * view->border_right;
+ box.height = TITLEBAR_BORDER_THICKNESS;
scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
}
+}
- if (view->border_bottom) {
- // Child border - bottom edge
- if (con->parent->children->length == 1
- && con->parent->layout == L_VERT) {
- memcpy(&color, colors->indicator, sizeof(float) * 4);
- } else {
- memcpy(&color, colors->child_border, sizeof(float) * 4);
- }
- premultiply_alpha(color, con->alpha);
- box.x = con->x;
- box.y = con->y + con->height - view->border_thickness;
- box.width = con->width;
- box.height = view->border_thickness;
- scale_box(&box, output_scale);
- render_rect(output->wlr_output, output_damage, &box, color);
+/**
+ * Render the top border line for a view using "border pixel".
+ */
+static void render_top_border(struct sway_output *output,
+ pixman_region32_t *output_damage, struct sway_container *con,
+ struct border_colors *colors) {
+ struct sway_view *view = con->sway_view;
+ if (!view->border_top) {
+ return;
}
+ struct wlr_box box;
+ float color[4];
+ float output_scale = output->wlr_output->scale;
+
+ // Child border - top edge
+ memcpy(&color, colors->child_border, sizeof(float) * 4);
+ premultiply_alpha(color, con->alpha);
+ box.x = con->x;
+ box.y = con->y;
+ box.width = con->width;
+ box.height = view->border_thickness;
+ scale_box(&box, output_scale);
+ render_rect(output->wlr_output, output_damage, &box, color);
}
static void render_container(struct sway_output *output,
@@ -565,33 +592,30 @@ static void render_container_simple(struct sway_output *output,
struct sway_container *child = con->children->items[i];
if (child->type == C_VIEW) {
- if (child->sway_view->border != B_NONE) {
- struct border_colors *colors;
- struct wlr_texture *title_texture;
- struct wlr_texture *marks_texture;
- if (focus == child || parent_focused) {
- colors = &config->border_colors.focused;
- title_texture = child->title_focused;
- marks_texture = child->sway_view->marks_focused;
- } else if (seat_get_focus_inactive(seat, con) == child) {
- colors = &config->border_colors.focused_inactive;
- title_texture = child->title_focused_inactive;
- marks_texture = child->sway_view->marks_focused_inactive;
- } else {
- colors = &config->border_colors.unfocused;
- title_texture = child->title_unfocused;
- marks_texture = child->sway_view->marks_unfocused;
- }
-
- if (child->sway_view->border == B_NORMAL) {
- render_container_simple_border_normal(output, damage,
- child, colors, title_texture, marks_texture);
- } else {
- render_container_simple_border_pixel(output, damage, child,
- colors);
- }
+ struct border_colors *colors;
+ struct wlr_texture *title_texture;
+ struct wlr_texture *marks_texture;
+ if (focus == child || parent_focused) {
+ colors = &config->border_colors.focused;
+ title_texture = child->title_focused;
+ marks_texture = child->sway_view->marks_focused;
+ } else if (seat_get_focus_inactive(seat, con) == child) {
+ colors = &config->border_colors.focused_inactive;
+ title_texture = child->title_focused_inactive;
+ marks_texture = child->sway_view->marks_focused_inactive;
+ } else {
+ colors = &config->border_colors.unfocused;
+ title_texture = child->title_unfocused;
+ marks_texture = child->sway_view->marks_unfocused;
+ }
+
+ if (child->sway_view->border == B_NORMAL) {
+ render_titlebar(output, damage, child, child->x, child->y,
+ child->width, colors, title_texture, marks_texture);
+ } else {
+ render_top_border(output, damage, child, colors);
}
- render_view(child->sway_view, output, damage);
+ render_view(output, damage, child, colors);
} else {
render_container(output, damage, child,
parent_focused || focus == child);
@@ -599,154 +623,71 @@ static void render_container_simple(struct sway_output *output,
}
}
-static void render_tab(struct sway_output *output, pixman_region32_t *damage,
- struct sway_container *parent, int child_index,
- struct border_colors *colors, struct wlr_texture *title_texture) {
- struct sway_container *con = parent->children->items[child_index];
- float output_scale = output->wlr_output->scale;
- float color[4];
- struct wlr_box box;
-
- int tab_width = parent->width / parent->children->length;
- int x = parent->x + tab_width * child_index;
- // Make last tab use the remaining width of the parent
- if (child_index == parent->children->length - 1) {
- tab_width = parent->width - tab_width * child_index;
+/**
+ * Render a container's children using the L_TABBED layout.
+ */
+static void render_container_tabbed(struct sway_output *output,
+ pixman_region32_t *damage, struct sway_container *con,
+ bool parent_focused) {
+ if (!con->children->length) {
+ return;
}
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+ struct sway_container *focus = seat_get_focus(seat);
+ struct sway_container *current = seat_get_active_child(seat, con);
+ struct border_colors *current_colors = NULL;
- // Single pixel bar above title
- memcpy(&color, colors->border, sizeof(float) * 4);
- premultiply_alpha(color, con->alpha);
- box.x = x;
- box.y = parent->y;
- box.width = tab_width;
- box.height = 1;
- scale_box(&box, output_scale);
- render_rect(output->wlr_output, damage, &box, color);
-
- // Single pixel bar below title
- box.y = (parent->y + config->border_thickness * 2 + config->font_height - 1)
- * output_scale;
- render_rect(output->wlr_output, damage, &box, color);
-
- // Single pixel bar on left
- box.x = x;
- box.y = parent->y + 1;
- box.width = 1;
- box.height = config->border_thickness * 2 + config->font_height - 2;
- scale_box(&box, output_scale);
- render_rect(output->wlr_output, damage, &box, color);
-
- // Single pixel bar on right
- box.x = (x + tab_width - 1) * output_scale;
- render_rect(output->wlr_output, damage, &box, color);
-
- // Title text
- size_t title_width = 0;
- if (title_texture) {
- struct wlr_box texture_box;
- wlr_texture_get_size(title_texture,
- &texture_box.width, &texture_box.height);
- texture_box.x = (x + 1 + config->border_thickness) * output_scale;
- texture_box.y = (parent->y + config->border_thickness) * output_scale;
-
- float matrix[9];
- wlr_matrix_project_box(matrix, &texture_box,
- WL_OUTPUT_TRANSFORM_NORMAL,
- 0.0, output->wlr_output->transform_matrix);
+ // Render tabs
+ for (int i = 0; i < con->children->length; ++i) {
+ struct sway_container *child = con->children->items[i];
+ struct border_colors *colors;
+ struct wlr_texture *title_texture;
+ struct wlr_texture *marks_texture;
+ struct sway_view *view =
+ child->type == C_VIEW ? child->sway_view : NULL;
- int available = (tab_width - config->border_thickness * 2 - 2)
- * output_scale;
- if (texture_box.width > available) {
- texture_box.width = available;
+ if (focus == child || parent_focused) {
+ colors = &config->border_colors.focused;
+ title_texture = child->title_focused;
+ marks_texture = view ? view->marks_focused : NULL;
+ } else if (child == current) {
+ colors = &config->border_colors.focused_inactive;
+ title_texture = child->title_focused_inactive;
+ marks_texture = view ? view->marks_focused : NULL;
+ } else {
+ colors = &config->border_colors.unfocused;
+ title_texture = child->title_unfocused;
+ marks_texture = view ? view->marks_unfocused : NULL;
}
- render_texture(output->wlr_output, damage, title_texture,
- &texture_box, matrix, 1.0);
- title_width = texture_box.width;
- }
-
- // Title background - above the text
- memcpy(&color, colors->background, sizeof(float) * 4);
- premultiply_alpha(color, con->alpha);
- box.x = x + 1;
- box.y = parent->y + 1;
- box.width = tab_width - 2;
- box.height = config->border_thickness - 1;
- scale_box(&box, output_scale);
- render_rect(output->wlr_output, damage, &box, color);
- // Title background - below the text
- box.y = (parent->y + config->border_thickness + config->font_height)
- * output_scale;
- render_rect(output->wlr_output, damage, &box, color);
-
- // Title background - left of text
- box.x = x + 1;
- box.y = parent->y + config->border_thickness;
- box.width = config->border_thickness;
- box.height = config->font_height;
- scale_box(&box, output_scale);
- render_rect(output->wlr_output, damage, &box, color);
-
- // Title background - right of text
- box.x = (x + 1 + config->border_thickness) * output_scale + title_width;
- box.y = (parent->y + config->border_thickness) * output_scale;
- box.width = (tab_width - config->border_thickness - 2) * output_scale
- - title_width;
- box.height = config->font_height * output_scale;
- render_rect(output->wlr_output, damage, &box, color);
-}
-
-static void render_tab_content(struct sway_output *output,
- pixman_region32_t *damage, struct sway_container *con,
- struct border_colors *colors) {
- struct sway_view *view = con->sway_view;
- render_view(view, output, damage);
-
- struct wlr_box box;
- float output_scale = output->wlr_output->scale;
- float color[4];
-
- if (view->border != B_NONE) {
- if (view->border_left) {
- memcpy(&color, colors->child_border, sizeof(float) * 4);
- premultiply_alpha(color, con->alpha);
- box.x = con->x;
- box.y = con->y + config->border_thickness * 2 + config->font_height;
- box.width = view->border_thickness;
- box.height = view->height;
- scale_box(&box, output_scale);
- render_rect(output->wlr_output, damage, &box, color);
+ int tab_width = con->width / con->children->length;
+ int x = con->x + tab_width * i;
+ // Make last tab use the remaining width of the parent
+ if (i == con->children->length - 1) {
+ tab_width = con->width - tab_width * i;
}
- if (view->border_right) {
- memcpy(&color, colors->child_border, sizeof(float) * 4);
- premultiply_alpha(color, con->alpha);
- box.x = view->x + view->width;
- box.y = con->y + config->border_thickness * 2 + config->font_height;
- box.width = view->border_thickness;
- box.height = view->height;
- scale_box(&box, output_scale);
- render_rect(output->wlr_output, damage, &box, color);
- }
+ render_titlebar(output, damage, child, x, child->y, tab_width, colors,
+ title_texture, marks_texture);
- if (view->border_bottom) {
- memcpy(&color, colors->child_border, sizeof(float) * 4);
- premultiply_alpha(color, con->alpha);
- box.x = con->x;
- box.y = view->y + view->height;
- box.width = con->width;
- box.height = view->border_thickness;
- scale_box(&box, output_scale);
- render_rect(output->wlr_output, damage, &box, color);
+ if (child == current) {
+ current_colors = colors;
}
}
+
+ // Render surface and left/right/bottom borders
+ if (current->type == C_VIEW) {
+ render_view(output, damage, current, current_colors);
+ } else {
+ render_container(output, damage, current,
+ parent_focused || current == focus);
+ }
}
/**
- * Render a container's children using the L_TABBED layout.
+ * Render a container's children using the L_STACKED layout.
*/
-static void render_container_tabbed(struct sway_output *output,
+static void render_container_stacked(struct sway_output *output,
pixman_region32_t *damage, struct sway_container *con,
bool parent_focused) {
if (!con->children->length) {
@@ -757,24 +698,32 @@ static void render_container_tabbed(struct sway_output *output,
struct sway_container *current = seat_get_active_child(seat, con);
struct border_colors *current_colors = NULL;
- // Render tabs
+ // Render titles
for (int i = 0; i < con->children->length; ++i) {
struct sway_container *child = con->children->items[i];
struct border_colors *colors;
struct wlr_texture *title_texture;
+ struct wlr_texture *marks_texture;
+ struct sway_view *view =
+ child->type == C_VIEW ? child->sway_view : NULL;
if (focus == child || parent_focused) {
colors = &config->border_colors.focused;
title_texture = child->title_focused;
+ marks_texture = view ? view->marks_focused : NULL;
} else if (child == current) {
colors = &config->border_colors.focused_inactive;
title_texture = child->title_focused_inactive;
+ marks_texture = view ? view->marks_focused_inactive : NULL;
} else {
colors = &config->border_colors.unfocused;
title_texture = child->title_unfocused;
+ marks_texture = view ? view->marks_unfocused : NULL;
}
- render_tab(output, damage, con, i, colors, title_texture);
+ int y = con->y + container_titlebar_height() * i;
+ render_titlebar(output, damage, child, child->x, y, child->width,
+ colors, title_texture, marks_texture);
if (child == current) {
current_colors = colors;
@@ -783,21 +732,13 @@ static void render_container_tabbed(struct sway_output *output,
// Render surface and left/right/bottom borders
if (current->type == C_VIEW) {
- render_tab_content(output, damage, current, current_colors);
+ render_view(output, damage, current, current_colors);
} else {
render_container(output, damage, current,
parent_focused || current == focus);
}
}
-/**
- * Render a container's children using the L_STACKED layout.
- */
-static void render_container_stacked(struct sway_output *output,
- pixman_region32_t *damage, struct sway_container *con) {
- // TODO
-}
-
static void render_container(struct sway_output *output,
pixman_region32_t *damage, struct sway_container *con,
bool parent_focused) {
@@ -808,7 +749,7 @@ static void render_container(struct sway_output *output,
render_container_simple(output, damage, con, parent_focused);
break;
case L_STACKED:
- render_container_stacked(output, damage, con);
+ render_container_stacked(output, damage, con, parent_focused);
break;
case L_TABBED:
render_container_tabbed(output, damage, con, parent_focused);
@@ -868,7 +809,8 @@ static void render_output(struct sway_output *output, struct timespec *when,
}
// TODO: handle views smaller than the output
- render_view(workspace->sway_workspace->fullscreen, output, damage);
+ render_view_surfaces(
+ workspace->sway_workspace->fullscreen, output, damage);
if (workspace->sway_workspace->fullscreen->type == SWAY_VIEW_XWAYLAND) {
render_unmanaged(output, damage,
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index e0b987d2..9a0b4f01 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -147,10 +147,10 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
struct sway_container *c = container_at_coords(cursor->seat,
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
if (c && config->focus_follows_mouse && allow_refocusing) {
- if (c->type == C_WORKSPACE) {
+ struct sway_container *focus = seat_get_focus(cursor->seat);
+ if (focus && c->type == C_WORKSPACE) {
// Only follow the mouse if it would move to a new output
// Otherwise we'll focus the workspace, which is probably wrong
- struct sway_container *focus = seat_get_focus(cursor->seat);
if (focus->type != C_OUTPUT) {
focus = container_parent(focus, C_OUTPUT);
}
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 8734e8f8..15ed6f80 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -22,6 +22,7 @@
#include "sway/server.h"
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
+#include "sway/tree/view.h"
#include "list.h"
#include "log.h"
@@ -429,6 +430,16 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace,
json_object_new_boolean(visible));
}
+static void ipc_get_marks_callback(struct sway_container *con, void *data) {
+ json_object *marks = (json_object *)data;
+ if (con->type == C_VIEW && con->sway_view->marks) {
+ for (int i = 0; i < con->sway_view->marks->length; ++i) {
+ char *mark = (char *)con->sway_view->marks->items[i];
+ json_object_array_add(marks, json_object_new_string(mark));
+ }
+ }
+}
+
void ipc_client_handle_command(struct ipc_client *client) {
if (!sway_assert(client != NULL, "client != NULL")) {
return;
@@ -569,6 +580,17 @@ void ipc_client_handle_command(struct ipc_client *client) {
goto exit_cleanup;
}
+ case IPC_GET_MARKS:
+ {
+ json_object *marks = json_object_new_array();
+ container_descendants(&root_container, C_VIEW, ipc_get_marks_callback,
+ marks);
+ const char *json_string = json_object_to_json_string(marks);
+ ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
+ json_object_put(marks);
+ goto exit_cleanup;
+ }
+
case IPC_GET_VERSION:
{
json_object *version = ipc_json_get_version();
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index 8aebc0cc..bdef56ea 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -86,12 +86,14 @@ static void apply_horiz_layout(struct sway_container *parent) {
if (!num_children) {
return;
}
- size_t parent_height = parent->height;
size_t parent_offset = 0;
if (parent->parent->layout == L_TABBED) {
- parent_offset = config->border_thickness * 2 + config->font_height;
- parent_height -= parent_offset;
+ parent_offset = container_titlebar_height();
+ } else if (parent->parent->layout == L_STACKED) {
+ parent_offset =
+ container_titlebar_height() * parent->parent->children->length;
}
+ size_t parent_height = parent->height - parent_offset;
// Calculate total width of children
double total_width = 0;
@@ -132,12 +134,14 @@ static void apply_vert_layout(struct sway_container *parent) {
if (!num_children) {
return;
}
- size_t parent_height = parent->height;
size_t parent_offset = 0;
if (parent->parent->layout == L_TABBED) {
- parent_offset = config->border_thickness * 2 + config->font_height;
- parent_height -= parent_offset;
+ parent_offset = container_titlebar_height();
+ } else if (parent->parent->layout == L_STACKED) {
+ parent_offset =
+ container_titlebar_height() * parent->parent->children->length;
}
+ size_t parent_height = parent->height - parent_offset;
// Calculate total height of children
double total_height = 0;
@@ -173,16 +177,24 @@ static void apply_vert_layout(struct sway_container *parent) {
child->height = parent->y + parent_offset + parent_height - child->y;
}
-static void apply_tabbed_layout(struct sway_container *parent) {
+static void apply_tabbed_or_stacked_layout(struct sway_container *parent) {
if (!parent->children->length) {
return;
}
+ size_t parent_offset = 0;
+ if (parent->parent->layout == L_TABBED) {
+ parent_offset = container_titlebar_height();
+ } else if (parent->parent->layout == L_STACKED) {
+ parent_offset =
+ container_titlebar_height() * parent->parent->children->length;
+ }
+ size_t parent_height = parent->height - parent_offset;
for (int i = 0; i < parent->children->length; ++i) {
struct sway_container *child = parent->children->items[i];
child->x = parent->x;
- child->y = parent->y;
+ child->y = parent->y + parent_offset;
child->width = parent->width;
- child->height = parent->height;
+ child->height = parent_height;
}
}
@@ -217,7 +229,8 @@ void arrange_children_of(struct sway_container *parent) {
apply_vert_layout(parent);
break;
case L_TABBED:
- apply_tabbed_layout(parent);
+ case L_STACKED:
+ apply_tabbed_or_stacked_layout(parent);
break;
default:
wlr_log(L_DEBUG, "TODO: arrange layout type %d", parent->layout);
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 5d88325f..f29a9adc 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -21,6 +21,7 @@
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
#include "log.h"
+#include "stringop.h"
static list_t *bfs_queue;
@@ -510,7 +511,7 @@ static struct sway_container *container_at_tabbed(struct sway_container *parent,
struct sway_seat *seat = input_manager_current_seat(input_manager);
// Tab titles
- int title_height = config->border_thickness * 2 + config->font_height;
+ int title_height = container_titlebar_height();
if (oy < parent->y + title_height) {
int tab_width = parent->width / parent->children->length;
int child_index = (ox - parent->x) / tab_width;
@@ -533,8 +534,23 @@ static struct sway_container *container_at_tabbed(struct sway_container *parent,
static struct sway_container *container_at_stacked(
struct sway_container *parent, double ox, double oy,
struct wlr_surface **surface, double *sx, double *sy) {
- // TODO
- return NULL;
+ if (oy < parent->y || oy > parent->y + parent->height) {
+ return NULL;
+ }
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+
+ // Title bars
+ int title_height = container_titlebar_height();
+ int child_index = (oy - parent->y) / title_height;
+ if (child_index < parent->children->length) {
+ struct sway_container *child = parent->children->items[child_index];
+ return seat_get_focus_inactive(seat, child);
+ }
+
+ // Surfaces
+ struct sway_container *current = seat_get_active_child(seat, parent);
+
+ return container_at(current, ox, oy, surface, sx, sy);
}
/**
@@ -759,42 +775,36 @@ void container_calculate_title_height(struct sway_container *container) {
}
/**
- * Calculate and return the length of the concatenated child titles.
- * An example concatenated title is: V[Terminal, Firefox]
- * If buffer is not NULL, also populate the buffer with the concatenated title.
+ * Calculate and return the length of the tree representation.
+ * An example tree representation is: V[Terminal, Firefox]
+ * If buffer is not NULL, also populate the buffer with the representation.
*/
-static size_t concatenate_child_titles(struct sway_container *parent,
- char *buffer) {
- size_t len = 2; // V[
- if (buffer) {
- switch (parent->layout) {
- case L_VERT:
- strcpy(buffer, "V[");
- break;
- case L_HORIZ:
- strcpy(buffer, "H[");
- break;
- case L_TABBED:
- strcpy(buffer, "T[");
- break;
- case L_STACKED:
- strcpy(buffer, "S[");
- break;
- case L_FLOATING:
- strcpy(buffer, "F[");
- break;
- case L_NONE:
- strcpy(buffer, "D[");
- break;
- }
+static size_t get_tree_representation(struct sway_container *parent, char *buffer) {
+ size_t len = 2;
+ switch (parent->layout) {
+ case L_VERT:
+ lenient_strcat(buffer, "V[");
+ break;
+ case L_HORIZ:
+ lenient_strcat(buffer, "H[");
+ break;
+ case L_TABBED:
+ lenient_strcat(buffer, "T[");
+ break;
+ case L_STACKED:
+ lenient_strcat(buffer, "S[");
+ break;
+ case L_FLOATING:
+ lenient_strcat(buffer, "F[");
+ break;
+ case L_NONE:
+ lenient_strcat(buffer, "D[");
+ break;
}
-
for (int i = 0; i < parent->children->length; ++i) {
if (i != 0) {
- len += 1;
- if (buffer) {
- strcat(buffer, " ");
- }
+ ++len;
+ lenient_strcat(buffer, " ");
}
struct sway_container *child = parent->children->items[i];
const char *identifier = NULL;
@@ -804,46 +814,41 @@ static size_t concatenate_child_titles(struct sway_container *parent,
identifier = view_get_app_id(child->sway_view);
}
} else {
- identifier = child->name;
+ identifier = child->formatted_title;
}
if (identifier) {
len += strlen(identifier);
- if (buffer) {
- strcat(buffer, identifier);
- }
+ lenient_strcat(buffer, identifier);
} else {
len += 6;
- if (buffer) {
- strcat(buffer, "(null)");
- }
+ lenient_strcat(buffer, "(null)");
}
}
-
- len += 1;
- if (buffer) {
- strcat(buffer, "]");
- }
+ ++len;
+ lenient_strcat(buffer, "]");
return len;
}
-void container_notify_child_title_changed(struct sway_container *container) {
+void container_notify_subtree_changed(struct sway_container *container) {
if (!container || container->type != C_CONTAINER) {
return;
}
- if (container->formatted_title) {
- free(container->formatted_title);
- }
+ free(container->formatted_title);
+ container->formatted_title = NULL;
- size_t len = concatenate_child_titles(container, NULL);
+ size_t len = get_tree_representation(container, NULL);
char *buffer = calloc(len + 1, sizeof(char));
if (!sway_assert(buffer, "Unable to allocate title string")) {
return;
}
- concatenate_child_titles(container, buffer);
+ get_tree_representation(container, buffer);
- container->name = buffer;
container->formatted_title = buffer;
container_calculate_title_height(container);
container_update_title_textures(container);
- container_notify_child_title_changed(container->parent);
+ container_notify_subtree_changed(container->parent);
+}
+
+size_t container_titlebar_height() {
+ return config->font_height + TITLEBAR_V_PADDING * 2;
}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index f8acdf6c..21cec529 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -149,7 +149,7 @@ struct sway_container *container_remove_child(struct sway_container *child) {
}
}
child->parent = NULL;
- container_notify_child_title_changed(parent);
+ container_notify_subtree_changed(parent);
return parent;
}
@@ -184,12 +184,20 @@ void container_move_to(struct sway_container *container,
container_sort_workspaces(new_parent);
seat_set_focus(seat, new_parent);
}
- container_notify_child_title_changed(old_parent);
- container_notify_child_title_changed(new_parent);
+ container_notify_subtree_changed(old_parent);
+ container_notify_subtree_changed(new_parent);
if (old_parent) {
- arrange_children_of(old_parent);
+ if (old_parent->type == C_OUTPUT) {
+ arrange_output(old_parent);
+ } else {
+ arrange_children_of(old_parent);
+ }
+ }
+ if (new_parent->type == C_OUTPUT) {
+ arrange_output(new_parent);
+ } else {
+ arrange_children_of(new_parent);
}
- arrange_children_of(new_parent);
// If view was moved to a fullscreen workspace, refocus the fullscreen view
struct sway_container *new_workspace = container;
if (new_workspace->type != C_WORKSPACE) {
@@ -319,9 +327,11 @@ void container_move(struct sway_container *container,
current = container_parent(container, C_OUTPUT);
}
- if (parent != container_flatten(parent)) {
+ struct sway_container *new_parent = container_flatten(parent);
+ if (new_parent != parent) {
// Special case: we were the last one in this container, so flatten it
// and leave
+ arrange_children_of(new_parent);
update_debug_tree();
return;
}
@@ -489,8 +499,8 @@ void container_move(struct sway_container *container,
}
}
- container_notify_child_title_changed(old_parent);
- container_notify_child_title_changed(container->parent);
+ container_notify_subtree_changed(old_parent);
+ container_notify_subtree_changed(container->parent);
if (old_parent) {
seat_set_focus(config->handler_context.seat, old_parent);
@@ -578,11 +588,19 @@ static struct sway_container *get_swayc_in_output_direction(
if (ws->children->length > 0) {
switch (dir) {
case MOVE_LEFT:
- // get most right child of new output
- return ws->children->items[ws->children->length-1];
+ if (ws->layout == L_HORIZ || ws->layout == L_TABBED) {
+ // get most right child of new output
+ return ws->children->items[ws->children->length-1];
+ } else {
+ return seat_get_focus_inactive(seat, ws);
+ }
case MOVE_RIGHT:
- // get most left child of new output
- return ws->children->items[0];
+ if (ws->layout == L_HORIZ || ws->layout == L_TABBED) {
+ // get most left child of new output
+ return ws->children->items[0];
+ } else {
+ return seat_get_focus_inactive(seat, ws);
+ }
case MOVE_UP:
case MOVE_DOWN: {
struct sway_container *focused =
@@ -839,7 +857,7 @@ struct sway_container *container_split(struct sway_container *child,
container_add_child(cont, child);
}
- container_notify_child_title_changed(cont);
+ container_notify_subtree_changed(cont);
return cont;
}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 64597c02..812d7740 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -17,6 +17,7 @@
#include "sway/tree/workspace.h"
#include "sway/config.h"
#include "pango.h"
+#include "stringop.h"
void view_init(struct sway_view *view, enum sway_view_type type,
const struct sway_view_impl *impl) {
@@ -141,9 +142,18 @@ void view_autoconfigure(struct sway_view *view) {
struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
- int other_views = 1;
+ int other_views = 0;
if (config->hide_edge_borders == E_SMART) {
- other_views = container_count_descendants_of_type(ws, C_VIEW) - 1;
+ struct sway_container *con = view->swayc;
+ while (con != output) {
+ if (con->layout != L_TABBED && con->layout != L_STACKED) {
+ other_views += con->children ? con->children->length - 1 : 0;
+ if (other_views > 0) {
+ break;
+ }
+ }
+ con = con->parent;
+ }
}
view->border_top = view->border_bottom = true;
@@ -173,11 +183,11 @@ void view_autoconfigure(struct sway_view *view) {
// area. We have to offset the surface y by the height of the title bar, and
// disable any top border because we'll always have the title bar.
if (view->swayc->parent->layout == L_TABBED) {
- y_offset = config->border_thickness * 2 + config->font_height;
+ y_offset = container_titlebar_height();
view->border_top = 0;
} else if (view->swayc->parent->layout == L_STACKED) {
- y_offset = config->border_thickness * 2 + config->font_height;
- y_offset *= view->swayc->parent->children->length;
+ y_offset = container_titlebar_height()
+ * view->swayc->parent->children->length;
view->border_top = 0;
}
@@ -199,7 +209,7 @@ void view_autoconfigure(struct sway_view *view) {
- view->border_thickness * view->border_bottom;
break;
case B_NORMAL:
- // Height is: border + title height + border + view height + border
+ // Height is: 1px border + 3px pad + title height + 3px pad + 1px border
x = view->swayc->x + view->border_thickness * view->border_left;
width = view->swayc->width
- view->border_thickness * view->border_left
@@ -209,10 +219,9 @@ void view_autoconfigure(struct sway_view *view) {
height = view->swayc->height - y_offset
- view->border_thickness * view->border_bottom;
} else {
- y = view->swayc->y + config->font_height + view->border_thickness * 2
- + y_offset;
- height = view->swayc->height - config->font_height
- - view->border_thickness * (2 + view->border_bottom);
+ y = view->swayc->y + container_titlebar_height();
+ height = view->swayc->height - container_titlebar_height()
+ - view->border_thickness * view->border_bottom;
}
break;
}
@@ -430,10 +439,11 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
// Check if there's any `assign` criteria for the view
list_t *criterias = criteria_for_view(view,
CT_ASSIGN_WORKSPACE | CT_ASSIGN_OUTPUT);
+ struct sway_container *workspace = NULL;
if (criterias->length) {
struct criteria *criteria = criterias->items[0];
if (criteria->type == CT_ASSIGN_WORKSPACE) {
- struct sway_container *workspace = workspace_by_name(criteria->target);
+ workspace = workspace_by_name(criteria->target);
if (!workspace) {
workspace = workspace_create(NULL, criteria->target);
}
@@ -460,9 +470,12 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
arrange_children_of(cont->parent);
input_manager_set_focus(input_manager, cont);
+ if (workspace) {
+ workspace_switch(workspace);
+ }
view_update_title(view, false);
- container_notify_child_title_changed(view->swayc->parent);
+ container_notify_subtree_changed(view->swayc->parent);
view_execute_criteria(view);
container_damage_whole(cont);
@@ -653,49 +666,35 @@ static size_t parse_title_format(struct sway_view *view, char *buffer) {
char *format = view->title_format;
char *next = strchr(format, '%');
while (next) {
- if (buffer) {
- // Copy everything up to the %
- strncat(buffer, format, next - format);
- }
+ // Copy everything up to the %
+ lenient_strncat(buffer, format, next - format);
len += next - format;
format = next;
if (strncmp(next, "%title", 6) == 0) {
- if (buffer && title) {
- strcat(buffer, title);
- }
+ lenient_strcat(buffer, title);
len += title_len;
format += 6;
} else if (strncmp(next, "%class", 6) == 0) {
- if (buffer && class) {
- strcat(buffer, class);
- }
+ lenient_strcat(buffer, class);
len += class_len;
format += 6;
} else if (strncmp(next, "%instance", 9) == 0) {
- if (buffer && instance) {
- strcat(buffer, instance);
- }
+ lenient_strcat(buffer, instance);
len += instance_len;
format += 9;
} else if (strncmp(next, "%shell", 6) == 0) {
- if (buffer) {
- strcat(buffer, shell);
- }
+ lenient_strcat(buffer, shell);
len += shell_len;
format += 6;
} else {
- if (buffer) {
- strcat(buffer, "%");
- }
+ lenient_strcat(buffer, "%");
++format;
++len;
}
next = strchr(format, '%');
}
- if (buffer) {
- strcat(buffer, format);
- }
+ lenient_strcat(buffer, format);
len += strlen(format);
return len;
@@ -751,7 +750,6 @@ void view_update_title(struct sway_view *view, bool force) {
}
container_calculate_title_height(view->swayc);
container_update_title_textures(view->swayc);
- container_notify_child_title_changed(view->swayc->parent);
config_update_font_height(false);
}
diff --git a/swaylock/main.c b/swaylock/main.c
index 11b5e8c8..f89f2849 100644
--- a/swaylock/main.c
+++ b/swaylock/main.c
@@ -64,6 +64,52 @@ static void daemonize() {
}
}
+static void destroy_surface(struct swaylock_surface *surface) {
+ wl_list_remove(&surface->link);
+ if (surface->layer_surface != NULL) {
+ zwlr_layer_surface_v1_destroy(surface->layer_surface);
+ }
+ if (surface->surface != NULL) {
+ wl_surface_destroy(surface->surface);
+ }
+ destroy_buffer(&surface->buffers[0]);
+ destroy_buffer(&surface->buffers[1]);
+ wl_output_destroy(surface->output);
+ free(surface);
+}
+
+static const struct zwlr_layer_surface_v1_listener layer_surface_listener;
+
+static cairo_surface_t *select_image(struct swaylock_state *state,
+ struct swaylock_surface *surface);
+
+static void create_layer_surface(struct swaylock_surface *surface) {
+ struct swaylock_state *state = surface->state;
+
+ surface->image = select_image(state, surface);
+
+ surface->surface = wl_compositor_create_surface(state->compositor);
+ assert(surface->surface);
+
+ surface->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
+ state->layer_shell, surface->surface, surface->output,
+ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "lockscreen");
+ assert(surface->layer_surface);
+
+ zwlr_layer_surface_v1_set_size(surface->layer_surface, 0, 0);
+ zwlr_layer_surface_v1_set_anchor(surface->layer_surface,
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
+ zwlr_layer_surface_v1_set_exclusive_zone(surface->layer_surface, -1);
+ zwlr_layer_surface_v1_set_keyboard_interactivity(
+ surface->layer_surface, true);
+ zwlr_layer_surface_v1_add_listener(surface->layer_surface,
+ &layer_surface_listener, surface);
+ wl_surface_commit(surface->surface);
+}
+
static void layer_surface_configure(void *data,
struct zwlr_layer_surface_v1 *layer_surface,
uint32_t serial, uint32_t width, uint32_t height) {
@@ -77,9 +123,7 @@ static void layer_surface_configure(void *data,
static void layer_surface_closed(void *data,
struct zwlr_layer_surface_v1 *layer_surface) {
struct swaylock_surface *surface = data;
- zwlr_layer_surface_v1_destroy(surface->layer_surface);
- wl_surface_destroy(surface->surface);
- surface->state->run_display = false;
+ destroy_surface(surface);
}
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
@@ -181,14 +225,27 @@ static void handle_global(void *data, struct wl_registry *registry,
surface->state = state;
surface->output = wl_registry_bind(registry, name,
&wl_output_interface, 3);
+ surface->output_global_name = name;
wl_output_add_listener(surface->output, &_wl_output_listener, surface);
wl_list_insert(&state->surfaces, &surface->link);
+
+ if (state->run_display) {
+ create_layer_surface(surface);
+ wl_display_roundtrip(state->display);
+ }
}
}
static void handle_global_remove(void *data, struct wl_registry *registry,
uint32_t name) {
- // who cares
+ struct swaylock_state *state = data;
+ struct swaylock_surface *surface;
+ wl_list_for_each(surface, &state->surfaces, link) {
+ if (surface->output_global_name == name) {
+ destroy_surface(surface);
+ break;
+ }
+ }
}
static const struct wl_registry_listener registry_listener = {
@@ -276,7 +333,7 @@ int main(int argc, char **argv) {
{0, 0, 0, 0}
};
- const char *usage =
+ const char usage[] =
"Usage: swaylock [options...]\n"
"\n"
" -h, --help Show help message and quit.\n"
@@ -288,13 +345,13 @@ int main(int argc, char **argv) {
" -u, --no-unlock-indicator Disable the unlock indicator.\n"
" -f, --daemonize Detach from the controlling terminal.\n";
- struct swaylock_args args = {
+ state.args = (struct swaylock_args){
.mode = BACKGROUND_MODE_SOLID_COLOR,
.color = 0xFFFFFFFF,
.show_indicator = true,
};
- state.args = args;
wl_list_init(&state.images);
+
wlr_log_init(L_DEBUG, NULL);
int c;
@@ -369,6 +426,8 @@ int main(int argc, char **argv) {
return 0;
}
+ zwlr_input_inhibit_manager_v1_get_inhibitor(state.input_inhibit_manager);
+
if (state.zxdg_output_manager) {
struct swaylock_surface *surface;
wl_list_for_each(surface, &state.surfaces, link) {
@@ -385,33 +444,9 @@ int main(int argc, char **argv) {
struct swaylock_surface *surface;
wl_list_for_each(surface, &state.surfaces, link) {
- surface->image = select_image(&state, surface);
-
- surface->surface = wl_compositor_create_surface(state.compositor);
- assert(surface->surface);
-
- surface->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
- state.layer_shell, surface->surface, surface->output,
- ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "lockscreen");
- assert(surface->layer_surface);
-
- zwlr_layer_surface_v1_set_size(surface->layer_surface, 0, 0);
- zwlr_layer_surface_v1_set_anchor(surface->layer_surface,
- ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
- ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
- zwlr_layer_surface_v1_set_exclusive_zone(surface->layer_surface, -1);
- zwlr_layer_surface_v1_set_keyboard_interactivity(
- surface->layer_surface, true);
- zwlr_layer_surface_v1_add_listener(surface->layer_surface,
- &layer_surface_listener, surface);
- wl_surface_commit(surface->surface);
- wl_display_roundtrip(state.display);
+ create_layer_surface(surface);
}
- zwlr_input_inhibit_manager_v1_get_inhibitor(state.input_inhibit_manager);
-
state.run_display = true;
while (wl_display_dispatch(state.display) != -1 && state.run_display) {
// This space intentionally left blank
diff --git a/swaylock/render.c b/swaylock/render.c
index cc40f4e9..05236dea 100644
--- a/swaylock/render.c
+++ b/swaylock/render.c
@@ -17,6 +17,9 @@ void render_frame(struct swaylock_surface *surface) {
int buffer_width = surface->width * surface->scale;
int buffer_height = surface->height * surface->scale;
+ if (buffer_width == 0 || buffer_height == 0) {
+ return; // not yet configured
+ }
surface->current_buffer = get_next_buffer(state->shm,
surface->buffers, buffer_width, buffer_height);