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. */}#endifelse 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)));elsesurface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],cursor->x, cursor->y, &sx, &sy);
}voidrender(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);}voidrenderclients(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 XWAYLANDrenderindependents(m->wlr_output, &now);#endifrenderlayer(&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);
}voidscalebox(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;}}
}voidrenderindependents(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;