mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2026-03-26 07:58:16 -04:00
test tear
This commit is contained in:
parent
05e9d149c1
commit
e72b9f4429
6 changed files with 186 additions and 12 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,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"
|
||||||
106
src/ext-protocol/tearing.h
Normal file
106
src/ext-protocol/tearing.h
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
#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;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct SendFrameDoneData {
|
||||||
|
struct timespec when;
|
||||||
|
struct Monitor *mon;
|
||||||
|
} SendFrameDoneData;
|
||||||
|
|
||||||
|
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 output_get_tearing_allowance(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_FORCED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* honor tearing as requested by action */
|
||||||
|
return c->force_tearing == STATE_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendframedoneiterator(struct wlr_scene_buffer *buffer, int x, int y,
|
||||||
|
void *user_data) {
|
||||||
|
SendFrameDoneData *data = user_data;
|
||||||
|
if (buffer->primary_output != data->mon->scene_output)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wlr_scene_buffer_send_frame_done(buffer, &data->when);
|
||||||
|
}
|
||||||
75
src/mango.c
75
src/mango.c
|
|
@ -164,6 +164,14 @@ enum { UP, DOWN, LEFT, RIGHT, UNDIR }; /* smartmovewin */
|
||||||
enum { NONE, OPEN, MOVE, CLOSE, TAG };
|
enum { NONE, OPEN, MOVE, CLOSE, TAG };
|
||||||
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,
|
||||||
|
TEARING_FULLSCREEN_FORCED,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct Pertag Pertag;
|
typedef struct Pertag Pertag;
|
||||||
typedef struct Monitor Monitor;
|
typedef struct Monitor Monitor;
|
||||||
|
|
@ -347,6 +355,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;
|
||||||
|
bool tearing_hint;
|
||||||
|
bool force_tearing;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -1940,6 +1950,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);
|
||||||
|
|
@ -4078,10 +4089,27 @@ 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 skip_commit = false; // 新增:控制是否跳过提交
|
||||||
|
|
||||||
|
struct wlr_scene_output *scene_output = m->scene_output;
|
||||||
|
SendFrameDoneData frame_done_data = {0};
|
||||||
|
|
||||||
|
m->wlr_output->frame_pending = false;
|
||||||
|
|
||||||
|
if (!wlr_scene_output_needs_frame(scene_output)) {
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 初始化输出状态
|
||||||
|
wlr_output_state_init(&pending);
|
||||||
|
if (!wlr_scene_output_build_state(m->scene_output, &pending, NULL)) {
|
||||||
|
wlr_output_state_finish(&pending);
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制层和淡出效果
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
@ -4095,24 +4123,43 @@ 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) &&
|
||||||
goto skip;
|
!client_is_stopped(c)) {
|
||||||
|
skip_commit = true; // 标记跳过提交,但不中断循环
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_scene_output_commit(m->scene_output, NULL);
|
// 如果不需要跳过提交,才进行实际提交
|
||||||
|
if (!skip_commit) {
|
||||||
|
if (output_get_tearing_allowance(m)) {
|
||||||
|
pending.tearing_page_flip = true;
|
||||||
|
|
||||||
|
if (!wlr_output_test_state(m->wlr_output, &pending)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Output test failed on '%s', retrying without tearing "
|
||||||
|
"page-flip\n",
|
||||||
|
m->wlr_output->name);
|
||||||
|
pending.tearing_page_flip = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wlr_output_commit_state(m->wlr_output, &pending))
|
||||||
|
fprintf(stderr, "Page-flip failed on output %s",
|
||||||
|
m->wlr_output->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_output_state_finish(&pending);
|
||||||
|
|
||||||
skip:
|
skip:
|
||||||
|
// 发送帧完成通知
|
||||||
// Send frame done notification
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
wlr_scene_output_send_frame_done(m->scene_output, &now);
|
frame_done_data.mon = m;
|
||||||
|
wlr_scene_output_for_each_buffer(m->scene_output, sendframedoneiterator,
|
||||||
// // Clean up pending state
|
&frame_done_data);
|
||||||
wlr_output_state_finish(&pending);
|
|
||||||
|
|
||||||
if (need_more_frames) {
|
if (need_more_frames) {
|
||||||
wlr_output_schedule_frame(m->wlr_output);
|
wlr_output_schedule_frame(m->wlr_output);
|
||||||
|
|
@ -4900,6 +4947,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);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue