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);
}
void
destroydragicon(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 XWAYLAND
wl_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);
}
void
maximizenotify(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;
}
void
outputmgrapplyortest(config, 1);
}
void
outputmgrtest(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);
else
wlr_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);
else
if (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 */
}
void
c->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);
else
wlr_data_source_destroy(event->drag->source);
}
void
}
void
m->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 on
printstatus();
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();
}
void
resize(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
}
void
setpsel(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);
}
void
setsel(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)
}
void
if (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 XWAYLAND
signal(SIGINT, quitsignal);
signal(SIGTERM, quitsignal);
#else
signal(SIGCHLD, SIG_IGN);
#endif
layers[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);
#endif
wl_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;
}
void
startdrag(struct wl_listener *listener, void *data)
{
struct wlr_drag *drag = data;
togglefullscreen(const Arg *arg)
{
Client *sel = selclient();
if (sel)
setfullscreen(sel, !sel->isfullscreen);
}
void
printstatus();
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);
}
void
motionnotify(0);
focusclient(selclient(), 1);
if (layersurface->layer_surface->surface ==
seat->keyboard_state.focused_surface)
{
unmaplayersurfacenotify(struct wl_listener *listener, void *data)
}
void
printstatus();
}
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;
}
void
toggleview(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)
{
}
void
if (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();
}
}
void
if (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
}
void
wlr_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? */
}
#endif
xcb_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;
}
void
createlayersurface(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)
}
void
wl_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;
else
startup_cmd = optarg;
if (c == 's')
while ((c = getopt(argc, argv, "s:hv")) != -1) {
int c;
char *startup_cmd = NULL;
int
main(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:");
}
void
sigchld(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)
}
void
sethints(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;
}
Atom
getatom(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)
{
}
void
struct 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 XWAYLAND
void
activatex11(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();
void
zoom(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);
void
virtualkeyboard(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)
{
}
void
printstatus();
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++;
}
}
void
ty += 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;
else
mw = 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)
{
}
void
if (sel)
setmon(sel, dirtomon(arg->i), 0);
tagmon(const Arg *arg)
{
Client *sel = selclient();
void
}
printstatus();
}
arrange(selmon);
focusclient(focustop(selmon), 1);
}
void
tag(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 XWAYLAND
wlr_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 for
cursor = 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 a
wl_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 you
die("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)
{
}
void
arrange(c->mon);
c->isfloating = floating;
{
setfloating(Client *c, int floating)
}
void
event->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 is
cursor_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)
}
void
quitsignal(int signo)
{
quit(NULL);
}
void
wl_display_terminate(dpy);
{
quit(const Arg *arg)
}
void
printf("%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;
}
void
printstatus(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)
}
void
wlr_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 moment
client_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 == XDGShell
c->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)
}
void
motionnotify(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);
}
void
killclient(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. */
{
void
keypressmod(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;
}
void
inputdevice(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;
}
void
incnmaster(const Arg *arg)
{
setfullscreen(c, client_wants_fullscreen(c));
}
void
fullscreennotify(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);
}
void
focusmon(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 focuscolor
if (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)
}
void
dir ^ (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. */
}
void
free(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)
{
}
void
wlr_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)) {
{
}
void
LISTEN(&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 a
createnotify(struct wl_listener *listener, void *data)
}
void
m->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);
void
createlayersurface(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;
}
void
createmon(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);
}
void
createnotify(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);
}
void
createpointer(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);
}
void
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. */
/* Notify the client with pointer focus of the frame event. */
wlr_seat_pointer_notify_frame(seat);
}
void
destroydragicon(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);
}
void
destroyidleinhibitor(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);
}
void
destroylayersurfacenotify(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);
}
void
destroynotify(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 XWAYLAND
if (c->type != XDGShell) {
wl_list_remove(&c->configure.link);
wl_list_remove(&c->set_hints.link);
wl_list_remove(&c->activate.link);
}
#endif
free(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;
}
void
focusclient(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);
}
void
focusmon(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);
}
void
focusstack(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;
}
void
fullscreennotify(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, fullscreen);
setfullscreen(c, client_wants_fullscreen(c));
}
void
incnmaster(const Arg *arg)
{
if (!arg || !selmon)
return;
selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
arrange(selmon);
}
void
inputdevice(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);
}
int
keybinding(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;
}
void
keypress(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);
}
}
void
keypressmod(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);
}
void
killclient(const Arg *arg)
{
Client *sel = selclient();
if (sel)
client_send_close(sel);
}
void
maplayersurfacenotify(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);
}
void
mapnotify(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;
}
#endif
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);
}
/* 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;
}
void
maximizenotify(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);
}
void
monocle(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);
}
void
motionabsolute(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);
}
void
motionnotify(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);
}
void
motionrelative(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);
}
void
moveresize(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;
}
}
void
outputmgrapply(struct wl_listener *listener, void *data)
{
struct wlr_output_configuration_v1 *config = data;
outputmgrapplyortest(config, 0);
}
void
outputmgrapplyortest(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);
else
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);
/* 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);
else
wlr_output_configuration_v1_send_failed(config);
wlr_output_configuration_v1_destroy(config);
/* TODO: use a wrapper function? */
updatemons(NULL, NULL);
}
void
outputmgrtest(struct wl_listener *listener, void *data)
{
struct wlr_output_configuration_v1 *config = data;
outputmgrapplyortest(config, 1);
}
void
pointerfocus(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);
}
void
printstatus(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);
}
}
void
quit(const Arg *arg)
{
wl_display_terminate(dpy);
}
void
quitsignal(int signo)
{
quit(NULL);
}
void
rendermon(struct wl_listener *listener, void *data)
{
/* This function is called every time an output is ready to display a frame,
* generally at the output's refresh rate (e.g. 60Hz). */
Monitor *m = wl_container_of(listener, m, frame);
Client *c;
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;
}
void
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);
else
wlr_data_source_destroy(event->drag->source);
}
void
resize(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);
}
void
run(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;
}
void
setcursor(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);
}
void
setfloating(Client *c, int floating)
{
c->isfloating = floating;
wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]);
arrange(c->mon);
printstatus();
}
void
setfullscreen(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();
}
void
setlayout(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 */
void
setmfact(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);
}
void
setmon(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);
}
void
setpsel(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);
}
void
setsel(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);
}
void
setup(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 XWAYLAND
sigchld(0);
#else
signal(SIGCHLD, SIG_IGN);
#endif
signal(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
}
void
spawn(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]);
}
}
void
startdrag(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);
}
void
tag(const Arg *arg)
{
Client *sel = selclient();
if (sel && arg->ui & TAGMASK) {
sel->tags = arg->ui & TAGMASK;
focusclient(focustop(selmon), 1);
arrange(selmon);
}
printstatus();
}
void
tagmon(const Arg *arg)
{
Client *sel = selclient();
if (sel)
setmon(sel, dirtomon(arg->i), 0);
}
void
tile(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;
else
mw = 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++;
}
}
void
togglefloating(const Arg *arg)
{
Client *sel = selclient();
/* return if fullscreen */
if (sel && !sel->isfullscreen)
setfloating(sel, !sel->isfloating);
}
void
togglefullscreen(const Arg *arg)
{
Client *sel = selclient();
if (sel)
setfullscreen(sel, !sel->isfullscreen);
}
void
toggletag(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();
}
void
toggleview(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();
}
void
unmaplayersurfacenotify(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);
}
void
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);
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);
}
void
updatemons(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);
}
void
updatetitle(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, set_title);
if (c == focustop(c->mon))
printstatus();
}
void
urgent(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();
}
}
void
view(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();
}
void
virtualkeyboard(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;
}
void
zoom(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 XWAYLAND
void
activatex11(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);
}
void
configurex11(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);
}
void
createnotifyx11(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);
}
Atom
getatom(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;
}
void
sethints(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();
}
}
void
sigchld(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);
}
void
xwaylandready(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);
}
#endif
int
main(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);
else
goto 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]);
}