|
|
@ -8,15 +8,13 @@
|
|
|
|
#include <wlr/types/wlr_output_layout.h>
|
|
|
|
#include <wlr/types/wlr_output_layout.h>
|
|
|
|
#include <wlr/types/wlr_subcompositor.h>
|
|
|
|
#include <wlr/types/wlr_subcompositor.h>
|
|
|
|
#include "linux-dmabuf-unstable-v1-protocol.h"
|
|
|
|
#include "linux-dmabuf-unstable-v1-protocol.h"
|
|
|
|
#include "cairo_util.h"
|
|
|
|
|
|
|
|
#include "pango.h"
|
|
|
|
|
|
|
|
#include "sway/config.h"
|
|
|
|
#include "sway/config.h"
|
|
|
|
#include "sway/desktop.h"
|
|
|
|
|
|
|
|
#include "sway/desktop/transaction.h"
|
|
|
|
#include "sway/desktop/transaction.h"
|
|
|
|
#include "sway/input/input-manager.h"
|
|
|
|
#include "sway/input/input-manager.h"
|
|
|
|
#include "sway/input/seat.h"
|
|
|
|
#include "sway/input/seat.h"
|
|
|
|
#include "sway/ipc-server.h"
|
|
|
|
#include "sway/ipc-server.h"
|
|
|
|
#include "sway/scene_descriptor.h"
|
|
|
|
#include "sway/scene_descriptor.h"
|
|
|
|
|
|
|
|
#include "sway/sway_text_node.h"
|
|
|
|
#include "sway/output.h"
|
|
|
|
#include "sway/output.h"
|
|
|
|
#include "sway/server.h"
|
|
|
|
#include "sway/server.h"
|
|
|
|
#include "sway/surface.h"
|
|
|
|
#include "sway/surface.h"
|
|
|
@ -120,9 +118,328 @@ struct sway_container *container_create(struct sway_view *view) {
|
|
|
|
wl_signal_init(&c->events.destroy);
|
|
|
|
wl_signal_init(&c->events.destroy);
|
|
|
|
wl_signal_emit_mutable(&root->events.new_node, &c->node);
|
|
|
|
wl_signal_emit_mutable(&root->events.new_node, &c->node);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
container_update(c);
|
|
|
|
|
|
|
|
|
|
|
|
return c;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool container_is_focused(struct sway_container *con, void *data) {
|
|
|
|
|
|
|
|
return con->current.focused;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool container_has_focused_child(struct sway_container *con) {
|
|
|
|
|
|
|
|
return container_find_child(con, container_is_focused, NULL);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool container_is_current_parent_focused(struct sway_container *con) {
|
|
|
|
|
|
|
|
if (con->current.parent) {
|
|
|
|
|
|
|
|
struct sway_container *parent = con->current.parent;
|
|
|
|
|
|
|
|
return parent->current.focused || container_is_current_parent_focused(parent);
|
|
|
|
|
|
|
|
} else if (con->current.workspace) {
|
|
|
|
|
|
|
|
struct sway_workspace *ws = con->current.workspace;
|
|
|
|
|
|
|
|
return ws->current.focused;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct border_colors *container_get_current_colors(
|
|
|
|
|
|
|
|
struct sway_container *con) {
|
|
|
|
|
|
|
|
struct border_colors *colors;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool urgent = con->view ?
|
|
|
|
|
|
|
|
view_is_urgent(con->view) : container_has_urgent_child(con);
|
|
|
|
|
|
|
|
struct sway_container *active_child;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (con->current.parent) {
|
|
|
|
|
|
|
|
active_child = con->current.parent->current.focused_inactive_child;
|
|
|
|
|
|
|
|
} else if (con->current.workspace) {
|
|
|
|
|
|
|
|
active_child = con->current.workspace->current.focused_inactive_child;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
active_child = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (urgent) {
|
|
|
|
|
|
|
|
colors = &config->border_colors.urgent;
|
|
|
|
|
|
|
|
} else if (con->current.focused || container_is_current_parent_focused(con)) {
|
|
|
|
|
|
|
|
colors = &config->border_colors.focused;
|
|
|
|
|
|
|
|
} else if (config->has_focused_tab_title && container_has_focused_child(con)) {
|
|
|
|
|
|
|
|
colors = &config->border_colors.focused_tab_title;
|
|
|
|
|
|
|
|
} else if (con == active_child) {
|
|
|
|
|
|
|
|
colors = &config->border_colors.focused_inactive;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
colors = &config->border_colors.unfocused;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return colors;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool container_is_current_floating(struct sway_container *container) {
|
|
|
|
|
|
|
|
if (!container->current.parent && container->current.workspace &&
|
|
|
|
|
|
|
|
list_find(container->current.workspace->floating, container) != -1) {
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (container->scratchpad) {
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// scene rect wants premultiplied colors
|
|
|
|
|
|
|
|
static void scene_rect_set_color(struct wlr_scene_rect *rect,
|
|
|
|
|
|
|
|
const float color[4], float opacity) {
|
|
|
|
|
|
|
|
const float premultiplied[] = {
|
|
|
|
|
|
|
|
color[0] * color[3] * opacity,
|
|
|
|
|
|
|
|
color[1] * color[3] * opacity,
|
|
|
|
|
|
|
|
color[2] * color[3] * opacity,
|
|
|
|
|
|
|
|
color[3] * opacity,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wlr_scene_rect_set_color(rect, premultiplied);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void container_update(struct sway_container *con) {
|
|
|
|
|
|
|
|
struct border_colors *colors = container_get_current_colors(con);
|
|
|
|
|
|
|
|
list_t *siblings = NULL;
|
|
|
|
|
|
|
|
enum sway_container_layout layout = L_NONE;
|
|
|
|
|
|
|
|
float alpha = con->alpha;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (con->current.parent) {
|
|
|
|
|
|
|
|
siblings = con->current.parent->current.children;
|
|
|
|
|
|
|
|
layout = con->current.parent->current.layout;
|
|
|
|
|
|
|
|
} else if (con->current.workspace) {
|
|
|
|
|
|
|
|
siblings = con->current.workspace->current.tiling;
|
|
|
|
|
|
|
|
layout = con->current.workspace->current.layout;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float bottom[4], right[4];
|
|
|
|
|
|
|
|
memcpy(bottom, colors->child_border, sizeof(bottom));
|
|
|
|
|
|
|
|
memcpy(right, colors->child_border, sizeof(right));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!container_is_current_floating(con) && siblings && siblings->length == 1) {
|
|
|
|
|
|
|
|
if (layout == L_HORIZ) {
|
|
|
|
|
|
|
|
memcpy(right, colors->indicator, sizeof(right));
|
|
|
|
|
|
|
|
} else if (layout == L_VERT) {
|
|
|
|
|
|
|
|
memcpy(bottom, colors->indicator, sizeof(bottom));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct wlr_scene_node *node;
|
|
|
|
|
|
|
|
wl_list_for_each(node, &con->title_bar.border->children, link) {
|
|
|
|
|
|
|
|
struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
|
|
|
|
|
|
|
|
scene_rect_set_color(rect, colors->border, alpha);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wl_list_for_each(node, &con->title_bar.background->children, link) {
|
|
|
|
|
|
|
|
struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
|
|
|
|
|
|
|
|
scene_rect_set_color(rect, colors->background, alpha);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (con->view) {
|
|
|
|
|
|
|
|
scene_rect_set_color(con->border.top, colors->child_border, alpha);
|
|
|
|
|
|
|
|
scene_rect_set_color(con->border.bottom, bottom, alpha);
|
|
|
|
|
|
|
|
scene_rect_set_color(con->border.left, colors->child_border, alpha);
|
|
|
|
|
|
|
|
scene_rect_set_color(con->border.right, right, alpha);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (con->title_bar.title_text) {
|
|
|
|
|
|
|
|
sway_text_node_set_color(con->title_bar.title_text, colors->text);
|
|
|
|
|
|
|
|
sway_text_node_set_background(con->title_bar.title_text, colors->background);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (con->title_bar.marks_text) {
|
|
|
|
|
|
|
|
sway_text_node_set_color(con->title_bar.marks_text, colors->text);
|
|
|
|
|
|
|
|
sway_text_node_set_background(con->title_bar.marks_text, colors->background);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void container_update_itself_and_parents(struct sway_container *con) {
|
|
|
|
|
|
|
|
container_update(con);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (con->current.parent) {
|
|
|
|
|
|
|
|
container_update_itself_and_parents(con->current.parent);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void update_rect_list(struct wlr_scene_tree *tree, pixman_region32_t *region) {
|
|
|
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
const pixman_box32_t *rects = pixman_region32_rectangles(region, &len);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wlr_scene_node_set_enabled(&tree->node, len > 0);
|
|
|
|
|
|
|
|
if (len == 0) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
struct wlr_scene_node *node;
|
|
|
|
|
|
|
|
wl_list_for_each(node, &tree->children, link) {
|
|
|
|
|
|
|
|
struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
|
|
|
|
|
|
|
|
wlr_scene_node_set_enabled(&rect->node, i < len);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (i < len) {
|
|
|
|
|
|
|
|
const pixman_box32_t *box = &rects[i++];
|
|
|
|
|
|
|
|
wlr_scene_node_set_position(&rect->node, box->x1, box->y1);
|
|
|
|
|
|
|
|
wlr_scene_rect_set_size(rect, box->x2 - box->x1, box->y2 - box->y1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void container_arrange_title_bar(struct sway_container *con) {
|
|
|
|
|
|
|
|
enum alignment title_align = config->title_align;
|
|
|
|
|
|
|
|
int marks_buffer_width = 0;
|
|
|
|
|
|
|
|
int width = con->title_width;
|
|
|
|
|
|
|
|
int height = container_titlebar_height();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pixman_region32_t text_area;
|
|
|
|
|
|
|
|
pixman_region32_init(&text_area);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (con->title_bar.marks_text) {
|
|
|
|
|
|
|
|
struct sway_text_node *node = con->title_bar.marks_text;
|
|
|
|
|
|
|
|
marks_buffer_width = node->width;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int h_padding;
|
|
|
|
|
|
|
|
if (title_align == ALIGN_RIGHT) {
|
|
|
|
|
|
|
|
h_padding = config->titlebar_h_padding;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
h_padding = width - config->titlebar_h_padding - marks_buffer_width;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
h_padding = MAX(h_padding, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int alloc_width = MIN((int)node->width,
|
|
|
|
|
|
|
|
width - h_padding - config->titlebar_h_padding);
|
|
|
|
|
|
|
|
sway_text_node_set_max_width(node, alloc_width);
|
|
|
|
|
|
|
|
wlr_scene_node_set_position(node->node,
|
|
|
|
|
|
|
|
h_padding, (height - node->height) >> 1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pixman_region32_union_rect(&text_area, &text_area,
|
|
|
|
|
|
|
|
node->node->x, node->node->y, alloc_width, node->height);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (con->title_bar.title_text) {
|
|
|
|
|
|
|
|
struct sway_text_node *node = con->title_bar.title_text;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int h_padding;
|
|
|
|
|
|
|
|
if (title_align == ALIGN_RIGHT) {
|
|
|
|
|
|
|
|
h_padding = width - config->titlebar_h_padding - node->width;
|
|
|
|
|
|
|
|
} else if (title_align == ALIGN_CENTER) {
|
|
|
|
|
|
|
|
h_padding = ((int)width - marks_buffer_width - node->width) >> 1;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
h_padding = config->titlebar_h_padding;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
h_padding = MAX(h_padding, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int alloc_width = MIN((int) node->width,
|
|
|
|
|
|
|
|
width - h_padding - config->titlebar_h_padding);
|
|
|
|
|
|
|
|
sway_text_node_set_max_width(node, alloc_width);
|
|
|
|
|
|
|
|
wlr_scene_node_set_position(node->node,
|
|
|
|
|
|
|
|
h_padding, (height - node->height) >> 1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pixman_region32_union_rect(&text_area, &text_area,
|
|
|
|
|
|
|
|
node->node->x, node->node->y, alloc_width, node->height);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// silence pixman errors
|
|
|
|
|
|
|
|
if (width <= 0 || height <= 0) {
|
|
|
|
|
|
|
|
pixman_region32_fini(&text_area);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pixman_region32_t background, border;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int thickness = config->titlebar_border_thickness;
|
|
|
|
|
|
|
|
pixman_region32_init_rect(&background,
|
|
|
|
|
|
|
|
thickness, thickness,
|
|
|
|
|
|
|
|
width - thickness * 2, height - thickness * 2);
|
|
|
|
|
|
|
|
pixman_region32_init_rect(&border, 0, 0, width, height);
|
|
|
|
|
|
|
|
pixman_region32_subtract(&border, &border, &background);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pixman_region32_subtract(&background, &background, &text_area);
|
|
|
|
|
|
|
|
pixman_region32_fini(&text_area);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
update_rect_list(con->title_bar.background, &background);
|
|
|
|
|
|
|
|
pixman_region32_fini(&background);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
update_rect_list(con->title_bar.border, &border);
|
|
|
|
|
|
|
|
pixman_region32_fini(&border);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
container_update(con);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void container_update_marks(struct sway_container *con) {
|
|
|
|
|
|
|
|
char *buffer = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (config->show_marks && con->marks->length) {
|
|
|
|
|
|
|
|
size_t len = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < con->marks->length; ++i) {
|
|
|
|
|
|
|
|
char *mark = con->marks->items[i];
|
|
|
|
|
|
|
|
if (mark[0] != '_') {
|
|
|
|
|
|
|
|
len += strlen(mark) + 2;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer = calloc(len + 1, 1);
|
|
|
|
|
|
|
|
char *part = malloc(len + 1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!sway_assert(buffer && part, "Unable to allocate memory")) {
|
|
|
|
|
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < con->marks->length; ++i) {
|
|
|
|
|
|
|
|
char *mark = con->marks->items[i];
|
|
|
|
|
|
|
|
if (mark[0] != '_') {
|
|
|
|
|
|
|
|
snprintf(part, len + 1, "[%s]", mark);
|
|
|
|
|
|
|
|
strcat(buffer, part);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
free(part);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!buffer) {
|
|
|
|
|
|
|
|
if (con->title_bar.marks_text) {
|
|
|
|
|
|
|
|
wlr_scene_node_destroy(con->title_bar.marks_text->node);
|
|
|
|
|
|
|
|
con->title_bar.marks_text = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (!con->title_bar.marks_text) {
|
|
|
|
|
|
|
|
struct border_colors *colors = container_get_current_colors(con);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
con->title_bar.marks_text = sway_text_node_create(con->title_bar.tree,
|
|
|
|
|
|
|
|
buffer, colors->text, false);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
sway_text_node_set_text(con->title_bar.marks_text, buffer);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
container_arrange_title_bar(con);
|
|
|
|
|
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void container_update_title_bar(struct sway_container *con) {
|
|
|
|
|
|
|
|
if (!con->formatted_title) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct border_colors *colors = container_get_current_colors(con);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (con->title_bar.title_text) {
|
|
|
|
|
|
|
|
wlr_scene_node_destroy(con->title_bar.title_text->node);
|
|
|
|
|
|
|
|
con->title_bar.title_text = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
con->title_bar.title_text = sway_text_node_create(con->title_bar.tree,
|
|
|
|
|
|
|
|
con->formatted_title, colors->text, config->pango_markup);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// we always have to remake these text buffers completely for text font
|
|
|
|
|
|
|
|
// changes etc...
|
|
|
|
|
|
|
|
if (con->title_bar.marks_text) {
|
|
|
|
|
|
|
|
wlr_scene_node_destroy(con->title_bar.marks_text->node);
|
|
|
|
|
|
|
|
con->title_bar.marks_text = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
container_update_marks(con);
|
|
|
|
|
|
|
|
container_arrange_title_bar(con);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void container_destroy(struct sway_container *con) {
|
|
|
|
void container_destroy(struct sway_container *con) {
|
|
|
|
if (!sway_assert(con->node.destroying,
|
|
|
|
if (!sway_assert(con->node.destroying,
|
|
|
|
"Tried to free container which wasn't marked as destroying")) {
|
|
|
|
"Tried to free container which wasn't marked as destroying")) {
|
|
|
@ -134,21 +451,11 @@ void container_destroy(struct sway_container *con) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(con->title);
|
|
|
|
free(con->title);
|
|
|
|
free(con->formatted_title);
|
|
|
|
free(con->formatted_title);
|
|
|
|
wlr_texture_destroy(con->title_focused);
|
|
|
|
|
|
|
|
wlr_texture_destroy(con->title_focused_inactive);
|
|
|
|
|
|
|
|
wlr_texture_destroy(con->title_unfocused);
|
|
|
|
|
|
|
|
wlr_texture_destroy(con->title_urgent);
|
|
|
|
|
|
|
|
wlr_texture_destroy(con->title_focused_tab_title);
|
|
|
|
|
|
|
|
list_free(con->pending.children);
|
|
|
|
list_free(con->pending.children);
|
|
|
|
list_free(con->current.children);
|
|
|
|
list_free(con->current.children);
|
|
|
|
list_free(con->outputs);
|
|
|
|
list_free(con->outputs);
|
|
|
|
|
|
|
|
|
|
|
|
list_free_items_and_destroy(con->marks);
|
|
|
|
list_free_items_and_destroy(con->marks);
|
|
|
|
wlr_texture_destroy(con->marks_focused);
|
|
|
|
|
|
|
|
wlr_texture_destroy(con->marks_focused_inactive);
|
|
|
|
|
|
|
|
wlr_texture_destroy(con->marks_unfocused);
|
|
|
|
|
|
|
|
wlr_texture_destroy(con->marks_urgent);
|
|
|
|
|
|
|
|
wlr_texture_destroy(con->marks_focused_tab_title);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (con->view && con->view->container == con) {
|
|
|
|
if (con->view && con->view->container == con) {
|
|
|
|
con->view->container = NULL;
|
|
|
|
con->view->container = NULL;
|
|
|
@ -308,108 +615,6 @@ struct sway_output *container_get_effective_output(struct sway_container *con) {
|
|
|
|
return con->outputs->items[con->outputs->length - 1];
|
|
|
|
return con->outputs->items[con->outputs->length - 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void render_titlebar_text_texture(struct sway_output *output,
|
|
|
|
|
|
|
|
struct sway_container *con, struct wlr_texture **texture,
|
|
|
|
|
|
|
|
struct border_colors *class, bool pango_markup, char *text) {
|
|
|
|
|
|
|
|
double scale = output->wlr_output->scale;
|
|
|
|
|
|
|
|
int width = 0;
|
|
|
|
|
|
|
|
int height = config->font_height * scale;
|
|
|
|
|
|
|
|
int baseline;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We must use a non-nil cairo_t for cairo_set_font_options to work.
|
|
|
|
|
|
|
|
// Therefore, we cannot use cairo_create(NULL).
|
|
|
|
|
|
|
|
cairo_surface_t *dummy_surface = cairo_image_surface_create(
|
|
|
|
|
|
|
|
CAIRO_FORMAT_ARGB32, 0, 0);
|
|
|
|
|
|
|
|
cairo_t *c = cairo_create(dummy_surface);
|
|
|
|
|
|
|
|
cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST);
|
|
|
|
|
|
|
|
cairo_font_options_t *fo = cairo_font_options_create();
|
|
|
|
|
|
|
|
if (output->wlr_output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) {
|
|
|
|
|
|
|
|
cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
|
|
|
|
|
|
|
|
cairo_font_options_set_subpixel_order(fo,
|
|
|
|
|
|
|
|
to_cairo_subpixel_order(output->wlr_output->subpixel));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_set_font_options(c, fo);
|
|
|
|
|
|
|
|
get_text_size(c, config->font_description, &width, NULL, &baseline, scale,
|
|
|
|
|
|
|
|
config->pango_markup, "%s", text);
|
|
|
|
|
|
|
|
cairo_surface_destroy(dummy_surface);
|
|
|
|
|
|
|
|
cairo_destroy(c);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (width == 0 || height == 0) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (height > config->font_height * scale) {
|
|
|
|
|
|
|
|
height = config->font_height * scale;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cairo_surface_t *surface = cairo_image_surface_create(
|
|
|
|
|
|
|
|
CAIRO_FORMAT_ARGB32, width, height);
|
|
|
|
|
|
|
|
cairo_status_t status = cairo_surface_status(surface);
|
|
|
|
|
|
|
|
if (status != CAIRO_STATUS_SUCCESS) {
|
|
|
|
|
|
|
|
sway_log(SWAY_ERROR, "cairo_image_surface_create failed: %s",
|
|
|
|
|
|
|
|
cairo_status_to_string(status));
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cairo_t *cairo = cairo_create(surface);
|
|
|
|
|
|
|
|
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
|
|
|
|
|
|
|
|
cairo_set_font_options(cairo, fo);
|
|
|
|
|
|
|
|
cairo_font_options_destroy(fo);
|
|
|
|
|
|
|
|
cairo_set_source_rgba(cairo, class->background[0], class->background[1],
|
|
|
|
|
|
|
|
class->background[2], class->background[3]);
|
|
|
|
|
|
|
|
cairo_paint(cairo);
|
|
|
|
|
|
|
|
PangoContext *pango = pango_cairo_create_context(cairo);
|
|
|
|
|
|
|
|
cairo_set_source_rgba(cairo, class->text[0], class->text[1],
|
|
|
|
|
|
|
|
class->text[2], class->text[3]);
|
|
|
|
|
|
|
|
cairo_move_to(cairo, 0, config->font_baseline * scale - baseline);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
render_text(cairo, config->font_description, scale, pango_markup, "%s", text);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cairo_surface_flush(surface);
|
|
|
|
|
|
|
|
unsigned char *data = cairo_image_surface_get_data(surface);
|
|
|
|
|
|
|
|
int stride = cairo_image_surface_get_stride(surface);
|
|
|
|
|
|
|
|
struct wlr_renderer *renderer = output->wlr_output->renderer;
|
|
|
|
|
|
|
|
*texture = wlr_texture_from_pixels(
|
|
|
|
|
|
|
|
renderer, DRM_FORMAT_ARGB8888, stride, width, height, data);
|
|
|
|
|
|
|
|
cairo_surface_destroy(surface);
|
|
|
|
|
|
|
|
g_object_unref(pango);
|
|
|
|
|
|
|
|
cairo_destroy(cairo);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void update_title_texture(struct sway_container *con,
|
|
|
|
|
|
|
|
struct wlr_texture **texture, struct border_colors *class) {
|
|
|
|
|
|
|
|
struct sway_output *output = container_get_effective_output(con);
|
|
|
|
|
|
|
|
if (!output) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*texture) {
|
|
|
|
|
|
|
|
wlr_texture_destroy(*texture);
|
|
|
|
|
|
|
|
*texture = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!con->formatted_title) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
render_titlebar_text_texture(output, con, texture, class,
|
|
|
|
|
|
|
|
config->pango_markup, con->formatted_title);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void container_update_title_textures(struct sway_container *container) {
|
|
|
|
|
|
|
|
update_title_texture(container, &container->title_focused,
|
|
|
|
|
|
|
|
&config->border_colors.focused);
|
|
|
|
|
|
|
|
update_title_texture(container, &container->title_focused_inactive,
|
|
|
|
|
|
|
|
&config->border_colors.focused_inactive);
|
|
|
|
|
|
|
|
update_title_texture(container, &container->title_unfocused,
|
|
|
|
|
|
|
|
&config->border_colors.unfocused);
|
|
|
|
|
|
|
|
update_title_texture(container, &container->title_urgent,
|
|
|
|
|
|
|
|
&config->border_colors.urgent);
|
|
|
|
|
|
|
|
update_title_texture(container, &container->title_focused_tab_title,
|
|
|
|
|
|
|
|
&config->border_colors.focused_tab_title);
|
|
|
|
|
|
|
|
container_damage_whole(container);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Calculate and return the length of the tree representation.
|
|
|
|
* Calculate and return the length of the tree representation.
|
|
|
|
* An example tree representation is: V[Terminal, Firefox]
|
|
|
|
* An example tree representation is: V[Terminal, Firefox]
|
|
|
@ -475,7 +680,13 @@ void container_update_representation(struct sway_container *con) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
container_build_representation(con->pending.layout, con->pending.children,
|
|
|
|
container_build_representation(con->pending.layout, con->pending.children,
|
|
|
|
con->formatted_title);
|
|
|
|
con->formatted_title);
|
|
|
|
container_update_title_textures(con);
|
|
|
|
|
|
|
|
|
|
|
|
if (con->title_bar.title_text) {
|
|
|
|
|
|
|
|
sway_text_node_set_text(con->title_bar.title_text, con->formatted_title);
|
|
|
|
|
|
|
|
container_arrange_title_bar(con);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
container_update_title_bar(con);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (con->pending.parent) {
|
|
|
|
if (con->pending.parent) {
|
|
|
|
container_update_representation(con->pending.parent);
|
|
|
|
container_update_representation(con->pending.parent);
|
|
|
@ -761,17 +972,6 @@ bool container_is_floating(struct sway_container *container) {
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool container_is_current_floating(struct sway_container *container) {
|
|
|
|
|
|
|
|
if (!container->current.parent && container->current.workspace &&
|
|
|
|
|
|
|
|
list_find(container->current.workspace->floating, container) != -1) {
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (container->scratchpad) {
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void container_get_box(struct sway_container *container, struct wlr_box *box) {
|
|
|
|
void container_get_box(struct sway_container *container, struct wlr_box *box) {
|
|
|
|
box->x = container->pending.x;
|
|
|
|
box->x = container->pending.x;
|
|
|
|
box->y = container->pending.y;
|
|
|
|
box->y = container->pending.y;
|
|
|
@ -1092,7 +1292,6 @@ void container_discover_outputs(struct sway_container *con) {
|
|
|
|
.width = con->current.width,
|
|
|
|
.width = con->current.width,
|
|
|
|
.height = con->current.height,
|
|
|
|
.height = con->current.height,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
struct sway_output *old_output = container_get_effective_output(con);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < root->outputs->length; ++i) {
|
|
|
|
for (int i = 0; i < root->outputs->length; ++i) {
|
|
|
|
struct sway_output *output = root->outputs->items[i];
|
|
|
|
struct sway_output *output = root->outputs->items[i];
|
|
|
@ -1129,14 +1328,6 @@ void container_discover_outputs(struct sway_container *con) {
|
|
|
|
list_del(con->outputs, index);
|
|
|
|
list_del(con->outputs, index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
struct sway_output *new_output = container_get_effective_output(con);
|
|
|
|
|
|
|
|
double old_scale = old_output && old_output->enabled ?
|
|
|
|
|
|
|
|
old_output->wlr_output->scale : -1;
|
|
|
|
|
|
|
|
double new_scale = new_output ? new_output->wlr_output->scale : -1;
|
|
|
|
|
|
|
|
if (old_scale != new_scale) {
|
|
|
|
|
|
|
|
container_update_title_textures(con);
|
|
|
|
|
|
|
|
container_update_marks_textures(con);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
enum sway_container_layout container_parent_layout(struct sway_container *con) {
|
|
|
|
enum sway_container_layout container_parent_layout(struct sway_container *con) {
|
|
|
@ -1149,14 +1340,6 @@ enum sway_container_layout container_parent_layout(struct sway_container *con) {
|
|
|
|
return L_NONE;
|
|
|
|
return L_NONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
enum sway_container_layout container_current_parent_layout(
|
|
|
|
|
|
|
|
struct sway_container *con) {
|
|
|
|
|
|
|
|
if (con->current.parent) {
|
|
|
|
|
|
|
|
return con->current.parent->current.layout;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return con->current.workspace->current.layout;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
list_t *container_get_siblings(struct sway_container *container) {
|
|
|
|
list_t *container_get_siblings(struct sway_container *container) {
|
|
|
|
if (container->pending.parent) {
|
|
|
|
if (container->pending.parent) {
|
|
|
|
return container->pending.parent->pending.children;
|
|
|
|
return container->pending.parent->pending.children;
|
|
|
@ -1174,13 +1357,6 @@ int container_sibling_index(struct sway_container *child) {
|
|
|
|
return list_find(container_get_siblings(child), child);
|
|
|
|
return list_find(container_get_siblings(child), child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
list_t *container_get_current_siblings(struct sway_container *container) {
|
|
|
|
|
|
|
|
if (container->current.parent) {
|
|
|
|
|
|
|
|
return container->current.parent->current.children;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return container->current.workspace->current.tiling;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void container_handle_fullscreen_reparent(struct sway_container *con) {
|
|
|
|
void container_handle_fullscreen_reparent(struct sway_container *con) {
|
|
|
|
if (con->pending.fullscreen_mode != FULLSCREEN_WORKSPACE || !con->pending.workspace ||
|
|
|
|
if (con->pending.fullscreen_mode != FULLSCREEN_WORKSPACE || !con->pending.workspace ||
|
|
|
|
con->pending.workspace->fullscreen == con) {
|
|
|
|
con->pending.workspace->fullscreen == con) {
|
|
|
@ -1395,7 +1571,7 @@ bool container_find_and_unmark(char *mark) {
|
|
|
|
if (strcmp(con_mark, mark) == 0) {
|
|
|
|
if (strcmp(con_mark, mark) == 0) {
|
|
|
|
free(con_mark);
|
|
|
|
free(con_mark);
|
|
|
|
list_del(con->marks, i);
|
|
|
|
list_del(con->marks, i);
|
|
|
|
container_update_marks_textures(con);
|
|
|
|
container_update_marks(con);
|
|
|
|
ipc_event_window(con, "mark");
|
|
|
|
ipc_event_window(con, "mark");
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1426,70 +1602,15 @@ void container_add_mark(struct sway_container *con, char *mark) {
|
|
|
|
ipc_event_window(con, "mark");
|
|
|
|
ipc_event_window(con, "mark");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void update_marks_texture(struct sway_container *con,
|
|
|
|
|
|
|
|
struct wlr_texture **texture, struct border_colors *class) {
|
|
|
|
|
|
|
|
struct sway_output *output = container_get_effective_output(con);
|
|
|
|
|
|
|
|
if (!output) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*texture) {
|
|
|
|
|
|
|
|
wlr_texture_destroy(*texture);
|
|
|
|
|
|
|
|
*texture = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!con->marks->length) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
size_t len = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < con->marks->length; ++i) {
|
|
|
|
|
|
|
|
char *mark = con->marks->items[i];
|
|
|
|
|
|
|
|
if (mark[0] != '_') {
|
|
|
|
|
|
|
|
len += strlen(mark) + 2;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
char *buffer = calloc(len + 1, 1);
|
|
|
|
|
|
|
|
char *part = malloc(len + 1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!sway_assert(buffer && part, "Unable to allocate memory")) {
|
|
|
|
|
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < con->marks->length; ++i) {
|
|
|
|
|
|
|
|
char *mark = con->marks->items[i];
|
|
|
|
|
|
|
|
if (mark[0] != '_') {
|
|
|
|
|
|
|
|
snprintf(part, len + 1, "[%s]", mark);
|
|
|
|
|
|
|
|
strcat(buffer, part);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
free(part);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
render_titlebar_text_texture(output, con, texture, class, false, buffer);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void container_update_marks_textures(struct sway_container *con) {
|
|
|
|
|
|
|
|
if (!config->show_marks) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
update_marks_texture(con, &con->marks_focused,
|
|
|
|
|
|
|
|
&config->border_colors.focused);
|
|
|
|
|
|
|
|
update_marks_texture(con, &con->marks_focused_inactive,
|
|
|
|
|
|
|
|
&config->border_colors.focused_inactive);
|
|
|
|
|
|
|
|
update_marks_texture(con, &con->marks_unfocused,
|
|
|
|
|
|
|
|
&config->border_colors.unfocused);
|
|
|
|
|
|
|
|
update_marks_texture(con, &con->marks_urgent,
|
|
|
|
|
|
|
|
&config->border_colors.urgent);
|
|
|
|
|
|
|
|
update_marks_texture(con, &con->marks_focused_tab_title,
|
|
|
|
|
|
|
|
&config->border_colors.focused_tab_title);
|
|
|
|
|
|
|
|
container_damage_whole(con);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void container_raise_floating(struct sway_container *con) {
|
|
|
|
void container_raise_floating(struct sway_container *con) {
|
|
|
|
// Bring container to front by putting it at the end of the floating list.
|
|
|
|
// Bring container to front by putting it at the end of the floating list.
|
|
|
|
struct sway_container *floater = container_toplevel_ancestor(con);
|
|
|
|
struct sway_container *floater = container_toplevel_ancestor(con);
|
|
|
|
if (container_is_floating(floater) && floater->pending.workspace) {
|
|
|
|
if (container_is_floating(floater) && floater->pending.workspace) {
|
|
|
|
|
|
|
|
// it's okay to just raise the scene directly instead of waiting
|
|
|
|
|
|
|
|
// for the transaction to go through. We won't be reconfiguring
|
|
|
|
|
|
|
|
// surfaces
|
|
|
|
|
|
|
|
wlr_scene_node_raise_to_top(&floater->scene_tree->node);
|
|
|
|
|
|
|
|
|
|
|
|
list_move_to_end(floater->pending.workspace->floating, floater);
|
|
|
|
list_move_to_end(floater->pending.workspace->floating, floater);
|
|
|
|
node_set_dirty(&floater->pending.workspace->node);
|
|
|
|
node_set_dirty(&floater->pending.workspace->node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|