mirror of
https://github.com/gwenhael-le-moine/sway-patched-tray-menu.git
synced 2024-12-28 22:23:42 +01:00
Merge branch 'master' into fix-swaylock-hotplugging
This commit is contained in:
commit
cd0fca2ebf
20 changed files with 990 additions and 338 deletions
|
@ -29,7 +29,8 @@ struct sway_cursor {
|
|||
|
||||
void sway_cursor_destroy(struct sway_cursor *cursor);
|
||||
struct sway_cursor *sway_cursor_create(struct sway_seat *seat);
|
||||
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);
|
||||
void dispatch_cursor_button(struct sway_cursor *cursor, uint32_t time_msec,
|
||||
uint32_t button, enum wlr_button_state state);
|
||||
|
||||
|
|
|
@ -94,6 +94,12 @@ struct sway_container *seat_get_focus_inactive(struct sway_seat *seat,
|
|||
struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat,
|
||||
struct sway_container *container);
|
||||
|
||||
/**
|
||||
* Return the immediate child of container which was most recently focused.
|
||||
*/
|
||||
struct sway_container *seat_get_active_child(struct sway_seat *seat,
|
||||
struct sway_container *container);
|
||||
|
||||
/**
|
||||
* Iterate over the focus-inactive children of the container calling the
|
||||
* function on each.
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
@ -98,6 +104,8 @@ struct sway_container {
|
|||
// Passed the previous parent
|
||||
struct wl_signal reparent;
|
||||
} events;
|
||||
|
||||
struct wl_listener reparent;
|
||||
};
|
||||
|
||||
struct sway_container *container_create(enum sway_container_type type);
|
||||
|
@ -160,7 +168,7 @@ struct sway_container *container_parent(struct sway_container *container,
|
|||
* is a view and the view contains a surface at those coordinates.
|
||||
*/
|
||||
struct sway_container *container_at(struct sway_container *container,
|
||||
double lx, double ly, struct wlr_surface **surface,
|
||||
double ox, double oy, struct wlr_surface **surface,
|
||||
double *sx, double *sy);
|
||||
|
||||
/**
|
||||
|
@ -210,4 +218,9 @@ void container_calculate_title_height(struct sway_container *container);
|
|||
|
||||
void container_notify_child_title_changed(struct sway_container *container);
|
||||
|
||||
/**
|
||||
* Return the height of a regular title bar.
|
||||
*/
|
||||
size_t container_titlebar_height(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -274,4 +274,10 @@ bool view_has_mark(struct sway_view *view, char *mark);
|
|||
|
||||
void view_update_marks_textures(struct sway_view *view);
|
||||
|
||||
/**
|
||||
* Returns true if there's a possibility the view may be rendered on screen.
|
||||
* Intended for damage tracking.
|
||||
*/
|
||||
bool view_is_visible(struct sway_view *view);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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 {
|
||||
|
@ -37,12 +37,14 @@ struct swaylock_state {
|
|||
struct zwlr_input_inhibit_manager_v1 *input_inhibit_manager;
|
||||
struct wl_shm *shm;
|
||||
struct wl_list surfaces;
|
||||
struct wl_list images;
|
||||
struct swaylock_args args;
|
||||
cairo_surface_t *background_image;
|
||||
struct swaylock_password password;
|
||||
struct swaylock_xkb xkb;
|
||||
enum auth_state auth_state;
|
||||
bool run_display;
|
||||
struct zxdg_output_manager_v1 *zxdg_output_manager;
|
||||
};
|
||||
|
||||
struct swaylock_surface {
|
||||
|
@ -50,12 +52,22 @@ struct swaylock_surface {
|
|||
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;
|
||||
struct pool_buffer buffers[2];
|
||||
struct pool_buffer *current_buffer;
|
||||
uint32_t width, height;
|
||||
int32_t scale;
|
||||
char *output_name;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
// There is exactly one swaylock_image for each -i argument
|
||||
struct swaylock_image {
|
||||
char *path;
|
||||
char *output_name;
|
||||
cairo_surface_t *cairo_surface;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ wayland_server = dependency('wayland-server')
|
|||
wayland_client = dependency('wayland-client')
|
||||
wayland_cursor = dependency('wayland-cursor')
|
||||
wayland_egl = dependency('wayland-egl')
|
||||
wayland_protos = dependency('wayland-protocols')
|
||||
wayland_protos = dependency('wayland-protocols', version: '>=1.14')
|
||||
xkbcommon = dependency('xkbcommon')
|
||||
cairo = dependency('cairo')
|
||||
pango = dependency('pango')
|
||||
|
|
|
@ -29,16 +29,18 @@ wayland_scanner_server = generator(
|
|||
|
||||
client_protocols = [
|
||||
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
||||
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
|
||||
['wlr-layer-shell-unstable-v1.xml'],
|
||||
['idle.xml'],
|
||||
['wlr-input-inhibitor-unstable-v1.xml']
|
||||
['wlr-input-inhibitor-unstable-v1.xml'],
|
||||
]
|
||||
|
||||
server_protocols = [
|
||||
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
|
||||
[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'],
|
||||
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
|
||||
['wlr-layer-shell-unstable-v1.xml'],
|
||||
['wlr-input-inhibitor-unstable-v1.xml']
|
||||
['wlr-input-inhibitor-unstable-v1.xml'],
|
||||
]
|
||||
|
||||
client_protos_src = []
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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".
|
||||
* Render a view's surface and left/bottom/right borders.
|
||||
*/
|
||||
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;
|
||||
render_view_surfaces(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 = 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_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_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) {
|
||||
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->sway_view;
|
||||
struct sway_view *view = con->type == C_VIEW ? con->sway_view : NULL;
|
||||
float output_scale = output->wlr_output->scale;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 + 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// 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 (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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Render the top border line for a view using "border pixel".
|
||||
*/
|
||||
static void render_container_simple_border_pixel(struct sway_output *output,
|
||||
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];
|
||||
struct sway_view *view = con->sway_view;
|
||||
float output_scale = output->wlr_output->scale;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
render_view(child->sway_view, output, damage);
|
||||
|
||||
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(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,79 +452,153 @@ 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
list_add(queue, parent);
|
||||
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
158
swaylock/main.c
158
swaylock/main.c
|
@ -13,6 +13,7 @@
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-client.h>
|
||||
#include <wordexp.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "swaylock/seat.h"
|
||||
#include "swaylock/swaylock.h"
|
||||
|
@ -20,9 +21,11 @@
|
|||
#include "pool-buffer.h"
|
||||
#include "cairo.h"
|
||||
#include "log.h"
|
||||
#include "stringop.h"
|
||||
#include "util.h"
|
||||
#include "wlr-input-inhibitor-unstable-v1-client-protocol.h"
|
||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||
|
||||
void sway_terminate(int exit_code) {
|
||||
exit(exit_code);
|
||||
|
@ -77,9 +80,14 @@ static void destroy_surface(struct swaylock_surface *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);
|
||||
|
||||
|
@ -123,22 +131,23 @@ static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
|
|||
.closed = layer_surface_closed,
|
||||
};
|
||||
|
||||
static void output_geometry(void *data, struct wl_output *output, int32_t x,
|
||||
static void handle_wl_output_geometry(void *data, struct wl_output *output, int32_t x,
|
||||
int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel,
|
||||
const char *make, const char *model, int32_t transform) {
|
||||
// Who cares
|
||||
}
|
||||
|
||||
static void output_mode(void *data, struct wl_output *output, uint32_t flags,
|
||||
static void handle_wl_output_mode(void *data, struct wl_output *output, uint32_t flags,
|
||||
int32_t width, int32_t height, int32_t refresh) {
|
||||
// Who cares
|
||||
}
|
||||
|
||||
static void output_done(void *data, struct wl_output *output) {
|
||||
static void handle_wl_output_done(void *data, struct wl_output *output) {
|
||||
// Who cares
|
||||
}
|
||||
|
||||
static void output_scale(void *data, struct wl_output *output, int32_t factor) {
|
||||
static void handle_wl_output_scale(void *data, struct wl_output *output,
|
||||
int32_t factor) {
|
||||
struct swaylock_surface *surface = data;
|
||||
surface->scale = factor;
|
||||
if (surface->state->run_display) {
|
||||
|
@ -146,11 +155,46 @@ static void output_scale(void *data, struct wl_output *output, int32_t factor) {
|
|||
}
|
||||
}
|
||||
|
||||
struct wl_output_listener output_listener = {
|
||||
.geometry = output_geometry,
|
||||
.mode = output_mode,
|
||||
.done = output_done,
|
||||
.scale = output_scale,
|
||||
struct wl_output_listener _wl_output_listener = {
|
||||
.geometry = handle_wl_output_geometry,
|
||||
.mode = handle_wl_output_mode,
|
||||
.done = handle_wl_output_done,
|
||||
.scale = handle_wl_output_scale,
|
||||
};
|
||||
|
||||
static void handle_xdg_output_logical_size(void *data, struct zxdg_output_v1 *output,
|
||||
int width, int height) {
|
||||
// Who cares
|
||||
}
|
||||
|
||||
static void handle_xdg_output_logical_position(void *data,
|
||||
struct zxdg_output_v1 *output, int x, int y) {
|
||||
// Who cares
|
||||
}
|
||||
|
||||
static void handle_xdg_output_name(void *data, struct zxdg_output_v1 *output,
|
||||
const char *name) {
|
||||
wlr_log(L_DEBUG, "output name is %s", name);
|
||||
struct swaylock_surface *surface = data;
|
||||
surface->xdg_output = output;
|
||||
surface->output_name = strdup(name);
|
||||
}
|
||||
|
||||
static void handle_xdg_output_description(void *data, struct zxdg_output_v1 *output,
|
||||
const char *description) {
|
||||
// Who cares
|
||||
}
|
||||
|
||||
static void handle_xdg_output_done(void *data, struct zxdg_output_v1 *output) {
|
||||
// Who cares
|
||||
}
|
||||
|
||||
struct zxdg_output_v1_listener _xdg_output_listener = {
|
||||
.logical_position = handle_xdg_output_logical_position,
|
||||
.logical_size = handle_xdg_output_logical_size,
|
||||
.done = handle_xdg_output_done,
|
||||
.name = handle_xdg_output_name,
|
||||
.description = handle_xdg_output_description,
|
||||
};
|
||||
|
||||
static void handle_global(void *data, struct wl_registry *registry,
|
||||
|
@ -172,6 +216,9 @@ static void handle_global(void *data, struct wl_registry *registry,
|
|||
} else if (strcmp(interface, zwlr_input_inhibit_manager_v1_interface.name) == 0) {
|
||||
state->input_inhibit_manager = wl_registry_bind(
|
||||
registry, name, &zwlr_input_inhibit_manager_v1_interface, 1);
|
||||
} else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
|
||||
state->zxdg_output_manager = wl_registry_bind(
|
||||
registry, name, &zxdg_output_manager_v1_interface, 2);
|
||||
} else if (strcmp(interface, wl_output_interface.name) == 0) {
|
||||
struct swaylock_surface *surface =
|
||||
calloc(1, sizeof(struct swaylock_surface));
|
||||
|
@ -180,7 +227,7 @@ static void handle_global(void *data, struct wl_registry *registry,
|
|||
&wl_output_interface, 3);
|
||||
surface->output_global_name = name;
|
||||
surface->image = state->background_image;
|
||||
wl_output_add_listener(surface->output, &output_listener, surface);
|
||||
wl_output_add_listener(surface->output, &_wl_output_listener, surface);
|
||||
wl_list_insert(&state->surfaces, &surface->link);
|
||||
|
||||
if (state->run_display) {
|
||||
|
@ -207,6 +254,70 @@ static const struct wl_registry_listener registry_listener = {
|
|||
.global_remove = handle_global_remove,
|
||||
};
|
||||
|
||||
static cairo_surface_t *select_image(struct swaylock_state *state,
|
||||
struct swaylock_surface *surface) {
|
||||
struct swaylock_image *image;
|
||||
cairo_surface_t *default_image = NULL;
|
||||
wl_list_for_each(image, &state->images, link) {
|
||||
if (lenient_strcmp(image->output_name, surface->output_name) == 0) {
|
||||
return image->cairo_surface;
|
||||
} else if (!image->output_name) {
|
||||
default_image = image->cairo_surface;
|
||||
}
|
||||
}
|
||||
return default_image;
|
||||
}
|
||||
|
||||
static void load_image(char *arg, struct swaylock_state *state) {
|
||||
// [<output>:]<path>
|
||||
struct swaylock_image *image = calloc(1, sizeof(struct swaylock_image));
|
||||
char *separator = strchr(arg, ':');
|
||||
if (separator) {
|
||||
*separator = '\0';
|
||||
image->output_name = strdup(arg);
|
||||
image->path = strdup(separator + 1);
|
||||
} else {
|
||||
image->output_name = NULL;
|
||||
image->path = strdup(arg);
|
||||
}
|
||||
|
||||
bool exists = false;
|
||||
struct swaylock_image *iter_image;
|
||||
wl_list_for_each(iter_image, &state->images, link) {
|
||||
if (lenient_strcmp(iter_image->output_name, image->output_name) == 0) {
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists) {
|
||||
if (image->output_name) {
|
||||
wlr_log(L_ERROR, "Multiple images defined for output %s",
|
||||
image->output_name);
|
||||
} else {
|
||||
wlr_log(L_ERROR, "Multiple default images defined");
|
||||
}
|
||||
}
|
||||
|
||||
// Bash doesn't replace the ~ with $HOME if the output name is supplied
|
||||
wordexp_t p;
|
||||
if (wordexp(image->path, &p, 0) == 0) {
|
||||
free(image->path);
|
||||
image->path = strdup(p.we_wordv[0]);
|
||||
wordfree(&p);
|
||||
}
|
||||
|
||||
// Load the actual image
|
||||
image->cairo_surface = load_background_image(image->path);
|
||||
if (!image->cairo_surface) {
|
||||
free(image);
|
||||
return;
|
||||
}
|
||||
wl_list_insert(&state->images, &image->link);
|
||||
state->args.mode = BACKGROUND_MODE_FILL;
|
||||
wlr_log(L_DEBUG, "Loaded image %s for output %s",
|
||||
image->path, image->output_name ? image->output_name : "*");
|
||||
}
|
||||
|
||||
static struct swaylock_state state;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
@ -233,14 +344,14 @@ int main(int argc, char **argv) {
|
|||
" -v, --version Show the version number and quit.\n"
|
||||
" -i, --image [<output>:]<path> Display the given image.\n"
|
||||
" -u, --no-unlock-indicator Disable the unlock indicator.\n"
|
||||
" -f, --daemonize Detach from the controlling terminal.\n"
|
||||
" --socket <socket> Use the specified socket.\n";
|
||||
" -f, --daemonize Detach from the controlling terminal.\n";
|
||||
|
||||
state.args = (struct swaylock_args){
|
||||
.mode = BACKGROUND_MODE_SOLID_COLOR,
|
||||
.color = 0xFFFFFFFF,
|
||||
.show_indicator = true,
|
||||
};
|
||||
wl_list_init(&state.images);
|
||||
|
||||
wlr_log_init(L_DEBUG, NULL);
|
||||
|
||||
|
@ -258,12 +369,7 @@ int main(int argc, char **argv) {
|
|||
break;
|
||||
}
|
||||
case 'i':
|
||||
// TODO: Multiple background images (bleh)
|
||||
state.background_image = load_background_image(optarg);
|
||||
if (!state.background_image) {
|
||||
return 1;
|
||||
}
|
||||
state.args.mode = BACKGROUND_MODE_FILL;
|
||||
load_image(optarg, &state);
|
||||
break;
|
||||
case 's':
|
||||
state.args.mode = parse_background_mode(optarg);
|
||||
|
@ -313,6 +419,7 @@ int main(int argc, char **argv) {
|
|||
if (!state.input_inhibit_manager) {
|
||||
wlr_log(L_ERROR, "Compositor does not support the input inhibitor "
|
||||
"protocol, refusing to run insecurely");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (wl_list_empty(&state.surfaces)) {
|
||||
|
@ -322,11 +429,24 @@ int main(int argc, char **argv) {
|
|||
|
||||
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) {
|
||||
surface->xdg_output = zxdg_output_manager_v1_get_xdg_output(
|
||||
state.zxdg_output_manager, surface->output);
|
||||
zxdg_output_v1_add_listener(
|
||||
surface->xdg_output, &_xdg_output_listener, surface);
|
||||
}
|
||||
wl_display_roundtrip(state.display);
|
||||
} else {
|
||||
wlr_log(L_INFO, "Compositor does not support zxdg output manager, "
|
||||
"images assigned to named outputs will not work");
|
||||
}
|
||||
|
||||
struct swaylock_surface *surface;
|
||||
wl_list_for_each(surface, &state.surfaces, link) {
|
||||
create_layer_surface(surface);
|
||||
}
|
||||
wl_display_roundtrip(state.display);
|
||||
|
||||
state.run_display = true;
|
||||
while (wl_display_dispatch(state.display) != -1 && state.run_display) {
|
||||
|
|
|
@ -23,7 +23,7 @@ void render_frame(struct swaylock_surface *surface) {
|
|||
cairo_t *cairo = surface->current_buffer->cairo;
|
||||
cairo_identity_matrix(cairo);
|
||||
|
||||
if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR) {
|
||||
if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR || !surface->image) {
|
||||
cairo_set_source_u32(cairo, state->args.color);
|
||||
cairo_paint(cairo);
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue