mirror of
https://codeberg.org/dwl/dwl.git
synced 2026-11-03 20:02:23 +00:00
Compare commits
9
Commits
f08d8b3913
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6e2c155de | ||
|
|
be2bd72314 | ||
|
|
12a5856427 | ||
|
|
4ecb2a9df5 | ||
|
|
4953b7ea0c | ||
|
|
9dfaea2f79 | ||
|
|
afbafd53ab | ||
|
|
4ff9db2c40 | ||
|
|
d3fa32993c |
@@ -153,6 +153,7 @@ given the base on which it is built. Implemented default features are:
|
||||
- Support screen lockers via ext-session-lock-v1 protocol
|
||||
- Various Wayland protocols
|
||||
- XWayland support as provided by wlroots (can be enabled in `config.mk`)
|
||||
- Zero flickering - Wayland users naturally expect that "every frame is perfect"
|
||||
- Layer shell popups (used by Waybar)
|
||||
- Damage tracking provided by scenegraph API
|
||||
|
||||
|
||||
@@ -324,19 +324,36 @@ client_set_scale(struct wlr_surface *s, float scale)
|
||||
wlr_surface_set_preferred_buffer_scale(s, (int32_t)ceilf(scale));
|
||||
}
|
||||
|
||||
static inline void
|
||||
/* Returns nonzero if the client has to commit a buffer with the new size */
|
||||
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;
|
||||
return (int)width != client_surface(c)->current.width
|
||||
|| (int)height != client_surface(c)->current.height;
|
||||
}
|
||||
#endif
|
||||
if ((int32_t)width != c->surface.xdg->toplevel->current.width
|
||||
|| (int32_t)height != c->surface.xdg->toplevel->current.height)
|
||||
wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height);
|
||||
if ((int32_t)width == c->surface.xdg->toplevel->scheduled.width
|
||||
&& (int32_t)height == c->surface.xdg->toplevel->scheduled.height)
|
||||
return 0;
|
||||
return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height);
|
||||
}
|
||||
|
||||
static inline void
|
||||
client_send_frame_done_iterator(struct wlr_surface *s, int sx, int sy, void *data)
|
||||
{
|
||||
wlr_surface_send_frame_done(s, data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
client_send_frame_done(Client *c)
|
||||
{
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
wlr_surface_for_each_surface(client_surface(c), client_send_frame_done_iterator, &now);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
||||
@@ -12,7 +12,6 @@ static const float rootcolor[] = COLOR(0x222222ff);
|
||||
static const float bordercolor[] = COLOR(0x444444ff);
|
||||
static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
|
||||
@@ -126,6 +126,9 @@ typedef struct {
|
||||
struct wl_list flink;
|
||||
struct wlr_box geom; /* layout-relative, includes border */
|
||||
struct wlr_box prev; /* layout-relative, includes border */
|
||||
struct wlr_box current; /* geom currently shown in the scene graph */
|
||||
struct wlr_scene_node *snapshot; /* content shown while resizing */
|
||||
uint32_t resize_serial; /* nonzero while waiting for a resized buffer */
|
||||
struct wlr_box bounds; /* only width and height are used */
|
||||
union {
|
||||
struct wlr_xdg_surface *xdg;
|
||||
@@ -262,6 +265,7 @@ typedef struct {
|
||||
|
||||
/* function declarations */
|
||||
static void applybounds(Client *c, struct wlr_box *bbox);
|
||||
static void applygeom(Client *c);
|
||||
static void applyrules(Client *c);
|
||||
static void arrange(Monitor *m);
|
||||
static void arrangelayer(Monitor *m, struct wl_list *list,
|
||||
@@ -324,6 +328,7 @@ static void mapnotify(struct wl_listener *listener, void *data);
|
||||
static void maximizenotify(struct wl_listener *listener, void *data);
|
||||
static void monocle(Monitor *m);
|
||||
static void motionabsolute(struct wl_listener *listener, void *data);
|
||||
static char **monoff(struct wlr_output *wlr_output);
|
||||
static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx,
|
||||
double sy, double sx_unaccel, double sy_unaccel);
|
||||
static void motionrelative(struct wl_listener *listener, void *data);
|
||||
@@ -349,9 +354,12 @@ static void setfullscreen(Client *c, int fullscreen);
|
||||
static void setlayout(const Arg *arg);
|
||||
static void setmfact(const Arg *arg);
|
||||
static void setmon(Client *c, Monitor *m, uint32_t newtags);
|
||||
static void setmonoff(struct wlr_output *wlr_output, int off);
|
||||
static void setpsel(struct wl_listener *listener, void *data);
|
||||
static void setsel(struct wl_listener *listener, void *data);
|
||||
static void setup(void);
|
||||
static struct wlr_scene_node *snapshot(struct wlr_scene_node *node,
|
||||
struct wlr_scene_tree *parent, void *data);
|
||||
static void spawn(const Arg *arg);
|
||||
static void startdrag(struct wl_listener *listener, void *data);
|
||||
static void tag(const Arg *arg);
|
||||
@@ -361,6 +369,11 @@ static void togglefloating(const Arg *arg);
|
||||
static void togglefullscreen(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void transactionapply(void);
|
||||
static void transactioncheck(void *data);
|
||||
static void transactioncommit(Client *c, int ready);
|
||||
static void transactionschedule(void);
|
||||
static int transactiontimeout(void *data);
|
||||
static void unlocksession(struct wl_listener *listener, void *data);
|
||||
static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
|
||||
static void unmapnotify(struct wl_listener *listener, void *data);
|
||||
@@ -432,6 +445,15 @@ static struct wl_list mons;
|
||||
static Monitor *selmon;
|
||||
static int consumed[KEY_MAX + 1];
|
||||
|
||||
/* Transactions: the scene graph is updated only once all visible clients have
|
||||
* committed buffers with their new size, or after TRANSACTION_TIMEOUT ms */
|
||||
#define TRANSACTION_TIMEOUT 100
|
||||
static struct wl_event_source *transaction_idle;
|
||||
static struct wl_event_source *transaction_timer;
|
||||
static int transaction_waiting;
|
||||
static struct wl_array ghosts; /* struct wlr_scene_node *, unmapped clients */
|
||||
static struct wl_array offmons; /* char *, names of outputs turned off by clients */
|
||||
|
||||
/* global event handlers */
|
||||
static struct wl_listener cursor_axis = {.notify = axisnotify};
|
||||
static struct wl_listener cursor_button = {.notify = buttonpress};
|
||||
@@ -460,12 +482,14 @@ static struct wl_listener request_set_sel = {.notify = setsel};
|
||||
static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape};
|
||||
static struct wl_listener request_start_drag = {.notify = requeststartdrag};
|
||||
static struct wl_listener start_drag = {.notify = startdrag};
|
||||
static struct wl_listener drag_icon_destroy = {.notify = destroydragicon};
|
||||
static struct wl_listener new_session_lock = {.notify = locksession};
|
||||
static struct wl_listener new_foreign_toplevel_capture_request = {.notify = capturerequest};
|
||||
|
||||
#ifdef XWAYLAND
|
||||
static void activatex11(struct wl_listener *listener, void *data);
|
||||
static void associatex11(struct wl_listener *listener, void *data);
|
||||
static void commitx11(struct wl_listener *listener, void *data);
|
||||
static void configurex11(struct wl_listener *listener, void *data);
|
||||
static void createnotifyx11(struct wl_listener *listener, void *data);
|
||||
static void dissociatex11(struct wl_listener *listener, void *data);
|
||||
@@ -516,6 +540,41 @@ applybounds(Client *c, struct wlr_box *bbox)
|
||||
c->geom.y = bbox->y;
|
||||
}
|
||||
|
||||
void
|
||||
applygeom(Client *c)
|
||||
{
|
||||
struct wlr_box clip;
|
||||
Client *p = client_get_parent(c);
|
||||
|
||||
/* We move all floating clients to LyrTile while in floating layout
|
||||
* to avoid "real" floating clients be always on top */
|
||||
wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen
|
||||
|| (p && p->isfullscreen) ? LyrFS
|
||||
: c->isfloating && c->mon->lt[c->mon->sellt]->arrange ? LyrFloat
|
||||
: LyrTile]);
|
||||
|
||||
c->current = c->geom;
|
||||
if (c->snapshot) {
|
||||
wlr_scene_node_destroy(c->snapshot);
|
||||
c->snapshot = NULL;
|
||||
wlr_scene_node_set_enabled(&c->scene_surface->node, 1);
|
||||
}
|
||||
|
||||
/* Update scene-graph, including borders */
|
||||
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
|
||||
wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
|
||||
wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw);
|
||||
wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw);
|
||||
wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw);
|
||||
wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw);
|
||||
wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw);
|
||||
wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw);
|
||||
wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);
|
||||
|
||||
client_get_clip(c, &clip);
|
||||
wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
|
||||
}
|
||||
|
||||
void
|
||||
applyrules(Client *c)
|
||||
{
|
||||
@@ -555,37 +614,18 @@ arrange(Monitor *m)
|
||||
return;
|
||||
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
if (c->mon == m) {
|
||||
wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m));
|
||||
if (c->mon == m)
|
||||
client_set_suspended(c, !VISIBLEON(c, m)
|
||||
&& (!c->image_capture_source
|
||||
|| wl_list_empty(&c->image_capture_source->resources)));
|
||||
}
|
||||
}
|
||||
|
||||
wlr_scene_node_set_enabled(&m->fullscreen_bg->node,
|
||||
(c = focustop(m)) && c->isfullscreen);
|
||||
|
||||
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
|
||||
|
||||
/* We move all clients (except fullscreen and unmanaged) to LyrTile while
|
||||
* in floating layout to avoid "real" floating clients be always on top */
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
if (c->mon != m || c->scene->node.parent == layers[LyrFS])
|
||||
continue;
|
||||
|
||||
wlr_scene_node_reparent(&c->scene->node,
|
||||
(!m->lt[m->sellt]->arrange && c->isfloating)
|
||||
? layers[LyrTile]
|
||||
: (m->lt[m->sellt]->arrange && c->isfloating)
|
||||
? layers[LyrFloat]
|
||||
: c->scene->node.parent);
|
||||
}
|
||||
|
||||
if (m->lt[m->sellt]->arrange)
|
||||
m->lt[m->sellt]->arrange(m);
|
||||
motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
checkidleinhibitor(NULL);
|
||||
|
||||
transactionschedule();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -788,6 +828,8 @@ checkidleinhibitor(struct wlr_surface *exclude)
|
||||
void
|
||||
cleanup(void)
|
||||
{
|
||||
char **name;
|
||||
|
||||
cleanuplisteners();
|
||||
#ifdef XWAYLAND
|
||||
wlr_xwayland_destroy(xwayland);
|
||||
@@ -809,6 +851,14 @@ cleanup(void)
|
||||
* Destroy it until it's fixed on the wlroots side */
|
||||
wlr_backend_destroy(backend);
|
||||
|
||||
if (transaction_idle)
|
||||
wl_event_source_remove(transaction_idle);
|
||||
wl_event_source_remove(transaction_timer);
|
||||
wl_array_release(&ghosts);
|
||||
wl_array_for_each(name, &offmons)
|
||||
free(*name);
|
||||
wl_array_release(&offmons);
|
||||
|
||||
wl_display_destroy(dpy);
|
||||
/* Destroy after the wayland display (when the monitors are already destroyed)
|
||||
to avoid destroying them with an invalid scene output. */
|
||||
@@ -990,6 +1040,8 @@ commitnotify(struct wl_listener *listener, void *data)
|
||||
return;
|
||||
}
|
||||
|
||||
transactioncommit(c, c->resize_serial && c->surface.xdg->current.configure_serial
|
||||
>= c->resize_serial);
|
||||
resize(c, c->geom, (c->isfloating && !c->isfullscreen));
|
||||
}
|
||||
|
||||
@@ -1186,14 +1238,17 @@ createmon(struct wl_listener *listener, void *data)
|
||||
* monitor supports only a specific set of modes. We just pick the
|
||||
* monitor's preferred mode; a more sophisticated compositor would let
|
||||
* the user configure it. */
|
||||
wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output));
|
||||
|
||||
/* Set up event listeners */
|
||||
LISTEN(&wlr_output->events.frame, &m->frame, rendermon);
|
||||
LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon);
|
||||
LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate);
|
||||
|
||||
wlr_output_state_set_enabled(&state, 1);
|
||||
/* Some monitors disconnect when they are turned off and reconnect shortly
|
||||
* after, so keep outputs that were turned off disabled. */
|
||||
if (!monoff(wlr_output)) {
|
||||
wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output));
|
||||
wlr_output_state_set_enabled(&state, 1);
|
||||
}
|
||||
wlr_output_commit_state(wlr_output, &state);
|
||||
wlr_output_state_finish(&state);
|
||||
|
||||
@@ -1219,6 +1274,12 @@ createmon(struct wl_listener *listener, void *data)
|
||||
* output (such as DPI, scale factor, manufacturer, etc).
|
||||
*/
|
||||
m->scene_output = wlr_scene_output_create(scene, wlr_output);
|
||||
|
||||
if (!wlr_output->enabled) {
|
||||
updatemons(NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m->m.x == -1 && m->m.y == -1)
|
||||
wlr_output_layout_add_auto(output_layout, wlr_output);
|
||||
else
|
||||
@@ -1363,7 +1424,6 @@ destroydragicon(struct wl_listener *listener, void *data)
|
||||
focusclient(focustop(selmon), NULL, 1);
|
||||
motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
wl_list_remove(&listener->link);
|
||||
free(listener);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1550,7 +1610,6 @@ focusclient(Client *c, LayerSurface *l, int lift)
|
||||
/* Don't change border color if there is an exclusive focus or we are
|
||||
* handling a drag operation */
|
||||
if (!(old_l && old_l->layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
|
||||
&& !(old_c && client_wants_focus(old_c))
|
||||
&& !seat->drag)
|
||||
client_set_border_color(c, focuscolor);
|
||||
}
|
||||
@@ -1641,10 +1700,14 @@ Client *
|
||||
focustop(Monitor *m)
|
||||
{
|
||||
Client *c;
|
||||
wl_list_for_each(c, &fstack, flink) {
|
||||
|
||||
wl_list_for_each(c, &fstack, flink)
|
||||
if (VISIBLEON(c, m) && c->isfullscreen)
|
||||
return c;
|
||||
|
||||
wl_list_for_each(c, &fstack, flink)
|
||||
if (VISIBLEON(c, m))
|
||||
return c;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2019,6 +2082,17 @@ motionabsolute(struct wl_listener *listener, void *data)
|
||||
motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy);
|
||||
}
|
||||
|
||||
char **
|
||||
monoff(struct wlr_output *wlr_output)
|
||||
{
|
||||
char **name;
|
||||
wl_array_for_each(name, &offmons) {
|
||||
if (!strcmp(*name, wlr_output->name))
|
||||
return name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
|
||||
double dx_unaccel, double dy_unaccel)
|
||||
@@ -2205,6 +2279,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test)
|
||||
/* Ensure displays previously disabled by wlr-output-power-management-v1
|
||||
* are properly handled*/
|
||||
m->asleep = 0;
|
||||
setmonoff(wlr_output, !config_head->state.enabled);
|
||||
|
||||
/* Don't move monitors if position wouldn't change. This avoids
|
||||
* wlroots marking the output as manually configured.
|
||||
@@ -2323,6 +2398,10 @@ powermgrsetmode(struct wl_listener *listener, void *data)
|
||||
|
||||
m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the output */
|
||||
wlr_output_state_set_enabled(&state, event->mode);
|
||||
/* The output was reconnected while off and was never modeset */
|
||||
if (event->mode && !m->wlr_output->current_mode)
|
||||
wlr_output_state_set_mode(&state, wlr_output_preferred_mode(m->wlr_output));
|
||||
setmonoff(m->wlr_output, !event->mode);
|
||||
wlr_output_commit_state(m->wlr_output, &state);
|
||||
|
||||
m->asleep = !event->mode;
|
||||
@@ -2385,7 +2464,7 @@ void
|
||||
resize(Client *c, struct wlr_box geo, int interact)
|
||||
{
|
||||
struct wlr_box *bbox;
|
||||
struct wlr_box clip;
|
||||
uint32_t serial;
|
||||
|
||||
if (!c->mon || !client_surface(c)->mapped)
|
||||
return;
|
||||
@@ -2396,20 +2475,27 @@ resize(Client *c, struct wlr_box geo, int interact)
|
||||
c->geom = geo;
|
||||
applybounds(c, bbox);
|
||||
|
||||
/* Update scene-graph, including borders */
|
||||
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
|
||||
wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
|
||||
wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw);
|
||||
wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw);
|
||||
wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw);
|
||||
wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw);
|
||||
wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw);
|
||||
wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw);
|
||||
wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);
|
||||
if ((serial = client_set_size(c, c->geom.width - 2 * c->bw,
|
||||
c->geom.height - 2 * c->bw)))
|
||||
c->resize_serial = serial;
|
||||
|
||||
client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw);
|
||||
client_get_clip(c, &clip);
|
||||
wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
|
||||
if (interact || (!c->resize_serial && wlr_box_equal(&c->geom, &c->current))) {
|
||||
c->resize_serial = 0;
|
||||
applygeom(c);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Until the transaction is applied, keep showing the current content
|
||||
* instead of buffers with the new size at the old position. */
|
||||
if (c->resize_serial) {
|
||||
if (!c->snapshot && c->scene->node.enabled
|
||||
&& (c->snapshot = snapshot(&c->scene_surface->node, c->scene, c)))
|
||||
wlr_scene_node_set_enabled(&c->scene_surface->node, 0);
|
||||
/* The scene graph doesn't send frame done events to hidden
|
||||
* surfaces, but the client may be waiting for one to redraw */
|
||||
client_send_frame_done(c);
|
||||
}
|
||||
transactionschedule();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2510,14 +2596,10 @@ setcursorshape(struct wl_listener *listener, void *data)
|
||||
void
|
||||
setfloating(Client *c, int floating)
|
||||
{
|
||||
Client *p = client_get_parent(c);
|
||||
c->isfloating = floating;
|
||||
/* If in floating layout do not change the client's layer */
|
||||
if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange)
|
||||
return;
|
||||
wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
|
||||
(p && p->isfullscreen) ? LyrFS
|
||||
: c->isfloating ? LyrFloat : LyrTile]);
|
||||
arrange(c->mon);
|
||||
printstatus();
|
||||
}
|
||||
@@ -2530,8 +2612,6 @@ setfullscreen(Client *c, int fullscreen)
|
||||
return;
|
||||
c->bw = fullscreen ? 0 : borderpx;
|
||||
client_set_fullscreen(c, fullscreen);
|
||||
wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen
|
||||
? LyrFS : c->isfloating ? LyrFloat : LyrTile]);
|
||||
|
||||
if (fullscreen) {
|
||||
c->prev = c->geom;
|
||||
@@ -2597,6 +2677,22 @@ setmon(Client *c, Monitor *m, uint32_t newtags)
|
||||
focusclient(focustop(selmon), NULL, 1);
|
||||
}
|
||||
|
||||
void
|
||||
setmonoff(struct wlr_output *wlr_output, int off)
|
||||
{
|
||||
char **name = monoff(wlr_output), **last;
|
||||
|
||||
if (off && !name && (name = wl_array_add(&offmons, sizeof(*name)))) {
|
||||
if (!(*name = strdup(wlr_output->name)))
|
||||
offmons.size -= sizeof(*name);
|
||||
} else if (!off && name) {
|
||||
free(*name);
|
||||
last = (char **)((char *)offmons.data + offmons.size) - 1;
|
||||
*name = *last;
|
||||
offmons.size -= sizeof(*name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
setpsel(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -2735,6 +2831,10 @@ setup(void)
|
||||
wl_list_init(&clients);
|
||||
wl_list_init(&fstack);
|
||||
|
||||
transaction_timer = wl_event_loop_add_timer(event_loop, transactiontimeout, NULL);
|
||||
wl_array_init(&ghosts);
|
||||
wl_array_init(&offmons);
|
||||
|
||||
xdg_shell = wlr_xdg_shell_create(dpy, 6);
|
||||
wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel);
|
||||
wl_signal_add(&xdg_shell->events.new_popup, &new_xdg_popup);
|
||||
@@ -2856,6 +2956,57 @@ setup(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
struct wlr_scene_node *
|
||||
snapshot(struct wlr_scene_node *node, struct wlr_scene_tree *parent, void *data)
|
||||
{
|
||||
/* Copy the visible part of a scene graph subtree, keeping references to
|
||||
* the buffers so that they can be shown after the client changes them */
|
||||
struct wlr_scene_node *child, *copy;
|
||||
struct wlr_scene_tree *tree;
|
||||
struct wlr_scene_rect *rect;
|
||||
struct wlr_scene_buffer *src, *buffer;
|
||||
|
||||
if (!node->enabled)
|
||||
return NULL;
|
||||
|
||||
switch (node->type) {
|
||||
case WLR_SCENE_NODE_TREE:
|
||||
tree = wlr_scene_tree_create(parent);
|
||||
wl_list_for_each(child, &wlr_scene_tree_from_node(node)->children, link)
|
||||
snapshot(child, tree, data);
|
||||
copy = &tree->node;
|
||||
break;
|
||||
case WLR_SCENE_NODE_RECT:
|
||||
rect = wlr_scene_rect_from_node(node);
|
||||
copy = &wlr_scene_rect_create(parent, rect->width, rect->height, rect->color)->node;
|
||||
break;
|
||||
case WLR_SCENE_NODE_BUFFER:
|
||||
src = wlr_scene_buffer_from_node(node);
|
||||
buffer = wlr_scene_buffer_create(parent, NULL);
|
||||
wlr_scene_buffer_set_dest_size(buffer, src->dst_width, src->dst_height);
|
||||
wlr_scene_buffer_set_opaque_region(buffer, &src->opaque_region);
|
||||
wlr_scene_buffer_set_opacity(buffer, src->opacity);
|
||||
wlr_scene_buffer_set_filter_mode(buffer, src->filter_mode);
|
||||
wlr_scene_buffer_set_transfer_function(buffer, src->transfer_function);
|
||||
wlr_scene_buffer_set_primaries(buffer, src->primaries);
|
||||
wlr_scene_buffer_set_color_encoding(buffer, src->color_encoding);
|
||||
wlr_scene_buffer_set_color_range(buffer, src->color_range);
|
||||
wlr_scene_buffer_set_source_box(buffer, &src->src_box);
|
||||
wlr_scene_buffer_set_transform(buffer, src->transform);
|
||||
wlr_scene_buffer_set_buffer(buffer, src->buffer);
|
||||
copy = &buffer->node;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
copy->data = data;
|
||||
wlr_scene_node_set_position(copy, node->x, node->y);
|
||||
if (node->parent == parent)
|
||||
wlr_scene_node_place_above(copy, node);
|
||||
return copy;
|
||||
}
|
||||
|
||||
void
|
||||
spawn(const Arg *arg)
|
||||
{
|
||||
@@ -2875,7 +3026,7 @@ startdrag(struct wl_listener *listener, void *data)
|
||||
return;
|
||||
|
||||
drag->icon->data = &wlr_scene_drag_icon_create(drag_icon, drag->icon)->node;
|
||||
LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon);
|
||||
wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2977,6 +3128,88 @@ toggleview(const Arg *arg)
|
||||
printstatus();
|
||||
}
|
||||
|
||||
void
|
||||
transactionapply(void)
|
||||
{
|
||||
struct wlr_scene_node **ghost;
|
||||
Client *c;
|
||||
Monitor *m;
|
||||
|
||||
wl_event_source_timer_update(transaction_timer, 0);
|
||||
transaction_waiting = 0;
|
||||
|
||||
wl_array_for_each(ghost, &ghosts)
|
||||
wlr_scene_node_destroy(*ghost);
|
||||
ghosts.size = 0;
|
||||
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
c->resize_serial = 0;
|
||||
if (!c->mon)
|
||||
continue;
|
||||
if (c->mon->wlr_output->enabled)
|
||||
wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, c->mon));
|
||||
applygeom(c);
|
||||
}
|
||||
|
||||
wl_list_for_each(m, &mons, link) {
|
||||
if (m->wlr_output->enabled)
|
||||
wlr_scene_node_set_enabled(&m->fullscreen_bg->node,
|
||||
(c = focustop(m)) && c->isfullscreen);
|
||||
}
|
||||
|
||||
motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
checkidleinhibitor(NULL);
|
||||
}
|
||||
|
||||
void
|
||||
transactioncheck(void *data)
|
||||
{
|
||||
Client *c;
|
||||
|
||||
transaction_idle = NULL;
|
||||
|
||||
/* Hidden clients don't have to redraw before the layout is shown */
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
if (c->resize_serial && VISIBLEON(c, c->mon) && c->mon->wlr_output->enabled) {
|
||||
if (!transaction_waiting) {
|
||||
/* Don't restart the timer on updates of the pending
|
||||
* layout, so the delay is bounded */
|
||||
wl_event_source_timer_update(transaction_timer, TRANSACTION_TIMEOUT);
|
||||
transaction_waiting = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
transactionapply();
|
||||
}
|
||||
|
||||
void
|
||||
transactioncommit(Client *c, int ready)
|
||||
{
|
||||
if (c->resize_serial && ready) {
|
||||
c->resize_serial = 0;
|
||||
transactionschedule();
|
||||
} else if (c->snapshot) {
|
||||
/* This buffer is not shown, let the client draw again */
|
||||
client_send_frame_done(c);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
transactionschedule(void)
|
||||
{
|
||||
if (!transaction_idle)
|
||||
transaction_idle = wl_event_loop_add_idle(event_loop, transactioncheck, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
transactiontimeout(void *data)
|
||||
{
|
||||
transactionapply();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
unlocksession(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -3003,6 +3236,7 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* Called when the surface is unmapped, and should no longer be shown. */
|
||||
Client *c = wl_container_of(listener, c, unmap);
|
||||
struct wlr_scene_node *ghost, **slot;
|
||||
if (c == grabc) {
|
||||
cursor_mode = CurNormal;
|
||||
grabc = NULL;
|
||||
@@ -3011,6 +3245,15 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||
focused_client = NULL;
|
||||
|
||||
if (!client_is_unmanaged(c)) {
|
||||
/* Keep showing the client until the transaction rearranging the
|
||||
* remaining ones is applied, to not show a gap */
|
||||
if ((ghost = snapshot(&c->scene->node, c->scene->node.parent, NULL))) {
|
||||
if ((slot = wl_array_add(&ghosts, sizeof(ghost))))
|
||||
*slot = ghost;
|
||||
else
|
||||
wlr_scene_node_destroy(ghost);
|
||||
transactionschedule();
|
||||
}
|
||||
wl_list_remove(&c->link);
|
||||
setmon(c, NULL, 0);
|
||||
wl_list_remove(&c->flink);
|
||||
@@ -3034,6 +3277,9 @@ unmapnotify(struct wl_listener *listener, void *data)
|
||||
c->image_capture_source = NULL;
|
||||
wlr_scene_node_destroy(&c->scene->node);
|
||||
client_surface(c)->data = NULL;
|
||||
c->snapshot = NULL;
|
||||
c->resize_serial = 0;
|
||||
c->current = (struct wlr_box){0};
|
||||
printstatus();
|
||||
motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
}
|
||||
@@ -3233,20 +3479,26 @@ xytonode(double x, double y, struct wlr_surface **psurface,
|
||||
Client **pc, LayerSurface **pl, double *nx, double *ny)
|
||||
{
|
||||
struct wlr_scene_node *node;
|
||||
struct wlr_scene_surface *scene_surface;
|
||||
struct wlr_surface *surface = NULL;
|
||||
Client *c = NULL;
|
||||
int layer;
|
||||
|
||||
for (layer = NUM_LAYERS - 1; !surface && layer >= (locked ? LyrBlock : 0); layer--) {
|
||||
for (layer = NUM_LAYERS - 1; !surface && !c && layer >= (locked ? LyrBlock : 0); layer--) {
|
||||
if (layer == LyrIMPopup ||
|
||||
!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny)))
|
||||
!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny))
|
||||
|| node->type != WLR_SCENE_NODE_BUFFER)
|
||||
continue;
|
||||
|
||||
if (node->type == WLR_SCENE_NODE_BUFFER)
|
||||
surface = wlr_scene_surface_try_from_buffer(
|
||||
wlr_scene_buffer_from_node(node))->surface;
|
||||
if ((scene_surface = wlr_scene_surface_try_from_buffer(
|
||||
wlr_scene_buffer_from_node(node))))
|
||||
surface = scene_surface->surface;
|
||||
else /* snapshot of a client during a transaction */
|
||||
c = node->data;
|
||||
}
|
||||
|
||||
if (psurface) *psurface = surface;
|
||||
if (pc) *pc = c;
|
||||
toplevel_from_wlr_surface(surface, pc, pl);
|
||||
}
|
||||
|
||||
@@ -3299,10 +3551,21 @@ associatex11(struct wl_listener *listener, void *data)
|
||||
{
|
||||
Client *c = wl_container_of(listener, c, associate);
|
||||
|
||||
LISTEN(&client_surface(c)->events.commit, &c->commit, commitx11);
|
||||
LISTEN(&client_surface(c)->events.map, &c->map, mapnotify);
|
||||
LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify);
|
||||
}
|
||||
|
||||
void
|
||||
commitx11(struct wl_listener *listener, void *data)
|
||||
{
|
||||
Client *c = wl_container_of(listener, c, commit);
|
||||
struct wlr_surface *surface = client_surface(c);
|
||||
|
||||
transactioncommit(c, surface->current.width == c->geom.width - 2 * (int)c->bw
|
||||
&& surface->current.height == c->geom.height - 2 * (int)c->bw);
|
||||
}
|
||||
|
||||
void
|
||||
configurex11(struct wl_listener *listener, void *data)
|
||||
{
|
||||
@@ -3351,6 +3614,7 @@ void
|
||||
dissociatex11(struct wl_listener *listener, void *data)
|
||||
{
|
||||
Client *c = wl_container_of(listener, c, dissociate);
|
||||
wl_list_remove(&c->commit.link);
|
||||
wl_list_remove(&c->map.link);
|
||||
wl_list_remove(&c->unmap.link);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user