testsplit

This commit is contained in:
DreamMaoMao 2026-02-05 09:44:55 +08:00
parent 21a492e961
commit 63276d1bee
33 changed files with 10562 additions and 10243 deletions

View file

@ -96,7 +96,16 @@ endif
executable('mango',
'src/mango.c',
'src/animation/client.c',
'src/animation/common.c',
'src/animation/layer.c',
'src/animation/tag.c',
'src/client/client.c',
'src/layout/arrange.c',
'src/layout/layout.c',
'src/common/util.c',
'src/config/parse_config.c',
'src/dispatch/bind_define.c',
'src/ext-protocol/wlr_ext_workspace_v1.c',
wayland_sources,
dependencies : [

View file

@ -18,71 +18,71 @@
char *argv0;
static enum {
enum {
NONE = 0,
SET = 1 << 0,
GET = 1 << 1,
WATCH = 1 << 2 | GET,
} mode = NONE;
static int32_t Oflag;
static int32_t Tflag;
static int32_t Lflag;
static int32_t oflag;
static int32_t tflag;
static int32_t lflag;
static int32_t cflag;
static int32_t vflag;
static int32_t mflag;
static int32_t fflag;
static int32_t qflag;
static int32_t dflag;
static int32_t xflag;
static int32_t eflag;
static int32_t kflag;
static int32_t bflag;
static int32_t Aflag;
int32_t Oflag;
int32_t Tflag;
int32_t Lflag;
int32_t oflag;
int32_t tflag;
int32_t lflag;
int32_t cflag;
int32_t vflag;
int32_t mflag;
int32_t fflag;
int32_t qflag;
int32_t dflag;
int32_t xflag;
int32_t eflag;
int32_t kflag;
int32_t bflag;
int32_t Aflag;
static uint32_t occ, seltags, total_clients, urg;
uint32_t occ, seltags, total_clients, urg;
static char *output_name;
static int32_t tagcount;
static char *tagset;
static char *layout_name;
static int32_t layoutcount, layout_idx;
static char *client_tags;
static char *dispatch_cmd;
static char *dispatch_arg1;
static char *dispatch_arg2;
static char *dispatch_arg3;
static char *dispatch_arg4;
static char *dispatch_arg5;
char *output_name;
int32_t tagcount;
char *tagset;
char *layout_name;
int32_t layoutcount, layout_idx;
char *client_tags;
char *dispatch_cmd;
char *dispatch_arg1;
char *dispatch_arg2;
char *dispatch_arg3;
char *dispatch_arg4;
char *dispatch_arg5;
struct output {
char *output_name;
uint32_t name;
};
static DYNARR_DEF(struct output) outputs;
DYNARR_DEF(struct output) outputs;
static struct wl_display *display;
static struct zdwl_ipc_manager_v2 *dwl_ipc_manager;
struct wl_display *display;
struct zdwl_ipc_manager_v2 *dwl_ipc_manager;
// 为每个回调定义专用的空函数
static void noop_geometry(void *data, struct wl_output *wl_output, int32_t x,
void noop_geometry(void *data, struct wl_output *wl_output, int32_t x,
int32_t y, int32_t physical_width,
int32_t physical_height, int32_t subpixel,
const char *make, const char *model,
int32_t transform) {}
static void noop_mode(void *data, struct wl_output *wl_output, uint32_t flags,
void noop_mode(void *data, struct wl_output *wl_output, uint32_t flags,
int32_t width, int32_t height, int32_t refresh) {}
static void noop_done(void *data, struct wl_output *wl_output) {}
void noop_done(void *data, struct wl_output *wl_output) {}
static void noop_scale(void *data, struct wl_output *wl_output,
void noop_scale(void *data, struct wl_output *wl_output,
int32_t factor) {}
static void noop_description(void *data, struct wl_output *wl_output,
void noop_description(void *data, struct wl_output *wl_output,
const char *description) {}
// 将 n 转换为 9 位二进制字符串,结果存入 buf至少长度 10
@ -93,7 +93,7 @@ void bin_str_9bits(char *buf, uint32_t n) {
*buf = '\0'; // 字符串结尾
}
static void dwl_ipc_tags(void *data,
void dwl_ipc_tags(void *data,
struct zdwl_ipc_manager_v2 *dwl_ipc_manager,
uint32_t count) {
tagcount = count;
@ -101,7 +101,7 @@ static void dwl_ipc_tags(void *data,
printf("%d\n", tagcount);
}
static void dwl_ipc_layout(void *data,
void dwl_ipc_layout(void *data,
struct zdwl_ipc_manager_v2 *dwl_ipc_manager,
const char *name) {
if (lflag && mode & SET && strcmp(layout_name, name) == 0)
@ -111,10 +111,10 @@ static void dwl_ipc_layout(void *data,
layoutcount++;
}
static const struct zdwl_ipc_manager_v2_listener dwl_ipc_listener = {
const struct zdwl_ipc_manager_v2_listener dwl_ipc_listener = {
.tags = dwl_ipc_tags, .layout = dwl_ipc_layout};
static void
void
dwl_ipc_output_toggle_visibility(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output) {
if (!vflag)
@ -125,7 +125,7 @@ dwl_ipc_output_toggle_visibility(void *data,
printf("toggle\n");
}
static void dwl_ipc_output_active(void *data,
void dwl_ipc_output_active(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
uint32_t active) {
if (!oflag) {
@ -139,7 +139,7 @@ static void dwl_ipc_output_active(void *data,
printf("selmon %u\n", active ? 1 : 0);
}
static void dwl_ipc_output_tag(void *data,
void dwl_ipc_output_tag(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
uint32_t tag, uint32_t state, uint32_t clients,
uint32_t focused) {
@ -163,11 +163,11 @@ static void dwl_ipc_output_tag(void *data,
printf("tag %u %u %u %u\n", tag + 1, state, clients, focused);
}
static void dwl_ipc_output_layout(void *data,
void dwl_ipc_output_layout(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
uint32_t layout) {}
static void dwl_ipc_output_layout_symbol(
void dwl_ipc_output_layout_symbol(
void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output, const char *layout) {
if (!(lflag && mode & GET))
return;
@ -177,7 +177,7 @@ static void dwl_ipc_output_layout_symbol(
printf("layout %s\n", layout);
}
static void dwl_ipc_output_title(void *data,
void dwl_ipc_output_title(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
const char *title) {
if (!(cflag && mode & GET))
@ -188,7 +188,7 @@ static void dwl_ipc_output_title(void *data,
printf("title %s\n", title);
}
static void dwl_ipc_output_appid(void *data,
void dwl_ipc_output_appid(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
const char *appid) {
if (!(cflag && mode & GET))
@ -199,7 +199,7 @@ static void dwl_ipc_output_appid(void *data,
printf("appid %s\n", appid);
}
static void dwl_ipc_output_x(void *data,
void dwl_ipc_output_x(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
int32_t x) {
if (!xflag)
@ -210,7 +210,7 @@ static void dwl_ipc_output_x(void *data,
printf("x %d\n", x);
}
static void dwl_ipc_output_y(void *data,
void dwl_ipc_output_y(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
int32_t y) {
if (!xflag)
@ -221,7 +221,7 @@ static void dwl_ipc_output_y(void *data,
printf("y %d\n", y);
}
static void dwl_ipc_output_width(void *data,
void dwl_ipc_output_width(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
int32_t width) {
if (!xflag)
@ -232,7 +232,7 @@ static void dwl_ipc_output_width(void *data,
printf("width %d\n", width);
}
static void dwl_ipc_output_height(void *data,
void dwl_ipc_output_height(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
int32_t height) {
if (!xflag)
@ -243,7 +243,7 @@ static void dwl_ipc_output_height(void *data,
printf("height %d\n", height);
}
static void dwl_ipc_output_last_layer(void *data,
void dwl_ipc_output_last_layer(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
const char *last_layer) {
if (!eflag)
@ -254,7 +254,7 @@ static void dwl_ipc_output_last_layer(void *data,
printf("last_layer %s\n", last_layer);
}
static void dwl_ipc_output_kb_layout(void *data,
void dwl_ipc_output_kb_layout(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
const char *kb_layout) {
if (!kflag)
@ -265,7 +265,7 @@ static void dwl_ipc_output_kb_layout(void *data,
printf("kb_layout %s\n", kb_layout);
}
static void
void
dwl_ipc_output_scalefactor(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
const uint32_t scalefactor) {
@ -277,7 +277,7 @@ dwl_ipc_output_scalefactor(void *data,
printf("scale_factor %f\n", scalefactor / 100.0f);
}
static void dwl_ipc_output_keymode(void *data,
void dwl_ipc_output_keymode(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
const char *keymode) {
if (!bflag)
@ -288,7 +288,7 @@ static void dwl_ipc_output_keymode(void *data,
printf("keymode %s\n", keymode);
}
static void dwl_ipc_output_fullscreen(void *data,
void dwl_ipc_output_fullscreen(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
uint32_t is_fullscreen) {
if (!mflag)
@ -299,7 +299,7 @@ static void dwl_ipc_output_fullscreen(void *data,
printf("fullscreen %u\n", is_fullscreen);
}
static void dwl_ipc_output_floating(void *data,
void dwl_ipc_output_floating(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output,
uint32_t is_floating) {
if (!fflag)
@ -310,7 +310,7 @@ static void dwl_ipc_output_floating(void *data,
printf("floating %u\n", is_floating);
}
static void dwl_ipc_output_frame(void *data,
void dwl_ipc_output_frame(void *data,
struct zdwl_ipc_output_v2 *dwl_ipc_output) {
if (mode & SET) {
if (data && (!output_name || strcmp(output_name, (char *)data)))
@ -409,7 +409,7 @@ static void dwl_ipc_output_frame(void *data,
fflush(stdout);
}
static const struct zdwl_ipc_output_v2_listener dwl_ipc_output_listener = {
const struct zdwl_ipc_output_v2_listener dwl_ipc_output_listener = {
.toggle_visibility = dwl_ipc_output_toggle_visibility,
.active = dwl_ipc_output_active,
.tag = dwl_ipc_output_tag,
@ -430,7 +430,7 @@ static const struct zdwl_ipc_output_v2_listener dwl_ipc_output_listener = {
.frame = dwl_ipc_output_frame,
};
static void wl_output_name(void *data, struct wl_output *output,
void wl_output_name(void *data, struct wl_output *output,
const char *name) {
if (outputs.arr) {
struct output *o = (struct output *)data;
@ -449,7 +449,7 @@ static void wl_output_name(void *data, struct wl_output *output,
output_name ? NULL : strdup(name));
}
static const struct wl_output_listener output_listener = {
const struct wl_output_listener output_listener = {
.geometry = noop_geometry,
.mode = noop_mode,
.done = noop_done,
@ -458,7 +458,7 @@ static const struct wl_output_listener output_listener = {
.description = noop_description,
};
static void global_add(void *data, struct wl_registry *wl_registry,
void global_add(void *data, struct wl_registry *wl_registry,
uint32_t name, const char *interface, uint32_t version) {
if (strcmp(interface, wl_output_interface.name) == 0) {
struct wl_output *o =
@ -479,7 +479,7 @@ static void global_add(void *data, struct wl_registry *wl_registry,
}
}
static void global_remove(void *data, struct wl_registry *wl_registry,
void global_remove(void *data, struct wl_registry *wl_registry,
uint32_t name) {
if (!outputs.arr)
return;
@ -493,12 +493,12 @@ static void global_remove(void *data, struct wl_registry *wl_registry,
}
}
static const struct wl_registry_listener registry_listener = {
const struct wl_registry_listener registry_listener = {
.global = global_add,
.global_remove = global_remove,
};
static void usage(void) {
void usage(void) {
fprintf(stderr,
"usage:"
"\t%s [-OTLq]\n"

1206
src/animation/client.c Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

270
src/animation/common.c Normal file
View file

@ -0,0 +1,270 @@
#include "../type.h"
extern Server server;
struct dvec2 calculate_animation_curve_at(double t, int32_t type) {
struct dvec2 point;
double *animation_curve;
if (type == MOVE) {
animation_curve = animation_curve_move;
} else if (type == OPEN) {
animation_curve = animation_curve_open;
} else if (type == TAG) {
animation_curve = animation_curve_tag;
} else if (type == CLOSE) {
animation_curve = animation_curve_close;
} else if (type == FOCUS) {
animation_curve = animation_curve_focus;
} else if (type == OPAFADEIN) {
animation_curve = animation_curve_opafadein;
} else if (type == OPAFADEOUT) {
animation_curve = animation_curve_opafadeout;
} else {
animation_curve = animation_curve_move;
}
point.x = 3 * t * (1 - t) * (1 - t) * animation_curve[0] +
3 * t * t * (1 - t) * animation_curve[2] + t * t * t;
point.y = 3 * t * (1 - t) * (1 - t) * animation_curve[1] +
3 * t * t * (1 - t) * animation_curve[3] + t * t * t;
return point;
}
void init_baked_points(void) {
server.baked_points_move =
calloc(BAKED_POINTS_COUNT, sizeof(*server.baked_points_move));
server.baked_points_open =
calloc(BAKED_POINTS_COUNT, sizeof(*server.baked_points_open));
server.baked_points_tag =
calloc(BAKED_POINTS_COUNT, sizeof(*server.baked_points_tag));
server.baked_points_close =
calloc(BAKED_POINTS_COUNT, sizeof(*server.baked_points_close));
server.baked_points_focus =
calloc(BAKED_POINTS_COUNT, sizeof(*server.baked_points_focus));
server.baked_points_opafadein =
calloc(BAKED_POINTS_COUNT, sizeof(*server.baked_points_opafadein));
server.baked_points_opafadeout =
calloc(BAKED_POINTS_COUNT, sizeof(*server.baked_points_opafadeout));
for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) {
server.baked_points_move[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), MOVE);
}
for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) {
server.baked_points_open[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), OPEN);
}
for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) {
server.baked_points_tag[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), TAG);
}
for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) {
server.baked_points_close[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), CLOSE);
}
for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) {
server.baked_points_focus[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), FOCUS);
}
for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) {
server.baked_points_opafadein[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), OPAFADEIN);
}
for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) {
server.baked_points_opafadeout[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), OPAFADEOUT);
}
}
double find_animation_curve_at(double t, int32_t type) {
int32_t down = 0;
int32_t up = BAKED_POINTS_COUNT - 1;
int32_t middle = (up + down) / 2;
struct dvec2 *baked_points;
if (type == MOVE) {
baked_points = server.baked_points_move;
} else if (type == OPEN) {
baked_points = server.baked_points_open;
} else if (type == TAG) {
baked_points = server.baked_points_tag;
} else if (type == CLOSE) {
baked_points = server.baked_points_close;
} else if (type == FOCUS) {
baked_points = server.baked_points_focus;
} else if (type == OPAFADEIN) {
baked_points = server.baked_points_opafadein;
} else if (type == OPAFADEOUT) {
baked_points = server.baked_points_opafadeout;
} else {
baked_points = server.baked_points_move;
}
while (up - down != 1) {
if (baked_points[middle].x <= t) {
down = middle;
} else {
up = middle;
}
middle = (up + down) / 2;
}
return baked_points[up].y;
}
bool scene_node_snapshot(struct wlr_scene_node *node, int32_t lx,
int32_t ly,
struct wlr_scene_tree *snapshot_tree) {
if (!node->enabled && node->type != WLR_SCENE_NODE_TREE) {
return true;
}
lx += node->x;
ly += node->y;
struct wlr_scene_node *snapshot_node = NULL;
switch (node->type) {
case WLR_SCENE_NODE_TREE: {
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
struct wlr_scene_node *child;
wl_list_for_each(child, &scene_tree->children, link) {
scene_node_snapshot(child, lx, ly, snapshot_tree);
}
break;
}
case WLR_SCENE_NODE_RECT: {
// struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node);
// struct wlr_scene_rect *snapshot_rect =
// wlr_scene_rect_create(snapshot_tree, scene_rect->width,
// scene_rect->height, scene_rect->color);
// snapshot_rect->node.data = scene_rect->node.data;
// if (snapshot_rect == NULL) {
// return false;
// }
// wlr_scene_rect_set_clipped_region(scene_rect,
// snapshot_rect->clipped_region);
// wlr_scene_rect_set_backdrop_blur(scene_rect, false);
// wlr_scene_rect_set_backdrop_blur_optimized(
// scene_rect, snapshot_rect->backdrop_blur_optimized);
// wlr_scene_rect_set_corner_radius(
// scene_rect, snapshot_rect->corner_radius, snapshot_rect->corners);
// wlr_scene_rect_set_color(scene_rect, snapshot_rect->color);
// snapshot_node = &snapshot_rect->node;
break;
}
case WLR_SCENE_NODE_BUFFER: {
struct wlr_scene_buffer *scene_buffer =
wlr_scene_buffer_from_node(node);
struct wlr_scene_buffer *snapshot_buffer =
wlr_scene_buffer_create(snapshot_tree, NULL);
if (snapshot_buffer == NULL) {
return false;
}
snapshot_node = &snapshot_buffer->node;
snapshot_buffer->node.data = scene_buffer->node.data;
wlr_scene_buffer_set_dest_size(snapshot_buffer, scene_buffer->dst_width,
scene_buffer->dst_height);
wlr_scene_buffer_set_opaque_region(snapshot_buffer,
&scene_buffer->opaque_region);
wlr_scene_buffer_set_source_box(snapshot_buffer,
&scene_buffer->src_box);
wlr_scene_buffer_set_transform(snapshot_buffer,
scene_buffer->transform);
wlr_scene_buffer_set_filter_mode(snapshot_buffer,
scene_buffer->filter_mode);
// Effects
wlr_scene_buffer_set_opacity(snapshot_buffer, scene_buffer->opacity);
wlr_scene_buffer_set_corner_radius(snapshot_buffer,
scene_buffer->corner_radius,
scene_buffer->corners);
// wlr_scene_buffer_set_backdrop_blur_optimized(
// snapshot_buffer, scene_buffer->backdrop_blur_optimized);
// wlr_scene_buffer_set_backdrop_blur_ignore_transparent(
// snapshot_buffer, scene_buffer->backdrop_blur_ignore_transparent);
wlr_scene_buffer_set_backdrop_blur(snapshot_buffer, false);
snapshot_buffer->node.data = scene_buffer->node.data;
struct wlr_scene_surface *scene_surface =
wlr_scene_surface_try_from_buffer(scene_buffer);
if (scene_surface != NULL && scene_surface->surface->buffer != NULL) {
wlr_scene_buffer_set_buffer(snapshot_buffer,
&scene_surface->surface->buffer->base);
} else {
wlr_scene_buffer_set_buffer(snapshot_buffer, scene_buffer->buffer);
}
break;
}
case WLR_SCENE_NODE_SHADOW: {
struct wlr_scene_shadow *scene_shadow =
wlr_scene_shadow_from_node(node);
struct wlr_scene_shadow *snapshot_shadow = wlr_scene_shadow_create(
snapshot_tree, scene_shadow->width, scene_shadow->height,
scene_shadow->corner_radius, scene_shadow->blur_sigma,
scene_shadow->color);
if (snapshot_shadow == NULL) {
return false;
}
snapshot_node = &snapshot_shadow->node;
wlr_scene_shadow_set_clipped_region(snapshot_shadow,
scene_shadow->clipped_region);
snapshot_shadow->node.data = scene_shadow->node.data;
wlr_scene_node_set_enabled(&snapshot_shadow->node, false);
break;
}
case WLR_SCENE_NODE_OPTIMIZED_BLUR:
return true;
}
if (snapshot_node != NULL) {
wlr_scene_node_set_position(snapshot_node, lx, ly);
}
return true;
}
struct wlr_scene_tree *wlr_scene_tree_snapshot(struct wlr_scene_node *node,
struct wlr_scene_tree *parent) {
struct wlr_scene_tree *snapshot = wlr_scene_tree_create(parent);
if (snapshot == NULL) {
return NULL;
}
// Disable and enable the snapshot tree like so to atomically update
// the server.scene -graph. This will prevent over-damaging or other
// weirdness.
wlr_scene_node_set_enabled(&snapshot->node, false);
if (!scene_node_snapshot(node, 0, 0, snapshot)) {
wlr_scene_node_destroy(&snapshot->node);
return NULL;
}
wlr_scene_node_set_enabled(&snapshot->node, true);
return snapshot;
}
void request_fresh_all_monitors(void) {
Monitor *m = NULL;
wl_list_for_each(m, &server.mons, link) {
if (!m->wlr_output->enabled) {
continue;
}
wlr_output_schedule_frame(m->wlr_output);
}
}

View file

@ -1,266 +1,16 @@
struct dvec2 calculate_animation_curve_at(double t, int32_t type) {
struct dvec2 point;
double *animation_curve;
if (type == MOVE) {
animation_curve = animation_curve_move;
} else if (type == OPEN) {
animation_curve = animation_curve_open;
} else if (type == TAG) {
animation_curve = animation_curve_tag;
} else if (type == CLOSE) {
animation_curve = animation_curve_close;
} else if (type == FOCUS) {
animation_curve = animation_curve_focus;
} else if (type == OPAFADEIN) {
animation_curve = animation_curve_opafadein;
} else if (type == OPAFADEOUT) {
animation_curve = animation_curve_opafadeout;
} else {
animation_curve = animation_curve_move;
}
#ifndef MANGO_ANIMATION_COMMON_H
#define MANGO_ANIMATION_COMMON_H
point.x = 3 * t * (1 - t) * (1 - t) * animation_curve[0] +
3 * t * t * (1 - t) * animation_curve[2] + t * t * t;
// 动画曲线相关函数
struct dvec2 calculate_animation_curve_at(double t, int32_t type);
void init_baked_points(void);
double find_animation_curve_at(double t, int32_t type);
point.y = 3 * t * (1 - t) * (1 - t) * animation_curve[1] +
3 * t * t * (1 - t) * animation_curve[3] + t * t * t;
// 场景快照函数
bool scene_node_snapshot(struct wlr_scene_node *node, int32_t lx, int32_t ly, struct wlr_scene_tree *snapshot_tree);
struct wlr_scene_tree *wlr_scene_tree_snapshot(struct wlr_scene_node *node, struct wlr_scene_tree *parent);
return point;
}
// 屏幕刷新函数
void request_fresh_all_monitors(void);
void init_baked_points(void) {
server.baked_points_move =
calloc(BAKED_POINTS_COUNT, sizeof(*server.baked_points_move));
server.baked_points_open =
calloc(BAKED_POINTS_COUNT, sizeof(*server.baked_points_open));
server.baked_points_tag =
calloc(BAKED_POINTS_COUNT, sizeof(*server.baked_points_tag));
server.baked_points_close =
calloc(BAKED_POINTS_COUNT, sizeof(*server.baked_points_close));
server.baked_points_focus =
calloc(BAKED_POINTS_COUNT, sizeof(*server.baked_points_focus));
server.baked_points_opafadein =
calloc(BAKED_POINTS_COUNT, sizeof(*server.baked_points_opafadein));
server.baked_points_opafadeout =
calloc(BAKED_POINTS_COUNT, sizeof(*server.baked_points_opafadeout));
for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) {
server.baked_points_move[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), MOVE);
}
for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) {
server.baked_points_open[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), OPEN);
}
for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) {
server.baked_points_tag[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), TAG);
}
for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) {
server.baked_points_close[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), CLOSE);
}
for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) {
server.baked_points_focus[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), FOCUS);
}
for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) {
server.baked_points_opafadein[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), OPAFADEIN);
}
for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) {
server.baked_points_opafadeout[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), OPAFADEOUT);
}
}
double find_animation_curve_at(double t, int32_t type) {
int32_t down = 0;
int32_t up = BAKED_POINTS_COUNT - 1;
int32_t middle = (up + down) / 2;
struct dvec2 *baked_points;
if (type == MOVE) {
baked_points = server.baked_points_move;
} else if (type == OPEN) {
baked_points = server.baked_points_open;
} else if (type == TAG) {
baked_points = server.baked_points_tag;
} else if (type == CLOSE) {
baked_points = server.baked_points_close;
} else if (type == FOCUS) {
baked_points = server.baked_points_focus;
} else if (type == OPAFADEIN) {
baked_points = server.baked_points_opafadein;
} else if (type == OPAFADEOUT) {
baked_points = server.baked_points_opafadeout;
} else {
baked_points = server.baked_points_move;
}
while (up - down != 1) {
if (baked_points[middle].x <= t) {
down = middle;
} else {
up = middle;
}
middle = (up + down) / 2;
}
return baked_points[up].y;
}
static bool scene_node_snapshot(struct wlr_scene_node *node, int32_t lx,
int32_t ly,
struct wlr_scene_tree *snapshot_tree) {
if (!node->enabled && node->type != WLR_SCENE_NODE_TREE) {
return true;
}
lx += node->x;
ly += node->y;
struct wlr_scene_node *snapshot_node = NULL;
switch (node->type) {
case WLR_SCENE_NODE_TREE: {
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
struct wlr_scene_node *child;
wl_list_for_each(child, &scene_tree->children, link) {
scene_node_snapshot(child, lx, ly, snapshot_tree);
}
break;
}
case WLR_SCENE_NODE_RECT: {
// struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node);
// struct wlr_scene_rect *snapshot_rect =
// wlr_scene_rect_create(snapshot_tree, scene_rect->width,
// scene_rect->height, scene_rect->color);
// snapshot_rect->node.data = scene_rect->node.data;
// if (snapshot_rect == NULL) {
// return false;
// }
// wlr_scene_rect_set_clipped_region(scene_rect,
// snapshot_rect->clipped_region);
// wlr_scene_rect_set_backdrop_blur(scene_rect, false);
// wlr_scene_rect_set_backdrop_blur_optimized(
// scene_rect, snapshot_rect->backdrop_blur_optimized);
// wlr_scene_rect_set_corner_radius(
// scene_rect, snapshot_rect->corner_radius, snapshot_rect->corners);
// wlr_scene_rect_set_color(scene_rect, snapshot_rect->color);
// snapshot_node = &snapshot_rect->node;
break;
}
case WLR_SCENE_NODE_BUFFER: {
struct wlr_scene_buffer *scene_buffer =
wlr_scene_buffer_from_node(node);
struct wlr_scene_buffer *snapshot_buffer =
wlr_scene_buffer_create(snapshot_tree, NULL);
if (snapshot_buffer == NULL) {
return false;
}
snapshot_node = &snapshot_buffer->node;
snapshot_buffer->node.data = scene_buffer->node.data;
wlr_scene_buffer_set_dest_size(snapshot_buffer, scene_buffer->dst_width,
scene_buffer->dst_height);
wlr_scene_buffer_set_opaque_region(snapshot_buffer,
&scene_buffer->opaque_region);
wlr_scene_buffer_set_source_box(snapshot_buffer,
&scene_buffer->src_box);
wlr_scene_buffer_set_transform(snapshot_buffer,
scene_buffer->transform);
wlr_scene_buffer_set_filter_mode(snapshot_buffer,
scene_buffer->filter_mode);
// Effects
wlr_scene_buffer_set_opacity(snapshot_buffer, scene_buffer->opacity);
wlr_scene_buffer_set_corner_radius(snapshot_buffer,
scene_buffer->corner_radius,
scene_buffer->corners);
// wlr_scene_buffer_set_backdrop_blur_optimized(
// snapshot_buffer, scene_buffer->backdrop_blur_optimized);
// wlr_scene_buffer_set_backdrop_blur_ignore_transparent(
// snapshot_buffer, scene_buffer->backdrop_blur_ignore_transparent);
wlr_scene_buffer_set_backdrop_blur(snapshot_buffer, false);
snapshot_buffer->node.data = scene_buffer->node.data;
struct wlr_scene_surface *scene_surface =
wlr_scene_surface_try_from_buffer(scene_buffer);
if (scene_surface != NULL && scene_surface->surface->buffer != NULL) {
wlr_scene_buffer_set_buffer(snapshot_buffer,
&scene_surface->surface->buffer->base);
} else {
wlr_scene_buffer_set_buffer(snapshot_buffer, scene_buffer->buffer);
}
break;
}
case WLR_SCENE_NODE_SHADOW: {
struct wlr_scene_shadow *scene_shadow =
wlr_scene_shadow_from_node(node);
struct wlr_scene_shadow *snapshot_shadow = wlr_scene_shadow_create(
snapshot_tree, scene_shadow->width, scene_shadow->height,
scene_shadow->corner_radius, scene_shadow->blur_sigma,
scene_shadow->color);
if (snapshot_shadow == NULL) {
return false;
}
snapshot_node = &snapshot_shadow->node;
wlr_scene_shadow_set_clipped_region(snapshot_shadow,
scene_shadow->clipped_region);
snapshot_shadow->node.data = scene_shadow->node.data;
wlr_scene_node_set_enabled(&snapshot_shadow->node, false);
break;
}
case WLR_SCENE_NODE_OPTIMIZED_BLUR:
return true;
}
if (snapshot_node != NULL) {
wlr_scene_node_set_position(snapshot_node, lx, ly);
}
return true;
}
struct wlr_scene_tree *wlr_scene_tree_snapshot(struct wlr_scene_node *node,
struct wlr_scene_tree *parent) {
struct wlr_scene_tree *snapshot = wlr_scene_tree_create(parent);
if (snapshot == NULL) {
return NULL;
}
// Disable and enable the snapshot tree like so to atomically update
// the server.scene -graph. This will prevent over-damaging or other
// weirdness.
wlr_scene_node_set_enabled(&snapshot->node, false);
if (!scene_node_snapshot(node, 0, 0, snapshot)) {
wlr_scene_node_destroy(&snapshot->node);
return NULL;
}
wlr_scene_node_set_enabled(&snapshot->node, true);
return snapshot;
}
void request_fresh_all_monitors(void) {
Monitor *m = NULL;
wl_list_for_each(m, &server.mons, link) {
if (!m->wlr_output->enabled) {
continue;
}
wlr_output_schedule_frame(m->wlr_output);
}
}
#endif // MANGO_ANIMATION_COMMON_H

590
src/animation/layer.c Normal file
View file

@ -0,0 +1,590 @@
#include "../type.h"
extern Server server;
void layer_actual_size(LayerSurface *l, int32_t *width, int32_t *height) {
struct wlr_box box;
if (l->animation.running) {
*width = l->animation.current.width;
*height = l->animation.current.height;
} else {
get_layer_target_geometry(l, &box);
*width = box.width;
*height = box.height;
}
}
void get_layer_area_bound(LayerSurface *l, struct wlr_box *bound) {
const struct wlr_layer_surface_v1_state *state = &l->layer_surface->current;
if (state->exclusive_zone > 0 || state->exclusive_zone == -1)
*bound = l->mon->m;
else
*bound = l->mon->w;
}
void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box) {
if (!l || !l->mapped)
return;
const struct wlr_layer_surface_v1_state *state = &l->layer_surface->current;
// 限制区域
// waybar一般都是大于0,表示要占用多少区域,所以计算位置也要用全部区域作为基准
// 如果是-1可能表示独占所有可用空间
// 如果是0应该是表示使用exclusive_zone外的可用区域
struct wlr_box bounds;
if (state->exclusive_zone > 0 || state->exclusive_zone == -1)
bounds = l->mon->m;
else
bounds = l->mon->w;
// 初始化几何位置
struct wlr_box box = {.width = state->desired_width,
.height = state->desired_height};
// 水平方向定位
const int32_t both_horiz =
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
if (box.width == 0) {
box.x = bounds.x;
} else if ((state->anchor & both_horiz) == both_horiz) {
box.x = bounds.x + ((bounds.width - box.width) / 2);
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) {
box.x = bounds.x;
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
box.x = bounds.x + (bounds.width - box.width);
} else {
box.x = bounds.x + ((bounds.width - box.width) / 2);
}
// 垂直方向定位
const int32_t both_vert =
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
if (box.height == 0) {
box.y = bounds.y;
} else if ((state->anchor & both_vert) == both_vert) {
box.y = bounds.y + ((bounds.height - box.height) / 2);
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
box.y = bounds.y;
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) {
box.y = bounds.y + (bounds.height - box.height);
} else {
box.y = bounds.y + ((bounds.height - box.height) / 2);
}
// 应用边距
if (box.width == 0) {
box.x += state->margin.left;
box.width = bounds.width - (state->margin.left + state->margin.right);
} else {
if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) {
box.x += state->margin.left;
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
box.x -= state->margin.right;
}
}
if (box.height == 0) {
box.y += state->margin.top;
box.height = bounds.height - (state->margin.top + state->margin.bottom);
} else {
if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
box.y += state->margin.top;
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) {
box.y -= state->margin.bottom;
}
}
target_box->x = box.x;
target_box->y = box.y;
target_box->width = box.width;
target_box->height = box.height;
}
void set_layer_dir_animaiton(LayerSurface *l, struct wlr_box *geo) {
int32_t slide_direction;
int32_t horizontal, horizontal_value;
int32_t vertical, vertical_value;
int32_t center_x, center_y;
if (!l)
return;
struct wlr_box usable_area;
get_layer_area_bound(l, &usable_area);
geo->width = l->geom.width;
geo->height = l->geom.height;
center_x = l->geom.x + l->geom.width / 2;
center_y = l->geom.y + l->geom.height / 2;
horizontal =
center_x > usable_area.x + usable_area.width / 2 ? RIGHT : LEFT;
horizontal_value = horizontal == LEFT
? center_x - usable_area.x
: usable_area.x + usable_area.width - center_x;
vertical = center_y > usable_area.y + usable_area.height / 2 ? DOWN : UP;
vertical_value = vertical == UP
? center_y - l->mon->w.y
: usable_area.y + usable_area.height - center_y;
slide_direction = horizontal_value < vertical_value ? horizontal : vertical;
switch (slide_direction) {
case UP:
geo->x = l->geom.x;
geo->y = usable_area.y - l->geom.height;
break;
case DOWN:
geo->x = l->geom.x;
geo->y = usable_area.y + usable_area.height;
break;
case LEFT:
geo->x = usable_area.x - l->geom.width;
geo->y = l->geom.y;
break;
case RIGHT:
geo->x = usable_area.x + usable_area.width;
geo->y = l->geom.y;
break;
default:
geo->x = l->geom.x;
geo->y = 0 - l->geom.height;
}
}
void layer_draw_shadow(LayerSurface *l) {
if (!l->mapped || !l->shadow)
return;
if (!shadows || !layer_shadows || l->noshadow) {
wlr_scene_shadow_set_size(l->shadow, 0, 0);
return;
}
int32_t width, height;
layer_actual_size(l, &width, &height);
int32_t delta = shadows_size;
/* we calculate where to clip the shadow */
struct wlr_box layer_box = {
.x = 0,
.y = 0,
.width = width,
.height = height,
};
struct wlr_box shadow_box = {
.x = shadows_position_x,
.y = shadows_position_y,
.width = width + 2 * delta,
.height = height + 2 * delta,
};
struct wlr_box intersection_box;
wlr_box_intersection(&intersection_box, &layer_box, &shadow_box);
/* clipped region takes shadow relative coords, so we translate everything
* by its position */
intersection_box.x -= shadows_position_x;
intersection_box.y -= shadows_position_y;
struct clipped_region clipped_region = {
.area = intersection_box,
.corner_radius = border_radius,
.corners = border_radius_location_default,
};
wlr_scene_node_set_position(&l->shadow->node, shadow_box.x, shadow_box.y);
wlr_scene_shadow_set_size(l->shadow, shadow_box.width, shadow_box.height);
wlr_scene_shadow_set_clipped_region(l->shadow, clipped_region);
}
void layer_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer,
int32_t sx, int32_t sy, void *data) {
BufferData *buffer_data = (BufferData *)data;
struct wlr_scene_surface *scene_surface =
wlr_scene_surface_try_from_buffer(buffer);
if (scene_surface == NULL)
return;
struct wlr_surface *surface = scene_surface->surface;
int32_t surface_width = surface->current.width * buffer_data->width_scale;
int32_t surface_height =
surface->current.height * buffer_data->height_scale;
if (surface_height > 0 && surface_width > 0) {
wlr_scene_buffer_set_dest_size(buffer, surface_width, surface_height);
}
}
void layer_fadeout_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer,
int32_t sx, int32_t sy,
void *data) {
BufferData *buffer_data = (BufferData *)data;
wlr_scene_buffer_set_dest_size(buffer, buffer_data->width,
buffer_data->height);
}
void fadeout_layer_animation_next_tick(LayerSurface *l) {
if (!l)
return;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
int32_t passed_time = timespec_to_ms(&now) - l->animation.time_started;
double animation_passed =
l->animation.duration
? (double)passed_time / (double)l->animation.duration
: 1.0;
int32_t type = l->animation.action = l->animation.action;
double factor = find_animation_curve_at(animation_passed, type);
int32_t width = l->animation.initial.width +
(l->current.width - l->animation.initial.width) * factor;
int32_t height = l->animation.initial.height +
(l->current.height - l->animation.initial.height) * factor;
int32_t x = l->animation.initial.x +
(l->current.x - l->animation.initial.x) * factor;
int32_t y = l->animation.initial.y +
(l->current.y - l->animation.initial.y) * factor;
wlr_scene_node_set_position(&l->scene->node, x, y);
BufferData buffer_data;
buffer_data.width = width;
buffer_data.height = height;
if ((!l->animation_type_close &&
strcmp(layer_animation_type_close, "zoom") == 0) ||
(l->animation_type_close &&
strcmp(l->animation_type_close, "zoom") == 0)) {
wlr_scene_node_for_each_buffer(&l->scene->node,
layer_fadeout_scene_buffer_apply_effect,
&buffer_data);
}
l->animation.current = (struct wlr_box){
.x = x,
.y = y,
.width = width,
.height = height,
};
double opacity_eased_progress =
find_animation_curve_at(animation_passed, OPAFADEOUT);
double percent = fadeout_begin_opacity -
(opacity_eased_progress * fadeout_begin_opacity);
double opacity = MAX(percent, 0.0f);
if (animation_fade_out)
wlr_scene_node_for_each_buffer(&l->scene->node,
scene_buffer_apply_opacity, &opacity);
if (animation_passed >= 1.0) {
wl_list_remove(&l->fadeout_link);
wlr_scene_node_destroy(&l->scene->node);
free(l);
l = NULL;
}
}
void layer_animation_next_tick(LayerSurface *l) {
if (!l || !l->mapped)
return;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
int32_t passed_time = timespec_to_ms(&now) - l->animation.time_started;
double animation_passed =
l->animation.duration
? (double)passed_time / (double)l->animation.duration
: 1.0;
int32_t type = l->animation.action == NONE ? MOVE : l->animation.action;
double factor = find_animation_curve_at(animation_passed, type);
int32_t width = l->animation.initial.width +
(l->current.width - l->animation.initial.width) * factor;
int32_t height = l->animation.initial.height +
(l->current.height - l->animation.initial.height) * factor;
int32_t x = l->animation.initial.x +
(l->current.x - l->animation.initial.x) * factor;
int32_t y = l->animation.initial.y +
(l->current.y - l->animation.initial.y) * factor;
double opacity_eased_progress =
find_animation_curve_at(animation_passed, OPAFADEIN);
double opacity =
MIN(fadein_begin_opacity +
opacity_eased_progress * (1.0 - fadein_begin_opacity),
1.0f);
if (animation_fade_in)
wlr_scene_node_for_each_buffer(&l->scene->node,
scene_buffer_apply_opacity, &opacity);
wlr_scene_node_set_position(&l->scene->node, x, y);
BufferData buffer_data;
if (factor == 1.0) {
buffer_data.width_scale = 1.0f;
buffer_data.height_scale = 1.0f;
} else {
buffer_data.width_scale = (float)width / (float)l->current.width;
buffer_data.height_scale = (float)height / (float)l->current.height;
}
if ((!l->animation_type_open &&
strcmp(layer_animation_type_open, "zoom") == 0) ||
(l->animation_type_open &&
strcmp(l->animation_type_open, "zoom") == 0)) {
wlr_scene_node_for_each_buffer(
&l->scene->node, layer_scene_buffer_apply_effect, &buffer_data);
}
l->animation.current = (struct wlr_box){
.x = x,
.y = y,
.width = width,
.height = height,
};
if (animation_passed >= 1.0) {
l->animation.running = false;
l->need_output_flush = false;
l->animation.action = MOVE;
}
}
void init_fadeout_layers(LayerSurface *l) {
if (!animations || !layer_animations || l->noanim) {
return;
}
if (!l->mon || !l->scene)
return;
if ((l->animation_type_close &&
strcmp(l->animation_type_close, "none") == 0) ||
(!l->animation_type_close &&
strcmp(layer_animation_type_close, "none") == 0)) {
return;
}
if (l->layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM ||
l->layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND)
return;
LayerSurface *fadeout_layer = ecalloc(1, sizeof(*fadeout_layer));
struct wlr_box usable_area;
get_layer_area_bound(l, &usable_area);
wlr_scene_node_set_enabled(&l->scene->node, true);
fadeout_layer->scene =
wlr_scene_tree_snapshot(&l->scene->node, server.layers[LyrFadeOut]);
wlr_scene_node_set_enabled(&l->scene->node, false);
if (!fadeout_layer->scene) {
free(fadeout_layer);
return;
}
fadeout_layer->animation.duration = animation_duration_close;
fadeout_layer->geom = fadeout_layer->current =
fadeout_layer->animainit_geom = fadeout_layer->animation.initial =
l->animation.current;
fadeout_layer->mon = l->mon;
fadeout_layer->animation.action = CLOSE;
fadeout_layer->animation_type_close = l->animation_type_close;
fadeout_layer->animation_type_open = l->animation_type_open;
// 这里snap节点的坐标设置是使用的相对坐标不能用绝对坐标
// 这跟普通node有区别
fadeout_layer->animation.initial.x = 0;
fadeout_layer->animation.initial.y = 0;
if ((!l->animation_type_close &&
strcmp(layer_animation_type_close, "zoom") == 0) ||
(l->animation_type_close &&
strcmp(l->animation_type_close, "zoom") == 0)) {
// 算出要设置的绝对坐标和大小
fadeout_layer->current.width =
(float)l->animation.current.width * zoom_end_ratio;
fadeout_layer->current.height =
(float)l->animation.current.height * zoom_end_ratio;
fadeout_layer->current.x = usable_area.x + usable_area.width / 2 -
fadeout_layer->current.width / 2;
fadeout_layer->current.y = usable_area.y + usable_area.height / 2 -
fadeout_layer->current.height / 2;
// 算出偏差坐标大小不用因为后续不使用他的大小偏差去设置而是直接缩放buffer
fadeout_layer->current.x =
fadeout_layer->current.x - l->animation.current.x;
fadeout_layer->current.y =
fadeout_layer->current.y - l->animation.current.y;
} else if ((!l->animation_type_close &&
strcmp(layer_animation_type_close, "slide") == 0) ||
(l->animation_type_close &&
strcmp(l->animation_type_close, "slide") == 0)) {
// 获取slide动画的结束绝对坐标和大小
set_layer_dir_animaiton(l, &fadeout_layer->current);
// 算出也能够有设置的偏差坐标和大小
fadeout_layer->current.x = fadeout_layer->current.x - l->geom.x;
fadeout_layer->current.y = fadeout_layer->current.y - l->geom.y;
fadeout_layer->current.width =
fadeout_layer->current.width - l->geom.width;
fadeout_layer->current.height =
fadeout_layer->current.height - l->geom.height;
} else {
// fade动画坐标大小不用变
fadeout_layer->current.x = 0;
fadeout_layer->current.y = 0;
fadeout_layer->current.width = 0;
fadeout_layer->current.height = 0;
}
// 动画开始时间
fadeout_layer->animation.time_started = get_now_in_ms();
// 将节点插入到关闭动画链表中,屏幕刷新哪里会检查链表中是否有节点可以应用于动画
wlr_scene_node_set_enabled(&fadeout_layer->scene->node, true);
wl_list_insert(&server.fadeout_layers, &fadeout_layer->fadeout_link);
// 请求刷新屏幕
if (l->mon)
wlr_output_schedule_frame(l->mon->wlr_output);
}
void layer_set_pending_state(LayerSurface *l) {
if (!l || !l->mapped)
return;
struct wlr_box usable_area;
get_layer_area_bound(l, &usable_area);
l->pending = l->geom;
if (l->animation.action == OPEN && !l->animation.running) {
if ((!l->animation_type_open &&
strcmp(layer_animation_type_open, "zoom") == 0) ||
(l->animation_type_open &&
strcmp(l->animation_type_open, "zoom") == 0)) {
l->animainit_geom.width = l->geom.width * zoom_initial_ratio;
l->animainit_geom.height = l->geom.height * zoom_initial_ratio;
l->animainit_geom.x = usable_area.x + usable_area.width / 2 -
l->animainit_geom.width / 2;
l->animainit_geom.y = usable_area.y + usable_area.height / 2 -
l->animainit_geom.height / 2;
} else if ((!l->animation_type_open &&
strcmp(layer_animation_type_open, "slide") == 0) ||
(l->animation_type_open &&
strcmp(l->animation_type_open, "slide") == 0)) {
set_layer_dir_animaiton(l, &l->animainit_geom);
} else {
l->animainit_geom.x = l->geom.x;
l->animainit_geom.y = l->geom.y;
l->animainit_geom.width = l->geom.width;
l->animainit_geom.height = l->geom.height;
}
} else {
l->animainit_geom = l->animation.current;
}
// 判断是否需要动画
if (!animations || !layer_animations || l->noanim ||
l->layer_surface->current.layer ==
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ||
l->layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) {
l->animation.should_animate = false;
} else {
l->animation.should_animate = true;
}
if (((l->animation_type_open &&
strcmp(l->animation_type_open, "none") == 0) ||
(!l->animation_type_open &&
strcmp(layer_animation_type_open, "none") == 0)) &&
l->animation.action == OPEN) {
l->animation.should_animate = false;
}
// 开始动画
layer_commit(l);
l->dirty = true;
}
void layer_commit(LayerSurface *l) {
if (!l || !l->mapped)
return;
l->current = l->pending; // 设置动画的结束位置
if (l->animation.should_animate) {
if (!l->animation.running) {
l->animation.current = l->animainit_geom;
}
l->animation.initial = l->animainit_geom;
l->animation.time_started = get_now_in_ms();
// 标记动画开始
l->animation.running = true;
l->animation.should_animate = false;
}
// 请求刷新屏幕
if (l->mon)
wlr_output_schedule_frame(l->mon->wlr_output);
}
bool layer_draw_frame(LayerSurface *l) {
if (!l || !l->mapped)
return false;
if (!l->need_output_flush)
return false;
if (l->layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_TOP &&
l->layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) {
return false;
}
if (animations && layer_animations && l->animation.running && !l->noanim) {
layer_animation_next_tick(l);
layer_draw_shadow(l);
} else {
layer_draw_shadow(l);
l->need_output_flush = false;
}
return true;
}
bool layer_draw_fadeout_frame(LayerSurface *l) {
if (!l)
return false;
fadeout_layer_animation_next_tick(l);
return true;
}

View file

@ -1,586 +1,26 @@
void layer_actual_size(LayerSurface *l, int32_t *width, int32_t *height) {
struct wlr_box box;
if (l->animation.running) {
*width = l->animation.current.width;
*height = l->animation.current.height;
} else {
get_layer_target_geometry(l, &box);
*width = box.width;
*height = box.height;
}
}
void get_layer_area_bound(LayerSurface *l, struct wlr_box *bound) {
const struct wlr_layer_surface_v1_state *state = &l->layer_surface->current;
if (state->exclusive_zone > 0 || state->exclusive_zone == -1)
*bound = l->mon->m;
else
*bound = l->mon->w;
}
void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box) {
if (!l || !l->mapped)
return;
const struct wlr_layer_surface_v1_state *state = &l->layer_surface->current;
// 限制区域
// waybar一般都是大于0,表示要占用多少区域,所以计算位置也要用全部区域作为基准
// 如果是-1可能表示独占所有可用空间
// 如果是0应该是表示使用exclusive_zone外的可用区域
struct wlr_box bounds;
if (state->exclusive_zone > 0 || state->exclusive_zone == -1)
bounds = l->mon->m;
else
bounds = l->mon->w;
// 初始化几何位置
struct wlr_box box = {.width = state->desired_width,
.height = state->desired_height};
// 水平方向定位
const int32_t both_horiz =
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
if (box.width == 0) {
box.x = bounds.x;
} else if ((state->anchor & both_horiz) == both_horiz) {
box.x = bounds.x + ((bounds.width - box.width) / 2);
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) {
box.x = bounds.x;
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
box.x = bounds.x + (bounds.width - box.width);
} else {
box.x = bounds.x + ((bounds.width - box.width) / 2);
}
// 垂直方向定位
const int32_t both_vert =
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
if (box.height == 0) {
box.y = bounds.y;
} else if ((state->anchor & both_vert) == both_vert) {
box.y = bounds.y + ((bounds.height - box.height) / 2);
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
box.y = bounds.y;
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) {
box.y = bounds.y + (bounds.height - box.height);
} else {
box.y = bounds.y + ((bounds.height - box.height) / 2);
}
// 应用边距
if (box.width == 0) {
box.x += state->margin.left;
box.width = bounds.width - (state->margin.left + state->margin.right);
} else {
if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) {
box.x += state->margin.left;
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
box.x -= state->margin.right;
}
}
if (box.height == 0) {
box.y += state->margin.top;
box.height = bounds.height - (state->margin.top + state->margin.bottom);
} else {
if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
box.y += state->margin.top;
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) {
box.y -= state->margin.bottom;
}
}
target_box->x = box.x;
target_box->y = box.y;
target_box->width = box.width;
target_box->height = box.height;
}
void set_layer_dir_animaiton(LayerSurface *l, struct wlr_box *geo) {
int32_t slide_direction;
int32_t horizontal, horizontal_value;
int32_t vertical, vertical_value;
int32_t center_x, center_y;
if (!l)
return;
struct wlr_box usable_area;
get_layer_area_bound(l, &usable_area);
geo->width = l->geom.width;
geo->height = l->geom.height;
center_x = l->geom.x + l->geom.width / 2;
center_y = l->geom.y + l->geom.height / 2;
horizontal =
center_x > usable_area.x + usable_area.width / 2 ? RIGHT : LEFT;
horizontal_value = horizontal == LEFT
? center_x - usable_area.x
: usable_area.x + usable_area.width - center_x;
vertical = center_y > usable_area.y + usable_area.height / 2 ? DOWN : UP;
vertical_value = vertical == UP
? center_y - l->mon->w.y
: usable_area.y + usable_area.height - center_y;
slide_direction = horizontal_value < vertical_value ? horizontal : vertical;
switch (slide_direction) {
case UP:
geo->x = l->geom.x;
geo->y = usable_area.y - l->geom.height;
break;
case DOWN:
geo->x = l->geom.x;
geo->y = usable_area.y + usable_area.height;
break;
case LEFT:
geo->x = usable_area.x - l->geom.width;
geo->y = l->geom.y;
break;
case RIGHT:
geo->x = usable_area.x + usable_area.width;
geo->y = l->geom.y;
break;
default:
geo->x = l->geom.x;
geo->y = 0 - l->geom.height;
}
}
void layer_draw_shadow(LayerSurface *l) {
if (!l->mapped || !l->shadow)
return;
if (!shadows || !layer_shadows || l->noshadow) {
wlr_scene_shadow_set_size(l->shadow, 0, 0);
return;
}
int32_t width, height;
layer_actual_size(l, &width, &height);
int32_t delta = shadows_size;
/* we calculate where to clip the shadow */
struct wlr_box layer_box = {
.x = 0,
.y = 0,
.width = width,
.height = height,
};
struct wlr_box shadow_box = {
.x = shadows_position_x,
.y = shadows_position_y,
.width = width + 2 * delta,
.height = height + 2 * delta,
};
struct wlr_box intersection_box;
wlr_box_intersection(&intersection_box, &layer_box, &shadow_box);
/* clipped region takes shadow relative coords, so we translate everything
* by its position */
intersection_box.x -= shadows_position_x;
intersection_box.y -= shadows_position_y;
struct clipped_region clipped_region = {
.area = intersection_box,
.corner_radius = border_radius,
.corners = border_radius_location_default,
};
wlr_scene_node_set_position(&l->shadow->node, shadow_box.x, shadow_box.y);
wlr_scene_shadow_set_size(l->shadow, shadow_box.width, shadow_box.height);
wlr_scene_shadow_set_clipped_region(l->shadow, clipped_region);
}
void layer_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer,
int32_t sx, int32_t sy, void *data) {
BufferData *buffer_data = (BufferData *)data;
struct wlr_scene_surface *scene_surface =
wlr_scene_surface_try_from_buffer(buffer);
if (scene_surface == NULL)
return;
struct wlr_surface *surface = scene_surface->surface;
int32_t surface_width = surface->current.width * buffer_data->width_scale;
int32_t surface_height =
surface->current.height * buffer_data->height_scale;
if (surface_height > 0 && surface_width > 0) {
wlr_scene_buffer_set_dest_size(buffer, surface_width, surface_height);
}
}
void layer_fadeout_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer,
int32_t sx, int32_t sy,
void *data) {
BufferData *buffer_data = (BufferData *)data;
wlr_scene_buffer_set_dest_size(buffer, buffer_data->width,
buffer_data->height);
}
void fadeout_layer_animation_next_tick(LayerSurface *l) {
if (!l)
return;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
int32_t passed_time = timespec_to_ms(&now) - l->animation.time_started;
double animation_passed =
l->animation.duration
? (double)passed_time / (double)l->animation.duration
: 1.0;
int32_t type = l->animation.action = l->animation.action;
double factor = find_animation_curve_at(animation_passed, type);
int32_t width = l->animation.initial.width +
(l->current.width - l->animation.initial.width) * factor;
int32_t height = l->animation.initial.height +
(l->current.height - l->animation.initial.height) * factor;
int32_t x = l->animation.initial.x +
(l->current.x - l->animation.initial.x) * factor;
int32_t y = l->animation.initial.y +
(l->current.y - l->animation.initial.y) * factor;
wlr_scene_node_set_position(&l->scene->node, x, y);
BufferData buffer_data;
buffer_data.width = width;
buffer_data.height = height;
if ((!l->animation_type_close &&
strcmp(layer_animation_type_close, "zoom") == 0) ||
(l->animation_type_close &&
strcmp(l->animation_type_close, "zoom") == 0)) {
wlr_scene_node_for_each_buffer(&l->scene->node,
layer_fadeout_scene_buffer_apply_effect,
&buffer_data);
}
l->animation.current = (struct wlr_box){
.x = x,
.y = y,
.width = width,
.height = height,
};
double opacity_eased_progress =
find_animation_curve_at(animation_passed, OPAFADEOUT);
double percent = fadeout_begin_opacity -
(opacity_eased_progress * fadeout_begin_opacity);
double opacity = MAX(percent, 0.0f);
if (animation_fade_out)
wlr_scene_node_for_each_buffer(&l->scene->node,
scene_buffer_apply_opacity, &opacity);
if (animation_passed >= 1.0) {
wl_list_remove(&l->fadeout_link);
wlr_scene_node_destroy(&l->scene->node);
free(l);
l = NULL;
}
}
void layer_animation_next_tick(LayerSurface *l) {
if (!l || !l->mapped)
return;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
int32_t passed_time = timespec_to_ms(&now) - l->animation.time_started;
double animation_passed =
l->animation.duration
? (double)passed_time / (double)l->animation.duration
: 1.0;
int32_t type = l->animation.action == NONE ? MOVE : l->animation.action;
double factor = find_animation_curve_at(animation_passed, type);
int32_t width = l->animation.initial.width +
(l->current.width - l->animation.initial.width) * factor;
int32_t height = l->animation.initial.height +
(l->current.height - l->animation.initial.height) * factor;
int32_t x = l->animation.initial.x +
(l->current.x - l->animation.initial.x) * factor;
int32_t y = l->animation.initial.y +
(l->current.y - l->animation.initial.y) * factor;
double opacity_eased_progress =
find_animation_curve_at(animation_passed, OPAFADEIN);
double opacity =
MIN(fadein_begin_opacity +
opacity_eased_progress * (1.0 - fadein_begin_opacity),
1.0f);
if (animation_fade_in)
wlr_scene_node_for_each_buffer(&l->scene->node,
scene_buffer_apply_opacity, &opacity);
wlr_scene_node_set_position(&l->scene->node, x, y);
BufferData buffer_data;
if (factor == 1.0) {
buffer_data.width_scale = 1.0f;
buffer_data.height_scale = 1.0f;
} else {
buffer_data.width_scale = (float)width / (float)l->current.width;
buffer_data.height_scale = (float)height / (float)l->current.height;
}
if ((!l->animation_type_open &&
strcmp(layer_animation_type_open, "zoom") == 0) ||
(l->animation_type_open &&
strcmp(l->animation_type_open, "zoom") == 0)) {
wlr_scene_node_for_each_buffer(
&l->scene->node, layer_scene_buffer_apply_effect, &buffer_data);
}
l->animation.current = (struct wlr_box){
.x = x,
.y = y,
.width = width,
.height = height,
};
if (animation_passed >= 1.0) {
l->animation.running = false;
l->need_output_flush = false;
l->animation.action = MOVE;
}
}
void init_fadeout_layers(LayerSurface *l) {
if (!animations || !layer_animations || l->noanim) {
return;
}
if (!l->mon || !l->scene)
return;
if ((l->animation_type_close &&
strcmp(l->animation_type_close, "none") == 0) ||
(!l->animation_type_close &&
strcmp(layer_animation_type_close, "none") == 0)) {
return;
}
if (l->layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM ||
l->layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND)
return;
LayerSurface *fadeout_layer = ecalloc(1, sizeof(*fadeout_layer));
struct wlr_box usable_area;
get_layer_area_bound(l, &usable_area);
wlr_scene_node_set_enabled(&l->scene->node, true);
fadeout_layer->scene =
wlr_scene_tree_snapshot(&l->scene->node, server.layers[LyrFadeOut]);
wlr_scene_node_set_enabled(&l->scene->node, false);
if (!fadeout_layer->scene) {
free(fadeout_layer);
return;
}
fadeout_layer->animation.duration = animation_duration_close;
fadeout_layer->geom = fadeout_layer->current =
fadeout_layer->animainit_geom = fadeout_layer->animation.initial =
l->animation.current;
fadeout_layer->mon = l->mon;
fadeout_layer->animation.action = CLOSE;
fadeout_layer->animation_type_close = l->animation_type_close;
fadeout_layer->animation_type_open = l->animation_type_open;
// 这里snap节点的坐标设置是使用的相对坐标不能用绝对坐标
// 这跟普通node有区别
fadeout_layer->animation.initial.x = 0;
fadeout_layer->animation.initial.y = 0;
if ((!l->animation_type_close &&
strcmp(layer_animation_type_close, "zoom") == 0) ||
(l->animation_type_close &&
strcmp(l->animation_type_close, "zoom") == 0)) {
// 算出要设置的绝对坐标和大小
fadeout_layer->current.width =
(float)l->animation.current.width * zoom_end_ratio;
fadeout_layer->current.height =
(float)l->animation.current.height * zoom_end_ratio;
fadeout_layer->current.x = usable_area.x + usable_area.width / 2 -
fadeout_layer->current.width / 2;
fadeout_layer->current.y = usable_area.y + usable_area.height / 2 -
fadeout_layer->current.height / 2;
// 算出偏差坐标大小不用因为后续不使用他的大小偏差去设置而是直接缩放buffer
fadeout_layer->current.x =
fadeout_layer->current.x - l->animation.current.x;
fadeout_layer->current.y =
fadeout_layer->current.y - l->animation.current.y;
} else if ((!l->animation_type_close &&
strcmp(layer_animation_type_close, "slide") == 0) ||
(l->animation_type_close &&
strcmp(l->animation_type_close, "slide") == 0)) {
// 获取slide动画的结束绝对坐标和大小
set_layer_dir_animaiton(l, &fadeout_layer->current);
// 算出也能够有设置的偏差坐标和大小
fadeout_layer->current.x = fadeout_layer->current.x - l->geom.x;
fadeout_layer->current.y = fadeout_layer->current.y - l->geom.y;
fadeout_layer->current.width =
fadeout_layer->current.width - l->geom.width;
fadeout_layer->current.height =
fadeout_layer->current.height - l->geom.height;
} else {
// fade动画坐标大小不用变
fadeout_layer->current.x = 0;
fadeout_layer->current.y = 0;
fadeout_layer->current.width = 0;
fadeout_layer->current.height = 0;
}
// 动画开始时间
fadeout_layer->animation.time_started = get_now_in_ms();
// 将节点插入到关闭动画链表中,屏幕刷新哪里会检查链表中是否有节点可以应用于动画
wlr_scene_node_set_enabled(&fadeout_layer->scene->node, true);
wl_list_insert(&server.fadeout_layers, &fadeout_layer->fadeout_link);
// 请求刷新屏幕
if (l->mon)
wlr_output_schedule_frame(l->mon->wlr_output);
}
void layer_set_pending_state(LayerSurface *l) {
if (!l || !l->mapped)
return;
struct wlr_box usable_area;
get_layer_area_bound(l, &usable_area);
l->pending = l->geom;
if (l->animation.action == OPEN && !l->animation.running) {
if ((!l->animation_type_open &&
strcmp(layer_animation_type_open, "zoom") == 0) ||
(l->animation_type_open &&
strcmp(l->animation_type_open, "zoom") == 0)) {
l->animainit_geom.width = l->geom.width * zoom_initial_ratio;
l->animainit_geom.height = l->geom.height * zoom_initial_ratio;
l->animainit_geom.x = usable_area.x + usable_area.width / 2 -
l->animainit_geom.width / 2;
l->animainit_geom.y = usable_area.y + usable_area.height / 2 -
l->animainit_geom.height / 2;
} else if ((!l->animation_type_open &&
strcmp(layer_animation_type_open, "slide") == 0) ||
(l->animation_type_open &&
strcmp(l->animation_type_open, "slide") == 0)) {
set_layer_dir_animaiton(l, &l->animainit_geom);
} else {
l->animainit_geom.x = l->geom.x;
l->animainit_geom.y = l->geom.y;
l->animainit_geom.width = l->geom.width;
l->animainit_geom.height = l->geom.height;
}
} else {
l->animainit_geom = l->animation.current;
}
// 判断是否需要动画
if (!animations || !layer_animations || l->noanim ||
l->layer_surface->current.layer ==
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ||
l->layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) {
l->animation.should_animate = false;
} else {
l->animation.should_animate = true;
}
if (((l->animation_type_open &&
strcmp(l->animation_type_open, "none") == 0) ||
(!l->animation_type_open &&
strcmp(layer_animation_type_open, "none") == 0)) &&
l->animation.action == OPEN) {
l->animation.should_animate = false;
}
// 开始动画
layer_commit(l);
l->dirty = true;
}
void layer_commit(LayerSurface *l) {
if (!l || !l->mapped)
return;
l->current = l->pending; // 设置动画的结束位置
if (l->animation.should_animate) {
if (!l->animation.running) {
l->animation.current = l->animainit_geom;
}
l->animation.initial = l->animainit_geom;
l->animation.time_started = get_now_in_ms();
// 标记动画开始
l->animation.running = true;
l->animation.should_animate = false;
}
// 请求刷新屏幕
if (l->mon)
wlr_output_schedule_frame(l->mon->wlr_output);
}
bool layer_draw_frame(LayerSurface *l) {
if (!l || !l->mapped)
return false;
if (!l->need_output_flush)
return false;
if (l->layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_TOP &&
l->layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) {
return false;
}
if (animations && layer_animations && l->animation.running && !l->noanim) {
layer_animation_next_tick(l);
layer_draw_shadow(l);
} else {
layer_draw_shadow(l);
l->need_output_flush = false;
}
return true;
}
bool layer_draw_fadeout_frame(LayerSurface *l) {
if (!l)
return false;
fadeout_layer_animation_next_tick(l);
return true;
}
#ifndef MANGO_ANIMATION_LAYER_H
#define MANGO_ANIMATION_LAYER_H
// 图层大小和几何计算函数
void layer_actual_size(LayerSurface *l, int32_t *width, int32_t *height);
void get_layer_area_bound(LayerSurface *l, struct wlr_box *bound);
void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box);
void set_layer_dir_animaiton(LayerSurface *l, struct wlr_box *geo);
// 图层阴影和视觉效果函数
void layer_draw_shadow(LayerSurface *l);
void layer_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int32_t sx, int32_t sy, void *data);
void layer_fadeout_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int32_t sx, int32_t sy, void *data);
// 图层动画相关函数
void fadeout_layer_animation_next_tick(LayerSurface *l);
void layer_animation_next_tick(LayerSurface *l);
void init_fadeout_layers(LayerSurface *l);
void layer_set_pending_state(LayerSurface *l);
void layer_commit(LayerSurface *l);
// 图层绘制函数
bool layer_draw_frame(LayerSurface *l);
bool layer_draw_fadeout_frame(LayerSurface *l);
#endif // MANGO_ANIMATION_LAYER_H

98
src/animation/tag.c Normal file
View file

@ -0,0 +1,98 @@
#include "../type.h"
#include "../client/client.h"
extern Server server;
void set_tagin_animation(Monitor *m, Client *c) {
if (c->animation.running) {
c->animainit_geom.x = c->animation.current.x;
c->animainit_geom.y = c->animation.current.y;
return;
}
if (m->pertag->curtag > m->pertag->prevtag) {
c->animainit_geom.x = tag_animation_direction == VERTICAL
? c->animation.current.x
: MAX(c->mon->m.x + c->mon->m.width,
c->geom.x + c->mon->m.width);
c->animainit_geom.y = tag_animation_direction == VERTICAL
? MAX(c->mon->m.y + c->mon->m.height,
c->geom.y + c->mon->m.height)
: c->animation.current.y;
} else {
c->animainit_geom.x =
tag_animation_direction == VERTICAL
? c->animation.current.x
: MIN(m->m.x - c->geom.width, c->geom.x - c->mon->m.width);
c->animainit_geom.y =
tag_animation_direction == VERTICAL
? MIN(m->m.y - c->geom.height, c->geom.y - c->mon->m.height)
: c->animation.current.y;
}
}
void set_arrange_visible(Monitor *m, Client *c, bool want_animation) {
if (!c->is_clip_to_hide || !ISTILED(c) || !is_scroller_layout(c->mon)) {
c->is_clip_to_hide = false;
wlr_scene_node_set_enabled(&c->scene->node, true);
wlr_scene_node_set_enabled(&c->scene_surface->node, true);
}
client_set_suspended(c, false);
if (!c->animation.tag_from_rule && want_animation &&
m->pertag->prevtag != 0 && m->pertag->curtag != 0 && animations) {
c->animation.tagining = true;
set_tagin_animation(m, c);
} else {
c->animainit_geom.x = c->animation.current.x;
c->animainit_geom.y = c->animation.current.y;
}
c->animation.tag_from_rule = false;
c->animation.tagouting = false;
c->animation.tagouted = false;
resize(c, c->geom, 0);
}
void set_tagout_animation(Monitor *m, Client *c) {
if (m->pertag->curtag > m->pertag->prevtag) {
c->pending = c->geom;
c->pending.x =
tag_animation_direction == VERTICAL
? c->animation.current.x
: MIN(c->mon->m.x - c->geom.width, c->geom.x - c->mon->m.width);
c->pending.y = tag_animation_direction == VERTICAL
? MIN(c->mon->m.y - c->geom.height,
c->geom.y - c->mon->m.height)
: c->animation.current.y;
resize(c, c->geom, 0);
} else {
c->pending = c->geom;
c->pending.x = tag_animation_direction == VERTICAL
? c->animation.current.x
: MAX(c->mon->m.x + c->mon->m.width,
c->geom.x + c->mon->m.width);
c->pending.y = tag_animation_direction == VERTICAL
? MAX(c->mon->m.y + c->mon->m.height,
c->geom.y + c->mon->m.height)
: c->animation.current.y;
resize(c, c->geom, 0);
}
}
void set_arrange_hidden(Monitor *m, Client *c, bool want_animation) {
if ((c->tags & (1 << (m->pertag->prevtag - 1))) &&
m->pertag->prevtag != 0 && m->pertag->curtag != 0 && animations) {
c->animation.tagouting = true;
c->animation.tagining = false;
set_tagout_animation(m, c);
} else {
wlr_scene_node_set_enabled(&c->scene->node, false);
client_set_suspended(c, true);
}
}

View file

@ -1,93 +1,10 @@
void set_tagin_animation(Monitor *m, Client *c) {
if (c->animation.running) {
c->animainit_geom.x = c->animation.current.x;
c->animainit_geom.y = c->animation.current.y;
return;
}
#ifndef MANGO_ANIMATION_TAG_H
#define MANGO_ANIMATION_TAG_H
if (m->pertag->curtag > m->pertag->prevtag) {
// 标签切换动画函数
void set_tagin_animation(Monitor *m, Client *c);
void set_arrange_visible(Monitor *m, Client *c, bool want_animation);
void set_tagout_animation(Monitor *m, Client *c);
void set_arrange_hidden(Monitor *m, Client *c, bool want_animation);
c->animainit_geom.x = tag_animation_direction == VERTICAL
? c->animation.current.x
: MAX(c->mon->m.x + c->mon->m.width,
c->geom.x + c->mon->m.width);
c->animainit_geom.y = tag_animation_direction == VERTICAL
? MAX(c->mon->m.y + c->mon->m.height,
c->geom.y + c->mon->m.height)
: c->animation.current.y;
} else {
c->animainit_geom.x =
tag_animation_direction == VERTICAL
? c->animation.current.x
: MIN(m->m.x - c->geom.width, c->geom.x - c->mon->m.width);
c->animainit_geom.y =
tag_animation_direction == VERTICAL
? MIN(m->m.y - c->geom.height, c->geom.y - c->mon->m.height)
: c->animation.current.y;
}
}
void set_arrange_visible(Monitor *m, Client *c, bool want_animation) {
if (!c->is_clip_to_hide || !ISTILED(c) || !is_scroller_layout(c->mon)) {
c->is_clip_to_hide = false;
wlr_scene_node_set_enabled(&c->scene->node, true);
wlr_scene_node_set_enabled(&c->scene_surface->node, true);
}
client_set_suspended(c, false);
if (!c->animation.tag_from_rule && want_animation &&
m->pertag->prevtag != 0 && m->pertag->curtag != 0 && animations) {
c->animation.tagining = true;
set_tagin_animation(m, c);
} else {
c->animainit_geom.x = c->animation.current.x;
c->animainit_geom.y = c->animation.current.y;
}
c->animation.tag_from_rule = false;
c->animation.tagouting = false;
c->animation.tagouted = false;
resize(c, c->geom, 0);
}
void set_tagout_animation(Monitor *m, Client *c) {
if (m->pertag->curtag > m->pertag->prevtag) {
c->pending = c->geom;
c->pending.x =
tag_animation_direction == VERTICAL
? c->animation.current.x
: MIN(c->mon->m.x - c->geom.width, c->geom.x - c->mon->m.width);
c->pending.y = tag_animation_direction == VERTICAL
? MIN(c->mon->m.y - c->geom.height,
c->geom.y - c->mon->m.height)
: c->animation.current.y;
resize(c, c->geom, 0);
} else {
c->pending = c->geom;
c->pending.x = tag_animation_direction == VERTICAL
? c->animation.current.x
: MAX(c->mon->m.x + c->mon->m.width,
c->geom.x + c->mon->m.width);
c->pending.y = tag_animation_direction == VERTICAL
? MAX(c->mon->m.y + c->mon->m.height,
c->geom.y + c->mon->m.height)
: c->animation.current.y;
resize(c, c->geom, 0);
}
}
void set_arrange_hidden(Monitor *m, Client *c, bool want_animation) {
if ((c->tags & (1 << (m->pertag->prevtag - 1))) &&
m->pertag->prevtag != 0 && m->pertag->curtag != 0 && animations) {
c->animation.tagouting = true;
c->animation.tagining = false;
set_tagout_animation(m, c);
} else {
wlr_scene_node_set_enabled(&c->scene->node, false);
client_set_suspended(c, true);
}
}
#endif // MANGO_ANIMATION_TAG_H

546
src/client/client.c Normal file
View file

@ -0,0 +1,546 @@
#include "../type.h"
extern Server server;
int32_t client_is_x11(Client *c) {
#ifdef XWAYLAND
return c->type == X11;
#endif
return 0;
}
struct wlr_surface *client_surface(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->surface;
#endif
return c->surface.xdg->surface;
}
int32_t toplevel_from_wlr_surface(struct wlr_surface *s,
Client **pc,
LayerSurface **pl) {
struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface;
struct wlr_surface *root_surface;
struct wlr_layer_surface_v1 *layer_surface;
Client *c = NULL;
LayerSurface *l = NULL;
int32_t type = -1;
#ifdef XWAYLAND
struct wlr_xwayland_surface *xsurface;
#endif
if (!s)
return -1;
root_surface = wlr_surface_get_root_surface(s);
#ifdef XWAYLAND
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) {
c = xsurface->data;
type = c->type;
goto end;
}
#endif
if ((layer_surface =
wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) {
l = layer_surface->data;
type = LayerShell;
goto end;
}
xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface);
while (xdg_surface) {
tmp_xdg_surface = NULL;
switch (xdg_surface->role) {
case WLR_XDG_SURFACE_ROLE_POPUP:
if (!xdg_surface->popup || !xdg_surface->popup->parent)
return -1;
tmp_xdg_surface = wlr_xdg_surface_try_from_wlr_surface(
xdg_surface->popup->parent);
if (!tmp_xdg_surface)
return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc,
pl);
xdg_surface = tmp_xdg_surface;
break;
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
c = xdg_surface->data;
type = c->type;
goto end;
case WLR_XDG_SURFACE_ROLE_NONE:
return -1;
}
}
end:
if (pl)
*pl = l;
if (pc)
*pc = c;
return type;
}
/* The others */
void client_activate_surface(struct wlr_surface *s,
int32_t activated) {
struct wlr_xdg_toplevel *toplevel;
#ifdef XWAYLAND
struct wlr_xwayland_surface *xsurface;
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) {
if (activated && xsurface->minimized)
wlr_xwayland_surface_set_minimized(xsurface, false);
wlr_xwayland_surface_activate(xsurface, activated);
return;
}
#endif
if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s)))
wlr_xdg_toplevel_set_activated(toplevel, activated);
}
const char *client_get_appid(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->class ? c->surface.xwayland->class
: "broken";
#endif
return c->surface.xdg->toplevel->app_id ? c->surface.xdg->toplevel->app_id
: "broken";
}
int32_t client_get_pid(Client *c) {
pid_t pid;
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->pid;
#endif
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
return pid;
}
void client_get_clip(Client *c, struct wlr_box *clip) {
*clip = (struct wlr_box){
.x = 0,
.y = 0,
.width = c->geom.width - 2 * c->bw,
.height = c->geom.height - 2 * c->bw,
};
#ifdef XWAYLAND
if (client_is_x11(c))
return;
#endif
clip->x = c->surface.xdg->geometry.x;
clip->y = c->surface.xdg->geometry.y;
}
void client_get_geometry(Client *c, struct wlr_box *geom) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
geom->x = c->surface.xwayland->x;
geom->y = c->surface.xwayland->y;
geom->width = c->surface.xwayland->width;
geom->height = c->surface.xwayland->height;
return;
}
#endif
*geom = c->surface.xdg->geometry;
}
Client *client_get_parent(Client *c) {
Client *p = NULL;
#ifdef XWAYLAND
if (client_is_x11(c)) {
if (c->surface.xwayland->parent)
toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p,
NULL);
return p;
}
#endif
if (c->surface.xdg->toplevel->parent)
toplevel_from_wlr_surface(
c->surface.xdg->toplevel->parent->base->surface, &p, NULL);
return p;
}
int32_t client_has_children(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c))
return !wl_list_empty(&c->surface.xwayland->children);
#endif
/* surface.xdg->link is never empty because it always contains at least the
* surface itself. */
return wl_list_length(&c->surface.xdg->link) > 1;
}
const char *client_get_title(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->title ? c->surface.xwayland->title
: "broken";
#endif
return c->surface.xdg->toplevel->title ? c->surface.xdg->toplevel->title
: "broken";
}
int32_t client_is_float_type(Client *c) {
struct wlr_xdg_toplevel *toplevel;
struct wlr_xdg_toplevel_state state;
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
xcb_size_hints_t *size_hints = surface->size_hints;
if (!size_hints)
return 0;
if (surface->modal)
return 1;
if (wlr_xwayland_surface_has_window_type(
surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DIALOG) ||
wlr_xwayland_surface_has_window_type(
surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_SPLASH) ||
wlr_xwayland_surface_has_window_type(
surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_TOOLBAR) ||
wlr_xwayland_surface_has_window_type(
surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_UTILITY)) {
return 1;
}
return size_hints && size_hints->min_width > 0 &&
size_hints->min_height > 0 &&
(size_hints->max_width == size_hints->min_width ||
size_hints->max_height == size_hints->min_height);
}
#endif
toplevel = c->surface.xdg->toplevel;
state = toplevel->current;
return toplevel->parent || (state.min_width != 0 && state.min_height != 0 &&
(state.min_width == state.max_width ||
state.min_height == state.max_height));
}
int32_t client_is_rendered_on_mon(Client *c, Monitor *m) {
/* This is needed for when you don't want to check formal assignment,
* but rather actual displaying of the pixels.
* Usually VISIBLEON suffices and is also faster. */
struct wlr_surface_output *s;
int32_t unused_lx, unused_ly;
if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly))
return 0;
wl_list_for_each(s, &client_surface(c)->current_outputs,
link) if (s->output == m->wlr_output) return 1;
return 0;
}
int32_t client_is_stopped(Client *c) {
int32_t pid;
siginfo_t in = {0};
#ifdef XWAYLAND
if (client_is_x11(c))
return 0;
#endif
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
if (waitid(P_PID, pid, &in, WNOHANG | WCONTINUED | WSTOPPED | WNOWAIT) <
0) {
/* This process is not our child process, while is very unluckely that
* it is stopped, in order to do not skip frames assume that it is. */
if (errno == ECHILD)
return 1;
} else if (in.si_pid) {
if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED)
return 1;
if (in.si_code == CLD_CONTINUED)
return 0;
}
return 0;
}
int32_t client_is_unmanaged(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->override_redirect;
#endif
return 0;
}
void client_notify_enter(struct wlr_surface *s,
struct wlr_keyboard *kb) {
if (kb)
wlr_seat_keyboard_notify_enter(server.seat, s, kb->keycodes,
kb->num_keycodes, &kb->modifiers);
else
wlr_seat_keyboard_notify_enter(server.seat, s, NULL, 0, NULL);
}
void client_send_close(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_close(c->surface.xwayland);
return;
}
#endif
wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel);
}
void client_set_border_color(Client *c,
const float color[4]) {
wlr_scene_rect_set_color(c->border, color);
}
void client_set_fullscreen(Client *c, int32_t fullscreen) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen);
return;
}
#endif
wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen);
}
void client_set_scale(struct wlr_surface *s, float scale) {
wlr_fractional_scale_v1_notify_scale(s, scale);
wlr_surface_set_preferred_buffer_scale(s, (int32_t)ceilf(scale));
}
uint32_t client_set_size(Client *c, uint32_t width,
uint32_t height) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_configure(c->surface.xwayland, c->geom.x + c->bw,
c->geom.y + c->bw, width, height);
return 0;
}
#endif
if ((int32_t)width == c->surface.xdg->toplevel->current.width &&
(int32_t)height == c->surface.xdg->toplevel->current.height)
return 0;
return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width,
(int32_t)height);
}
void client_set_minimized(Client *c, bool minimized) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_set_minimized(c->surface.xwayland, minimized);
return;
}
#endif
return;
}
void client_set_maximized(Client *c, bool maximized) {
struct wlr_xdg_toplevel *toplevel;
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_set_maximized(c->surface.xwayland, maximized,
maximized);
return;
}
#endif
toplevel = c->surface.xdg->toplevel;
wlr_xdg_toplevel_set_maximized(toplevel, maximized);
return;
}
void client_set_tiled(Client *c, uint32_t edges) {
struct wlr_xdg_toplevel *toplevel;
#ifdef XWAYLAND
if (client_is_x11(c) && c->force_maximize) {
wlr_xwayland_surface_set_maximized(c->surface.xwayland,
edges != WLR_EDGE_NONE,
edges != WLR_EDGE_NONE);
return;
}
#endif
toplevel = c->surface.xdg->toplevel;
if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >=
XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
}
if (c->force_maximize) {
wlr_xdg_toplevel_set_maximized(toplevel, edges != WLR_EDGE_NONE);
}
}
void client_set_suspended(Client *c, int32_t suspended) {
#ifdef XWAYLAND
if (client_is_x11(c))
return;
#endif
wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);
}
int32_t client_should_ignore_focus(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
if (!surface->hints)
return 0;
return !surface->hints->input;
}
#endif
return 0;
}
int32_t client_is_x11_popup(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
// 处理不需要焦点的窗口类型
const uint32_t no_focus_types[] = {
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_COMBO,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DND,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_MENU,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_NOTIFICATION,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_POPUP_MENU,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_SPLASH,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_TOOLTIP,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_UTILITY};
// 检查窗口类型是否需要禁止焦点
for (size_t i = 0;
i < sizeof(no_focus_types) / sizeof(no_focus_types[0]); ++i) {
if (wlr_xwayland_surface_has_window_type(surface,
no_focus_types[i])) {
return 1;
}
}
}
#endif
return 0;
}
int32_t client_should_global(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
if (surface->sticky)
return 1;
}
#endif
return 0;
}
int32_t client_should_overtop(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
if (surface->above)
return 1;
}
#endif
return 0;
}
int32_t client_wants_focus(Client *c) {
#ifdef XWAYLAND
return client_is_unmanaged(c) &&
wlr_xwayland_surface_override_redirect_wants_focus(
c->surface.xwayland) &&
wlr_xwayland_surface_icccm_input_model(c->surface.xwayland) !=
WLR_ICCCM_INPUT_MODEL_NONE;
#endif
return 0;
}
int32_t client_wants_fullscreen(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->fullscreen;
#endif
return c->surface.xdg->toplevel->requested.fullscreen;
}
bool client_request_minimize(Client *c, void *data) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_minimize_event *event = data;
return event->minimize;
}
#endif
return c->surface.xdg->toplevel->requested.minimized;
}
bool client_request_maximize(Client *c, void *data) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
return surface->maximized_vert || surface->maximized_horz;
}
#endif
return c->surface.xdg->toplevel->requested.maximized;
}
void client_set_size_bound(Client *c) {
struct wlr_xdg_toplevel *toplevel;
struct wlr_xdg_toplevel_state state;
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
xcb_size_hints_t *size_hints = surface->size_hints;
if (!size_hints)
return;
if ((uint32_t)c->geom.width - 2 * c->bw < size_hints->min_width &&
size_hints->min_width > 0)
c->geom.width = size_hints->min_width + 2 * c->bw;
if ((uint32_t)c->geom.height - 2 * c->bw < size_hints->min_height &&
size_hints->min_height > 0)
c->geom.height = size_hints->min_height + 2 * c->bw;
if ((uint32_t)c->geom.width - 2 * c->bw > size_hints->max_width &&
size_hints->max_width > 0)
c->geom.width = size_hints->max_width + 2 * c->bw;
if ((uint32_t)c->geom.height - 2 * c->bw > size_hints->max_height &&
size_hints->max_height > 0)
c->geom.height = size_hints->max_height + 2 * c->bw;
return;
}
#endif
toplevel = c->surface.xdg->toplevel;
state = toplevel->current;
if ((uint32_t)c->geom.width - 2 * c->bw < state.min_width &&
state.min_width > 0) {
c->geom.width = state.min_width + 2 * c->bw;
}
if ((uint32_t)c->geom.height - 2 * c->bw < state.min_height &&
state.min_height > 0) {
c->geom.height = state.min_height + 2 * c->bw;
}
if ((uint32_t)c->geom.width - 2 * c->bw > state.max_width &&
state.max_width > 0) {
c->geom.width = state.max_width + 2 * c->bw;
}
if ((uint32_t)c->geom.height - 2 * c->bw > state.max_height &&
state.max_height > 0) {
c->geom.height = state.max_height + 2 * c->bw;
}
}

View file

@ -1,550 +1,50 @@
/*
* Attempt to consolidate unavoidable suck into one file, away from dwl.c. This
* file is not meant to be pretty. We use a .h file with static inline
* functions instead of a separate .c module, or function pointers like sway, so
* that they will simply compile out if the chosen #defines leave them unused.
*/
/* Leave these functions first; they're used in the others */
static inline int32_t client_is_x11(Client *c) {
#ifdef XWAYLAND
return c->type == X11;
#endif
return 0;
}
static inline struct wlr_surface *client_surface(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->surface;
#endif
return c->surface.xdg->surface;
}
static inline int32_t toplevel_from_wlr_surface(struct wlr_surface *s,
Client **pc,
LayerSurface **pl) {
struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface;
struct wlr_surface *root_surface;
struct wlr_layer_surface_v1 *layer_surface;
Client *c = NULL;
LayerSurface *l = NULL;
int32_t type = -1;
#ifdef XWAYLAND
struct wlr_xwayland_surface *xsurface;
#endif
if (!s)
return -1;
root_surface = wlr_surface_get_root_surface(s);
#ifdef XWAYLAND
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) {
c = xsurface->data;
type = c->type;
goto end;
}
#endif
if ((layer_surface =
wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) {
l = layer_surface->data;
type = LayerShell;
goto end;
}
xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface);
while (xdg_surface) {
tmp_xdg_surface = NULL;
switch (xdg_surface->role) {
case WLR_XDG_SURFACE_ROLE_POPUP:
if (!xdg_surface->popup || !xdg_surface->popup->parent)
return -1;
tmp_xdg_surface = wlr_xdg_surface_try_from_wlr_surface(
xdg_surface->popup->parent);
if (!tmp_xdg_surface)
return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc,
pl);
xdg_surface = tmp_xdg_surface;
break;
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
c = xdg_surface->data;
type = c->type;
goto end;
case WLR_XDG_SURFACE_ROLE_NONE:
return -1;
}
}
end:
if (pl)
*pl = l;
if (pc)
*pc = c;
return type;
}
/* The others */
static inline void client_activate_surface(struct wlr_surface *s,
int32_t activated) {
struct wlr_xdg_toplevel *toplevel;
#ifdef XWAYLAND
struct wlr_xwayland_surface *xsurface;
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) {
if (activated && xsurface->minimized)
wlr_xwayland_surface_set_minimized(xsurface, false);
wlr_xwayland_surface_activate(xsurface, activated);
return;
}
#endif
if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s)))
wlr_xdg_toplevel_set_activated(toplevel, activated);
}
static inline const char *client_get_appid(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->class ? c->surface.xwayland->class
: "broken";
#endif
return c->surface.xdg->toplevel->app_id ? c->surface.xdg->toplevel->app_id
: "broken";
}
static inline int32_t client_get_pid(Client *c) {
pid_t pid;
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->pid;
#endif
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
return pid;
}
static inline void client_get_clip(Client *c, struct wlr_box *clip) {
*clip = (struct wlr_box){
.x = 0,
.y = 0,
.width = c->geom.width - 2 * c->bw,
.height = c->geom.height - 2 * c->bw,
};
#ifdef XWAYLAND
if (client_is_x11(c))
return;
#endif
clip->x = c->surface.xdg->geometry.x;
clip->y = c->surface.xdg->geometry.y;
}
static inline void client_get_geometry(Client *c, struct wlr_box *geom) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
geom->x = c->surface.xwayland->x;
geom->y = c->surface.xwayland->y;
geom->width = c->surface.xwayland->width;
geom->height = c->surface.xwayland->height;
return;
}
#endif
*geom = c->surface.xdg->geometry;
}
static inline Client *client_get_parent(Client *c) {
Client *p = NULL;
#ifdef XWAYLAND
if (client_is_x11(c)) {
if (c->surface.xwayland->parent)
toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p,
NULL);
return p;
}
#endif
if (c->surface.xdg->toplevel->parent)
toplevel_from_wlr_surface(
c->surface.xdg->toplevel->parent->base->surface, &p, NULL);
return p;
}
static inline int32_t client_has_children(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c))
return !wl_list_empty(&c->surface.xwayland->children);
#endif
/* surface.xdg->link is never empty because it always contains at least the
* surface itself. */
return wl_list_length(&c->surface.xdg->link) > 1;
}
static inline const char *client_get_title(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->title ? c->surface.xwayland->title
: "broken";
#endif
return c->surface.xdg->toplevel->title ? c->surface.xdg->toplevel->title
: "broken";
}
static inline int32_t client_is_float_type(Client *c) {
struct wlr_xdg_toplevel *toplevel;
struct wlr_xdg_toplevel_state state;
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
xcb_size_hints_t *size_hints = surface->size_hints;
if (!size_hints)
return 0;
if (surface->modal)
return 1;
if (wlr_xwayland_surface_has_window_type(
surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DIALOG) ||
wlr_xwayland_surface_has_window_type(
surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_SPLASH) ||
wlr_xwayland_surface_has_window_type(
surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_TOOLBAR) ||
wlr_xwayland_surface_has_window_type(
surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_UTILITY)) {
return 1;
}
return size_hints && size_hints->min_width > 0 &&
size_hints->min_height > 0 &&
(size_hints->max_width == size_hints->min_width ||
size_hints->max_height == size_hints->min_height);
}
#endif
toplevel = c->surface.xdg->toplevel;
state = toplevel->current;
return toplevel->parent || (state.min_width != 0 && state.min_height != 0 &&
(state.min_width == state.max_width ||
state.min_height == state.max_height));
}
static inline int32_t client_is_rendered_on_mon(Client *c, Monitor *m) {
/* This is needed for when you don't want to check formal assignment,
* but rather actual displaying of the pixels.
* Usually VISIBLEON suffices and is also faster. */
struct wlr_surface_output *s;
int32_t unused_lx, unused_ly;
if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly))
return 0;
wl_list_for_each(s, &client_surface(c)->current_outputs,
link) if (s->output == m->wlr_output) return 1;
return 0;
}
static inline int32_t client_is_stopped(Client *c) {
int32_t pid;
siginfo_t in = {0};
#ifdef XWAYLAND
if (client_is_x11(c))
return 0;
#endif
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
if (waitid(P_PID, pid, &in, WNOHANG | WCONTINUED | WSTOPPED | WNOWAIT) <
0) {
/* This process is not our child process, while is very unluckely that
* it is stopped, in order to do not skip frames assume that it is. */
if (errno == ECHILD)
return 1;
} else if (in.si_pid) {
if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED)
return 1;
if (in.si_code == CLD_CONTINUED)
return 0;
}
return 0;
}
static inline int32_t client_is_unmanaged(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->override_redirect;
#endif
return 0;
}
static inline void client_notify_enter(struct wlr_surface *s,
struct wlr_keyboard *kb) {
if (kb)
wlr_seat_keyboard_notify_enter(server.seat, s, kb->keycodes,
kb->num_keycodes, &kb->modifiers);
else
wlr_seat_keyboard_notify_enter(server.seat, s, NULL, 0, NULL);
}
static inline void client_send_close(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_close(c->surface.xwayland);
return;
}
#endif
wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel);
}
static inline void client_set_border_color(Client *c,
const float color[static 4]) {
wlr_scene_rect_set_color(c->border, color);
}
static inline void client_set_fullscreen(Client *c, int32_t fullscreen) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen);
return;
}
#endif
wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen);
}
static inline void client_set_scale(struct wlr_surface *s, float scale) {
wlr_fractional_scale_v1_notify_scale(s, scale);
wlr_surface_set_preferred_buffer_scale(s, (int32_t)ceilf(scale));
}
static inline uint32_t client_set_size(Client *c, uint32_t width,
uint32_t height) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_configure(c->surface.xwayland, c->geom.x + c->bw,
c->geom.y + c->bw, width, height);
return 0;
}
#endif
if ((int32_t)width == c->surface.xdg->toplevel->current.width &&
(int32_t)height == c->surface.xdg->toplevel->current.height)
return 0;
return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width,
(int32_t)height);
}
static inline void client_set_minimized(Client *c, bool minimized) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_set_minimized(c->surface.xwayland, minimized);
return;
}
#endif
return;
}
static inline void client_set_maximized(Client *c, bool maximized) {
struct wlr_xdg_toplevel *toplevel;
#ifdef XWAYLAND
if (client_is_x11(c)) {
wlr_xwayland_surface_set_maximized(c->surface.xwayland, maximized,
maximized);
return;
}
#endif
toplevel = c->surface.xdg->toplevel;
wlr_xdg_toplevel_set_maximized(toplevel, maximized);
return;
}
static inline void client_set_tiled(Client *c, uint32_t edges) {
struct wlr_xdg_toplevel *toplevel;
#ifdef XWAYLAND
if (client_is_x11(c) && c->force_maximize) {
wlr_xwayland_surface_set_maximized(c->surface.xwayland,
edges != WLR_EDGE_NONE,
edges != WLR_EDGE_NONE);
return;
}
#endif
toplevel = c->surface.xdg->toplevel;
if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >=
XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
}
if (c->force_maximize) {
wlr_xdg_toplevel_set_maximized(toplevel, edges != WLR_EDGE_NONE);
}
}
static inline void client_set_suspended(Client *c, int32_t suspended) {
#ifdef XWAYLAND
if (client_is_x11(c))
return;
#endif
wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);
}
static inline int32_t client_should_ignore_focus(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
if (!surface->hints)
return 0;
return !surface->hints->input;
}
#endif
return 0;
}
static inline int32_t client_is_x11_popup(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
// 处理不需要焦点的窗口类型
const uint32_t no_focus_types[] = {
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_COMBO,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DND,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_MENU,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_NOTIFICATION,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_POPUP_MENU,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_SPLASH,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_TOOLTIP,
WLR_XWAYLAND_NET_WM_WINDOW_TYPE_UTILITY};
// 检查窗口类型是否需要禁止焦点
for (size_t i = 0;
i < sizeof(no_focus_types) / sizeof(no_focus_types[0]); ++i) {
if (wlr_xwayland_surface_has_window_type(surface,
no_focus_types[i])) {
return 1;
}
}
}
#endif
return 0;
}
static inline int32_t client_should_global(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
if (surface->sticky)
return 1;
}
#endif
return 0;
}
static inline int32_t client_should_overtop(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
if (surface->above)
return 1;
}
#endif
return 0;
}
static inline int32_t client_wants_focus(Client *c) {
#ifdef XWAYLAND
return client_is_unmanaged(c) &&
wlr_xwayland_surface_override_redirect_wants_focus(
c->surface.xwayland) &&
wlr_xwayland_surface_icccm_input_model(c->surface.xwayland) !=
WLR_ICCCM_INPUT_MODEL_NONE;
#endif
return 0;
}
static inline int32_t client_wants_fullscreen(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->fullscreen;
#endif
return c->surface.xdg->toplevel->requested.fullscreen;
}
static inline bool client_request_minimize(Client *c, void *data) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_minimize_event *event = data;
return event->minimize;
}
#endif
return c->surface.xdg->toplevel->requested.minimized;
}
static inline bool client_request_maximize(Client *c, void *data) {
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
return surface->maximized_vert || surface->maximized_horz;
}
#endif
return c->surface.xdg->toplevel->requested.maximized;
}
static inline void client_set_size_bound(Client *c) {
struct wlr_xdg_toplevel *toplevel;
struct wlr_xdg_toplevel_state state;
#ifdef XWAYLAND
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
xcb_size_hints_t *size_hints = surface->size_hints;
if (!size_hints)
return;
if ((uint32_t)c->geom.width - 2 * c->bw < size_hints->min_width &&
size_hints->min_width > 0)
c->geom.width = size_hints->min_width + 2 * c->bw;
if ((uint32_t)c->geom.height - 2 * c->bw < size_hints->min_height &&
size_hints->min_height > 0)
c->geom.height = size_hints->min_height + 2 * c->bw;
if ((uint32_t)c->geom.width - 2 * c->bw > size_hints->max_width &&
size_hints->max_width > 0)
c->geom.width = size_hints->max_width + 2 * c->bw;
if ((uint32_t)c->geom.height - 2 * c->bw > size_hints->max_height &&
size_hints->max_height > 0)
c->geom.height = size_hints->max_height + 2 * c->bw;
return;
}
#endif
toplevel = c->surface.xdg->toplevel;
state = toplevel->current;
if ((uint32_t)c->geom.width - 2 * c->bw < state.min_width &&
state.min_width > 0) {
c->geom.width = state.min_width + 2 * c->bw;
}
if ((uint32_t)c->geom.height - 2 * c->bw < state.min_height &&
state.min_height > 0) {
c->geom.height = state.min_height + 2 * c->bw;
}
if ((uint32_t)c->geom.width - 2 * c->bw > state.max_width &&
state.max_width > 0) {
c->geom.width = state.max_width + 2 * c->bw;
}
if ((uint32_t)c->geom.height - 2 * c->bw > state.max_height &&
state.max_height > 0) {
c->geom.height = state.max_height + 2 * c->bw;
}
}
#ifndef MANGO_CLIENT_CLIENT_H
#define MANGO_CLIENT_CLIENT_H
/* 基础客户端类型检测和表面处理 */
int32_t client_is_x11(Client *c);
struct wlr_surface *client_surface(Client *c);
int32_t toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl);
/* 客户端激活和焦点控制 */
void client_activate_surface(struct wlr_surface *s, int32_t activated);
void client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb);
int32_t client_should_ignore_focus(Client *c);
int32_t client_is_x11_popup(Client *c);
int32_t client_wants_focus(Client *c);
/* 客户端信息获取 */
const char *client_get_appid(Client *c);
int32_t client_get_pid(Client *c);
const char *client_get_title(Client *c);
Client *client_get_parent(Client *c);
int32_t client_has_children(Client *c);
int32_t client_is_float_type(Client *c);
int32_t client_is_rendered_on_mon(Client *c, Monitor *m);
int32_t client_is_stopped(Client *c);
int32_t client_is_unmanaged(Client *c);
int32_t client_wants_fullscreen(Client *c);
bool client_request_minimize(Client *c, void *data);
bool client_request_maximize(Client *c, void *data);
/* 客户端几何和布局 */
void client_get_clip(Client *c, struct wlr_box *clip);
void client_get_geometry(Client *c, struct wlr_box *geom);
void client_set_size_bound(Client *c);
/* 客户端状态设置 */
void client_send_close(Client *c);
void client_set_border_color(Client *c, const float color[4]);
void client_set_fullscreen(Client *c, int32_t fullscreen);
void client_set_scale(struct wlr_surface *s, float scale);
uint32_t client_set_size(Client *c, uint32_t width, uint32_t height);
void client_set_minimized(Client *c, bool minimized);
void client_set_maximized(Client *c, bool maximized);
void client_set_tiled(Client *c, uint32_t edges);
void client_set_suspended(Client *c, int32_t suspended);
/* 特殊客户端行为 */
int32_t client_should_global(Client *c);
int32_t client_should_overtop(Client *c);
#endif // MANGO_CLIENT_CLIENT_H

3403
src/config/parse_config.c Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -126,7 +126,7 @@ char xkb_rules_variant[256];
char xkb_rules_options[256];
/* keyboard */
static const struct xkb_rule_names xkb_fallback_rules = {
const struct xkb_rule_names xkb_fallback_rules = {
.layout = "us",
.variant = NULL,
.model = NULL,
@ -134,7 +134,7 @@ static const struct xkb_rule_names xkb_fallback_rules = {
.options = NULL,
};
static const struct xkb_rule_names xkb_default_rules = {
const struct xkb_rule_names xkb_default_rules = {
.options = NULL,
};
@ -206,7 +206,7 @@ enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM;
/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
#define MODKEY WLR_MODIFIER_ALT
static const char *tags[] = {
const char *tags[] = {
"1", "2", "3", "4", "5", "6", "7", "8", "9",
};

View file

@ -3,7 +3,7 @@ typedef struct {
const char *abbr; // 全部使用小写
} LayoutMapping;
static const LayoutMapping layout_mappings[] = {
const LayoutMapping layout_mappings[] = {
{"English (US)", "us"},
{"English (UK)", "gb"},
{"Russian", "ru"},

View file

@ -1,72 +0,0 @@
int32_t minimized(const Arg *arg);
int32_t restore_minimized(const Arg *arg);
int32_t toggle_scratchpad(const Arg *arg);
int32_t focusdir(const Arg *arg);
int32_t toggleoverview(const Arg *arg);
int32_t set_proportion(const Arg *arg);
int32_t switch_proportion_preset(const Arg *arg);
int32_t zoom(const Arg *arg);
int32_t tagsilent(const Arg *arg);
int32_t tagtoleft(const Arg *arg);
int32_t tagtoright(const Arg *arg);
int32_t tagcrossmon(const Arg *arg);
int32_t viewtoleft(const Arg *arg);
int32_t viewtoright(const Arg *arg);
int32_t viewtoleft_have_client(const Arg *arg);
int32_t viewtoright_have_client(const Arg *arg);
int32_t viewcrossmon(const Arg *arg);
int32_t togglefloating(const Arg *arg);
int32_t togglefullscreen(const Arg *arg);
int32_t togglemaximizescreen(const Arg *arg);
int32_t togglegaps(const Arg *arg);
int32_t tagmon(const Arg *arg);
int32_t spawn(const Arg *arg);
int32_t spawn_shell(const Arg *arg);
int32_t spawn_on_empty(const Arg *arg);
int32_t setkeymode(const Arg *arg);
int32_t switch_keyboard_layout(const Arg *arg);
int32_t setlayout(const Arg *arg);
int32_t switch_layout(const Arg *arg);
int32_t setmfact(const Arg *arg);
int32_t quit(const Arg *arg);
int32_t moveresize(const Arg *arg);
int32_t exchange_client(const Arg *arg);
int32_t exchange_stack_client(const Arg *arg);
int32_t killclient(const Arg *arg);
int32_t toggleglobal(const Arg *arg);
int32_t incnmaster(const Arg *arg);
int32_t focusmon(const Arg *arg);
int32_t focusstack(const Arg *arg);
int32_t chvt(const Arg *arg);
int32_t reload_config(const Arg *arg);
int32_t smartmovewin(const Arg *arg);
int32_t smartresizewin(const Arg *arg);
int32_t centerwin(const Arg *arg);
int32_t bind_to_view(const Arg *arg);
int32_t toggletag(const Arg *arg);
int32_t toggleview(const Arg *arg);
int32_t tag(const Arg *arg);
int32_t comboview(const Arg *arg);
int32_t incgaps(const Arg *arg);
int32_t incigaps(const Arg *arg);
int32_t incihgaps(const Arg *arg);
int32_t incivgaps(const Arg *arg);
int32_t incogaps(const Arg *arg);
int32_t incohgaps(const Arg *arg);
int32_t incovgaps(const Arg *arg);
int32_t defaultgaps(const Arg *arg);
int32_t togglefakefullscreen(const Arg *arg);
int32_t toggleoverlay(const Arg *arg);
int32_t movewin(const Arg *arg);
int32_t resizewin(const Arg *arg);
int32_t toggle_named_scratchpad(const Arg *arg);
int32_t toggle_render_border(const Arg *arg);
int32_t create_virtual_output(const Arg *arg);
int32_t destroy_all_virtual_output(const Arg *arg);
int32_t focuslast(const Arg *arg);
int32_t toggle_trackpad_enable(const Arg *arg);
int32_t setoption(const Arg *arg);
int32_t disable_monitor(const Arg *arg);
int32_t enable_monitor(const Arg *arg);
int32_t toggle_monitor(const Arg *arg);
int32_t scroller_stack(const Arg *arg);

1795
src/dispatch/bind_define.c Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,5 +0,0 @@
#include "dwl-ipc.h"
#include "ext-workspace.h"
#include "foreign-toplevel.h"
#include "tearing.h"
#include "text-input.h"

View file

@ -1,41 +1,41 @@
#include "dwl-ipc-unstable-v2-protocol.h"
static void dwl_ipc_manager_bind(struct wl_client *client, void *data,
void dwl_ipc_manager_bind(struct wl_client *client, void *data,
uint32_t version, uint32_t id);
static void dwl_ipc_manager_destroy(struct wl_resource *resource);
static void dwl_ipc_manager_get_output(struct wl_client *client,
void dwl_ipc_manager_destroy(struct wl_resource *resource);
void dwl_ipc_manager_get_output(struct wl_client *client,
struct wl_resource *resource,
uint32_t id, struct wl_resource *output);
static void dwl_ipc_manager_release(struct wl_client *client,
void dwl_ipc_manager_release(struct wl_client *client,
struct wl_resource *resource);
static void dwl_ipc_output_destroy(struct wl_resource *resource);
static void dwl_ipc_output_printstatus(Monitor *monitor);
static void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output);
static void dwl_ipc_output_set_client_tags(struct wl_client *client,
void dwl_ipc_output_destroy(struct wl_resource *resource);
void dwl_ipc_output_printstatus(Monitor *monitor);
void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output);
void dwl_ipc_output_set_client_tags(struct wl_client *client,
struct wl_resource *resource,
uint32_t and_tags,
uint32_t xor_tags);
static void dwl_ipc_output_set_layout(struct wl_client *client,
void dwl_ipc_output_set_layout(struct wl_client *client,
struct wl_resource *resource,
uint32_t index);
static void dwl_ipc_output_set_tags(struct wl_client *client,
void dwl_ipc_output_set_tags(struct wl_client *client,
struct wl_resource *resource,
uint32_t tagmask, uint32_t toggle_tagset);
static void dwl_ipc_output_quit(struct wl_client *client,
void dwl_ipc_output_quit(struct wl_client *client,
struct wl_resource *resource);
static void dwl_ipc_output_dispatch(struct wl_client *client,
void dwl_ipc_output_dispatch(struct wl_client *client,
struct wl_resource *resource,
const char *dispatch, const char *arg1,
const char *arg2, const char *arg3,
const char *arg4, const char *arg5);
static void dwl_ipc_output_release(struct wl_client *client,
void dwl_ipc_output_release(struct wl_client *client,
struct wl_resource *resource);
/* global event handlers */
static struct zdwl_ipc_manager_v2_interface dwl_manager_implementation = {
struct zdwl_ipc_manager_v2_interface dwl_manager_implementation = {
.release = dwl_ipc_manager_release,
.get_output = dwl_ipc_manager_get_output};
static struct zdwl_ipc_output_v2_interface dwl_output_implementation = {
struct zdwl_ipc_output_v2_interface dwl_output_implementation = {
.release = dwl_ipc_output_release,
.set_tags = dwl_ipc_output_set_tags,
.quit = dwl_ipc_output_quit,
@ -57,7 +57,7 @@ void dwl_ipc_manager_bind(struct wl_client *client, void *data,
zdwl_ipc_manager_v2_send_tags(manager_resource, LENGTH(tags));
for (uint32_t i = 0; i < LENGTH(layouts); i++)
for (uint32_t i = 0; i < layouts_len; i++) {
zdwl_ipc_manager_v2_send_layout(manager_resource, layouts[i].symbol);
}
@ -93,7 +93,7 @@ void dwl_ipc_manager_release(struct wl_client *client,
wl_resource_destroy(resource);
}
static void dwl_ipc_output_destroy(struct wl_resource *resource) {
void dwl_ipc_output_destroy(struct wl_resource *resource) {
DwlIpcOutput *ipc_output = wl_resource_get_user_data(resource);
wl_list_remove(&ipc_output->link);
free(ipc_output);
@ -254,7 +254,7 @@ void dwl_ipc_output_set_layout(struct wl_client *client,
return;
monitor = ipc_output->mon;
if (index >= LENGTH(layouts))
if (index >= layouts_len)
index = 0;
monitor->pertag->ltidxs[monitor->pertag->curtag] = &layouts[index];

View file

@ -43,7 +43,7 @@ void toggle_workspace(struct workspace *target) {
}
}
static void handle_ext_workspace_activate(struct wl_listener *listener,
void handle_ext_workspace_activate(struct wl_listener *listener,
void *data) {
struct workspace *workspace =
wl_container_of(listener, workspace, activate);
@ -56,7 +56,7 @@ static void handle_ext_workspace_activate(struct wl_listener *listener,
wlr_log(WLR_INFO, "ext activating workspace %d", workspace->tag);
}
static void handle_ext_workspace_deactivate(struct wl_listener *listener,
void handle_ext_workspace_deactivate(struct wl_listener *listener,
void *data) {
struct workspace *workspace =
wl_container_of(listener, workspace, deactivate);
@ -69,8 +69,8 @@ static void handle_ext_workspace_deactivate(struct wl_listener *listener,
wlr_log(WLR_INFO, "ext deactivating workspace %d", workspace->tag);
}
static const char *get_name_from_tag(uint32_t tag) {
static const char *names[] = {"overview", "1", "2", "3", "4",
const char *get_name_from_tag(uint32_t tag) {
const char *names[] = {"overview", "1", "2", "3", "4",
"5", "6", "7", "8", "9"};
return (tag < sizeof(names) / sizeof(names[0])) ? names[tag] : NULL;
}
@ -92,7 +92,7 @@ void cleanup_workspaces_by_monitor(Monitor *m) {
}
}
static void remove_workspace_by_tag(uint32_t tag, Monitor *m) {
void remove_workspace_by_tag(uint32_t tag, Monitor *m) {
struct workspace *workspace, *tmp;
wl_list_for_each_safe(workspace, tmp, &workspaces, link) {
if (workspace->tag == tag && workspace->m == m) {
@ -102,7 +102,7 @@ static void remove_workspace_by_tag(uint32_t tag, Monitor *m) {
}
}
static void add_workspace_by_tag(int32_t tag, Monitor *m) {
void add_workspace_by_tag(int32_t tag, Monitor *m) {
const char *name = get_name_from_tag(tag);
struct workspace *workspace = ecalloc(1, sizeof(*workspace));

View file

@ -1,6 +1,6 @@
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
static struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager;
struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager;
void handle_foreign_activate_request(struct wl_listener *listener, void *data) {
Client *c = wl_container_of(listener, c, foreign_activate_request);

View file

@ -9,7 +9,7 @@ struct tearing_controller {
struct wlr_tearing_control_manager_v1 *tearing_control;
struct wl_listener tearing_new_object;
static void handle_controller_set_hint(struct wl_listener *listener,
void handle_controller_set_hint(struct wl_listener *listener,
void *data) {
struct tearing_controller *controller =
wl_container_of(listener, controller, set_hint);
@ -29,7 +29,7 @@ static void handle_controller_set_hint(struct wl_listener *listener,
}
}
static void handle_controller_destroy(struct wl_listener *listener,
void handle_controller_destroy(struct wl_listener *listener,
void *data) {
struct tearing_controller *controller =
wl_container_of(listener, controller, destroy);

View file

@ -88,7 +88,7 @@ Monitor *output_nearest_to(int32_t lx, int32_t ly) {
bool output_is_usable(Monitor *m) { return m && m->wlr_output->enabled; }
static bool
bool
is_keyboard_emulated_by_input_method(struct wlr_keyboard *keyboard,
struct wlr_input_method_v2 *input_method) {
struct wlr_virtual_keyboard_v1 *virtual_keyboard;
@ -103,7 +103,7 @@ is_keyboard_emulated_by_input_method(struct wlr_keyboard *keyboard,
wl_resource_get_client(input_method->resource);
}
static struct wlr_input_method_keyboard_grab_v2 *
struct wlr_input_method_keyboard_grab_v2 *
get_keyboard_grab(KeyboardGroup *keyboard) {
struct wlr_input_method_v2 *input_method =
dwl_input_method_relay->input_method;
@ -157,7 +157,7 @@ bool dwl_im_keyboard_grab_forward_key(KeyboardGroup *keyboard,
}
}
static struct text_input *
struct text_input *
get_active_text_input(struct dwl_input_method_relay *relay) {
struct text_input *text_input;
@ -173,7 +173,7 @@ get_active_text_input(struct dwl_input_method_relay *relay) {
return NULL;
}
static void update_active_text_input(struct dwl_input_method_relay *relay) {
void update_active_text_input(struct dwl_input_method_relay *relay) {
struct text_input *active_text_input = get_active_text_input(relay);
if (relay->input_method && relay->active_text_input != active_text_input) {
@ -188,7 +188,7 @@ static void update_active_text_input(struct dwl_input_method_relay *relay) {
relay->active_text_input = active_text_input;
}
static void
void
update_text_inputs_focused_surface(struct dwl_input_method_relay *relay) {
struct text_input *text_input;
wl_list_for_each(text_input, &relay->text_inputs, link) {
@ -215,7 +215,7 @@ update_text_inputs_focused_surface(struct dwl_input_method_relay *relay) {
}
}
static void update_popup_position(struct dwl_input_method_popup *popup) {
void update_popup_position(struct dwl_input_method_popup *popup) {
struct dwl_input_method_relay *relay = popup->relay;
struct text_input *text_input = relay->active_text_input;
struct wlr_box cursor_rect;
@ -291,14 +291,14 @@ static void update_popup_position(struct dwl_input_method_popup *popup) {
});
}
static void update_popups_position(struct dwl_input_method_relay *relay) {
void update_popups_position(struct dwl_input_method_relay *relay) {
struct dwl_input_method_popup *popup;
wl_list_for_each(popup, &relay->popups, link) {
update_popup_position(popup);
}
}
static void handle_input_method_commit(struct wl_listener *listener,
void handle_input_method_commit(struct wl_listener *listener,
void *data) {
struct dwl_input_method_relay *relay =
wl_container_of(listener, relay, input_method_commit);
@ -330,7 +330,7 @@ static void handle_input_method_commit(struct wl_listener *listener,
wlr_text_input_v3_send_done(text_input->input);
}
static void handle_keyboard_grab_destroy(struct wl_listener *listener,
void handle_keyboard_grab_destroy(struct wl_listener *listener,
void *data) {
struct dwl_input_method_relay *relay =
wl_container_of(listener, relay, keyboard_grab_destroy);
@ -343,7 +343,7 @@ static void handle_keyboard_grab_destroy(struct wl_listener *listener,
}
}
static void handle_input_method_grab_keyboard(struct wl_listener *listener,
void handle_input_method_grab_keyboard(struct wl_listener *listener,
void *data) {
struct dwl_input_method_relay *relay =
wl_container_of(listener, relay, input_method_grab_keyboard);
@ -362,7 +362,7 @@ static void handle_input_method_grab_keyboard(struct wl_listener *listener,
&relay->keyboard_grab_destroy);
}
static void handle_input_method_destroy(struct wl_listener *listener,
void handle_input_method_destroy(struct wl_listener *listener,
void *data) {
struct dwl_input_method_relay *relay =
wl_container_of(listener, relay, input_method_destroy);
@ -377,7 +377,7 @@ static void handle_input_method_destroy(struct wl_listener *listener,
update_active_text_input(relay);
}
static void handle_popup_surface_destroy(struct wl_listener *listener,
void handle_popup_surface_destroy(struct wl_listener *listener,
void *data) {
struct dwl_input_method_popup *popup =
wl_container_of(listener, popup, destroy);
@ -388,14 +388,14 @@ static void handle_popup_surface_destroy(struct wl_listener *listener,
free(popup);
}
static void handle_popup_surface_commit(struct wl_listener *listener,
void handle_popup_surface_commit(struct wl_listener *listener,
void *data) {
struct dwl_input_method_popup *popup =
wl_container_of(listener, popup, commit);
update_popup_position(popup);
}
static void handle_input_method_new_popup_surface(struct wl_listener *listener,
void handle_input_method_new_popup_surface(struct wl_listener *listener,
void *data) {
struct dwl_input_method_relay *relay =
wl_container_of(listener, relay, input_method_new_popup_surface);
@ -422,7 +422,7 @@ static void handle_input_method_new_popup_surface(struct wl_listener *listener,
update_popup_position(popup);
}
static void handle_new_input_method(struct wl_listener *listener, void *data) {
void handle_new_input_method(struct wl_listener *listener, void *data) {
struct dwl_input_method_relay *relay =
wl_container_of(listener, relay, new_input_method);
struct wlr_input_method_v2 *input_method = data;
@ -459,7 +459,7 @@ static void handle_new_input_method(struct wl_listener *listener, void *data) {
update_active_text_input(relay);
}
static void send_state_to_input_method(struct dwl_input_method_relay *relay) {
void send_state_to_input_method(struct dwl_input_method_relay *relay) {
struct wlr_input_method_v2 *input_method = relay->input_method;
struct wlr_text_input_v3 *input = relay->active_text_input->input;
@ -481,7 +481,7 @@ static void send_state_to_input_method(struct dwl_input_method_relay *relay) {
wlr_input_method_v2_send_done(input_method);
}
static void handle_text_input_enable(struct wl_listener *listener, void *data) {
void handle_text_input_enable(struct wl_listener *listener, void *data) {
struct text_input *text_input =
wl_container_of(listener, text_input, enable);
struct dwl_input_method_relay *relay = text_input->relay;
@ -494,7 +494,7 @@ static void handle_text_input_enable(struct wl_listener *listener, void *data) {
wlr_text_input_v3_send_done(text_input->input);
}
static void handle_text_input_disable(struct wl_listener *listener,
void handle_text_input_disable(struct wl_listener *listener,
void *data) {
struct text_input *text_input =
wl_container_of(listener, text_input, disable);
@ -502,7 +502,7 @@ static void handle_text_input_disable(struct wl_listener *listener,
update_active_text_input(text_input->relay);
}
static void handle_text_input_commit(struct wl_listener *listener, void *data) {
void handle_text_input_commit(struct wl_listener *listener, void *data) {
struct text_input *text_input =
wl_container_of(listener, text_input, commit);
struct dwl_input_method_relay *relay = text_input->relay;
@ -513,7 +513,7 @@ static void handle_text_input_commit(struct wl_listener *listener, void *data) {
}
}
static void handle_text_input_destroy(struct wl_listener *listener,
void handle_text_input_destroy(struct wl_listener *listener,
void *data) {
struct text_input *text_input =
wl_container_of(listener, text_input, destroy);
@ -526,7 +526,7 @@ static void handle_text_input_destroy(struct wl_listener *listener,
free(text_input);
}
static void handle_new_text_input(struct wl_listener *listener, void *data) {
void handle_new_text_input(struct wl_listener *listener, void *data) {
struct dwl_input_method_relay *relay =
wl_container_of(listener, relay, new_text_input);
struct wlr_text_input_v3 *wlr_text_input = data;
@ -555,7 +555,7 @@ static void handle_new_text_input(struct wl_listener *listener, void *data) {
update_text_inputs_focused_surface(relay);
}
static void handle_focused_surface_destroy(struct wl_listener *listener,
void handle_focused_surface_destroy(struct wl_listener *listener,
void *data) {
struct dwl_input_method_relay *relay =
wl_container_of(listener, relay, focused_surface_destroy);

View file

@ -71,39 +71,39 @@ struct wlr_ext_workspace_v1_resource {
manager_resource_link; // wlr_ext_workspace_manager_v1_resource.workspace_resources
};
static const struct ext_workspace_group_handle_v1_interface group_impl;
const struct ext_workspace_group_handle_v1_interface group_impl;
static struct wlr_ext_workspace_group_v1_resource *
struct wlr_ext_workspace_group_v1_resource *
group_resource_from_resource(struct wl_resource *resource) {
assert(wl_resource_instance_of(
resource, &ext_workspace_group_handle_v1_interface, &group_impl));
return wl_resource_get_user_data(resource);
}
static const struct ext_workspace_handle_v1_interface workspace_impl;
const struct ext_workspace_handle_v1_interface workspace_impl;
static struct wlr_ext_workspace_v1_resource *
struct wlr_ext_workspace_v1_resource *
workspace_resource_from_resource(struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &ext_workspace_handle_v1_interface,
&workspace_impl));
return wl_resource_get_user_data(resource);
}
static const struct ext_workspace_manager_v1_interface manager_impl;
const struct ext_workspace_manager_v1_interface manager_impl;
static struct wlr_ext_workspace_manager_v1_resource *
struct wlr_ext_workspace_manager_v1_resource *
manager_resource_from_resource(struct wl_resource *resource) {
assert(wl_resource_instance_of(
resource, &ext_workspace_manager_v1_interface, &manager_impl));
return wl_resource_get_user_data(resource);
}
static void workspace_handle_destroy(struct wl_client *client,
void workspace_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static void workspace_handle_activate(struct wl_client *client,
void workspace_handle_activate(struct wl_client *client,
struct wl_resource *workspace_resource) {
struct wlr_ext_workspace_v1_resource *workspace_res =
workspace_resource_from_resource(workspace_resource);
@ -121,7 +121,7 @@ static void workspace_handle_activate(struct wl_client *client,
wl_list_insert(workspace_res->manager->requests.prev, &req->link);
}
static void
void
workspace_handle_deactivate(struct wl_client *client,
struct wl_resource *workspace_resource) {
struct wlr_ext_workspace_v1_resource *workspace_res =
@ -140,7 +140,7 @@ workspace_handle_deactivate(struct wl_client *client,
wl_list_insert(workspace_res->manager->requests.prev, &req->link);
}
static void workspace_handle_assign(struct wl_client *client,
void workspace_handle_assign(struct wl_client *client,
struct wl_resource *workspace_resource,
struct wl_resource *group_resource) {
struct wlr_ext_workspace_v1_resource *workspace_res =
@ -162,7 +162,7 @@ static void workspace_handle_assign(struct wl_client *client,
wl_list_insert(workspace_res->manager->requests.prev, &req->link);
}
static void workspace_handle_remove(struct wl_client *client,
void workspace_handle_remove(struct wl_client *client,
struct wl_resource *workspace_resource) {
struct wlr_ext_workspace_v1_resource *workspace_res =
workspace_resource_from_resource(workspace_resource);
@ -180,7 +180,7 @@ static void workspace_handle_remove(struct wl_client *client,
wl_list_insert(workspace_res->manager->requests.prev, &req->link);
}
static const struct ext_workspace_handle_v1_interface workspace_impl = {
const struct ext_workspace_handle_v1_interface workspace_impl = {
.destroy = workspace_handle_destroy,
.activate = workspace_handle_activate,
.deactivate = workspace_handle_deactivate,
@ -188,7 +188,7 @@ static const struct ext_workspace_handle_v1_interface workspace_impl = {
.remove = workspace_handle_remove,
};
static void group_handle_create_workspace(struct wl_client *client,
void group_handle_create_workspace(struct wl_client *client,
struct wl_resource *group_resource,
const char *name) {
struct wlr_ext_workspace_group_v1_resource *group_res =
@ -213,17 +213,17 @@ static void group_handle_create_workspace(struct wl_client *client,
wl_list_insert(group_res->manager->requests.prev, &req->link);
}
static void group_handle_destroy(struct wl_client *client,
void group_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static const struct ext_workspace_group_handle_v1_interface group_impl = {
const struct ext_workspace_group_handle_v1_interface group_impl = {
.create_workspace = group_handle_create_workspace,
.destroy = group_handle_destroy,
};
static void destroy_workspace_resource(
void destroy_workspace_resource(
struct wlr_ext_workspace_v1_resource *workspace_res) {
wl_list_remove(&workspace_res->link);
wl_list_remove(&workspace_res->manager_resource_link);
@ -231,7 +231,7 @@ static void destroy_workspace_resource(
free(workspace_res);
}
static void workspace_resource_destroy(struct wl_resource *resource) {
void workspace_resource_destroy(struct wl_resource *resource) {
struct wlr_ext_workspace_v1_resource *workspace_res =
workspace_resource_from_resource(resource);
if (workspace_res) {
@ -239,7 +239,7 @@ static void workspace_resource_destroy(struct wl_resource *resource) {
}
}
static struct wlr_ext_workspace_v1_resource *create_workspace_resource(
struct wlr_ext_workspace_v1_resource *create_workspace_resource(
struct wlr_ext_workspace_handle_v1 *workspace,
struct wlr_ext_workspace_manager_v1_resource *manager_res) {
struct wlr_ext_workspace_v1_resource *workspace_res =
@ -268,7 +268,7 @@ static struct wlr_ext_workspace_v1_resource *create_workspace_resource(
return workspace_res;
}
static void
void
destroy_group_resource(struct wlr_ext_workspace_group_v1_resource *group_res) {
wl_list_remove(&group_res->link);
wl_list_remove(&group_res->manager_resource_link);
@ -276,7 +276,7 @@ destroy_group_resource(struct wlr_ext_workspace_group_v1_resource *group_res) {
free(group_res);
}
static void group_handle_resource_destroy(struct wl_resource *resource) {
void group_handle_resource_destroy(struct wl_resource *resource) {
struct wlr_ext_workspace_group_v1_resource *group_res =
group_resource_from_resource(resource);
if (group_res) {
@ -284,7 +284,7 @@ static void group_handle_resource_destroy(struct wl_resource *resource) {
}
}
static struct wlr_ext_workspace_group_v1_resource *create_group_resource(
struct wlr_ext_workspace_group_v1_resource *create_group_resource(
struct wlr_ext_workspace_group_handle_v1 *group,
struct wlr_ext_workspace_manager_v1_resource *manager_res) {
struct wlr_ext_workspace_group_v1_resource *group_res =
@ -313,13 +313,13 @@ static struct wlr_ext_workspace_group_v1_resource *create_group_resource(
return group_res;
}
static void destroy_request(struct wlr_ext_workspace_v1_request *req) {
void destroy_request(struct wlr_ext_workspace_v1_request *req) {
wl_list_remove(&req->link);
free(req->name);
free(req);
}
static void manager_handle_commit(struct wl_client *client,
void manager_handle_commit(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_ext_workspace_manager_v1_resource *manager_res =
manager_resource_from_resource(resource);
@ -355,7 +355,7 @@ static void manager_handle_commit(struct wl_client *client,
}
}
static void handle_idle(void *data) {
void handle_idle(void *data) {
struct wlr_ext_workspace_manager_v1 *manager = data;
struct wlr_ext_workspace_manager_v1_resource *manager_res;
@ -365,7 +365,7 @@ static void handle_idle(void *data) {
manager->idle_source = NULL;
}
static void
void
manager_schedule_done(struct wlr_ext_workspace_manager_v1 *manager) {
if (!manager->idle_source) {
manager->idle_source =
@ -373,7 +373,7 @@ manager_schedule_done(struct wlr_ext_workspace_manager_v1 *manager) {
}
}
static void
void
workspace_send_details(struct wlr_ext_workspace_v1_resource *workspace_res) {
struct wlr_ext_workspace_handle_v1 *workspace = workspace_res->workspace;
struct wl_resource *resource = workspace_res->resource;
@ -393,18 +393,18 @@ workspace_send_details(struct wlr_ext_workspace_v1_resource *workspace_res) {
manager_schedule_done(workspace->manager);
}
static void manager_handle_stop(struct wl_client *client,
void manager_handle_stop(struct wl_client *client,
struct wl_resource *resource) {
ext_workspace_manager_v1_send_finished(resource);
wl_resource_destroy(resource);
}
static const struct ext_workspace_manager_v1_interface manager_impl = {
const struct ext_workspace_manager_v1_interface manager_impl = {
.commit = manager_handle_commit,
.stop = manager_handle_stop,
};
static void destroy_manager_resource(
void destroy_manager_resource(
struct wlr_ext_workspace_manager_v1_resource *manager_res) {
struct wlr_ext_workspace_v1_request *req, *tmp;
wl_list_for_each_safe(req, tmp, &manager_res->requests, link) {
@ -427,7 +427,7 @@ static void destroy_manager_resource(
free(manager_res);
}
static void manager_resource_destroy(struct wl_resource *resource) {
void manager_resource_destroy(struct wl_resource *resource) {
struct wlr_ext_workspace_manager_v1_resource *manager_res =
manager_resource_from_resource(resource);
if (manager_res) {
@ -435,7 +435,7 @@ static void manager_resource_destroy(struct wl_resource *resource) {
}
}
static void
void
group_send_details(struct wlr_ext_workspace_group_v1_resource *group_res) {
struct wlr_ext_workspace_group_handle_v1 *group = group_res->group;
struct wl_resource *resource = group_res->resource;
@ -458,7 +458,7 @@ group_send_details(struct wlr_ext_workspace_group_v1_resource *group_res) {
manager_schedule_done(group->manager);
}
static void manager_bind(struct wl_client *client, void *data, uint32_t version,
void manager_bind(struct wl_client *client, void *data, uint32_t version,
uint32_t id) {
struct wlr_ext_workspace_manager_v1 *manager = data;
@ -525,7 +525,7 @@ static void manager_bind(struct wl_client *client, void *data, uint32_t version,
ext_workspace_manager_v1_send_done(manager_res->resource);
}
static void manager_handle_display_destroy(struct wl_listener *listener,
void manager_handle_display_destroy(struct wl_listener *listener,
void *data) {
struct wlr_ext_workspace_manager_v1 *manager =
wl_container_of(listener, manager, display_destroy);
@ -623,7 +623,7 @@ wlr_ext_workspace_group_handle_v1_create(
return group;
}
static void
void
workspace_send_group(struct wlr_ext_workspace_handle_v1 *workspace,
struct wlr_ext_workspace_group_handle_v1 *group,
bool enter) {
@ -648,7 +648,7 @@ workspace_send_group(struct wlr_ext_workspace_handle_v1 *workspace,
manager_schedule_done(workspace->manager);
}
static void
void
destroy_group_output(struct wlr_ext_workspace_v1_group_output *group_output) {
wl_list_remove(&group_output->output_bind.link);
wl_list_remove(&group_output->output_destroy.link);
@ -656,7 +656,7 @@ destroy_group_output(struct wlr_ext_workspace_v1_group_output *group_output) {
free(group_output);
}
static void group_send_output(struct wlr_ext_workspace_group_handle_v1 *group,
void group_send_output(struct wlr_ext_workspace_group_handle_v1 *group,
struct wlr_output *output, bool enter) {
struct wlr_ext_workspace_group_v1_resource *group_res;
@ -728,7 +728,7 @@ void wlr_ext_workspace_group_handle_v1_destroy(
free(group);
}
static void handle_output_bind(struct wl_listener *listener, void *data) {
void handle_output_bind(struct wl_listener *listener, void *data) {
struct wlr_ext_workspace_v1_group_output *group_output =
wl_container_of(listener, group_output, output_bind);
struct wlr_output_event_bind *event = data;
@ -745,14 +745,14 @@ static void handle_output_bind(struct wl_listener *listener, void *data) {
manager_schedule_done(group_output->group->manager);
}
static void handle_output_destroy(struct wl_listener *listener, void *data) {
void handle_output_destroy(struct wl_listener *listener, void *data) {
struct wlr_ext_workspace_v1_group_output *group_output =
wl_container_of(listener, group_output, output_destroy);
group_send_output(group_output->group, group_output->output, false);
destroy_group_output(group_output);
}
static struct wlr_ext_workspace_v1_group_output *
struct wlr_ext_workspace_v1_group_output *
get_group_output(struct wlr_ext_workspace_group_handle_v1 *group,
struct wlr_output *output) {
struct wlr_ext_workspace_v1_group_output *group_output;
@ -929,7 +929,7 @@ void wlr_ext_workspace_handle_v1_set_name(
manager_schedule_done(workspace->manager);
}
static bool array_equal(struct wl_array *a, struct wl_array *b) {
bool array_equal(struct wl_array *a, struct wl_array *b) {
return (a->size == b->size) &&
(a->size == 0 || memcmp(a->data, b->data, a->size) == 0);
}
@ -956,7 +956,7 @@ void wlr_ext_workspace_handle_v1_set_coordinates(
manager_schedule_done(workspace->manager);
}
static void workspace_set_state(struct wlr_ext_workspace_handle_v1 *workspace,
void workspace_set_state(struct wlr_ext_workspace_handle_v1 *workspace,
enum ext_workspace_handle_v1_state state,
bool enabled) {
uint32_t old_state = workspace->state;

View file

@ -126,7 +126,7 @@ setclient_coordinate_center(Client *c, Monitor *tm, struct wlr_box geom,
return tempbox;
}
/* Helper: Check if rule matches client */
static bool is_window_rule_matches(const ConfigWinRule *r, const char *appid,
bool is_window_rule_matches(const ConfigWinRule *r, const char *appid,
const char *title) {
return (r->title && regex_match(r->title, title) && !r->id) ||
(r->id && regex_match(r->id, appid) && !r->title) ||

844
src/layout/arrange.c Normal file
View file

@ -0,0 +1,844 @@
#include "../type.h"
#include "layout.h"
#include "../animation/tag.h"
extern Server server;
extern Layout layouts[];
extern Layout overviewlayout;
void set_size_per(Monitor *m, Client *c) {
Client *fc = NULL;
bool found = false;
if (!m || !c)
return;
wl_list_for_each(fc, &server.clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) {
c->master_mfact_per = fc->master_mfact_per;
c->master_inner_per = fc->master_inner_per;
c->stack_inner_per = fc->stack_inner_per;
found = true;
break;
}
}
if (!found) {
c->master_mfact_per = m->pertag->mfacts[m->pertag->curtag];
c->master_inner_per = 1.0f;
c->stack_inner_per = 1.0f;
}
}
void resize_tile_master_horizontal(Client *rec, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time,
int32_t type) {
Client *tc = NULL;
float delta_x, delta_y;
Client *next = NULL;
Client *prev = NULL;
Client *nextnext = NULL;
Client *prevprev = NULL;
struct wl_list *node;
bool begin_find_nextnext = false;
bool begin_find_prevprev = false;
// 从当前节点的下一个开始遍历
for (node = rec->link.next; node != &server.clients;
node = node->next) {
tc = wl_container_of(node, tc, link);
if (begin_find_nextnext && VISIBLEON(tc, rec->mon) &&
ISTILED(tc)) {
nextnext = tc;
break;
}
if (!begin_find_nextnext && VISIBLEON(tc, rec->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
next = tc;
begin_find_nextnext = true;
continue;
}
}
// 从当前节点的上一个开始遍历
for (node = rec->link.prev; node != &server.clients;
node = node->prev) {
tc = wl_container_of(node, tc, link);
if (begin_find_prevprev && VISIBLEON(tc, rec->mon) &&
ISTILED(tc)) {
prevprev = tc;
break;
}
if (!begin_find_prevprev && VISIBLEON(tc, rec->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
prev = tc;
begin_find_prevprev = true;
continue;
}
}
if (!server.start_drag_window && isdrag) {
server.drag_begin_cursorx = server.cursor->x;
server.drag_begin_cursory = server.cursor->y;
server.start_drag_window = true;
// 记录初始状态
rec->old_master_mfact_per = rec->master_mfact_per;
rec->old_master_inner_per = rec->master_inner_per;
rec->old_stack_inner_per = rec->stack_inner_per;
rec->cursor_in_upper_half =
server.cursor->y <
rec->geom.y + rec->geom.height / 2;
rec->cursor_in_left_half =
server.cursor->x <
rec->geom.x + rec->geom.width / 2;
// 记录初始几何信息
rec->drag_begin_geom = rec->geom;
} else {
// 计算相对于屏幕尺寸的比例变化
if (isdrag) {
offsetx = server.cursor->x - server.drag_begin_cursorx;
offsety = server.cursor->y - server.drag_begin_cursory;
} else {
rec->old_master_mfact_per = rec->master_mfact_per;
rec->old_master_inner_per = rec->master_inner_per;
rec->old_stack_inner_per = rec->stack_inner_per;
rec->drag_begin_geom = rec->geom;
rec->cursor_in_upper_half = true;
rec->cursor_in_left_half = false;
}
if (rec->ismaster) {
delta_x = (float)(offsetx) * (rec->old_master_mfact_per) /
rec->drag_begin_geom.width;
delta_y = (float)(offsety) * (rec->old_master_inner_per) /
rec->drag_begin_geom.height;
} else {
delta_x = (float)(offsetx) *
(1 - rec->old_master_mfact_per) /
rec->drag_begin_geom.width;
delta_y = (float)(offsety) * (rec->old_stack_inner_per) /
rec->drag_begin_geom.height;
}
bool moving_up;
bool moving_down;
if (!isdrag) {
moving_up = offsety < 0 ? true : false;
moving_down = offsety > 0 ? true : false;
} else {
moving_up = server.cursor->y < server.drag_begin_cursory;
moving_down = server.cursor->y > server.drag_begin_cursory;
}
if (rec->ismaster && !prev) {
if (moving_up) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
} else if (rec->ismaster && next && !next->ismaster) {
if (moving_up) {
delta_y = fabsf(delta_y);
} else {
delta_y = -fabsf(delta_y);
}
} else if (!rec->ismaster && prev && prev->ismaster) {
if (moving_up) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
} else if (!rec->ismaster && !next) {
if (moving_up) {
delta_y = fabsf(delta_y);
} else {
delta_y = -fabsf(delta_y);
}
} else if (type == CENTER_TILE && !rec->ismaster &&
!nextnext) {
if (moving_up) {
delta_y = fabsf(delta_y);
} else {
delta_y = -fabsf(delta_y);
}
} else if (type == CENTER_TILE && !rec->ismaster && prevprev &&
prevprev->ismaster) {
if (moving_up) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
} else if ((rec->cursor_in_upper_half && moving_up) ||
(!rec->cursor_in_upper_half && moving_down)) {
// 光标在窗口上方且向上移动,或在窗口下方且向下移动 → 增加高度
delta_y = fabsf(delta_y);
delta_y = delta_y * 2;
} else {
// 其他情况 → 减小高度
delta_y = -fabsf(delta_y);
delta_y = delta_y * 2;
}
if (!rec->ismaster && rec->isleftstack &&
type == CENTER_TILE) {
delta_x = delta_x * -1.0f;
}
if (rec->ismaster && type == CENTER_TILE &&
rec->cursor_in_left_half) {
delta_x = delta_x * -1.0f;
}
if (rec->ismaster && type == CENTER_TILE) {
delta_x = delta_x * 2;
}
if (type == RIGHT_TILE) {
delta_x = delta_x * -1.0f;
}
// 直接设置新的比例,基于初始值 + 变化量
float new_master_mfact_per =
rec->old_master_mfact_per + delta_x;
float new_master_inner_per =
rec->old_master_inner_per + delta_y;
float new_stack_inner_per = rec->old_stack_inner_per + delta_y;
// 应用限制,确保比例在合理范围内
new_master_mfact_per = fmaxf(0.1f, fminf(0.9f, new_master_mfact_per));
new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per));
new_stack_inner_per = fmaxf(0.1f, fminf(0.9f, new_stack_inner_per));
// 应用到所有平铺窗口
wl_list_for_each(tc, &server.clients, link) {
if (VISIBLEON(tc, rec->mon) && ISTILED(tc)) {
tc->master_mfact_per = new_master_mfact_per;
}
}
rec->master_inner_per = new_master_inner_per;
rec->stack_inner_per = new_stack_inner_per;
if (!isdrag) {
arrange(rec->mon, false, false);
return;
}
if (server.last_apply_drag_time == 0 ||
time - server.last_apply_drag_time > drag_tile_refresh_interval) {
arrange(rec->mon, false, false);
server.last_apply_drag_time = time;
}
}
}
void resize_tile_master_vertical(Client *rec, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time, int32_t type) {
Client *tc = NULL;
float delta_x, delta_y;
Client *next = NULL;
Client *prev = NULL;
struct wl_list *node;
// 从当前节点的下一个开始遍历
for (node = rec->link.next; node != &server.clients;
node = node->next) {
tc = wl_container_of(node, tc, link);
if (VISIBLEON(tc, rec->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
next = tc;
break;
}
}
// 从当前节点的上一个开始遍历
for (node = rec->link.prev; node != &server.clients;
node = node->prev) {
tc = wl_container_of(node, tc, link);
if (VISIBLEON(tc, rec->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
prev = tc;
break;
}
}
if (!server.start_drag_window && isdrag) {
server.drag_begin_cursorx = server.cursor->x;
server.drag_begin_cursory = server.cursor->y;
server.start_drag_window = true;
// 记录初始状态
rec->old_master_mfact_per = rec->master_mfact_per;
rec->old_master_inner_per = rec->master_inner_per;
rec->old_stack_inner_per = rec->stack_inner_per;
rec->cursor_in_upper_half =
server.cursor->y <
rec->geom.y + rec->geom.height / 2;
rec->cursor_in_left_half =
server.cursor->x <
rec->geom.x + rec->geom.width / 2;
// 记录初始几何信息
rec->drag_begin_geom = rec->geom;
} else {
// 计算相对于屏幕尺寸的比例变化
// 计算相对于屏幕尺寸的比例变化
if (isdrag) {
offsetx = server.cursor->x - server.drag_begin_cursorx;
offsety = server.cursor->y - server.drag_begin_cursory;
} else {
rec->old_master_mfact_per = rec->master_mfact_per;
rec->old_master_inner_per = rec->master_inner_per;
rec->old_stack_inner_per = rec->stack_inner_per;
rec->drag_begin_geom = rec->geom;
rec->cursor_in_upper_half = true;
rec->cursor_in_left_half = false;
}
if (rec->ismaster) {
// 垂直版本:左右移动调整高度比例,上下移动调整宽度比例
delta_x = (float)(offsetx) * (rec->old_master_inner_per) /
rec->drag_begin_geom.width;
delta_y = (float)(offsety) * (rec->old_master_mfact_per) /
rec->drag_begin_geom.height;
} else {
delta_x = (float)(offsetx) * (rec->old_stack_inner_per) /
rec->drag_begin_geom.width;
delta_y = (float)(offsety) *
(1 - rec->old_master_mfact_per) /
rec->drag_begin_geom.height;
}
bool moving_left;
bool moving_right;
if (!isdrag) {
moving_left = offsetx < 0 ? true : false;
moving_right = offsetx > 0 ? true : false;
} else {
moving_left = server.cursor->x < server.drag_begin_cursorx;
moving_right = server.cursor->x > server.drag_begin_cursorx;
}
// 调整主区域和栈区域的高度比例(垂直分割)
if (rec->ismaster && !prev) {
if (moving_left) {
delta_x = -fabsf(delta_x); // 向上移动减少主区域高度
} else {
delta_x = fabsf(delta_x); // 向下移动增加主区域高度
}
} else if (rec->ismaster && next && !next->ismaster) {
if (moving_left) {
delta_x = fabsf(delta_x); // 向上移动增加主区域高度
} else {
delta_x = -fabsf(delta_x); // 向下移动减少主区域高度
}
} else if (!rec->ismaster && prev && prev->ismaster) {
if (moving_left) {
delta_x = -fabsf(delta_x); // 向上移动减少栈区域高度
} else {
delta_x = fabsf(delta_x); // 向下移动增加栈区域高度
}
} else if (!rec->ismaster && !next) {
if (moving_left) {
delta_x = fabsf(delta_x); // 向上移动增加栈区域高度
} else {
delta_x = -fabsf(delta_x); // 向下移动减少栈区域高度
}
} else if ((rec->cursor_in_left_half && moving_left) ||
(!rec->cursor_in_left_half && moving_right)) {
// 光标在窗口左侧且向左移动,或在窗口右侧且向右移动 → 增加宽度
delta_x = fabsf(delta_x);
delta_x = delta_x * 2;
} else {
// 其他情况 → 减小宽度
delta_x = -fabsf(delta_x);
delta_x = delta_x * 2;
}
// 直接设置新的比例,基于初始值 + 变化量
float new_master_mfact_per = rec->old_master_mfact_per +
delta_y; // 垂直delta_y调整主区域高度
float new_master_inner_per = rec->old_master_inner_per +
delta_x; // 垂直delta_x调整主区域内部宽度
float new_stack_inner_per = rec->old_stack_inner_per +
delta_x; // 垂直delta_x调整栈区域内部宽度
// 应用限制,确保比例在合理范围内
new_master_mfact_per = fmaxf(0.1f, fminf(0.9f, new_master_mfact_per));
new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per));
new_stack_inner_per = fmaxf(0.1f, fminf(0.9f, new_stack_inner_per));
// 应用到所有平铺窗口
wl_list_for_each(tc, &server.clients, link) {
if (VISIBLEON(tc, rec->mon) && ISTILED(tc)) {
tc->master_mfact_per = new_master_mfact_per;
}
}
rec->master_inner_per = new_master_inner_per;
rec->stack_inner_per = new_stack_inner_per;
if (!isdrag) {
arrange(rec->mon, false, false);
return;
}
if (server.last_apply_drag_time == 0 ||
time - server.last_apply_drag_time > drag_tile_refresh_interval) {
arrange(rec->mon, false, false);
server.last_apply_drag_time = time;
}
}
}
void resize_tile_scroller(Client *rec, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time, bool isvertical) {
float delta_x, delta_y;
float new_scroller_proportion;
float new_stack_proportion;
Client *stack_head = get_scroll_stack_head(rec);
if (rec && rec->mon->visible_tiling_clients == 1 &&
!scroller_ignore_proportion_single)
return;
if (!server.start_drag_window && isdrag) {
server.drag_begin_cursorx = server.cursor->x;
server.drag_begin_cursory = server.cursor->y;
server.start_drag_window = true;
// 记录初始状态
stack_head->old_scroller_pproportion = stack_head->scroller_proportion;
rec->old_stack_proportion = rec->stack_proportion;
rec->cursor_in_left_half =
server.cursor->x <
rec->geom.x + rec->geom.width / 2;
rec->cursor_in_upper_half =
server.cursor->y <
rec->geom.y + rec->geom.height / 2;
// 记录初始几何信息
rec->drag_begin_geom = rec->geom;
} else {
// 计算相对于屏幕尺寸的比例变化
// 计算相对于屏幕尺寸的比例变化
if (isdrag) {
offsetx = server.cursor->x - server.drag_begin_cursorx;
offsety = server.cursor->y - server.drag_begin_cursory;
} else {
rec->old_master_mfact_per = rec->master_mfact_per;
rec->old_master_inner_per = rec->master_inner_per;
rec->old_stack_inner_per = rec->stack_inner_per;
rec->drag_begin_geom = rec->geom;
stack_head->old_scroller_pproportion =
stack_head->scroller_proportion;
rec->old_stack_proportion = rec->stack_proportion;
rec->cursor_in_upper_half = false;
rec->cursor_in_left_half = false;
}
if (isvertical) {
delta_y = (float)(offsety) *
(stack_head->old_scroller_pproportion) /
rec->drag_begin_geom.height;
delta_x = (float)(offsetx) * (rec->old_stack_proportion) /
rec->drag_begin_geom.width;
} else {
delta_x = (float)(offsetx) *
(stack_head->old_scroller_pproportion) /
rec->drag_begin_geom.width;
delta_y = (float)(offsety) * (rec->old_stack_proportion) /
rec->drag_begin_geom.height;
}
bool moving_up;
bool moving_down;
bool moving_left;
bool moving_right;
if (!isdrag) {
moving_up = offsety < 0 ? true : false;
moving_down = offsety > 0 ? true : false;
moving_left = offsetx < 0 ? true : false;
moving_right = offsetx > 0 ? true : false;
} else {
moving_up = server.cursor->y < server.drag_begin_cursory;
moving_down = server.cursor->y > server.drag_begin_cursory;
moving_left = server.cursor->x < server.drag_begin_cursorx;
moving_right = server.cursor->x > server.drag_begin_cursorx;
}
if ((rec->cursor_in_upper_half && moving_up) ||
(!rec->cursor_in_upper_half && moving_down)) {
// 光标在窗口上方且向上移动,或在窗口下方且向下移动 → 增加高度
delta_y = fabsf(delta_y);
} else {
// 其他情况 → 减小高度
delta_y = -fabsf(delta_y);
}
if ((rec->cursor_in_left_half && moving_left) ||
(!rec->cursor_in_left_half && moving_right)) {
delta_x = fabsf(delta_x);
} else {
delta_x = -fabsf(delta_x);
}
if (isvertical) {
if (!rec->next_in_stack && rec->prev_in_stack &&
!isdrag) {
delta_x = delta_x * -1.0f;
}
if (!rec->next_in_stack && rec->prev_in_stack &&
isdrag) {
if (moving_right) {
delta_x = -fabsf(delta_x);
} else {
delta_x = fabsf(delta_x);
}
}
if (!rec->prev_in_stack && rec->next_in_stack &&
isdrag) {
if (moving_left) {
delta_x = -fabsf(delta_x);
} else {
delta_x = fabsf(delta_x);
}
}
if (isdrag) {
if (moving_up) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
}
} else {
if (!rec->next_in_stack && rec->prev_in_stack &&
!isdrag) {
delta_y = delta_y * -1.0f;
}
if (!rec->next_in_stack && rec->prev_in_stack &&
isdrag) {
if (moving_down) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
}
if (!rec->prev_in_stack && rec->next_in_stack &&
isdrag) {
if (moving_up) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
}
if (isdrag) {
if (moving_left) {
delta_x = -fabsf(delta_x);
} else {
delta_x = fabsf(delta_x);
}
}
}
// 直接设置新的比例,基于初始值 + 变化量
if (isvertical) {
new_scroller_proportion =
stack_head->old_scroller_pproportion + delta_y;
new_stack_proportion = rec->old_stack_proportion + delta_x;
} else {
new_scroller_proportion =
stack_head->old_scroller_pproportion + delta_x;
new_stack_proportion = rec->old_stack_proportion + delta_y;
}
// 应用限制,确保比例在合理范围内
new_scroller_proportion =
fmaxf(0.1f, fminf(1.0f, new_scroller_proportion));
new_stack_proportion = fmaxf(0.1f, fminf(1.0f, new_stack_proportion));
rec->stack_proportion = new_stack_proportion;
stack_head->scroller_proportion = new_scroller_proportion;
if (!isdrag) {
arrange(rec->mon, false, false);
return;
}
if (server.last_apply_drag_time == 0 ||
time - server.last_apply_drag_time > drag_tile_refresh_interval) {
arrange(rec->mon, false, false);
server.last_apply_drag_time = time;
}
}
}
void resize_tile_client(Client *rec, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time) {
if (!rec || rec->isfullscreen ||
rec->ismaximizescreen)
return;
if (rec->mon->isoverview)
return;
const Layout *current_layout =
rec->mon->pertag->ltidxs[rec->mon->pertag->curtag];
if (current_layout->id == TILE || current_layout->id == DECK ||
current_layout->id == CENTER_TILE || current_layout->id == RIGHT_TILE ||
(current_layout->id == TGMIX &&
rec->mon->visible_tiling_clients <= 3)
) {
resize_tile_master_horizontal(rec, isdrag, offsetx, offsety,
time, current_layout->id);
} else if (current_layout->id == VERTICAL_TILE ||
current_layout->id == VERTICAL_DECK) {
resize_tile_master_vertical(rec, isdrag, offsetx, offsety,
time, current_layout->id);
} else if (current_layout->id == SCROLLER) {
resize_tile_scroller(rec, isdrag, offsetx, offsety, time,
false);
} else if (current_layout->id == VERTICAL_SCROLLER) {
resize_tile_scroller(rec, isdrag, offsetx, offsety, time,
true);
}
}
void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num,
double total_left_stack_hight_percent,
double total_right_stack_hight_percent,
double total_stack_hight_percent,
double total_master_inner_percent, int32_t master_num,
int32_t stack_num) {
Client *c = NULL;
int32_t i = 0;
uint32_t stack_index = 0;
uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag];
if (m->pertag->ltidxs[m->pertag->curtag]->id != CENTER_TILE) {
wl_list_for_each(c, &server.clients, link) {
if (VISIBLEON(c, m) && ISTILED(c)) {
if (total_master_inner_percent > 0.0 && i < nmasters) {
c->ismaster = true;
c->stack_inner_per = stack_num ? 1.0f / stack_num : 1.0f;
c->master_inner_per =
c->master_inner_per / total_master_inner_percent;
} else {
c->ismaster = false;
c->master_inner_per =
master_num > 0 ? 1.0f / master_num : 1.0f;
c->stack_inner_per =
total_stack_hight_percent
? c->stack_inner_per / total_stack_hight_percent
: 1.0f;
}
i++;
}
}
} else {
wl_list_for_each(c, &server.clients, link) {
if (VISIBLEON(c, m) && ISTILED(c)) {
if (total_master_inner_percent > 0.0 && i < nmasters) {
c->ismaster = true;
if ((stack_index % 2) ^ (tile_cilent_num % 2 == 0)) {
c->stack_inner_per =
stack_num > 1 ? 1.0f / ((stack_num - 1) / 2) : 1.0f;
} else {
c->stack_inner_per =
stack_num > 1 ? 2.0f / stack_num : 1.0f;
}
c->master_inner_per =
c->master_inner_per / total_master_inner_percent;
} else {
stack_index = i - nmasters;
c->ismaster = false;
c->master_inner_per =
master_num > 0 ? 1.0f / master_num : 1.0f;
if ((stack_index % 2) ^ (tile_cilent_num % 2 == 0)) {
c->stack_inner_per =
total_right_stack_hight_percent
? c->stack_inner_per /
total_right_stack_hight_percent
: 1.0f;
} else {
c->stack_inner_per =
total_left_stack_hight_percent
? c->stack_inner_per /
total_left_stack_hight_percent
: 1.0f;
}
}
i++;
}
}
}
}
void resize_floating_window(Client *rec) {
int cdx = (int)round(server.cursor->x) - server.grabcx;
int cdy = (int)round(server.cursor->y) - server.grabcy;
cdx = !(server.rzcorner & 1) &&
rec->geom.width - 2 * (int)rec->bw - cdx < 1
? 0
: cdx;
cdy =
!(server.rzcorner & 2) &&
rec->geom.height - 2 * (int)rec->bw - cdy < 1
? 0
: cdy;
const struct wlr_box box = {
.x = rec->geom.x + (server.rzcorner & 1 ? 0 : cdx),
.y = rec->geom.y + (server.rzcorner & 2 ? 0 : cdy),
.width = rec->geom.width + (server.rzcorner & 1 ? cdx : -cdx),
.height =
rec->geom.height + (server.rzcorner & 2 ? cdy : -cdy)};
rec->float_geom = box;
resize(rec, box, 1);
server.grabcx += cdx;
server.grabcy += cdy;
}
void // 17
arrange(Monitor *m, bool want_animation, bool from_view) {
Client *c = NULL;
double total_stack_inner_percent = 0;
double total_master_inner_percent = 0;
double total_right_stack_hight_percent = 0;
double total_left_stack_hight_percent = 0;
int32_t i = 0;
int32_t nmasters = 0;
int32_t stack_index = 0;
int32_t master_num = 0;
int32_t stack_num = 0;
if (!m)
return;
if (!m->wlr_output->enabled)
return;
m->visible_clients = 0;
m->visible_tiling_clients = 0;
m->visible_scroll_tiling_clients = 0;
wl_list_for_each(c, &server.clients, link) {
if (!client_only_in_one_tag(c) || c->isglobal || c->isunglobal) {
exit_scroller_stack(c);
}
if (from_view && (c->isglobal || c->isunglobal)) {
set_size_per(m, c);
}
if (c->mon == m && (c->isglobal || c->isunglobal)) {
c->tags = m->tagset[m->seltags];
}
if (from_view && m->sel == NULL && c->isglobal && VISIBLEON(c, m)) {
focusclient(c, 1);
}
if (VISIBLEON(c, m)) {
if (from_view && !client_only_in_one_tag(c)) {
set_size_per(m, c);
}
if (!c->isunglobal)
m->visible_clients++;
if (ISTILED(c)) {
m->visible_tiling_clients++;
}
if (ISSCROLLTILED(c) && !c->prev_in_stack) {
m->visible_scroll_tiling_clients++;
}
}
}
nmasters = m->pertag->nmasters[m->pertag->curtag];
wl_list_for_each(c, &server.clients, link) {
if (c->iskilling)
continue;
if (c->mon == m) {
if (VISIBLEON(c, m)) {
if (ISTILED(c)) {
if (i < nmasters) {
master_num++;
total_master_inner_percent += c->master_inner_per;
} else {
stack_num++;
total_stack_inner_percent += c->stack_inner_per;
stack_index = i - nmasters;
if ((stack_index % 2) ^
(m->visible_tiling_clients % 2 == 0)) {
c->isleftstack = false;
total_right_stack_hight_percent +=
c->stack_inner_per;
} else {
c->isleftstack = true;
total_left_stack_hight_percent +=
c->stack_inner_per;
}
}
i++;
}
set_arrange_visible(m, c, want_animation);
} else {
set_arrange_hidden(m, c, want_animation);
}
}
if (c->mon == m && c->ismaximizescreen && !c->animation.tagouted &&
!c->animation.tagouting && VISIBLEON(c, m)) {
reset_maximizescreen_size(c);
}
}
reset_size_per_mon(
m, m->visible_tiling_clients, total_left_stack_hight_percent,
total_right_stack_hight_percent, total_stack_inner_percent,
total_master_inner_percent, master_num, stack_num);
if (m->isoverview) {
overviewlayout.arrange(m);
} else {
m->pertag->ltidxs[m->pertag->curtag]->arrange(m);
}
if (!server.start_drag_window) {
motionnotify(0, NULL, 0, 0, 0, 0);
checkidleinhibitor(NULL);
}
printstatus();
}

View file

@ -1,836 +1,37 @@
void set_size_per(Monitor *m, Client *c) {
Client *fc = NULL;
bool found = false;
#ifndef TILE_RESIZE_H
#define TILE_RESIZE_H
if (!m || !c)
return;
wl_list_for_each(fc, &server.clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) {
c->master_mfact_per = fc->master_mfact_per;
c->master_inner_per = fc->master_inner_per;
c->stack_inner_per = fc->stack_inner_per;
found = true;
break;
}
}
if (!found) {
c->master_mfact_per = m->pertag->mfacts[m->pertag->curtag];
c->master_inner_per = 1.0f;
c->stack_inner_per = 1.0f;
}
}
/* 平铺窗口大小比例设置 */
void set_size_per(Monitor *m, Client *c);
/* 水平布局平铺窗口调整 */
void resize_tile_master_horizontal(Client *rec, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time,
int32_t type) {
Client *tc = NULL;
float delta_x, delta_y;
Client *next = NULL;
Client *prev = NULL;
Client *nextnext = NULL;
Client *prevprev = NULL;
struct wl_list *node;
bool begin_find_nextnext = false;
bool begin_find_prevprev = false;
// 从当前节点的下一个开始遍历
for (node = rec->link.next; node != &server.clients;
node = node->next) {
tc = wl_container_of(node, tc, link);
if (begin_find_nextnext && VISIBLEON(tc, rec->mon) &&
ISTILED(tc)) {
nextnext = tc;
break;
}
if (!begin_find_nextnext && VISIBLEON(tc, rec->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
next = tc;
begin_find_nextnext = true;
continue;
}
}
// 从当前节点的上一个开始遍历
for (node = rec->link.prev; node != &server.clients;
node = node->prev) {
tc = wl_container_of(node, tc, link);
if (begin_find_prevprev && VISIBLEON(tc, rec->mon) &&
ISTILED(tc)) {
prevprev = tc;
break;
}
if (!begin_find_prevprev && VISIBLEON(tc, rec->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
prev = tc;
begin_find_prevprev = true;
continue;
}
}
if (!server.start_drag_window && isdrag) {
server.drag_begin_cursorx = server.cursor->x;
server.drag_begin_cursory = server.cursor->y;
server.start_drag_window = true;
// 记录初始状态
rec->old_master_mfact_per = rec->master_mfact_per;
rec->old_master_inner_per = rec->master_inner_per;
rec->old_stack_inner_per = rec->stack_inner_per;
rec->cursor_in_upper_half =
server.cursor->y <
rec->geom.y + rec->geom.height / 2;
rec->cursor_in_left_half =
server.cursor->x <
rec->geom.x + rec->geom.width / 2;
// 记录初始几何信息
rec->drag_begin_geom = rec->geom;
} else {
// 计算相对于屏幕尺寸的比例变化
if (isdrag) {
offsetx = server.cursor->x - server.drag_begin_cursorx;
offsety = server.cursor->y - server.drag_begin_cursory;
} else {
rec->old_master_mfact_per = rec->master_mfact_per;
rec->old_master_inner_per = rec->master_inner_per;
rec->old_stack_inner_per = rec->stack_inner_per;
rec->drag_begin_geom = rec->geom;
rec->cursor_in_upper_half = true;
rec->cursor_in_left_half = false;
}
if (rec->ismaster) {
delta_x = (float)(offsetx) * (rec->old_master_mfact_per) /
rec->drag_begin_geom.width;
delta_y = (float)(offsety) * (rec->old_master_inner_per) /
rec->drag_begin_geom.height;
} else {
delta_x = (float)(offsetx) *
(1 - rec->old_master_mfact_per) /
rec->drag_begin_geom.width;
delta_y = (float)(offsety) * (rec->old_stack_inner_per) /
rec->drag_begin_geom.height;
}
bool moving_up;
bool moving_down;
if (!isdrag) {
moving_up = offsety < 0 ? true : false;
moving_down = offsety > 0 ? true : false;
} else {
moving_up = server.cursor->y < server.drag_begin_cursory;
moving_down = server.cursor->y > server.drag_begin_cursory;
}
if (rec->ismaster && !prev) {
if (moving_up) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
} else if (rec->ismaster && next && !next->ismaster) {
if (moving_up) {
delta_y = fabsf(delta_y);
} else {
delta_y = -fabsf(delta_y);
}
} else if (!rec->ismaster && prev && prev->ismaster) {
if (moving_up) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
} else if (!rec->ismaster && !next) {
if (moving_up) {
delta_y = fabsf(delta_y);
} else {
delta_y = -fabsf(delta_y);
}
} else if (type == CENTER_TILE && !rec->ismaster &&
!nextnext) {
if (moving_up) {
delta_y = fabsf(delta_y);
} else {
delta_y = -fabsf(delta_y);
}
} else if (type == CENTER_TILE && !rec->ismaster && prevprev &&
prevprev->ismaster) {
if (moving_up) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
} else if ((rec->cursor_in_upper_half && moving_up) ||
(!rec->cursor_in_upper_half && moving_down)) {
// 光标在窗口上方且向上移动,或在窗口下方且向下移动 → 增加高度
delta_y = fabsf(delta_y);
delta_y = delta_y * 2;
} else {
// 其他情况 → 减小高度
delta_y = -fabsf(delta_y);
delta_y = delta_y * 2;
}
if (!rec->ismaster && rec->isleftstack &&
type == CENTER_TILE) {
delta_x = delta_x * -1.0f;
}
if (rec->ismaster && type == CENTER_TILE &&
rec->cursor_in_left_half) {
delta_x = delta_x * -1.0f;
}
if (rec->ismaster && type == CENTER_TILE) {
delta_x = delta_x * 2;
}
if (type == RIGHT_TILE) {
delta_x = delta_x * -1.0f;
}
// 直接设置新的比例,基于初始值 + 变化量
float new_master_mfact_per =
rec->old_master_mfact_per + delta_x;
float new_master_inner_per =
rec->old_master_inner_per + delta_y;
float new_stack_inner_per = rec->old_stack_inner_per + delta_y;
// 应用限制,确保比例在合理范围内
new_master_mfact_per = fmaxf(0.1f, fminf(0.9f, new_master_mfact_per));
new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per));
new_stack_inner_per = fmaxf(0.1f, fminf(0.9f, new_stack_inner_per));
// 应用到所有平铺窗口
wl_list_for_each(tc, &server.clients, link) {
if (VISIBLEON(tc, rec->mon) && ISTILED(tc)) {
tc->master_mfact_per = new_master_mfact_per;
}
}
rec->master_inner_per = new_master_inner_per;
rec->stack_inner_per = new_stack_inner_per;
if (!isdrag) {
arrange(rec->mon, false, false);
return;
}
if (server.last_apply_drag_time == 0 ||
time - server.last_apply_drag_time > drag_tile_refresh_interval) {
arrange(rec->mon, false, false);
server.last_apply_drag_time = time;
}
}
}
int32_t offsety, uint32_t time, int32_t type);
/* 垂直布局平铺窗口调整 */
void resize_tile_master_vertical(Client *rec, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time, int32_t type) {
Client *tc = NULL;
float delta_x, delta_y;
Client *next = NULL;
Client *prev = NULL;
struct wl_list *node;
// 从当前节点的下一个开始遍历
for (node = rec->link.next; node != &server.clients;
node = node->next) {
tc = wl_container_of(node, tc, link);
if (VISIBLEON(tc, rec->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
next = tc;
break;
}
}
// 从当前节点的上一个开始遍历
for (node = rec->link.prev; node != &server.clients;
node = node->prev) {
tc = wl_container_of(node, tc, link);
if (VISIBLEON(tc, rec->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
prev = tc;
break;
}
}
if (!server.start_drag_window && isdrag) {
server.drag_begin_cursorx = server.cursor->x;
server.drag_begin_cursory = server.cursor->y;
server.start_drag_window = true;
// 记录初始状态
rec->old_master_mfact_per = rec->master_mfact_per;
rec->old_master_inner_per = rec->master_inner_per;
rec->old_stack_inner_per = rec->stack_inner_per;
rec->cursor_in_upper_half =
server.cursor->y <
rec->geom.y + rec->geom.height / 2;
rec->cursor_in_left_half =
server.cursor->x <
rec->geom.x + rec->geom.width / 2;
// 记录初始几何信息
rec->drag_begin_geom = rec->geom;
} else {
// 计算相对于屏幕尺寸的比例变化
// 计算相对于屏幕尺寸的比例变化
if (isdrag) {
offsetx = server.cursor->x - server.drag_begin_cursorx;
offsety = server.cursor->y - server.drag_begin_cursory;
} else {
rec->old_master_mfact_per = rec->master_mfact_per;
rec->old_master_inner_per = rec->master_inner_per;
rec->old_stack_inner_per = rec->stack_inner_per;
rec->drag_begin_geom = rec->geom;
rec->cursor_in_upper_half = true;
rec->cursor_in_left_half = false;
}
if (rec->ismaster) {
// 垂直版本:左右移动调整高度比例,上下移动调整宽度比例
delta_x = (float)(offsetx) * (rec->old_master_inner_per) /
rec->drag_begin_geom.width;
delta_y = (float)(offsety) * (rec->old_master_mfact_per) /
rec->drag_begin_geom.height;
} else {
delta_x = (float)(offsetx) * (rec->old_stack_inner_per) /
rec->drag_begin_geom.width;
delta_y = (float)(offsety) *
(1 - rec->old_master_mfact_per) /
rec->drag_begin_geom.height;
}
bool moving_left;
bool moving_right;
if (!isdrag) {
moving_left = offsetx < 0 ? true : false;
moving_right = offsetx > 0 ? true : false;
} else {
moving_left = server.cursor->x < server.drag_begin_cursorx;
moving_right = server.cursor->x > server.drag_begin_cursorx;
}
// 调整主区域和栈区域的高度比例(垂直分割)
if (rec->ismaster && !prev) {
if (moving_left) {
delta_x = -fabsf(delta_x); // 向上移动减少主区域高度
} else {
delta_x = fabsf(delta_x); // 向下移动增加主区域高度
}
} else if (rec->ismaster && next && !next->ismaster) {
if (moving_left) {
delta_x = fabsf(delta_x); // 向上移动增加主区域高度
} else {
delta_x = -fabsf(delta_x); // 向下移动减少主区域高度
}
} else if (!rec->ismaster && prev && prev->ismaster) {
if (moving_left) {
delta_x = -fabsf(delta_x); // 向上移动减少栈区域高度
} else {
delta_x = fabsf(delta_x); // 向下移动增加栈区域高度
}
} else if (!rec->ismaster && !next) {
if (moving_left) {
delta_x = fabsf(delta_x); // 向上移动增加栈区域高度
} else {
delta_x = -fabsf(delta_x); // 向下移动减少栈区域高度
}
} else if ((rec->cursor_in_left_half && moving_left) ||
(!rec->cursor_in_left_half && moving_right)) {
// 光标在窗口左侧且向左移动,或在窗口右侧且向右移动 → 增加宽度
delta_x = fabsf(delta_x);
delta_x = delta_x * 2;
} else {
// 其他情况 → 减小宽度
delta_x = -fabsf(delta_x);
delta_x = delta_x * 2;
}
// 直接设置新的比例,基于初始值 + 变化量
float new_master_mfact_per = rec->old_master_mfact_per +
delta_y; // 垂直delta_y调整主区域高度
float new_master_inner_per = rec->old_master_inner_per +
delta_x; // 垂直delta_x调整主区域内部宽度
float new_stack_inner_per = rec->old_stack_inner_per +
delta_x; // 垂直delta_x调整栈区域内部宽度
// 应用限制,确保比例在合理范围内
new_master_mfact_per = fmaxf(0.1f, fminf(0.9f, new_master_mfact_per));
new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per));
new_stack_inner_per = fmaxf(0.1f, fminf(0.9f, new_stack_inner_per));
// 应用到所有平铺窗口
wl_list_for_each(tc, &server.clients, link) {
if (VISIBLEON(tc, rec->mon) && ISTILED(tc)) {
tc->master_mfact_per = new_master_mfact_per;
}
}
rec->master_inner_per = new_master_inner_per;
rec->stack_inner_per = new_stack_inner_per;
if (!isdrag) {
arrange(rec->mon, false, false);
return;
}
if (server.last_apply_drag_time == 0 ||
time - server.last_apply_drag_time > drag_tile_refresh_interval) {
arrange(rec->mon, false, false);
server.last_apply_drag_time = time;
}
}
}
int32_t offsety, uint32_t time, int32_t type);
/* 滚动布局平铺窗口调整 */
void resize_tile_scroller(Client *rec, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time, bool isvertical) {
float delta_x, delta_y;
float new_scroller_proportion;
float new_stack_proportion;
Client *stack_head = get_scroll_stack_head(rec);
if (rec && rec->mon->visible_tiling_clients == 1 &&
!scroller_ignore_proportion_single)
return;
if (!server.start_drag_window && isdrag) {
server.drag_begin_cursorx = server.cursor->x;
server.drag_begin_cursory = server.cursor->y;
server.start_drag_window = true;
// 记录初始状态
stack_head->old_scroller_pproportion = stack_head->scroller_proportion;
rec->old_stack_proportion = rec->stack_proportion;
rec->cursor_in_left_half =
server.cursor->x <
rec->geom.x + rec->geom.width / 2;
rec->cursor_in_upper_half =
server.cursor->y <
rec->geom.y + rec->geom.height / 2;
// 记录初始几何信息
rec->drag_begin_geom = rec->geom;
} else {
// 计算相对于屏幕尺寸的比例变化
// 计算相对于屏幕尺寸的比例变化
if (isdrag) {
offsetx = server.cursor->x - server.drag_begin_cursorx;
offsety = server.cursor->y - server.drag_begin_cursory;
} else {
rec->old_master_mfact_per = rec->master_mfact_per;
rec->old_master_inner_per = rec->master_inner_per;
rec->old_stack_inner_per = rec->stack_inner_per;
rec->drag_begin_geom = rec->geom;
stack_head->old_scroller_pproportion =
stack_head->scroller_proportion;
rec->old_stack_proportion = rec->stack_proportion;
rec->cursor_in_upper_half = false;
rec->cursor_in_left_half = false;
}
if (isvertical) {
delta_y = (float)(offsety) *
(stack_head->old_scroller_pproportion) /
rec->drag_begin_geom.height;
delta_x = (float)(offsetx) * (rec->old_stack_proportion) /
rec->drag_begin_geom.width;
} else {
delta_x = (float)(offsetx) *
(stack_head->old_scroller_pproportion) /
rec->drag_begin_geom.width;
delta_y = (float)(offsety) * (rec->old_stack_proportion) /
rec->drag_begin_geom.height;
}
bool moving_up;
bool moving_down;
bool moving_left;
bool moving_right;
if (!isdrag) {
moving_up = offsety < 0 ? true : false;
moving_down = offsety > 0 ? true : false;
moving_left = offsetx < 0 ? true : false;
moving_right = offsetx > 0 ? true : false;
} else {
moving_up = server.cursor->y < server.drag_begin_cursory;
moving_down = server.cursor->y > server.drag_begin_cursory;
moving_left = server.cursor->x < server.drag_begin_cursorx;
moving_right = server.cursor->x > server.drag_begin_cursorx;
}
if ((rec->cursor_in_upper_half && moving_up) ||
(!rec->cursor_in_upper_half && moving_down)) {
// 光标在窗口上方且向上移动,或在窗口下方且向下移动 → 增加高度
delta_y = fabsf(delta_y);
} else {
// 其他情况 → 减小高度
delta_y = -fabsf(delta_y);
}
if ((rec->cursor_in_left_half && moving_left) ||
(!rec->cursor_in_left_half && moving_right)) {
delta_x = fabsf(delta_x);
} else {
delta_x = -fabsf(delta_x);
}
if (isvertical) {
if (!rec->next_in_stack && rec->prev_in_stack &&
!isdrag) {
delta_x = delta_x * -1.0f;
}
if (!rec->next_in_stack && rec->prev_in_stack &&
isdrag) {
if (moving_right) {
delta_x = -fabsf(delta_x);
} else {
delta_x = fabsf(delta_x);
}
}
if (!rec->prev_in_stack && rec->next_in_stack &&
isdrag) {
if (moving_left) {
delta_x = -fabsf(delta_x);
} else {
delta_x = fabsf(delta_x);
}
}
if (isdrag) {
if (moving_up) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
}
} else {
if (!rec->next_in_stack && rec->prev_in_stack &&
!isdrag) {
delta_y = delta_y * -1.0f;
}
if (!rec->next_in_stack && rec->prev_in_stack &&
isdrag) {
if (moving_down) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
}
if (!rec->prev_in_stack && rec->next_in_stack &&
isdrag) {
if (moving_up) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
}
if (isdrag) {
if (moving_left) {
delta_x = -fabsf(delta_x);
} else {
delta_x = fabsf(delta_x);
}
}
}
// 直接设置新的比例,基于初始值 + 变化量
if (isvertical) {
new_scroller_proportion =
stack_head->old_scroller_pproportion + delta_y;
new_stack_proportion = rec->old_stack_proportion + delta_x;
} else {
new_scroller_proportion =
stack_head->old_scroller_pproportion + delta_x;
new_stack_proportion = rec->old_stack_proportion + delta_y;
}
// 应用限制,确保比例在合理范围内
new_scroller_proportion =
fmaxf(0.1f, fminf(1.0f, new_scroller_proportion));
new_stack_proportion = fmaxf(0.1f, fminf(1.0f, new_stack_proportion));
rec->stack_proportion = new_stack_proportion;
stack_head->scroller_proportion = new_scroller_proportion;
if (!isdrag) {
arrange(rec->mon, false, false);
return;
}
if (server.last_apply_drag_time == 0 ||
time - server.last_apply_drag_time > drag_tile_refresh_interval) {
arrange(rec->mon, false, false);
server.last_apply_drag_time = time;
}
}
}
int32_t offsety, uint32_t time, bool isvertical);
/* 通用平铺窗口调整入口函数 */
void resize_tile_client(Client *rec, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time) {
if (!rec || rec->isfullscreen ||
rec->ismaximizescreen)
return;
if (rec->mon->isoverview)
return;
const Layout *current_layout =
rec->mon->pertag->ltidxs[rec->mon->pertag->curtag];
if (current_layout->id == TILE || current_layout->id == DECK ||
current_layout->id == CENTER_TILE || current_layout->id == RIGHT_TILE ||
(current_layout->id == TGMIX &&
rec->mon->visible_tiling_clients <= 3)
) {
resize_tile_master_horizontal(rec, isdrag, offsetx, offsety,
time, current_layout->id);
} else if (current_layout->id == VERTICAL_TILE ||
current_layout->id == VERTICAL_DECK) {
resize_tile_master_vertical(rec, isdrag, offsetx, offsety,
time, current_layout->id);
} else if (current_layout->id == SCROLLER) {
resize_tile_scroller(rec, isdrag, offsetx, offsety, time,
false);
} else if (current_layout->id == VERTICAL_SCROLLER) {
resize_tile_scroller(rec, isdrag, offsetx, offsety, time,
true);
}
}
int32_t offsety, uint32_t time);
/* 重置显示器上所有平铺窗口的比例 */
void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num,
double total_left_stack_hight_percent,
double total_right_stack_hight_percent,
double total_stack_hight_percent,
double total_master_inner_percent, int32_t master_num,
int32_t stack_num) {
Client *c = NULL;
int32_t i = 0;
uint32_t stack_index = 0;
uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag];
int32_t stack_num);
if (m->pertag->ltidxs[m->pertag->curtag]->id != CENTER_TILE) {
/* 浮动窗口调整大小 */
void resize_floating_window(Client *rec);
wl_list_for_each(c, &server.clients, link) {
if (VISIBLEON(c, m) && ISTILED(c)) {
if (total_master_inner_percent > 0.0 && i < nmasters) {
c->ismaster = true;
c->stack_inner_per = stack_num ? 1.0f / stack_num : 1.0f;
c->master_inner_per =
c->master_inner_per / total_master_inner_percent;
} else {
c->ismaster = false;
c->master_inner_per =
master_num > 0 ? 1.0f / master_num : 1.0f;
c->stack_inner_per =
total_stack_hight_percent
? c->stack_inner_per / total_stack_hight_percent
: 1.0f;
}
i++;
}
}
} else {
wl_list_for_each(c, &server.clients, link) {
if (VISIBLEON(c, m) && ISTILED(c)) {
if (total_master_inner_percent > 0.0 && i < nmasters) {
c->ismaster = true;
if ((stack_index % 2) ^ (tile_cilent_num % 2 == 0)) {
c->stack_inner_per =
stack_num > 1 ? 1.0f / ((stack_num - 1) / 2) : 1.0f;
/* 排列显示器上的所有窗口 */
void arrange(Monitor *m, bool want_animation, bool from_view);
} else {
c->stack_inner_per =
stack_num > 1 ? 2.0f / stack_num : 1.0f;
}
c->master_inner_per =
c->master_inner_per / total_master_inner_percent;
} else {
stack_index = i - nmasters;
c->ismaster = false;
c->master_inner_per =
master_num > 0 ? 1.0f / master_num : 1.0f;
if ((stack_index % 2) ^ (tile_cilent_num % 2 == 0)) {
c->stack_inner_per =
total_right_stack_hight_percent
? c->stack_inner_per /
total_right_stack_hight_percent
: 1.0f;
} else {
c->stack_inner_per =
total_left_stack_hight_percent
? c->stack_inner_per /
total_left_stack_hight_percent
: 1.0f;
}
}
i++;
}
}
}
}
void resize_floating_window(Client *rec) {
int cdx = (int)round(server.cursor->x) - server.grabcx;
int cdy = (int)round(server.cursor->y) - server.grabcy;
cdx = !(server.rzcorner & 1) &&
rec->geom.width - 2 * (int)rec->bw - cdx < 1
? 0
: cdx;
cdy =
!(server.rzcorner & 2) &&
rec->geom.height - 2 * (int)rec->bw - cdy < 1
? 0
: cdy;
const struct wlr_box box = {
.x = rec->geom.x + (server.rzcorner & 1 ? 0 : cdx),
.y = rec->geom.y + (server.rzcorner & 2 ? 0 : cdy),
.width = rec->geom.width + (server.rzcorner & 1 ? cdx : -cdx),
.height =
rec->geom.height + (server.rzcorner & 2 ? cdy : -cdy)};
rec->float_geom = box;
resize(rec, box, 1);
server.grabcx += cdx;
server.grabcy += cdy;
}
void // 17
arrange(Monitor *m, bool want_animation, bool from_view) {
Client *c = NULL;
double total_stack_inner_percent = 0;
double total_master_inner_percent = 0;
double total_right_stack_hight_percent = 0;
double total_left_stack_hight_percent = 0;
int32_t i = 0;
int32_t nmasters = 0;
int32_t stack_index = 0;
int32_t master_num = 0;
int32_t stack_num = 0;
if (!m)
return;
if (!m->wlr_output->enabled)
return;
m->visible_clients = 0;
m->visible_tiling_clients = 0;
m->visible_scroll_tiling_clients = 0;
wl_list_for_each(c, &server.clients, link) {
if (!client_only_in_one_tag(c) || c->isglobal || c->isunglobal) {
exit_scroller_stack(c);
}
if (from_view && (c->isglobal || c->isunglobal)) {
set_size_per(m, c);
}
if (c->mon == m && (c->isglobal || c->isunglobal)) {
c->tags = m->tagset[m->seltags];
}
if (from_view && m->sel == NULL && c->isglobal && VISIBLEON(c, m)) {
focusclient(c, 1);
}
if (VISIBLEON(c, m)) {
if (from_view && !client_only_in_one_tag(c)) {
set_size_per(m, c);
}
if (!c->isunglobal)
m->visible_clients++;
if (ISTILED(c)) {
m->visible_tiling_clients++;
}
if (ISSCROLLTILED(c) && !c->prev_in_stack) {
m->visible_scroll_tiling_clients++;
}
}
}
nmasters = m->pertag->nmasters[m->pertag->curtag];
wl_list_for_each(c, &server.clients, link) {
if (c->iskilling)
continue;
if (c->mon == m) {
if (VISIBLEON(c, m)) {
if (ISTILED(c)) {
if (i < nmasters) {
master_num++;
total_master_inner_percent += c->master_inner_per;
} else {
stack_num++;
total_stack_inner_percent += c->stack_inner_per;
stack_index = i - nmasters;
if ((stack_index % 2) ^
(m->visible_tiling_clients % 2 == 0)) {
c->isleftstack = false;
total_right_stack_hight_percent +=
c->stack_inner_per;
} else {
c->isleftstack = true;
total_left_stack_hight_percent +=
c->stack_inner_per;
}
}
i++;
}
set_arrange_visible(m, c, want_animation);
} else {
set_arrange_hidden(m, c, want_animation);
}
}
if (c->mon == m && c->ismaximizescreen && !c->animation.tagouted &&
!c->animation.tagouting && VISIBLEON(c, m)) {
reset_maximizescreen_size(c);
}
}
reset_size_per_mon(
m, m->visible_tiling_clients, total_left_stack_hight_percent,
total_right_stack_hight_percent, total_stack_inner_percent,
total_master_inner_percent, master_num, stack_num);
if (m->isoverview) {
overviewlayout.arrange(m);
} else {
m->pertag->ltidxs[m->pertag->curtag]->arrange(m);
}
if (!server.start_drag_window) {
motionnotify(0, NULL, 0, 0, 0, 0);
checkidleinhibitor(NULL);
}
printstatus();
}
#endif // TILE_RESIZE_H

26
src/layout/layout.c Normal file
View file

@ -0,0 +1,26 @@
#include "../type.h"
#include "layout.h"
Layout overviewlayout = {"󰃇", overview, "overview"};
Layout layouts[] = {
// 最少两个,不能删除少于两个
/* symbol arrange function name */
{"T", tile, "tile", TILE}, // 平铺布局
{"S", scroller, "scroller", SCROLLER}, // 滚动布局
{"G", grid, "grid", GRID}, // 格子布局
{"M", monocle, "monocle", MONOCLE}, // 单屏布局
{"K", deck, "deck", DECK}, // 卡片布局
{"CT", center_tile, "center_tile", CENTER_TILE}, // 居中布局
{"RT", right_tile, "right_tile", RIGHT_TILE}, // 右布局
{"VS", vertical_scroller, "vertical_scroller",
VERTICAL_SCROLLER}, // 垂直滚动布局
{"VT", vertical_tile, "vertical_tile", VERTICAL_TILE}, // 垂直平铺布局
{"VG", vertical_grid, "vertical_grid", VERTICAL_GRID}, // 垂直格子布局
{"VK", vertical_deck, "vertical_deck", VERTICAL_DECK}, // 垂直卡片布局
{"TG", tgmix, "tgmix", TGMIX}, // 混合布局
};
const uint32_t layouts_len = sizeof(layouts) / sizeof(layouts[0]);

View file

@ -1,20 +1,17 @@
static void tile(Monitor *m);
static void center_tile(Monitor *m);
static void right_tile(Monitor *m);
static void overview(Monitor *m);
static void grid(Monitor *m);
static void scroller(Monitor *m);
static void deck(Monitor *mon);
static void monocle(Monitor *m);
static void vertical_tile(Monitor *m);
static void vertical_overview(Monitor *m);
static void vertical_grid(Monitor *m);
static void vertical_scroller(Monitor *m);
static void vertical_deck(Monitor *mon);
static void tgmix(Monitor *m);
/* layout(s) */
Layout overviewlayout = {"󰃇", overview, "overview"};
void tile(Monitor *m);
void center_tile(Monitor *m);
void right_tile(Monitor *m);
void overview(Monitor *m);
void grid(Monitor *m);
void scroller(Monitor *m);
void deck(Monitor *mon);
void monocle(Monitor *m);
void vertical_tile(Monitor *m);
void vertical_overview(Monitor *m);
void vertical_grid(Monitor *m);
void vertical_scroller(Monitor *m);
void vertical_deck(Monitor *mon);
void tgmix(Monitor *m);
enum {
TILE,
@ -30,21 +27,3 @@ enum {
RIGHT_TILE,
TGMIX,
};
Layout layouts[] = {
// 最少两个,不能删除少于两个
/* symbol arrange function name */
{"T", tile, "tile", TILE}, // 平铺布局
{"S", scroller, "scroller", SCROLLER}, // 滚动布局
{"G", grid, "grid", GRID}, // 格子布局
{"M", monocle, "monocle", MONOCLE}, // 单屏布局
{"K", deck, "deck", DECK}, // 卡片布局
{"CT", center_tile, "center_tile", CENTER_TILE}, // 居中布局
{"RT", right_tile, "right_tile", RIGHT_TILE}, // 右布局
{"VS", vertical_scroller, "vertical_scroller",
VERTICAL_SCROLLER}, // 垂直滚动布局
{"VT", vertical_tile, "vertical_tile", VERTICAL_TILE}, // 垂直平铺布局
{"VG", vertical_grid, "vertical_grid", VERTICAL_GRID}, // 垂直格子布局
{"VK", vertical_deck, "vertical_deck", VERTICAL_DECK}, // 垂直卡片布局
{"TG", tgmix, "tgmix", TGMIX}, // 混合布局
};

File diff suppressed because it is too large Load diff

916
src/type.h Normal file
View file

@ -0,0 +1,916 @@
/*
* See LICENSE file for copyright and license details.
*/
#include "wlr-layer-shell-unstable-v1-protocol.h"
#include "wlr/util/box.h"
#include <getopt.h>
#include <libinput.h>
#include <limits.h>
#include <linux/input-event-codes.h>
#include <scenefx/render/fx_renderer/fx_renderer.h>
#include <scenefx/types/fx/blur_data.h>
#include <scenefx/types/fx/clipped_region.h>
#include <scenefx/types/fx/corner_location.h>
#include <scenefx/types/wlr_scene.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <wayland-server-core.h>
#include <wayland-util.h>
#include <wlr/backend.h>
#include <wlr/backend/headless.h>
#include <wlr/backend/libinput.h>
#include <wlr/backend/multi.h>
#include <wlr/backend/wayland.h>
#include <wlr/interfaces/wlr_keyboard.h>
#include <wlr/render/allocator.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_alpha_modifier_v1.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_cursor_shape_v1.h>
#include <wlr/types/wlr_data_control_v1.h>
#include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_drm.h>
#include <wlr/types/wlr_drm_lease_v1.h>
#include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_ext_data_control_v1.h>
#include <wlr/types/wlr_ext_image_capture_source_v1.h>
#include <wlr/types/wlr_ext_image_copy_capture_v1.h>
#include <wlr/types/wlr_fractional_scale_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_idle_inhibit_v1.h>
#include <wlr/types/wlr_idle_notify_v1.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_keyboard.h>
#include <wlr/types/wlr_keyboard_group.h>
#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_linux_drm_syncobj_v1.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_output_power_management_v1.h>
#include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_pointer_constraints_v1.h>
#include <wlr/types/wlr_pointer_gestures_v1.h>
#include <wlr/types/wlr_presentation_time.h>
#include <wlr/types/wlr_primary_selection.h>
#include <wlr/types/wlr_primary_selection_v1.h>
#include <wlr/types/wlr_relative_pointer_v1.h>
#include <wlr/types/wlr_screencopy_v1.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_session_lock_v1.h>
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_switch.h>
#include <wlr/types/wlr_viewporter.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/types/wlr_xdg_activation_v1.h>
#include <wlr/types/wlr_xdg_decoration_v1.h>
#include <wlr/types/wlr_xdg_foreign_registry.h>
#include <wlr/types/wlr_xdg_foreign_v1.h>
#include <wlr/types/wlr_xdg_foreign_v2.h>
#include <wlr/types/wlr_xdg_output_v1.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/log.h>
#include <wlr/util/region.h>
#include <wordexp.h>
#include <xkbcommon/xkbcommon.h>
#ifdef XWAYLAND
#include <X11/Xlib.h>
#include <wlr/xwayland.h>
#include <xcb/xcb_icccm.h>
#endif
#include "common/util.h"
/* macros */
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define GEZERO(A) ((A) >= 0 ? (A) : 0)
#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
#define INSIDEMON(A) \
(A->geom.x >= A->mon->m.x && A->geom.y >= A->mon->m.y && \
A->geom.x + A->geom.width <= A->mon->m.x + A->mon->m.width && \
A->geom.y + A->geom.height <= A->mon->m.y + A->mon->m.height)
#define GEOMINSIDEMON(A, M) \
(A->x >= M->m.x && A->y >= M->m.y && \
A->x + A->width <= M->m.x + M->m.width && \
A->y + A->height <= M->m.y + M->m.height)
#define ISTILED(A) \
(A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \
!(A)->ismaximizescreen && !(A)->isfullscreen && !(A)->isunglobal)
#define ISSCROLLTILED(A) \
(A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \
!(A)->isunglobal)
#define VISIBLEON(C, M) \
((C) && (M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define END(A) ((A) + LENGTH(A))
#define TAGMASK ((1 << LENGTH(tags)) - 1)
#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L)))
#define ISFULLSCREEN(A) \
((A)->isfullscreen || (A)->ismaximizescreen || \
(A)->overview_ismaximizescreenbak || (A)->overview_isfullscreenbak)
#define LISTEN_STATIC(E, H) \
do { \
struct wl_listener *_l = ecalloc(1, sizeof(*_l)); \
_l->notify = (H); \
wl_signal_add((E), _l); \
} while (0)
#define APPLY_INT_PROP(obj, rule, prop) \
if (rule->prop >= 0) \
obj->prop = rule->prop
#define APPLY_FLOAT_PROP(obj, rule, prop) \
if (rule->prop > 0.0f) \
obj->prop = rule->prop
#define APPLY_STRING_PROP(obj, rule, prop) \
if (rule->prop != NULL) \
obj->prop = rule->prop
#define BAKED_POINTS_COUNT 256
/* enums */
enum { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT };
enum { VERTICAL, HORIZONTAL };
enum { SWIPE_UP, SWIPE_DOWN, SWIPE_LEFT, SWIPE_RIGHT };
enum { CurNormal, CurPressed, CurMove, CurResize }; /* server.cursor */
enum { XDGShell, LayerShell, X11 }; /* client types */
enum { AxisUp, AxisDown, AxisLeft, AxisRight }; // 滚轮滚动的方向
enum {
LyrBg,
LyrBlur,
LyrBottom,
LyrTile,
LyrTop,
LyrFadeOut,
LyrOverlay,
LyrIMPopup, // text-input layer
LyrBlock,
NUM_LAYERS
}; /* server.scene server.layers */
#ifdef XWAYLAND
enum {
NetWMWindowTypeDialog,
NetWMWindowTypeSplash,
NetWMWindowTypeToolbar,
NetWMWindowTypeUtility,
NetLast
}; /* EWMH atoms */
#endif
enum { UP, DOWN, LEFT, RIGHT, UNDIR }; /* smartmovewin */
enum { NONE, OPEN, MOVE, CLOSE, TAG, FOCUS, OPAFADEIN, OPAFADEOUT };
enum { UNFOLD, FOLD, INVALIDFOLD };
enum { PREV, NEXT };
enum { STATE_UNSPECIFIED = 0, STATE_ENABLED, STATE_DISABLED };
enum tearing_mode {
TEARING_DISABLED = 0,
TEARING_ENABLED,
TEARING_FULLSCREEN_ONLY,
};
enum seat_config_shortcuts_inhibit {
SHORTCUTS_INHIBIT_DISABLE,
SHORTCUTS_INHIBIT_ENABLE,
};
// 事件掩码枚举
enum print_event_type {
PRINT_ACTIVE = 1 << 0,
PRINT_TAG = 1 << 1,
PRINT_LAYOUT = 1 << 2,
PRINT_TITLE = 1 << 3,
PRINT_APPID = 1 << 4,
PRINT_LAYOUT_SYMBOL = 1 << 5,
PRINT_FULLSCREEN = 1 << 6,
PRINT_FLOATING = 1 << 7,
PRINT_X = 1 << 8,
PRINT_Y = 1 << 9,
PRINT_WIDTH = 1 << 10,
PRINT_HEIGHT = 1 << 11,
PRINT_LAST_LAYER = 1 << 12,
PRINT_KB_LAYOUT = 1 << 13,
PRINT_KEYMODE = 1 << 14,
PRINT_SCALEFACTOR = 1 << 15,
PRINT_FRAME = 1 << 16,
PRINT_ALL = (1 << 17) - 1 // 所有位都设为1
};
typedef struct Pertag Pertag;
typedef struct Monitor Monitor;
typedef struct Client Client;
struct dvec2 {
double x, y;
};
struct ivec2 {
int32_t x, y, width, height;
};
typedef struct {
int32_t i;
int32_t i2;
float f;
float f2;
char *v;
char *v2;
char *v3;
uint32_t ui;
uint32_t ui2;
} Arg;
typedef struct {
char *name; // keymode名称
bool is_default; // 是否为默认模式
bool is_common; // 是否为公共模式
} KeyMode;
typedef struct {
uint32_t mod;
uint32_t button;
int32_t (*func)(const Arg *);
const Arg arg;
} Button; // 鼠标按键
typedef struct {
uint32_t mod;
uint32_t dir;
int32_t (*func)(const Arg *);
const Arg arg;
} Axis;
typedef struct {
struct wl_list link;
struct wlr_input_device *wlr_device;
struct libinput_device *libinput_device;
struct wl_listener destroy_listener; // 用于监听设备销毁事件
void *device_data; // 新增:指向设备特定数据(如 Switch
} InputDevice;
typedef struct {
struct wl_list link;
struct wlr_switch *wlr_switch;
struct wl_listener toggle;
InputDevice *input_dev;
} Switch;
struct dwl_animation {
bool should_animate;
bool running;
bool tagining;
bool tagouted;
bool tagouting;
bool begin_fade_in;
bool tag_from_rule;
uint32_t time_started;
uint32_t duration;
struct wlr_box initial;
struct wlr_box current;
int32_t action;
};
struct dwl_opacity_animation {
bool running;
float current_opacity;
float target_opacity;
float initial_opacity;
uint32_t time_started;
uint32_t duration;
float current_border_color[4];
float target_border_color[4];
float initial_border_color[4];
};
typedef struct {
float width_scale;
float height_scale;
int32_t width;
int32_t height;
enum corner_location corner_location;
bool should_scale;
} BufferData;
struct Client {
/* Must keep these three elements in this order */
uint32_t type; /* XDGShell or X11* */
struct wlr_box geom, pending, float_geom, animainit_geom,
overview_backup_geom, current,
drag_begin_geom; /* layout-relative, includes border */
Monitor *mon;
struct wlr_scene_tree *scene;
struct wlr_scene_rect *border; /* top, bottom, left, right */
struct wlr_scene_shadow *shadow;
struct wlr_scene_tree *scene_surface;
struct wl_list link;
struct wl_list flink;
struct wl_list fadeout_link;
union {
struct wlr_xdg_surface *xdg;
struct wlr_xwayland_surface *xwayland;
} surface;
struct wl_listener commit;
struct wl_listener map;
struct wl_listener maximize;
struct wl_listener minimize;
struct wl_listener unmap;
struct wl_listener destroy;
struct wl_listener set_title;
struct wl_listener fullscreen;
#ifdef XWAYLAND
struct wl_listener activate;
struct wl_listener associate;
struct wl_listener dissociate;
struct wl_listener configure;
struct wl_listener set_hints;
struct wl_listener set_geometry;
#endif
uint32_t bw;
uint32_t tags, oldtags, mini_restore_tag;
bool dirty;
uint32_t configure_serial;
struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel;
int32_t isfloating, isurgent, isfullscreen, isfakefullscreen,
need_float_size_reduce, isminimized, isoverlay, isnosizehint,
ignore_maximize, ignore_minimize;
int32_t ismaximizescreen;
int32_t overview_backup_bw;
int32_t fullscreen_backup_x, fullscreen_backup_y, fullscreen_backup_w,
fullscreen_backup_h;
int32_t overview_isfullscreenbak, overview_ismaximizescreenbak,
overview_isfloatingbak;
struct wlr_xdg_toplevel_decoration_v1 *decoration;
struct wl_listener foreign_activate_request;
struct wl_listener foreign_fullscreen_request;
struct wl_listener foreign_close_request;
struct wl_listener foreign_destroy;
struct wl_listener foreign_minimize_request;
struct wl_listener foreign_maximize_request;
struct wl_listener set_decoration_mode;
struct wl_listener destroy_decoration;
const char *animation_type_open;
const char *animation_type_close;
int32_t is_in_scratchpad;
int32_t iscustomsize;
int32_t iscustompos;
int32_t is_scratchpad_show;
int32_t isglobal;
int32_t isnoborder;
int32_t isnoshadow;
int32_t isnoradius;
int32_t isnoanimation;
int32_t isopensilent;
int32_t istagsilent;
int32_t iskilling;
int32_t istagswitching;
int32_t isnamedscratchpad;
bool is_pending_open_animation;
bool is_restoring_from_ov;
float scroller_proportion;
float stack_proportion;
float old_stack_proportion;
bool need_output_flush;
struct dwl_animation animation;
struct dwl_opacity_animation opacity_animation;
int32_t isterm, noswallow;
int32_t allow_csd;
int32_t force_maximize;
pid_t pid;
Client *swallowing, *swallowedby;
bool is_clip_to_hide;
bool drag_to_tile;
bool scratchpad_switching_mon;
bool fake_no_border;
int32_t nofocus;
int32_t nofadein;
int32_t nofadeout;
int32_t no_force_center;
int32_t isunglobal;
float focused_opacity;
float unfocused_opacity;
char oldmonname[128];
int32_t noblur;
double master_mfact_per, master_inner_per, stack_inner_per;
double old_master_mfact_per, old_master_inner_per, old_stack_inner_per;
double old_scroller_pproportion;
bool ismaster;
bool cursor_in_upper_half, cursor_in_left_half;
bool isleftstack;
int32_t tearing_hint;
int32_t force_tearing;
int32_t allow_shortcuts_inhibit;
float scroller_proportion_single;
bool isfocusing;
struct Client *next_in_stack;
struct Client *prev_in_stack;
};
typedef struct {
struct wl_list link;
struct wl_resource *resource;
Monitor *mon;
} DwlIpcOutput;
typedef struct {
uint32_t mod;
xkb_keysym_t keysym;
int32_t (*func)(const Arg *);
const Arg arg;
} Key;
typedef struct {
struct wlr_keyboard_group *wlr_group;
int32_t nsyms;
const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */
uint32_t mods; /* invalid if nsyms == 0 */
uint32_t keycode;
struct wl_event_source *key_repeat_source;
struct wl_listener modifiers;
struct wl_listener key;
struct wl_listener destroy;
} KeyboardGroup;
typedef struct {
struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor;
struct wl_listener destroy;
struct wl_list link;
} KeyboardShortcutsInhibitor;
typedef struct {
/* Must keep these three elements in this order */
uint32_t type; /* LayerShell */
struct wlr_box geom, current, pending, animainit_geom;
Monitor *mon;
struct wlr_scene_tree *scene;
struct wlr_scene_tree *popups;
struct wlr_scene_shadow *shadow;
struct wlr_scene_layer_surface_v1 *scene_layer;
struct wl_list link;
struct wl_list fadeout_link;
int32_t mapped;
struct wlr_layer_surface_v1 *layer_surface;
struct wl_listener destroy;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener surface_commit;
struct dwl_animation animation;
bool dirty;
int32_t noblur;
int32_t noanim;
int32_t noshadow;
char *animation_type_open;
char *animation_type_close;
bool need_output_flush;
bool being_unmapped;
} LayerSurface;
typedef struct {
const char *symbol;
void (*arrange)(Monitor *);
const char *name;
uint32_t id;
} Layout;
struct Monitor {
struct wl_list link;
struct wlr_output *wlr_output;
struct wlr_scene_output *scene_output;
struct wlr_output_state pending;
struct wl_listener frame;
struct wl_listener destroy;
struct wl_listener request_state;
struct wl_listener destroy_lock_surface;
struct wlr_session_lock_surface_v1 *lock_surface;
struct wlr_box m; /* monitor area, layout-relative */
struct wlr_box w; /* window area, layout-relative */
struct wl_list layers[4]; /* LayerSurface::link */
uint32_t seltags;
uint32_t tagset[2];
struct wl_list dwl_ipc_outputs;
int32_t gappih; /* horizontal gap between windows */
int32_t gappiv; /* vertical gap between windows */
int32_t gappoh; /* horizontal outer gaps */
int32_t gappov; /* vertical outer gaps */
Pertag *pertag;
Client *sel, *prevsel;
int32_t isoverview;
int32_t is_in_hotarea;
int32_t asleep;
uint32_t visible_clients;
uint32_t visible_tiling_clients;
uint32_t visible_scroll_tiling_clients;
struct wlr_scene_optimized_blur *blur;
char last_surface_ws_name[256];
struct wlr_ext_workspace_group_handle_v1 *ext_group;
};
typedef struct {
struct wlr_pointer_constraint_v1 *constraint;
struct wl_listener destroy;
} PointerConstraint;
typedef struct {
struct wlr_scene_tree *scene;
struct wlr_session_lock_v1 *lock;
struct wl_listener new_surface;
struct wl_listener unlock;
struct wl_listener destroy;
} SessionLock;
// 在你的头文件中(比如 server.h
// 在你的头文件中(比如 server.h
typedef struct {
// 键盘模式相关
KeyMode keymode;
// 核心 Wayland/WLRoots 对象
struct wl_display *dpy;
struct wl_event_loop *event_loop;
struct wlr_backend *backend;
struct wlr_backend *headless_backend;
struct wlr_scene *scene;
struct wlr_scene_tree *layers[NUM_LAYERS];
struct wlr_renderer *drw;
struct wlr_allocator *alloc;
struct wlr_compositor *compositor;
// Shell 相关
struct wlr_xdg_shell *xdg_shell;
struct wlr_xdg_activation_v1 *activation;
struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr;
struct wl_list clients; /* tiling order */
struct wl_list fstack; /* focus order */
struct wl_list fadeout_clients;
struct wl_list fadeout_layers;
struct wlr_idle_notifier_v1 *idle_notifier;
struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr;
struct wlr_layer_shell_v1 *layer_shell;
struct wlr_output_manager_v1 *output_mgr;
struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;
struct wlr_keyboard_shortcuts_inhibit_manager_v1
*keyboard_shortcuts_inhibit;
struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr;
struct wlr_output_power_manager_v1 *power_mgr;
struct wlr_pointer_gestures_v1 *pointer_gestures;
struct wlr_drm_lease_v1_manager *drm_lease_manager;
struct mango_print_status_manager *print_status_manager;
// 光标和输入相关
struct wlr_cursor *cursor;
struct wlr_xcursor_manager *cursor_mgr;
struct wlr_session *session;
// 界面元素
struct wlr_scene_rect *root_bg;
struct wlr_session_lock_manager_v1 *session_lock_mgr;
struct wlr_scene_rect *locked_bg;
struct wlr_session_lock_v1 *cur_lock;
struct wlr_scene_tree *drag_icon;
struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr;
struct wlr_pointer_constraints_v1 *pointer_constraints;
struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr;
struct wlr_pointer_constraint_v1 *active_constraint;
// 座位和键盘
struct wlr_seat *seat;
KeyboardGroup *kb_group;
struct wl_list inputdevices;
struct wl_list keyboard_shortcut_inhibitors;
// 布局相关
struct wlr_output_layout *output_layout;
struct wl_list mons;
Monitor *selmon;
struct wlr_box sgeom;
// 动画曲线数据
struct dvec2 *baked_points_move;
struct dvec2 *baked_points_open;
struct dvec2 *baked_points_tag;
struct dvec2 *baked_points_close;
struct dvec2 *baked_points_focus;
struct dvec2 *baked_points_opafadein;
struct dvec2 *baked_points_opafadeout;
// 事件源
struct wl_event_source *hide_source;
// 光标状态
struct {
enum wp_cursor_shape_device_v1_shape shape;
struct wlr_surface *surface;
int32_t hotspot_x;
int32_t hotspot_y;
} last_cursor;
// 各种状态变量
pid_t child_pid;
int32_t locked;
uint32_t locked_mods;
void *exclusive_focus;
uint32_t cursor_mode;
Client *grabc;
int32_t rzcorner;
int32_t grabcx, grabcy;
int32_t drag_begin_cursorx, drag_begin_cursory;
bool start_drag_window;
int32_t last_apply_drag_time;
int32_t enablegaps;
int32_t axis_apply_time;
int32_t axis_apply_dir;
int32_t scroller_focus_lock;
uint32_t swipe_fingers;
double swipe_dx;
double swipe_dy;
bool render_border;
uint32_t chvt_backup_tag;
bool allow_frame_scheduling;
char chvt_backup_selmon[32];
bool cursor_hidden;
bool tag_combo;
// 配置路径
const char *cli_config_path;
} Server;
/* function declarations */
void init_server(void);
void free_server(void);
void applybounds(
Client *c,
struct wlr_box *bbox); // 设置边界规则,能让一些窗口拥有比较适合的大小
void applyrules(Client *c); // 窗口规则应用,应用config.h中定义的窗口规则
void arrange(Monitor *m, bool want_animation,
bool from_view); // 布局函数,让窗口俺平铺规则移动和重置大小
void arrangelayer(Monitor *m, struct wl_list *list,
struct wlr_box *usable_area, int32_t exclusive);
void arrangelayers(Monitor *m);
void handle_print_status(struct wl_listener *listener, void *data);
void axisnotify(struct wl_listener *listener,
void *data); // 滚轮事件处理
void buttonpress(struct wl_listener *listener,
void *data); // 鼠标按键事件处理
int32_t ongesture(struct wlr_pointer_swipe_end_event *event);
void swipe_begin(struct wl_listener *listener, void *data);
void swipe_update(struct wl_listener *listener, void *data);
void swipe_end(struct wl_listener *listener, void *data);
void pinch_begin(struct wl_listener *listener, void *data);
void pinch_update(struct wl_listener *listener, void *data);
void pinch_end(struct wl_listener *listener, void *data);
void hold_begin(struct wl_listener *listener, void *data);
void hold_end(struct wl_listener *listener, void *data);
void checkidleinhibitor(struct wlr_surface *exclude);
void cleanup(void); // 退出清理
void cleanupmon(struct wl_listener *listener, void *data); // 退出清理
void closemon(Monitor *m);
void cleanuplisteners(void);
void toggle_hotarea(int32_t x_root, int32_t y_root); // 触发热区
void maplayersurfacenotify(struct wl_listener *listener, void *data);
void commitlayersurfacenotify(struct wl_listener *listener, void *data);
void commitnotify(struct wl_listener *listener, void *data);
void createdecoration(struct wl_listener *listener, void *data);
void createidleinhibitor(struct wl_listener *listener, void *data);
void createkeyboard(struct wlr_keyboard *keyboard);
void requestmonstate(struct wl_listener *listener, void *data);
void createlayersurface(struct wl_listener *listener, void *data);
void createlocksurface(struct wl_listener *listener, void *data);
void createmon(struct wl_listener *listener, void *data);
void createnotify(struct wl_listener *listener, void *data);
void createpointer(struct wlr_pointer *pointer);
void configure_pointer(struct libinput_device *device);
void destroyinputdevice(struct wl_listener *listener, void *data);
void createswitch(struct wlr_switch *switch_device);
void switch_toggle(struct wl_listener *listener, void *data);
void createpointerconstraint(struct wl_listener *listener, void *data);
void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
void commitpopup(struct wl_listener *listener, void *data);
void createpopup(struct wl_listener *listener, void *data);
void cursorframe(struct wl_listener *listener, void *data);
void cursorwarptohint(void);
void destroydecoration(struct wl_listener *listener, void *data);
void destroydragicon(struct wl_listener *listener, void *data);
void destroyidleinhibitor(struct wl_listener *listener, void *data);
void destroylayernodenotify(struct wl_listener *listener, void *data);
void destroylock(SessionLock *lock, int32_t unlocked);
void destroylocksurface(struct wl_listener *listener, void *data);
void destroynotify(struct wl_listener *listener, void *data);
void destroypointerconstraint(struct wl_listener *listener, void *data);
void destroysessionlock(struct wl_listener *listener, void *data);
void destroykeyboardgroup(struct wl_listener *listener, void *data);
Monitor *dirtomon(enum wlr_direction dir);
void setcursorshape(struct wl_listener *listener, void *data);
void focusclient(Client *c, int32_t lift);
void setborder_color(Client *c);
Client *focustop(Monitor *m);
void fullscreennotify(struct wl_listener *listener, void *data);
void gpureset(struct wl_listener *listener, void *data);
int32_t keyrepeat(void *data);
void inputdevice(struct wl_listener *listener, void *data);
int32_t keybinding(uint32_t state, bool locked, uint32_t mods,
xkb_keysym_t sym, uint32_t keycode);
void keypress(struct wl_listener *listener, void *data);
void keypressmod(struct wl_listener *listener, void *data);
bool keypressglobal(struct wlr_surface *last_surface,
struct wlr_keyboard *keyboard,
struct wlr_keyboard_key_event *event, uint32_t mods,
xkb_keysym_t keysym, uint32_t keycode);
void locksession(struct wl_listener *listener, void *data);
void mapnotify(struct wl_listener *listener, void *data);
void maximizenotify(struct wl_listener *listener, void *data);
void minimizenotify(struct wl_listener *listener, void *data);
void motionabsolute(struct wl_listener *listener, void *data);
void motionnotify(uint32_t time, struct wlr_input_device *device,
double sx, double sy, double sx_unaccel,
double sy_unaccel);
void motionrelative(struct wl_listener *listener, void *data);
void reset_foreign_tolevel(Client *c);
void remove_foreign_topleve(Client *c);
void add_foreign_topleve(Client *c);
void exchange_two_client(Client *c1, Client *c2);
void outputmgrapply(struct wl_listener *listener, void *data);
void outputmgrapplyortest(struct wlr_output_configuration_v1 *config,
int32_t test);
void outputmgrtest(struct wl_listener *listener, void *data);
void pointerfocus(Client *c, struct wlr_surface *surface, double sx,
double sy, uint32_t time);
void printstatus(void);
void quitsignal(int32_t signo);
void powermgrsetmode(struct wl_listener *listener, void *data);
void rendermon(struct wl_listener *listener, void *data);
void requestdecorationmode(struct wl_listener *listener, void *data);
void requestdrmlease(struct wl_listener *listener, void *data);
void requeststartdrag(struct wl_listener *listener, void *data);
void resize(Client *c, struct wlr_box geo, int32_t interact);
void run(char *startup_cmd);
void setcursor(struct wl_listener *listener, void *data);
void setfloating(Client *c, int32_t floating);
void setfakefullscreen(Client *c, int32_t fakefullscreen);
void setfullscreen(Client *c, int32_t fullscreen);
void setmaximizescreen(Client *c, int32_t maximizescreen);
void reset_maximizescreen_size(Client *c);
void setgaps(int32_t oh, int32_t ov, int32_t ih, int32_t iv);
void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus);
void setpsel(struct wl_listener *listener, void *data);
void setsel(struct wl_listener *listener, void *data);
void setup(void);
void startdrag(struct wl_listener *listener, void *data);
void unlocksession(struct wl_listener *listener, void *data);
void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
void unmapnotify(struct wl_listener *listener, void *data);
void updatemons(struct wl_listener *listener, void *data);
void updatetitle(struct wl_listener *listener, void *data);
void urgent(struct wl_listener *listener, void *data);
void view(const Arg *arg, bool want_animation);
void handlesig(int32_t signo);
void
handle_keyboard_shortcuts_inhibit_new_inhibitor(struct wl_listener *listener,
void *data);
void virtualkeyboard(struct wl_listener *listener, void *data);
void virtualpointer(struct wl_listener *listener, void *data);
void warp_cursor(const Client *c);
Monitor *xytomon(double x, double y);
void xytonode(double x, double y, struct wlr_surface **psurface,
Client **pc, LayerSurface **pl, double *nx, double *ny);
void clear_fullscreen_flag(Client *c);
pid_t getparentprocess(pid_t p);
int32_t isdescprocess(pid_t p, pid_t c);
Client *termforwin(Client *w);
void swallow(Client *c, Client *w);
void warp_cursor_to_selmon(Monitor *m);
uint32_t want_restore_fullscreen(Client *target_client);
void overview_restore(Client *c, const Arg *arg);
void overview_backup(Client *c);
void set_minimized(Client *c);
void show_scratchpad(Client *c);
void show_hide_client(Client *c);
void tag_client(const Arg *arg, Client *target_client);
struct wlr_box setclient_coordinate_center(Client *c, Monitor *m,
struct wlr_box geom,
int32_t offsetx,
int32_t offsety);
uint32_t get_tags_first_tag(uint32_t tags);
struct wlr_output_mode *
get_nearest_output_mode(struct wlr_output *output, int32_t width,
int32_t height, float refresh);
void client_commit(Client *c);
void layer_commit(LayerSurface *l);
void apply_border(Client *c);
void client_set_opacity(Client *c, double opacity);
void init_baked_points(void);
void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer,
int32_t sx, int32_t sy, void *data);
Client *direction_select(const Arg *arg);
void view_in_mon(const Arg *arg, bool want_animation, Monitor *m,
bool changefocus);
void buffer_set_effect(Client *c, BufferData buffer_data);
void snap_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer,
int32_t sx, int32_t sy, void *data);
void client_set_pending_state(Client *c);
void layer_set_pending_state(LayerSurface *l);
void set_rect_size(struct wlr_scene_rect *rect, int32_t width,
int32_t height);
Client *center_tiled_select(Monitor *m);
void handlecursoractivity(void);
int32_t hidecursor(void *data);
bool check_hit_no_border(Client *c);
void reset_keyboard_layout(void);
void client_update_oldmonname_record(Client *c, Monitor *m);
void pending_kill_client(Client *c);
uint32_t get_tags_first_tag_num(uint32_t source_tags);
void set_layer_open_animaiton(LayerSurface *l, struct wlr_box geo);
void init_fadeout_layers(LayerSurface *l);
void layer_actual_size(LayerSurface *l, int32_t *width, int32_t *height);
void get_layer_target_geometry(LayerSurface *l,
struct wlr_box *target_box);
void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer,
int32_t sx, int32_t sy, void *data);
double find_animation_curve_at(double t, int32_t type);
void apply_opacity_to_rect_nodes(Client *c, struct wlr_scene_node *node,
double animation_passed);
enum corner_location set_client_corner_location(Client *c);
double all_output_frame_duration_ms();
struct wlr_scene_tree *
wlr_scene_tree_snapshot(struct wlr_scene_node *node,
struct wlr_scene_tree *parent);
bool is_scroller_layout(Monitor *m);
bool is_centertile_layout(Monitor *m);
void create_output(struct wlr_backend *backend, void *data);
void get_layout_abbr(char *abbr, const char *full_name);
void apply_named_scratchpad(Client *target_client);
Client *get_client_by_id_or_title(const char *arg_id,
const char *arg_title);
bool switch_scratchpad_client_state(Client *c);
bool check_trackpad_disabled(struct wlr_pointer *pointer);
uint32_t get_tag_status(uint32_t tag, Monitor *m);
void enable_adaptive_sync(Monitor *m, struct wlr_output_state *state);
Client *get_next_stack_client(Client *c, bool reverse);
void set_float_malposition(Client *tc);
void set_size_per(Monitor *m, Client *c);
void resize_tile_client(Client *rec, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time);
void refresh_monitors_workspaces_status(Monitor *m);
void init_client_properties(Client *c);
float *get_border_color(Client *c);
void clear_fullscreen_and_maximized_state(Monitor *m);
void request_fresh_all_monitors(void);
Client *find_client_by_direction(Client *tc, const Arg *arg,
bool findfloating, bool ignore_align);
void exit_scroller_stack(Client *c);
Client *get_scroll_stack_head(Client *c);
bool client_only_in_one_tag(Client *c);
Client *get_focused_stack_client(Client *sc);
bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc);
#include "config/preset.h"
struct Pertag {
uint32_t curtag, prevtag; /* current and previous tag */
int32_t nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
bool no_hide[LENGTH(tags) + 1]; /* no_hide per tag */
bool no_render_border[LENGTH(tags) + 1]; /* no_render_border per tag */
const Layout
*ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */
};