summaryrefslogtreecommitdiffstats
path: root/dwl.c
diff options
context:
space:
mode:
Diffstat (limited to 'dwl.c')
-rw-r--r--dwl.c184
1 files changed, 170 insertions, 14 deletions
diff --git a/dwl.c b/dwl.c
index fd6cf35..9bb4702 100644
--- a/dwl.c
+++ b/dwl.c
@@ -51,6 +51,7 @@
#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_tearing_control_v1.h>
#include <wlr/types/wlr_viewporter.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h>
@@ -87,6 +88,11 @@ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
enum { XDGShell, LayerShell, X11 }; /* client types */
enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
+typedef struct ForceTearingRule {
+ const char* title;
+ const char* appid;
+} ForceTearingRule;
+
typedef union {
int i;
uint32_t ui;
@@ -141,6 +147,7 @@ typedef struct {
uint32_t tags;
int isfloating, isurgent, isfullscreen;
uint32_t resize; /* configure serial of a pending resize */
+ enum wp_tearing_control_v1_presentation_hint tearing_hint;
} Client;
typedef struct {
@@ -250,6 +257,19 @@ typedef struct {
struct wl_listener destroy;
} SessionLock;
+typedef struct TearingController {
+ struct wlr_tearing_control_v1 *tearing_control;
+ struct wl_listener set_hint;
+ struct wl_listener destroy;
+
+ struct wl_list link; /* tearing_controllers */
+} TearingController;
+
+typedef struct SendFrameDoneData {
+ struct timespec when;
+ struct Monitor *mon;
+} SendFrameDoneData;
+
/* function declarations */
static void applybounds(Client *c, struct wlr_box *bbox);
static void applyrules(Client *c);
@@ -311,6 +331,9 @@ static Client *focustop(Monitor *m);
static void fullscreennotify(struct wl_listener *listener, void *data);
static void gpureset(struct wl_listener *listener, void *data);
static void handlesig(int signo);
+static void handletearingcontrollersethint(struct wl_listener *listener, void *data);
+static void handletearingcontrollerdestroy(struct wl_listener *listener, void *data);
+static void handlenewtearinghint(struct wl_listener *listener, void *data);
static void incnmaster(const Arg *arg);
static void inputdevice(struct wl_listener *listener, void *data);
static int keybinding(uint32_t mods, xkb_keysym_t sym);
@@ -327,6 +350,7 @@ static void motionnotify(uint32_t time, struct wlr_input_device *device, double
double sy, double sx_unaccel, double sy_unaccel);
static void motionrelative(struct wl_listener *listener, void *data);
static void moveresize(const Arg *arg);
+static int moncantear(Monitor* m);
static void outputmgrapply(struct wl_listener *listener, void *data);
static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test);
static void outputmgrtest(struct wl_listener *listener, void *data);
@@ -341,6 +365,7 @@ static void requeststartdrag(struct wl_listener *listener, void *data);
static void requestmonstate(struct wl_listener *listener, void *data);
static void resize(Client *c, struct wlr_box geo, int interact);
static void run(char *startup_cmd);
+static void sendframedoneiterator(struct wlr_scene_buffer *buffer, int x, int y, void *user_data);
static void setcursor(struct wl_listener *listener, void *data);
static void setcursorshape(struct wl_listener *listener, void *data);
static void setfloating(Client *c, int floating);
@@ -419,6 +444,10 @@ static struct wlr_session_lock_manager_v1 *session_lock_mgr;
static struct wlr_scene_rect *locked_bg;
static struct wlr_session_lock_v1 *cur_lock;
+struct wlr_tearing_control_manager_v1 *tearing_control_v1;
+struct wl_listener tearing_control_new_object;
+struct wl_list tearing_controllers;
+
static struct wlr_seat *seat;
static KeyboardGroup *kb_group;
static unsigned int cursor_mode;
@@ -1799,6 +1828,69 @@ handlesig(int signo)
}
void
+handletearingcontrollersethint(struct wl_listener *listener, void *data)
+{
+ Client *c = NULL, *i = NULL;
+ struct TearingController *controller = wl_container_of(listener, controller, set_hint);
+
+ struct wlr_xdg_surface *surface = wlr_xdg_surface_try_from_wlr_surface(controller->tearing_control->surface);
+#ifdef XWAYLAND
+ struct wlr_xwayland_surface *xsurface = wlr_xwayland_surface_try_from_wlr_surface(controller->tearing_control->surface);
+#endif
+
+ wl_list_for_each(i, &fstack, flink) {
+ if (i->surface.xdg == surface
+#ifdef XWAYLAND
+ || i->surface.xwayland == xsurface
+#endif
+ ) {
+ c = i;
+ break;
+ }
+ }
+
+ if (c) {
+ enum wp_tearing_control_v1_presentation_hint hint = controller->tearing_control->current;
+ fprintf(
+ stderr, "TEARING: found surface: %p(appid: '%s', title: '%s'), hint: %d(%s)\n",
+ (void*)c, client_get_appid(c), client_get_title(c), hint, hint ? "ASYNC" : "VSYNC"
+ );
+ c->tearing_hint = controller->tearing_control->current;
+ }
+}
+
+void
+handletearingcontrollerdestroy(struct wl_listener *listener, void *data)
+{
+ struct TearingController *controller = wl_container_of(listener, controller, destroy);
+
+ wl_list_remove(&controller->set_hint.link);
+ wl_list_remove(&controller->destroy.link);
+ wl_list_remove(&controller->link);
+ free(controller);
+}
+
+void
+handlenewtearinghint(struct wl_listener *listener, void *data)
+{
+ struct wlr_tearing_control_v1 *tearing_control = data;
+ struct TearingController *controller = calloc(1, sizeof(struct TearingController));
+
+ if (!controller)
+ return;
+
+ controller->tearing_control = tearing_control;
+ controller->set_hint.notify = handletearingcontrollersethint;
+ wl_signal_add(&tearing_control->events.set_hint, &controller->set_hint);
+
+ controller->destroy.notify = handletearingcontrollerdestroy;
+ wl_signal_add(&tearing_control->events.destroy, &controller->destroy);
+
+ wl_list_init(&controller->link);
+ wl_list_insert(&tearing_controllers, &controller->link);
+}
+
+void
incnmaster(const Arg *arg)
{
Client *c;
@@ -1982,6 +2074,33 @@ locksession(struct wl_listener *listener, void *data)
wlr_session_lock_v1_send_locked(session_lock);
}
+static inline void
+forcetearingrule(Client *c)
+{
+ int success = 0;
+ const char* appid = client_get_appid(c);
+ const char* title = client_get_title(c);
+
+ for (unsigned i = 0; i < LENGTH(force_tearing); i++) {
+ if (appid)
+ if (strcmp(force_tearing[i].appid, appid) == 0) {
+ success = 1;
+ break;
+ }
+
+ if (title)
+ if (strcmp(force_tearing[i].title, title) == 0) {
+ success = 1;
+ break;
+ }
+ }
+
+ if (success) {
+ c->tearing_hint = WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC;
+ fprintf(stderr, "tearing forced for: appid: '%s', title: '%s'\n", appid, title);
+ }
+}
+
void
mapnotify(struct wl_listener *listener, void *data)
{
@@ -1991,6 +2110,8 @@ mapnotify(struct wl_listener *listener, void *data)
Monitor *m;
int i;
+ forcetearingrule(c);
+
/* Create scene tree for this client and its border */
c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]);
/* Enabled later by a call to arrange() */
@@ -2234,6 +2355,13 @@ moveresize(const Arg *arg)
}
}
+int
+moncantear(Monitor* m)
+{
+ Client *c = focustop(m);
+ return (c && c->isfullscreen && c->tearing_hint); /* 1 == ASYNC */
+}
+
void
outputmgrapply(struct wl_listener *listener, void *data)
{
@@ -2375,27 +2503,40 @@ quit(const Arg *arg)
void
rendermon(struct wl_listener *listener, void *data)
{
- /* This function is called every time an output is ready to display a frame,
- * generally at the output's refresh rate (e.g. 60Hz). */
Monitor *m = wl_container_of(listener, m, frame);
- Client *c;
+ struct wlr_scene_output *scene_output = m->scene_output;
struct wlr_output_state pending = {0};
- struct timespec now;
+ SendFrameDoneData frame_done_data = {0};
- /* Render if no XDG clients have an outstanding resize and are visible on
- * this monitor. */
- wl_list_for_each(c, &clients, link) {
- if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c))
- goto skip;
+ m->wlr_output->frame_pending = false;
+
+ if (!wlr_scene_output_needs_frame(scene_output)) {
+ goto skip;
}
- wlr_scene_output_commit(m->scene_output, NULL);
+ wlr_output_state_init(&pending);
+ if (!wlr_scene_output_build_state(m->scene_output, &pending, NULL)) {
+ goto skip;
+ }
+
+ if (tearing_allowed && moncantear(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);
-skip:
- /* Let clients know a frame has been rendered */
- clock_gettime(CLOCK_MONOTONIC, &now);
- wlr_scene_output_send_frame_done(m->scene_output, &now);
wlr_output_state_finish(&pending);
+
+skip:
+ clock_gettime(CLOCK_MONOTONIC, &frame_done_data.when);
+ frame_done_data.mon = m;
+ wlr_scene_output_for_each_buffer(m->scene_output, sendframedoneiterator, &frame_done_data);
}
void
@@ -2520,6 +2661,16 @@ run(char *startup_cmd)
}
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);
+}
+
+void
setcursor(struct wl_listener *listener, void *data)
{
/* This event is raised by the seat when a client provides a cursor image */
@@ -2886,6 +3037,11 @@ setup(void)
wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, dwl_ipc_manager_bind);
+ tearing_control_v1 = wlr_tearing_control_manager_v1_create(dpy, 1);
+ tearing_control_new_object.notify = handlenewtearinghint;
+ wl_signal_add(&tearing_control_v1->events.new_object, &tearing_control_new_object);
+ wl_list_init(&tearing_controllers);
+
/* Make sure XWayland clients don't connect to the parent X server,
* e.g when running in the x11 backend or the wayland backend and the
* compositor has Xwayland support */