24ZMBWYLMODPBAVLT4XNOSETHQXVLXNASYXUIGG2435IT7WIZC5AC
SRHFRPHRRPOA4RPND65UFKLIY2KM6HMP2PZMGBYNJ56ABI3Y655QC
2JGWKS7AC3SNETNLVD2PSRESRAHXTY533E5GYJ5DHNJTBZF65SJAC
D3P2FW5KLXK7TJQEQV56CGEOUHGQ45OMGYQ24TOD3LPUK3T7JHKAC
CXLGE3YYT2YXJIR7JE6NT27ONH445P5LZIKJHT53R3ZYQ3V4BHMAC
SPM222UZLPKPMWK34K4ZVIJVKI3ZZZFAQ74IANEXX36OE3Y5ZFQAC
5BKYVJBZYC3JFPKM7VJ5BW7S35AZ6E3MAWOVEWKIB5ZIZJYLTC7AC
3EEY5STEAFJZ5GYCSZRNGGDOYB2YF23ZPSGYFSREZN3NR5UHSDSAC
J7X4HM2XFWYAEAYYXGTUKHNBZ4JZX64BZW5WUYAHEUPXYPWFUMRAC
VIPO7NAXJ7HWGD5XJEBQI6FBQ2QYR5HTI6UYGK64U4WH6EXPSBOQC
5GWZP4P5XROA7WO4XOWNHL2SS3POFUACQLZMP2FR3ET3NJ3TIIMQC
X4Q25YFYZHXT6GTWNT5OCUNT66WM4RWKF6VRVUBD3BSQLQOFEPBQC
WVSX4HL763MHTPSNJOCEXKGYBFYOABSPX637PKY6RAU55FFFY7YQC
7B74AT3BXYB7PVW4F6SGQNPMHOU5TEV5TZ54CG6VSQI46XSEKWXQC
LQPHYO7IIMLXHUD5IK657BO4BE3SGT5HYDRJDU5OFDF5YUXKIRTAC
ZTOYJ4G4UQ665FKUH376KJOOO5GXHI62SWVXNZS7X6F2Y4GG2FSQC
BV5IC2T45XW6YFGPZLF2YDVEUPUH5RGCAX5HIJ3FLGV5PCJ62L6QC
QL6IFEPOHHUDBY2SGUZNNIRTDSZOSRJIHJKVU54LZSGTPTFPM2UAC
XKWY25ZVEJIJU7R23CEG5CTYRAWKZ5FXSHY3ZEZRGCIWYIKQSLOAC
VCNLR5X75OAXVKPZQHF5RUZ7BONBUC6RPGO2NZEUD3FZ7TEVL66AC
2ZRKX4A24W4WNSLJNPKP3FWB3Y3UCYLWWESTC65P45BQFSJKS4PQC
7XCGFU3GX4TQXZBOU7GFAQ62EEOTVRNWFYQGI3XULFPSUKDZ2EYAC
J6OSBEBQXZR5JZ5TOCCUPELBPUVEQULGCXURXLPY7WFYTDEQOU2AC
7L3TU7JVWPBPHN7WF4TJ263BZ6BC3AYRRW6PULFUP5JZUGWWNUSAC
CJH33PU2NGWN3E6HQQ3QE6PB25JVMXWJXZTSP4ZGPU4TZRZGNLYAC
24NXTKJNNOM6P3OPCN7OZE6LGGMFKRWFR6NUZ5JKETRABZA4YAGQC
D425ND7AT3F7QJ3CCSESMVDOC3J5C5P32M5SJDBHECZJXLHNQ2FAC
WT554G3D2X4YAEDOCISXRNXQNNMQZVHIUANSJMT2CWRL756ZWZTAC
S7RXJJZG4IEIVLPHEWFT5M2T3SRRO5US5SYBPXSYSWJJLXAKNNPAC
P3BVYOM6YV7M33KYMI5XNLZ6F44BBAP3I6NXPNTTCUAAPVPJ3PVQC
BW2EZIIAEAWT5MYAEMTMHOIIQXGZR7FHGU4KO7Q6IEHUF3WZLZRAC
6XZIQSMIVP2GZ5S3UCKEVNDSLTHSQEVSXLV4UIFF3G3SRCGJPXYAC
CJYJF7B4EVOQ52VLDGPXTJSYZEBXJO4S4A5N2DM4IWI6UQ2BZTVQC
NOI4U573ODSPVF6CUC4T7QSYHZGZFHJ4EKTP5Y73LMUZPXK35FKQC
6V3JKJZJ7KBS5I3Q266ZCRJYVO56ZQKLJL4EOHN6XC222CZFXCDQC
7UDWES3V56FD5L7VJXSFC6POZ7SXN4Z2JNJQ3XBVN7KBZD6AXTDQC
MZ734MOA6IYZE7SDSQGTBLYUF5VWLLK7M7E6T3KIY6DBEJR3CFMAC
E7UO6NRGXFDMBU3BSJYRDNOA3Y7VHD7NWPHI5PHCPHQF6ZNOPZLQC
TOFCZFUYVBVEBHMKVG6G5MKCAEF2QCQ4GKMKGQUSJRLGLDZEJF4QC
4QUF4MKRSB5LYYS5FSYTCDSIEMYIERI2BQZLRGJ3GIGVYCPJVEPAC
ZIXAFAJJEKSFECJJW57MQ2Z666IZSJXU5FVAQ2JLG34BEJIV322AC
PMRSYJRYQAXZ3OEDD7ANMXTECMT2DNJEC3XQABRNA63SAOUZWA3AC
DADSQJFKYX6U5JOHSHJWWDSUFC7ZWSZVHFMEKPZEXKPELMEQBL2QC
65GPTMYLVOQPVAKNBCN5RHHZEL7USZYSJ4VJQO7LYBCS7BZM7BYAC
FCEQONUYK6M5ZEWKBAPW6F64EURYKHBH4YIM4HVBSBKFRDD7YHRQC
F72VJF4KJZEYZEYGAGKCWPMEQGPKS7T5PEEJPJKZO6ZG246TTLAQC
BFWKVWAIUKHCZVRA62GW6QZUEUKQLW365HUWIVKTEIPJNJSOZBAQC
BI7H3J3BRWCCZEPPL3RBWEG5OKN25TCVVP3Z2CBIARI56FJS2GWQC
5IGKKZ3URJE5EL5ZVCOKDTIBHRL7DTLKUJXIVYVJ4LRMKYARRNZAC
LJJH53FPOX3RP5PCHNORRMTUSV4DXYYP2A47X6VDZ5KZI6T2DEOAC
7BF4DJIZ4X73ADYFJZZJHQJJUTNHKLEYER6LNVAAWD5VJXPIMSIQC
2GP4MXKEDQMZ7E6TCRSMV2AGN7HLEAHR3QEAC2QFCQQNPMNJSIHQC
HWS332I73ETH3YIIOCQO7WB7VPQICME6GGXFJ7EUWDH5O3KA27QQC
72JCJDBV7H5Y5B5QMBPA2352RBFDICJWOTJZAB4ODHPSYFQPUAUQC
N5UP6P3PMCBSSWFIEOJCZSWBYFDKWZFWBIRUOJQEJ453KZCHU4SAC
XEH27JOXKCN2VZ54BWMIWEVW4IBS2QNU3534SJAPPI3Z4GKBM24QC
O5JVMDEEKP334BAYMJ6HHXROW4X4WC24JHCYZTKJRQE5UGYXV7YQC
UCSTVE5NIAIQ3NJL5YLDFDKDPOCJS6NMAGABSWG67RGCPH47JQEQC
2QL2H4REDZT46FI3LQ4RYEMQYZBNBK3IC3KH3XERAJU3NCZWMNYQC
XJN5KX6Y7ON7XQGCLYJSGUQ3TRNZDV5QFMSN35U3SPGNRCN7B2IAC
ZS3JMIJKWXEQU566WUC2YPXRXWOYY2VKATUYZN7B3V435QBJGHWAC
L4X3HG56S4DS7QJTLMLP47BGCPF2TM5XRUFEN56BTWYJICBYUUEAC
RM7J7D2HLZX66BJZW5O6BLUIDECLCCPQIZH3PXLQOZC67YCBSY6QC
RTF6FIROMZBLFDIGA66N3CZXVXKYJWI7TB5RM3B5X4BU5AFIAEMAC
R2M4FCUNZ7JKU6I7AIFEFJFHRQY7JNWKKI6HKEFSKICL4L2NV6YAC
US4HQXVWZEPU6HZ7Q733QB5QXOD32HJBYHUAQTT3DZGVXBMPNNOAC
WH2QXAEHJ3UWIAS5YCRYXCTROAX4SNC3UESM56HUMM3UGUUAAZQAC
GGLHB6M466D32B57EBNJMZRGNJB2DAKCMHNUKTN25TPZ4LV2GNYQC
ZGRRKB6DZARJGDEE2QL46TBMF6HO37VCQ26SEHMAWJ6SM7POXULAC
TSEUQ7WPEHWRO3XBGDD5BTLEBZ73BY2E63EID5ZBHED7IIUFXZDQC
E2ZMYDURQ5CJ2V2ZC7FEYZDODATF3JS64O6D2REOKRVYV2P336AQC
KP7Q7NW257U3YLYPR3TVNTN4YZCBCDLON5NDDZ425CMVJMCAQBCQC
2SBFINJKOJLIY2COLC4PD2LRMOAAMVA7CJFU57GUL43XGS6QJF5QC
OKQDKOVUGULJA6E4XL4VMUHPT4IOFYBFBJAU7QXNNPP6PJ4DYLVAC
QM6BQVVQOKLO6AYHJ272NTAOXJTVKN4FX7BU6J6YQKWBKEJDDFXQC
PLJJLNS7E2UXW2YARGBSV6IHZEBGL5EW354IMMHPDATY5DQD77DAC
2OQAWQSW5DDGUFJ4YWT5VXHZMRWQPDKZFO3JUPO4SV6JQHWT6HRAC
LRGGX34PR2PQEBW6U465VYOGIYOPD365PB444JGR6R3H7E524CCQC
64B27C6SLNH3P7VXF7X2XJZD5Q4KUPMVNNWAFCXDBDX6UTBYRKGQC
XHVBTXWGXGOVHLFX57RQI54NP2OY3BYI42K4ZODZDHXVZ2VF5YTQC
KCWXWLX3M54OOO65WI4KECOVJNDTON66DQ66KYW5TSQZLQGPFBLQC
52ME2RULOPZQLH3ZKDKNRIR6FZK2BUOHRULMVN7EN5TO4APCKAOAC
RWCXH2L4WZ4U5DZRUGRN6POD7C4WXXLCCSLINRXNBCNYGA7VJD7QC
MMCQLXIFYBYY3MTEIZDI7SI7D4QN4NM7EIGYGHFA43IN7NOERBLAC
OPA33YRIB5AVFBKVANDGJF4IO7ZPPSIAJ75RULIM46SI2YX54ODAC
VU5S7GWUAARNDZWDB6XGP5SHY43DRWPIDE2YQVCZWXI4MBBLDOEAC
FJIYVCRICFJ7T52B2SLJOGFFX6AEYZNOSM3FJZ2B2ETFFYX2QXNAC
QD3NDIJ4CRDN6QGCHALU2UG5DPMAYGE4MSGJPLYVXKLZNCV2WGIAC
KD353LTTUI6LTMYDTNPH3W6NXETRKDTNB6MA64K3WBQC6GSYKPMAC
HHQZAOG5ZVAAVGOEGOYMX2MMMTCDGAXN2AST2MXIHF4RAEEK3MHAC
G2TUE2LWVERJHOQTKETKV5CXSEK6ILOT5DIOVPIZJ2NZ4VYPDDEAC
3YASTKW6ARYFEDXJU2OH2O26NLG24ZKGELZNCRCPSMQ6KJ63OBUQC
/* Used to move all of the data necessary to render a surface from the top-level
* frame handler to the per-surface render function. */
struct render_data {
struct wlr_output *output;
struct timespec *when;
int x, y; /* layout-relative */
};
static void render(struct wlr_surface *surface, int sx, int sy, void *data);
static void renderclients(Monitor *m, struct timespec *now);
static void renderlayer(struct wl_list *layer_surfaces, struct timespec *now);
static Client *xytoclient(double x, double y);
static struct wlr_surface *xytolayersurface(struct wl_list *layer_surfaces,
double x, double y, double *sx, double *sy);
static struct wlr_scene_node *xytonode(double x, double y, struct wlr_surface **psurface,
Client **pc, LayerSurface **pl, double *nx, double *ny);
wl_list_remove(&c->slink);
wl_list_insert(&stack, &c->slink);
/* This isn't easy to do via the current API */
wl_list_remove(&c->scene->state.link);
wl_list_insert(c->scene->parent->state.children.prev, &c->scene->state.link);
int i;
/* Create scene tree for this client and its border */
c->scene = &wlr_scene_tree_create(layers[LyrTile])->node;
c->scene_surface = wlr_scene_surface_tree_create(c->scene, client_surface(c));
c->scene_surface->data = c;
for (i = 0; i < 4; i++) {
c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor);
c->border[i]->node.data = c;
}
/* Insert this client into client lists. */
wl_list_insert(&clients, &c->link);
wl_list_insert(&fstack, &c->flink);
wl_list_insert(&stack, &c->slink);
/* Initialize client geometry with room for border */
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);
/* Tell the client not to try anything fancy */
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);
/* Insert this client into client lists. */
wl_list_insert(&clients, &c->link);
wl_list_insert(&fstack, &c->flink);
if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
cursor->x, cursor->y, &sx, &sy)))
;
else if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
cursor->x, cursor->y, &sx, &sy)))
;
#ifdef XWAYLAND
/* Find an independent under the pointer and send the event along. */
else if ((c = xytoindependent(cursor->x, cursor->y))) {
surface = wlr_surface_surface_at(c->surface.xwayland->surface,
cursor->x - c->surface.xwayland->x - c->bw,
cursor->y - c->surface.xwayland->y - c->bw, &sx, &sy);
/* Find the client under the pointer and send the event along. */
xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy);
/* Otherwise, find the client under the pointer and send the event along. */
}
#endif
else if ((c = xytoclient(cursor->x, cursor->y))) {
surface = client_surface_at(c, cursor->x - c->geom.x - c->bw,
cursor->y - c->geom.y - c->bw, &sx, &sy);
}
else if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
cursor->x, cursor->y, &sx, &sy)))
;
else
surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
cursor->x, cursor->y, &sx, &sy);
}
void
render(struct wlr_surface *surface, int sx, int sy, void *data)
{
/* This function is called for every surface that needs to be rendered. */
struct render_data *rdata = data;
struct wlr_output *output = rdata->output;
double ox = 0, oy = 0;
struct wlr_box obox;
float matrix[9];
enum wl_output_transform transform;
/* We first obtain a wlr_texture, which is a GPU resource. wlroots
* automatically handles negotiating these with the client. The underlying
* resource could be an opaque handle passed from the client, or the client
* could have sent a pixel buffer which we copied to the GPU, or a few other
* means. You don't have to worry about this, wlroots takes care of it. */
struct wlr_texture *texture = wlr_surface_get_texture(surface);
if (!texture)
return;
/* The client has a position in layout coordinates. If you have two displays,
* one next to the other, both 1080p, a client on the rightmost display might
* have layout coordinates of 2000,100. We need to translate that to
* output-local coordinates, or (2000 - 1920). */
wlr_output_layout_output_coords(output_layout, output, &ox, &oy);
/* We also have to apply the scale factor for HiDPI outputs. This is only
* part of the puzzle, dwl does not fully support HiDPI. */
obox.x = ox + rdata->x + sx;
obox.y = oy + rdata->y + sy;
obox.width = surface->current.width;
obox.height = surface->current.height;
scalebox(&obox, output->scale);
/*
* Those familiar with OpenGL are also familiar with the role of matrices
* in graphics programming. We need to prepare a matrix to render the
* client with. wlr_matrix_project_box is a helper which takes a box with
* a desired x, y coordinates, width and height, and an output geometry,
* then prepares an orthographic projection and multiplies the necessary
* transforms to produce a model-view-projection matrix.
*
* Naturally you can do this any way you like, for example to make a 3D
* compositor.
*/
transform = wlr_output_transform_invert(surface->current.transform);
wlr_matrix_project_box(matrix, &obox, transform, 0,
output->transform_matrix);
/* This takes our matrix, the texture, and an alpha, and performs the actual
* rendering on the GPU. */
wlr_render_texture_with_matrix(drw, texture, matrix, 1);
/* This lets the client know that we've displayed that frame and it can
* prepare another one now if it likes. */
wlr_surface_send_frame_done(surface, rdata->when);
wlr_presentation_surface_sampled_on_output(presentation, surface, output);
}
void
renderclients(Monitor *m, struct timespec *now)
{
Client *c, *sel = selclient();
const float *color;
double ox, oy;
int i, w, h;
struct render_data rdata;
struct wlr_box *borders;
struct wlr_surface *surface;
/* Each subsequent window we render is rendered on top of the last. Because
* our stacking list is ordered front-to-back, we iterate over it backwards. */
wl_list_for_each_reverse(c, &stack, slink) {
/* Only render visible clients which show on this monitor */
if (!VISIBLEON(c, c->mon) || !wlr_output_layout_intersects(
output_layout, m->wlr_output, &c->geom))
continue;
surface = client_surface(c);
ox = c->geom.x, oy = c->geom.y;
wlr_output_layout_output_coords(output_layout, m->wlr_output,
&ox, &oy);
if (c->bw) {
w = surface->current.width;
h = surface->current.height;
borders = (struct wlr_box[4]) {
{ox, oy, w + 2 * c->bw, c->bw}, /* top */
{ox, oy + c->bw, c->bw, h}, /* left */
{ox + c->bw + w, oy + c->bw, c->bw, h}, /* right */
{ox, oy + c->bw + h, w + 2 * c->bw, c->bw}, /* bottom */
};
/* Draw window borders */
color = (c == sel) ? focuscolor : bordercolor;
for (i = 0; i < 4; i++) {
scalebox(&borders[i], m->wlr_output->scale);
wlr_render_rect(drw, &borders[i], color,
m->wlr_output->transform_matrix);
}
}
/* This calls our render function for each surface among the
* xdg_surface's toplevel and popups. */
rdata.output = m->wlr_output;
rdata.when = now;
rdata.x = c->geom.x + c->bw;
rdata.y = c->geom.y + c->bw;
client_for_each_surface(c, render, &rdata);
}
renderlayer(struct wl_list *layer_surfaces, struct timespec *now)
{
LayerSurface *layersurface;
wl_list_for_each(layersurface, layer_surfaces, link) {
struct render_data rdata = {
.output = layersurface->layer_surface->output,
.when = now,
.x = layersurface->geo.x,
.y = layersurface->geo.y,
};
wlr_surface_for_each_surface(layersurface->layer_surface->surface,
render, &rdata);
}
}
void
/* Do not render if any XDG clients have an outstanding resize. */
wl_list_for_each(c, &stack, slink) {
if (c->resize) {
wlr_surface_send_frame_done(client_surface(c), &now);
render = 0;
}
}
/* Skip rendering if any XDG clients have an outstanding resize. */
wl_list_for_each(c, &clients, link)
skip = skip || c->resize;
renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &now);
renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &now);
renderclients(m, &now);
#ifdef XWAYLAND
renderindependents(m->wlr_output, &now);
#endif
renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &now);
renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &now);
/* Hardware cursors are rendered by the GPU on a separate plane, and can be
* moved around without re-rendering what's beneath them - which is more
* efficient. However, not all hardware supports hardware cursors. For this
* reason, wlroots provides a software fallback, which we ask it to render
* here. wlr_cursor handles configuring hardware vs software cursors for you,
* and this function is a no-op when hardware cursors are in use. */
wlr_output_render_software_cursors(m->wlr_output, NULL);
/* Render the scene at (-mx, -my) to get this monitor's view.
* wlroots will not render windows falling outside the box. */
wlr_scene_render_output(scene, m->wlr_output, -m->m.x, -m->m.y, NULL);
/* Update scene-graph, including borders */
wlr_scene_node_set_position(c->scene, c->geom.x, c->geom.y);
wlr_scene_node_set_position(c->scene_surface, 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[3]->node, c->geom.width - c->bw, c->bw);
}
void
scalebox(struct wlr_box *box, float scale)
{
box->width = ROUND((box->x + box->width) * scale) - ROUND(box->x * scale);
box->height = ROUND((box->y + box->height) * scale) - ROUND(box->y * scale);
box->x = ROUND(box->x * scale);
box->y = ROUND(box->y * scale);
/* Initialize the scene graph used to lay out windows */
scene = wlr_scene_create();
layers[LyrBg] = &wlr_scene_tree_create(&scene->node)->node;
layers[LyrBottom] = &wlr_scene_tree_create(&scene->node)->node;
layers[LyrTile] = &wlr_scene_tree_create(&scene->node)->node;
layers[LyrFloat] = &wlr_scene_tree_create(&scene->node)->node;
layers[LyrTop] = &wlr_scene_tree_create(&scene->node)->node;
layers[LyrOverlay] = &wlr_scene_tree_create(&scene->node)->node;
/* Find the topmost visible client (if any) at point (x, y), including
* borders. This relies on stack being ordered from top to bottom. */
Client *c;
wl_list_for_each(c, &stack, slink)
if (VISIBLEON(c, c->mon) && wlr_box_contains_point(&c->geom, x, y))
return c;
return NULL;
}
struct wlr_scene_node *node, *pnode;
struct wlr_surface *surface = NULL;
Client *c = NULL;
LayerSurface *l = NULL;
struct wlr_surface *
xytolayersurface(struct wl_list *layer_surfaces, double x, double y,
double *sx, double *sy)
{
LayerSurface *layersurface;
wl_list_for_each_reverse(layersurface, layer_surfaces, link) {
struct wlr_surface *sub;
if (!layersurface->layer_surface->mapped)
continue;
sub = wlr_layer_surface_v1_surface_at(
layersurface->layer_surface,
x - layersurface->geo.x,
y - layersurface->geo.y,
sx, sy);
if (sub)
return sub;
if ((node = wlr_scene_node_at(&scene->node, x, y, nx, ny))) {
if (node->type == WLR_SCENE_NODE_SURFACE)
surface = wlr_scene_surface_from_node(node)->surface;
/* Walk the tree to find a node that knows the client */
for (pnode = node; pnode && !c; pnode = pnode->parent)
c = pnode->data;
if (c && c->type == LayerShell) {
c = NULL;
l = pnode->data;
}
}
}
void
renderindependents(struct wlr_output *output, struct timespec *now)
{
Client *c;
struct render_data rdata;
struct wlr_box geom;
wl_list_for_each_reverse(c, &independents, link) {
geom.x = c->surface.xwayland->x;
geom.y = c->surface.xwayland->y;
geom.width = c->surface.xwayland->width;
geom.height = c->surface.xwayland->height;
/* Only render visible clients which show on this output */
if (!wlr_output_layout_intersects(output_layout, output, &geom))
continue;
rdata.output = output;
rdata.when = now;
rdata.x = c->surface.xwayland->x;
rdata.y = c->surface.xwayland->y;
wlr_surface_for_each_surface(c->surface.xwayland->surface, render, &rdata);
}
}
Client *
xytoindependent(double x, double y)
{
/* Find the topmost visible independent at point (x, y).
* For independents, the most recently created can be used as the "top".
* We rely on the X11 convention of unmapping unmanaged when the "owning"
* client loses focus, which ensures that unmanaged are only visible on
* the current tag. */
Client *c;
wl_list_for_each_reverse(c, &independents, link) {
struct wlr_box geom = {
.x = c->surface.xwayland->x,
.y = c->surface.xwayland->y,
.width = c->surface.xwayland->width,
.height = c->surface.xwayland->height,
};
if (wlr_box_contains_point(&geom, x, y))
return c;
}
return NULL;