aboutsummaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
authoremersion <contact@emersion.fr>2018-05-23 22:54:52 +0100
committeremersion <contact@emersion.fr>2018-05-23 22:54:52 +0100
commitcd0fca2ebf81c252b3743c4474a5fdbcd3e2afad (patch)
tree595f1e80551b64de0d4e24f5721bae27acc195d9 /sway
parentb7ab7c0e66433aacaaccce08d6e40304e6f6593c (diff)
parent12a12878b9883c345dd73752a9cf714aeb245b8a (diff)
Merge branch 'master' into fix-swaylock-hotplugging
Diffstat (limited to 'sway')
-rw-r--r--sway/commands/border.c2
-rw-r--r--sway/commands/layout.c4
-rw-r--r--sway/commands/seat/cursor.c4
-rw-r--r--sway/desktop/output.c518
-rw-r--r--sway/input/cursor.c31
-rw-r--r--sway/input/seat.c16
-rw-r--r--sway/ipc-server.c22
-rw-r--r--sway/tree/arrange.c64
-rw-r--r--sway/tree/container.c336
-rw-r--r--sway/tree/layout.c11
-rw-r--r--sway/tree/view.c86
11 files changed, 793 insertions, 301 deletions
diff --git a/sway/commands/border.c b/sway/commands/border.c
index 1eb06a21..4ba361da 100644
--- a/sway/commands/border.c
+++ b/sway/commands/border.c
@@ -41,7 +41,7 @@ struct cmd_results *cmd_border(int argc, char **argv) {
struct sway_seat *seat = input_manager_current_seat(input_manager);
if (seat->cursor) {
- cursor_send_pointer_motion(seat->cursor, 0);
+ cursor_send_pointer_motion(seat->cursor, 0, false);
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/layout.c b/sway/commands/layout.c
index bb36bb18..58728f16 100644
--- a/sway/commands/layout.c
+++ b/sway/commands/layout.c
@@ -39,6 +39,10 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
parent->layout = L_HORIZ;
} else if (strcasecmp(argv[0], "splitv") == 0) {
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;
diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c
index 929384b0..4d0a22c7 100644
--- a/sway/commands/seat/cursor.c
+++ b/sway/commands/seat/cursor.c
@@ -36,7 +36,7 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) {
int delta_x = strtol(argv[1], NULL, 10);
int delta_y = strtol(argv[2], NULL, 10);
wlr_cursor_move(cursor->cursor, NULL, delta_x, delta_y);
- cursor_send_pointer_motion(cursor, 0);
+ cursor_send_pointer_motion(cursor, 0, true);
} else if (strcasecmp(argv[0], "set") == 0) {
if (argc < 3) {
return cmd_results_new(CMD_INVALID, "cursor", expected_syntax);
@@ -45,7 +45,7 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) {
float x = strtof(argv[1], NULL) / root_container.width;
float y = strtof(argv[2], NULL) / root_container.height;
wlr_cursor_warp_absolute(cursor->cursor, NULL, x, y);
- cursor_send_pointer_motion(cursor, 0);
+ cursor_send_pointer_motion(cursor, 0, true);
} else {
if (argc < 2) {
return cmd_results_new(CMD_INVALID, "cursor", expected_syntax);
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 94562052..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]) {
@@ -310,93 +299,149 @@ damage_finish:
pixman_region32_fini(&damage);
}
+static void premultiply_alpha(float color[4], float opacity) {
+ color[3] *= opacity;
+ color[0] *= color[3];
+ color[1] *= color[3];
+ 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);
- color[3] *= 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);
}
- color[3] *= 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);
}
- color[3] *= 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);
- color[3] *= con->alpha;
- box.x = con->x;
- box.y = con->y;
- box.width = con->width;
- box.height = 1;
+ premultiply_alpha(color, con->alpha);
+ 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);
// Single pixel bar below title
- memcpy(&color, colors->border, sizeof(float) * 4);
- color[3] *= con->alpha;
- box.x = con->x + view->border_thickness;
- box.y = view->y - 1;
- box.width = con->width - view->border_thickness * 2;
- 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);
- // 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;
+ 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;
@@ -404,14 +449,18 @@ static void render_container_simple_border_normal(struct sway_output *output,
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;
@@ -423,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,
@@ -439,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);
- color[3] *= con->alpha;
- box.x = inner_x;
- box.y = con->y + 1;
- box.width = inner_width;
- box.height = view->border_thickness - 1;
+ premultiply_alpha(color, con->alpha);
+ 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);
- color[3] *= 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);
- }
- color[3] *= 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);
- color[3] *= 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);
- }
- color[3] *= 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,
@@ -558,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);
@@ -596,16 +627,116 @@ static void render_container_simple(struct sway_output *output,
* 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) {
- // TODO
+ 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;
+
+ // 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;
+
+ 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;
+ }
+
+ 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;
+ }
+
+ render_titlebar(output, damage, child, x, child->y, tab_width, colors,
+ title_texture, marks_texture);
+
+ 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_STACKED layout.
*/
static void render_container_stacked(struct sway_output *output,
- pixman_region32_t *damage, struct sway_container *con) {
- // TODO
+ 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;
+
+ // 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;
+ }
+
+ 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;
+ }
+ }
+
+ // 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);
+ }
}
static void render_container(struct sway_output *output,
@@ -618,10 +749,10 @@ 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);
+ render_container_tabbed(output, damage, con, parent_focused);
break;
case L_FLOATING:
// TODO
@@ -678,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,
@@ -889,9 +1021,7 @@ static void output_damage_view(struct sway_output *output,
return;
}
- struct sway_container *workspace = container_parent(view->swayc,
- C_WORKSPACE);
- if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) {
+ if (!view_is_visible(view)) {
return;
}
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 9259c475..9a0b4f01 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -108,7 +108,7 @@ static struct sway_container *container_at_coords(
}
struct sway_container *c;
- if ((c = container_at(ws, x, y, surface, sx, sy))) {
+ if ((c = container_at(ws, ox, oy, surface, sx, sy))) {
return c;
}
@@ -135,7 +135,8 @@ static struct sway_container *container_at_coords(
return output->swayc;
}
-void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec) {
+void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
+ bool allow_refocusing) {
if (time_msec == 0) {
time_msec = get_current_time_msec();
}
@@ -145,8 +146,24 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec)
double sx, sy;
struct sway_container *c = container_at_coords(cursor->seat,
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
- if (c && config->focus_follows_mouse) {
- seat_set_focus_warp(cursor->seat, c, false);
+ if (c && config->focus_follows_mouse && allow_refocusing) {
+ 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
+ if (focus->type != C_OUTPUT) {
+ focus = container_parent(focus, C_OUTPUT);
+ }
+ struct sway_container *output = c;
+ if (output->type != C_OUTPUT) {
+ output = container_parent(c, C_OUTPUT);
+ }
+ if (output != focus) {
+ seat_set_focus_warp(cursor->seat, c, false);
+ }
+ } else {
+ seat_set_focus_warp(cursor->seat, c, false);
+ }
}
// reset cursor if switching between clients
@@ -177,7 +194,7 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) {
struct wlr_event_pointer_motion *event = data;
wlr_cursor_move(cursor->cursor, event->device,
event->delta_x, event->delta_y);
- cursor_send_pointer_motion(cursor, event->time_msec);
+ cursor_send_pointer_motion(cursor, event->time_msec, true);
}
static void handle_cursor_motion_absolute(
@@ -187,7 +204,7 @@ static void handle_cursor_motion_absolute(
wlr_idle_notify_activity(cursor->seat->input->server->idle, cursor->seat->wlr_seat);
struct wlr_event_pointer_motion_absolute *event = data;
wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y);
- cursor_send_pointer_motion(cursor, event->time_msec);
+ cursor_send_pointer_motion(cursor, event->time_msec, true);
}
void dispatch_cursor_button(struct sway_cursor *cursor,
@@ -357,7 +374,7 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) {
}
wlr_cursor_warp_absolute(cursor->cursor, event->device, x, y);
- cursor_send_pointer_motion(cursor, event->time_msec);
+ cursor_send_pointer_motion(cursor, event->time_msec, true);
}
static void handle_tool_tip(struct wl_listener *listener, void *data) {
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 9ac3e6a8..7a3e928a 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -602,7 +602,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
wlr_output, seat->cursor->cursor->x,
seat->cursor->cursor->y)) {
wlr_cursor_warp(seat->cursor->cursor, NULL, x, y);
- cursor_send_pointer_motion(seat->cursor, 0);
+ cursor_send_pointer_motion(seat->cursor, 0, true);
}
}
}
@@ -613,7 +613,7 @@ void seat_set_focus_warp(struct sway_seat *seat,
}
if (last_workspace && last_workspace != new_workspace) {
- cursor_send_pointer_motion(seat->cursor, 0);
+ cursor_send_pointer_motion(seat->cursor, 0, true);
}
seat->has_focus = (container != NULL);
@@ -718,6 +718,18 @@ struct sway_container *seat_get_focus_inactive(struct sway_seat *seat,
return seat_get_focus_by_type(seat, container, C_TYPES);
}
+struct sway_container *seat_get_active_child(struct sway_seat *seat,
+ struct sway_container *container) {
+ struct sway_container *focus = seat_get_focus_inactive(seat, container);
+ if (!focus) {
+ return NULL;
+ }
+ while (focus->parent != container) {
+ focus = focus->parent;
+ }
+ return focus;
+}
+
struct sway_container *sway_seat_get_focus(struct sway_seat *seat) {
if (!seat->has_focus) {
return NULL;
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 83bb20fb..37f4a066 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -86,6 +86,15 @@ static void apply_horiz_layout(struct sway_container *parent) {
if (!num_children) {
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;
+
// Calculate total width of children
double total_width = 0;
for (size_t i = 0; i < num_children; ++i) {
@@ -111,9 +120,9 @@ static void apply_horiz_layout(struct sway_container *parent) {
"Calculating arrangement for %p:%d (will scale %f by %f)",
child, child->type, child->width, scale);
child->x = child_x;
- child->y = parent->y;
+ child->y = parent->y + parent_offset;
child->width = floor(child->width * scale);
- child->height = parent->height;
+ child->height = parent_height;
child_x += child->width;
}
// Make last child use remaining width of parent
@@ -125,24 +134,33 @@ static void apply_vert_layout(struct sway_container *parent) {
if (!num_children) {
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;
+
// Calculate total height of children
double total_height = 0;
for (size_t i = 0; i < num_children; ++i) {
struct sway_container *child = parent->children->items[i];
if (child->height <= 0) {
if (num_children > 1) {
- child->height = parent->height / (num_children - 1);
+ child->height = parent_height / (num_children - 1);
} else {
- child->height = parent->height;
+ child->height = parent_height;
}
}
total_height += child->height;
}
- double scale = parent->height / total_height;
+ double scale = parent_height / total_height;
// Resize
wlr_log(L_DEBUG, "Arranging %p vertically", parent);
- double child_y = parent->y;
+ double child_y = parent->y + parent_offset;
struct sway_container *child;
for (size_t i = 0; i < num_children; ++i) {
child = parent->children->items[i];
@@ -156,7 +174,33 @@ static void apply_vert_layout(struct sway_container *parent) {
child_y += child->height;
}
// Make last child use remaining height of parent
- child->height = parent->y + parent->height - child->y;
+ child->height = parent->y + parent_offset + parent_height - child->y;
+}
+
+static void apply_tabbed_layout(struct sway_container *parent) {
+ if (!parent->children->length) {
+ return;
+ }
+ 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->width = parent->width;
+ child->height = parent->height;
+ }
+}
+
+static void apply_stacked_layout(struct sway_container *parent) {
+ if (!parent->children->length) {
+ return;
+ }
+ 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->width = parent->width;
+ child->height = parent->height;
+ }
}
void arrange_children_of(struct sway_container *parent) {
@@ -189,6 +233,12 @@ void arrange_children_of(struct sway_container *parent) {
case L_VERT:
apply_vert_layout(parent);
break;
+ case L_TABBED:
+ apply_tabbed_layout(parent);
+ break;
+ case L_STACKED:
+ apply_stacked_layout(parent);
+ break;
default:
wlr_log(L_DEBUG, "TODO: arrange layout type %d", parent->layout);
apply_horiz_layout(parent);
diff --git a/sway/tree/container.c b/sway/tree/container.c
index e47338e7..9cf18f61 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -73,6 +73,44 @@ static void container_close_notify(struct sway_container *container) {
}
}
+static void container_update_textures_recursive(struct sway_container *con) {
+ container_update_title_textures(con);
+
+ if (con->type == C_VIEW) {
+ view_update_marks_textures(con->sway_view);
+ } else {
+ for (int i = 0; i < con->children->length; ++i) {
+ struct sway_container *child = con->children->items[i];
+ container_update_textures_recursive(child);
+ }
+ }
+}
+
+static void handle_reparent(struct wl_listener *listener,
+ void *data) {
+ struct sway_container *container =
+ wl_container_of(listener, container, reparent);
+ struct sway_container *old_parent = data;
+
+ struct sway_container *old_output = old_parent;
+ if (old_output != NULL && old_output->type != C_OUTPUT) {
+ old_output = container_parent(old_output, C_OUTPUT);
+ }
+
+ struct sway_container *new_output = container->parent;
+ if (new_output != NULL && new_output->type != C_OUTPUT) {
+ new_output = container_parent(new_output, C_OUTPUT);
+ }
+
+ if (old_output && new_output) {
+ float old_scale = old_output->sway_output->wlr_output->scale;
+ float new_scale = new_output->sway_output->wlr_output->scale;
+ if (old_scale != new_scale) {
+ container_update_textures_recursive(container);
+ }
+ }
+}
+
struct sway_container *container_create(enum sway_container_type type) {
// next id starts at 1 because 0 is assigned to root_container in layout.c
static size_t next_id = 1;
@@ -92,6 +130,9 @@ struct sway_container *container_create(enum sway_container_type type) {
wl_signal_init(&c->events.destroy);
wl_signal_init(&c->events.reparent);
+ wl_signal_add(&c->events.reparent, &c->reparent);
+ c->reparent.notify = handle_reparent;
+
return c;
}
@@ -411,80 +452,154 @@ struct sway_container *container_parent(struct sway_container *container,
return container;
}
-struct sway_container *container_at(struct sway_container *parent,
- double lx, double ly,
+static struct sway_container *container_at_view(struct sway_container *swayc,
+ double ox, double oy,
struct wlr_surface **surface, double *sx, double *sy) {
- list_t *queue = get_bfs_queue();
- if (!queue) {
+ if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) {
return NULL;
}
+ struct sway_view *sview = swayc->sway_view;
+ double view_sx = ox - sview->x;
+ double view_sy = oy - sview->y;
- list_add(queue, parent);
+ double _sx, _sy;
+ struct wlr_surface *_surface = NULL;
+ switch (sview->type) {
+ case SWAY_VIEW_XWAYLAND:
+ _surface = wlr_surface_surface_at(sview->surface,
+ view_sx, view_sy, &_sx, &_sy);
+ break;
+ case SWAY_VIEW_XDG_SHELL_V6:
+ // the top left corner of the sway container is the
+ // coordinate of the top left corner of the window geometry
+ view_sx += sview->wlr_xdg_surface_v6->geometry.x;
+ view_sy += sview->wlr_xdg_surface_v6->geometry.y;
+
+ _surface = wlr_xdg_surface_v6_surface_at(
+ sview->wlr_xdg_surface_v6,
+ view_sx, view_sy, &_sx, &_sy);
+ break;
+ case SWAY_VIEW_XDG_SHELL:
+ // the top left corner of the sway container is the
+ // coordinate of the top left corner of the window geometry
+ view_sx += sview->wlr_xdg_surface->geometry.x;
+ view_sy += sview->wlr_xdg_surface->geometry.y;
+
+ _surface = wlr_xdg_surface_surface_at(
+ sview->wlr_xdg_surface,
+ view_sx, view_sy, &_sx, &_sy);
+ break;
+ }
+ if (_surface) {
+ *sx = _sx;
+ *sy = _sy;
+ *surface = _surface;
+ }
+ return swayc;
+}
- struct sway_container *swayc = NULL;
- while (queue->length) {
- swayc = queue->items[0];
- list_del(queue, 0);
- if (swayc->type == C_VIEW) {
- struct sway_view *sview = swayc->sway_view;
- struct sway_container *soutput = container_parent(swayc, C_OUTPUT);
- struct wlr_box *output_box =
- wlr_output_layout_get_box(
- root_container.sway_root->output_layout,
- soutput->sway_output->wlr_output);
- double ox = lx - output_box->x;
- double oy = ly - output_box->y;
- double view_sx = ox - sview->x;
- double view_sy = oy - sview->y;
-
- double _sx, _sy;
- struct wlr_surface *_surface;
- switch (sview->type) {
- case SWAY_VIEW_XWAYLAND:
- _surface = wlr_surface_surface_at(sview->surface,
- view_sx, view_sy, &_sx, &_sy);
- break;
- case SWAY_VIEW_XDG_SHELL_V6:
- // the top left corner of the sway container is the
- // coordinate of the top left corner of the window geometry
- view_sx += sview->wlr_xdg_surface_v6->geometry.x;
- view_sy += sview->wlr_xdg_surface_v6->geometry.y;
-
- _surface = wlr_xdg_surface_v6_surface_at(
- sview->wlr_xdg_surface_v6,
- view_sx, view_sy, &_sx, &_sy);
- break;
- case SWAY_VIEW_XDG_SHELL:
- // the top left corner of the sway container is the
- // coordinate of the top left corner of the window geometry
- view_sx += sview->wlr_xdg_surface->geometry.x;
- view_sy += sview->wlr_xdg_surface->geometry.y;
-
- _surface = wlr_xdg_surface_surface_at(
- sview->wlr_xdg_surface,
- view_sx, view_sy, &_sx, &_sy);
- break;
- }
- if (_surface) {
- *sx = _sx;
- *sy = _sy;
- *surface = _surface;
- return swayc;
- }
- // Check the view's decorations
- struct wlr_box swayc_box = {
- .x = swayc->x,
- .y = swayc->y,
- .width = swayc->width,
- .height = swayc->height,
- };
- if (wlr_box_contains_point(&swayc_box, ox, oy)) {
- return swayc;
- }
- } else {
- list_cat(queue, swayc->children);
+/**
+ * container_at for a container with layout L_TABBED.
+ */
+static struct sway_container *container_at_tabbed(struct sway_container *parent,
+ double ox, double oy,
+ struct wlr_surface **surface, double *sx, double *sy) {
+ if (oy < parent->y || oy > parent->y + parent->height) {
+ return NULL;
+ }
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+
+ // Tab titles
+ 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;
+ if (child_index >= parent->children->length) {
+ child_index = parent->children->length - 1;
+ }
+ 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);
+}
+
+/**
+ * container_at for a container with layout L_STACKED.
+ */
+static struct sway_container *container_at_stacked(
+ struct sway_container *parent, double ox, double oy,
+ struct wlr_surface **surface, double *sx, double *sy) {
+ 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);
+}
+
+/**
+ * container_at for a container with layout L_HORIZ or L_VERT.
+ */
+static struct sway_container *container_at_linear(struct sway_container *parent,
+ double ox, double oy,
+ struct wlr_surface **surface, double *sx, double *sy) {
+ for (int i = 0; i < parent->children->length; ++i) {
+ struct sway_container *child = parent->children->items[i];
+ struct wlr_box box = {
+ .x = child->x,
+ .y = child->y,
+ .width = child->width,
+ .height = child->height,
+ };
+ if (wlr_box_contains_point(&box, ox, oy)) {
+ return container_at(child, ox, oy, surface, sx, sy);
}
}
+ return NULL;
+}
+
+struct sway_container *container_at(struct sway_container *parent,
+ double ox, double oy,
+ struct wlr_surface **surface, double *sx, double *sy) {
+ if (!sway_assert(parent->type >= C_WORKSPACE,
+ "Expected workspace or deeper")) {
+ return NULL;
+ }
+ if (parent->type == C_VIEW) {
+ return container_at_view(parent, ox, oy, surface, sx, sy);
+ }
+ if (!parent->children->length) {
+ return NULL;
+ }
+
+ switch (parent->layout) {
+ case L_HORIZ:
+ case L_VERT:
+ return container_at_linear(parent, ox, oy, surface, sx, sy);
+ case L_TABBED:
+ return container_at_tabbed(parent, ox, oy, surface, sx, sy);
+ case L_STACKED:
+ return container_at_stacked(parent, ox, oy, surface, sx, sy);
+ case L_FLOATING:
+ return NULL; // TODO
+ case L_NONE:
+ return NULL;
+ }
return NULL;
}
@@ -658,19 +773,96 @@ void container_calculate_title_height(struct sway_container *container) {
container->title_height = height;
}
+/**
+ * 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.
+ */
+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;
+ }
+ }
+
+ for (int i = 0; i < parent->children->length; ++i) {
+ if (i != 0) {
+ len += 1;
+ if (buffer) {
+ strcat(buffer, " ");
+ }
+ }
+ struct sway_container *child = parent->children->items[i];
+ const char *identifier = NULL;
+ if (child->type == C_VIEW) {
+ identifier = view_get_class(child->sway_view);
+ if (!identifier) {
+ identifier = view_get_app_id(child->sway_view);
+ }
+ } else {
+ identifier = child->name;
+ }
+ if (identifier) {
+ len += strlen(identifier);
+ if (buffer) {
+ strcat(buffer, identifier);
+ }
+ } else {
+ len += 6;
+ if (buffer) {
+ strcat(buffer, "(null)");
+ }
+ }
+ }
+
+ len += 1;
+ if (buffer) {
+ strcat(buffer, "]");
+ }
+ return len;
+}
+
void container_notify_child_title_changed(struct sway_container *container) {
if (!container || container->type != C_CONTAINER) {
return;
}
- if (container->layout != L_TABBED && container->layout != L_STACKED) {
- return;
- }
if (container->formatted_title) {
free(container->formatted_title);
}
- // TODO: iterate children and concatenate their titles
- container->formatted_title = strdup("");
+
+ size_t len = concatenate_child_titles(container, NULL);
+ char *buffer = calloc(len + 1, sizeof(char));
+ if (!sway_assert(buffer, "Unable to allocate title string")) {
+ return;
+ }
+ concatenate_child_titles(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);
}
+
+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 ec1c6fe5..f8acdf6c 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -149,6 +149,8 @@ struct sway_container *container_remove_child(struct sway_container *child) {
}
}
child->parent = NULL;
+ container_notify_child_title_changed(parent);
+
return parent;
}
@@ -182,6 +184,8 @@ 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);
if (old_parent) {
arrange_children_of(old_parent);
}
@@ -234,9 +238,9 @@ static bool is_parallel(enum sway_container_layout layout,
enum movement_direction dir) {
switch (layout) {
case L_TABBED:
- case L_STACKED:
case L_HORIZ:
return dir == MOVE_LEFT || dir == MOVE_RIGHT;
+ case L_STACKED:
case L_VERT:
return dir == MOVE_UP || dir == MOVE_DOWN;
default:
@@ -485,6 +489,9 @@ void container_move(struct sway_container *container,
}
}
+ container_notify_child_title_changed(old_parent);
+ container_notify_child_title_changed(container->parent);
+
if (old_parent) {
seat_set_focus(config->handler_context.seat, old_parent);
seat_set_focus(config->handler_context.seat, container);
@@ -832,6 +839,8 @@ struct sway_container *container_split(struct sway_container *child,
container_add_child(cont, child);
}
+ container_notify_child_title_changed(cont);
+
return cont;
}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 648c1655..07157818 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -139,10 +139,20 @@ void view_autoconfigure(struct sway_view *view) {
return;
}
- int other_views = 1;
+ struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
+
+ int other_views = 0;
if (config->hide_edge_borders == E_SMART) {
- struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);
- 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;
@@ -151,47 +161,67 @@ void view_autoconfigure(struct sway_view *view) {
if (config->hide_edge_borders == E_BOTH
|| config->hide_edge_borders == E_VERTICAL
|| (config->hide_edge_borders == E_SMART && !other_views)) {
- view->border_left = view->swayc->x != 0;
+ view->border_left = view->swayc->x != ws->x;
int right_x = view->swayc->x + view->swayc->width;
- view->border_right = right_x != output->width;
+ view->border_right = right_x != ws->x + ws->width;
}
if (config->hide_edge_borders == E_BOTH
|| config->hide_edge_borders == E_HORIZONTAL
|| (config->hide_edge_borders == E_SMART && !other_views)) {
- view->border_top = view->swayc->y != 0;
+ view->border_top = view->swayc->y != ws->y;
int bottom_y = view->swayc->y + view->swayc->height;
- view->border_bottom = bottom_y != output->height;
+ view->border_bottom = bottom_y != ws->y + ws->height;
}
}
double x, y, width, height;
x = y = width = height = 0;
+ double y_offset = 0;
+
+ // In a tabbed or stacked container, the swayc's y is the top of the title
+ // 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 = container_titlebar_height();
+ view->border_top = 0;
+ } else if (view->swayc->parent->layout == L_STACKED) {
+ y_offset = container_titlebar_height()
+ * view->swayc->parent->children->length;
+ view->border_top = 0;
+ }
+
switch (view->border) {
case B_NONE:
x = view->swayc->x;
- y = view->swayc->y;
+ y = view->swayc->y + y_offset;
width = view->swayc->width;
- height = view->swayc->height;
+ height = view->swayc->height - y_offset;
break;
case B_PIXEL:
x = view->swayc->x + view->border_thickness * view->border_left;
- y = view->swayc->y + view->border_thickness * view->border_top;
+ y = view->swayc->y + view->border_thickness * view->border_top + y_offset;
width = view->swayc->width
- view->border_thickness * view->border_left
- view->border_thickness * view->border_right;
- height = view->swayc->height
+ height = view->swayc->height - y_offset
- view->border_thickness * view->border_top
- 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;
- y = view->swayc->y + config->font_height + view->border_thickness * 2;
width = view->swayc->width
- view->border_thickness * view->border_left
- view->border_thickness * view->border_right;
- height = view->swayc->height - config->font_height
- - view->border_thickness * (2 + view->border_bottom);
+ if (y_offset) {
+ y = view->swayc->y + y_offset;
+ height = view->swayc->height - y_offset
+ - view->border_thickness * view->border_bottom;
+ } else {
+ y = view->swayc->y + container_titlebar_height();
+ height = view->swayc->height - container_titlebar_height()
+ - view->border_thickness * view->border_bottom;
+ }
break;
}
@@ -440,6 +470,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
input_manager_set_focus(input_manager, cont);
view_update_title(view, false);
+ container_notify_child_title_changed(view->swayc->parent);
view_execute_criteria(view);
container_damage_whole(cont);
@@ -863,3 +894,28 @@ void view_update_marks_textures(struct sway_view *view) {
&config->border_colors.urgent);
container_damage_whole(view->swayc);
}
+
+bool view_is_visible(struct sway_view *view) {
+ if (!view->swayc) {
+ return false;
+ }
+ // Check view isn't in a tabbed or stacked container on an inactive tab
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+ struct sway_container *container = view->swayc;
+ while (container->type != C_WORKSPACE) {
+ if (container->parent->layout == L_TABBED ||
+ container->parent->layout == L_STACKED) {
+ if (seat_get_active_child(seat, container->parent) != container) {
+ return false;
+ }
+ }
+ container = container->parent;
+ }
+ // Check view isn't hidden by another fullscreen view
+ struct sway_container *workspace = container;
+ if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) {
+ return false;
+ }
+ // Check the workspace is visible
+ return workspace_is_visible(workspace);
+}