feat: tearing support
This commit is contained in:
@@ -19,6 +19,7 @@ wayland_xmls = [
|
|||||||
wl_protocol_dir + '/staging/ext-image-capture-source/ext-image-capture-source-v1.xml',
|
wl_protocol_dir + '/staging/ext-image-capture-source/ext-image-capture-source-v1.xml',
|
||||||
wl_protocol_dir + '/staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml',
|
wl_protocol_dir + '/staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml',
|
||||||
wl_protocol_dir + '/staging/ext-workspace/ext-workspace-v1.xml',
|
wl_protocol_dir + '/staging/ext-workspace/ext-workspace-v1.xml',
|
||||||
|
wl_protocol_dir + '/staging/tearing-control/tearing-control-v1.xml',
|
||||||
'wlr-foreign-toplevel-management-unstable-v1.xml',
|
'wlr-foreign-toplevel-management-unstable-v1.xml',
|
||||||
'dwl-ipc-unstable-v2.xml',
|
'dwl-ipc-unstable-v2.xml',
|
||||||
'wlr-layer-shell-unstable-v1.xml',
|
'wlr-layer-shell-unstable-v1.xml',
|
||||||
|
|||||||
@@ -153,6 +153,20 @@ static inline void client_get_geometry(Client *c, struct wlr_box *geom) {
|
|||||||
*geom = c->surface.xdg->geometry;
|
*geom = c->surface.xdg->geometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Client *get_client_from_surface(struct wlr_surface *surface) {
|
||||||
|
if (!surface)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// 从 surface 的 data 指针获取 scene tree
|
||||||
|
struct wlr_scene_tree *scene_tree = surface->data;
|
||||||
|
if (!scene_tree)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// 从 scene tree 的 node data 获取 Client
|
||||||
|
Client *c = scene_tree->node.data;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
static inline Client *client_get_parent(Client *c) {
|
static inline Client *client_get_parent(Client *c) {
|
||||||
Client *p = NULL;
|
Client *p = NULL;
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ typedef struct {
|
|||||||
int isterm;
|
int isterm;
|
||||||
int allow_csd;
|
int allow_csd;
|
||||||
int force_maximize;
|
int force_maximize;
|
||||||
|
int force_tearing;
|
||||||
int noswallow;
|
int noswallow;
|
||||||
int noblur;
|
int noblur;
|
||||||
float focused_opacity;
|
float focused_opacity;
|
||||||
@@ -328,6 +329,7 @@ typedef struct {
|
|||||||
int xwayland_persistence;
|
int xwayland_persistence;
|
||||||
int syncobj_enable;
|
int syncobj_enable;
|
||||||
int adaptive_sync;
|
int adaptive_sync;
|
||||||
|
int allow_tearing;
|
||||||
|
|
||||||
struct xkb_rule_names xkb_rules;
|
struct xkb_rule_names xkb_rules;
|
||||||
|
|
||||||
@@ -1232,6 +1234,8 @@ void parse_option(Config *config, char *key, char *value) {
|
|||||||
config->syncobj_enable = atoi(value);
|
config->syncobj_enable = atoi(value);
|
||||||
} else if (strcmp(key, "adaptive_sync") == 0) {
|
} else if (strcmp(key, "adaptive_sync") == 0) {
|
||||||
config->adaptive_sync = atoi(value);
|
config->adaptive_sync = atoi(value);
|
||||||
|
} else if (strcmp(key, "allow_tearing") == 0) {
|
||||||
|
config->allow_tearing = atoi(value);
|
||||||
} else if (strcmp(key, "no_border_when_single") == 0) {
|
} else if (strcmp(key, "no_border_when_single") == 0) {
|
||||||
config->no_border_when_single = atoi(value);
|
config->no_border_when_single = atoi(value);
|
||||||
} else if (strcmp(key, "no_radius_when_single") == 0) {
|
} else if (strcmp(key, "no_radius_when_single") == 0) {
|
||||||
@@ -1673,6 +1677,7 @@ void parse_option(Config *config, char *key, char *value) {
|
|||||||
rule->isterm = -1;
|
rule->isterm = -1;
|
||||||
rule->allow_csd = -1;
|
rule->allow_csd = -1;
|
||||||
rule->force_maximize = -1;
|
rule->force_maximize = -1;
|
||||||
|
rule->force_tearing = -1;
|
||||||
rule->noswallow = -1;
|
rule->noswallow = -1;
|
||||||
rule->noblur = -1;
|
rule->noblur = -1;
|
||||||
rule->nofadein = -1;
|
rule->nofadein = -1;
|
||||||
@@ -1769,6 +1774,8 @@ void parse_option(Config *config, char *key, char *value) {
|
|||||||
rule->allow_csd = atoi(val);
|
rule->allow_csd = atoi(val);
|
||||||
} else if (strcmp(key, "force_maximize") == 0) {
|
} else if (strcmp(key, "force_maximize") == 0) {
|
||||||
rule->force_maximize = atoi(val);
|
rule->force_maximize = atoi(val);
|
||||||
|
} else if (strcmp(key, "force_tearing") == 0) {
|
||||||
|
rule->force_tearing = atoi(val);
|
||||||
} else if (strcmp(key, "noswallow") == 0) {
|
} else if (strcmp(key, "noswallow") == 0) {
|
||||||
rule->noswallow = atoi(val);
|
rule->noswallow = atoi(val);
|
||||||
} else if (strcmp(key, "noblur") == 0) {
|
} else if (strcmp(key, "noblur") == 0) {
|
||||||
@@ -2642,6 +2649,7 @@ void override_config(void) {
|
|||||||
xwayland_persistence = CLAMP_INT(config.xwayland_persistence, 0, 1);
|
xwayland_persistence = CLAMP_INT(config.xwayland_persistence, 0, 1);
|
||||||
syncobj_enable = CLAMP_INT(config.syncobj_enable, 0, 1);
|
syncobj_enable = CLAMP_INT(config.syncobj_enable, 0, 1);
|
||||||
adaptive_sync = CLAMP_INT(config.adaptive_sync, 0, 1);
|
adaptive_sync = CLAMP_INT(config.adaptive_sync, 0, 1);
|
||||||
|
allow_tearing = CLAMP_INT(config.allow_tearing, 0, 2);
|
||||||
axis_bind_apply_timeout =
|
axis_bind_apply_timeout =
|
||||||
CLAMP_INT(config.axis_bind_apply_timeout, 0, 1000);
|
CLAMP_INT(config.axis_bind_apply_timeout, 0, 1000);
|
||||||
focus_on_activate = CLAMP_INT(config.focus_on_activate, 0, 1);
|
focus_on_activate = CLAMP_INT(config.focus_on_activate, 0, 1);
|
||||||
@@ -2816,6 +2824,7 @@ void set_value_default() {
|
|||||||
config.xwayland_persistence = xwayland_persistence;
|
config.xwayland_persistence = xwayland_persistence;
|
||||||
config.syncobj_enable = syncobj_enable;
|
config.syncobj_enable = syncobj_enable;
|
||||||
config.adaptive_sync = adaptive_sync;
|
config.adaptive_sync = adaptive_sync;
|
||||||
|
config.allow_tearing = allow_tearing;
|
||||||
config.no_border_when_single = no_border_when_single;
|
config.no_border_when_single = no_border_when_single;
|
||||||
config.no_radius_when_single = no_radius_when_single;
|
config.no_radius_when_single = no_radius_when_single;
|
||||||
config.snap_distance = snap_distance;
|
config.snap_distance = snap_distance;
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ int xwayland_persistence = 1; /* xwayland persistence */
|
|||||||
int syncobj_enable = 0;
|
int syncobj_enable = 0;
|
||||||
int adaptive_sync = 0;
|
int adaptive_sync = 0;
|
||||||
double drag_refresh_interval = 30.0;
|
double drag_refresh_interval = 30.0;
|
||||||
|
int allow_tearing = TEARING_DISABLED;
|
||||||
|
|
||||||
/* keyboard */
|
/* keyboard */
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "dwl-ipc.h"
|
#include "dwl-ipc.h"
|
||||||
#include "ext-workspace.h"
|
#include "ext-workspace.h"
|
||||||
#include "foreign-toplevel.h"
|
#include "foreign-toplevel.h"
|
||||||
|
#include "tearing.h"
|
||||||
#include "text-input.h"
|
#include "text-input.h"
|
||||||
168
src/ext-protocol/tearing.h
Normal file
168
src/ext-protocol/tearing.h
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
#include <wlr/types/wlr_tearing_control_v1.h>
|
||||||
|
|
||||||
|
struct tearing_controller {
|
||||||
|
struct wlr_tearing_control_v1 *tearing_control;
|
||||||
|
struct wl_listener set_hint;
|
||||||
|
struct wl_listener destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 *data) {
|
||||||
|
struct tearing_controller *controller =
|
||||||
|
wl_container_of(listener, controller, set_hint);
|
||||||
|
Client *c = get_client_from_surface(controller->tearing_control->surface);
|
||||||
|
if (c) {
|
||||||
|
/*
|
||||||
|
* tearing_control->current is actually an enum:
|
||||||
|
* WP_TEARING_CONTROL_V1_PRESENTATION_HINT_VSYNC = 0
|
||||||
|
* WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC = 1
|
||||||
|
*
|
||||||
|
* Using it as a bool here allows us to not ship the XML.
|
||||||
|
*/
|
||||||
|
c->tearing_hint = controller->tearing_control->current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_controller_destroy(struct wl_listener *listener,
|
||||||
|
void *data) {
|
||||||
|
struct tearing_controller *controller =
|
||||||
|
wl_container_of(listener, controller, destroy);
|
||||||
|
wl_list_remove(&controller->set_hint.link);
|
||||||
|
wl_list_remove(&controller->destroy.link);
|
||||||
|
free(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_tearing_new_object(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_tearing_control_v1 *new_tearing_control = data;
|
||||||
|
|
||||||
|
enum wp_tearing_control_v1_presentation_hint hint =
|
||||||
|
wlr_tearing_control_manager_v1_surface_hint_from_surface(
|
||||||
|
tearing_control, new_tearing_control->surface);
|
||||||
|
wlr_log(WLR_DEBUG, "New presentation hint %d received for surface %p", hint,
|
||||||
|
new_tearing_control->surface);
|
||||||
|
|
||||||
|
struct tearing_controller *controller =
|
||||||
|
ecalloc(1, sizeof(struct tearing_controller));
|
||||||
|
controller->tearing_control = new_tearing_control;
|
||||||
|
|
||||||
|
controller->set_hint.notify = handle_controller_set_hint;
|
||||||
|
wl_signal_add(&new_tearing_control->events.set_hint, &controller->set_hint);
|
||||||
|
|
||||||
|
controller->destroy.notify = handle_controller_destroy;
|
||||||
|
wl_signal_add(&new_tearing_control->events.destroy, &controller->destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_tearing_frame_allow(Monitor *m) {
|
||||||
|
/* never allow tearing when disabled */
|
||||||
|
if (!allow_tearing) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Client *c = selmon->sel;
|
||||||
|
|
||||||
|
/* tearing is only allowed for the output with the active client */
|
||||||
|
if (!c || c->mon != m) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allow tearing for any window when requested or forced */
|
||||||
|
if (allow_tearing == TEARING_ENABLED) {
|
||||||
|
if (c->force_tearing == STATE_UNSPECIFIED) {
|
||||||
|
return c->tearing_hint;
|
||||||
|
} else {
|
||||||
|
return c->force_tearing == STATE_ENABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remaining tearing options apply only to full-screen windows */
|
||||||
|
if (!c->isfullscreen) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->force_tearing == STATE_UNSPECIFIED) {
|
||||||
|
/* honor the tearing hint or the fullscreen-force preference */
|
||||||
|
return c->tearing_hint || allow_tearing == TEARING_FULLSCREEN_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* honor tearing as requested by action */
|
||||||
|
return c->force_tearing == STATE_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool custom_wlr_scene_output_commit(struct wlr_scene_output *scene_output,
|
||||||
|
struct wlr_output_state *state) {
|
||||||
|
struct wlr_output *wlr_output = scene_output->output;
|
||||||
|
Monitor *m = wlr_output->data;
|
||||||
|
|
||||||
|
// 检查是否需要帧
|
||||||
|
if (!wlr_scene_output_needs_frame(scene_output)) {
|
||||||
|
wlr_log(WLR_DEBUG, "No frame needed for output %s", wlr_output->name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建输出状态
|
||||||
|
if (!wlr_scene_output_build_state(scene_output, state, NULL)) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to build output state for %s",
|
||||||
|
wlr_output->name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试撕裂翻页
|
||||||
|
if (state->tearing_page_flip) {
|
||||||
|
if (!wlr_output_test_state(wlr_output, state)) {
|
||||||
|
state->tearing_page_flip = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试提交
|
||||||
|
bool committed = wlr_output_commit_state(wlr_output, state);
|
||||||
|
|
||||||
|
// 如果启用撕裂翻页但提交失败,重试禁用撕裂翻页
|
||||||
|
if (!committed && state->tearing_page_flip) {
|
||||||
|
wlr_log(WLR_DEBUG, "Retrying commit without tearing for %s",
|
||||||
|
wlr_output->name);
|
||||||
|
state->tearing_page_flip = false;
|
||||||
|
committed = wlr_output_commit_state(wlr_output, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理状态清理
|
||||||
|
if (committed) {
|
||||||
|
wlr_log(WLR_DEBUG, "Successfully committed output %s",
|
||||||
|
wlr_output->name);
|
||||||
|
if (state == &m->pending) {
|
||||||
|
wlr_output_state_finish(&m->pending);
|
||||||
|
wlr_output_state_init(&m->pending);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to commit output %s", wlr_output->name);
|
||||||
|
// 即使提交失败,也清理状态避免积累
|
||||||
|
if (state == &m->pending) {
|
||||||
|
wlr_output_state_finish(&m->pending);
|
||||||
|
wlr_output_state_init(&m->pending);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_tear_state(Monitor *m) {
|
||||||
|
if (wlr_scene_output_needs_frame(m->scene_output)) {
|
||||||
|
wlr_output_state_init(&m->pending);
|
||||||
|
if (wlr_scene_output_build_state(m->scene_output, &m->pending, NULL)) {
|
||||||
|
struct wlr_output_state *pending = &m->pending;
|
||||||
|
pending->tearing_page_flip = true;
|
||||||
|
|
||||||
|
if (!custom_wlr_scene_output_commit(m->scene_output, pending)) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to commit output %s",
|
||||||
|
m->scene_output->output->name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to build state for output %s",
|
||||||
|
m->scene_output->output->name);
|
||||||
|
wlr_output_state_finish(&m->pending);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/mango.c
45
src/mango.c
@@ -164,6 +164,13 @@ enum { UP, DOWN, LEFT, RIGHT, UNDIR }; /* smartmovewin */
|
|||||||
enum { NONE, OPEN, MOVE, CLOSE, TAG, FOCUS };
|
enum { NONE, OPEN, MOVE, CLOSE, TAG, FOCUS };
|
||||||
enum { UNFOLD, FOLD, INVALIDFOLD };
|
enum { UNFOLD, FOLD, INVALIDFOLD };
|
||||||
enum { PREV, NEXT };
|
enum { PREV, NEXT };
|
||||||
|
enum { STATE_UNSPECIFIED = 0, STATE_ENABLED, STATE_DISABLED };
|
||||||
|
|
||||||
|
enum tearing_mode {
|
||||||
|
TEARING_DISABLED = 0,
|
||||||
|
TEARING_ENABLED,
|
||||||
|
TEARING_FULLSCREEN_ONLY,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct Pertag Pertag;
|
typedef struct Pertag Pertag;
|
||||||
typedef struct Monitor Monitor;
|
typedef struct Monitor Monitor;
|
||||||
@@ -357,6 +364,8 @@ struct Client {
|
|||||||
bool ismaster;
|
bool ismaster;
|
||||||
bool cursor_in_upper_half, cursor_in_left_half;
|
bool cursor_in_upper_half, cursor_in_left_half;
|
||||||
bool isleftstack;
|
bool isleftstack;
|
||||||
|
int tearing_hint;
|
||||||
|
int force_tearing;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -426,6 +435,7 @@ struct Monitor {
|
|||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
struct wlr_output *wlr_output;
|
struct wlr_output *wlr_output;
|
||||||
struct wlr_scene_output *scene_output;
|
struct wlr_scene_output *scene_output;
|
||||||
|
struct wlr_output_state pending;
|
||||||
struct wl_listener frame;
|
struct wl_listener frame;
|
||||||
struct wl_listener destroy;
|
struct wl_listener destroy;
|
||||||
struct wl_listener request_state;
|
struct wl_listener request_state;
|
||||||
@@ -1117,6 +1127,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) {
|
|||||||
APPLY_INT_PROP(c, r, isterm);
|
APPLY_INT_PROP(c, r, isterm);
|
||||||
APPLY_INT_PROP(c, r, allow_csd);
|
APPLY_INT_PROP(c, r, allow_csd);
|
||||||
APPLY_INT_PROP(c, r, force_maximize);
|
APPLY_INT_PROP(c, r, force_maximize);
|
||||||
|
APPLY_INT_PROP(c, r, force_tearing);
|
||||||
APPLY_INT_PROP(c, r, noswallow);
|
APPLY_INT_PROP(c, r, noswallow);
|
||||||
APPLY_INT_PROP(c, r, nofadein);
|
APPLY_INT_PROP(c, r, nofadein);
|
||||||
APPLY_INT_PROP(c, r, nofadeout);
|
APPLY_INT_PROP(c, r, nofadeout);
|
||||||
@@ -1952,6 +1963,7 @@ void cleanuplisteners(void) {
|
|||||||
wl_list_remove(&start_drag.link);
|
wl_list_remove(&start_drag.link);
|
||||||
wl_list_remove(&new_session_lock.link);
|
wl_list_remove(&new_session_lock.link);
|
||||||
wl_list_remove(&drm_lease_request.link);
|
wl_list_remove(&drm_lease_request.link);
|
||||||
|
wl_list_remove(&tearing_new_object.link);
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
wl_list_remove(&new_xwayland_surface.link);
|
wl_list_remove(&new_xwayland_surface.link);
|
||||||
wl_list_remove(&xwayland_ready.link);
|
wl_list_remove(&xwayland_ready.link);
|
||||||
@@ -2017,6 +2029,7 @@ void cleanupmon(struct wl_listener *listener, void *data) {
|
|||||||
wlr_scene_node_destroy(&m->blur->node);
|
wlr_scene_node_destroy(&m->blur->node);
|
||||||
m->blur = NULL;
|
m->blur = NULL;
|
||||||
}
|
}
|
||||||
|
m->wlr_output->data = NULL;
|
||||||
free(m->pertag);
|
free(m->pertag);
|
||||||
free(m);
|
free(m);
|
||||||
}
|
}
|
||||||
@@ -2546,6 +2559,7 @@ void createmon(struct wl_listener *listener, void *data) {
|
|||||||
|
|
||||||
m = wlr_output->data = ecalloc(1, sizeof(*m));
|
m = wlr_output->data = ecalloc(1, sizeof(*m));
|
||||||
m->wlr_output = wlr_output;
|
m->wlr_output = wlr_output;
|
||||||
|
m->wlr_output->data = m;
|
||||||
|
|
||||||
wl_list_init(&m->dwl_ipc_outputs);
|
wl_list_init(&m->dwl_ipc_outputs);
|
||||||
|
|
||||||
@@ -3538,6 +3552,7 @@ void init_client_properties(Client *c) {
|
|||||||
c->isterm = 0;
|
c->isterm = 0;
|
||||||
c->allow_csd = 0;
|
c->allow_csd = 0;
|
||||||
c->force_maximize = 0;
|
c->force_maximize = 0;
|
||||||
|
c->force_tearing = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void // old fix to 0.5
|
void // old fix to 0.5
|
||||||
@@ -4066,10 +4081,11 @@ void rendermon(struct wl_listener *listener, void *data) {
|
|||||||
|
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
bool need_more_frames = false;
|
bool need_more_frames = false;
|
||||||
|
bool frame_allow_tearing = check_tearing_frame_allow(m);
|
||||||
|
|
||||||
|
// 绘制层和淡出效果
|
||||||
for (i = 0; i < LENGTH(m->layers); i++) {
|
for (i = 0; i < LENGTH(m->layers); i++) {
|
||||||
layer_list = &m->layers[i];
|
layer_list = &m->layers[i];
|
||||||
// Draw frames for all layer
|
|
||||||
wl_list_for_each_safe(l, tmpl, layer_list, link) {
|
wl_list_for_each_safe(l, tmpl, layer_list, link) {
|
||||||
need_more_frames = layer_draw_frame(l) || need_more_frames;
|
need_more_frames = layer_draw_frame(l) || need_more_frames;
|
||||||
}
|
}
|
||||||
@@ -4083,25 +4099,34 @@ void rendermon(struct wl_listener *listener, void *data) {
|
|||||||
need_more_frames = layer_draw_fadeout_frame(l) || need_more_frames;
|
need_more_frames = layer_draw_fadeout_frame(l) || need_more_frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw frames for all clients
|
// 绘制客户端
|
||||||
wl_list_for_each(c, &clients, link) {
|
wl_list_for_each(c, &clients, link) {
|
||||||
need_more_frames = client_draw_frame(c) || need_more_frames;
|
need_more_frames = client_draw_frame(c) || need_more_frames;
|
||||||
if (!animations && c->configure_serial && !c->isfloating &&
|
if (!animations && !allow_tearing && c->configure_serial &&
|
||||||
client_is_rendered_on_mon(c, m) && !client_is_stopped(c))
|
!c->isfloating && client_is_rendered_on_mon(c, m) &&
|
||||||
|
!client_is_stopped(c)) {
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只有在需要帧时才构建和提交状态
|
||||||
|
if (allow_tearing && frame_allow_tearing) {
|
||||||
|
apply_tear_state(m);
|
||||||
|
} else {
|
||||||
wlr_scene_output_commit(m->scene_output, NULL);
|
wlr_scene_output_commit(m->scene_output, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
skip:
|
skip:
|
||||||
|
// 发送帧完成通知
|
||||||
// Send frame done notification
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
if (allow_tearing && frame_allow_tearing) {
|
||||||
|
wlr_scene_output_send_frame_done(m->scene_output, &now);
|
||||||
|
} else {
|
||||||
wlr_scene_output_send_frame_done(m->scene_output, &now);
|
wlr_scene_output_send_frame_done(m->scene_output, &now);
|
||||||
|
|
||||||
// // Clean up pending state
|
|
||||||
wlr_output_state_finish(&pending);
|
wlr_output_state_finish(&pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果需要更多帧,确保安排下一帧
|
||||||
if (need_more_frames) {
|
if (need_more_frames) {
|
||||||
request_fresh_all_monitors();
|
request_fresh_all_monitors();
|
||||||
}
|
}
|
||||||
@@ -4843,6 +4868,10 @@ void setup(void) {
|
|||||||
power_mgr = wlr_output_power_manager_v1_create(dpy);
|
power_mgr = wlr_output_power_manager_v1_create(dpy);
|
||||||
wl_signal_add(&power_mgr->events.set_mode, &output_power_mgr_set_mode);
|
wl_signal_add(&power_mgr->events.set_mode, &output_power_mgr_set_mode);
|
||||||
|
|
||||||
|
tearing_control = wlr_tearing_control_manager_v1_create(dpy, 1);
|
||||||
|
tearing_new_object.notify = handle_tearing_new_object;
|
||||||
|
wl_signal_add(&tearing_control->events.new_object, &tearing_new_object);
|
||||||
|
|
||||||
/* Creates an output layout, which a wlroots utility for working with an
|
/* Creates an output layout, which a wlroots utility for working with an
|
||||||
* arrangement of screens in a physical layout. */
|
* arrangement of screens in a physical layout. */
|
||||||
output_layout = wlr_output_layout_create(dpy);
|
output_layout = wlr_output_layout_create(dpy);
|
||||||
|
|||||||
Reference in New Issue
Block a user