EQRGODLKSVSPFSUZU7BV5ER72U4QS4ATSBKV544XXQVKKTOSC7EAC NM27KHHDIYDZXM3YNH3TJUG75J7YBJ723VBM4K27RSM6DGYEKHXQC NXW63IJ62NK77SFR2WKZ35CEZYOHBU5RF72ON6VIYB53YNPD6MVQC HVSOS7ZRF3CCOAETGHCBNPG742RLDW7UF5GZ5FBYXDO2LFUXA5RQC 6P3BDREHG34EX64JM3S6KCY7R6LRLCKDVD64OA7ESNC6QJPF73DQC T3WUZ4CKNTRKTK4YTJOMUNTUXAR5TGODQHK2MR37YYXWCBHNEZSQC W37SPE5ZYCKFHQZY2NHZW52KFC6LFDQQQGTAE3EO6G2ZSARYZTMAC AXM5ZQUQP3PWS5UVCBJM5UMICYHK6CERLLQHSTSGUGXCHM6IVDQAC S7M7G6VP7V6W5NBMRQZZB5WCVZNFG6A7UGPXR6SD3VUIFQY55HNAC M3S5337IUCZFRW6R4VUHLUIR5H2VPWVQFYBPMO2KSLG4PK5VPUNAC BGH6P25KGU5NCWYE2GRGKHJSHJPYPHWLJV4YNP4WKDZSBA6PYHYQC KSCKJ5QQQNTPEKNJWGPOJYLIURZJUFAHAO5WARKBOTSZMSUXCYRQC 7SX2FCAXAENDA2GY4UD5W42NFHVAYGNL6QYISS3SKSNQ4VWDSLYQC BJCFR5KY67ZBPSIS7KISVGNTYERXEXHZCULMMTO3OBEOEU6WHNFQC 3TK5YIHO3GEAZNAGG3S2L3CCJOMFC3EMJA5YGLXCHE2AHE5PSS4QC XSWSJEVX3PBLX2FRNX3UCYBVDKC4C5FG7V52HVFWEUKJTX2RKNHQC EFDPJMACTG42EMPCVPCEN5XAG52EKLZZH73DSLXIYLPOY4H5SUJQC I6Z6KWIEXPI5JVIVQCMLXRZJT3ZQ22SHOMT2UPGEWTXXFJ7GNJ7QC 43USN3Y7CDB2OWA6PNH7MTP4SAB25UQ2JZNMLJHVPFWLGX3WIQZQC DRWLFF3QJE234HFDICPBHHGGVE5L3427RILQTNCA227WWRVOYZOAC XH3EYZ7Z2CUJG7W7KI3JF6I4D5JTZ2MBW6YRJAT53V6DJLDAI4GQC DS37FCWLU4T4LQ2PC2BD23YTXSENIYRTWB7GFS2W3NKJ7VSLXXCAC 65L2PNW24TUNNKWXJHXSYEFQXNH27HR3YXLSKMVVRQI5LNEJFMXQC TOOYRW4UUCY7IGVCIUJIBZ7NCDPMKMZSNQSVXG37D4PDYOGSDR3QC 7VGTKZH6YU7XYRQOYUN3UHAZYAO7UIOHONZBOBL726IKUUKEBP4QC GOO4MIWDY35FLKJKRJP6KG32ZNSY7SSQAZNAPCWNNK7Z7L6E7KRAC XPAAAMZSDVXJNF36RIMTTGSM2MVFLJUU3Q5HYC23A2VEINYFSTRAC DLU7ISTBB5XXOZYHQFWZLDXSGURGTNOUUS65YD2DOQRGTEZVAZIQC UK6FXGKR64ZLXYFGN3J3HOLCSF6C3V6GNBTCKTI7EXTLYJXVMBGAC 6OWRW24NFJB3AYE4GRX346CXWOTA3O5XRNCF6KIG4JRR5BEKA26QC Q6FHKKYF5MCT6TAKTP5JRHBB7R6IEQQNMREB5JLAIXVTMIDTZKKQC KFWALFDANWNR7VMESTWV7RHSKBQ33ZEDCLJ4CUVNOQADLJ3LJUIAC 5NRRYLEJ4AWTLQHD6AAWANLPOOLBVUA66YJOC7N3FU4WRP2DQZBQC QWVYKUD2WPG5N3I3LFJ3KL6SJ5GTLCC6IL3PWBM2ACI4FKXKLQ6QC 4H7PW3UQXITXOAF7XQQVOVTXUWRSWHSVLIOR6Y5ZQNAAG5QABNVQC SHIW2UVL5DIRRK642NOPNZPI54UH6JGFOB23STWYMA3AYIWVNG7AC IELBCWXVOODA7RQENOSAXZMCQCL3FNZFI7JHGKVY5NG55SDIKHKAC HS67GPF5X7ZJVUGQINYKW6UIVRJA53NEKXDLM5QPPRTQKX4IDGTQC IJZRH6EWM5ZOSEF7DAVWF6MTA3TCEHRZDN2U3D3OJGMBSTWMZL3AC ZWOPXQLBOGBOGJSPDHVBCKFHJ3C552K52JPAW4WGPPSVHN3AJU2AC 2E4K2Z564WPFT2CUDPD536FZXZJYO3OFC4UFHPOFPE26IHBX6MKQC VAB2INZYCWFZNUZFYFTVJAPBORPDF3XS47YVOKZIJA23WDHVAVGQC 5BKYVJBZYC3JFPKM7VJ5BW7S35AZ6E3MAWOVEWKIB5ZIZJYLTC7AC 7B74AT3BXYB7PVW4F6SGQNPMHOU5TEV5TZ54CG6VSQI46XSEKWXQC IHNPLPDUK3SU5DXWUMM3SOKLD4G57XSIHKVLCFULQYRL7ECKNVWAC 6A7RDSA4PVYCSTDZMQDU5IHIR3AY7DJXTNS27ZDCLVSMI2UBNBJQC XGXZF5T7UFWJQES25XVBJZ4BN53SJ3SXZH3YUB2JUYVPN2PDRPJAC DEWMVR6ZOXJDMECRB47RCED2QPVZWYWHLBB4KHYKXCPXKSLT7NWQC 6US7XFRJWUNIUZHKTODZDU3DX6WO5K3J2G3ECIQYSVBDII3DXGWAC D425ND7AT3F7QJ3CCSESMVDOC3J5C5P32M5SJDBHECZJXLHNQ2FAC JRXMQ2GKMY3ZPLMON4D7OPHU62B4A7PV5FXLYBQMJRNCLVKTUALQC BFWKVWAIUKHCZVRA62GW6QZUEUKQLW365HUWIVKTEIPJNJSOZBAQC TOFCZFUYVBVEBHMKVG6G5MKCAEF2QCQ4GKMKGQUSJRLGLDZEJF4QC WSRZTSPBWOSDVVEINEYXKFBEQ62H66Y3QZ7ZNIRHI4YFDN5C4N3AC NBKUNVS3OI6G2JXUF2OA2NMA7EKDCHS3O2RKOZAY66HCHWJ4T5KAC QO4HGTGWT2R4CXQONLUGEI36G6UGVDMHNR2IOZ47S3H2YTE5TCOQC REPAXEATPLO5OHQX275Y5ZTMIQATFPRK3X7ZS76RH3WNCEPCVYUAC B6TUAMCBEXWFEPZM4UGEFZ4VZRPF5Z6WS4FZR4JFVEDN5IQ42SZAC 2FH7Z3JINBAKWQ5QQM5YR4B43PVGOSPKWDFTIRRI7YYQONERYUVAC PL4DXCW5LO6UQACFWH624ZQGBH3SZU7SSU75EQ67KXU5BY4VKYEQC TBKI4ZJEAL2IJMRG2JFHYLOVQQEOQ7IESPMS2PS7VFSLXTPWHJRQC E7UO6NRGXFDMBU3BSJYRDNOA3Y7VHD7NWPHI5PHCPHQF6ZNOPZLQC OFMBPPFARLKEKUP4ENSHZSIFJOFMO65UZOYO77N4YCXJ2S6PVTMQC UPMIXNYHEKLKPCYWRROMNRA4MLIFSSLMPJH3LUK7LUXMWETHQ7AQC NZZZBRGVI57UXK257IAY7ZPC5DOTWP2HGFZLNS543R2EH5FDHNKQC OCGEJM5ICIQMXPZTLCX23HEXOPOOSD2FLPLU6F4AWIUMZSJY6GSQC NBXXOEK7Y2B5NUYQTJXEYKKMXV26KXGBRUOPPFC5SJUFBLKZZAMQC 4QUF4MKRSB5LYYS5FSYTCDSIEMYIERI2BQZLRGJ3GIGVYCPJVEPAC FEU4KJII73TAZ433FXJBWCQG6QGRDFYBE4LG2F7NSKLZ5CUBMZ7AC EPPTZMTAFXNPO62VJ66ZDLACQRU5K2WSDFSCH7K6IGXKKPKCOEYQC T5LZF6MAZN3S2CDRSWJTJRNOTM24DRE4NQBQI6F2ALYC5ZU74PTAC ZDRTKWCMR4VVGLTCPIAG6YCBTDSZFWJVBRKI2QQYDW5U5OVEMN4AC INFGFQAZC2P57M7B7G32YWZOAMUNVDB4FUMRY6GTQ6ANSMSPLIHAC KJY62KKZ5S7DJU36LOX2IYOHZSFRPINNWNHQ6CMHROZE5EZYPEMQC AU3THYT63RUOPFNNP7BNQQO6X62OW47HGXOOX6GN2CCHEXIKGNJAC KUB4ULGPNSBXFDH46OMH4SRT2A2R4YFFIYEDKW7OFVJU5TSDOIGQC G3QIBFHUXIPZOPRBEVWZ73FN2NVFNK342LFTAE4B2QFMMEZGKIYQC YL6TMLW5YFLMKYPWGTNJHD5GQ2LR2Y7KC4N5U3Y4NBFQXZQ6NRZAC NTMEJFRMCBJVUVLQYUFNYI3NPVYMRMZNK3IKEIX6EAZ3DVXASRXAC VV4T437DES4F55WINIINLWOHFTTLVMZY7E5VRUVWMWHF6UIEWG7QC R5PTRDZ52GPVS3572NJBRZQEBU3YVNUV4KYO4ICNIWQ3UUIPAUMQC DVZNMII7NCB2B6GOP33NWWNND3JDUR3UR2MXVLEOG2DNEP5OOBPAC 5IGKKZ3URJE5EL5ZVCOKDTIBHRL7DTLKUJXIVYVJ4LRMKYARRNZAC I2UG6WQKU6GNMQXFZXVONILKQFYXI7AIGK44KCMDWCQETA3UZW2AC 2GP4MXKEDQMZ7E6TCRSMV2AGN7HLEAHR3QEAC2QFCQQNPMNJSIHQC 2FBILAASURBC6XQLU7Q4NOOTAZMWFFSIB66S4YHWJ5JHYEUAMJWQC OEUI55XGUBOPUZYV3CGHVZOTXTUU57ZWDGTLQH6FC7FMMUQL4CRQC 5IA7GZ3YCEHSL6MWQK4XE6ZSZ2LDT4S7QUPEZOYKIPYQHPGXXA4QC W2IIP5B2G4PR6LRN5C3WYIMROFJV7YIAT5NBMCQTYCEMOZAULMVQC ZEKBZDRVZJFHG75HZQVVQHO4G7RIY5OZTSI5G3BWIF566BRQBXHAC FJIYVCRICFJ7T52B2SLJOGFFX6AEYZNOSM3FJZ2B2ETFFYX2QXNAC O5JVMDEEKP334BAYMJ6HHXROW4X4WC24JHCYZTKJRQE5UGYXV7YQC 7BF4DJIZ4X73ADYFJZZJHQJJUTNHKLEYER6LNVAAWD5VJXPIMSIQC N5UP6P3PMCBSSWFIEOJCZSWBYFDKWZFWBIRUOJQEJ453KZCHU4SAC 24ZMBWYLMODPBAVLT4XNOSETHQXVLXNASYXUIGG2435IT7WIZC5AC K7GMQ3NNZF4Z4RVMTV7FXFDI3NJROAXWNHCH7Y6TYXPFW2Q2C37QC 64STJYAKOVLMNC4VO4OGWNQ4J4LBIETANLDKON2NDPJV7ZEWTDLQC NOJ7YCRN3IEPR3R2SDXJZR7RA5C55TRKZTDY27V7WVD6SYEATQ2AC 2MNQBTVRKKCIBBLZY42PNL5VS5R62LFYKZ2GMCZM6CEEA6PGEKZQC 2OPRUCF6X32U4MLIW3I5LSKCXWJNVDIZJDZQK7W2XNNIEGXC2UVQC WMNBUD2PGH4XJP7UJNQXULQ475EIQUPEDPZOVU4AT2ALU3FHKFEQC Z5Z7GRJMSKQLA2VWSHTK5ZLKUMFHUOYESH3X4SAXAEDZ2NSWAWLAC V24HNYFIMA4SECR4AVQJ2AIVEWOK5XJDMCNFGGGSIT6L2DEFBGJAC IH7QAHDQUTGT7KS2IP7SLDHYDEDX4BCQ4KDRYKIGV5Y477X3ZABQC Q2X3PNJKODBITH6W5ZNPJULJRQN6XJTEVYLEEBUXEAQTHIWUWPAAC R3TFI3G7RUTSZZ445TXSI3J2SICBI3LBKJXFBMULJU64L3F25UHAC W4ZVXVT6B2UNBEQPHD75UMUAC2KPIHBPVYJSLHTS46FG7OP6OI4QC 7QP2Q5MUDMETQEZD2FRAVIFPIFNURQDKWJ32LJCK3XJU56BCPFFAC DGJFEKNKYTSZNU4VGJXLHBOQGRGKYQVDN6IHN25DPKPDEGYQBBAQC UCSTVE5NIAIQ3NJL5YLDFDKDPOCJS6NMAGABSWG67RGCPH47JQEQC EDMIP6NWRBPL24VODBTEDFMVJXWTSO7W7HKYTMXZNQKWNVLANJQQC 7UDWES3V56FD5L7VJXSFC6POZ7SXN4Z2JNJQ3XBVN7KBZD6AXTDQC XUF22VC6FRHE755HMNIKOHMPKGZWSS4WBML4POEN43TH3QYRWRAAC 2MNEWEUDXLYJSIGGRQF55ZYEJCOC7TQ7IHV3SJC5A7NAQ5X5NA7AC 6FEVENN7V6Y36QECBGRVHQWWYFAZR5AH5NEABLBFA4JRMMRHDRLAC FU2WC4UK4Q5M3K3TSKML2HVBNQFJST4DJ2HCOOD4UW5K3RFV6OSAC NLOBELMSKHUSKSMPZ2QSDVIOJRGWV7HNXNIKZ55TMUCH7DI73TAAC LWFDWL3LH5PLBYUJJKI6C24PXWIRLE2UF64GVFLB23JWBSJHJQDQC NC56KN4JMD4LGGP73GW73SKVLISXZQBNE4LT3VV6FFWAITNBUOOAC LYYPWYVJLPUXGDW4QBAUY3643G3ZUNLL65VCYM42Z7WPGYE3E6JQC KNZTVAWZZH2ES6EIZNB3MSQBNQAC4IPUJKOUCBVOPDRP6UQQBBDQC ZSSVUMLBSC7P4VMBM5GPNOBJGCUGYQGSU5SXIIZWX54Y674EZWDAC B2J66BGK3JX4IICMKRKLUFQOP5GD65UMFP7OBEH6VMDVN54E4ZXQC TQOJCCHCKAEC2SZWVQMZW4XRKKBT4VNZHMQOHTDNMCP4XMSVDZ2AC GZ5EL7AQY4CDL5IBPXUF4XKIR7NF6P5HZXXF2BUNK5YJIW5XWUTQC ZJSS4UDVHV6NYWHSI2U4CHCP46CKN3S5XJ3LL2KT4V6FFYHD5D2QC BBVJTFGO2BY35M4RQNBDESF5BZVEHFHWA72WWRMKP2OSFSMPTPXAC PLJJLNS7E2UXW2YARGBSV6IHZEBGL5EW354IMMHPDATY5DQD77DAC 4XZATWRQIRK75HLKR4CHOGRQCSVSYB2W6BR5AQRLRRFJKDDIEODQC RYEGK6T65T2JERD364BNLAFJO2KERYHN52HB6EKRPOY3G6VCJSEQC HIFS24I32X4DPDLGVEK47AC3N2TRDUANPWFOZ5C52K4AGSITZLHAC WXDI7LEXSSMEY36AMMHM3BDHXJVMLL3HPSVJOOE7GFJMCA36CB4QC KCWXWLX3M54OOO65WI4KECOVJNDTON66DQ66KYW5TSQZLQGPFBLQC M7VCIVNL7F4NLYJPCY2W634TERQDSGN3HFI3HZZBOU74G2IHXWZQC 4QDLLONBTF3RRJHEJ5EVCWU5YBKREPHG7NCEA2C7OMHL55K2G7NAC 52ME2RULOPZQLH3ZKDKNRIR6FZK2BUOHRULMVN7EN5TO4APCKAOAC CLFRYF7CROZDF4776NYUZXZ46ZJNH3AEITGA3DOCLZ2QEMMUPOLQC 7L3TU7JVWPBPHN7WF4TJ263BZ6BC3AYRRW6PULFUP5JZUGWWNUSAC RWCXH2L4WZ4U5DZRUGRN6POD7C4WXXLCCSLINRXNBCNYGA7VJD7QC US4HQXVWZEPU6HZ7Q733QB5QXOD32HJBYHUAQTT3DZGVXBMPNNOAC HWS332I73ETH3YIIOCQO7WB7VPQICME6GGXFJ7EUWDH5O3KA27QQC PNZ7OLEKOH5SGRV46BDUGVE2JKS5RVHDMXLLJJZODE6VEZRTKYGAC 65GPTMYLVOQPVAKNBCN5RHHZEL7USZYSJ4VJQO7LYBCS7BZM7BYAC 2OQAWQSW5DDGUFJ4YWT5VXHZMRWQPDKZFO3JUPO4SV6JQHWT6HRAC VZP5KLKVB635ERG2G57KPTUMTPE3BYKBVQCWMFW6GDZ3H5QU74FAC AVOU4HCKZUPX5K6TVRJWVZI5LQRT2XESSVCPIDJ5GIQWGP3J5J5QC XHVBTXWGXGOVHLFX57RQI54NP2OY3BYI42K4ZODZDHXVZ2VF5YTQC ZO37G4TIN3ISIX5QZNMNSXNCXOW3AUUIJEHXAIMSBLSNEV3OE3IQC 6ASWDJYLLOR6DQ3RI774N5LMGQSVX53MG2B5LAVNLZHKZ5TAWTVAC ZDQJLNDNDQPWEEWF2QZDRY5LZNJS653SDUQZDHK6EQPH7N4MHXUQC 5F7NOLLCOKIZTCHKBJR4ELVFJ7P46B22G2WL2ZSQL2CWZ4BPQNWQC XJMR455KTFPEBEVZIPBY7PVPXAF6SABRQG7X6MBZGLOAYZK6KWXQC OPA33YRIB5AVFBKVANDGJF4IO7ZPPSIAJ75RULIM46SI2YX54ODAC 6XZIQSMIVP2GZ5S3UCKEVNDSLTHSQEVSXLV4UIFF3G3SRCGJPXYAC 2QL2H4REDZT46FI3LQ4RYEMQYZBNBK3IC3KH3XERAJU3NCZWMNYQC VU5S7GWUAARNDZWDB6XGP5SHY43DRWPIDE2YQVCZWXI4MBBLDOEAC C3IYU5EQOMXONEDMVSM6SPEGXGQZSUSIPVQOE4OLIQMRI7SDHUFQC JITN3S74SXWXJSPCFNHWVSPF4WXZ575BEYCYE2RUBLEXMUJBTPUQC IIKPVF4PWEWCLOY4656OTCFZJ6KUMBGCHZW6A76AJBI2WJWYROGAC SPGP6FCO4KP6YRECRYV76AWKVCFQU2V7AVNAFT4QH54AAF2Y4DEAC ZCTQJ724XCOD6BTABJD4UWCUIB4JBMOVNLVK2BTK2J6CCNCDJWSAC D5HTYSN3PVRTJEEHTPSYP53HNCCE6PRWA5YSMKVGWM4ELJ5IQEEAC QD3NDIJ4CRDN6QGCHALU2UG5DPMAYGE4MSGJPLYVXKLZNCV2WGIAC 6ZKVISYIRGGLYDMIHGXDCHV6N6WYJP2DK3CRJL4AMCZY65OSEYDAC 5N25IN2JVE2A7FJWC3ZYGBQSH2SOX6NIGD6SDJU6YCX75YMG6KLQC CBXTRF6YOMNM7AIPQR63T3YA63U6QPWE4IQOGNY7F2JAPR6QVGPAC R7M5DZY2NDAELIYA3HNBHQZ37HJKXTESMS6U46OZ2SZVD7KIMJXQC FCEQONUYK6M5ZEWKBAPW6F64EURYKHBH4YIM4HVBSBKFRDD7YHRQC STNAKFBNSAXICF6AJNYSCQKE4YYQGIMZHR7RSLZJBEOSSUMKBCNAC S5I7HVUVLNMAV64UX4AW4OWIB7UTQRGQG6TXBR7ZMZXXLCTVGAJAC VIPO7NAXJ7HWGD5XJEBQI6FBQ2QYR5HTI6UYGK64U4WH6EXPSBOQC XDDA5JPEY3VNHPK32G7GYRFNHF5K5JOIL7QBPK6F7GSR5MNRMAJQC QPIH44BS3UQOFH7SUW5JGWQ7EK6CGTPVBB57PKRU7EOK6PLVTQAQC RVM5OZCQQ4AWCQVPLBNCS4FLWNRQ7EY5E3R2BFZIYNBCSTBLLRQQC WYVKSPRLSTAQDVP3JAQHRDMOSOXSBFALXNANKYXSDHRIWFADKZMAC 3LD373HUEDIOTZZP7RWTC2DQ3I2XIUXIDKXDHPZ6U2B72MBUJB6AC A37WAPYRXHQZLFAMACWUQATUG6SO2YZPPHS7VEWYXZNX2KTUXSEAC BOINFNDI3IZEW4AMYS5P2PNVQGIF5Y7LZVVMT3QFUUHT7CY6736QC WVSX4HL763MHTPSNJOCEXKGYBFYOABSPX637PKY6RAU55FFFY7YQC SLL7ZONJYXEHJVFGEH7HU6ZOKFEOF2HSFNG3AV555PBXCFKL7D3AC ECOJQLQTN3LTJT7DRH7MXAJMZ5A7UOIMKLTNZFODOGE5B2U7EDVAC BMOAOKYHU36BNSV4SENMM3TGC7TPSAZSZBKND2B4YMNDDRHWRPMAC Q3BFKMS4YCHJ66QGNXGPCBEL5HOL5VXNJNR7MZEY4TPO2XH2C4KAC VCNLR5X75OAXVKPZQHF5RUZ7BONBUC6RPGO2NZEUD3FZ7TEVL66AC BOH54DATFCM5ZC6GDQKEU23PQSIOOINLX3UAI47STL7PP56PQUYAC MIZBQX6SKECIVNNGBF3LCR3IHXQVWQ5BJURMRSBNEVEUWFBH3MTQC 5IX4KHKIMDTDIW3ZJZGAIYEKEASNEO2ZYEAQJXSNXE2DOABMR4TQC PYRALXEFRJ5O2NSVSR7WFJ56QNW2VMWYTBKKGJMDLZCHEU4JXZKQC AEOM6GBTSH3NGIN365GS5L2PAUUSXSMDPMYTGJPL7UDMHDWLYXSQC LQPHYO7IIMLXHUD5IK657BO4BE3SGT5HYDRJDU5OFDF5YUXKIRTAC SV4UYATUNO4G473QWSHDFONASDFDGWTEFJD47IRN6RQJOVR5PUTQC EUJMBPB6W6ADQS4ZFMODC4S5WWH6SZIVM5OW46Z6CPMPDOL4HM7QC IVZBYI5KGIDCGTI3FPIIRYFJCPYBZ223LENQ4A4APOQSAZ2XRCRQC CFF6MYUDSO3VVMMCGJR7RPDBSLKDVR3AROFY5ZE33VG52ER2WYWAC QKVRBSFOOQUQMZ3P7CMPA7QCVQW5TXAKWH6NDL3K7Q3Z4GMXOVPQC SOJYAUEXVINKZDEVGWTPR77NCZKS5IZE57IBWMMVLVRCDX7EC4PQC TOHEQJ4RLXZXOUGTQN2OCPCIKSVNGVMSUC4UB3KGCLZV4JUULD2QC C7HAJAVDN5M4RIQAET2RE6DBC43BZG7AMKWLKDRE3WTPGJAUC6UQC FC37JD7W53YYYY7ZFXCYZ3F62BRT5YACMMVNCLAFFIQSCT5H22QAC GX2PWWI3Y7BOEOUIXW5NS4SYX4SXRWUC4TZ4RALA3AVCPX23CUEAC G2TUE2LWVERJHOQTKETKV5CXSEK6ILOT5DIOVPIZJ2NZ4VYPDDEAC 3YASTKW6ARYFEDXJU2OH2O26NLG24ZKGELZNCRCPSMQ6KJ63OBUQC 7RI7UGWKFURXSDLBGBDBLYQCNNAZWMQQU7GNHY6CONXBGIHWICLAC PCHXO6CL7MGW4GX5VXJJ4DAVNKIUH3H3AC6PTS5LOLF6UYWZ25XQC DADSQJFKYX6U5JOHSHJWWDSUFC7ZWSZVHFMEKPZEXKPELMEQBL2QC F3ECDKF3RS2X4IPFALLE5R2QHGGQRL5JA7JTSFTBOEOA4THGJ4TQC 24NXTKJNNOM6P3OPCN7OZE6LGGMFKRWFR6NUZ5JKETRABZA4YAGQC WQ63NGFV5NUX5GTAHWN23SKHDQGGBMMYMQV2RBWP2GCMHEGKR6WQC T6DAHHAHXFVYYMTYUBWWWZ5ZZERFT64JUFENSXO2V3GNXD4WBMUQC Q4AL7C3THEGDN44IYB36QATRYRV22JGNBTYA3LD4ZUXGAITRSJ2AC IWSIO23DR44ZS2MBV66XNR2MIDID2KUNBRUTCEQRE4P5OMVZHSNAC CSPAH4L2TN5OJPO5VXUUBKKBUQLSEZITRDTYA3YLZQE35KUN7PYAC 3NLF4MLNP7HXMGM3CX6BD6MVGU6V22Z7DT7VXYNXF257GAXDW6KQC ST2AX7B3G7YBGOIF45XX3A2DLK2BONI67DHADM4KSLZVPBTUPC5QC YLGDJZL6AA4C63VNGO56QBK5I36CAV6A7PJPQCS6MV3HFPU6YGZAC AM5JOYMT67L4UT4ITRITCSU5COKDZHBDLELWDBU4CGDMJ35NWQOAC D32KHJNN65HEUZ2GBAA23E7TQ4EDGX4GQW7DAUCZE2YTTHOIU6BQC IUOBSL5OUIT4OZWCDBK3TOHG6T72HCA5RTOIFZ5NCVXW3C3FLTWQC B7KRA45PWIXKJBTZGRTQWHUKUXKIRLUW7GIBGZDWMP445TGOCIMQC ZIXAFAJJEKSFECJJW57MQ2Z666IZSJXU5FVAQ2JLG34BEJIV322AC GTZOYCXWCWTCL23VJCIOVMREQ65SKM3X2UOQ732KX7AR46D644OQC D3P2FW5KLXK7TJQEQV56CGEOUHGQ45OMGYQ24TOD3LPUK3T7JHKAC KUCKWBBYTF6AXDCIH6YP2BBSJZV5GJPXTHI4FSS2EOKELIX3ZPTQC 5CZ5FAO42JN4HNYZZBFI7DOE7GQDSLLFDNJNYAZVYS7YMTT3HEYAC YEHKNAGHE3ETYE5A25SSFTEM565LOM3BX3TN3QDQLLTVQMAJJ5XQC 3HPB5ODTWGOTRGDML5LCC4AZVICLRBRBTTPUAWMNU5NBMQ76P5QAC 66TSV5DVW2ILJNGV3EGWPLHHYW2KXGZPCVW4UZ3J4GZOSSR7374AC JZPF3C4POYLQLD2N4WOOBUJ53UCXX2GUI2MBRHUOBWQPJEEEALWQC 4PP7MBYHY3LMNJV4H7QYJ3ZFPCPEHBTDMAPYPCH3OWBVLKF7NIKQC LKIYLQY3RABIGKYY7YJY5EBMWTFGVQQCQR3HOTDGHHLJIM7N3R6AC DW7VJBQRTDYTT5YCBH2MUZYMNXZOM7H4PU7HQBTMDFM3RFVKAOQAC GFTS3IVLML6FY526XUUZAAUDTWZAHJTH7MD4HIC7ZMVZJOOFA7MQC WWYCDUXC3LTWNEZL464AILJV5JXWG2ZGL2BPXSKN24MHEN6GXFLQC HFIKAPN3TBMDVBDG7SZLX4ZJMSFFDGINTO6C2SKO5IVYUILGCQEQC ZS3JMIJKWXEQU566WUC2YPXRXWOYY2VKATUYZN7B3V435QBJGHWAC J6OSBEBQXZR5JZ5TOCCUPELBPUVEQULGCXURXLPY7WFYTDEQOU2AC S7RXJJZG4IEIVLPHEWFT5M2T3SRRO5US5SYBPXSYSWJJLXAKNNPAC 6XZPXDROIJ6BDFKLBQDHMJIEFQUCOCZ7VRK2AJMVJ5QYTLJFPFLAC D3UVBUCXGJOJYSD7QW2KTDQTNMVUYMAOBPN2OGNLM7IZWFOVMG3QC ERBETXYU7NGSWW5LHQ3NSJA2N27JNMDDYMZ74B6IVQTEQMLRP6PAC QAPSVUOF7DV6R2PSLKLZUKC5TMB62ZYOUZ2NA6CHFOU6PSTJULWAC 5M42RUK7QBQHH2TECDIIPDD5KWQZEOGAE2M6PTOSV4CMLOABO4XQC UHGDUY5LVH5S6TZKJXKQ37DUP624WD3IQ34HIZC2E2EKPCTWGKPAC FAGFMJELLBID6PONKHW7CKVRTZLEFAQQRF4FSE3LBCERN2ONFC6QC YPBR3SBNUKK6FRVP2R23PJ3GTVACFNIHGRNGOWK3IQM4UIA4JGYAC J3JCJKBEK46D6NYLWN6KFHTN3A5RYU6SDB4LUFNFH2AINAYICNQQC JET4TDNWNG5GSGMZRWTY7TFEFTQJDHUKJIA2ZJ3XGT4X4KP5KJFQC YQQETCXBXPPLXBU3UPUIIKB3JZCHRFSW7PPP2DR436WVIXNXFUHAC O7NGXVYAM6W2CKJIXBQILGONIRRKXNO6I6YXX2FEVBBQY6MRGPVQC JGK5XPT7C6ADDT7KF34JLNJILUL5NWTSP4RVE3DZD6TOSLCDKV7QC 62GO7V737RZAC63OER322Q6WIUGZBDRJ2OGDK3DRY2YCR7RSRDYAC Z53RRSEGCT3PGEZNNSAREB3WVYOHCTDXXPNAKOWWGCEYW4G2QC4QC XUXHXCDZ4MKBFFQYX7VXQIPF5LULZBHET5WJD6SR5FAC7TALXSDAC OR2DSFSWCKUGE6I62ML7RCDDEW42HZBZGCM7LCON6QRVIK5VN2OAC MZ734MOA6IYZE7SDSQGTBLYUF5VWLLK7M7E6T3KIY6DBEJR3CFMAC 6V3JKJZJ7KBS5I3Q266ZCRJYVO56ZQKLJL4EOHN6XC222CZFXCDQC OPMH4TJKAIMPP5NJDKHP3U3WZILNCOMDBTEBKFON4AHOVS7HEVTQC 6OZ3VUODEBOTXODIJQU5TKXCDEJOWTYHCMCDB4MJ2X3T6EG374SAC 3RU5REBOOAYYK7CJKRFPTSQ7QKD7CPIM6C3I6G6NCE47IRMTRIPAC BHAVCU3626VQYRHL7PPGBXGM3N5GBHTN5L5P74M6BKDAARKQDOAQC QQGHHW5XN2GWROQUW6BRS3W5J5W6ANKEVCP3EC7RTXAA3KCA4GYAC 26Y5FAOMX2BNNR35YSK2UZBZ2SDWOFSARCLRTMWVH7WLUHP3KVBQC PJDNTBE3LRHIN2Q5YH5JT3HQ34KJ7PRQK3KLBGVZW7ZHWRYKZVPAC PJQVRLW3CN4BVBMWOH7R2N5RM5QCWOIGU4CHBVLCBQUW3RLWG6CQC 4VNCBQXHKJMDO7A4KJCFLLU6ORI6ZYOEGJOQWBLGXKF67I3P7V6QC WT554G3D2X4YAEDOCISXRNXQNNMQZVHIUANSJMT2CWRL756ZWZTAC 7QTKZEHTZVV5GLTPUSLQZFCJE3S6KLEMC6ZT4Y2G3O7ITZ35SVNAC 4WVZ2LAGAIQ2EROHNA4T5PWQEEIPJRTA3CBHGAO55NACCUGLKEZQC R2EEZTZFT5S4KDNLI6RTD5X4H6BYJCL6EF24I33DSLUI6E7FBYRQC KCFRNMAN2W7TNJC3BC6P4LIBBU5SQPQEJHAGA2J4QFU2KPMN6JDQC LJJH53FPOX3RP5PCHNORRMTUSV4DXYYP2A47X6VDZ5KZI6T2DEOAC NOI4U573ODSPVF6CUC4T7QSYHZGZFHJ4EKTP5Y73LMUZPXK35FKQC IGF3ON2AZQQX3FSS3QSEVOECUGK3XW4J3QDDWGYTWOVVRRPT2EXAC HW2YJWC6AUWHZBS7KHF3PAWN44XGWSJ5WU47MCHTDCH32L5JN7EQC QL6IFEPOHHUDBY2SGUZNNIRTDSZOSRJIHJKVU54LZSGTPTFPM2UAC ZDQINUTDXQUS7OBW53UEYR6IN7DJLTPBOMRURGYQBGJ2FBROIQVAC AXYOCJJNJECLJKI6EFQRIB4OZDZVSTCC4YEO7YAMS3QVNLXGK5HQC XKWY25ZVEJIJU7R23CEG5CTYRAWKZ5FXSHY3ZEZRGCIWYIKQSLOAC KZZ5LJHBHFEDJPJEFFXY6LHABTMPE3LUO2VCH2I4VRGLE2QYRR5QC KSU7NI4ZRW6YORQTAUVG3YSBSDM55RF6SG2SMOTW7SNAQFEHFVBQC HUA3A5LYU2IXLH7E3LPRIL7HEHU3G3ORVJBSUCH4CTX5NNAFF3SAC WWL35N23TZ2UPTMLXTVLR5KKFWA3H4MHQ5VXZDADRBS22I4A5F5QC MJC3HT2VAXQTX53MRPT3PA3LMNNCI4STEOLLPT4KSSPPDGOAHUXQC CXLGE3YYT2YXJIR7JE6NT27ONH445P5LZIKJHT53R3ZYQ3V4BHMAC 3EKVUJXI7KI4ZCILWWFJ6UNBYAHBS42TZ3PIPXOEXQ24KEFFA72QC NVYH3JEQ32BX26LR5KPYTEW4QJNM2YCOOIHLAINQ7QXNTL7KDJCQC OBJHNI7ZMIJ4R2T6RULIDJQFNBLOWSDDYWPNCPUFKZVMEL6KWAMQC MO5ORR7VSER3YUNO77DZJVKGOVYC2KNDCSC72J4NF7JYOHHTLRQAC MEMJUZF3HSX3M747YTV4LVUCOPRIS75IXAVXZIWLCZN2BHPUZHEQC VWSYJ3CH2IDZIV2GLGEBB3TME2DMMDH4L36YUX7UUP2QEWNTFTDAC CTSHZM6KZHMKQEITRPIUL2PXVU4TFN66M4CDAE33GRWTGN6KLYWQC SEQ6U37LIHEYR2PQNCZJYELYYVEF6KS2N5YN7JCQU6VQCOJ4DKPAC 2OGQ2YPLFUBNUKVQSOI77GEKZGGPDVFPL2VKDHHX4LVOXWP4S5RQC HH5I4HSPYNDRQHIOTASMU5BGFD754OUI4ZGRZQHUE5SM6OTJTEWQC RJ7S5NA6INT3LYOYNXEBBXJRGVZBRVSN2ZVQACWXOGFNBRUYFB2AC IIWDZCVWWDAJITIXQXCFIAF7Z46DTFV2FYCUYMS4P7JMP34A6BUQC VVVXTAJCZ4GUXO6RM3GOOEFHIZOHXRX4II3RSE2NM5HGNVHPMOUQC 5GWZP4P5XROA7WO4XOWNHL2SS3POFUACQLZMP2FR3ET3NJ3TIIMQC N3EKXG5WWWW3CDQ4PJS4EILLTS52CDGXY7B5V3DK6P7TJZEQMJDQC GDGXDTOLKG5RWSGDJCWTDYIRWE2R55UKUVRLDL33KTGJCRXHH3SQC JR5SMOKXLBLXJNPG4RMCYC3ULDLC4AU3XM3A5FLFIH4UGW6JKSSQC K5CMRF3IC47QDZWAWK2FSQEKJQHAMV4JR3H5PWF4IDHLDT53DDCAC TTRGOTCMJB2FCGT6A4NLZ75WGX6O3ZHYFNHPID5QTSPDGVRJS4UQC RM7J7D2HLZX66BJZW5O6BLUIDECLCCPQIZH3PXLQOZC67YCBSY6QC 2X6Y5GAVZKHNJ2DDBVUIU7UQKFWLLFGDX542WJU4QBFLJJCFJNGAC RMV5MH5OBOLKZ46NYZPTAPGJ6O6M7U3HTX5JH3FYQ2SKIPSQWAVQC FDHPVQQGJLCSULJ676SOFOLWE44NELPAVX4GKMF4HABDYTBD3ILAC L2QLSXLWYBIPQD2K7D5MGNCCS3AONK2UA7WDQXT5GVMXELM2BCRQC T5EZYNEH57OJ7X3GMOKNQIP64SOPUPGRC7FFVOZGUVSYKQLERIKAC 7XCGFU3GX4TQXZBOU7GFAQ62EEOTVRNWFYQGI3XULFPSUKDZ2EYAC NNBK7MMS3MCRQGIYBYXVSF4DJVWFVZMXDD3O2W2MUIPL23DJLXOQC MMCQLXIFYBYY3MTEIZDI7SI7D4QN4NM7EIGYGHFA43IN7NOERBLAC CN4FS77B6FLSEDGAQ4R5YGHS56TNW7IGUR7RK4HKCLDX2627VBKAC CJYJF7B4EVOQ52VLDGPXTJSYZEBXJO4S4A5N2DM4IWI6UQ2BZTVQC IZ2KIIKXVGAUR2NRYJMZCTIXUCPWCRQFDXDAE2SAW6NFKINXRPWQC AX4DPXMMD3V3MV2ZMVAWKTDJ67NPQGELE7SMJDGW7VAGUJY5W63QC 4NQNTJRAWLAA6I2I7NJ7LUTMIFXKKBMU5CSMQ3JSSTY3WSKIFNHAC HRPYY7AN45VGEMP4HK7VYJEWRRLE5TFKDIZR3AM5RRJ2AI34G3QQC PJYEVNHWOKY53NR2C2PT6RTRACRSKPSPDFTTLTEOYN3ICAIIN45AC P3BVYOM6YV7M33KYMI5XNLZ6F44BBAP3I6NXPNTTCUAAPVPJ3PVQC QM6BQVVQOKLO6AYHJ272NTAOXJTVKN4FX7BU6J6YQKWBKEJDDFXQC XCR4GSSB7FGHK446WSHZ5ZGQZCP6I36YGW6IF4AC5YATQCKLT2UAC DEYEAIOK6XPZXJXKS4S6EFXRZL7U65VBC2T3ABPDTSTEQRBXY25AC W32YIHMVPAREXUADJOAX45B6CTXZY42EE77RDDZYNJFEE2HLQ3HAC QIIHRSY26Q3QJQUIDTU4M4C5NGAW3NGDOKT5UVZBD25A6UVPQDPQC NHTE5TSHXVCAPG2RXL3JD6HIWDH3BUQO7Y3DVXSLQULF2XG3QZCQC MBGZ5B4CBCVFCGPJQBEIABE36HVZMOPI3WWJKQCAIYA2A6ZEXVBQC OYZELWD247C2GT4QAW6YECUCA2GRLG4VI25BMOZKOGNRKERPZ6AQC 4XX4YR2C7535PZN4U7BZJ55F4ZHHOFPGJXGJMB2XUYEI6OKH5PFAC QDFBAKHJXFFUKZASI36Y25WMR7MNUQOAPYIRIRL6WGIWV45BMSNAC GBB275NC5B7SPX2K7I6BIPHPENDAV5H6VFQN7BGXRODMAAEUTPRQC 46MQCVOAPLYAM3HMYFA7E2B6IXSXO2Z57JNBORUBRL6P2GXADSPQC L4X3HG56S4DS7QJTLMLP47BGCPF2TM5XRUFEN56BTWYJICBYUUEAC DZARK42IRA3GGM2HTCVSMT3IXJATCQCKXPWJKS6CZ23FWRH34YDAC IM5D7DQINVNZPB6MV4Q5TWZU23YM7QMWNCCZNTF4SBBEESV3S2PAC SPM222UZLPKPMWK34K4ZVIJVKI3ZZZFAQ74IANEXX36OE3Y5ZFQAC 6ZTDXB3VJTLPCJOXKML7E4QIN7BXL7IDILOLWB43EBLACXZAO45QC 3EDO6OUSMQ77E3GRBT5QDQ556NF4YEU4LMRXT5IU2MQVOG2D3KUAC SRHFRPHRRPOA4RPND65UFKLIY2KM6HMP2PZMGBYNJ56ABI3Y655QC HNCOIBG56SF5Q55XJDIHSN67EKDV5ZLGEII5XT5S7FX5UXM34KWAC STQCOMJFP365KC42CYLC22QKL3MFWZ5JNVA3LADAVZFMVQKO7K7QC SJYYGTAHOXUL5VHGVPIZKIYQ3JCXQHARIECVKKPBFBSMGIOSDA7AC X2AZU5RIKMQ3NEE3GP4TSQO5OS4X4PJBXW7LFTCNOE4B4JPO5XWQC 7BTBZG6KWANVIT5TKJJS4QJ23PLMJYC4KIEC6BA5NRJVDLPEC2KAC WV5PX6JK4SJCOOZOKPSHW73BVL4WH6SFIPVXMMLVI6I4YH4VEE5AC 34ZVZ4LWAOYLVXC2VO5QZLJHCH4ZKLDJUPILGNFFEPJ6BLTAN3HAC BRPRY4LJCSZ7UYDJF3DW6LF4EJWV7RLYCK25WOEF4XHXDW44KTFAC RE7BLLEBV2AVIBDYUESOIKI5ZPDJ47272ZWJFVEE4MD7LE7OF45AC GVPRPAVLH42RKRJO4AVXWTVCQVRRXL6OQOUVYB3ZHKC3NU5MZLFQC PMRSYJRYQAXZ3OEDD7ANMXTECMT2DNJEC3XQABRNA63SAOUZWA3AC 5VFH6L4OSAROK6AIGY47QVLFKZL2LVCIHJWVWAYLQRL6HLLE3GVQC 2B3SWBLKAAQYLU33YJTU2LQMO337JXHRMWDZA3V3G3IEXIFK5P6QC VMZMREUYGSLGVRMAFFRKGQ3TRRZ5QLDVXQ26OM2KIIGM6MORBDIAC 3EEY5STEAFJZ5GYCSZRNGGDOYB2YF23ZPSGYFSREZN3NR5UHSDSAC 72JCJDBV7H5Y5B5QMBPA2352RBFDICJWOTJZAB4ODHPSYFQPUAUQC 52BEET6JL7L5PXXHSC6TN7K53HVSOIOVGUZTSQJ3OFF2YXC25UNQC LGJV6OQEGISFF4OFJN7VQA3IABSBVWM72RH76MFPCA5EEHIPMKPQC HUEKJA2MHTP6CPNBLKNHT775NLRKNNURXA355X6YWP77OYDYNTNQC PFYWKRX474ZAFT4JGNNIDZISNVAMU7MCSBL6NHQQYZXOXCUW3WCAC QABPNBR63OM7GUPREDFVZEQH3SE55ZGJLSOI7TPFA2KJNJSQMZLAC UDZ2EERBTYRBS54DVKWXAOQY33RXW3SMWZY5KHYDXVWLDY6LL3RQC BZ3O64R2O6IPKBT2U3OIJFSNNHG2PEASPL7AFOTBHRIWA57U4E5AC VQFHLTRH5SLA7WGMCOUV2CJLDOCXRABFLQLTQQ2XB7LLJGUQFZ4QC OKQDKOVUGULJA6E4XL4VMUHPT4IOFYBFBJAU7QXNNPP6PJ4DYLVAC UXGT6OW6ENH6SWLVRF3JVS3WGTXPTKZPVOESJAGUSSLZT2WRASBAC ZT7DMHVYGFANXMWZ7V3CWHCJSOTPGIDVNXZ3PKEQNXG25I3ZD74AC GDIXQLGMO2XD22TWXHBZELMOMRQRR6FLUDI22S4OXYL2Z4OM2XZAC OHAXZDUSN77TGUZFMNO6V4744KH3HDP7SCXVXYEM7EK35KMHOLLAC 6LVZRZGDURMWBUBXHFGV4HGB7L5M2FKCYGJCAU3X2PK74VJQ6RCAC 3ONWXUBO3OC3KAKHAM3VFRVMGNNRE6GXHGLTS6AD2HIV4LDSLKLQC RS7FD3UJQ7HVHZ6I5TW476LSXRHSQS4BZMN6MJDMDQ42JH2MOE6QC 2ZRKX4A24W4WNSLJNPKP3FWB3Y3UCYLWWESTC65P45BQFSJKS4PQC CD2JEM3MH5BXN7ADZAWLJFTRZG7PMDCKISDNJEO472PIBEJHBH2AC KH2HI5AHY3PLRXYTLX5U5IPCOLTOABOLF6EPSMPRU42ZCWOSRSMAC M4ZMV4ICABF3KJGNXYHW47Y7BZDUUKIU4K3EQBBDOFBGFEEHYDPQC 22AOV53ZPZKPZPJGHYOLNJYTUNQEB55NXSDW3HNFXD4IX4KXGHTAC E2R42IRNQ5XSPNVGV6YNTHVQF53UG46G3MZ3HE3KLTRN7LUZLRAQC VYZMMYEO3CEHLATYEHS7G6XBGEVOWDMAXHMHMINACSNF75TH72UAC DASMW24DLDHAN2O6APMHOAVLFIGI7DKCRA2UPP6GLP424UCFLV4QC DI5JM3QZKGN2RLH7PJLPDTQL3JLDYJGV6NHRNB23EZAV6IMJM23AC WH6INE7T37IEIBN7MVHXW6QJRAHVZL7RI7LVTSNSE6Y55HFXQVBAC ZC64T7UNMQIVGZVYRRFGP4UMRXYPB5447FKVG5DM77KXNQPY3D7AC IKYTHOLQMJQ5QTXZ6UJ75LL6XBZSWMIBOYCWF657A3ZF57RZX3NQC XWIRQADLKJFFA2N4HCSVNGUOAMRKJD43MLDRKRR4MTYYYGPYUXOAC FQJ6I2VMQ7L4NS4HFVFMPRYR426RVAHSBMFH2HF6NQKCNEBA35BQC 2JULGXDZBBN35LZSHNV7HNZN6BTGFGLB6GVOMQNOUOHIUHCAHTPAC FUZEZTLBNTVGUNLBGFLMVZOHLGMMHFPQD7USP4JYMGGVXBL2EUBQC 3VV4BEF4XL3UURJHRQ3MEC3E3IIE6KMNKY7DHQTMQ4QBACKIKLMQC SP45PRAMJKF52GEK4TQU6PQQ3AY3KRXCUDGQNUN65UOBA4R6VL6QC CFIOQQFW4UKNDR2FDDHPZN5DBTMELTGUVZDNEZA6OF7WVONVEZJQC DACFL7ZVMNMIL75ZQE5BIXFCRYOWYISZ42OKHOTD4AD5GY63AUWAC QRRSKK2KU2ELH5E6ZGDCCWJRXG6RB5EYFHD324I6LKWADGG56M6QC BP4KULCSEU247KG3K7ODS5ZJH3VD6G7EWPGWZAIRNEZZ3VUEIYOAC 625W47O7SIM55H5CFM7JKX2EN4EIP2TXFVFO7URBZIXQNMX4LBDAC Q63IYM3JPFW56MOE5PFL7U4AJ6BHTRSV7NHO5N3ILDA43MNQ4PZQC AILEOG6JDK6PKFTW6JIDQ5GGSKEZL3DBLHLUHF7KR262QE2FZQFQC VO3MWB6Z442HXCPJQAIFUKJGKNM5HKSZMELZTOBHDPXSVMZONWMQC ZOOCZQBGZ4PCOU54EPPUPWNOIFWCM5RMZ4EFL2WFR7LFJTAMHZGAC KXSIFSLDSIBGAB46RWY67XNWIKEEXOUVOUWR2B6CTTX2VSIISSIAC 4B434DTLYDP6FGLR52756VWYDVI7OQJUDJUNYLNQGEKGZOMXIF2QC VPJQMU6GLXQ34RRPU7ER6CC3UDB2OM3FQWMEPK33LG5LGHNBZTFQC NEWCEW2B2N47C7YC5NJ4YAOFPPO62ESYX7YORUCH7275BX6XW2IAC YPEFSYD2O7BLC6VVQTXQMU4XGNIG2CXJAMV3WVBSWZRDVUSXRQDAC 3QPBTZ4HYU4SED7AIJLATN3ABPIMJDOHMJN2VSGTK66TGW3P5T6AC ZDYKSDYRFFWS24DNKV7TEUZYCHBSLEDP7U7HBWCBR3HWM7LBDOQQC SMPVNWKUULOMWGJELCISIFGBRVX6IKCOQVKIIZMQKDNVVAFRHQYAC RJ533ETG67DQKGRTX2A6N2MFI76GTSU3KFGFAZGCVD33TT3SC67AC 7QPBYBLDDSHGGIU7CWCX5PKUUECVBDTH4H6X2TLLH3HMXXCYVAEAC KDTN5PQWSUUS7QBDQD4Z5WMXQYOZSQN3ENAXYVE3GRSTPUUZ2U7AC HKO3RLWXJ6XLAPIZTBAM7VMWDC3Q4J5KFAHKXINYOTYZE7NWBFSQC 7HUMD4TAMWWBQDOZYCMWQXR66G3IU5WU3IVKTPCSMETSB6VREWTAC GBK2UGQ4CNOPJKFXFXUTHK5AHJ4XG6LFMBWDD62PSTAPUGKKYTLQC SCGPO3IMIRLM6JAGVBLYO6MCN24HTDRMOTBZ36RRDO3R65BZJFAQC 7JQD43QS55Q2YI6OQ6BGVAHSHKQHI3TKD6PXIKYKJZXOVOWFHMWAC 4STIHURYLRLYMGSU325GCLA4C6SURA4TXRNBWBTWST2C6R2H6U2AC DLY7JA3XHX26EHIDTO6N7XVGLIG4FRUDW6NOBAZRRIXSCABZLDVQC VPJKNRN7WO5UAJYYVW3LEAIH55EQ47WBY54FZEX523JCBX273MSAC GBPNNVSTRYC5VBC46GLT5YXUTF5BVIBHORH2EIJFZJ7E6D6SUDDAC createpointer(struct wlr_pointer *pointer)for (r = monrules; r < END(monrules); r++) {wl_list_insert(&mons, &m->link);printstatus();if (!xdg_surface->popup->parent)return;LayerSurface *l = toplevel_from_popup(xdg_surface->popup);if (!l || !l->mon)/* Probably the check of `l` is useless, the only thing that can be NULL* is its monitor */wlr_cursor_attach_input_device(cursor, &pointer->base);}voiddestroydragicon(struct wl_listener *listener, void *data){struct wlr_drag_icon *icon = data;wlr_scene_node_destroy(icon->data);/* Focus enter isn't sent during drag, so refocus the focused node. */focusclient(selclient(), 1);motionnotify(0);wl_list_remove(&c->set_title.link);wl_list_remove(&c->set_hints.link);#endif}wl_list_remove(&c->activate.link);if (c->type != XDGShell) {wl_list_remove(&c->configure.link);#ifdef XWAYLANDwl_list_remove(&c->fullscreen.link);for (i = 0; i < 4; i++)wlr_scene_rect_set_color(c->border[i], focuscolor);/* Don't change border color if there is an exclusive focus or we are* handling a drag operation */if (!exclusive_focus && !seat->drag)client_restack_surface(c);c->isurgent = 0;}wl_list_remove(&c->flink);wl_list_insert(&fstack, &c->flink);selmon = c->mon;if (c && !client_is_unmanaged(c)) {/* Put the new client atop the focus stack and select its monitor */return;if (c && client_surface(c) == old)Client *w = client_from_wlr_surface(old);checkidleinhibitor(NULL);/* We probably should change the name of this, it sounds like* will focus the topmost client of this mon, when actually will* only return that client */arrange(selmon);int i;#ifdef XWAYLAND/* Handle unmanaged clients first so we can return prior create borders */#endif/* Insert this client into client lists. */wl_list_insert(&clients, &c->link);wl_list_insert(&fstack, &c->flink);}voidmaximizenotify(struct wl_listener *listener, void *data){/* This event is raised when a client would like to maximize itself,* typically because the user clicked on the maximize button on* client-side decorations. dwl doesn't support maximization, but* to conform to xdg-shell protocol we still must send a configure.* wlr_xdg_surface_schedule_configure() is used to send an empty reply. */Client *c = wl_container_of(listener, c, maximize);wlr_xdg_surface_schedule_configure(c->surface.xdg);c->mon->un_map = 1;LayerSurface *l;/* Update drag icon's position if any */if (seat->drag && (icon = seat->drag->icon))wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx,cursor->y + icon->surface->sy);}/* Update selmon (even while dragging a window) */if (sloppyfocus)selmon = xytomon(cursor->x, cursor->y);IDLE_NOTIFY_ACTIVITY;if (time) {/* time is 0 in internal calls meant to restore pointer focus. */struct wlr_drag_icon *icon;struct wlr_surface *surface = NULL;Client *c = NULL;double sx = 0, sy = 0;}voidoutputmgrapplyortest(config, 1);}voidoutputmgrtest(struct wl_listener *listener, void *data){struct wlr_output_configuration_v1 *config = data;/* TODO: use a wrapper function? */updatemons(NULL, NULL);wlr_output_configuration_v1_send_failed(config);wlr_output_configuration_v1_destroy(config);elsewlr_output_configuration_v1_send_succeeded(config);if (ok)}}ok &= wlr_output_commit(wlr_output);if (test) {ok &= wlr_output_test(wlr_output);wlr_output_rollback(wlr_output);} else {apply_or_test:wlr_output_enable_adaptive_sync(wlr_output,config_head->state.adaptive_sync_enabled);wlr_output_set_transform(wlr_output, config_head->state.transform);wlr_output_set_scale(wlr_output, config_head->state.scale);/* Don't move monitors if position wouldn't change, this to avoid* wlroots marking the output as manually configured */if (m->m.x != config_head->state.x || m->m.y != config_head->state.y)wlr_output_layout_move(output_layout, wlr_output,config_head->state.x, config_head->state.y);wlr_output_set_custom_mode(wlr_output,config_head->state.custom_mode.width,config_head->state.custom_mode.height,config_head->state.custom_mode.refresh);elseif (config_head->state.mode)wlr_output_set_mode(wlr_output, config_head->state.mode);wlr_output_enable(wlr_output, config_head->state.enabled);if (!config_head->state.enabled)goto apply_or_test;Monitor *m = wlr_output->data;struct wlr_output *wlr_output = config_head->state.output;wl_list_for_each(config_head, &config->heads, link) {int ok = 1;struct wlr_output_configuration_head_v1 *config_head;/** Called when a client such as wlr-randr requests a change in output* configuration. This is only one way that the layout can be changed,* so any Monitor information should be updated by updatemons() after an* output_layout.change event, not here.*/{outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test)void}outputmgrapplyortest(config, 0);outputmgrapply(struct wl_listener *listener, void *data){struct wlr_output_configuration_v1 *config = data;/* Let the client know that the mouse cursor has entered one* of its surfaces, and make keyboard focus follow if desired.* wlroots makes this a no-op if surface is already focused */clock_gettime(CLOCK_MONOTONIC, &now);client_set_bounds(c, geo.width, geo.height);c->geom = geo;struct wlr_box *bbox = interact ? &sgeom : &c->mon->w;if (c->fullscreen_bg)wlr_scene_rect_set_size(c->fullscreen_bg, c->geom.width, c->geom.height);wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);wlr_scene_node_set_position(&c->border[2]->node, 0, 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->scene->node, c->geom.x, c->geom.y);wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);/* Update scene-graph, including borders */}voidc->resize = client_set_size(c, c->geom.width - 2 * c->bw,c->geom.height - 2 * c->bw);/* wlroots makes this a no-op if size hasn't changed */applybounds(c, bbox);{resize(Client *c, struct wlr_box geo, int interact)requeststartdrag(struct wl_listener *listener, void *data){struct wlr_seat_request_start_drag_event *event = data;if (wlr_seat_validate_pointer_grab_serial(seat, event->origin,event->serial))wlr_seat_start_pointer_drag(seat, event->drag, event->serial);elsewlr_data_source_destroy(event->drag->source);}void}voidm->un_map = 0;wlr_scene_output_send_frame_done(m->scene_output, &now);/* Let clients know a frame has been rendered */if (!skip && !wlr_scene_output_commit(m->scene_output))return;* this monitor. *//* Checking m->un_map for every client is not optimal but works */wl_list_for_each(c, &clients, link) {if ((c->resize && m->un_map) || (c->type == XDGShell&& (c->surface.xdg->pending.geometry.width !=c->surface.xdg->current.geometry.width|| c->surface.xdg->pending.geometry.height !=c->surface.xdg->current.geometry.height))) {/* Lie */wlr_surface_send_frame_done(client_surface(c), &now);skip = 1;}}/* Render if no XDG clients have an outstanding resize and are visible on/* Start the backend. This will enumerate outputs and inputs, become the DRM* master, etc */if (!wlr_backend_start(backend))die("startup: backend_start");/* Now that the socket exists and the backend is started, run the startup command */wlr_xcursor_manager_set_cursor_image(cursor_mgr, cursor_image, cursor);* cursor position, and set default cursor image */selmon = xytomon(cursor->x, cursor->y);/* TODO hack to get cursor to display in its initial location (100, 100)* instead of (0, 0) and then jumping. still may not be fully* initialized, as the image/coordinates are not transformed for the* monitor when displayed here */wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y);/* At this point the outputs are initialized, choose initial selmon based onprintstatus();wl_display_run(dpy);wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]);printstatus();if (!c->fullscreen_bg) {c->fullscreen_bg = wlr_scene_rect_create(c->scene,c->geom.width, c->geom.height, fullscreen_bg);wlr_scene_node_lower_to_bottom(&c->fullscreen_bg->node);}/* The xdg-protocol specifies:** If the fullscreened surface is not opaque, the compositor must make* sure that other screen content not part of the same surface tree (made* up of subsurfaces, popups or similarly coupled surfaces) are not* visible below the fullscreened surface.** For brevity we set a black background for all clients*/if (c->fullscreen_bg) {wlr_scene_node_destroy(&c->fullscreen_bg->node);c->fullscreen_bg = NULL;}}arrange(c->mon);printstatus();}voidresize(c, c->prev, 0);} else {/* restore previous size instead of arrange for floating windows since* client positions are set by the user and cannot be recalculated */resize(c, c->mon->m, 0);c->bw = fullscreen ? 0 : borderpx;client_set_fullscreen(c, fullscreen);if (fullscreen) {c->prev = c->geom;if (!c->mon)return;setfullscreen(Client *c, int fullscreen){c->isfullscreen = fullscreen;if (!selmon)return;printstatus();arrange(selmon);if (oldmon == m)return;}void}voidsetpsel(struct wl_listener *listener, void *data){/* This event is raised by the seat when a client wants to set the selection,* usually when the user copies something. wlroots allows compositors to* ignore such requests if they so choose, but in dwl we always honor*/struct wlr_seat_request_set_primary_selection_event *event = data;wlr_seat_set_primary_selection(seat, event->source, event->serial);}voidsetsel(struct wl_listener *listener, void *data){/* This event is raised by the seat when a client wants to set the selection,* usually when the user copies something. wlroots allows compositors to* ignore such requests if they so choose, but in dwl we always honor*/struct wlr_seat_request_set_selection_event *event = data;wlr_seat_set_selection(seat, event->source, event->serial);focusclient(focustop(selmon), 1);}setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */wlr_surface_send_enter(client_surface(c), m->wlr_output);resize(c, c->geom, 0);if (m) {/* Make sure window actually overlaps with the monitor */arrange(oldmon);}wlr_surface_send_leave(client_surface(c), oldmon->wlr_output);if (oldmon) {/* TODO leave/enter is not optimal but works */c->prev = c->geom;c->mon = m;Monitor *oldmon = c->mon;{setmon(Client *c, Monitor *m, unsigned int newtags)}voidif (f < 0.1 || f > 0.9)return;selmon->mfact = f;f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;return;if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange)float f;setmfact(const Arg *arg){#ifdef XWAYLANDsignal(SIGINT, quitsignal);signal(SIGTERM, quitsignal);#elsesignal(SIGCHLD, SIG_IGN);#endiflayers[LyrDragIcon] = wlr_scene_tree_create(&scene->tree);layers[LyrBg] = wlr_scene_tree_create(&scene->tree);layers[LyrBottom] = wlr_scene_tree_create(&scene->tree);layers[LyrTile] = wlr_scene_tree_create(&scene->tree);layers[LyrFloat] = wlr_scene_tree_create(&scene->tree);layers[LyrTop] = wlr_scene_tree_create(&scene->tree);layers[LyrOverlay] = wlr_scene_tree_create(&scene->tree);/* Initialize the scene graph used to lay out windows */scene = wlr_scene_create();wlr_data_control_manager_v1_create(dpy);wlr_primary_selection_v1_device_manager_create(dpy);wlr_single_pixel_buffer_manager_v1_create(dpy);wlr_subcompositor_create(dpy);wlr_viewporter_create(dpy);wlr_gamma_control_manager_v1_create(dpy);wl_signal_add(&output_layout->events.change, &layout_change);wlr_xdg_output_manager_v1_create(dpy, output_layout);idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy);wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create);xdg_shell = wlr_xdg_shell_create(dpy, 4);layer_shell = wlr_layer_shell_v1_create(dpy);wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface);idle_notifier = wlr_idle_notifier_v1_create(dpy);idle = wlr_idle_create(dpy);input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy);/* Use decoration protocols to negotiate server-side decorations */wlr_server_decoration_manager_set_default_mode(wlr_server_decoration_manager_create(dpy),WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);wlr_xdg_decoration_manager_v1_create(dpy);wl_signal_add(&seat->events.request_start_drag, &request_start_drag);wl_signal_add(&seat->events.start_drag, &start_drag);#endifwl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy);motionnotify(0);drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrDragIcon], drag->icon->surface);if (!drag->icon)return;}voidstartdrag(struct wl_listener *listener, void *data){struct wlr_drag *drag = data;togglefullscreen(const Arg *arg){Client *sel = selclient();if (sel)setfullscreen(sel, !sel->isfullscreen);}voidprintstatus();if (layersurface->layer_surface->output&& (layersurface->mon = layersurface->layer_surface->output->data))arrangelayers(layersurface->mon);if (layersurface == exclusive_focus)exclusive_focus = NULL;LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap);layersurface->mapped = 0;wlr_scene_node_set_enabled(&layersurface->scene->node, 0);}voidmotionnotify(0);focusclient(selclient(), 1);if (layersurface->layer_surface->surface ==seat->keyboard_state.focused_surface){unmaplayersurfacenotify(struct wl_listener *listener, void *data)}voidprintstatus();}arrange(selmon);focusclient(focustop(selmon), 1);if (newtagset) {selmon->tagset[selmon->seltags] = newtagset;unsigned int newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0;}voidtoggleview(const Arg *arg){}arrange(selmon);focusclient(focustop(selmon), 1);if (newtags) {sel->tags = newtags;newtags = sel->tags ^ (arg->ui & TAGMASK);Client *sel = selclient();if (!sel)return;unsigned int newtags;toggletag(const Arg *arg){}voidif (sel && !sel->isfullscreen)setfloating(sel, !sel->isfloating);/* return if fullscreen */togglefloating(const Arg *arg){Client *sel = selclient();motionnotify(0);struct wlr_output_configuration_head_v1 *config_head;Client *c;struct wlr_output_configuration_v1 *config =wlr_output_configuration_v1_create();/** Called whenever the output layout changes: adding or removing a* monitor, changing an output's mode or position, etc. This is where* the change officially happens and we update geometry, window* positions, focus, and the stored configuration in wlroots'* output-manager implementation.*//* First remove from the layout the disabled monitors */wl_list_for_each(m, &mons, link) {if (m->wlr_output->enabled)continue;config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);config_head->state.enabled = 0;/* Remove this output from the layout to avoid cursor enter inside it */wlr_output_layout_remove(output_layout, m->wlr_output);closemon(m);memset(&m->m, 0, sizeof(m->m));memset(&m->w, 0, sizeof(m->w));}/* Insert outputs that need to */wl_list_for_each(m, &mons, link)if (m->wlr_output->enabled&& !wlr_output_layout_get(output_layout, m->wlr_output))wlr_output_layout_add_auto(output_layout, m->wlr_output);/* Now that we update the output layout we can get its box */if (!m->wlr_output->enabled)continue;config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y);config_head->state.mode = m->wlr_output->current_mode;config_head->state.x = m->m.x;config_head->state.y = m->m.y;config_head->state.enabled = 1;c->isurgent = 1;printstatus();}}voidif (c && c != selclient()) {Client *c = client_from_wlr_surface(event->surface);urgent(struct wl_listener *listener, void *data){struct wlr_xdg_activation_v1_request_activate_event *event = data;updatetitle(struct wl_listener *listener, void *data){Client *c = wl_container_of(listener, c, set_title);if (c == focustop(c->mon))printstatus();}void}voidwlr_output_manager_v1_set_configuration(output_mgr, config);if (selmon && selmon->wlr_output->enabled)wl_list_for_each(c, &clients, link)if (!c->mon && client_is_mapped(c))setmon(c, selmon, c->tags);}/* Calculate the effective monitor geometry to use for clients */arrangelayers(m);/* Don't move clients to the left output when plugging monitors */arrange(m);wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->m));wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->w));/* Get the effective monitor geometry to use for surfaces */wl_list_for_each(m, &mons, link) {wlr_output_layout_get_box(output_layout, NULL, &sgeom);Monitor *m;{updatemons(struct wl_listener *listener, void *data)printstatus();int focus_order[] = { LyrOverlay, LyrTop, LyrFloat, LyrTile, LyrBottom, LyrBg };const int *layer;/* TODO: why we unset fullscreen when a xwayland client is created? */}#endifxcb_disconnect(xc);if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "left_ptr", 1)))wlr_xwayland_set_cursor(xwayland,xcursor->images[0]->buffer, xcursor->images[0]->width * 4,xcursor->images[0]->width, xcursor->images[0]->height,xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y);/* Set the default XWayland cursor to match the rest of dwl. *//* assign the one and only seat */wlr_xwayland_set_seat(xwayland, seat);netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR");netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY");xcb_connection_t *xc = xcb_connect(xwayland->display_name, NULL);int err = xcb_connection_has_error(xc);if (err) {fprintf(stderr, "xcb_connect to X server failed with code %d\n. Continuing with degraded functionality.\n", err);return;}/* Collect atoms we are interested in. If getatom returns 0, we will* not detect that window type. */netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG");netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH");struct wlr_xcursor *xcursor;xwaylandready(struct wl_listener *listener, void *data){else if (c == 'v')die("dwl " VERSION);wlr_layer_surface->data = layersurface;wlr_layer_surface->current = old_state;arrangelayers(layersurface->mon);layersurface->mapped = 1;&layersurface->link);/* Temporarily set the layer's current state to pending* so that we can easily arrange it*/old_state = wlr_layer_surface->current;wlr_layer_surface->current = wlr_layer_surface->pending;wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->pending.layer],layersurface->scene->node.data = layersurface;layersurface->scene = layersurface->scene_layer->tree;layersurface->popups = wlr_layer_surface->surface->data =&wlr_scene_tree_create(layers[wlr_layer_surface->pending.layer])->node;layersurface->scene_layer = wlr_scene_layer_surface_v1_create(layers[wlr_layer_surface->pending.layer], wlr_layer_surface);layersurface->mon = wlr_layer_surface->output->data;LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy,destroylayersurfacenotify);LISTEN(&wlr_layer_surface->events.map, &layersurface->map,maplayersurfacenotify);LISTEN(&wlr_layer_surface->events.unmap, &layersurface->unmap,unmaplayersurfacenotify);layersurface->layer_surface = wlr_layer_surface;&layersurface->surface_commit, commitlayersurfacenotify);layersurface = ecalloc(1, sizeof(LayerSurface));layersurface->type = LayerShell;LISTEN(&wlr_layer_surface->surface->events.commit,wlr_layer_surface->output = selmon ? selmon->wlr_output : NULL;if (!wlr_layer_surface->output)wlr_layer_surface_v1_destroy(wlr_layer_surface);if (!wlr_layer_surface->output)struct wlr_layer_surface_v1_state old_state;}voidcreatelayersurface(struct wl_listener *listener, void *data){struct wlr_layer_surface_v1 *wlr_layer_surface = data;LayerSurface *layersurface;size_t i;wlr_output_init_render(wlr_output, alloc, drw);m->wlr_output = wlr_output;Monitor *m = wlr_output->data = ecalloc(1, sizeof(*m));const MonitorRule *r;struct wlr_output *wlr_output = data;* monitor) becomes available. *//* This event is raised by the backend when a new output (aka a display or{createmon(struct wl_listener *listener, void *data)}voidwl_list_insert(&keyboards, &kb->link);/* And add the keyboard to our list of keyboards */wlr_seat_set_keyboard(seat, keyboard);LISTEN(&keyboard->events.modifiers, &kb->modifiers, keypressmod);LISTEN(&keyboard->events.key, &kb->key, keypress);LISTEN(&keyboard->base.events.destroy, &kb->destroy, cleanupkeyboard);/* Here we set up listeners for keyboard events. */wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay);xkb_keymap_unref(keymap);xkb_context_unref(context);wlr_keyboard_set_keymap(keyboard, keymap);XKB_KEYMAP_COMPILE_NO_FLAGS);keymap = xkb_keymap_new_from_names(context, &xkb_rules,context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);/* Prepare an XKB keymap and assign it to the keyboard. */kb->wlr_keyboard = keyboard;Keyboard *kb = keyboard->data = ecalloc(1, sizeof(*kb));struct xkb_context *context;struct xkb_keymap *keymap;{}die("Usage: %s [-v] [-s startup command]", argv[0]);usage:return EXIT_SUCCESS;cleanup();setup();run(startup_cmd);die("XDG_RUNTIME_DIR must be set");if (!getenv("XDG_RUNTIME_DIR"))/* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */if (optind < argc)goto usage;}goto usage;elsestartup_cmd = optarg;if (c == 's')while ((c = getopt(argc, argv, "s:hv")) != -1) {int c;char *startup_cmd = NULL;intmain(int argc, char *argv[]){}void/* WNOWAIT leaves the child in a waitable state, in case this is the* XWayland process*/while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid&& in.si_pid != xwayland->server->pid)waitpid(in.si_pid, NULL, 0);die("can't install SIGCHLD handler:");}voidsigchld(int unused){siginfo_t in;/* We should be able to remove this function in favor of a simple* signal(SIGCHLD, SIG_IGN);* but the Xwayland implementation in wlroots currently prevents us from* setting our own disposition for SIGCHLD.*/if (signal(SIGCHLD, sigchld) == SIG_ERR)}voidsethints(struct wl_listener *listener, void *data){Client *c = wl_container_of(listener, c, set_hints);if (c != selclient()) {c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints);printstatus();}if ((reply = xcb_intern_atom_reply(xc, cookie, NULL)))atom = reply->atom;free(reply);return atom;xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name);xcb_intern_atom_reply_t *reply;}Atomgetatom(xcb_connection_t *xc, const char *name){Atom atom = 0;LISTEN(&xwayland_surface->events.destroy, &c->destroy, destroynotify);LISTEN(&xwayland_surface->events.request_fullscreen, &c->fullscreen,fullscreennotify);LISTEN(&xwayland_surface->events.set_title, &c->set_title, updatetitle);LISTEN(&xwayland_surface->events.set_hints, &c->set_hints, sethints);LISTEN(&xwayland_surface->events.request_configure, &c->configure,configurex11);LISTEN(&xwayland_surface->events.request_activate, &c->activate, activatex11);LISTEN(&xwayland_surface->events.map, &c->map, mapnotify);LISTEN(&xwayland_surface->events.unmap, &c->unmap, unmapnotify);/* Listen to the various events it can emit */c->surface.xwayland = xwayland_surface;c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed;c->bw = borderpx;c = xwayland_surface->data = ecalloc(1, sizeof(*c));/* Allocate a Client for this surface */setfullscreen(c, 0);wl_list_for_each(c, &clients, link)if (c->isfullscreen && VISIBLEON(c, c->mon))Client *c;struct wlr_xwayland_surface *xwayland_surface = data;createnotifyx11(struct wl_listener *listener, void *data){}voidstruct wlr_xwayland_surface_configure_event *event = data;wlr_xwayland_surface_configure(c->surface.xwayland,event->x, event->y, event->width, event->height);configurex11(struct wl_listener *listener, void *data){Client *c = wl_container_of(listener, c, configure);}void/* Only "managed" windows can be activated */if (c->type == X11Managed)wlr_xwayland_surface_activate(c->surface.xwayland, 1);Client *c = wl_container_of(listener, c, activate);}#ifdef XWAYLANDvoidactivatex11(struct wl_listener *listener, void *data){arrange(selmon);focusclient(sel, 1);wl_list_remove(&sel->link);wl_list_insert(&clients, &sel->link);/* If we passed sel, move c to the front; otherwise, move sel to the* front */if (!sel)sel = c;return;/* Return if no other tiled window was found */if (&c->link == &clients)}sel = NULL;break;if (c != sel)wl_list_for_each(c, &clients, link)if (VISIBLEON(c, selmon) && !c->isfloating) {/* Search for the first tiled window that is not sel, marking sel as* NULL if we pass it along the way */return;if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating)Client *c, *sel = selclient();voidzoom(const Arg *arg){}if (psurface) *psurface = surface;if (pc) *pc = c;if (pl) *pl = l;return node;}if (surface)break;}c = pnode->data;if (c && c->type == LayerShell) {c = NULL;l = pnode->data;}for (pnode = node; pnode && !c; pnode = &pnode->parent->node)/* Walk the tree to find a node that knows the client */if (node->type == WLR_SCENE_NODE_BUFFER)surface = wlr_scene_surface_from_buffer(wlr_scene_buffer_from_node(node))->surface;if ((node = wlr_scene_node_at(&layers[*layer]->node, x, y, nx, ny))) {for (layer = focus_order; layer < END(focus_order); layer++) {struct wlr_scene_node *node, *pnode;struct wlr_surface *surface = NULL;Client *c = NULL;LayerSurface *l = NULL;{struct wlr_scene_node *xytonode(double x, double y, struct wlr_surface **psurface,Client **pc, LayerSurface **pl, double *nx, double *ny)Monitor *xytomon(double x, double y){struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y);return o ? o->data : NULL;}}createkeyboard(&keyboard->keyboard);voidvirtualkeyboard(struct wl_listener *listener, void *data){struct wlr_virtual_keyboard_v1 *keyboard = data;}arrange(selmon);focusclient(focustop(selmon), 1);return;selmon->seltags ^= 1; /* toggle sel tagset */if (arg->ui & TAGMASK)selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])view(const Arg *arg){}voidprintstatus();wlr_scene_node_destroy(&c->scene->node);wl_list_remove(&c->commit.link);if (client_is_unmanaged(c)) {if (c == exclusive_focus)exclusive_focus = NULL;if (client_surface(c) == seat->keyboard_state.focused_surface)focusclient(selclient(), 1);} else {wl_list_remove(&c->link);setmon(c, NULL, 0);wl_list_remove(&c->flink);}if (c->mon)c->mon->un_map = 1;if (c == grabc) {cursor_mode = CurNormal;grabc = NULL;}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);}i++;}}voidty += c->geom.height;resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,.width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0);} else {my += c->geom.height;resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,.height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0);if (i < m->nmaster) {continue;if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)i = my = ty = 0;wl_list_for_each(c, &clients, link) {mw = m->w.width;elsemw = m->nmaster ? m->w.width * m->mfact : 0;if (n == 0)return;if (n > m->nmaster)n++;if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)wl_list_for_each(c, &clients, link)Client *c;unsigned int i, n = 0, mw, my, ty;tile(Monitor *m){}voidif (sel)setmon(sel, dirtomon(arg->i), 0);tagmon(const Arg *arg){Client *sel = selclient();void}printstatus();}arrange(selmon);focusclient(focustop(selmon), 1);}voidtag(const Arg *arg){Client *sel = selclient();if (sel && arg->ui & TAGMASK) {sel->tags = arg->ui & TAGMASK;}die("dwl: execvp %s failed:", ((char **)arg->v)[0]);setsid();execvp(((char **)arg->v)[0], (char **)arg->v);dup2(STDERR_FILENO, STDOUT_FILENO);spawn(const Arg *arg){if (fork() == 0) {void}} else {fprintf(stderr, "failed to setup XWayland X server, continuing without it\n");}setenv("DISPLAY", xwayland->display_name, 1);wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface);wl_signal_add(&xwayland->events.ready, &xwayland_ready);if (xwayland) {xwayland = wlr_xwayland_create(dpy, compositor, 1);/** Initialise the XWayland X server.* It will be started when the first X client is started.*/#ifdef XWAYLANDwlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend));output_mgr = wlr_output_manager_v1_create(dpy);wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);wl_signal_add(&output_mgr->events.test, &output_mgr_test);wl_signal_add(&seat->events.request_set_cursor, &request_cursor);wl_signal_add(&seat->events.request_set_selection, &request_set_sel);wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel);seat = wlr_seat_create(dpy, "seat0");virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard,&new_virtual_keyboard);wl_signal_add(&backend->events.new_input, &new_input);wl_list_init(&keyboards);/** Configures a seat, which is a single "seat" at which a user sits and* operates the computer. This conceptually includes up to one keyboard,* pointer, touch, and drawing tablet device. We also rig up a listener to* let us know when new input devices are available on the backend.*/wl_signal_add(&cursor->events.frame, &cursor_frame);wl_signal_add(&cursor->events.axis, &cursor_axis);wl_signal_add(&cursor->events.button, &cursor_button);wl_signal_add(&cursor->events.motion_absolute, &cursor_motion_absolute);wl_signal_add(&cursor->events.motion, &cursor_motion);/** wlr_cursor *only* displays an image on screen. It does not move around* when the pointer moves. However, we can attach input devices to it, and* it will generate aggregate events for all of them. In these events, we* can choose how we want to process them, forwarding them to clients and* moving the cursor around. More detail on this process is described in my* input handling blog post:** https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html** And more comments are sprinkled throughout the notify functions above.*/cursor_mgr = wlr_xcursor_manager_create(NULL, 24);* HiDPI support). Scaled cursors will be loaded with each output. *//* Creates an xcursor manager, another wlroots utility which loads up* Xcursor themes to source cursor images from and makes sure that cursor* images are available at all scale factors on the screen (necessary forcursor = wlr_cursor_create();wlr_cursor_attach_output_layout(cursor, output_layout);/** Creates a cursor, which is a wlroots utility for tracking the cursor* image shown on screen.*/wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface);wl_list_init(&fstack);wl_list_init(&clients);** https://drewdevault.com/2018/07/29/Wayland-shells.html*/* Wayland protocol which is used for application windows. For more* detail on shells, refer to the article:/* Set up our client lists and the xdg-shell. The xdg-shell is awl_signal_add(&backend->events.new_output, &new_output);wl_list_init(&mons);/* Configure a listener to be notified when new outputs are available on the* backend. */output_layout = wlr_output_layout_create();/* Creates an output layout, which a wlroots utility for working with an* arrangement of screens in a physical layout. *//* Initializes the interface used to implement urgency hints */activation = wlr_xdg_activation_v1_create(dpy);wl_signal_add(&activation->events.request_activate, &request_activate);wlr_data_device_manager_create(dpy);wlr_screencopy_manager_v1_create(dpy);wlr_export_dmabuf_manager_v1_create(dpy);compositor = wlr_compositor_create(dpy, drw);* to dig your fingers in and play with their behavior if you want. Note that* the clients cannot set the selection directly without compositor approval,* see the setsel() function. *//* This creates some hands-off wlroots interfaces. The compositor is* necessary for clients to allocate surfaces and the data device manager* handles the clipboard. Each of these wlroots interfaces has room for youdie("couldn't create allocator");/* Create a default allocator */if (!(alloc = wlr_allocator_autocreate(backend, drw)))wlr_renderer_init_wl_display(drw, dpy);die("couldn't create renderer");/* Create a renderer with the default implementation */if (!(drw = wlr_renderer_autocreate(backend)))die("couldn't create backend");if (!(backend = wlr_backend_autocreate(dpy)))/* The backend is a wlroots feature which abstracts the underlying input and* output hardware. The autocreate option will choose the most suitable* backend based on the current environment, such as opening an X11 window* if an X11 server is running. The NULL argument here optionally allows you* to pass in a custom renderer if wlr_renderer doesn't meet your needs. The* backend uses the renderer, for example, to fall back to software cursors* if the backend does not support hardware cursors (some older GPUs* don't). */sigchld(0);/* Set up signal handlers *//* The Wayland display is managed by libwayland. It handles accepting* clients from the Unix socket, manging Wayland globals, and so on. */dpy = wl_display_create();/* Force line-buffered stdout */setvbuf(stdout, NULL, _IOLBF, 0);{setup(void)void/* arg > 1.0 will set mfact absolutely */}arrange(selmon);/* TODO change layout symbol? */if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])selmon->sellt ^= 1;if (arg && arg->v)selmon->lt[selmon->sellt] = (Layout *)arg->v;setlayout(const Arg *arg){}voidarrange(c->mon);c->isfloating = floating;{setfloating(Client *c, int floating)}voidevent->hotspot_x, event->hotspot_y);wlr_cursor_set_surface(cursor, event->surface,* actually has pointer focus first. If so, we can tell the cursor to* use the provided surface as the cursor image. It will set the* hardware cursor on the output that it's currently on and continue to* do so as the cursor moves between outputs. */if (event->seat_client == seat->pointer_state.focused_client)/* This can be sent by any client, so we check to make sure this one iscursor_image = NULL;return;if (cursor_mode != CurNormal && cursor_mode != CurPressed)/* If we're "grabbing" the cursor, don't use the client's image, we will* restore it after "grabbing" sending a leave event, followed by a enter* event, which will result in the client requesting set the cursor surface *//* This event is raised by the seat when a client provides a cursor image */struct wlr_seat_pointer_request_set_cursor_event *event = data;setcursor(struct wl_listener *listener, void *data){void}Client *selclient(void){Client *c = wl_container_of(fstack.next, c, flink);if (wl_list_empty(&fstack) || !VISIBLEON(c, selmon))return NULL;return c;}/* Run the Wayland event loop. This does not return until you exit the* compositor. Starting the backend rigged up all of the necessary event* loop configuration to listen to libinput events, DRM events, generate* frame events at the refresh rate, and so on. *//* If nobody is reading the status output, don't terminate */signal(SIGPIPE, SIG_IGN);}close(piperw[0]);close(piperw[1]);dup2(piperw[1], STDOUT_FILENO);}die("startup: execl:");execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL);close(piperw[1]);close(piperw[0]);dup2(piperw[0], STDIN_FILENO);if (child_pid == 0) {die("startup: fork:");if ((child_pid = fork()) < 0)if (pipe(piperw) < 0)die("startup: pipe:");int piperw[2];if (startup_cmd) {setenv("WAYLAND_DISPLAY", socket, 1);die("startup: display_add_socket_auto");if (!socket)const char *socket = wl_display_add_socket_auto(dpy);/* Add a Unix socket to the Wayland display. */run(char *startup_cmd){struct timespec now;int skip = 0;Client *c;Monitor *m = wl_container_of(listener, m, frame);/* This function is called every time an output is ready to display a frame,* generally at the output's refresh rate (e.g. 60Hz). */{rendermon(struct wl_listener *listener, void *data)}voidquitsignal(int signo){quit(NULL);}voidwl_display_terminate(dpy);{quit(const Arg *arg)}voidprintf("%s layout %s\n", m->wlr_output->name, m->lt[m->sellt]->symbol);}printf("%s tags %u %u %u %u\n", m->wlr_output->name, occ, m->tagset[m->seltags],sel, urg);printf("%s selmon %u\n", m->wlr_output->name, m == selmon);sel = 0;}printf("%s fullscreen \n", m->wlr_output->name);printf("%s floating \n", m->wlr_output->name);printf("%s title \n", m->wlr_output->name);sel = c->tags;} else {printf("%s title %s\n", m->wlr_output->name, client_get_title(c));printf("%s fullscreen %u\n", m->wlr_output->name, c->isfullscreen);printf("%s floating %u\n", m->wlr_output->name, c->isfloating);if ((c = focustop(m))) {}if (c->mon != m)continue;occ |= c->tags;if (c->isurgent)urg |= c->tags;wl_list_for_each(c, &clients, link) {occ = urg = 0;wl_list_for_each(m, &mons, link) {Client *c;unsigned int occ, urg, sel;}voidprintstatus(void){Monitor *m = NULL;wlr_seat_pointer_notify_motion(seat, time, sx, sy);wlr_seat_pointer_notify_enter(seat, surface, sx, sy);}clock_gettime(CLOCK_MONOTONIC, &now);time = now.tv_sec * 1000 + now.tv_nsec / 1000000;if (internal_call) {return;}/* If surface is NULL, clear pointer focus */if (!surface) {wlr_seat_pointer_notify_clear_focus(seat);if (sloppyfocus && !internal_call && c && !client_is_unmanaged(c))focusclient(c, 0);struct timespec now;int internal_call = !time;{pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,uint32_t time)void}break;}(cursor_image = "bottom_right_corner"), cursor);break;case CurResize:/* Doesn't work for X11 output - the next absolute motion event* returns the cursor to where it started */wlr_cursor_warp_closest(cursor, NULL,grabc->geom.x + grabc->geom.width,grabc->geom.y + grabc->geom.height);wlr_xcursor_manager_set_cursor_image(cursor_mgr,wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "fleur"), cursor);grabcx = cursor->x - grabc->geom.x;grabcy = cursor->y - grabc->geom.y;switch (cursor_mode = arg->ui) {case CurMove:setfloating(grabc, 1);/* Float the window and tell motionnotify to grab it */return;if (!grabc || client_is_unmanaged(grabc))return;xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL);if (cursor_mode != CurNormal && cursor_mode != CurPressed){moveresize(const Arg *arg)void}motionnotify(event->time_msec);wlr_cursor_move(cursor, &event->pointer->base, event->delta_x, event->delta_y);/* The cursor doesn't move unless we tell it to. The cursor automatically* handles constraining the motion to the output layout, as well as any* special configuration applied for the specific input device which* generated the event. You can pass NULL for the device if you want to move* the cursor around without any input. */struct wlr_pointer_motion_event *event = data;/* This event is forwarded by the cursor when a pointer emits a _relative_* pointer motion event (i.e. a delta) */motionrelative(struct wl_listener *listener, void *data){void}pointerfocus(c, surface, sx, sy, time);wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "left_ptr"), cursor);if (!surface && !seat->drag && (!cursor_image || strcmp(cursor_image, "left_ptr")))* off of a client or over its border. */* default. This is what makes the cursor image appear when you move it/* If there's no client surface under the cursor, set the cursor image to a}if ((l = toplevel_from_wlr_layer_surface(seat->pointer_state.focused_surface))) {surface = seat->pointer_state.focused_surface;sx = cursor->x - l->geom.x;sy = cursor->y - l->geom.y;}if (cursor_mode == CurPressed && !seat->drag) {/* Find the client under the pointer and send the event along. */xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy);return;}resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,.width = cursor->x - grabc->geom.x, .height = cursor->y - grabc->geom.y}, 1);} else if (cursor_mode == CurResize) {return;resize(grabc, (struct wlr_box){.x = cursor->x - grabcx, .y = cursor->y - grabcy,.width = grabc->geom.width, .height = grabc->geom.height}, 1);/* Move the grabbed client to the new position. */if (cursor_mode == CurMove) {/* If we are currently grabbing the mouse, handle and return */{motionnotify(uint32_t time)void}motionnotify(event->time_msec);struct wlr_pointer_motion_absolute_event *event = data;wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y);/* This event is forwarded by the cursor when a pointer emits an _absolute_* motion event, from 0..1 on each axis. This happens, for example, when* wlroots is running under a Wayland window rather than KMS+DRM, and you* move the mouse over the window. You could enter the window from any edge,* so we have to warp the mouse there. There is also some hardware which* emits these events. */{motionabsolute(struct wl_listener *listener, void *data)}voidwlr_scene_node_raise_to_top(&c->scene->node);if ((c = focustop(m)))}resize(c, m->w, 0);continue;if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)monocle(Monitor *m){Client *c;wl_list_for_each(c, &clients, link) {void}printstatus();} else {applyrules(c);}setmon(c, p->mon, p->tags);wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]);c->isfloating = 1;if ((p = client_get_parent(c))) {/* Set initial monitor, tags, floating status, and focus:* we always consider floating, clients that have parent and thus* we set the same tags and monitor than its parent, if not* try to apply rules for them */client_get_geometry(c, &c->geom);c->geom.width += 2 * c->bw;c->geom.height += 2 * c->bw;/* Initialize client geometry with room for border */client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);}for (i = 0; i < 4; i++) {c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor);c->border[i]->node.data = c;wlr_scene_rect_set_color(c->border[i], bordercolor);return;}if (client_wants_focus(c)) {focusclient(c, 1);exclusive_focus = c;}c->geom.y + borderpx);wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]);wlr_scene_node_set_position(&c->scene->node, c->geom.x + borderpx,/* Unmanaged clients always are floating */client_get_geometry(c, &c->geom);if (client_is_unmanaged(c)) {c->scene->node.data = c->scene_surface->node.data = c;LISTEN(&client_surface(c)->events.commit, &c->commit, commitnotify);}* wlr_xwayland_surface doesn't have wlr_surface yet. *//* Ideally we should do this in createnotify{,x11} but at that momentclient_surface(c)->data = c->scene;if (client_surface(c)) {? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg): wlr_scene_subsurface_tree_create(c->scene, client_surface(c));c->scene_surface = c->type == XDGShellc->scene = wlr_scene_tree_create(layers[LyrTile]);int i;/* Create scene tree for this client and its border */Client *p, *c = wl_container_of(listener, c, map);/* Called when the surface is mapped, or ready to display on-screen. */{mapnotify(struct wl_listener *listener, void *data)}voidmotionnotify(0);LayerSurface *l = wl_container_of(listener, l, map);wlr_surface_send_enter(l->layer_surface->surface, l->mon->wlr_output);{maplayersurfacenotify(struct wl_listener *listener, void *data)void}if (sel)client_send_close(sel);}voidkillclient(const Arg *arg){Client *sel = selclient();&kb->wlr_keyboard->modifiers);wlr_seat_keyboard_notify_modifiers(seat,/* Send modifiers to the client. */wlr_seat_set_keyboard(seat, kb->wlr_keyboard);*/* A seat can only have one keyboard, but this is a limitation of the* Wayland protocol - not wlroots. We assign all connected keyboards to the* same seat. You can swap out the underlying wlr_keyboard like this and* wlr_seat handles this transparently./*Keyboard *kb = wl_container_of(listener, kb, modifiers);/* This event is raised when a modifier key, such as shift or alt, is* pressed. We simply communicate this to the client. */{voidkeypressmod(struct wl_listener *listener, void *data)wlr_seat_keyboard_notify_key(seat, event->time_msec,event->keycode, event->state);}}wlr_seat_set_keyboard(seat, kb->wlr_keyboard);/* Pass unhandled keycodes along to the client. */if (!handled) {handled = keybinding(mods, syms[i]) || handled;for (i = 0; i < nsyms; i++)/* On _press_ if there is no active screen locker,* attempt to process a compositor keybinding. */if (!input_inhibit_mgr->active_inhibitor&& event->state == WL_KEYBOARD_KEY_STATE_PRESSED)IDLE_NOTIFY_ACTIVITY;uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard);int handled = 0;kb->wlr_keyboard->xkb_state, keycode, &syms);/* Translate libinput keycode -> xkbcommon */uint32_t keycode = event->keycode + 8;/* Get a list of keysyms based on the keymap for this keyboard */const xkb_keysym_t *syms;int nsyms = xkb_state_key_get_syms(struct wlr_keyboard_key_event *event = data;Keyboard *kb = wl_container_of(listener, kb, key);/* This event is raised when a key is pressed or released. */keypress(struct wl_listener *listener, void *data){void}return handled;}}handled = 1;const Key *k;for (k = keys; k < END(keys); k++) {if (CLEANMASK(mods) == CLEANMASK(k->mod) &&sym == k->keysym && k->func) {k->func(&k->arg);int handled = 0;*//** Here we handle compositor keybindings. This is when the compositor is* processing keys, rather than passing them on to the client for its own* processing.{keybinding(uint32_t mods, xkb_keysym_t sym)int}wlr_seat_set_capabilities(seat, caps);caps |= WL_SEAT_CAPABILITY_KEYBOARD;if (!wl_list_empty(&keyboards))caps = WL_SEAT_CAPABILITY_POINTER;/* TODO do we actually require a cursor? *//* We need to let the wlr_seat know what our capabilities are, which is* communiciated to the client. In dwl we always have a cursor, even if* there are no pointer devices, so we always include that capability. */break;}/* TODO handle other input device types */break;default:createpointer(wlr_pointer_from_input_device(device));break;case WLR_INPUT_DEVICE_POINTER:createkeyboard(wlr_keyboard_from_input_device(device));switch (device->type) {case WLR_INPUT_DEVICE_KEYBOARD:uint32_t caps;struct wlr_input_device *device = data;}voidinputdevice(struct wl_listener *listener, void *data){/* This event is raised by the backend when a new input device becomes* available. */selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);if (!arg || !selmon)return;}voidincnmaster(const Arg *arg){setfullscreen(c, client_wants_fullscreen(c));}voidfullscreennotify(struct wl_listener *listener, void *data){Client *c = wl_container_of(listener, c, fullscreen);Client *focustop(Monitor *m){Client *c;wl_list_for_each(c, &fstack, flink)if (VISIBLEON(c, m))return c;return NULL;}focusclient(c, 1);/* If only one client is visible on selmon, then c == sel */}if (arg->i > 0) {wl_list_for_each(c, &sel->link, link) {if (&c->link == &clients)continue; /* wrap past the sentinel node */if (VISIBLEON(c, selmon))break; /* found it */}} else {wl_list_for_each_reverse(c, &sel->link, link) {if (&c->link == &clients)continue; /* wrap past the sentinel node */if (VISIBLEON(c, selmon))break; /* found it */}return;if (!sel || (sel->isfullscreen && lockfullscreen))Client *c, *sel = selclient();/* Focus the next or previous client (in tiling order) on selmon */{focusstack(const Arg *arg)void}focusclient(focustop(selmon), 1);int i = 0, nmons = wl_list_length(&mons);if (nmons)do /* don't switch to disabled mons */selmon = dirtomon(arg->i);while (!selmon->wlr_output->enabled && i++ < nmons);}voidfocusmon(const Arg *arg){client_activate_surface(client_surface(c), 1);/* Activate the new client */client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat));/* Have a client, so focus its top-level wlr_surface *//* Change cursor surface */motionnotify(0);return;}wlr_seat_keyboard_notify_clear_focus(seat);if (!c) {/* With no client, all we have left is to clear focus */printstatus();}}client_activate_surface(old, 0);} else if (w && w == exclusive_focus && client_wants_focus(w)) {return;/* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg* and probably other clients */} else if (w && !client_is_unmanaged(w) && (!c || !client_wants_focus(c))) {for (i = 0; i < 4; i++)wlr_scene_rect_set_color(w->border[i], bordercolor);return;if (wlr_layer_surface && ((LayerSurface *)wlr_layer_surface->data)->mapped&& (wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP|| wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY))struct wlr_layer_surface_v1 *wlr_layer_surface =wlr_layer_surface_v1_from_wlr_surface(old);if (wlr_surface_is_layer_surface(old)) {* and focus it after the overlay is closed. *//* If an overlay is focused, don't focus or activate the client,* but only update its position in fstack to render its border with focuscolorif (old && (!c || client_surface(c) != old)) {/* Deactivate old client if focus is changing */wlr_scene_node_raise_to_top(&c->scene->node);if (c && lift)/* Raise client in stacking order if requested */int i;struct wlr_surface *old = seat->keyboard_state.focused_surface;{focusclient(Client *c, int lift)}voiddir ^ (WLR_DIRECTION_LEFT|WLR_DIRECTION_RIGHT),selmon->wlr_output, selmon->m.x, selmon->m.y)))return next->data;return selmon;if (wlr_output_layout_get(output_layout, selmon->wlr_output)&& (next = wlr_output_layout_farthest_output(output_layout,dir, selmon->wlr_output, selmon->m.x, selmon->m.y)))return next->data;if (wlr_output_layout_get(output_layout, selmon->wlr_output)&& (next = wlr_output_layout_adjacent_output(output_layout,struct wlr_output *next;{dirtomon(enum wlr_direction dir)Monitor *free(c);wl_list_remove(&c->map.link);wl_list_remove(&c->unmap.link);wl_list_remove(&c->destroy.link);Client *c = wl_container_of(listener, c, destroy);destroynotify(struct wl_listener *listener, void *data){/* Called when the surface is destroyed and should never be shown again. */}voidfree(layersurface);wl_list_remove(&layersurface->link);wl_list_remove(&layersurface->destroy.link);wl_list_remove(&layersurface->map.link);wl_list_remove(&layersurface->unmap.link);wl_list_remove(&layersurface->surface_commit.link);LayerSurface *layersurface = wl_container_of(listener, layersurface, destroy);{destroylayersurfacenotify(struct wl_listener *listener, void *data)}void/* `data` is the wlr_surface of the idle inhibitor being destroyed,* at this point the idle inhibitor is still in the list of the manager */checkidleinhibitor(data);destroyidleinhibitor(struct wl_listener *listener, void *data){}voidwlr_seat_pointer_notify_frame(seat);/* Notify the client with pointer focus of the frame event. */cursorframe(struct wl_listener *listener, void *data){/* This event is forwarded by the cursor when a pointer emits an frame* event. Frame events are sent after regular pointer events to group* multiple events together. For instance, two axis events may happen at the* same time, in which case a frame event won't be sent in between. */}void}if (libinput_device_config_send_events_get_modes(libinput_device))libinput_device_config_send_events_set_mode(libinput_device, send_events_mode);if (libinput_device_config_accel_is_available(libinput_device)) {libinput_device_config_accel_set_profile(libinput_device, accel_profile);libinput_device_config_accel_set_speed(libinput_device, accel_speed);}if (libinput_device_config_click_get_methods(libinput_device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE)libinput_device_config_click_set_method (libinput_device, click_method);if (libinput_device_config_dwt_is_available(libinput_device))libinput_device_config_dwt_set_enabled(libinput_device, disable_while_typing);if (libinput_device_config_left_handed_is_available(libinput_device))libinput_device_config_left_handed_set(libinput_device, left_handed);if (libinput_device_config_middle_emulation_is_available(libinput_device))libinput_device_config_middle_emulation_set_enabled(libinput_device, middle_button_emulation);if (libinput_device_config_scroll_get_methods(libinput_device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL)libinput_device_config_scroll_set_method (libinput_device, scroll_method);if (libinput_device_config_scroll_has_natural_scroll(libinput_device))libinput_device_config_scroll_set_natural_scroll_enabled(libinput_device, natural_scrolling);}libinput_device_config_tap_set_drag_lock_enabled(libinput_device, drag_lock);if (libinput_device_config_tap_get_finger_count(libinput_device)) {libinput_device_config_tap_set_enabled(libinput_device, tap_to_click);libinput_device_config_tap_set_drag_enabled(libinput_device, tap_and_drag);wlr_libinput_get_device_handle(&pointer->base);struct libinput_device *libinput_device = (struct libinput_device*)if (wlr_input_device_is_libinput(&pointer->base)) {{}voidLISTEN(&xdg_surface->toplevel->events.request_maximize, &c->maximize,maximizenotify);LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen,fullscreennotify);LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle);LISTEN(&xdg_surface->events.map, &c->map, mapnotify);LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify);LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify);c->bw = borderpx;c->surface.xdg = xdg_surface;c = xdg_surface->data = ecalloc(1, sizeof(*c));/* Allocate a Client for this surface */return;wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &box);return;} else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE)box = l->type == LayerShell ? l->mon->m : l->mon->w;box.x -= l->geom.x;box.y -= l->geom.y;return;xdg_surface->surface->data = wlr_scene_xdg_surface_create(xdg_surface->popup->parent->data, xdg_surface);struct wlr_box box;if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {Client *c;struct wlr_xdg_surface *xdg_surface = data;* client, either a toplevel (application window) or popup,* or when wlr_layer_shell receives a new popup from a layer.* If you want to do something tricky with popups you should check if* its parent is wlr_xdg_shell or wlr_layer_shell */{/* This event is raised when wlr_xdg_shell receives a new xdg surface from acreatenotify(struct wl_listener *listener, void *data)}voidm->scene_output = wlr_scene_output_create(scene, wlr_output);wlr_output_layout_add_auto(output_layout, wlr_output);** The output layout utility automatically adds a wl_output global to the* display, which Wayland clients can see to find out information about the* output (such as DPI, scale factor, manufacturer, etc).*//* Adds this to the output layout in the order it was configured in./* Try to enable adaptive sync, note that not all monitors support it.* wlr_output_commit() will deactivate it in case it cannot be enabled */wlr_output_enable_adaptive_sync(wlr_output, 1);wlr_output_commit(wlr_output);if (!wlr_output_commit(wlr_output))return;wlr_output_enable(wlr_output, 1);LISTEN(&wlr_output->events.frame, &m->frame, rendermon);LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon);/* Set up event listeners *//* The mode is a tuple of (width, height, refresh rate), and each* 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_set_mode(wlr_output, wlr_output_preferred_mode(wlr_output));}break;}wlr_output_set_transform(wlr_output, r->rr);m->lt[0] = m->lt[1] = r->lt;m->mfact = r->mfact;m->nmaster = r->nmaster;wlr_output_set_scale(wlr_output, r->scale);wlr_xcursor_manager_load(cursor_mgr, r->scale);if (!r->name || strstr(wlr_output->name, r->name)) {m->tagset[0] = m->tagset[1] = 1;wl_list_init(&m->layers[i]);for (i = 0; i < LENGTH(m->layers); i++)/* Initialize monitor state using configured rules */
{struct xkb_context *context;struct xkb_keymap *keymap;Keyboard *kb = keyboard->data = ecalloc(1, sizeof(*kb));kb->wlr_keyboard = keyboard;/* Prepare an XKB keymap and assign it to the keyboard. */context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);keymap = xkb_keymap_new_from_names(context, &xkb_rules,XKB_KEYMAP_COMPILE_NO_FLAGS);wlr_keyboard_set_keymap(keyboard, keymap);xkb_keymap_unref(keymap);xkb_context_unref(context);wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay);/* Here we set up listeners for keyboard events. */LISTEN(&keyboard->events.modifiers, &kb->modifiers, keypressmod);LISTEN(&keyboard->events.key, &kb->key, keypress);LISTEN(&keyboard->base.events.destroy, &kb->destroy, cleanupkeyboard);wlr_seat_set_keyboard(seat, keyboard);/* And add the keyboard to our list of keyboards */wl_list_insert(&keyboards, &kb->link);
voidcreatelayersurface(struct wl_listener *listener, void *data){struct wlr_layer_surface_v1 *wlr_layer_surface = data;LayerSurface *layersurface;struct wlr_layer_surface_v1_state old_state;if (!wlr_layer_surface->output)wlr_layer_surface->output = selmon ? selmon->wlr_output : NULL;if (!wlr_layer_surface->output)wlr_layer_surface_v1_destroy(wlr_layer_surface);layersurface = ecalloc(1, sizeof(LayerSurface));layersurface->type = LayerShell;LISTEN(&wlr_layer_surface->surface->events.commit,&layersurface->surface_commit, commitlayersurfacenotify);LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy,destroylayersurfacenotify);LISTEN(&wlr_layer_surface->events.map, &layersurface->map,maplayersurfacenotify);LISTEN(&wlr_layer_surface->events.unmap, &layersurface->unmap,unmaplayersurfacenotify);layersurface->layer_surface = wlr_layer_surface;layersurface->mon = wlr_layer_surface->output->data;wlr_layer_surface->data = layersurface;layersurface->scene_layer = wlr_scene_layer_surface_v1_create(layers[wlr_layer_surface->pending.layer], wlr_layer_surface);layersurface->scene = layersurface->scene_layer->tree;layersurface->popups = wlr_layer_surface->surface->data =&wlr_scene_tree_create(layers[wlr_layer_surface->pending.layer])->node;layersurface->scene->node.data = layersurface;wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->pending.layer],&layersurface->link);/* Temporarily set the layer's current state to pending* so that we can easily arrange it*/old_state = wlr_layer_surface->current;wlr_layer_surface->current = wlr_layer_surface->pending;layersurface->mapped = 1;arrangelayers(layersurface->mon);wlr_layer_surface->current = old_state;}voidcreatemon(struct wl_listener *listener, void *data){/* This event is raised by the backend when a new output (aka a display or* monitor) becomes available. */struct wlr_output *wlr_output = data;const MonitorRule *r;size_t i;Monitor *m = wlr_output->data = ecalloc(1, sizeof(*m));m->wlr_output = wlr_output;wlr_output_init_render(wlr_output, alloc, drw);/* Initialize monitor state using configured rules */for (i = 0; i < LENGTH(m->layers); i++)wl_list_init(&m->layers[i]);m->tagset[0] = m->tagset[1] = 1;for (r = monrules; r < END(monrules); r++) {if (!r->name || strstr(wlr_output->name, r->name)) {m->mfact = r->mfact;m->nmaster = r->nmaster;wlr_output_set_scale(wlr_output, r->scale);wlr_xcursor_manager_load(cursor_mgr, r->scale);m->lt[0] = m->lt[1] = r->lt;wlr_output_set_transform(wlr_output, r->rr);break;}}/* The mode is a tuple of (width, height, refresh rate), and each* 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_set_mode(wlr_output, 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);wlr_output_enable(wlr_output, 1);if (!wlr_output_commit(wlr_output))return;/* Try to enable adaptive sync, note that not all monitors support it.* wlr_output_commit() will deactivate it in case it cannot be enabled */wlr_output_enable_adaptive_sync(wlr_output, 1);wlr_output_commit(wlr_output);wl_list_insert(&mons, &m->link);printstatus();/* Adds this to the output layout in the order it was configured in.** The output layout utility automatically adds a wl_output global to the* display, which Wayland clients can see to find out information about the* output (such as DPI, scale factor, manufacturer, etc).*/m->scene_output = wlr_scene_output_create(scene, wlr_output);wlr_output_layout_add_auto(output_layout, wlr_output);}voidcreatenotify(struct wl_listener *listener, void *data){/* This event is raised when wlr_xdg_shell receives a new xdg surface from a* client, either a toplevel (application window) or popup,* or when wlr_layer_shell receives a new popup from a layer.* If you want to do something tricky with popups you should check if* its parent is wlr_xdg_shell or wlr_layer_shell */struct wlr_xdg_surface *xdg_surface = data;Client *c;if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {struct wlr_box box;LayerSurface *l = toplevel_from_popup(xdg_surface->popup);if (!xdg_surface->popup->parent)return;xdg_surface->surface->data = wlr_scene_xdg_surface_create(xdg_surface->popup->parent->data, xdg_surface);/* Probably the check of `l` is useless, the only thing that can be NULL* is its monitor */if (!l || !l->mon)return;box = l->type == LayerShell ? l->mon->m : l->mon->w;box.x -= l->geom.x;box.y -= l->geom.y;wlr_xdg_popup_unconstrain_from_box(xdg_surface->popup, &box);return;} else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE)return;/* Allocate a Client for this surface */c = xdg_surface->data = ecalloc(1, sizeof(*c));c->surface.xdg = xdg_surface;c->bw = borderpx;LISTEN(&xdg_surface->events.map, &c->map, mapnotify);LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify);LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify);LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle);LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen,fullscreennotify);LISTEN(&xdg_surface->toplevel->events.request_maximize, &c->maximize,maximizenotify);}voidcreatepointer(struct wlr_pointer *pointer){if (wlr_input_device_is_libinput(&pointer->base)) {struct libinput_device *libinput_device = (struct libinput_device*)wlr_libinput_get_device_handle(&pointer->base);if (libinput_device_config_tap_get_finger_count(libinput_device)) {libinput_device_config_tap_set_enabled(libinput_device, tap_to_click);libinput_device_config_tap_set_drag_enabled(libinput_device, tap_and_drag);libinput_device_config_tap_set_drag_lock_enabled(libinput_device, drag_lock);}if (libinput_device_config_scroll_has_natural_scroll(libinput_device))libinput_device_config_scroll_set_natural_scroll_enabled(libinput_device, natural_scrolling);if (libinput_device_config_dwt_is_available(libinput_device))libinput_device_config_dwt_set_enabled(libinput_device, disable_while_typing);if (libinput_device_config_left_handed_is_available(libinput_device))libinput_device_config_left_handed_set(libinput_device, left_handed);if (libinput_device_config_middle_emulation_is_available(libinput_device))libinput_device_config_middle_emulation_set_enabled(libinput_device, middle_button_emulation);if (libinput_device_config_scroll_get_methods(libinput_device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL)libinput_device_config_scroll_set_method (libinput_device, scroll_method);if (libinput_device_config_click_get_methods(libinput_device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE)libinput_device_config_click_set_method (libinput_device, click_method);if (libinput_device_config_send_events_get_modes(libinput_device))libinput_device_config_send_events_set_mode(libinput_device, send_events_mode);if (libinput_device_config_accel_is_available(libinput_device)) {libinput_device_config_accel_set_profile(libinput_device, accel_profile);libinput_device_config_accel_set_speed(libinput_device, accel_speed);}}wlr_cursor_attach_input_device(cursor, &pointer->base);}voidcursorframe(struct wl_listener *listener, void *data){/* This event is forwarded by the cursor when a pointer emits an frame* event. Frame events are sent after regular pointer events to group* multiple events together. For instance, two axis events may happen at the* same time, in which case a frame event won't be sent in between. *//* Notify the client with pointer focus of the frame event. */wlr_seat_pointer_notify_frame(seat);}voiddestroydragicon(struct wl_listener *listener, void *data){struct wlr_drag_icon *icon = data;wlr_scene_node_destroy(icon->data);/* Focus enter isn't sent during drag, so refocus the focused node. */focusclient(selclient(), 1);motionnotify(0);}voiddestroyidleinhibitor(struct wl_listener *listener, void *data){/* `data` is the wlr_surface of the idle inhibitor being destroyed,* at this point the idle inhibitor is still in the list of the manager */checkidleinhibitor(data);}voiddestroylayersurfacenotify(struct wl_listener *listener, void *data){LayerSurface *layersurface = wl_container_of(listener, layersurface, destroy);wl_list_remove(&layersurface->link);wl_list_remove(&layersurface->destroy.link);wl_list_remove(&layersurface->map.link);wl_list_remove(&layersurface->unmap.link);wl_list_remove(&layersurface->surface_commit.link);
free(layersurface);}voiddestroynotify(struct wl_listener *listener, void *data){/* Called when the surface is destroyed and should never be shown again. */Client *c = wl_container_of(listener, c, destroy);wl_list_remove(&c->map.link);wl_list_remove(&c->unmap.link);wl_list_remove(&c->destroy.link);wl_list_remove(&c->set_title.link);wl_list_remove(&c->fullscreen.link);#ifdef XWAYLANDif (c->type != XDGShell) {wl_list_remove(&c->configure.link);wl_list_remove(&c->set_hints.link);wl_list_remove(&c->activate.link);}#endiffree(c);}Monitor *dirtomon(enum wlr_direction dir){struct wlr_output *next;if (wlr_output_layout_get(output_layout, selmon->wlr_output)&& (next = wlr_output_layout_adjacent_output(output_layout,dir, selmon->wlr_output, selmon->m.x, selmon->m.y)))return next->data;if (wlr_output_layout_get(output_layout, selmon->wlr_output)&& (next = wlr_output_layout_farthest_output(output_layout,dir ^ (WLR_DIRECTION_LEFT|WLR_DIRECTION_RIGHT),selmon->wlr_output, selmon->m.x, selmon->m.y)))return next->data;return selmon;}voidfocusclient(Client *c, int lift){struct wlr_surface *old = seat->keyboard_state.focused_surface;int i;/* Raise client in stacking order if requested */if (c && lift)wlr_scene_node_raise_to_top(&c->scene->node);if (c && client_surface(c) == old)return;/* Put the new client atop the focus stack and select its monitor */if (c && !client_is_unmanaged(c)) {wl_list_remove(&c->flink);wl_list_insert(&fstack, &c->flink);selmon = c->mon;c->isurgent = 0;client_restack_surface(c);/* Don't change border color if there is an exclusive focus or we are* handling a drag operation */if (!exclusive_focus && !seat->drag)for (i = 0; i < 4; i++)wlr_scene_rect_set_color(c->border[i], focuscolor);}/* Deactivate old client if focus is changing */if (old && (!c || client_surface(c) != old)) {/* If an overlay is focused, don't focus or activate the client,* but only update its position in fstack to render its border with focuscolor* and focus it after the overlay is closed. */Client *w = client_from_wlr_surface(old);if (wlr_surface_is_layer_surface(old)) {struct wlr_layer_surface_v1 *wlr_layer_surface =wlr_layer_surface_v1_from_wlr_surface(old);if (wlr_layer_surface && ((LayerSurface *)wlr_layer_surface->data)->mapped&& (wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP|| wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY))return;} else if (w && w == exclusive_focus && client_wants_focus(w)) {return;/* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg* and probably other clients */} else if (w && !client_is_unmanaged(w) && (!c || !client_wants_focus(c))) {for (i = 0; i < 4; i++)wlr_scene_rect_set_color(w->border[i], bordercolor);client_activate_surface(old, 0);}}printstatus();checkidleinhibitor(NULL);if (!c) {/* With no client, all we have left is to clear focus */wlr_seat_keyboard_notify_clear_focus(seat);return;}/* Change cursor surface */motionnotify(0);/* Have a client, so focus its top-level wlr_surface */client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat));/* Activate the new client */client_activate_surface(client_surface(c), 1);}voidfocusmon(const Arg *arg){int i = 0, nmons = wl_list_length(&mons);if (nmons)do /* don't switch to disabled mons */selmon = dirtomon(arg->i);while (!selmon->wlr_output->enabled && i++ < nmons);focusclient(focustop(selmon), 1);}voidfocusstack(const Arg *arg){/* Focus the next or previous client (in tiling order) on selmon */Client *c, *sel = selclient();if (!sel || (sel->isfullscreen && lockfullscreen))return;if (arg->i > 0) {wl_list_for_each(c, &sel->link, link) {if (&c->link == &clients)continue; /* wrap past the sentinel node */if (VISIBLEON(c, selmon))break; /* found it */}} else {wl_list_for_each_reverse(c, &sel->link, link) {if (&c->link == &clients)continue; /* wrap past the sentinel node */if (VISIBLEON(c, selmon))break; /* found it */}}/* If only one client is visible on selmon, then c == sel */focusclient(c, 1);}/* We probably should change the name of this, it sounds like* will focus the topmost client of this mon, when actually will* only return that client */Client *focustop(Monitor *m){Client *c;wl_list_for_each(c, &fstack, flink)if (VISIBLEON(c, m))return c;return NULL;}voidfullscreennotify(struct wl_listener *listener, void *data){Client *c = wl_container_of(listener, c, fullscreen);setfullscreen(c, client_wants_fullscreen(c));}voidincnmaster(const Arg *arg){if (!arg || !selmon)return;selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);arrange(selmon);}voidinputdevice(struct wl_listener *listener, void *data){/* This event is raised by the backend when a new input device becomes* available. */struct wlr_input_device *device = data;uint32_t caps;switch (device->type) {case WLR_INPUT_DEVICE_KEYBOARD:createkeyboard(wlr_keyboard_from_input_device(device));break;case WLR_INPUT_DEVICE_POINTER:createpointer(wlr_pointer_from_input_device(device));break;default:/* TODO handle other input device types */break;}/* We need to let the wlr_seat know what our capabilities are, which is* communiciated to the client. In dwl we always have a cursor, even if* there are no pointer devices, so we always include that capability. *//* TODO do we actually require a cursor? */caps = WL_SEAT_CAPABILITY_POINTER;if (!wl_list_empty(&keyboards))caps |= WL_SEAT_CAPABILITY_KEYBOARD;wlr_seat_set_capabilities(seat, caps);}intkeybinding(uint32_t mods, xkb_keysym_t sym){/** Here we handle compositor keybindings. This is when the compositor is* processing keys, rather than passing them on to the client for its own* processing.*/int handled = 0;const Key *k;for (k = keys; k < END(keys); k++) {if (CLEANMASK(mods) == CLEANMASK(k->mod) &&sym == k->keysym && k->func) {k->func(&k->arg);handled = 1;}}return handled;}voidkeypress(struct wl_listener *listener, void *data){int i;/* This event is raised when a key is pressed or released. */Keyboard *kb = wl_container_of(listener, kb, key);struct wlr_keyboard_key_event *event = data;/* Translate libinput keycode -> xkbcommon */uint32_t keycode = event->keycode + 8;/* Get a list of keysyms based on the keymap for this keyboard */const xkb_keysym_t *syms;int nsyms = xkb_state_key_get_syms(kb->wlr_keyboard->xkb_state, keycode, &syms);int handled = 0;uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard);IDLE_NOTIFY_ACTIVITY;/* On _press_ if there is no active screen locker,* attempt to process a compositor keybinding. */if (!input_inhibit_mgr->active_inhibitor&& event->state == WL_KEYBOARD_KEY_STATE_PRESSED)for (i = 0; i < nsyms; i++)handled = keybinding(mods, syms[i]) || handled;if (!handled) {/* Pass unhandled keycodes along to the client. */wlr_seat_set_keyboard(seat, kb->wlr_keyboard);wlr_seat_keyboard_notify_key(seat, event->time_msec,event->keycode, event->state);}}voidkeypressmod(struct wl_listener *listener, void *data){/* This event is raised when a modifier key, such as shift or alt, is* pressed. We simply communicate this to the client. */Keyboard *kb = wl_container_of(listener, kb, modifiers);/** A seat can only have one keyboard, but this is a limitation of the* Wayland protocol - not wlroots. We assign all connected keyboards to the* same seat. You can swap out the underlying wlr_keyboard like this and* wlr_seat handles this transparently.*/wlr_seat_set_keyboard(seat, kb->wlr_keyboard);/* Send modifiers to the client. */wlr_seat_keyboard_notify_modifiers(seat,&kb->wlr_keyboard->modifiers);}voidkillclient(const Arg *arg){Client *sel = selclient();if (sel)client_send_close(sel);}voidmaplayersurfacenotify(struct wl_listener *listener, void *data){LayerSurface *l = wl_container_of(listener, l, map);wlr_surface_send_enter(l->layer_surface->surface, l->mon->wlr_output);motionnotify(0);}voidmapnotify(struct wl_listener *listener, void *data){/* Called when the surface is mapped, or ready to display on-screen. */Client *p, *c = wl_container_of(listener, c, map);int i;/* Create scene tree for this client and its border */c->scene = wlr_scene_tree_create(layers[LyrTile]);c->scene_surface = c->type == XDGShell? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg): wlr_scene_subsurface_tree_create(c->scene, client_surface(c));if (client_surface(c)) {client_surface(c)->data = c->scene;/* Ideally we should do this in createnotify{,x11} but at that moment* wlr_xwayland_surface doesn't have wlr_surface yet. */LISTEN(&client_surface(c)->events.commit, &c->commit, commitnotify);}c->scene->node.data = c->scene_surface->node.data = c;#ifdef XWAYLAND/* Handle unmanaged clients first so we can return prior create borders */if (client_is_unmanaged(c)) {client_get_geometry(c, &c->geom);/* Unmanaged clients always are floating */wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]);wlr_scene_node_set_position(&c->scene->node, c->geom.x + borderpx,c->geom.y + borderpx);if (client_wants_focus(c)) {focusclient(c, 1);exclusive_focus = c;}return;}#endiffor (i = 0; i < 4; i++) {c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor);c->border[i]->node.data = c;wlr_scene_rect_set_color(c->border[i], bordercolor);}/* Initialize client geometry with room for border */client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);client_get_geometry(c, &c->geom);c->geom.width += 2 * c->bw;c->geom.height += 2 * c->bw;/* Insert this client into client lists. */wl_list_insert(&clients, &c->link);wl_list_insert(&fstack, &c->flink);/* Set initial monitor, tags, floating status, and focus:* we always consider floating, clients that have parent and thus* we set the same tags and monitor than its parent, if not* try to apply rules for them */if ((p = client_get_parent(c))) {c->isfloating = 1;wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]);setmon(c, p->mon, p->tags);} else {applyrules(c);}printstatus();c->mon->un_map = 1;}voidmaximizenotify(struct wl_listener *listener, void *data){/* This event is raised when a client would like to maximize itself,* typically because the user clicked on the maximize button on* client-side decorations. dwl doesn't support maximization, but* to conform to xdg-shell protocol we still must send a configure.* wlr_xdg_surface_schedule_configure() is used to send an empty reply. */Client *c = wl_container_of(listener, c, maximize);wlr_xdg_surface_schedule_configure(c->surface.xdg);}voidmonocle(Monitor *m){Client *c;wl_list_for_each(c, &clients, link) {if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)continue;resize(c, m->w, 0);}if ((c = focustop(m)))wlr_scene_node_raise_to_top(&c->scene->node);}voidmotionabsolute(struct wl_listener *listener, void *data){/* This event is forwarded by the cursor when a pointer emits an _absolute_* motion event, from 0..1 on each axis. This happens, for example, when* wlroots is running under a Wayland window rather than KMS+DRM, and you* move the mouse over the window. You could enter the window from any edge,* so we have to warp the mouse there. There is also some hardware which* emits these events. */struct wlr_pointer_motion_absolute_event *event = data;wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y);motionnotify(event->time_msec);}voidmotionnotify(uint32_t time){double sx = 0, sy = 0;Client *c = NULL;LayerSurface *l;struct wlr_surface *surface = NULL;struct wlr_drag_icon *icon;/* time is 0 in internal calls meant to restore pointer focus. */if (time) {IDLE_NOTIFY_ACTIVITY;/* Update selmon (even while dragging a window) */if (sloppyfocus)selmon = xytomon(cursor->x, cursor->y);}/* Update drag icon's position if any */if (seat->drag && (icon = seat->drag->icon))wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx,cursor->y + icon->surface->sy);/* If we are currently grabbing the mouse, handle and return */if (cursor_mode == CurMove) {/* Move the grabbed client to the new position. */resize(grabc, (struct wlr_box){.x = cursor->x - grabcx, .y = cursor->y - grabcy,.width = grabc->geom.width, .height = grabc->geom.height}, 1);return;} else if (cursor_mode == CurResize) {resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,.width = cursor->x - grabc->geom.x, .height = cursor->y - grabc->geom.y}, 1);return;}/* Find the client under the pointer and send the event along. */xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy);if (cursor_mode == CurPressed && !seat->drag) {if ((l = toplevel_from_wlr_layer_surface(seat->pointer_state.focused_surface))) {surface = seat->pointer_state.focused_surface;sx = cursor->x - l->geom.x;sy = cursor->y - l->geom.y;}}/* If there's no client surface under the cursor, set the cursor image to a* default. This is what makes the cursor image appear when you move it* off of a client or over its border. */if (!surface && !seat->drag && (!cursor_image || strcmp(cursor_image, "left_ptr")))wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "left_ptr"), cursor);pointerfocus(c, surface, sx, sy, time);}voidmotionrelative(struct wl_listener *listener, void *data){/* This event is forwarded by the cursor when a pointer emits a _relative_* pointer motion event (i.e. a delta) */struct wlr_pointer_motion_event *event = data;/* The cursor doesn't move unless we tell it to. The cursor automatically* handles constraining the motion to the output layout, as well as any* special configuration applied for the specific input device which* generated the event. You can pass NULL for the device if you want to move* the cursor around without any input. */wlr_cursor_move(cursor, &event->pointer->base, event->delta_x, event->delta_y);motionnotify(event->time_msec);}voidmoveresize(const Arg *arg){if (cursor_mode != CurNormal && cursor_mode != CurPressed)return;xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL);if (!grabc || client_is_unmanaged(grabc))return;/* Float the window and tell motionnotify to grab it */setfloating(grabc, 1);switch (cursor_mode = arg->ui) {case CurMove:grabcx = cursor->x - grabc->geom.x;grabcy = cursor->y - grabc->geom.y;wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "fleur"), cursor);break;case CurResize:/* Doesn't work for X11 output - the next absolute motion event* returns the cursor to where it started */wlr_cursor_warp_closest(cursor, NULL,grabc->geom.x + grabc->geom.width,grabc->geom.y + grabc->geom.height);wlr_xcursor_manager_set_cursor_image(cursor_mgr,(cursor_image = "bottom_right_corner"), cursor);break;}}voidoutputmgrapply(struct wl_listener *listener, void *data){struct wlr_output_configuration_v1 *config = data;outputmgrapplyortest(config, 0);}voidoutputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test){/** Called when a client such as wlr-randr requests a change in output* configuration. This is only one way that the layout can be changed,* so any Monitor information should be updated by updatemons() after an* output_layout.change event, not here.*/struct wlr_output_configuration_head_v1 *config_head;int ok = 1;wl_list_for_each(config_head, &config->heads, link) {struct wlr_output *wlr_output = config_head->state.output;Monitor *m = wlr_output->data;wlr_output_enable(wlr_output, config_head->state.enabled);if (!config_head->state.enabled)goto apply_or_test;if (config_head->state.mode)wlr_output_set_mode(wlr_output, config_head->state.mode);elsewlr_output_set_custom_mode(wlr_output,config_head->state.custom_mode.width,config_head->state.custom_mode.height,config_head->state.custom_mode.refresh);/* Don't move monitors if position wouldn't change, this to avoid* wlroots marking the output as manually configured */if (m->m.x != config_head->state.x || m->m.y != config_head->state.y)wlr_output_layout_move(output_layout, wlr_output,config_head->state.x, config_head->state.y);wlr_output_set_transform(wlr_output, config_head->state.transform);wlr_output_set_scale(wlr_output, config_head->state.scale);wlr_output_enable_adaptive_sync(wlr_output,config_head->state.adaptive_sync_enabled);apply_or_test:if (test) {ok &= wlr_output_test(wlr_output);wlr_output_rollback(wlr_output);} else {ok &= wlr_output_commit(wlr_output);}}if (ok)wlr_output_configuration_v1_send_succeeded(config);elsewlr_output_configuration_v1_send_failed(config);wlr_output_configuration_v1_destroy(config);/* TODO: use a wrapper function? */updatemons(NULL, NULL);}voidoutputmgrtest(struct wl_listener *listener, void *data){struct wlr_output_configuration_v1 *config = data;outputmgrapplyortest(config, 1);}voidpointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,uint32_t time){struct timespec now;int internal_call = !time;if (sloppyfocus && !internal_call && c && !client_is_unmanaged(c))focusclient(c, 0);/* If surface is NULL, clear pointer focus */if (!surface) {wlr_seat_pointer_notify_clear_focus(seat);return;}if (internal_call) {clock_gettime(CLOCK_MONOTONIC, &now);time = now.tv_sec * 1000 + now.tv_nsec / 1000000;}/* Let the client know that the mouse cursor has entered one* of its surfaces, and make keyboard focus follow if desired.* wlroots makes this a no-op if surface is already focused */wlr_seat_pointer_notify_enter(seat, surface, sx, sy);wlr_seat_pointer_notify_motion(seat, time, sx, sy);}voidprintstatus(void){Monitor *m = NULL;Client *c;unsigned int occ, urg, sel;wl_list_for_each(m, &mons, link) {occ = urg = 0;wl_list_for_each(c, &clients, link) {if (c->mon != m)continue;occ |= c->tags;if (c->isurgent)urg |= c->tags;}if ((c = focustop(m))) {printf("%s title %s\n", m->wlr_output->name, client_get_title(c));printf("%s fullscreen %u\n", m->wlr_output->name, c->isfullscreen);printf("%s floating %u\n", m->wlr_output->name, c->isfloating);sel = c->tags;} else {printf("%s title \n", m->wlr_output->name);printf("%s fullscreen \n", m->wlr_output->name);printf("%s floating \n", m->wlr_output->name);sel = 0;}printf("%s selmon %u\n", m->wlr_output->name, m == selmon);printf("%s tags %u %u %u %u\n", m->wlr_output->name, occ, m->tagset[m->seltags],sel, urg);printf("%s layout %s\n", m->wlr_output->name, m->lt[m->sellt]->symbol);}}voidquit(const Arg *arg){wl_display_terminate(dpy);}voidquitsignal(int signo){quit(NULL);}voidrendermon(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;int skip = 0;struct timespec now;clock_gettime(CLOCK_MONOTONIC, &now);/* Render if no XDG clients have an outstanding resize and are visible on* this monitor. *//* Checking m->un_map for every client is not optimal but works */wl_list_for_each(c, &clients, link) {if ((c->resize && m->un_map) || (c->type == XDGShell&& (c->surface.xdg->pending.geometry.width !=c->surface.xdg->current.geometry.width|| c->surface.xdg->pending.geometry.height !=c->surface.xdg->current.geometry.height))) {/* Lie */wlr_surface_send_frame_done(client_surface(c), &now);skip = 1;}}if (!skip && !wlr_scene_output_commit(m->scene_output))return;/* Let clients know a frame has been rendered */wlr_scene_output_send_frame_done(m->scene_output, &now);m->un_map = 0;}voidrequeststartdrag(struct wl_listener *listener, void *data){struct wlr_seat_request_start_drag_event *event = data;if (wlr_seat_validate_pointer_grab_serial(seat, event->origin,event->serial))wlr_seat_start_pointer_drag(seat, event->drag, event->serial);elsewlr_data_source_destroy(event->drag->source);}voidresize(Client *c, struct wlr_box geo, int interact){struct wlr_box *bbox = interact ? &sgeom : &c->mon->w;client_set_bounds(c, geo.width, geo.height);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 (c->fullscreen_bg)wlr_scene_rect_set_size(c->fullscreen_bg, c->geom.width, c->geom.height);/* wlroots makes this a no-op if size hasn't changed */c->resize = client_set_size(c, c->geom.width - 2 * c->bw,c->geom.height - 2 * c->bw);}voidrun(char *startup_cmd){/* Add a Unix socket to the Wayland display. */const char *socket = wl_display_add_socket_auto(dpy);if (!socket)die("startup: display_add_socket_auto");setenv("WAYLAND_DISPLAY", socket, 1);/* Start the backend. This will enumerate outputs and inputs, become the DRM* master, etc */if (!wlr_backend_start(backend))die("startup: backend_start");/* Now that the socket exists and the backend is started, run the startup command */if (startup_cmd) {int piperw[2];if (pipe(piperw) < 0)die("startup: pipe:");if ((child_pid = fork()) < 0)die("startup: fork:");if (child_pid == 0) {dup2(piperw[0], STDIN_FILENO);close(piperw[0]);close(piperw[1]);execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL);die("startup: execl:");}dup2(piperw[1], STDOUT_FILENO);close(piperw[1]);close(piperw[0]);}/* If nobody is reading the status output, don't terminate */signal(SIGPIPE, SIG_IGN);printstatus();/* At this point the outputs are initialized, choose initial selmon based on* cursor position, and set default cursor image */selmon = xytomon(cursor->x, cursor->y);/* TODO hack to get cursor to display in its initial location (100, 100)* instead of (0, 0) and then jumping. still may not be fully* initialized, as the image/coordinates are not transformed for the* monitor when displayed here */wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y);wlr_xcursor_manager_set_cursor_image(cursor_mgr, cursor_image, cursor);/* Run the Wayland event loop. This does not return until you exit the* compositor. Starting the backend rigged up all of the necessary event* loop configuration to listen to libinput events, DRM events, generate* frame events at the refresh rate, and so on. */wl_display_run(dpy);}Client *selclient(void){Client *c = wl_container_of(fstack.next, c, flink);if (wl_list_empty(&fstack) || !VISIBLEON(c, selmon))return NULL;return c;}voidsetcursor(struct wl_listener *listener, void *data){/* This event is raised by the seat when a client provides a cursor image */struct wlr_seat_pointer_request_set_cursor_event *event = data;/* If we're "grabbing" the cursor, don't use the client's image, we will* restore it after "grabbing" sending a leave event, followed by a enter* event, which will result in the client requesting set the cursor surface */if (cursor_mode != CurNormal && cursor_mode != CurPressed)return;cursor_image = NULL;/* This can be sent by any client, so we check to make sure this one is* actually has pointer focus first. If so, we can tell the cursor to* use the provided surface as the cursor image. It will set the* hardware cursor on the output that it's currently on and continue to* do so as the cursor moves between outputs. */if (event->seat_client == seat->pointer_state.focused_client)wlr_cursor_set_surface(cursor, event->surface,event->hotspot_x, event->hotspot_y);}voidsetfloating(Client *c, int floating){c->isfloating = floating;wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]);arrange(c->mon);printstatus();}voidsetfullscreen(Client *c, int fullscreen){c->isfullscreen = fullscreen;if (!c->mon)return;c->bw = fullscreen ? 0 : borderpx;client_set_fullscreen(c, fullscreen);if (fullscreen) {c->prev = c->geom;resize(c, c->mon->m, 0);/* The xdg-protocol specifies:** If the fullscreened surface is not opaque, the compositor must make* sure that other screen content not part of the same surface tree (made* up of subsurfaces, popups or similarly coupled surfaces) are not* visible below the fullscreened surface.** For brevity we set a black background for all clients*/if (!c->fullscreen_bg) {c->fullscreen_bg = wlr_scene_rect_create(c->scene,c->geom.width, c->geom.height, fullscreen_bg);wlr_scene_node_lower_to_bottom(&c->fullscreen_bg->node);}} else {/* restore previous size instead of arrange for floating windows since* client positions are set by the user and cannot be recalculated */resize(c, c->prev, 0);if (c->fullscreen_bg) {wlr_scene_node_destroy(&c->fullscreen_bg->node);c->fullscreen_bg = NULL;}}arrange(c->mon);printstatus();}voidsetlayout(const Arg *arg){if (!selmon)return;if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])selmon->sellt ^= 1;if (arg && arg->v)selmon->lt[selmon->sellt] = (Layout *)arg->v;/* TODO change layout symbol? */arrange(selmon);printstatus();}/* arg > 1.0 will set mfact absolutely */voidsetmfact(const Arg *arg){float f;if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange)return;f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;if (f < 0.1 || f > 0.9)return;selmon->mfact = f;arrange(selmon);}voidsetmon(Client *c, Monitor *m, unsigned int newtags){Monitor *oldmon = c->mon;if (oldmon == m)return;c->mon = m;c->prev = c->geom;/* TODO leave/enter is not optimal but works */if (oldmon) {wlr_surface_send_leave(client_surface(c), oldmon->wlr_output);arrange(oldmon);}if (m) {/* Make sure window actually overlaps with the monitor */resize(c, c->geom, 0);wlr_surface_send_enter(client_surface(c), m->wlr_output);c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */}focusclient(focustop(selmon), 1);}voidsetpsel(struct wl_listener *listener, void *data){/* This event is raised by the seat when a client wants to set the selection,* usually when the user copies something. wlroots allows compositors to* ignore such requests if they so choose, but in dwl we always honor*/struct wlr_seat_request_set_primary_selection_event *event = data;wlr_seat_set_primary_selection(seat, event->source, event->serial);}voidsetsel(struct wl_listener *listener, void *data){/* This event is raised by the seat when a client wants to set the selection,* usually when the user copies something. wlroots allows compositors to* ignore such requests if they so choose, but in dwl we always honor*/struct wlr_seat_request_set_selection_event *event = data;wlr_seat_set_selection(seat, event->source, event->serial);}voidsetup(void){/* Force line-buffered stdout */setvbuf(stdout, NULL, _IOLBF, 0);/* The Wayland display is managed by libwayland. It handles accepting* clients from the Unix socket, manging Wayland globals, and so on. */dpy = wl_display_create();/* Set up signal handlers */#ifdef XWAYLANDsigchld(0);#elsesignal(SIGCHLD, SIG_IGN);#endifsignal(SIGINT, quitsignal);signal(SIGTERM, quitsignal);/* The backend is a wlroots feature which abstracts the underlying input and* output hardware. The autocreate option will choose the most suitable* backend based on the current environment, such as opening an X11 window* if an X11 server is running. The NULL argument here optionally allows you* to pass in a custom renderer if wlr_renderer doesn't meet your needs. The* backend uses the renderer, for example, to fall back to software cursors* if the backend does not support hardware cursors (some older GPUs* don't). */if (!(backend = wlr_backend_autocreate(dpy)))die("couldn't create backend");/* Initialize the scene graph used to lay out windows */scene = wlr_scene_create();layers[LyrBg] = wlr_scene_tree_create(&scene->tree);layers[LyrBottom] = wlr_scene_tree_create(&scene->tree);layers[LyrTile] = wlr_scene_tree_create(&scene->tree);layers[LyrFloat] = wlr_scene_tree_create(&scene->tree);layers[LyrTop] = wlr_scene_tree_create(&scene->tree);layers[LyrOverlay] = wlr_scene_tree_create(&scene->tree);layers[LyrDragIcon] = wlr_scene_tree_create(&scene->tree);/* Create a renderer with the default implementation */if (!(drw = wlr_renderer_autocreate(backend)))die("couldn't create renderer");wlr_renderer_init_wl_display(drw, dpy);/* Create a default allocator */if (!(alloc = wlr_allocator_autocreate(backend, drw)))die("couldn't create allocator");/* This creates some hands-off wlroots interfaces. The compositor is* necessary for clients to allocate surfaces and the data device manager* handles the clipboard. Each of these wlroots interfaces has room for you* to dig your fingers in and play with their behavior if you want. Note that* the clients cannot set the selection directly without compositor approval,* see the setsel() function. */compositor = wlr_compositor_create(dpy, drw);wlr_export_dmabuf_manager_v1_create(dpy);wlr_screencopy_manager_v1_create(dpy);wlr_data_control_manager_v1_create(dpy);wlr_data_device_manager_create(dpy);wlr_gamma_control_manager_v1_create(dpy);wlr_primary_selection_v1_device_manager_create(dpy);wlr_viewporter_create(dpy);wlr_single_pixel_buffer_manager_v1_create(dpy);wlr_subcompositor_create(dpy);/* Initializes the interface used to implement urgency hints */activation = wlr_xdg_activation_v1_create(dpy);wl_signal_add(&activation->events.request_activate, &request_activate);/* Creates an output layout, which a wlroots utility for working with an* arrangement of screens in a physical layout. */output_layout = wlr_output_layout_create();wl_signal_add(&output_layout->events.change, &layout_change);wlr_xdg_output_manager_v1_create(dpy, output_layout);/* Configure a listener to be notified when new outputs are available on the* backend. */wl_list_init(&mons);wl_signal_add(&backend->events.new_output, &new_output);/* Set up our client lists and the xdg-shell. The xdg-shell is a* Wayland protocol which is used for application windows. For more* detail on shells, refer to the article:** https://drewdevault.com/2018/07/29/Wayland-shells.html*/wl_list_init(&clients);wl_list_init(&fstack);idle = wlr_idle_create(dpy);idle_notifier = wlr_idle_notifier_v1_create(dpy);idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy);wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create);layer_shell = wlr_layer_shell_v1_create(dpy);wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface);xdg_shell = wlr_xdg_shell_create(dpy, 4);wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface);input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy);/* Use decoration protocols to negotiate server-side decorations */wlr_server_decoration_manager_set_default_mode(wlr_server_decoration_manager_create(dpy),WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);wlr_xdg_decoration_manager_v1_create(dpy);/** Creates a cursor, which is a wlroots utility for tracking the cursor* image shown on screen.*/cursor = wlr_cursor_create();wlr_cursor_attach_output_layout(cursor, output_layout);/* Creates an xcursor manager, another wlroots utility which loads up* Xcursor themes to source cursor images from and makes sure that cursor* images are available at all scale factors on the screen (necessary for* HiDPI support). Scaled cursors will be loaded with each output. */cursor_mgr = wlr_xcursor_manager_create(NULL, 24);/** wlr_cursor *only* displays an image on screen. It does not move around* when the pointer moves. However, we can attach input devices to it, and* it will generate aggregate events for all of them. In these events, we* can choose how we want to process them, forwarding them to clients and* moving the cursor around. More detail on this process is described in my* input handling blog post:** https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html** And more comments are sprinkled throughout the notify functions above.*/wl_signal_add(&cursor->events.motion, &cursor_motion);wl_signal_add(&cursor->events.motion_absolute, &cursor_motion_absolute);wl_signal_add(&cursor->events.button, &cursor_button);wl_signal_add(&cursor->events.axis, &cursor_axis);wl_signal_add(&cursor->events.frame, &cursor_frame);/** Configures a seat, which is a single "seat" at which a user sits and* operates the computer. This conceptually includes up to one keyboard,* pointer, touch, and drawing tablet device. We also rig up a listener to* let us know when new input devices are available on the backend.*/wl_list_init(&keyboards);wl_signal_add(&backend->events.new_input, &new_input);virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard,&new_virtual_keyboard);seat = wlr_seat_create(dpy, "seat0");wl_signal_add(&seat->events.request_set_cursor, &request_cursor);wl_signal_add(&seat->events.request_set_selection, &request_set_sel);wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel);wl_signal_add(&seat->events.request_start_drag, &request_start_drag);wl_signal_add(&seat->events.start_drag, &start_drag);output_mgr = wlr_output_manager_v1_create(dpy);wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);wl_signal_add(&output_mgr->events.test, &output_mgr_test);wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend));#ifdef XWAYLAND/** Initialise the XWayland X server.* It will be started when the first X client is started.*/xwayland = wlr_xwayland_create(dpy, compositor, 1);if (xwayland) {wl_signal_add(&xwayland->events.ready, &xwayland_ready);wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface);setenv("DISPLAY", xwayland->display_name, 1);} else {fprintf(stderr, "failed to setup XWayland X server, continuing without it\n");}#endif}voidspawn(const Arg *arg){if (fork() == 0) {dup2(STDERR_FILENO, STDOUT_FILENO);setsid();execvp(((char **)arg->v)[0], (char **)arg->v);die("dwl: execvp %s failed:", ((char **)arg->v)[0]);}}voidstartdrag(struct wl_listener *listener, void *data){struct wlr_drag *drag = data;if (!drag->icon)return;drag->icon->data = wlr_scene_subsurface_tree_create(layers[LyrDragIcon], drag->icon->surface);motionnotify(0);wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy);}voidtag(const Arg *arg){Client *sel = selclient();if (sel && arg->ui & TAGMASK) {sel->tags = arg->ui & TAGMASK;focusclient(focustop(selmon), 1);arrange(selmon);}printstatus();}voidtagmon(const Arg *arg){Client *sel = selclient();if (sel)setmon(sel, dirtomon(arg->i), 0);}voidtile(Monitor *m){unsigned int i, n = 0, mw, my, ty;Client *c;wl_list_for_each(c, &clients, link)if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)n++;if (n == 0)return;if (n > m->nmaster)mw = m->nmaster ? m->w.width * m->mfact : 0;elsemw = m->w.width;i = my = ty = 0;wl_list_for_each(c, &clients, link) {if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)continue;if (i < m->nmaster) {resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,.height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0);my += c->geom.height;} else {resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,.width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0);ty += c->geom.height;}i++;}}voidtogglefloating(const Arg *arg){Client *sel = selclient();/* return if fullscreen */if (sel && !sel->isfullscreen)setfloating(sel, !sel->isfloating);}voidtogglefullscreen(const Arg *arg){Client *sel = selclient();if (sel)setfullscreen(sel, !sel->isfullscreen);}voidtoggletag(const Arg *arg){unsigned int newtags;Client *sel = selclient();if (!sel)return;newtags = sel->tags ^ (arg->ui & TAGMASK);if (newtags) {sel->tags = newtags;focusclient(focustop(selmon), 1);arrange(selmon);}printstatus();}voidtoggleview(const Arg *arg){unsigned int newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0;if (newtagset) {selmon->tagset[selmon->seltags] = newtagset;focusclient(focustop(selmon), 1);arrange(selmon);}printstatus();}voidunmaplayersurfacenotify(struct wl_listener *listener, void *data){LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap);layersurface->mapped = 0;wlr_scene_node_set_enabled(&layersurface->scene->node, 0);if (layersurface == exclusive_focus)exclusive_focus = NULL;if (layersurface->layer_surface->output&& (layersurface->mon = layersurface->layer_surface->output->data))arrangelayers(layersurface->mon);if (layersurface->layer_surface->surface ==seat->keyboard_state.focused_surface)focusclient(selclient(), 1);motionnotify(0);}voidunmapnotify(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);if (c == grabc) {cursor_mode = CurNormal;grabc = NULL;}if (c->mon)c->mon->un_map = 1;if (client_is_unmanaged(c)) {if (c == exclusive_focus)exclusive_focus = NULL;if (client_surface(c) == seat->keyboard_state.focused_surface)focusclient(selclient(), 1);} else {wl_list_remove(&c->link);setmon(c, NULL, 0);wl_list_remove(&c->flink);}wl_list_remove(&c->commit.link);wlr_scene_node_destroy(&c->scene->node);printstatus();motionnotify(0);}voidupdatemons(struct wl_listener *listener, void *data){/** Called whenever the output layout changes: adding or removing a* monitor, changing an output's mode or position, etc. This is where* the change officially happens and we update geometry, window* positions, focus, and the stored configuration in wlroots'* output-manager implementation.*/struct wlr_output_configuration_v1 *config =wlr_output_configuration_v1_create();Client *c;struct wlr_output_configuration_head_v1 *config_head;Monitor *m;/* First remove from the layout the disabled monitors */wl_list_for_each(m, &mons, link) {if (m->wlr_output->enabled)continue;config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);config_head->state.enabled = 0;/* Remove this output from the layout to avoid cursor enter inside it */wlr_output_layout_remove(output_layout, m->wlr_output);closemon(m);memset(&m->m, 0, sizeof(m->m));memset(&m->w, 0, sizeof(m->w));}/* Insert outputs that need to */wl_list_for_each(m, &mons, link)if (m->wlr_output->enabled&& !wlr_output_layout_get(output_layout, m->wlr_output))wlr_output_layout_add_auto(output_layout, m->wlr_output);/* Now that we update the output layout we can get its box */wlr_output_layout_get_box(output_layout, NULL, &sgeom);wl_list_for_each(m, &mons, link) {if (!m->wlr_output->enabled)continue;config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);/* Get the effective monitor geometry to use for surfaces */wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->m));wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->w));wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y);/* Calculate the effective monitor geometry to use for clients */arrangelayers(m);/* Don't move clients to the left output when plugging monitors */arrange(m);config_head->state.enabled = 1;config_head->state.mode = m->wlr_output->current_mode;config_head->state.x = m->m.x;config_head->state.y = m->m.y;}if (selmon && selmon->wlr_output->enabled)wl_list_for_each(c, &clients, link)if (!c->mon && client_is_mapped(c))setmon(c, selmon, c->tags);wlr_output_manager_v1_set_configuration(output_mgr, config);}voidupdatetitle(struct wl_listener *listener, void *data){Client *c = wl_container_of(listener, c, set_title);if (c == focustop(c->mon))printstatus();}voidurgent(struct wl_listener *listener, void *data){struct wlr_xdg_activation_v1_request_activate_event *event = data;Client *c = client_from_wlr_surface(event->surface);if (c && c != selclient()) {c->isurgent = 1;printstatus();}}voidview(const Arg *arg){if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])return;selmon->seltags ^= 1; /* toggle sel tagset */if (arg->ui & TAGMASK)selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;focusclient(focustop(selmon), 1);arrange(selmon);printstatus();}voidvirtualkeyboard(struct wl_listener *listener, void *data){struct wlr_virtual_keyboard_v1 *keyboard = data;createkeyboard(&keyboard->keyboard);}Monitor *xytomon(double x, double y){struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y);return o ? o->data : NULL;}struct wlr_scene_node *xytonode(double x, double y, struct wlr_surface **psurface,Client **pc, LayerSurface **pl, double *nx, double *ny){struct wlr_scene_node *node, *pnode;struct wlr_surface *surface = NULL;Client *c = NULL;LayerSurface *l = NULL;const int *layer;int focus_order[] = { LyrOverlay, LyrTop, LyrFloat, LyrTile, LyrBottom, LyrBg };for (layer = focus_order; layer < END(focus_order); layer++) {if ((node = wlr_scene_node_at(&layers[*layer]->node, x, y, nx, ny))) {if (node->type == WLR_SCENE_NODE_BUFFER)surface = wlr_scene_surface_from_buffer(wlr_scene_buffer_from_node(node))->surface;/* Walk the tree to find a node that knows the client */for (pnode = node; pnode && !c; pnode = &pnode->parent->node)c = pnode->data;if (c && c->type == LayerShell) {c = NULL;l = pnode->data;}}if (surface)break;}if (psurface) *psurface = surface;if (pc) *pc = c;if (pl) *pl = l;return node;}voidzoom(const Arg *arg){Client *c, *sel = selclient();if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating)return;/* Search for the first tiled window that is not sel, marking sel as* NULL if we pass it along the way */wl_list_for_each(c, &clients, link)if (VISIBLEON(c, selmon) && !c->isfloating) {if (c != sel)break;sel = NULL;}/* Return if no other tiled window was found */if (&c->link == &clients)return;/* If we passed sel, move c to the front; otherwise, move sel to the* front */if (!sel)sel = c;wl_list_remove(&sel->link);wl_list_insert(&clients, &sel->link);focusclient(sel, 1);arrange(selmon);}#ifdef XWAYLANDvoidactivatex11(struct wl_listener *listener, void *data){Client *c = wl_container_of(listener, c, activate);/* Only "managed" windows can be activated */if (c->type == X11Managed)wlr_xwayland_surface_activate(c->surface.xwayland, 1);}voidconfigurex11(struct wl_listener *listener, void *data){Client *c = wl_container_of(listener, c, configure);struct wlr_xwayland_surface_configure_event *event = data;wlr_xwayland_surface_configure(c->surface.xwayland,event->x, event->y, event->width, event->height);}voidcreatenotifyx11(struct wl_listener *listener, void *data){struct wlr_xwayland_surface *xwayland_surface = data;Client *c;/* TODO: why we unset fullscreen when a xwayland client is created? */wl_list_for_each(c, &clients, link)if (c->isfullscreen && VISIBLEON(c, c->mon))setfullscreen(c, 0);/* Allocate a Client for this surface */c = xwayland_surface->data = ecalloc(1, sizeof(*c));c->surface.xwayland = xwayland_surface;c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed;c->bw = borderpx;/* Listen to the various events it can emit */LISTEN(&xwayland_surface->events.map, &c->map, mapnotify);LISTEN(&xwayland_surface->events.unmap, &c->unmap, unmapnotify);LISTEN(&xwayland_surface->events.request_activate, &c->activate, activatex11);LISTEN(&xwayland_surface->events.request_configure, &c->configure,configurex11);LISTEN(&xwayland_surface->events.set_hints, &c->set_hints, sethints);LISTEN(&xwayland_surface->events.set_title, &c->set_title, updatetitle);LISTEN(&xwayland_surface->events.destroy, &c->destroy, destroynotify);LISTEN(&xwayland_surface->events.request_fullscreen, &c->fullscreen,fullscreennotify);}Atomgetatom(xcb_connection_t *xc, const char *name){Atom atom = 0;xcb_intern_atom_reply_t *reply;xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name);if ((reply = xcb_intern_atom_reply(xc, cookie, NULL)))atom = reply->atom;free(reply);return atom;}voidsethints(struct wl_listener *listener, void *data){Client *c = wl_container_of(listener, c, set_hints);if (c != selclient()) {c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints);printstatus();}}voidsigchld(int unused){siginfo_t in;/* We should be able to remove this function in favor of a simple* signal(SIGCHLD, SIG_IGN);* but the Xwayland implementation in wlroots currently prevents us from* setting our own disposition for SIGCHLD.*/if (signal(SIGCHLD, sigchld) == SIG_ERR)die("can't install SIGCHLD handler:");/* WNOWAIT leaves the child in a waitable state, in case this is the* XWayland process*/while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid&& in.si_pid != xwayland->server->pid)waitpid(in.si_pid, NULL, 0);}voidxwaylandready(struct wl_listener *listener, void *data){struct wlr_xcursor *xcursor;xcb_connection_t *xc = xcb_connect(xwayland->display_name, NULL);int err = xcb_connection_has_error(xc);if (err) {fprintf(stderr, "xcb_connect to X server failed with code %d\n. Continuing with degraded functionality.\n", err);return;}/* Collect atoms we are interested in. If getatom returns 0, we will* not detect that window type. */netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG");netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH");netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR");netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY");/* assign the one and only seat */wlr_xwayland_set_seat(xwayland, seat);/* Set the default XWayland cursor to match the rest of dwl. */if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "left_ptr", 1)))wlr_xwayland_set_cursor(xwayland,xcursor->images[0]->buffer, xcursor->images[0]->width * 4,xcursor->images[0]->width, xcursor->images[0]->height,xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y);xcb_disconnect(xc);}#endifintmain(int argc, char *argv[]){char *startup_cmd = NULL;int c;while ((c = getopt(argc, argv, "s:hv")) != -1) {if (c == 's')startup_cmd = optarg;else if (c == 'v')die("dwl " VERSION);elsegoto usage;}if (optind < argc)goto usage;/* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */if (!getenv("XDG_RUNTIME_DIR"))die("XDG_RUNTIME_DIR must be set");setup();run(startup_cmd);cleanup();return EXIT_SUCCESS;usage:die("Usage: %s [-v] [-s startup command]", argv[0]);}