commit 540c1a5

ohmu  ·  2026-10-18 23:48:03 +0300 MSK
parent f33f07a
upload
19 files changed,  +9326, -0
+693, -0
  1@@ -0,0 +1,693 @@
  2+Leeloo - 5element for wayland
  3+
  4+Copyright © 2026 wh1tepearl 
  5+Copyright © 2026 umix11
  6+
  7+See also the files LICENSE.dwl, LICENSE.tinywl, LICENSE.dwm and LICENSE.sway.
  8+
  9+This program is free software: you can redistribute it and/or modify
 10+it under the terms of the GNU General Public License as published by
 11+the Free Software Foundation, either version 3 of the License, or
 12+(at your option) any later version.
 13+
 14+This program is distributed in the hope that it will be useful,
 15+but WITHOUT ANY WARRANTY; without even the implied warranty of
 16+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 17+GNU General Public License for more details.
 18+
 19+----
 20+
 21+                    GNU GENERAL PUBLIC LICENSE
 22+                       Version 3, 29 June 2007
 23+
 24+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
 25+ Everyone is permitted to copy and distribute verbatim copies
 26+ of this license document, but changing it is not allowed.
 27+
 28+                            Preamble
 29+
 30+  The GNU General Public License is a free, copyleft license for
 31+software and other kinds of works.
 32+
 33+  The licenses for most software and other practical works are designed
 34+to take away your freedom to share and change the works.  By contrast,
 35+the GNU General Public License is intended to guarantee your freedom to
 36+share and change all versions of a program--to make sure it remains free
 37+software for all its users.  We, the Free Software Foundation, use the
 38+GNU General Public License for most of our software; it applies also to
 39+any other work released this way by its authors.  You can apply it to
 40+your programs, too.
 41+
 42+  When we speak of free software, we are referring to freedom, not
 43+price.  Our General Public Licenses are designed to make sure that you
 44+have the freedom to distribute copies of free software (and charge for
 45+them if you wish), that you receive source code or can get it if you
 46+want it, that you can change the software or use pieces of it in new
 47+free programs, and that you know you can do these things.
 48+
 49+  To protect your rights, we need to prevent others from denying you
 50+these rights or asking you to surrender the rights.  Therefore, you have
 51+certain responsibilities if you distribute copies of the software, or if
 52+you modify it: responsibilities to respect the freedom of others.
 53+
 54+  For example, if you distribute copies of such a program, whether
 55+gratis or for a fee, you must pass on to the recipients the same
 56+freedoms that you received.  You must make sure that they, too, receive
 57+or can get the source code.  And you must show them these terms so they
 58+know their rights.
 59+
 60+  Developers that use the GNU GPL protect your rights with two steps:
 61+(1) assert copyright on the software, and (2) offer you this License
 62+giving you legal permission to copy, distribute and/or modify it.
 63+
 64+  For the developers' and authors' protection, the GPL clearly explains
 65+that there is no warranty for this free software.  For both users' and
 66+authors' sake, the GPL requires that modified versions be marked as
 67+changed, so that their problems will not be attributed erroneously to
 68+authors of previous versions.
 69+
 70+  Some devices are designed to deny users access to install or run
 71+modified versions of the software inside them, although the manufacturer
 72+can do so.  This is fundamentally incompatible with the aim of
 73+protecting users' freedom to change the software.  The systematic
 74+pattern of such abuse occurs in the area of products for individuals to
 75+use, which is precisely where it is most unacceptable.  Therefore, we
 76+have designed this version of the GPL to prohibit the practice for those
 77+products.  If such problems arise substantially in other domains, we
 78+stand ready to extend this provision to those domains in future versions
 79+of the GPL, as needed to protect the freedom of users.
 80+
 81+  Finally, every program is threatened constantly by software patents.
 82+States should not allow patents to restrict development and use of
 83+software on general-purpose computers, but in those that do, we wish to
 84+avoid the special danger that patents applied to a free program could
 85+make it effectively proprietary.  To prevent this, the GPL assures that
 86+patents cannot be used to render the program non-free.
 87+
 88+  The precise terms and conditions for copying, distribution and
 89+modification follow.
 90+
 91+                       TERMS AND CONDITIONS
 92+
 93+  0. Definitions.
 94+
 95+  "This License" refers to version 3 of the GNU General Public License.
 96+
 97+  "Copyright" also means copyright-like laws that apply to other kinds of
 98+works, such as semiconductor masks.
 99+
100+  "The Program" refers to any copyrightable work licensed under this
101+License.  Each licensee is addressed as "you".  "Licensees" and
102+"recipients" may be individuals or organizations.
103+
104+  To "modify" a work means to copy from or adapt all or part of the work
105+in a fashion requiring copyright permission, other than the making of an
106+exact copy.  The resulting work is called a "modified version" of the
107+earlier work or a work "based on" the earlier work.
108+
109+  A "covered work" means either the unmodified Program or a work based
110+on the Program.
111+
112+  To "propagate" a work means to do anything with it that, without
113+permission, would make you directly or secondarily liable for
114+infringement under applicable copyright law, except executing it on a
115+computer or modifying a private copy.  Propagation includes copying,
116+distribution (with or without modification), making available to the
117+public, and in some countries other activities as well.
118+
119+  To "convey" a work means any kind of propagation that enables other
120+parties to make or receive copies.  Mere interaction with a user through
121+a computer network, with no transfer of a copy, is not conveying.
122+
123+  An interactive user interface displays "Appropriate Legal Notices"
124+to the extent that it includes a convenient and prominently visible
125+feature that (1) displays an appropriate copyright notice, and (2)
126+tells the user that there is no warranty for the work (except to the
127+extent that warranties are provided), that licensees may convey the
128+work under this License, and how to view a copy of this License.  If
129+the interface presents a list of user commands or options, such as a
130+menu, a prominent item in the list meets this criterion.
131+
132+  1. Source Code.
133+
134+  The "source code" for a work means the preferred form of the work
135+for making modifications to it.  "Object code" means any non-source
136+form of a work.
137+
138+  A "Standard Interface" means an interface that either is an official
139+standard defined by a recognized standards body, or, in the case of
140+interfaces specified for a particular programming language, one that
141+is widely used among developers working in that language.
142+
143+  The "System Libraries" of an executable work include anything, other
144+than the work as a whole, that (a) is included in the normal form of
145+packaging a Major Component, but which is not part of that Major
146+Component, and (b) serves only to enable use of the work with that
147+Major Component, or to implement a Standard Interface for which an
148+implementation is available to the public in source code form.  A
149+"Major Component", in this context, means a major essential component
150+(kernel, window system, and so on) of the specific operating system
151+(if any) on which the executable work runs, or a compiler used to
152+produce the work, or an object code interpreter used to run it.
153+
154+  The "Corresponding Source" for a work in object code form means all
155+the source code needed to generate, install, and (for an executable
156+work) run the object code and to modify the work, including scripts to
157+control those activities.  However, it does not include the work's
158+System Libraries, or general-purpose tools or generally available free
159+programs which are used unmodified in performing those activities but
160+which are not part of the work.  For example, Corresponding Source
161+includes interface definition files associated with source files for
162+the work, and the source code for shared libraries and dynamically
163+linked subprograms that the work is specifically designed to require,
164+such as by intimate data communication or control flow between those
165+subprograms and other parts of the work.
166+
167+  The Corresponding Source need not include anything that users
168+can regenerate automatically from other parts of the Corresponding
169+Source.
170+
171+  The Corresponding Source for a work in source code form is that
172+same work.
173+
174+  2. Basic Permissions.
175+
176+  All rights granted under this License are granted for the term of
177+copyright on the Program, and are irrevocable provided the stated
178+conditions are met.  This License explicitly affirms your unlimited
179+permission to run the unmodified Program.  The output from running a
180+covered work is covered by this License only if the output, given its
181+content, constitutes a covered work.  This License acknowledges your
182+rights of fair use or other equivalent, as provided by copyright law.
183+
184+  You may make, run and propagate covered works that you do not
185+convey, without conditions so long as your license otherwise remains
186+in force.  You may convey covered works to others for the sole purpose
187+of having them make modifications exclusively for you, or provide you
188+with facilities for running those works, provided that you comply with
189+the terms of this License in conveying all material for which you do
190+not control copyright.  Those thus making or running the covered works
191+for you must do so exclusively on your behalf, under your direction
192+and control, on terms that prohibit them from making any copies of
193+your copyrighted material outside their relationship with you.
194+
195+  Conveying under any other circumstances is permitted solely under
196+the conditions stated below.  Sublicensing is not allowed; section 10
197+makes it unnecessary.
198+
199+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
200+
201+  No covered work shall be deemed part of an effective technological
202+measure under any applicable law fulfilling obligations under article
203+11 of the WIPO copyright treaty adopted on 20 December 1996, or
204+similar laws prohibiting or restricting circumvention of such
205+measures.
206+
207+  When you convey a covered work, you waive any legal power to forbid
208+circumvention of technological measures to the extent such circumvention
209+is effected by exercising rights under this License with respect to
210+the covered work, and you disclaim any intention to limit operation or
211+modification of the work as a means of enforcing, against the work's
212+users, your or third parties' legal rights to forbid circumvention of
213+technological measures.
214+
215+  4. Conveying Verbatim Copies.
216+
217+  You may convey verbatim copies of the Program's source code as you
218+receive it, in any medium, provided that you conspicuously and
219+appropriately publish on each copy an appropriate copyright notice;
220+keep intact all notices stating that this License and any
221+non-permissive terms added in accord with section 7 apply to the code;
222+keep intact all notices of the absence of any warranty; and give all
223+recipients a copy of this License along with the Program.
224+
225+  You may charge any price or no price for each copy that you convey,
226+and you may offer support or warranty protection for a fee.
227+
228+  5. Conveying Modified Source Versions.
229+
230+  You may convey a work based on the Program, or the modifications to
231+produce it from the Program, in the form of source code under the
232+terms of section 4, provided that you also meet all of these conditions:
233+
234+    a) The work must carry prominent notices stating that you modified
235+    it, and giving a relevant date.
236+
237+    b) The work must carry prominent notices stating that it is
238+    released under this License and any conditions added under section
239+    7.  This requirement modifies the requirement in section 4 to
240+    "keep intact all notices".
241+
242+    c) You must license the entire work, as a whole, under this
243+    License to anyone who comes into possession of a copy.  This
244+    License will therefore apply, along with any applicable section 7
245+    additional terms, to the whole of the work, and all its parts,
246+    regardless of how they are packaged.  This License gives no
247+    permission to license the work in any other way, but it does not
248+    invalidate such permission if you have separately received it.
249+
250+    d) If the work has interactive user interfaces, each must display
251+    Appropriate Legal Notices; however, if the Program has interactive
252+    interfaces that do not display Appropriate Legal Notices, your
253+    work need not make them do so.
254+
255+  A compilation of a covered work with other separate and independent
256+works, which are not by their nature extensions of the covered work,
257+and which are not combined with it such as to form a larger program,
258+in or on a volume of a storage or distribution medium, is called an
259+"aggregate" if the compilation and its resulting copyright are not
260+used to limit the access or legal rights of the compilation's users
261+beyond what the individual works permit.  Inclusion of a covered work
262+in an aggregate does not cause this License to apply to the other
263+parts of the aggregate.
264+
265+  6. Conveying Non-Source Forms.
266+
267+  You may convey a covered work in object code form under the terms
268+of sections 4 and 5, provided that you also convey the
269+machine-readable Corresponding Source under the terms of this License,
270+in one of these ways:
271+
272+    a) Convey the object code in, or embodied in, a physical product
273+    (including a physical distribution medium), accompanied by the
274+    Corresponding Source fixed on a durable physical medium
275+    customarily used for software interchange.
276+
277+    b) Convey the object code in, or embodied in, a physical product
278+    (including a physical distribution medium), accompanied by a
279+    written offer, valid for at least three years and valid for as
280+    long as you offer spare parts or customer support for that product
281+    model, to give anyone who possesses the object code either (1) a
282+    copy of the Corresponding Source for all the software in the
283+    product that is covered by this License, on a durable physical
284+    medium customarily used for software interchange, for a price no
285+    more than your reasonable cost of physically performing this
286+    conveying of source, or (2) access to copy the
287+    Corresponding Source from a network server at no charge.
288+
289+    c) Convey individual copies of the object code with a copy of the
290+    written offer to provide the Corresponding Source.  This
291+    alternative is allowed only occasionally and noncommercially, and
292+    only if you received the object code with such an offer, in accord
293+    with subsection 6b.
294+
295+    d) Convey the object code by offering access from a designated
296+    place (gratis or for a charge), and offer equivalent access to the
297+    Corresponding Source in the same way through the same place at no
298+    further charge.  You need not require recipients to copy the
299+    Corresponding Source along with the object code.  If the place to
300+    copy the object code is a network server, the Corresponding Source
301+    may be on a different server (operated by you or a third party)
302+    that supports equivalent copying facilities, provided you maintain
303+    clear directions next to the object code saying where to find the
304+    Corresponding Source.  Regardless of what server hosts the
305+    Corresponding Source, you remain obligated to ensure that it is
306+    available for as long as needed to satisfy these requirements.
307+
308+    e) Convey the object code using peer-to-peer transmission, provided
309+    you inform other peers where the object code and Corresponding
310+    Source of the work are being offered to the general public at no
311+    charge under subsection 6d.
312+
313+  A separable portion of the object code, whose source code is excluded
314+from the Corresponding Source as a System Library, need not be
315+included in conveying the object code work.
316+
317+  A "User Product" is either (1) a "consumer product", which means any
318+tangible personal property which is normally used for personal, family,
319+or household purposes, or (2) anything designed or sold for incorporation
320+into a dwelling.  In determining whether a product is a consumer product,
321+doubtful cases shall be resolved in favor of coverage.  For a particular
322+product received by a particular user, "normally used" refers to a
323+typical or common use of that class of product, regardless of the status
324+of the particular user or of the way in which the particular user
325+actually uses, or expects or is expected to use, the product.  A product
326+is a consumer product regardless of whether the product has substantial
327+commercial, industrial or non-consumer uses, unless such uses represent
328+the only significant mode of use of the product.
329+
330+  "Installation Information" for a User Product means any methods,
331+procedures, authorization keys, or other information required to install
332+and execute modified versions of a covered work in that User Product from
333+a modified version of its Corresponding Source.  The information must
334+suffice to ensure that the continued functioning of the modified object
335+code is in no case prevented or interfered with solely because
336+modification has been made.
337+
338+  If you convey an object code work under this section in, or with, or
339+specifically for use in, a User Product, and the conveying occurs as
340+part of a transaction in which the right of possession and use of the
341+User Product is transferred to the recipient in perpetuity or for a
342+fixed term (regardless of how the transaction is characterized), the
343+Corresponding Source conveyed under this section must be accompanied
344+by the Installation Information.  But this requirement does not apply
345+if neither you nor any third party retains the ability to install
346+modified object code on the User Product (for example, the work has
347+been installed in ROM).
348+
349+  The requirement to provide Installation Information does not include a
350+requirement to continue to provide support service, warranty, or updates
351+for a work that has been modified or installed by the recipient, or for
352+the User Product in which it has been modified or installed.  Access to a
353+network may be denied when the modification itself materially and
354+adversely affects the operation of the network or violates the rules and
355+protocols for communication across the network.
356+
357+  Corresponding Source conveyed, and Installation Information provided,
358+in accord with this section must be in a format that is publicly
359+documented (and with an implementation available to the public in
360+source code form), and must require no special password or key for
361+unpacking, reading or copying.
362+
363+  7. Additional Terms.
364+
365+  "Additional permissions" are terms that supplement the terms of this
366+License by making exceptions from one or more of its conditions.
367+Additional permissions that are applicable to the entire Program shall
368+be treated as though they were included in this License, to the extent
369+that they are valid under applicable law.  If additional permissions
370+apply only to part of the Program, that part may be used separately
371+under those permissions, but the entire Program remains governed by
372+this License without regard to the additional permissions.
373+
374+  When you convey a copy of a covered work, you may at your option
375+remove any additional permissions from that copy, or from any part of
376+it.  (Additional permissions may be written to require their own
377+removal in certain cases when you modify the work.)  You may place
378+additional permissions on material, added by you to a covered work,
379+for which you have or can give appropriate copyright permission.
380+
381+  Notwithstanding any other provision of this License, for material you
382+add to a covered work, you may (if authorized by the copyright holders of
383+that material) supplement the terms of this License with terms:
384+
385+    a) Disclaiming warranty or limiting liability differently from the
386+    terms of sections 15 and 16 of this License; or
387+
388+    b) Requiring preservation of specified reasonable legal notices or
389+    author attributions in that material or in the Appropriate Legal
390+    Notices displayed by works containing it; or
391+
392+    c) Prohibiting misrepresentation of the origin of that material, or
393+    requiring that modified versions of such material be marked in
394+    reasonable ways as different from the original version; or
395+
396+    d) Limiting the use for publicity purposes of names of licensors or
397+    authors of the material; or
398+
399+    e) Declining to grant rights under trademark law for use of some
400+    trade names, trademarks, or service marks; or
401+
402+    f) Requiring indemnification of licensors and authors of that
403+    material by anyone who conveys the material (or modified versions of
404+    it) with contractual assumptions of liability to the recipient, for
405+    any liability that these contractual assumptions directly impose on
406+    those licensors and authors.
407+
408+  All other non-permissive additional terms are considered "further
409+restrictions" within the meaning of section 10.  If the Program as you
410+received it, or any part of it, contains a notice stating that it is
411+governed by this License along with a term that is a further
412+restriction, you may remove that term.  If a license document contains
413+a further restriction but permits relicensing or conveying under this
414+License, you may add to a covered work material governed by the terms
415+of that license document, provided that the further restriction does
416+not survive such relicensing or conveying.
417+
418+  If you add terms to a covered work in accord with this section, you
419+must place, in the relevant source files, a statement of the
420+additional terms that apply to those files, or a notice indicating
421+where to find the applicable terms.
422+
423+  Additional terms, permissive or non-permissive, may be stated in the
424+form of a separately written license, or stated as exceptions;
425+the above requirements apply either way.
426+
427+  8. Termination.
428+
429+  You may not propagate or modify a covered work except as expressly
430+provided under this License.  Any attempt otherwise to propagate or
431+modify it is void, and will automatically terminate your rights under
432+this License (including any patent licenses granted under the third
433+paragraph of section 11).
434+
435+  However, if you cease all violation of this License, then your
436+license from a particular copyright holder is reinstated (a)
437+provisionally, unless and until the copyright holder explicitly and
438+finally terminates your license, and (b) permanently, if the copyright
439+holder fails to notify you of the violation by some reasonable means
440+prior to 60 days after the cessation.
441+
442+  Moreover, your license from a particular copyright holder is
443+reinstated permanently if the copyright holder notifies you of the
444+violation by some reasonable means, this is the first time you have
445+received notice of violation of this License (for any work) from that
446+copyright holder, and you cure the violation prior to 30 days after
447+your receipt of the notice.
448+
449+  Termination of your rights under this section does not terminate the
450+licenses of parties who have received copies or rights from you under
451+this License.  If your rights have been terminated and not permanently
452+reinstated, you do not qualify to receive new licenses for the same
453+material under section 10.
454+
455+  9. Acceptance Not Required for Having Copies.
456+
457+  You are not required to accept this License in order to receive or
458+run a copy of the Program.  Ancillary propagation of a covered work
459+occurring solely as a consequence of using peer-to-peer transmission
460+to receive a copy likewise does not require acceptance.  However,
461+nothing other than this License grants you permission to propagate or
462+modify any covered work.  These actions infringe copyright if you do
463+not accept this License.  Therefore, by modifying or propagating a
464+covered work, you indicate your acceptance of this License to do so.
465+
466+  10. Automatic Licensing of Downstream Recipients.
467+
468+  Each time you convey a covered work, the recipient automatically
469+receives a license from the original licensors, to run, modify and
470+propagate that work, subject to this License.  You are not responsible
471+for enforcing compliance by third parties with this License.
472+
473+  An "entity transaction" is a transaction transferring control of an
474+organization, or substantially all assets of one, or subdividing an
475+organization, or merging organizations.  If propagation of a covered
476+work results from an entity transaction, each party to that
477+transaction who receives a copy of the work also receives whatever
478+licenses to the work the party's predecessor in interest had or could
479+give under the previous paragraph, plus a right to possession of the
480+Corresponding Source of the work from the predecessor in interest, if
481+the predecessor has it or can get it with reasonable efforts.
482+
483+  You may not impose any further restrictions on the exercise of the
484+rights granted or affirmed under this License.  For example, you may
485+not impose a license fee, royalty, or other charge for exercise of
486+rights granted under this License, and you may not initiate litigation
487+(including a cross-claim or counterclaim in a lawsuit) alleging that
488+any patent claim is infringed by making, using, selling, offering for
489+sale, or importing the Program or any portion of it.
490+
491+  11. Patents.
492+
493+  A "contributor" is a copyright holder who authorizes use under this
494+License of the Program or a work on which the Program is based.  The
495+work thus licensed is called the contributor's "contributor version".
496+
497+  A contributor's "essential patent claims" are all patent claims
498+owned or controlled by the contributor, whether already acquired or
499+hereafter acquired, that would be infringed by some manner, permitted
500+by this License, of making, using, or selling its contributor version,
501+but do not include claims that would be infringed only as a
502+consequence of further modification of the contributor version.  For
503+purposes of this definition, "control" includes the right to grant
504+patent sublicenses in a manner consistent with the requirements of
505+this License.
506+
507+  Each contributor grants you a non-exclusive, worldwide, royalty-free
508+patent license under the contributor's essential patent claims, to
509+make, use, sell, offer for sale, import and otherwise run, modify and
510+propagate the contents of its contributor version.
511+
512+  In the following three paragraphs, a "patent license" is any express
513+agreement or commitment, however denominated, not to enforce a patent
514+(such as an express permission to practice a patent or covenant not to
515+sue for patent infringement).  To "grant" such a patent license to a
516+party means to make such an agreement or commitment not to enforce a
517+patent against the party.
518+
519+  If you convey a covered work, knowingly relying on a patent license,
520+and the Corresponding Source of the work is not available for anyone
521+to copy, free of charge and under the terms of this License, through a
522+publicly available network server or other readily accessible means,
523+then you must either (1) cause the Corresponding Source to be so
524+available, or (2) arrange to deprive yourself of the benefit of the
525+patent license for this particular work, or (3) arrange, in a manner
526+consistent with the requirements of this License, to extend the patent
527+license to downstream recipients.  "Knowingly relying" means you have
528+actual knowledge that, but for the patent license, your conveying the
529+covered work in a country, or your recipient's use of the covered work
530+in a country, would infringe one or more identifiable patents in that
531+country that you have reason to believe are valid.
532+
533+  If, pursuant to or in connection with a single transaction or
534+arrangement, you convey, or propagate by procuring conveyance of, a
535+covered work, and grant a patent license to some of the parties
536+receiving the covered work authorizing them to use, propagate, modify
537+or convey a specific copy of the covered work, then the patent license
538+you grant is automatically extended to all recipients of the covered
539+work and works based on it.
540+
541+  A patent license is "discriminatory" if it does not include within
542+the scope of its coverage, prohibits the exercise of, or is
543+conditioned on the non-exercise of one or more of the rights that are
544+specifically granted under this License.  You may not convey a covered
545+work if you are a party to an arrangement with a third party that is
546+in the business of distributing software, under which you make payment
547+to the third party based on the extent of your activity of conveying
548+the work, and under which the third party grants, to any of the
549+parties who would receive the covered work from you, a discriminatory
550+patent license (a) in connection with copies of the covered work
551+conveyed by you (or copies made from those copies), or (b) primarily
552+for and in connection with specific products or compilations that
553+contain the covered work, unless you entered into that arrangement,
554+or that patent license was granted, prior to 28 March 2007.
555+
556+  Nothing in this License shall be construed as excluding or limiting
557+any implied license or other defenses to infringement that may
558+otherwise be available to you under applicable patent law.
559+
560+  12. No Surrender of Others' Freedom.
561+
562+  If conditions are imposed on you (whether by court order, agreement or
563+otherwise) that contradict the conditions of this License, they do not
564+excuse you from the conditions of this License.  If you cannot convey a
565+covered work so as to satisfy simultaneously your obligations under this
566+License and any other pertinent obligations, then as a consequence you may
567+not convey it at all.  For example, if you agree to terms that obligate you
568+to collect a royalty for further conveying from those to whom you convey
569+the Program, the only way you could satisfy both those terms and this
570+License would be to refrain entirely from conveying the Program.
571+
572+  13. Use with the GNU Affero General Public License.
573+
574+  Notwithstanding any other provision of this License, you have
575+permission to link or combine any covered work with a work licensed
576+under version 3 of the GNU Affero General Public License into a single
577+combined work, and to convey the resulting work.  The terms of this
578+License will continue to apply to the part which is the covered work,
579+but the special requirements of the GNU Affero General Public License,
580+section 13, concerning interaction through a network will apply to the
581+combination as such.
582+
583+  14. Revised Versions of this License.
584+
585+  The Free Software Foundation may publish revised and/or new versions of
586+the GNU General Public License from time to time.  Such new versions will
587+be similar in spirit to the present version, but may differ in detail to
588+address new problems or concerns.
589+
590+  Each version is given a distinguishing version number.  If the
591+Program specifies that a certain numbered version of the GNU General
592+Public License "or any later version" applies to it, you have the
593+option of following the terms and conditions either of that numbered
594+version or of any later version published by the Free Software
595+Foundation.  If the Program does not specify a version number of the
596+GNU General Public License, you may choose any version ever published
597+by the Free Software Foundation.
598+
599+  If the Program specifies that a proxy can decide which future
600+versions of the GNU General Public License can be used, that proxy's
601+public statement of acceptance of a version permanently authorizes you
602+to choose that version for the Program.
603+
604+  Later license versions may give you additional or different
605+permissions.  However, no additional obligations are imposed on any
606+author or copyright holder as a result of your choosing to follow a
607+later version.
608+
609+  15. Disclaimer of Warranty.
610+
611+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
612+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
613+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
614+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
615+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
616+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
617+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
618+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
619+
620+  16. Limitation of Liability.
621+
622+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
623+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
624+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
625+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
626+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
627+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
628+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
629+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
630+SUCH DAMAGES.
631+
632+  17. Interpretation of Sections 15 and 16.
633+
634+  If the disclaimer of warranty and limitation of liability provided
635+above cannot be given local legal effect according to their terms,
636+reviewing courts shall apply local law that most closely approximates
637+an absolute waiver of all civil liability in connection with the
638+Program, unless a warranty or assumption of liability accompanies a
639+copy of the Program in return for a fee.
640+
641+                     END OF TERMS AND CONDITIONS
642+
643+            How to Apply These Terms to Your New Programs
644+
645+  If you develop a new program, and you want it to be of the greatest
646+possible use to the public, the best way to achieve this is to make it
647+free software which everyone can redistribute and change under these terms.
648+
649+  To do so, attach the following notices to the program.  It is safest
650+to attach them to the start of each source file to most effectively
651+state the exclusion of warranty; and each file should have at least
652+the "copyright" line and a pointer to where the full notice is found.
653+
654+    <one line to give the program's name and a brief idea of what it does.>
655+    Copyright (C) <year>  <name of author>
656+
657+    This program is free software: you can redistribute it and/or modify
658+    it under the terms of the GNU General Public License as published by
659+    the Free Software Foundation, either version 3 of the License, or
660+    (at your option) any later version.
661+
662+    This program is distributed in the hope that it will be useful,
663+    but WITHOUT ANY WARRANTY; without even the implied warranty of
664+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
665+    GNU General Public License for more details.
666+
667+    You should have received a copy of the GNU General Public License
668+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
669+
670+Also add information on how to contact you by electronic and paper mail.
671+
672+  If the program does terminal interaction, make it output a short
673+notice like this when it starts in an interactive mode:
674+
675+    <program>  Copyright (C) <year>  <name of author>
676+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
677+    This is free software, and you are welcome to redistribute it
678+    under certain conditions; type `show c' for details.
679+
680+The hypothetical commands `show w' and `show c' should show the appropriate
681+parts of the General Public License.  Of course, your program's commands
682+might be different; for a GUI interface, you would use an "about box".
683+
684+  You should also get your employer (if you work as a programmer) or school,
685+if any, to sign a "copyright disclaimer" for the program, if necessary.
686+For more information on this, and how to apply and follow the GNU GPL, see
687+<https://www.gnu.org/licenses/>.
688+
689+  The GNU General Public License does not permit incorporating your program
690+into proprietary programs.  If your program is a subroutine library, you
691+may consider it more useful to permit linking proprietary applications with
692+the library.  If this is what you want to do, use the GNU Lesser General
693+Public License instead of this License.  But first, please read
694+<https://www.gnu.org/licenses/why-not-lgpl.html>.
+692, -0
  1@@ -0,0 +1,692 @@
  2+dwl - dwm for Wayland
  3+
  4+Copyright © 2020 dwl team
  5+
  6+See also the files LICENSE.tinywl, LICENSE.dwm and LICENSE.sway.
  7+
  8+This program is free software: you can redistribute it and/or modify
  9+it under the terms of the GNU General Public License as published by
 10+the Free Software Foundation, either version 3 of the License, or
 11+(at your option) any later version.
 12+
 13+This program is distributed in the hope that it will be useful,
 14+but WITHOUT ANY WARRANTY; without even the implied warranty of
 15+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16+GNU General Public License for more details.
 17+
 18+----
 19+
 20+                    GNU GENERAL PUBLIC LICENSE
 21+                       Version 3, 29 June 2007
 22+
 23+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
 24+ Everyone is permitted to copy and distribute verbatim copies
 25+ of this license document, but changing it is not allowed.
 26+
 27+                            Preamble
 28+
 29+  The GNU General Public License is a free, copyleft license for
 30+software and other kinds of works.
 31+
 32+  The licenses for most software and other practical works are designed
 33+to take away your freedom to share and change the works.  By contrast,
 34+the GNU General Public License is intended to guarantee your freedom to
 35+share and change all versions of a program--to make sure it remains free
 36+software for all its users.  We, the Free Software Foundation, use the
 37+GNU General Public License for most of our software; it applies also to
 38+any other work released this way by its authors.  You can apply it to
 39+your programs, too.
 40+
 41+  When we speak of free software, we are referring to freedom, not
 42+price.  Our General Public Licenses are designed to make sure that you
 43+have the freedom to distribute copies of free software (and charge for
 44+them if you wish), that you receive source code or can get it if you
 45+want it, that you can change the software or use pieces of it in new
 46+free programs, and that you know you can do these things.
 47+
 48+  To protect your rights, we need to prevent others from denying you
 49+these rights or asking you to surrender the rights.  Therefore, you have
 50+certain responsibilities if you distribute copies of the software, or if
 51+you modify it: responsibilities to respect the freedom of others.
 52+
 53+  For example, if you distribute copies of such a program, whether
 54+gratis or for a fee, you must pass on to the recipients the same
 55+freedoms that you received.  You must make sure that they, too, receive
 56+or can get the source code.  And you must show them these terms so they
 57+know their rights.
 58+
 59+  Developers that use the GNU GPL protect your rights with two steps:
 60+(1) assert copyright on the software, and (2) offer you this License
 61+giving you legal permission to copy, distribute and/or modify it.
 62+
 63+  For the developers' and authors' protection, the GPL clearly explains
 64+that there is no warranty for this free software.  For both users' and
 65+authors' sake, the GPL requires that modified versions be marked as
 66+changed, so that their problems will not be attributed erroneously to
 67+authors of previous versions.
 68+
 69+  Some devices are designed to deny users access to install or run
 70+modified versions of the software inside them, although the manufacturer
 71+can do so.  This is fundamentally incompatible with the aim of
 72+protecting users' freedom to change the software.  The systematic
 73+pattern of such abuse occurs in the area of products for individuals to
 74+use, which is precisely where it is most unacceptable.  Therefore, we
 75+have designed this version of the GPL to prohibit the practice for those
 76+products.  If such problems arise substantially in other domains, we
 77+stand ready to extend this provision to those domains in future versions
 78+of the GPL, as needed to protect the freedom of users.
 79+
 80+  Finally, every program is threatened constantly by software patents.
 81+States should not allow patents to restrict development and use of
 82+software on general-purpose computers, but in those that do, we wish to
 83+avoid the special danger that patents applied to a free program could
 84+make it effectively proprietary.  To prevent this, the GPL assures that
 85+patents cannot be used to render the program non-free.
 86+
 87+  The precise terms and conditions for copying, distribution and
 88+modification follow.
 89+
 90+                       TERMS AND CONDITIONS
 91+
 92+  0. Definitions.
 93+
 94+  "This License" refers to version 3 of the GNU General Public License.
 95+
 96+  "Copyright" also means copyright-like laws that apply to other kinds of
 97+works, such as semiconductor masks.
 98+
 99+  "The Program" refers to any copyrightable work licensed under this
100+License.  Each licensee is addressed as "you".  "Licensees" and
101+"recipients" may be individuals or organizations.
102+
103+  To "modify" a work means to copy from or adapt all or part of the work
104+in a fashion requiring copyright permission, other than the making of an
105+exact copy.  The resulting work is called a "modified version" of the
106+earlier work or a work "based on" the earlier work.
107+
108+  A "covered work" means either the unmodified Program or a work based
109+on the Program.
110+
111+  To "propagate" a work means to do anything with it that, without
112+permission, would make you directly or secondarily liable for
113+infringement under applicable copyright law, except executing it on a
114+computer or modifying a private copy.  Propagation includes copying,
115+distribution (with or without modification), making available to the
116+public, and in some countries other activities as well.
117+
118+  To "convey" a work means any kind of propagation that enables other
119+parties to make or receive copies.  Mere interaction with a user through
120+a computer network, with no transfer of a copy, is not conveying.
121+
122+  An interactive user interface displays "Appropriate Legal Notices"
123+to the extent that it includes a convenient and prominently visible
124+feature that (1) displays an appropriate copyright notice, and (2)
125+tells the user that there is no warranty for the work (except to the
126+extent that warranties are provided), that licensees may convey the
127+work under this License, and how to view a copy of this License.  If
128+the interface presents a list of user commands or options, such as a
129+menu, a prominent item in the list meets this criterion.
130+
131+  1. Source Code.
132+
133+  The "source code" for a work means the preferred form of the work
134+for making modifications to it.  "Object code" means any non-source
135+form of a work.
136+
137+  A "Standard Interface" means an interface that either is an official
138+standard defined by a recognized standards body, or, in the case of
139+interfaces specified for a particular programming language, one that
140+is widely used among developers working in that language.
141+
142+  The "System Libraries" of an executable work include anything, other
143+than the work as a whole, that (a) is included in the normal form of
144+packaging a Major Component, but which is not part of that Major
145+Component, and (b) serves only to enable use of the work with that
146+Major Component, or to implement a Standard Interface for which an
147+implementation is available to the public in source code form.  A
148+"Major Component", in this context, means a major essential component
149+(kernel, window system, and so on) of the specific operating system
150+(if any) on which the executable work runs, or a compiler used to
151+produce the work, or an object code interpreter used to run it.
152+
153+  The "Corresponding Source" for a work in object code form means all
154+the source code needed to generate, install, and (for an executable
155+work) run the object code and to modify the work, including scripts to
156+control those activities.  However, it does not include the work's
157+System Libraries, or general-purpose tools or generally available free
158+programs which are used unmodified in performing those activities but
159+which are not part of the work.  For example, Corresponding Source
160+includes interface definition files associated with source files for
161+the work, and the source code for shared libraries and dynamically
162+linked subprograms that the work is specifically designed to require,
163+such as by intimate data communication or control flow between those
164+subprograms and other parts of the work.
165+
166+  The Corresponding Source need not include anything that users
167+can regenerate automatically from other parts of the Corresponding
168+Source.
169+
170+  The Corresponding Source for a work in source code form is that
171+same work.
172+
173+  2. Basic Permissions.
174+
175+  All rights granted under this License are granted for the term of
176+copyright on the Program, and are irrevocable provided the stated
177+conditions are met.  This License explicitly affirms your unlimited
178+permission to run the unmodified Program.  The output from running a
179+covered work is covered by this License only if the output, given its
180+content, constitutes a covered work.  This License acknowledges your
181+rights of fair use or other equivalent, as provided by copyright law.
182+
183+  You may make, run and propagate covered works that you do not
184+convey, without conditions so long as your license otherwise remains
185+in force.  You may convey covered works to others for the sole purpose
186+of having them make modifications exclusively for you, or provide you
187+with facilities for running those works, provided that you comply with
188+the terms of this License in conveying all material for which you do
189+not control copyright.  Those thus making or running the covered works
190+for you must do so exclusively on your behalf, under your direction
191+and control, on terms that prohibit them from making any copies of
192+your copyrighted material outside their relationship with you.
193+
194+  Conveying under any other circumstances is permitted solely under
195+the conditions stated below.  Sublicensing is not allowed; section 10
196+makes it unnecessary.
197+
198+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
199+
200+  No covered work shall be deemed part of an effective technological
201+measure under any applicable law fulfilling obligations under article
202+11 of the WIPO copyright treaty adopted on 20 December 1996, or
203+similar laws prohibiting or restricting circumvention of such
204+measures.
205+
206+  When you convey a covered work, you waive any legal power to forbid
207+circumvention of technological measures to the extent such circumvention
208+is effected by exercising rights under this License with respect to
209+the covered work, and you disclaim any intention to limit operation or
210+modification of the work as a means of enforcing, against the work's
211+users, your or third parties' legal rights to forbid circumvention of
212+technological measures.
213+
214+  4. Conveying Verbatim Copies.
215+
216+  You may convey verbatim copies of the Program's source code as you
217+receive it, in any medium, provided that you conspicuously and
218+appropriately publish on each copy an appropriate copyright notice;
219+keep intact all notices stating that this License and any
220+non-permissive terms added in accord with section 7 apply to the code;
221+keep intact all notices of the absence of any warranty; and give all
222+recipients a copy of this License along with the Program.
223+
224+  You may charge any price or no price for each copy that you convey,
225+and you may offer support or warranty protection for a fee.
226+
227+  5. Conveying Modified Source Versions.
228+
229+  You may convey a work based on the Program, or the modifications to
230+produce it from the Program, in the form of source code under the
231+terms of section 4, provided that you also meet all of these conditions:
232+
233+    a) The work must carry prominent notices stating that you modified
234+    it, and giving a relevant date.
235+
236+    b) The work must carry prominent notices stating that it is
237+    released under this License and any conditions added under section
238+    7.  This requirement modifies the requirement in section 4 to
239+    "keep intact all notices".
240+
241+    c) You must license the entire work, as a whole, under this
242+    License to anyone who comes into possession of a copy.  This
243+    License will therefore apply, along with any applicable section 7
244+    additional terms, to the whole of the work, and all its parts,
245+    regardless of how they are packaged.  This License gives no
246+    permission to license the work in any other way, but it does not
247+    invalidate such permission if you have separately received it.
248+
249+    d) If the work has interactive user interfaces, each must display
250+    Appropriate Legal Notices; however, if the Program has interactive
251+    interfaces that do not display Appropriate Legal Notices, your
252+    work need not make them do so.
253+
254+  A compilation of a covered work with other separate and independent
255+works, which are not by their nature extensions of the covered work,
256+and which are not combined with it such as to form a larger program,
257+in or on a volume of a storage or distribution medium, is called an
258+"aggregate" if the compilation and its resulting copyright are not
259+used to limit the access or legal rights of the compilation's users
260+beyond what the individual works permit.  Inclusion of a covered work
261+in an aggregate does not cause this License to apply to the other
262+parts of the aggregate.
263+
264+  6. Conveying Non-Source Forms.
265+
266+  You may convey a covered work in object code form under the terms
267+of sections 4 and 5, provided that you also convey the
268+machine-readable Corresponding Source under the terms of this License,
269+in one of these ways:
270+
271+    a) Convey the object code in, or embodied in, a physical product
272+    (including a physical distribution medium), accompanied by the
273+    Corresponding Source fixed on a durable physical medium
274+    customarily used for software interchange.
275+
276+    b) Convey the object code in, or embodied in, a physical product
277+    (including a physical distribution medium), accompanied by a
278+    written offer, valid for at least three years and valid for as
279+    long as you offer spare parts or customer support for that product
280+    model, to give anyone who possesses the object code either (1) a
281+    copy of the Corresponding Source for all the software in the
282+    product that is covered by this License, on a durable physical
283+    medium customarily used for software interchange, for a price no
284+    more than your reasonable cost of physically performing this
285+    conveying of source, or (2) access to copy the
286+    Corresponding Source from a network server at no charge.
287+
288+    c) Convey individual copies of the object code with a copy of the
289+    written offer to provide the Corresponding Source.  This
290+    alternative is allowed only occasionally and noncommercially, and
291+    only if you received the object code with such an offer, in accord
292+    with subsection 6b.
293+
294+    d) Convey the object code by offering access from a designated
295+    place (gratis or for a charge), and offer equivalent access to the
296+    Corresponding Source in the same way through the same place at no
297+    further charge.  You need not require recipients to copy the
298+    Corresponding Source along with the object code.  If the place to
299+    copy the object code is a network server, the Corresponding Source
300+    may be on a different server (operated by you or a third party)
301+    that supports equivalent copying facilities, provided you maintain
302+    clear directions next to the object code saying where to find the
303+    Corresponding Source.  Regardless of what server hosts the
304+    Corresponding Source, you remain obligated to ensure that it is
305+    available for as long as needed to satisfy these requirements.
306+
307+    e) Convey the object code using peer-to-peer transmission, provided
308+    you inform other peers where the object code and Corresponding
309+    Source of the work are being offered to the general public at no
310+    charge under subsection 6d.
311+
312+  A separable portion of the object code, whose source code is excluded
313+from the Corresponding Source as a System Library, need not be
314+included in conveying the object code work.
315+
316+  A "User Product" is either (1) a "consumer product", which means any
317+tangible personal property which is normally used for personal, family,
318+or household purposes, or (2) anything designed or sold for incorporation
319+into a dwelling.  In determining whether a product is a consumer product,
320+doubtful cases shall be resolved in favor of coverage.  For a particular
321+product received by a particular user, "normally used" refers to a
322+typical or common use of that class of product, regardless of the status
323+of the particular user or of the way in which the particular user
324+actually uses, or expects or is expected to use, the product.  A product
325+is a consumer product regardless of whether the product has substantial
326+commercial, industrial or non-consumer uses, unless such uses represent
327+the only significant mode of use of the product.
328+
329+  "Installation Information" for a User Product means any methods,
330+procedures, authorization keys, or other information required to install
331+and execute modified versions of a covered work in that User Product from
332+a modified version of its Corresponding Source.  The information must
333+suffice to ensure that the continued functioning of the modified object
334+code is in no case prevented or interfered with solely because
335+modification has been made.
336+
337+  If you convey an object code work under this section in, or with, or
338+specifically for use in, a User Product, and the conveying occurs as
339+part of a transaction in which the right of possession and use of the
340+User Product is transferred to the recipient in perpetuity or for a
341+fixed term (regardless of how the transaction is characterized), the
342+Corresponding Source conveyed under this section must be accompanied
343+by the Installation Information.  But this requirement does not apply
344+if neither you nor any third party retains the ability to install
345+modified object code on the User Product (for example, the work has
346+been installed in ROM).
347+
348+  The requirement to provide Installation Information does not include a
349+requirement to continue to provide support service, warranty, or updates
350+for a work that has been modified or installed by the recipient, or for
351+the User Product in which it has been modified or installed.  Access to a
352+network may be denied when the modification itself materially and
353+adversely affects the operation of the network or violates the rules and
354+protocols for communication across the network.
355+
356+  Corresponding Source conveyed, and Installation Information provided,
357+in accord with this section must be in a format that is publicly
358+documented (and with an implementation available to the public in
359+source code form), and must require no special password or key for
360+unpacking, reading or copying.
361+
362+  7. Additional Terms.
363+
364+  "Additional permissions" are terms that supplement the terms of this
365+License by making exceptions from one or more of its conditions.
366+Additional permissions that are applicable to the entire Program shall
367+be treated as though they were included in this License, to the extent
368+that they are valid under applicable law.  If additional permissions
369+apply only to part of the Program, that part may be used separately
370+under those permissions, but the entire Program remains governed by
371+this License without regard to the additional permissions.
372+
373+  When you convey a copy of a covered work, you may at your option
374+remove any additional permissions from that copy, or from any part of
375+it.  (Additional permissions may be written to require their own
376+removal in certain cases when you modify the work.)  You may place
377+additional permissions on material, added by you to a covered work,
378+for which you have or can give appropriate copyright permission.
379+
380+  Notwithstanding any other provision of this License, for material you
381+add to a covered work, you may (if authorized by the copyright holders of
382+that material) supplement the terms of this License with terms:
383+
384+    a) Disclaiming warranty or limiting liability differently from the
385+    terms of sections 15 and 16 of this License; or
386+
387+    b) Requiring preservation of specified reasonable legal notices or
388+    author attributions in that material or in the Appropriate Legal
389+    Notices displayed by works containing it; or
390+
391+    c) Prohibiting misrepresentation of the origin of that material, or
392+    requiring that modified versions of such material be marked in
393+    reasonable ways as different from the original version; or
394+
395+    d) Limiting the use for publicity purposes of names of licensors or
396+    authors of the material; or
397+
398+    e) Declining to grant rights under trademark law for use of some
399+    trade names, trademarks, or service marks; or
400+
401+    f) Requiring indemnification of licensors and authors of that
402+    material by anyone who conveys the material (or modified versions of
403+    it) with contractual assumptions of liability to the recipient, for
404+    any liability that these contractual assumptions directly impose on
405+    those licensors and authors.
406+
407+  All other non-permissive additional terms are considered "further
408+restrictions" within the meaning of section 10.  If the Program as you
409+received it, or any part of it, contains a notice stating that it is
410+governed by this License along with a term that is a further
411+restriction, you may remove that term.  If a license document contains
412+a further restriction but permits relicensing or conveying under this
413+License, you may add to a covered work material governed by the terms
414+of that license document, provided that the further restriction does
415+not survive such relicensing or conveying.
416+
417+  If you add terms to a covered work in accord with this section, you
418+must place, in the relevant source files, a statement of the
419+additional terms that apply to those files, or a notice indicating
420+where to find the applicable terms.
421+
422+  Additional terms, permissive or non-permissive, may be stated in the
423+form of a separately written license, or stated as exceptions;
424+the above requirements apply either way.
425+
426+  8. Termination.
427+
428+  You may not propagate or modify a covered work except as expressly
429+provided under this License.  Any attempt otherwise to propagate or
430+modify it is void, and will automatically terminate your rights under
431+this License (including any patent licenses granted under the third
432+paragraph of section 11).
433+
434+  However, if you cease all violation of this License, then your
435+license from a particular copyright holder is reinstated (a)
436+provisionally, unless and until the copyright holder explicitly and
437+finally terminates your license, and (b) permanently, if the copyright
438+holder fails to notify you of the violation by some reasonable means
439+prior to 60 days after the cessation.
440+
441+  Moreover, your license from a particular copyright holder is
442+reinstated permanently if the copyright holder notifies you of the
443+violation by some reasonable means, this is the first time you have
444+received notice of violation of this License (for any work) from that
445+copyright holder, and you cure the violation prior to 30 days after
446+your receipt of the notice.
447+
448+  Termination of your rights under this section does not terminate the
449+licenses of parties who have received copies or rights from you under
450+this License.  If your rights have been terminated and not permanently
451+reinstated, you do not qualify to receive new licenses for the same
452+material under section 10.
453+
454+  9. Acceptance Not Required for Having Copies.
455+
456+  You are not required to accept this License in order to receive or
457+run a copy of the Program.  Ancillary propagation of a covered work
458+occurring solely as a consequence of using peer-to-peer transmission
459+to receive a copy likewise does not require acceptance.  However,
460+nothing other than this License grants you permission to propagate or
461+modify any covered work.  These actions infringe copyright if you do
462+not accept this License.  Therefore, by modifying or propagating a
463+covered work, you indicate your acceptance of this License to do so.
464+
465+  10. Automatic Licensing of Downstream Recipients.
466+
467+  Each time you convey a covered work, the recipient automatically
468+receives a license from the original licensors, to run, modify and
469+propagate that work, subject to this License.  You are not responsible
470+for enforcing compliance by third parties with this License.
471+
472+  An "entity transaction" is a transaction transferring control of an
473+organization, or substantially all assets of one, or subdividing an
474+organization, or merging organizations.  If propagation of a covered
475+work results from an entity transaction, each party to that
476+transaction who receives a copy of the work also receives whatever
477+licenses to the work the party's predecessor in interest had or could
478+give under the previous paragraph, plus a right to possession of the
479+Corresponding Source of the work from the predecessor in interest, if
480+the predecessor has it or can get it with reasonable efforts.
481+
482+  You may not impose any further restrictions on the exercise of the
483+rights granted or affirmed under this License.  For example, you may
484+not impose a license fee, royalty, or other charge for exercise of
485+rights granted under this License, and you may not initiate litigation
486+(including a cross-claim or counterclaim in a lawsuit) alleging that
487+any patent claim is infringed by making, using, selling, offering for
488+sale, or importing the Program or any portion of it.
489+
490+  11. Patents.
491+
492+  A "contributor" is a copyright holder who authorizes use under this
493+License of the Program or a work on which the Program is based.  The
494+work thus licensed is called the contributor's "contributor version".
495+
496+  A contributor's "essential patent claims" are all patent claims
497+owned or controlled by the contributor, whether already acquired or
498+hereafter acquired, that would be infringed by some manner, permitted
499+by this License, of making, using, or selling its contributor version,
500+but do not include claims that would be infringed only as a
501+consequence of further modification of the contributor version.  For
502+purposes of this definition, "control" includes the right to grant
503+patent sublicenses in a manner consistent with the requirements of
504+this License.
505+
506+  Each contributor grants you a non-exclusive, worldwide, royalty-free
507+patent license under the contributor's essential patent claims, to
508+make, use, sell, offer for sale, import and otherwise run, modify and
509+propagate the contents of its contributor version.
510+
511+  In the following three paragraphs, a "patent license" is any express
512+agreement or commitment, however denominated, not to enforce a patent
513+(such as an express permission to practice a patent or covenant not to
514+sue for patent infringement).  To "grant" such a patent license to a
515+party means to make such an agreement or commitment not to enforce a
516+patent against the party.
517+
518+  If you convey a covered work, knowingly relying on a patent license,
519+and the Corresponding Source of the work is not available for anyone
520+to copy, free of charge and under the terms of this License, through a
521+publicly available network server or other readily accessible means,
522+then you must either (1) cause the Corresponding Source to be so
523+available, or (2) arrange to deprive yourself of the benefit of the
524+patent license for this particular work, or (3) arrange, in a manner
525+consistent with the requirements of this License, to extend the patent
526+license to downstream recipients.  "Knowingly relying" means you have
527+actual knowledge that, but for the patent license, your conveying the
528+covered work in a country, or your recipient's use of the covered work
529+in a country, would infringe one or more identifiable patents in that
530+country that you have reason to believe are valid.
531+
532+  If, pursuant to or in connection with a single transaction or
533+arrangement, you convey, or propagate by procuring conveyance of, a
534+covered work, and grant a patent license to some of the parties
535+receiving the covered work authorizing them to use, propagate, modify
536+or convey a specific copy of the covered work, then the patent license
537+you grant is automatically extended to all recipients of the covered
538+work and works based on it.
539+
540+  A patent license is "discriminatory" if it does not include within
541+the scope of its coverage, prohibits the exercise of, or is
542+conditioned on the non-exercise of one or more of the rights that are
543+specifically granted under this License.  You may not convey a covered
544+work if you are a party to an arrangement with a third party that is
545+in the business of distributing software, under which you make payment
546+to the third party based on the extent of your activity of conveying
547+the work, and under which the third party grants, to any of the
548+parties who would receive the covered work from you, a discriminatory
549+patent license (a) in connection with copies of the covered work
550+conveyed by you (or copies made from those copies), or (b) primarily
551+for and in connection with specific products or compilations that
552+contain the covered work, unless you entered into that arrangement,
553+or that patent license was granted, prior to 28 March 2007.
554+
555+  Nothing in this License shall be construed as excluding or limiting
556+any implied license or other defenses to infringement that may
557+otherwise be available to you under applicable patent law.
558+
559+  12. No Surrender of Others' Freedom.
560+
561+  If conditions are imposed on you (whether by court order, agreement or
562+otherwise) that contradict the conditions of this License, they do not
563+excuse you from the conditions of this License.  If you cannot convey a
564+covered work so as to satisfy simultaneously your obligations under this
565+License and any other pertinent obligations, then as a consequence you may
566+not convey it at all.  For example, if you agree to terms that obligate you
567+to collect a royalty for further conveying from those to whom you convey
568+the Program, the only way you could satisfy both those terms and this
569+License would be to refrain entirely from conveying the Program.
570+
571+  13. Use with the GNU Affero General Public License.
572+
573+  Notwithstanding any other provision of this License, you have
574+permission to link or combine any covered work with a work licensed
575+under version 3 of the GNU Affero General Public License into a single
576+combined work, and to convey the resulting work.  The terms of this
577+License will continue to apply to the part which is the covered work,
578+but the special requirements of the GNU Affero General Public License,
579+section 13, concerning interaction through a network will apply to the
580+combination as such.
581+
582+  14. Revised Versions of this License.
583+
584+  The Free Software Foundation may publish revised and/or new versions of
585+the GNU General Public License from time to time.  Such new versions will
586+be similar in spirit to the present version, but may differ in detail to
587+address new problems or concerns.
588+
589+  Each version is given a distinguishing version number.  If the
590+Program specifies that a certain numbered version of the GNU General
591+Public License "or any later version" applies to it, you have the
592+option of following the terms and conditions either of that numbered
593+version or of any later version published by the Free Software
594+Foundation.  If the Program does not specify a version number of the
595+GNU General Public License, you may choose any version ever published
596+by the Free Software Foundation.
597+
598+  If the Program specifies that a proxy can decide which future
599+versions of the GNU General Public License can be used, that proxy's
600+public statement of acceptance of a version permanently authorizes you
601+to choose that version for the Program.
602+
603+  Later license versions may give you additional or different
604+permissions.  However, no additional obligations are imposed on any
605+author or copyright holder as a result of your choosing to follow a
606+later version.
607+
608+  15. Disclaimer of Warranty.
609+
610+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
611+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
612+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
613+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
614+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
615+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
616+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
617+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
618+
619+  16. Limitation of Liability.
620+
621+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
622+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
623+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
624+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
625+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
626+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
627+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
628+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
629+SUCH DAMAGES.
630+
631+  17. Interpretation of Sections 15 and 16.
632+
633+  If the disclaimer of warranty and limitation of liability provided
634+above cannot be given local legal effect according to their terms,
635+reviewing courts shall apply local law that most closely approximates
636+an absolute waiver of all civil liability in connection with the
637+Program, unless a warranty or assumption of liability accompanies a
638+copy of the Program in return for a fee.
639+
640+                     END OF TERMS AND CONDITIONS
641+
642+            How to Apply These Terms to Your New Programs
643+
644+  If you develop a new program, and you want it to be of the greatest
645+possible use to the public, the best way to achieve this is to make it
646+free software which everyone can redistribute and change under these terms.
647+
648+  To do so, attach the following notices to the program.  It is safest
649+to attach them to the start of each source file to most effectively
650+state the exclusion of warranty; and each file should have at least
651+the "copyright" line and a pointer to where the full notice is found.
652+
653+    <one line to give the program's name and a brief idea of what it does.>
654+    Copyright (C) <year>  <name of author>
655+
656+    This program is free software: you can redistribute it and/or modify
657+    it under the terms of the GNU General Public License as published by
658+    the Free Software Foundation, either version 3 of the License, or
659+    (at your option) any later version.
660+
661+    This program is distributed in the hope that it will be useful,
662+    but WITHOUT ANY WARRANTY; without even the implied warranty of
663+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
664+    GNU General Public License for more details.
665+
666+    You should have received a copy of the GNU General Public License
667+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
668+
669+Also add information on how to contact you by electronic and paper mail.
670+
671+  If the program does terminal interaction, make it output a short
672+notice like this when it starts in an interactive mode:
673+
674+    <program>  Copyright (C) <year>  <name of author>
675+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
676+    This is free software, and you are welcome to redistribute it
677+    under certain conditions; type `show c' for details.
678+
679+The hypothetical commands `show w' and `show c' should show the appropriate
680+parts of the General Public License.  Of course, your program's commands
681+might be different; for a GUI interface, you would use an "about box".
682+
683+  You should also get your employer (if you work as a programmer) or school,
684+if any, to sign a "copyright disclaimer" for the program, if necessary.
685+For more information on this, and how to apply and follow the GNU GPL, see
686+<https://www.gnu.org/licenses/>.
687+
688+  The GNU General Public License does not permit incorporating your program
689+into proprietary programs.  If your program is a subroutine library, you
690+may consider it more useful to permit linking proprietary applications with
691+the library.  If this is what you want to do, use the GNU Lesser General
692+Public License instead of this License.  But first, please read
693+<https://www.gnu.org/licenses/why-not-lgpl.html>.
+39, -0
 1@@ -0,0 +1,39 @@
 2+Portions of dwl based on dwm code are used under the following license:
 3+
 4+MIT/X Consortium License
 5+
 6+© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
 7+© 2006-2009 Jukka Salmi <jukka at salmi dot ch>
 8+© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
 9+© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com>
10+© 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com>
11+© 2007-2009 Christof Musik <christof at sendfax dot de>
12+© 2007-2009 Premysl Hruby <dfenze at gmail dot com>
13+© 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
14+© 2008 Martin Hurton <martin dot hurton at gmail dot com>
15+© 2008 Neale Pickett <neale dot woozle dot org>
16+© 2009 Mate Nagy <mnagy at port70 dot net>
17+© 2010-2016 Hiltjo Posthuma <hiltjo@codemadness.org>
18+© 2010-2012 Connor Lane Smith <cls@lubutu.com>
19+© 2011 Christoph Lohmann <20h@r-36.net>
20+© 2015-2016 Quentin Rameau <quinq@fifth.space>
21+© 2015-2016 Eric Pruitt <eric.pruitt@gmail.com>
22+© 2016-2017 Markus Teich <markus.teich@stusta.mhn.de>
23+
24+Permission is hereby granted, free of charge, to any person obtaining a
25+copy of this software and associated documentation files (the "Software"),
26+to deal in the Software without restriction, including without limitation
27+the rights to use, copy, modify, merge, publish, distribute, sublicense,
28+and/or sell copies of the Software, and to permit persons to whom the
29+Software is furnished to do so, subject to the following conditions:
30+
31+The above copyright notice and this permission notice shall be included in
32+all copies or substantial portions of the Software.
33+
34+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
37+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
39+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
40+DEALINGS IN THE SOFTWARE.
+19, -0
 1@@ -0,0 +1,19 @@
 2+Copyright (c) 2016-2017 Drew DeVault
 3+
 4+Permission is hereby granted, free of charge, to any person obtaining a copy of
 5+this software and associated documentation files (the "Software"), to deal in
 6+the Software without restriction, including without limitation the rights to
 7+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 8+of the Software, and to permit persons to whom the Software is furnished to do
 9+so, subject to the following conditions:
10+
11+The above copyright notice and this permission notice shall be included in all
12+copies or substantial portions of the Software.
13+
14+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+SOFTWARE.
+127, -0
  1@@ -0,0 +1,127 @@
  2+dwl is originally based on TinyWL, which is used under the following license:
  3+
  4+This work is licensed under CC0, which effectively puts it in the public domain.
  5+
  6+---
  7+
  8+Creative Commons Legal Code
  9+
 10+CC0 1.0 Universal
 11+
 12+    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
 13+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
 14+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
 15+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
 16+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
 17+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
 18+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
 19+    HEREUNDER.
 20+
 21+Statement of Purpose
 22+
 23+The laws of most jurisdictions throughout the world automatically confer
 24+exclusive Copyright and Related Rights (defined below) upon the creator
 25+and subsequent owner(s) (each and all, an "owner") of an original work of
 26+authorship and/or a database (each, a "Work").
 27+
 28+Certain owners wish to permanently relinquish those rights to a Work for
 29+the purpose of contributing to a commons of creative, cultural and
 30+scientific works ("Commons") that the public can reliably and without fear
 31+of later claims of infringement build upon, modify, incorporate in other
 32+works, reuse and redistribute as freely as possible in any form whatsoever
 33+and for any purposes, including without limitation commercial purposes.
 34+These owners may contribute to the Commons to promote the ideal of a free
 35+culture and the further production of creative, cultural and scientific
 36+works, or to gain reputation or greater distribution for their Work in
 37+part through the use and efforts of others.
 38+
 39+For these and/or other purposes and motivations, and without any
 40+expectation of additional consideration or compensation, the person
 41+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
 42+is an owner of Copyright and Related Rights in the Work, voluntarily
 43+elects to apply CC0 to the Work and publicly distribute the Work under its
 44+terms, with knowledge of his or her Copyright and Related Rights in the
 45+Work and the meaning and intended legal effect of CC0 on those rights.
 46+
 47+1. Copyright and Related Rights. A Work made available under CC0 may be
 48+protected by copyright and related or neighboring rights ("Copyright and
 49+Related Rights"). Copyright and Related Rights include, but are not
 50+limited to, the following:
 51+
 52+  i. the right to reproduce, adapt, distribute, perform, display,
 53+     communicate, and translate a Work;
 54+ ii. moral rights retained by the original author(s) and/or performer(s);
 55+iii. publicity and privacy rights pertaining to a person's image or
 56+     likeness depicted in a Work;
 57+ iv. rights protecting against unfair competition in regards to a Work,
 58+     subject to the limitations in paragraph 4(a), below;
 59+  v. rights protecting the extraction, dissemination, use and reuse of data
 60+     in a Work;
 61+ vi. database rights (such as those arising under Directive 96/9/EC of the
 62+     European Parliament and of the Council of 11 March 1996 on the legal
 63+     protection of databases, and under any national implementation
 64+     thereof, including any amended or successor version of such
 65+     directive); and
 66+vii. other similar, equivalent or corresponding rights throughout the
 67+     world based on applicable law or treaty, and any national
 68+     implementations thereof.
 69+
 70+2. Waiver. To the greatest extent permitted by, but not in contravention
 71+of, applicable law, Affirmer hereby overtly, fully, permanently,
 72+irrevocably and unconditionally waives, abandons, and surrenders all of
 73+Affirmer's Copyright and Related Rights and associated claims and causes
 74+of action, whether now known or unknown (including existing as well as
 75+future claims and causes of action), in the Work (i) in all territories
 76+worldwide, (ii) for the maximum duration provided by applicable law or
 77+treaty (including future time extensions), (iii) in any current or future
 78+medium and for any number of copies, and (iv) for any purpose whatsoever,
 79+including without limitation commercial, advertising or promotional
 80+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
 81+member of the public at large and to the detriment of Affirmer's heirs and
 82+successors, fully intending that such Waiver shall not be subject to
 83+revocation, rescission, cancellation, termination, or any other legal or
 84+equitable action to disrupt the quiet enjoyment of the Work by the public
 85+as contemplated by Affirmer's express Statement of Purpose.
 86+
 87+3. Public License Fallback. Should any part of the Waiver for any reason
 88+be judged legally invalid or ineffective under applicable law, then the
 89+Waiver shall be preserved to the maximum extent permitted taking into
 90+account Affirmer's express Statement of Purpose. In addition, to the
 91+extent the Waiver is so judged Affirmer hereby grants to each affected
 92+person a royalty-free, non transferable, non sublicensable, non exclusive,
 93+irrevocable and unconditional license to exercise Affirmer's Copyright and
 94+Related Rights in the Work (i) in all territories worldwide, (ii) for the
 95+maximum duration provided by applicable law or treaty (including future
 96+time extensions), (iii) in any current or future medium and for any number
 97+of copies, and (iv) for any purpose whatsoever, including without
 98+limitation commercial, advertising or promotional purposes (the
 99+"License"). The License shall be deemed effective as of the date CC0 was
100+applied by Affirmer to the Work. Should any part of the License for any
101+reason be judged legally invalid or ineffective under applicable law, such
102+partial invalidity or ineffectiveness shall not invalidate the remainder
103+of the License, and in such case Affirmer hereby affirms that he or she
104+will not (i) exercise any of his or her remaining Copyright and Related
105+Rights in the Work or (ii) assert any associated claims and causes of
106+action with respect to the Work, in either case contrary to Affirmer's
107+express Statement of Purpose.
108+
109+4. Limitations and Disclaimers.
110+
111+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
112+    surrendered, licensed or otherwise affected by this document.
113+ b. Affirmer offers the Work as-is and makes no representations or
114+    warranties of any kind concerning the Work, express, implied,
115+    statutory or otherwise, including without limitation warranties of
116+    title, merchantability, fitness for a particular purpose, non
117+    infringement, or the absence of latent or other defects, accuracy, or
118+    the present or absence of errors, whether or not discoverable, all to
119+    the greatest extent permissible under applicable law.
120+ c. Affirmer disclaims responsibility for clearing rights of other persons
121+    that may apply to the Work or any use thereof, including without
122+    limitation any person's Copyright and Related Rights in the Work.
123+    Further, Affirmer disclaims responsibility for obtaining any necessary
124+    consents, permissions or other rights required for any use of the
125+    Work.
126+ d. Affirmer understands and acknowledges that Creative Commons is not a
127+    party to this document and has no duty or obligation with respect to
128+    this CC0 or use of the Work.
+89, -0
 1@@ -0,0 +1,89 @@
 2+.POSIX:
 3+.SUFFIXES:
 4+
 5+include config.mk
 6+include modules.mk
 7+
 8+VPATH = src
 9+
10+# flags for compiling
11+LEELOOCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L \
12+	-DVERSION=\"$(VERSION)\" $(XWAYLAND)
13+LEELOODEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \
14+	-Wno-unused-parameter -Wshadow -Wunused-macros -Werror=strict-prototypes \
15+	-Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types \
16+	-Wfloat-conversion
17+
18+# CFLAGS / LDFLAGS
19+PKGS      = wayland-server xkbcommon libinput $(XLIBS)
20+LEELOOCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(LEELOOMODULES) $(LEELOOCPPFLAGS) $(LEELOODEVCFLAGS) $(CFLAGS)
21+LDLIBS    = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)
22+
23+all: leeloo
24+leeloo: leeloo.o util.o
25+	$(CC) leeloo.o util.o $(LEELOOCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
26+leeloo.o: leeloo.c client.h config.h config.mk cursor-shape-v1-protocol.h \
27+	pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
28+	wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h \
29+	tablet-v2-protocol.h
30+util.o: util.c util.h
31+
32+# wayland-scanner is a tool which generates C headers and rigging for Wayland
33+# protocols, which are specified in XML. wlroots requires you to rig these up
34+# to your build system yourself and provide them in the include path.
35+WAYLAND_SCANNER   = `$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner`
36+WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols`
37+
38+cursor-shape-v1-protocol.h:
39+	$(WAYLAND_SCANNER) enum-header \
40+		$(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@
41+pointer-constraints-unstable-v1-protocol.h:
42+	$(WAYLAND_SCANNER) enum-header \
43+		$(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@
44+wlr-layer-shell-unstable-v1-protocol.h:
45+	$(WAYLAND_SCANNER) enum-header \
46+		protocols/wlr-layer-shell-unstable-v1.xml $@
47+wlr-output-power-management-unstable-v1-protocol.h:
48+	$(WAYLAND_SCANNER) server-header \
49+		protocols/wlr-output-power-management-unstable-v1.xml $@
50+xdg-shell-protocol.h:
51+	$(WAYLAND_SCANNER) server-header \
52+		$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
53+# tablet-input
54+tablet-v2-protocol.h:
55+	$(WAYLAND_SCANNER) server-header \
56+		$(WAYLAND_PROTOCOLS)/unstable/tablet/tablet-unstable-v2.xml $@
57+# tablet-input end
58+config.h:
59+	cp config.def.h $@
60+clean:
61+	rm -f leeloo *.o *-protocol.h leeloo-*.tar.gz
62+
63+dist: clean
64+	mkdir -p leeloo-$(VERSION)
65+	mkdir -p leeloo-$(VERSION)/src
66+	cp -R LICENSE* Makefile config.def.h \
67+		config.mk modules.mk protocols leeloo.desktop \
68+		leeloo-$(VERSION)
69+	cp -R src/leeloo.c src/client.h src/util.c src/util.h leeloo-$(VERSION)/src/
70+	tar -caf leeloo-$(VERSION).tar.gz leeloo-$(VERSION)
71+
72+	rm -rf leeloo-$(VERSION)
73+
74+install: leeloo
75+
76+	mkdir -p $(DESTDIR)$(PREFIX)/bin
77+	rm -f $(DESTDIR)$(PREFIX)/bin/leeloo
78+	cp -f leeloo $(DESTDIR)$(PREFIX)/bin
79+	chmod 755 $(DESTDIR)$(PREFIX)/bin/leeloo
80+	mkdir -p $(DESTDIR)$(MANDIR)/man1
81+	mkdir -p $(DESTDIR)$(DATADIR)/wayland-sessions
82+	cp -f leeloo.desktop $(DESTDIR)$(DATADIR)/wayland-sessions/leeloo.desktop
83+	chmod 644 $(DESTDIR)$(DATADIR)/wayland-sessions/leeloo.desktop
84+uninstall:
85+	rm -f $(DESTDIR)$(PREFIX)/bin/leeloo \
86+		$(DESTDIR)$(DATADIR)/wayland-sessions/leeloo.desktop
87+
88+.SUFFIXES: .c .o
89+.c.o:
90+	$(CC) $(CPPFLAGS) $(LEELOOCFLAGS) -o $@ -c $<
+6, -0
 1@@ -1,3 +1,9 @@
 2 # leeloo
 3 leeloo by wh1tepearl and ohmu(me)
 4 
 5+thanks tsukasa for archive
 6+
 7+THIS IS REUPLOAD BY OFFICIAL MAINTAINER
 8+
 9+For everything see manual
10+
+284, -0
  1@@ -0,0 +1,284 @@
  2+/* Taken from https://github.com/djpohly/dwl/issues/466 */
  3+#define COLOR(hex)    { ((hex >> 24) & 0xFF) / 255.0f, \
  4+                        ((hex >> 16) & 0xFF) / 255.0f, \
  5+                        ((hex >> 8) & 0xFF) / 255.0f, \
  6+                        (hex & 0xFF) / 255.0f }
  7+/* appearance */
  8+static const int tabletmaptosurface                = 1;  /* map tablet input to surface(1) or monitor(0) */
  9+static const int sloppyfocus                       = 1;  /* focus follows mouse */
 10+static const int bypass_surface_visibility         = 0;  /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible  */
 11+
 12+#define ZOOMMIN 0.05
 13+#define ZOOMMAX 3
 14+#define animatezoom 1
 15+#define zoomduration 0.33
 16+#define zoombezier "0.22,1.0,0.36,1.0"
 17+#define movecanvasmouse_multiplier_is_affected_by_zoom 1
 18+#define ZOOM_IN_TOWARDS_CURSOR 1
 19+#define ZOOM_OUT_TOWARDS_CURSOR 0
 20+
 21+#define SPAWNREGION_STYLE 2 /* 0 = None
 22+                               1 = Full rectangle.
 23+                               2 = outline
 24+                            */
 25+
 26+/* gaps */
 27+static const int enablegaps                        = 1;  /* 1 means gaps are enabled */
 28+static const int smartgaps                         = 0;  /* 1 means no outer gap when there is only one window */
 29+static const int monoclegaps                       = 0;  /* 1 means outer gaps in monocle layout */
 30+static const unsigned int gappih                   = 10; /* horizontal inner gap between windows */
 31+static const unsigned int gappiv                   = 10; /* vertical inner gap between windows */
 32+static const unsigned int gappoh                   = 10; /* horizontal outer gap between windows and screen edge */
 33+static const unsigned int gappov                   = 10; /* vertical outer gap between windows and screen edge */
 34+
 35+/* colors */
 36+static const float rootcolor[]                     = COLOR(0x22222267); /* Background color, only visible without any wallpaper setter */
 37+
 38+/* inner border */
 39+static const unsigned int innerborderpx = 4;  /* inner border pixel width */
 40+
 41+static const float focused_inner_border_color[]    = COLOR(0xFDD9C6ff);
 42+static const float urgent_inner_border_color[]     = COLOR(0xFDD9C6ff);
 43+static const float unfocused_inner_border_color[]  = COLOR(0x7B565600);
 44+
 45+/* outer border */
 46+static const unsigned int outerborderpx = 6;  /* outer border pixel width */
 47+
 48+static const float focused_outer_border_color[]    = COLOR(0x0a0100ff);
 49+static const float urgent_outer_border_color[]     = COLOR(0x0a0100ff);
 50+static const float unfocused_outer_border_color[]  = COLOR(0x1e1c1c00);
 51+
 52+#define SPAWNREGION_COLOR COLOR(0xFDD9C667)
 53+
 54+static const unsigned int spawnregion_innerborderpx  = 3;  /* spawnregion inner border pixel width */
 55+static const unsigned int spawnregion_outerborderpx  = 7;  /* spawnregion outer border pixel width */
 56+static const float spawnregion_inner_border_color[]  = COLOR(0xC9B8B6ff);
 57+static const float spawnregion_outer_border_color[]  = COLOR(0x430a03ff);
 58+
 59+/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
 60+static const float fullscreen_bg[]         = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
 61+/* Pen active area: value 0.0 => 1.0         { x,    y,    width, height } */
 62+static const double tablet_area[4] 		   = { 0.4,  0.4,  0.4,   0.4 };
 63+
 64+/* tagging - TAGCOUNT must be no greater than 31 */
 65+#define TAGCOUNT (9)
 66+
 67+/* logging */
 68+static int log_level = WLR_ERROR;
 69+
 70+
 71+
 72+static const Rule rules[] = {
 73+	/* app_id             title       tags mask     isfloating   monitor */
 74+	{ "Gimp_EXAMPLE",     NULL,       0,            1,           -1 }, /* Start on currently visible tags floating, not tiled */
 75+	{ "firefox_EXAMPLE",  NULL,       1 << 8,       0,           -1 }, /* Start on ONLY tag "9" */
 76+    /* default/example rule: can be changed but cannot be eliminated; at least one rule must exist */
 77+};
 78+
 79+#define CENTER_NEW_WINDOWS 1
 80+
 81+/* layout(s) */
 82+static const Layout layouts[] = {
 83+	/* symbol     arrange function */
 84+  { "><>",      NULL },    /* no layout function means floating behavior */
 85+	{ "[]=",      tile },
 86+	{ "[M]",      monocle },
 87+};
 88+
 89+/* monitors */
 90+/* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator
 91+ * WARNING: negative values other than (-1, -1) cause problems with Xwayland clients due to
 92+ * https://gitlab.freedesktop.org/xorg/xserver/-/issues/899 */
 93+static const MonitorRule monrules[] = {
 94+   /*    name  mfact nmaster  scale  layout       rotate/reflect                x   y      resx resy         rate mode   adaptive */
 95+   /*
 96+	* mode lets the user decide how dwl should implement the modes:
 97+	* -1 sets a custom mode following the user's choice
 98+	* All other numbers set the mode at the index n; 0 is the standard mode; see wlr-randr
 99+	*/
100+  { "HDMI-A-1", 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1, 0, 0, 180.003006f, 1, 0 },
101+ 	/* default monitor rule: can be changed but cannot be eliminated; at least one monitor rule must exist */
102+};
103+
104+/* keyboard */
105+static const struct xkb_rule_names xkb_rules = {
106+	/* can specify fields: rules, model, layout, variant, options */
107+	/* example:
108+	.options = "ctrl:nocaps",
109+	*/
110+	.options = NULL,
111+};
112+
113+static const int repeat_rate = 40;
114+static const int repeat_delay = 250;
115+
116+/* Trackpad */
117+static const int tap_to_click = 1;
118+static const int tap_and_drag = 1;
119+static const int drag_lock = 1;
120+static const int natural_scrolling = 0;
121+static const int disable_while_typing = 1;
122+static const int left_handed = 0;
123+static const int middle_button_emulation = 0;
124+/* You can choose between:
125+LIBINPUT_CONFIG_SCROLL_NO_SCROLL
126+LIBINPUT_CONFIG_SCROLL_2FG
127+LIBINPUT_CONFIG_SCROLL_EDGE
128+LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN
129+*/
130+static const enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
131+
132+/* You can choose between:
133+LIBINPUT_CONFIG_CLICK_METHOD_NONE
134+LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS
135+LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER
136+*/
137+static const enum libinput_config_click_method click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
138+
139+/* You can choose between:
140+LIBINPUT_CONFIG_SEND_EVENTS_ENABLED
141+LIBINPUT_CONFIG_SEND_EVENTS_DISABLED
142+LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE
143+*/
144+static const uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
145+
146+/* You can choose between:
147+LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT
148+LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE
149+*/
150+static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
151+static const double accel_speed = -1.0;
152+
153+/* You can choose between:
154+LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle
155+LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right
156+*/
157+static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM;
158+
159+/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
160+#define MODKEY WLR_MODIFIER_LOGO
161+#define ALT_MODKEY WLR_MODIFIER_ALT
162+
163+#define TAGKEYS(KEY,SKEY,TAG) \
164+	{ MODKEY,                    KEY,            view,            {.ui = 1 << TAG} }, \
165+	{ MODKEY|WLR_MODIFIER_CTRL,  KEY,            toggleview,      {.ui = 1 << TAG} }, \
166+	{ MODKEY|WLR_MODIFIER_SHIFT, SKEY,           tag,             {.ui = 1 << TAG} }, \
167+	{ MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} }
168+
169+/* helper for spawning shell commands in the pre dwm-5.0 fashion */
170+#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
171+
172+/* commands */
173+static const char *termcmd[] = { "foot", NULL };
174+static const char *menucmd[] = { "wmenu_run", NULL };
175+
176+static const Key keys[] = {
177+	/* Note that Shift changes certain key codes: 2 -> at, etc. */
178+	/* modifier                  key                  function          argument */
179+	{ MODKEY,                    XKB_KEY_p,           spawn,            {.v = menucmd} },
180+	{ MODKEY,                    XKB_KEY_Return,      spawn,            {.v = termcmd} },
181+	{ MODKEY,                    XKB_KEY_j,           focusstack,       {.i = +1} },
182+	{ MODKEY,                    XKB_KEY_k,           focusstack,       {.i = -1} },
183+	{ MODKEY,                    XKB_KEY_i,           incnmaster,       {.i = +1} },
184+	{ MODKEY,                    XKB_KEY_d,           incnmaster,       {.i = -1} },
185+	{ MODKEY,                    XKB_KEY_h,           setmfact,         {.f = -0.05f} },
186+	{ MODKEY,                    XKB_KEY_l,           setmfact,         {.f = +0.05f} },
187+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return,      swapmaster,       {0} },
188+	{ MODKEY,                    XKB_KEY_Tab,         view,             {0} },
189+	{ MODKEY,                    XKB_KEY_c,           killclient,       {0} },
190+	{ MODKEY,                    XKB_KEY_t,           setlayout,        {.v = &layouts[1]} },
191+	{ MODKEY,                    XKB_KEY_f,           setlayout,        {.v = &layouts[0]} },
192+	{ MODKEY,                    XKB_KEY_m,           setlayout,        {.v = &layouts[2]} },
193+	{ MODKEY,                    XKB_KEY_space,       setlayout,        {0} },
194+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space,       togglefloating,   {0} },
195+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_f,           togglefullscreen, {0} },
196+	{ MODKEY,                    XKB_KEY_0,           view,             {.ui = ~0} },
197+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright,  tag,              {.ui = ~0} },
198+	{ MODKEY,                    XKB_KEY_comma,       focusmon,         {.i = WLR_DIRECTION_LEFT} },
199+	{ MODKEY,                    XKB_KEY_period,      focusmon,         {.i = WLR_DIRECTION_RIGHT} },
200+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less,        tagmon,           {.i = WLR_DIRECTION_LEFT} },
201+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater,     tagmon,           {.i = WLR_DIRECTION_RIGHT} },
202+	TAGKEYS(          XKB_KEY_1, XKB_KEY_exclam,                        0),
203+	TAGKEYS(          XKB_KEY_2, XKB_KEY_at,                            1),
204+	TAGKEYS(          XKB_KEY_3, XKB_KEY_numbersign,                    2),
205+	TAGKEYS(          XKB_KEY_4, XKB_KEY_dollar,                        3),
206+	TAGKEYS(          XKB_KEY_5, XKB_KEY_percent,                       4),
207+	TAGKEYS(          XKB_KEY_6, XKB_KEY_asciicircum,                   5),
208+	TAGKEYS(          XKB_KEY_7, XKB_KEY_ampersand,                     6),
209+	TAGKEYS(          XKB_KEY_8, XKB_KEY_asterisk,                      7),
210+	TAGKEYS(          XKB_KEY_9, XKB_KEY_parenleft,                     8),
211+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_q,           quit,             {0} },
212+
213+	/* infinite_canvas */
214+	{ MODKEY,                    XKB_KEY_r,            homecanvas,       {0} },
215+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Left,         movecanvas,       {.i = 0} },
216+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Right,        movecanvas,       {.i = 1} },
217+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Up,           movecanvas,       {.i = 2} },
218+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Down,         movecanvas,       {.i = 3} },
219+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_d,            centerwindow,     {0} },
220+	/* infinite_canvas_end */
221+	{ MODKEY|WLR_MODIFIER_LOGO,  XKB_KEY_h,          incgaps,       {.i = +1 } },
222+	{ MODKEY|WLR_MODIFIER_LOGO,  XKB_KEY_l,          incgaps,       {.i = -1 } },
223+	{ MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT,   XKB_KEY_H,      incogaps,      {.i = +1 } },
224+	{ MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT,   XKB_KEY_L,      incogaps,      {.i = -1 } },
225+	{ MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL,    XKB_KEY_h,      incigaps,      {.i = +1 } },
226+	{ MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL,    XKB_KEY_l,      incigaps,      {.i = -1 } },
227+	{ MODKEY|WLR_MODIFIER_LOGO,  XKB_KEY_0,          togglegaps,     {0} },
228+	{ MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT,   XKB_KEY_parenright,defaultgaps,    {0} },
229+	{ MODKEY,                    XKB_KEY_y,          incihgaps,     {.i = +1 } },
230+	{ MODKEY,                    XKB_KEY_o,          incihgaps,     {.i = -1 } },
231+	{ MODKEY|WLR_MODIFIER_CTRL,  XKB_KEY_y,          incivgaps,     {.i = +1 } },
232+	{ MODKEY|WLR_MODIFIER_CTRL,  XKB_KEY_o,          incivgaps,     {.i = -1 } },
233+	{ MODKEY|WLR_MODIFIER_LOGO,  XKB_KEY_y,          incohgaps,     {.i = +1 } },
234+	{ MODKEY|WLR_MODIFIER_LOGO,  XKB_KEY_o,          incohgaps,     {.i = -1 } },
235+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Y,          incovgaps,     {.i = +1 } },
236+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O,          incovgaps,     {.i = -1 } },
237+  { WLR_MODIFIER_ALT,          XKB_KEY_R,          zoomreset,     {0} },
238+  { MODKEY, XKB_KEY_equal, zoom,      {.f =  +0.1f} },
239+  { MODKEY, XKB_KEY_minus, zoom,      {.f = -0.1f} },
240+	/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
241+	{ WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} },
242+	/* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is
243+	 * do not remove them.
244+	 */
245+#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} }
246+	CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6),
247+	CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12),
248+};
249+
250+static const Button buttons[] = {
251+	{ ClkClient, MODKEY, BTN_LEFT,   moveresize,     {.ui = CurMove} },
252+  { ClkRoot, 0,BTN_MIDDLE,   spawn,     {.v = menucmd} },
253+	{ ClkClient, MODKEY, BTN_MIDDLE, togglefloating, {0} },
254+	{ ClkClient, MODKEY, BTN_RIGHT,  moveresize,     {.ui = CurResize} },
255+	/* infinite_canvas */
256+	{ ClkClient, MODKEY|WLR_MODIFIER_SHIFT, BTN_LEFT, movecanvasmouse, {.f = 2} },
257+  { ClkRoot, MODKEY|WLR_MODIFIER_SHIFT, BTN_LEFT, movecanvasmouse, {.f = 2} },
258+  { ClkRoot, 0, BTN_LEFT, movecanvasmouse, {.f = 2} },
259+	/* infinite_canvas_end */
260+  { ClkRoot, 0, BTN_RIGHT, spawn, {.v = termcmd} },
261+  { ClkClient, MODKEY, SCROLL_UP, zoom,      {.f =  +0.25} },
262+  { ClkClient, MODKEY, SCROLL_DOWN, zoom,      {.f = -0.25f} },
263+
264+  { ClkRoot, MODKEY, SCROLL_UP, zoom,      {.f =  +0.25f} },
265+  { ClkRoot, MODKEY, SCROLL_DOWN, zoom,      {.f = -0.25f} },
266+
267+  { ClkRoot, 0, SCROLL_UP, zoom,      {.f =  +0.25f} },
268+  { ClkRoot, 0, SCROLL_DOWN, zoom,      {.f = -0.25f} },
269+};
270+
271+static const TabletButton tabletbuttons[] = {
272+    /* button       state                  function    argument */
273+/*  { BTN_STYLUS,   WLR_BUTTON_PRESSED,    spawn,      {.v = termcmd} }, */
274+/*  { BTN_STYLUS2,  WLR_BUTTON_PRESSED,    killclient, {0} }, */
275+	{ 0,            0,                     NULL,       {0} }
276+};
277+
278+static const TabletPadButton tabletpadbuttons[] = {
279+	/* button  state                  function          argument */
280+/*  { 0,       WLR_BUTTON_PRESSED,    spawn,            {.v = termcmd} }, */
281+/*  { 1,       WLR_BUTTON_PRESSED,    killclient,       {0} },*/
282+/*  { 2,       WLR_BUTTON_PRESSED,    togglefloating,   {0} },*/
283+/*  { 3,       WLR_BUTTON_PRESSED,    zoom,             {0} },*/
284+	{ 0,            0,                     NULL,       {0} }
285+};
+284, -0
  1@@ -0,0 +1,284 @@
  2+/* Taken from https://github.com/djpohly/dwl/issues/466 */
  3+#define COLOR(hex)    { ((hex >> 24) & 0xFF) / 255.0f, \
  4+                        ((hex >> 16) & 0xFF) / 255.0f, \
  5+                        ((hex >> 8) & 0xFF) / 255.0f, \
  6+                        (hex & 0xFF) / 255.0f }
  7+/* appearance */
  8+static const int tabletmaptosurface                = 1;  /* map tablet input to surface(1) or monitor(0) */
  9+static const int sloppyfocus                       = 1;  /* focus follows mouse */
 10+static const int bypass_surface_visibility         = 0;  /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible  */
 11+
 12+#define ZOOMMIN 0.05
 13+#define ZOOMMAX 3
 14+#define animatezoom 1
 15+#define zoomduration 0.33
 16+#define zoombezier "0.22,1.0,0.36,1.0"
 17+#define movecanvasmouse_multiplier_is_affected_by_zoom 1
 18+#define ZOOM_IN_TOWARDS_CURSOR 1
 19+#define ZOOM_OUT_TOWARDS_CURSOR 0
 20+
 21+#define SPAWNREGION_STYLE 2 /* 0 = None
 22+                               1 = Full rectangle.
 23+                               2 = outline
 24+                            */
 25+
 26+/* gaps */
 27+static const int enablegaps                        = 1;  /* 1 means gaps are enabled */
 28+static const int smartgaps                         = 0;  /* 1 means no outer gap when there is only one window */
 29+static const int monoclegaps                       = 0;  /* 1 means outer gaps in monocle layout */
 30+static const unsigned int gappih                   = 10; /* horizontal inner gap between windows */
 31+static const unsigned int gappiv                   = 10; /* vertical inner gap between windows */
 32+static const unsigned int gappoh                   = 10; /* horizontal outer gap between windows and screen edge */
 33+static const unsigned int gappov                   = 10; /* vertical outer gap between windows and screen edge */
 34+
 35+/* colors */
 36+static const float rootcolor[]                     = COLOR(0x22222267); /* Background color, only visible without any wallpaper setter */
 37+
 38+/* inner border */
 39+static const unsigned int innerborderpx = 4;  /* inner border pixel width */
 40+
 41+static const float focused_inner_border_color[]    = COLOR(0xFDD9C6ff);
 42+static const float urgent_inner_border_color[]     = COLOR(0xFDD9C6ff);
 43+static const float unfocused_inner_border_color[]  = COLOR(0x7B565600);
 44+
 45+/* outer border */
 46+static const unsigned int outerborderpx = 6;  /* outer border pixel width */
 47+
 48+static const float focused_outer_border_color[]    = COLOR(0x0a0100ff);
 49+static const float urgent_outer_border_color[]     = COLOR(0x0a0100ff);
 50+static const float unfocused_outer_border_color[]  = COLOR(0x1e1c1c00);
 51+
 52+#define SPAWNREGION_COLOR COLOR(0xFDD9C667)
 53+
 54+static const unsigned int spawnregion_innerborderpx  = 3;  /* spawnregion inner border pixel width */
 55+static const unsigned int spawnregion_outerborderpx  = 7;  /* spawnregion outer border pixel width */
 56+static const float spawnregion_inner_border_color[]  = COLOR(0xC9B8B6ff);
 57+static const float spawnregion_outer_border_color[]  = COLOR(0x430a03ff);
 58+
 59+/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
 60+static const float fullscreen_bg[]         = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
 61+/* Pen active area: value 0.0 => 1.0         { x,    y,    width, height } */
 62+static const double tablet_area[4] 		   = { 0.4,  0.4,  0.4,   0.4 };
 63+
 64+/* tagging - TAGCOUNT must be no greater than 31 */
 65+#define TAGCOUNT (9)
 66+
 67+/* logging */
 68+static int log_level = WLR_ERROR;
 69+
 70+
 71+
 72+static const Rule rules[] = {
 73+	/* app_id             title       tags mask     isfloating   monitor */
 74+	{ "Gimp_EXAMPLE",     NULL,       0,            1,           -1 }, /* Start on currently visible tags floating, not tiled */
 75+	{ "firefox_EXAMPLE",  NULL,       1 << 8,       0,           -1 }, /* Start on ONLY tag "9" */
 76+    /* default/example rule: can be changed but cannot be eliminated; at least one rule must exist */
 77+};
 78+
 79+#define CENTER_NEW_WINDOWS 1
 80+
 81+/* layout(s) */
 82+static const Layout layouts[] = {
 83+	/* symbol     arrange function */
 84+  { "><>",      NULL },    /* no layout function means floating behavior */
 85+	{ "[]=",      tile },
 86+	{ "[M]",      monocle },
 87+};
 88+
 89+/* monitors */
 90+/* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator
 91+ * WARNING: negative values other than (-1, -1) cause problems with Xwayland clients due to
 92+ * https://gitlab.freedesktop.org/xorg/xserver/-/issues/899 */
 93+static const MonitorRule monrules[] = {
 94+   /*    name  mfact nmaster  scale  layout       rotate/reflect                x   y      resx resy         rate mode   adaptive */
 95+   /*
 96+	* mode lets the user decide how dwl should implement the modes:
 97+	* -1 sets a custom mode following the user's choice
 98+	* All other numbers set the mode at the index n; 0 is the standard mode; see wlr-randr
 99+	*/
100+  { "HDMI-A-1", 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1, 0, 0, 180.003006f, 1, 0 },
101+ 	/* default monitor rule: can be changed but cannot be eliminated; at least one monitor rule must exist */
102+};
103+
104+/* keyboard */
105+static const struct xkb_rule_names xkb_rules = {
106+	/* can specify fields: rules, model, layout, variant, options */
107+	/* example:
108+	.options = "ctrl:nocaps",
109+	*/
110+	.options = NULL,
111+};
112+
113+static const int repeat_rate = 40;
114+static const int repeat_delay = 250;
115+
116+/* Trackpad */
117+static const int tap_to_click = 1;
118+static const int tap_and_drag = 1;
119+static const int drag_lock = 1;
120+static const int natural_scrolling = 0;
121+static const int disable_while_typing = 1;
122+static const int left_handed = 0;
123+static const int middle_button_emulation = 0;
124+/* You can choose between:
125+LIBINPUT_CONFIG_SCROLL_NO_SCROLL
126+LIBINPUT_CONFIG_SCROLL_2FG
127+LIBINPUT_CONFIG_SCROLL_EDGE
128+LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN
129+*/
130+static const enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
131+
132+/* You can choose between:
133+LIBINPUT_CONFIG_CLICK_METHOD_NONE
134+LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS
135+LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER
136+*/
137+static const enum libinput_config_click_method click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
138+
139+/* You can choose between:
140+LIBINPUT_CONFIG_SEND_EVENTS_ENABLED
141+LIBINPUT_CONFIG_SEND_EVENTS_DISABLED
142+LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE
143+*/
144+static const uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
145+
146+/* You can choose between:
147+LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT
148+LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE
149+*/
150+static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
151+static const double accel_speed = -1.0;
152+
153+/* You can choose between:
154+LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle
155+LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right
156+*/
157+static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM;
158+
159+/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
160+#define MODKEY WLR_MODIFIER_LOGO
161+#define ALT_MODKEY WLR_MODIFIER_ALT
162+
163+#define TAGKEYS(KEY,SKEY,TAG) \
164+	{ MODKEY,                    KEY,            view,            {.ui = 1 << TAG} }, \
165+	{ MODKEY|WLR_MODIFIER_CTRL,  KEY,            toggleview,      {.ui = 1 << TAG} }, \
166+	{ MODKEY|WLR_MODIFIER_SHIFT, SKEY,           tag,             {.ui = 1 << TAG} }, \
167+	{ MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} }
168+
169+/* helper for spawning shell commands in the pre dwm-5.0 fashion */
170+#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
171+
172+/* commands */
173+static const char *termcmd[] = { "foot", NULL };
174+static const char *menucmd[] = { "wmenu_run", NULL };
175+
176+static const Key keys[] = {
177+	/* Note that Shift changes certain key codes: 2 -> at, etc. */
178+	/* modifier                  key                  function          argument */
179+	{ MODKEY,                    XKB_KEY_p,           spawn,            {.v = menucmd} },
180+	{ MODKEY,                    XKB_KEY_Return,      spawn,            {.v = termcmd} },
181+	{ MODKEY,                    XKB_KEY_j,           focusstack,       {.i = +1} },
182+	{ MODKEY,                    XKB_KEY_k,           focusstack,       {.i = -1} },
183+	{ MODKEY,                    XKB_KEY_i,           incnmaster,       {.i = +1} },
184+	{ MODKEY,                    XKB_KEY_d,           incnmaster,       {.i = -1} },
185+	{ MODKEY,                    XKB_KEY_h,           setmfact,         {.f = -0.05f} },
186+	{ MODKEY,                    XKB_KEY_l,           setmfact,         {.f = +0.05f} },
187+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return,      swapmaster,       {0} },
188+	{ MODKEY,                    XKB_KEY_Tab,         view,             {0} },
189+	{ MODKEY,                    XKB_KEY_c,           killclient,       {0} },
190+	{ MODKEY,                    XKB_KEY_t,           setlayout,        {.v = &layouts[1]} },
191+	{ MODKEY,                    XKB_KEY_f,           setlayout,        {.v = &layouts[0]} },
192+	{ MODKEY,                    XKB_KEY_m,           setlayout,        {.v = &layouts[2]} },
193+	{ MODKEY,                    XKB_KEY_space,       setlayout,        {0} },
194+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space,       togglefloating,   {0} },
195+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_f,           togglefullscreen, {0} },
196+	{ MODKEY,                    XKB_KEY_0,           view,             {.ui = ~0} },
197+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright,  tag,              {.ui = ~0} },
198+	{ MODKEY,                    XKB_KEY_comma,       focusmon,         {.i = WLR_DIRECTION_LEFT} },
199+	{ MODKEY,                    XKB_KEY_period,      focusmon,         {.i = WLR_DIRECTION_RIGHT} },
200+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less,        tagmon,           {.i = WLR_DIRECTION_LEFT} },
201+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater,     tagmon,           {.i = WLR_DIRECTION_RIGHT} },
202+	TAGKEYS(          XKB_KEY_1, XKB_KEY_exclam,                        0),
203+	TAGKEYS(          XKB_KEY_2, XKB_KEY_at,                            1),
204+	TAGKEYS(          XKB_KEY_3, XKB_KEY_numbersign,                    2),
205+	TAGKEYS(          XKB_KEY_4, XKB_KEY_dollar,                        3),
206+	TAGKEYS(          XKB_KEY_5, XKB_KEY_percent,                       4),
207+	TAGKEYS(          XKB_KEY_6, XKB_KEY_asciicircum,                   5),
208+	TAGKEYS(          XKB_KEY_7, XKB_KEY_ampersand,                     6),
209+	TAGKEYS(          XKB_KEY_8, XKB_KEY_asterisk,                      7),
210+	TAGKEYS(          XKB_KEY_9, XKB_KEY_parenleft,                     8),
211+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_q,           quit,             {0} },
212+
213+	/* infinite_canvas */
214+	{ MODKEY,                    XKB_KEY_r,            homecanvas,       {0} },
215+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Left,         movecanvas,       {.i = 0} },
216+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Right,        movecanvas,       {.i = 1} },
217+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Up,           movecanvas,       {.i = 2} },
218+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Down,         movecanvas,       {.i = 3} },
219+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_d,            centerwindow,     {0} },
220+	/* infinite_canvas_end */
221+	{ MODKEY|WLR_MODIFIER_LOGO,  XKB_KEY_h,          incgaps,       {.i = +1 } },
222+	{ MODKEY|WLR_MODIFIER_LOGO,  XKB_KEY_l,          incgaps,       {.i = -1 } },
223+	{ MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT,   XKB_KEY_H,      incogaps,      {.i = +1 } },
224+	{ MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT,   XKB_KEY_L,      incogaps,      {.i = -1 } },
225+	{ MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL,    XKB_KEY_h,      incigaps,      {.i = +1 } },
226+	{ MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL,    XKB_KEY_l,      incigaps,      {.i = -1 } },
227+	{ MODKEY|WLR_MODIFIER_LOGO,  XKB_KEY_0,          togglegaps,     {0} },
228+	{ MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT,   XKB_KEY_parenright,defaultgaps,    {0} },
229+	{ MODKEY,                    XKB_KEY_y,          incihgaps,     {.i = +1 } },
230+	{ MODKEY,                    XKB_KEY_o,          incihgaps,     {.i = -1 } },
231+	{ MODKEY|WLR_MODIFIER_CTRL,  XKB_KEY_y,          incivgaps,     {.i = +1 } },
232+	{ MODKEY|WLR_MODIFIER_CTRL,  XKB_KEY_o,          incivgaps,     {.i = -1 } },
233+	{ MODKEY|WLR_MODIFIER_LOGO,  XKB_KEY_y,          incohgaps,     {.i = +1 } },
234+	{ MODKEY|WLR_MODIFIER_LOGO,  XKB_KEY_o,          incohgaps,     {.i = -1 } },
235+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Y,          incovgaps,     {.i = +1 } },
236+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O,          incovgaps,     {.i = -1 } },
237+  { WLR_MODIFIER_ALT,          XKB_KEY_R,          zoomreset,     {0} },
238+  { MODKEY, XKB_KEY_equal, zoom,      {.f =  +0.1f} },
239+  { MODKEY, XKB_KEY_minus, zoom,      {.f = -0.1f} },
240+	/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
241+	{ WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} },
242+	/* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is
243+	 * do not remove them.
244+	 */
245+#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} }
246+	CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6),
247+	CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12),
248+};
249+
250+static const Button buttons[] = {
251+	{ ClkClient, MODKEY, BTN_LEFT,   moveresize,     {.ui = CurMove} },
252+  { ClkRoot, 0,BTN_MIDDLE,   spawn,     {.v = menucmd} },
253+	{ ClkClient, MODKEY, BTN_MIDDLE, togglefloating, {0} },
254+	{ ClkClient, MODKEY, BTN_RIGHT,  moveresize,     {.ui = CurResize} },
255+	/* infinite_canvas */
256+	{ ClkClient, MODKEY|WLR_MODIFIER_SHIFT, BTN_LEFT, movecanvasmouse, {.f = 2} },
257+  { ClkRoot, MODKEY|WLR_MODIFIER_SHIFT, BTN_LEFT, movecanvasmouse, {.f = 2} },
258+  { ClkRoot, 0, BTN_LEFT, movecanvasmouse, {.f = 2} },
259+	/* infinite_canvas_end */
260+  { ClkRoot, 0, BTN_RIGHT, spawn, {.v = termcmd} },
261+  { ClkClient, MODKEY, SCROLL_UP, zoom,      {.f =  +0.25} },
262+  { ClkClient, MODKEY, SCROLL_DOWN, zoom,      {.f = -0.25f} },
263+
264+  { ClkRoot, MODKEY, SCROLL_UP, zoom,      {.f =  +0.25f} },
265+  { ClkRoot, MODKEY, SCROLL_DOWN, zoom,      {.f = -0.25f} },
266+
267+  { ClkRoot, 0, SCROLL_UP, zoom,      {.f =  +0.25f} },
268+  { ClkRoot, 0, SCROLL_DOWN, zoom,      {.f = -0.25f} },
269+};
270+
271+static const TabletButton tabletbuttons[] = {
272+    /* button       state                  function    argument */
273+/*  { BTN_STYLUS,   WLR_BUTTON_PRESSED,    spawn,      {.v = termcmd} }, */
274+/*  { BTN_STYLUS2,  WLR_BUTTON_PRESSED,    killclient, {0} }, */
275+	{ 0,            0,                     NULL,       {0} }
276+};
277+
278+static const TabletPadButton tabletpadbuttons[] = {
279+	/* button  state                  function          argument */
280+/*  { 0,       WLR_BUTTON_PRESSED,    spawn,            {.v = termcmd} }, */
281+/*  { 1,       WLR_BUTTON_PRESSED,    killclient,       {0} },*/
282+/*  { 2,       WLR_BUTTON_PRESSED,    togglefloating,   {0} },*/
283+/*  { 3,       WLR_BUTTON_PRESSED,    zoom,             {0} },*/
284+	{ 0,            0,                     NULL,       {0} }
285+};
+32, -0
 1@@ -0,0 +1,32 @@
 2+VERSION  = 1
 3+
 4+PKG_CONFIG = pkg-config
 5+
 6+# paths
 7+PREFIX = /usr/local
 8+MANDIR = $(PREFIX)/share/man
 9+DATADIR = $(PREFIX)/share
10+
11+WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.19`
12+WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.19`
13+
14+# Allow using an alternative wlroots installation
15+# This has to have all the includes required by wlroots, e.g:
16+# Assuming wlroots git repo is "${PWD}/wlroots" and you only ran "meson setup build && ninja -C build"
17+#WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \
18+#	-I$(PWD)/wlroots/include
19+# Set -rpath to avoid using the wrong library.
20+#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/build -L$(PWD)/wlroots/build -lwlroots-0.19
21+
22+# Assuming you ran "meson setup --prefix ${PWD}/0.19 build && ninja -C build install"
23+#WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \
24+#	-I$(PWD)/wlroots/0.19/include/wlroots-0.19
25+#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/0.19/lib64 -L$(PWD)/wlroots/0.19/lib64 -lwlroots-0.19
26+
27+XWAYLAND =
28+XLIBS =
29+# Uncomment to build XWayland support
30+XWAYLAND = -DXWAYLAND
31+XLIBS = xcb xcb-icccm
32+
33+CC = cc
+99, -0
  1@@ -0,0 +1,99 @@
  2+.Dd $Mdocdate$
  3+.Dt LEELOO 1
  4+.Os
  5+.Sh NAME
  6+.Nm leeloo
  7+.Nd Wayland compositor with an infinite canvas
  8+.Sh SYNOPSIS
  9+.Nm
 10+.Op Fl dv
 11+.Op Fl s Ar command
 12+.Sh DESCRIPTION
 13+.Nm
 14+is a Wayland compositor based on
 15+.Xr dwl 1 .
 16+Windows are placed on an unbounded canvas
 17+which can be panned and zoomed.
 18+.Pp
 19+The options are as follows:
 20+.Bl -tag -width Ds
 21+.It Fl d
 22+Log debugging messages to standard error.
 23+.It Fl s Ar command
 24+Run
 25+.Ar command
 26+with
 27+.Xr sh 1
 28+once the compositor is up.
 29+.Nm
 30+exits when it terminates.
 31+.It Fl v
 32+Print the version and exit.
 33+.El
 34+.Pp
 35+Configuration is done at compile time by editing
 36+.Pa config.h
 37+and rebuilding.
 38+.Sh DEFAULT BINDINGS
 39+.Bl -tag -width "Mod+Shift+Arrow" -compact
 40+.It Mod+Return
 41+Spawn
 42+.Xr foot 1 .
 43+.It Mod+p
 44+Spawn
 45+.Xr wmenu_run 1 .
 46+.It Mod+c
 47+Close window.
 48+.It Mod+Shift+q
 49+Quit.
 50+.It Mod+1\(en9
 51+View tag.
 52+.It Mod+Shift+1\(en9
 53+Move window to tag.
 54+.It Mod+t , f , m
 55+Tile, float, monocle.
 56+.It Mod+Shift+f
 57+Toggle fullscreen.
 58+.It Mod+Shift+Arrow
 59+Pan canvas.
 60+.It Mod+r
 61+Return canvas to origin.
 62+.It Mod+Shift+d
 63+Center window.
 64+.It Mod+= , \-
 65+Zoom in, out.
 66+.It Alt+Shift+r
 67+Reset zoom.
 68+.It Mod+Button1
 69+Move window.
 70+.It Mod+Button3
 71+Resize window.
 72+.It Button1
 73+Drag canvas.
 74+.It Scroll
 75+Zoom.
 76+.El
 77+.Pp
 78+.Dq Mod
 79+is the logo key.
 80+.Sh ENVIRONMENT
 81+.Bl -tag -width XDG_RUNTIME_DIR
 82+.It Ev XDG_RUNTIME_DIR
 83+Directory for the Wayland socket.
 84+Must be set.
 85+.It Ev WAYLAND_DISPLAY
 86+Set for child processes.
 87+.El
 88+.Sh EXIT STATUS
 89+.Ex -std
 90+.Sh SEE ALSO
 91+.Xr foot 1 ,
 92+.Xr sh 1
 93+.Sh AUTHORS
 94+.An -nosplit
 95+Based on
 96+.Xr dwl 1
 97+by
 98+.An Devin J. Pohly .
 99+.Sh CAVEATS
100+Changing the configuration requires recompilation.
+5, -0
1@@ -0,0 +1,5 @@
2+[Desktop Entry]
3+Name=Leeloo
4+Comment=Leeloo Wayland Compositor
5+Exec=leeloo
6+Type=Application
+8, -0
1@@ -0,0 +1,8 @@
2+# Additional modules cuz yeah
3+
4+# Tiling, i've made it a module because 
5+# i feel it is unneeded by many people 
6+# but it could be wanted by many others too. 
7+# (comment/uncomment to enable/disable support for tiling)
8+
9+LEELOOMODULES += -DTILING
+390, -0
  1@@ -0,0 +1,390 @@
  2+<?xml version="1.0" encoding="UTF-8"?>
  3+<protocol name="wlr_layer_shell_unstable_v1">
  4+  <copyright>
  5+    Copyright © 2017 Drew DeVault
  6+
  7+    Permission to use, copy, modify, distribute, and sell this
  8+    software and its documentation for any purpose is hereby granted
  9+    without fee, provided that the above copyright notice appear in
 10+    all copies and that both that copyright notice and this permission
 11+    notice appear in supporting documentation, and that the name of
 12+    the copyright holders not be used in advertising or publicity
 13+    pertaining to distribution of the software without specific,
 14+    written prior permission.  The copyright holders make no
 15+    representations about the suitability of this software for any
 16+    purpose.  It is provided "as is" without express or implied
 17+    warranty.
 18+
 19+    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 20+    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 21+    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 22+    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 23+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 24+    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 25+    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 26+    THIS SOFTWARE.
 27+  </copyright>
 28+
 29+  <interface name="zwlr_layer_shell_v1" version="4">
 30+    <description summary="create surfaces that are layers of the desktop">
 31+      Clients can use this interface to assign the surface_layer role to
 32+      wl_surfaces. Such surfaces are assigned to a "layer" of the output and
 33+      rendered with a defined z-depth respective to each other. They may also be
 34+      anchored to the edges and corners of a screen and specify input handling
 35+      semantics. This interface should be suitable for the implementation of
 36+      many desktop shell components, and a broad number of other applications
 37+      that interact with the desktop.
 38+    </description>
 39+
 40+    <request name="get_layer_surface">
 41+      <description summary="create a layer_surface from a surface">
 42+        Create a layer surface for an existing surface. This assigns the role of
 43+        layer_surface, or raises a protocol error if another role is already
 44+        assigned.
 45+
 46+        Creating a layer surface from a wl_surface which has a buffer attached
 47+        or committed is a client error, and any attempts by a client to attach
 48+        or manipulate a buffer prior to the first layer_surface.configure call
 49+        must also be treated as errors.
 50+
 51+        After creating a layer_surface object and setting it up, the client
 52+        must perform an initial commit without any buffer attached.
 53+        The compositor will reply with a layer_surface.configure event.
 54+        The client must acknowledge it and is then allowed to attach a buffer
 55+        to map the surface.
 56+
 57+        You may pass NULL for output to allow the compositor to decide which
 58+        output to use. Generally this will be the one that the user most
 59+        recently interacted with.
 60+
 61+        Clients can specify a namespace that defines the purpose of the layer
 62+        surface.
 63+      </description>
 64+      <arg name="id" type="new_id" interface="zwlr_layer_surface_v1"/>
 65+      <arg name="surface" type="object" interface="wl_surface"/>
 66+      <arg name="output" type="object" interface="wl_output" allow-null="true"/>
 67+      <arg name="layer" type="uint" enum="layer" summary="layer to add this surface to"/>
 68+      <arg name="namespace" type="string" summary="namespace for the layer surface"/>
 69+    </request>
 70+
 71+    <enum name="error">
 72+      <entry name="role" value="0" summary="wl_surface has another role"/>
 73+      <entry name="invalid_layer" value="1" summary="layer value is invalid"/>
 74+      <entry name="already_constructed" value="2" summary="wl_surface has a buffer attached or committed"/>
 75+    </enum>
 76+
 77+    <enum name="layer">
 78+      <description summary="available layers for surfaces">
 79+        These values indicate which layers a surface can be rendered in. They
 80+        are ordered by z depth, bottom-most first. Traditional shell surfaces
 81+        will typically be rendered between the bottom and top layers.
 82+        Fullscreen shell surfaces are typically rendered at the top layer.
 83+        Multiple surfaces can share a single layer, and ordering within a
 84+        single layer is undefined.
 85+      </description>
 86+
 87+      <entry name="background" value="0"/>
 88+      <entry name="bottom" value="1"/>
 89+      <entry name="top" value="2"/>
 90+      <entry name="overlay" value="3"/>
 91+    </enum>
 92+
 93+    <!-- Version 3 additions -->
 94+
 95+    <request name="destroy" type="destructor" since="3">
 96+      <description summary="destroy the layer_shell object">
 97+        This request indicates that the client will not use the layer_shell
 98+        object any more. Objects that have been created through this instance
 99+        are not affected.
100+      </description>
101+    </request>
102+  </interface>
103+
104+  <interface name="zwlr_layer_surface_v1" version="4">
105+    <description summary="layer metadata interface">
106+      An interface that may be implemented by a wl_surface, for surfaces that
107+      are designed to be rendered as a layer of a stacked desktop-like
108+      environment.
109+
110+      Layer surface state (layer, size, anchor, exclusive zone,
111+      margin, interactivity) is double-buffered, and will be applied at the
112+      time wl_surface.commit of the corresponding wl_surface is called.
113+
114+      Attaching a null buffer to a layer surface unmaps it.
115+
116+      Unmapping a layer_surface means that the surface cannot be shown by the
117+      compositor until it is explicitly mapped again. The layer_surface
118+      returns to the state it had right after layer_shell.get_layer_surface.
119+      The client can re-map the surface by performing a commit without any
120+      buffer attached, waiting for a configure event and handling it as usual.
121+    </description>
122+
123+    <request name="set_size">
124+      <description summary="sets the size of the surface">
125+        Sets the size of the surface in surface-local coordinates. The
126+        compositor will display the surface centered with respect to its
127+        anchors.
128+
129+        If you pass 0 for either value, the compositor will assign it and
130+        inform you of the assignment in the configure event. You must set your
131+        anchor to opposite edges in the dimensions you omit; not doing so is a
132+        protocol error. Both values are 0 by default.
133+
134+        Size is double-buffered, see wl_surface.commit.
135+      </description>
136+      <arg name="width" type="uint"/>
137+      <arg name="height" type="uint"/>
138+    </request>
139+
140+    <request name="set_anchor">
141+      <description summary="configures the anchor point of the surface">
142+        Requests that the compositor anchor the surface to the specified edges
143+        and corners. If two orthogonal edges are specified (e.g. 'top' and
144+        'left'), then the anchor point will be the intersection of the edges
145+        (e.g. the top left corner of the output); otherwise the anchor point
146+        will be centered on that edge, or in the center if none is specified.
147+
148+        Anchor is double-buffered, see wl_surface.commit.
149+      </description>
150+      <arg name="anchor" type="uint" enum="anchor"/>
151+    </request>
152+
153+    <request name="set_exclusive_zone">
154+      <description summary="configures the exclusive geometry of this surface">
155+        Requests that the compositor avoids occluding an area with other
156+        surfaces. The compositor's use of this information is
157+        implementation-dependent - do not assume that this region will not
158+        actually be occluded.
159+
160+        A positive value is only meaningful if the surface is anchored to one
161+        edge or an edge and both perpendicular edges. If the surface is not
162+        anchored, anchored to only two perpendicular edges (a corner), anchored
163+        to only two parallel edges or anchored to all edges, a positive value
164+        will be treated the same as zero.
165+
166+        A positive zone is the distance from the edge in surface-local
167+        coordinates to consider exclusive.
168+
169+        Surfaces that do not wish to have an exclusive zone may instead specify
170+        how they should interact with surfaces that do. If set to zero, the
171+        surface indicates that it would like to be moved to avoid occluding
172+        surfaces with a positive exclusive zone. If set to -1, the surface
173+        indicates that it would not like to be moved to accommodate for other
174+        surfaces, and the compositor should extend it all the way to the edges
175+        it is anchored to.
176+
177+        For example, a panel might set its exclusive zone to 10, so that
178+        maximized shell surfaces are not shown on top of it. A notification
179+        might set its exclusive zone to 0, so that it is moved to avoid
180+        occluding the panel, but shell surfaces are shown underneath it. A
181+        wallpaper or lock screen might set their exclusive zone to -1, so that
182+        they stretch below or over the panel.
183+
184+        The default value is 0.
185+
186+        Exclusive zone is double-buffered, see wl_surface.commit.
187+      </description>
188+      <arg name="zone" type="int"/>
189+    </request>
190+
191+    <request name="set_margin">
192+      <description summary="sets a margin from the anchor point">
193+        Requests that the surface be placed some distance away from the anchor
194+        point on the output, in surface-local coordinates. Setting this value
195+        for edges you are not anchored to has no effect.
196+
197+        The exclusive zone includes the margin.
198+
199+        Margin is double-buffered, see wl_surface.commit.
200+      </description>
201+      <arg name="top" type="int"/>
202+      <arg name="right" type="int"/>
203+      <arg name="bottom" type="int"/>
204+      <arg name="left" type="int"/>
205+    </request>
206+
207+    <enum name="keyboard_interactivity">
208+      <description summary="types of keyboard interaction possible for a layer shell surface">
209+        Types of keyboard interaction possible for layer shell surfaces. The
210+        rationale for this is twofold: (1) some applications are not interested
211+        in keyboard events and not allowing them to be focused can improve the
212+        desktop experience; (2) some applications will want to take exclusive
213+        keyboard focus.
214+      </description>
215+
216+      <entry name="none" value="0">
217+        <description summary="no keyboard focus is possible">
218+          This value indicates that this surface is not interested in keyboard
219+          events and the compositor should never assign it the keyboard focus.
220+
221+          This is the default value, set for newly created layer shell surfaces.
222+
223+          This is useful for e.g. desktop widgets that display information or
224+          only have interaction with non-keyboard input devices.
225+        </description>
226+      </entry>
227+      <entry name="exclusive" value="1">
228+        <description summary="request exclusive keyboard focus">
229+          Request exclusive keyboard focus if this surface is above the shell surface layer.
230+
231+          For the top and overlay layers, the seat will always give
232+          exclusive keyboard focus to the top-most layer which has keyboard
233+          interactivity set to exclusive. If this layer contains multiple
234+          surfaces with keyboard interactivity set to exclusive, the compositor
235+          determines the one receiving keyboard events in an implementation-
236+          defined manner. In this case, no guarantee is made when this surface
237+          will receive keyboard focus (if ever).
238+
239+          For the bottom and background layers, the compositor is allowed to use
240+          normal focus semantics.
241+
242+          This setting is mainly intended for applications that need to ensure
243+          they receive all keyboard events, such as a lock screen or a password
244+          prompt.
245+        </description>
246+      </entry>
247+      <entry name="on_demand" value="2" since="4">
248+        <description summary="request regular keyboard focus semantics">
249+          This requests the compositor to allow this surface to be focused and
250+          unfocused by the user in an implementation-defined manner. The user
251+          should be able to unfocus this surface even regardless of the layer
252+          it is on.
253+
254+          Typically, the compositor will want to use its normal mechanism to
255+          manage keyboard focus between layer shell surfaces with this setting
256+          and regular toplevels on the desktop layer (e.g. click to focus).
257+          Nevertheless, it is possible for a compositor to require a special
258+          interaction to focus or unfocus layer shell surfaces (e.g. requiring
259+          a click even if focus follows the mouse normally, or providing a
260+          keybinding to switch focus between layers).
261+
262+          This setting is mainly intended for desktop shell components (e.g.
263+          panels) that allow keyboard interaction. Using this option can allow
264+          implementing a desktop shell that can be fully usable without the
265+          mouse.
266+        </description>
267+      </entry>
268+    </enum>
269+
270+    <request name="set_keyboard_interactivity">
271+      <description summary="requests keyboard events">
272+        Set how keyboard events are delivered to this surface. By default,
273+        layer shell surfaces do not receive keyboard events; this request can
274+        be used to change this.
275+
276+        This setting is inherited by child surfaces set by the get_popup
277+        request.
278+
279+        Layer surfaces receive pointer, touch, and tablet events normally. If
280+        you do not want to receive them, set the input region on your surface
281+        to an empty region.
282+
283+        Keyboard interactivity is double-buffered, see wl_surface.commit.
284+      </description>
285+      <arg name="keyboard_interactivity" type="uint" enum="keyboard_interactivity"/>
286+    </request>
287+
288+    <request name="get_popup">
289+      <description summary="assign this layer_surface as an xdg_popup parent">
290+        This assigns an xdg_popup's parent to this layer_surface.  This popup
291+        should have been created via xdg_surface::get_popup with the parent set
292+        to NULL, and this request must be invoked before committing the popup's
293+        initial state.
294+
295+        See the documentation of xdg_popup for more details about what an
296+        xdg_popup is and how it is used.
297+      </description>
298+      <arg name="popup" type="object" interface="xdg_popup"/>
299+    </request>
300+
301+    <request name="ack_configure">
302+      <description summary="ack a configure event">
303+        When a configure event is received, if a client commits the
304+        surface in response to the configure event, then the client
305+        must make an ack_configure request sometime before the commit
306+        request, passing along the serial of the configure event.
307+
308+        If the client receives multiple configure events before it
309+        can respond to one, it only has to ack the last configure event.
310+
311+        A client is not required to commit immediately after sending
312+        an ack_configure request - it may even ack_configure several times
313+        before its next surface commit.
314+
315+        A client may send multiple ack_configure requests before committing, but
316+        only the last request sent before a commit indicates which configure
317+        event the client really is responding to.
318+      </description>
319+      <arg name="serial" type="uint" summary="the serial from the configure event"/>
320+    </request>
321+
322+    <request name="destroy" type="destructor">
323+      <description summary="destroy the layer_surface">
324+        This request destroys the layer surface.
325+      </description>
326+    </request>
327+
328+    <event name="configure">
329+      <description summary="suggest a surface change">
330+        The configure event asks the client to resize its surface.
331+
332+        Clients should arrange their surface for the new states, and then send
333+        an ack_configure request with the serial sent in this configure event at
334+        some point before committing the new surface.
335+
336+        The client is free to dismiss all but the last configure event it
337+        received.
338+
339+        The width and height arguments specify the size of the window in
340+        surface-local coordinates.
341+
342+        The size is a hint, in the sense that the client is free to ignore it if
343+        it doesn't resize, pick a smaller size (to satisfy aspect ratio or
344+        resize in steps of NxM pixels). If the client picks a smaller size and
345+        is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the
346+        surface will be centered on this axis.
347+
348+        If the width or height arguments are zero, it means the client should
349+        decide its own window dimension.
350+      </description>
351+      <arg name="serial" type="uint"/>
352+      <arg name="width" type="uint"/>
353+      <arg name="height" type="uint"/>
354+    </event>
355+
356+    <event name="closed">
357+      <description summary="surface should be closed">
358+        The closed event is sent by the compositor when the surface will no
359+        longer be shown. The output may have been destroyed or the user may
360+        have asked for it to be removed. Further changes to the surface will be
361+        ignored. The client should destroy the resource after receiving this
362+        event, and create a new surface if they so choose.
363+      </description>
364+    </event>
365+
366+    <enum name="error">
367+      <entry name="invalid_surface_state" value="0" summary="provided surface state is invalid"/>
368+      <entry name="invalid_size" value="1" summary="size is invalid"/>
369+      <entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/>
370+      <entry name="invalid_keyboard_interactivity" value="3" summary="keyboard interactivity is invalid"/>
371+    </enum>
372+
373+    <enum name="anchor" bitfield="true">
374+      <entry name="top" value="1" summary="the top edge of the anchor rectangle"/>
375+      <entry name="bottom" value="2" summary="the bottom edge of the anchor rectangle"/>
376+      <entry name="left" value="4" summary="the left edge of the anchor rectangle"/>
377+      <entry name="right" value="8" summary="the right edge of the anchor rectangle"/>
378+    </enum>
379+
380+    <!-- Version 2 additions -->
381+
382+    <request name="set_layer" since="2">
383+      <description summary="change the layer of the surface">
384+        Change the layer that the surface is rendered on.
385+
386+        Layer is double-buffered, see wl_surface.commit.
387+      </description>
388+      <arg name="layer" type="uint" enum="zwlr_layer_shell_v1.layer" summary="layer to move this surface to"/>
389+    </request>
390+  </interface>
391+</protocol>
+128, -0
  1@@ -0,0 +1,128 @@
  2+<?xml version="1.0" encoding="UTF-8"?>
  3+<protocol name="wlr_output_power_management_unstable_v1">
  4+  <copyright>
  5+    Copyright © 2019 Purism SPC
  6+
  7+    Permission is hereby granted, free of charge, to any person obtaining a
  8+    copy of this software and associated documentation files (the "Software"),
  9+    to deal in the Software without restriction, including without limitation
 10+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
 11+    and/or sell copies of the Software, and to permit persons to whom the
 12+    Software is furnished to do so, subject to the following conditions:
 13+
 14+    The above copyright notice and this permission notice (including the next
 15+    paragraph) shall be included in all copies or substantial portions of the
 16+    Software.
 17+
 18+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 21+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 23+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 24+    DEALINGS IN THE SOFTWARE.
 25+  </copyright>
 26+
 27+  <description summary="Control power management modes of outputs">
 28+    This protocol allows clients to control power management modes
 29+    of outputs that are currently part of the compositor space. The
 30+    intent is to allow special clients like desktop shells to power
 31+    down outputs when the system is idle.
 32+
 33+    To modify outputs not currently part of the compositor space see
 34+    wlr-output-management.
 35+
 36+    Warning! The protocol described in this file is experimental and
 37+    backward incompatible changes may be made. Backward compatible changes
 38+    may be added together with the corresponding interface version bump.
 39+    Backward incompatible changes are done by bumping the version number in
 40+    the protocol and interface names and resetting the interface version.
 41+    Once the protocol is to be declared stable, the 'z' prefix and the
 42+    version number in the protocol and interface names are removed and the
 43+    interface version number is reset.
 44+  </description>
 45+
 46+  <interface name="zwlr_output_power_manager_v1" version="1">
 47+    <description summary="manager to create per-output power management">
 48+      This interface is a manager that allows creating per-output power
 49+      management mode controls.
 50+    </description>
 51+
 52+    <request name="get_output_power">
 53+      <description summary="get a power management for an output">
 54+        Create a output power management mode control that can be used to
 55+        adjust the power management mode for a given output.
 56+      </description>
 57+      <arg name="id" type="new_id" interface="zwlr_output_power_v1"/>
 58+      <arg name="output" type="object" interface="wl_output"/>
 59+    </request>
 60+
 61+    <request name="destroy" type="destructor">
 62+      <description summary="destroy the manager">
 63+        All objects created by the manager will still remain valid, until their
 64+        appropriate destroy request has been called.
 65+      </description>
 66+    </request>
 67+  </interface>
 68+
 69+  <interface name="zwlr_output_power_v1" version="1">
 70+    <description summary="adjust power management mode for an output">
 71+      This object offers requests to set the power management mode of
 72+      an output.
 73+    </description>
 74+
 75+    <enum name="mode">
 76+      <entry name="off" value="0"
 77+             summary="Output is turned off."/>
 78+      <entry name="on" value="1"
 79+             summary="Output is turned on, no power saving"/>
 80+    </enum>
 81+
 82+    <enum name="error">
 83+      <entry name="invalid_mode" value="1" summary="inexistent power save mode"/>
 84+    </enum>
 85+
 86+    <request name="set_mode">
 87+      <description summary="Set an outputs power save mode">
 88+        Set an output's power save mode to the given mode. The mode change
 89+        is effective immediately. If the output does not support the given
 90+        mode a failed event is sent.
 91+      </description>
 92+      <arg name="mode" type="uint" enum="mode" summary="the power save mode to set"/>
 93+    </request>
 94+
 95+    <event name="mode">
 96+      <description summary="Report a power management mode change">
 97+        Report the power management mode change of an output.
 98+
 99+        The mode event is sent after an output changed its power
100+        management mode. The reason can be a client using set_mode or the
101+        compositor deciding to change an output's mode.
102+        This event is also sent immediately when the object is created
103+        so the client is informed about the current power management mode.
104+      </description>
105+      <arg name="mode" type="uint" enum="mode"
106+           summary="the output's new power management mode"/>
107+    </event>
108+
109+    <event name="failed">
110+      <description summary="object no longer valid">
111+        This event indicates that the output power management mode control
112+        is no longer valid. This can happen for a number of reasons,
113+        including:
114+        - The output doesn't support power management
115+        - Another client already has exclusive power management mode control
116+          for this output
117+        - The output disappeared
118+
119+        Upon receiving this event, the client should destroy this object.
120+      </description>
121+    </event>
122+
123+    <request name="destroy" type="destructor">
124+      <description summary="destroy this power management">
125+        Destroys the output power management mode control object.
126+      </description>
127+    </request>
128+  </interface>
129+</protocol>
+406, -0
  1@@ -0,0 +1,406 @@
  2+/*
  3+ * Attempt to consolidate unavoidable suck into one file, away from leeloo.c.  This
  4+ * file is not meant to be pretty.  We use a .h file with static inline
  5+ * functions instead of a separate .c module, or function pointers like sway, so
  6+ * that they will simply compile out if the chosen #defines leave them unused.
  7+ */
  8+
  9+/* Leave these functions first; they're used in the others */
 10+static inline int
 11+client_is_x11(Client *c)
 12+{
 13+#ifdef XWAYLAND
 14+	return c->type == X11;
 15+#endif
 16+	return 0;
 17+}
 18+
 19+static inline struct wlr_surface *
 20+client_surface(Client *c)
 21+{
 22+#ifdef XWAYLAND
 23+	if (client_is_x11(c))
 24+		return c->surface.xwayland->surface;
 25+#endif
 26+	return c->surface.xdg->surface;
 27+}
 28+
 29+static inline int
 30+toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl)
 31+{
 32+	struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface;
 33+	struct wlr_surface *root_surface;
 34+	struct wlr_layer_surface_v1 *layer_surface;
 35+	Client *c = NULL;
 36+	LayerSurface *l = NULL;
 37+	int type = -1;
 38+#ifdef XWAYLAND
 39+	struct wlr_xwayland_surface *xsurface;
 40+#endif
 41+
 42+	if (!s)
 43+		return -1;
 44+	root_surface = wlr_surface_get_root_surface(s);
 45+
 46+#ifdef XWAYLAND
 47+	if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) {
 48+		c = xsurface->data;
 49+		type = c->type;
 50+		goto end;
 51+	}
 52+#endif
 53+
 54+	if ((layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) {
 55+		l = layer_surface->data;
 56+		type = LayerShell;
 57+		goto end;
 58+	}
 59+
 60+	xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface);
 61+	while (xdg_surface) {
 62+		tmp_xdg_surface = NULL;
 63+		switch (xdg_surface->role) {
 64+		case WLR_XDG_SURFACE_ROLE_POPUP:
 65+			if (!xdg_surface->popup || !xdg_surface->popup->parent)
 66+				return -1;
 67+
 68+			tmp_xdg_surface = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent);
 69+
 70+			if (!tmp_xdg_surface)
 71+				return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl);
 72+
 73+			xdg_surface = tmp_xdg_surface;
 74+			break;
 75+		case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
 76+			c = xdg_surface->data;
 77+			type = c->type;
 78+			goto end;
 79+		case WLR_XDG_SURFACE_ROLE_NONE:
 80+			return -1;
 81+		}
 82+	}
 83+
 84+end:
 85+	if (pl)
 86+		*pl = l;
 87+	if (pc)
 88+		*pc = c;
 89+	return type;
 90+}
 91+
 92+/* The others */
 93+static inline void
 94+client_activate_surface(struct wlr_surface *s, int activated)
 95+{
 96+	struct wlr_xdg_toplevel *toplevel;
 97+#ifdef XWAYLAND
 98+	struct wlr_xwayland_surface *xsurface;
 99+	if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) {
100+		wlr_xwayland_surface_activate(xsurface, activated);
101+		return;
102+	}
103+#endif
104+	if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s)))
105+		wlr_xdg_toplevel_set_activated(toplevel, activated);
106+}
107+
108+static inline uint32_t
109+client_set_bounds(Client *c, int32_t width, int32_t height)
110+{
111+#ifdef XWAYLAND
112+	if (client_is_x11(c))
113+		return 0;
114+#endif
115+	if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >=
116+			XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0
117+			&& (c->bounds.width != width || c->bounds.height != height)) {
118+		c->bounds.width = width;
119+		c->bounds.height = height;
120+		return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height);
121+	}
122+	return 0;
123+}
124+
125+static inline const char *
126+client_get_appid(Client *c)
127+{
128+#ifdef XWAYLAND
129+	if (client_is_x11(c))
130+		return c->surface.xwayland->class ? c->surface.xwayland->class : "broken";
131+#endif
132+	return c->surface.xdg->toplevel->app_id ? c->surface.xdg->toplevel->app_id : "broken";
133+}
134+
135+static inline void
136+client_get_clip(Client *c, struct wlr_box *clip)
137+{
138+	*clip = (struct wlr_box){
139+		.x = 0,
140+		.y = 0,
141+		.width = c->geom.width - c->bw,
142+		.height = c->geom.height - c->bw,
143+	};
144+
145+#ifdef XWAYLAND
146+	if (client_is_x11(c))
147+		return;
148+#endif
149+
150+	clip->x = c->surface.xdg->geometry.x;
151+	clip->y = c->surface.xdg->geometry.y;
152+}
153+
154+static inline void
155+client_get_geometry(Client *c, struct wlr_box *geom)
156+{
157+#ifdef XWAYLAND
158+	if (client_is_x11(c)) {
159+		geom->x = c->surface.xwayland->x;
160+		geom->y = c->surface.xwayland->y;
161+		geom->width = c->surface.xwayland->width;
162+		geom->height = c->surface.xwayland->height;
163+		return;
164+	}
165+#endif
166+	*geom = c->surface.xdg->geometry;
167+}
168+
169+static inline Client *
170+client_get_parent(Client *c)
171+{
172+	Client *p = NULL;
173+#ifdef XWAYLAND
174+	if (client_is_x11(c)) {
175+		if (c->surface.xwayland->parent)
176+			toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL);
177+		return p;
178+	}
179+#endif
180+	if (c->surface.xdg->toplevel->parent)
181+		toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL);
182+	return p;
183+}
184+
185+static inline int
186+client_has_children(Client *c)
187+{
188+#ifdef XWAYLAND
189+	if (client_is_x11(c))
190+		return !wl_list_empty(&c->surface.xwayland->children);
191+#endif
192+	/* surface.xdg->link is never empty because it always contains at least the
193+	 * surface itself. */
194+	return wl_list_length(&c->surface.xdg->link) > 1;
195+}
196+
197+static inline const char *
198+client_get_title(Client *c)
199+{
200+#ifdef XWAYLAND
201+	if (client_is_x11(c))
202+		return c->surface.xwayland->title ? c->surface.xwayland->title : "broken";
203+#endif
204+	return c->surface.xdg->toplevel->title ? c->surface.xdg->toplevel->title : "broken";
205+}
206+
207+static inline int
208+client_is_float_type(Client *c)
209+{
210+	struct wlr_xdg_toplevel *toplevel;
211+	struct wlr_xdg_toplevel_state state;
212+
213+#ifdef XWAYLAND
214+	if (client_is_x11(c)) {
215+		struct wlr_xwayland_surface *surface = c->surface.xwayland;
216+		xcb_size_hints_t *size_hints = surface->size_hints;
217+		if (surface->modal)
218+			return 1;
219+
220+		if (wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DIALOG)
221+				|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_SPLASH)
222+				|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_TOOLBAR)
223+				|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_UTILITY)) {
224+			return 1;
225+		}
226+
227+		return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0
228+			&& (size_hints->max_width == size_hints->min_width
229+				|| size_hints->max_height == size_hints->min_height);
230+	}
231+#endif
232+
233+	toplevel = c->surface.xdg->toplevel;
234+	state = toplevel->current;
235+	return toplevel->parent || (state.min_width != 0 && state.min_height != 0
236+		&& (state.min_width == state.max_width
237+			|| state.min_height == state.max_height));
238+}
239+
240+static inline int
241+client_is_rendered_on_mon(Client *c, Monitor *m)
242+{
243+	/* This is needed for when you don't want to check formal assignment,
244+	 * but rather actual displaying of the pixels.
245+	 * Usually VISIBLEON suffices and is also faster. */
246+	struct wlr_surface_output *s;
247+	int unused_lx, unused_ly;
248+	if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly))
249+		return 0;
250+	wl_list_for_each(s, &client_surface(c)->current_outputs, link)
251+		if (s->output == m->wlr_output)
252+			return 1;
253+	return 0;
254+}
255+
256+static inline int
257+client_is_stopped(Client *c)
258+{
259+	int pid;
260+	siginfo_t in = {0};
261+#ifdef XWAYLAND
262+	if (client_is_x11(c))
263+		return 0;
264+#endif
265+
266+	wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
267+	if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) {
268+		/* This process is not our child process, while is very unlikely that
269+		 * it is stopped, in order to do not skip frames, assume that it is. */
270+		if (errno == ECHILD)
271+			return 1;
272+	} else if (in.si_pid) {
273+		if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED)
274+			return 1;
275+		if (in.si_code == CLD_CONTINUED)
276+			return 0;
277+	}
278+
279+	return 0;
280+}
281+
282+static inline int
283+client_is_unmanaged(Client *c)
284+{
285+#ifdef XWAYLAND
286+	if (client_is_x11(c))
287+		return c->surface.xwayland->override_redirect;
288+#endif
289+	return 0;
290+}
291+
292+static inline void
293+client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
294+{
295+	if (kb)
296+		wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes,
297+				kb->num_keycodes, &kb->modifiers);
298+	else
299+		wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL);
300+}
301+
302+static inline void
303+client_send_close(Client *c)
304+{
305+#ifdef XWAYLAND
306+	if (client_is_x11(c)) {
307+		wlr_xwayland_surface_close(c->surface.xwayland);
308+		return;
309+	}
310+#endif
311+	wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel);
312+}
313+
314+static inline void
315+client_set_border_color(Client *c, const float inner[static 4], const float outer[static 4])
316+{
317+    int i;
318+    for (i = 0; i < 4; i++) {
319+        wlr_scene_rect_set_color(c->inner_border[i], inner);
320+        wlr_scene_rect_set_color(c->outer_border[i], outer);
321+    }
322+}
323+
324+static inline void
325+client_set_fullscreen(Client *c, int fullscreen)
326+{
327+#ifdef XWAYLAND
328+	if (client_is_x11(c)) {
329+		wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen);
330+		return;
331+	}
332+#endif
333+	wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen);
334+}
335+
336+static inline void
337+client_set_scale(struct wlr_surface *s, float scale)
338+{
339+	wlr_fractional_scale_v1_notify_scale(s, scale);
340+	wlr_surface_set_preferred_buffer_scale(s, (int32_t)ceilf(scale));
341+}
342+
343+static inline uint32_t
344+client_set_size(Client *c, uint32_t width, uint32_t height)
345+{
346+#ifdef XWAYLAND
347+	if (client_is_x11(c)) {
348+		wlr_xwayland_surface_configure(c->surface.xwayland,
349+				c->geom.x + c->bw, c->geom.y + c->bw, width, height);
350+		return 0;
351+	}
352+#endif
353+	if ((int32_t)width == c->surface.xdg->toplevel->current.width
354+			&& (int32_t)height == c->surface.xdg->toplevel->current.height)
355+		return 0;
356+	return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height);
357+}
358+
359+static inline void
360+client_set_tiled(Client *c, uint32_t edges)
361+{
362+#ifdef XWAYLAND
363+	if (client_is_x11(c)) {
364+		wlr_xwayland_surface_set_maximized(c->surface.xwayland,
365+				edges != WLR_EDGE_NONE, edges != WLR_EDGE_NONE);
366+		return;
367+  }
368+#endif
369+	if (wl_resource_get_version(c->surface.xdg->toplevel->resource)
370+			>= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
371+		wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
372+	} else {
373+		wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != WLR_EDGE_NONE);
374+	}
375+}
376+
377+static inline void
378+client_set_suspended(Client *c, int suspended)
379+{
380+#ifdef XWAYLAND
381+	if (client_is_x11(c))
382+		return;
383+#endif
384+
385+	wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);
386+}
387+
388+static inline int
389+client_wants_focus(Client *c)
390+{
391+#ifdef XWAYLAND
392+	return client_is_unmanaged(c)
393+		&& wlr_xwayland_surface_override_redirect_wants_focus(c->surface.xwayland)
394+		&& wlr_xwayland_surface_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE;
395+#endif
396+	return 0;
397+}
398+
399+static inline int
400+client_wants_fullscreen(Client *c)
401+{
402+#ifdef XWAYLAND
403+	if (client_is_x11(c))
404+		return c->surface.xwayland->fullscreen;
405+#endif
406+	return c->surface.xdg->toplevel->requested.fullscreen;
407+}
+5969, -0
   1@@ -0,0 +1,5969 @@
   2+/*
   3+ * See LICENSE file for copyright and license details.
   4+ */
   5+#include <getopt.h>
   6+#include <libinput.h>
   7+#include <linux/input-event-codes.h>
   8+#include <math.h>
   9+#include <signal.h>
  10+#include <stdio.h>
  11+#include <stdlib.h>
  12+#include <sys/wait.h>
  13+#include <time.h>
  14+#include <unistd.h>
  15+#include <wayland-server-core.h>
  16+#include <wlr/backend.h>
  17+#include <wlr/backend/libinput.h>
  18+#include <wlr/render/allocator.h>
  19+#include <wlr/render/wlr_renderer.h>
  20+#include <wlr/types/wlr_alpha_modifier_v1.h>
  21+#include <wlr/types/wlr_compositor.h>
  22+#include <wlr/types/wlr_cursor.h>
  23+#include <wlr/types/wlr_cursor_shape_v1.h>
  24+#include <wlr/types/wlr_data_control_v1.h>
  25+#include <wlr/types/wlr_data_device.h>
  26+#include <wlr/types/wlr_drm.h>
  27+#include <wlr/types/wlr_export_dmabuf_v1.h>
  28+#include <wlr/types/wlr_ext_data_control_v1.h>
  29+#include <wlr/types/wlr_fractional_scale_v1.h>
  30+#include <wlr/types/wlr_gamma_control_v1.h>
  31+#include <wlr/types/wlr_idle_inhibit_v1.h>
  32+#include <wlr/types/wlr_idle_notify_v1.h>
  33+#include <wlr/types/wlr_input_device.h>
  34+#include <wlr/types/wlr_keyboard.h>
  35+#include <wlr/types/wlr_keyboard_group.h>
  36+#include <wlr/types/wlr_layer_shell_v1.h>
  37+#include <wlr/types/wlr_linux_dmabuf_v1.h>
  38+#include <wlr/types/wlr_linux_drm_syncobj_v1.h>
  39+#include <wlr/types/wlr_output.h>
  40+#include <wlr/types/wlr_output_layout.h>
  41+#include <wlr/types/wlr_output_management_v1.h>
  42+#include <wlr/types/wlr_output_power_management_v1.h>
  43+#include <wlr/types/wlr_pointer.h>
  44+#include <wlr/types/wlr_pointer_constraints_v1.h>
  45+#include <wlr/types/wlr_pointer_gestures_v1.h>
  46+#include <wlr/types/wlr_presentation_time.h>
  47+#include <wlr/types/wlr_primary_selection.h>
  48+#include <wlr/types/wlr_primary_selection_v1.h>
  49+#include <wlr/types/wlr_relative_pointer_v1.h>
  50+#include <wlr/types/wlr_scene.h>
  51+#include <wlr/types/wlr_screencopy_v1.h>
  52+#include <wlr/types/wlr_seat.h>
  53+#include <wlr/types/wlr_server_decoration.h>
  54+#include <wlr/types/wlr_session_lock_v1.h>
  55+#include <wlr/types/wlr_single_pixel_buffer_v1.h>
  56+#include <wlr/types/wlr_subcompositor.h>
  57+#include <wlr/types/wlr_viewporter.h>
  58+#include <wlr/types/wlr_virtual_keyboard_v1.h>
  59+#include <wlr/types/wlr_virtual_pointer_v1.h>
  60+#include <wlr/types/wlr_xcursor_manager.h>
  61+#include <wlr/types/wlr_xdg_activation_v1.h>
  62+#include <wlr/types/wlr_xdg_decoration_v1.h>
  63+#include <wlr/types/wlr_xdg_output_v1.h>
  64+#include <wlr/types/wlr_xdg_shell.h>
  65+#include <wlr/util/log.h>
  66+#include <wlr/util/region.h>
  67+#include <xkbcommon/xkbcommon.h>
  68+#ifdef XWAYLAND
  69+#include <wlr/xwayland.h>
  70+#include <xcb/xcb.h>
  71+#include <xcb/xcb_icccm.h>
  72+#endif
  73+/* tablet-input */
  74+#include <wlr/types/wlr_tablet_pad.h>
  75+#include <wlr/types/wlr_tablet_tool.h>
  76+#include <wlr/types/wlr_tablet_v2.h>
  77+/* tablet-input end */
  78+
  79+#include "util.h"
  80+
  81+/* macros */
  82+#define MAX(A, B)               ((A) > (B) ? (A) : (B))
  83+#define MIN(A, B)               ((A) < (B) ? (A) : (B))
  84+#define CLEANMASK(mask)         (mask & ~WLR_MODIFIER_CAPS)
  85+#define VISIBLEON(C, M)         ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
  86+#define LENGTH(X)               (sizeof X / sizeof X[0])
  87+#define END(A)                  ((A) + LENGTH(A))
  88+#define TAGMASK                 ((1u << TAGCOUNT) - 1)
  89+#define LISTEN(E, L, H)         wl_signal_add((E), ((L)->notify = (H), (L)))
  90+#define LISTEN_STATIC(E, H)     do { struct wl_listener *_l = ecalloc(1, sizeof(*_l)); _l->notify = (H); wl_signal_add((E), _l); } while (0)
  91+
  92+/* enums */
  93+enum { CurNormal, CurPressed, CurMove, CurResize, CurSpawnRegion }; /* cursor */
  94+enum { SnapLeft, SnapRight, SnapTop, SnapBottom,
  95+       SnapTopLeft, SnapTopRight, SnapBottomLeft, SnapBottomRight }; /* labwc-style keybind snap positions */
  96+enum { XDGShell, LayerShell, X11 }; /* client types */
  97+enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
  98+/* click */
  99+enum { ClkClient, ClkLayerShell, ClkRoot }; /* clicks */
 100+/* click end */
 101+typedef union {
 102+	int i;
 103+	uint32_t ui;
 104+	float f;
 105+	const void *v;
 106+} Arg;
 107+
 108+typedef struct {
 109+  /* click */
 110+  unsigned int click;
 111+  /* click end */
 112+	unsigned int mod;
 113+	unsigned int button;
 114+	void (*func)(const Arg *);
 115+	const Arg arg;
 116+} Button;
 117+
 118+typedef struct Monitor Monitor;
 119+typedef struct {
 120+	/* Must keep this field first */
 121+	unsigned int type; /* XDGShell or X11* */
 122+
 123+	Monitor *mon;
 124+	struct wlr_scene_tree *scene;
 125+
 126+  struct wlr_scene_rect *inner_border[4]; /* inner top, bottom, left, right */
 127+  struct wlr_scene_rect *outer_border[4]; /* outer top, bottom, left, right */
 128+
 129+	struct wlr_scene_tree *scene_surface;
 130+	struct wl_list link;
 131+	struct wl_list flink;
 132+	struct wlr_box geom; /* layout-relative, includes border */
 133+	struct wlr_box prev; /* layout-relative, includes border */
 134+	struct wlr_box bounds; /* only width and height are used */
 135+	union {
 136+		struct wlr_xdg_surface *xdg;
 137+		struct wlr_xwayland_surface *xwayland;
 138+	} surface;
 139+	struct wlr_xdg_toplevel_decoration_v1 *decoration;
 140+	struct wl_listener commit;
 141+	struct wl_listener map;
 142+	struct wl_listener maximize;
 143+	struct wl_listener unmap;
 144+	struct wl_listener destroy;
 145+	struct wl_listener set_title;
 146+	struct wl_listener fullscreen;
 147+	struct wl_listener set_decoration_mode;
 148+	struct wl_listener destroy_decoration;
 149+#ifdef XWAYLAND
 150+	struct wl_listener activate;
 151+	struct wl_listener associate;
 152+	struct wl_listener dissociate;
 153+	struct wl_listener configure;
 154+	struct wl_listener set_hints;
 155+#endif
 156+	unsigned int bw;
 157+  unsigned int ibw;  // inner border width
 158+  unsigned int obw;  // outer border width
 159+	uint32_t tags;
 160+	int isfloating, isurgent, isfullscreen, isfakefullscreen;
 161+	uint32_t resize; /* configure serial of a pending resize */
 162+	/* infinite_canvas */
 163+	int saved_cx, saved_cy;
 164+	int saved_cw, saved_ch;
 165+	int was_on_canvas;
 166+	int home_cx, home_cy; /* pan value in effect when this window was placed */
 167+	/* infinite_canvas_end */
 168+} Client;
 169+
 170+/* infinite_canvas */
 171+typedef struct {
 172+	int cx, cy;
 173+	int saved_cx, saved_cy;
 174+} CanvasOffset;
 175+/* infinite_canvas_end */
 176+
 177+typedef struct {
 178+	uint32_t mod;
 179+	xkb_keysym_t keysym;
 180+	void (*func)(const Arg *);
 181+	const Arg arg;
 182+} Key;
 183+
 184+typedef struct {
 185+	struct wlr_keyboard_group *wlr_group;
 186+
 187+	int nsyms;
 188+	const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */
 189+	uint32_t mods; /* invalid if nsyms == 0 */
 190+	struct wl_event_source *key_repeat_source;
 191+
 192+	struct wl_listener modifiers;
 193+	struct wl_listener key;
 194+	struct wl_listener destroy;
 195+} KeyboardGroup;
 196+
 197+typedef struct {
 198+	/* Must keep this field first */
 199+	unsigned int type; /* LayerShell */
 200+
 201+	Monitor *mon;
 202+	struct wlr_scene_tree *scene;
 203+	struct wlr_scene_tree *popups;
 204+	struct wlr_scene_layer_surface_v1 *scene_layer;
 205+	struct wl_list link;
 206+	int mapped;
 207+	struct wlr_layer_surface_v1 *layer_surface;
 208+
 209+	struct wl_listener destroy;
 210+	struct wl_listener unmap;
 211+	struct wl_listener surface_commit;
 212+} LayerSurface;
 213+
 214+typedef struct {
 215+	const char *symbol;
 216+	void (*arrange)(Monitor *);
 217+} Layout;
 218+
 219+typedef struct {
 220+	struct wl_list link;
 221+	char name[64];
 222+	unsigned int seltags;
 223+	unsigned int sellt;
 224+	uint32_t tagset[2];
 225+	float mfact;
 226+	int nmaster;
 227+	char ltsymbol[16];
 228+	const Layout *lt[2];
 229+	CanvasOffset *canvas;
 230+	double zoom_scale;
 231+	double zoom_target;
 232+	double zoom_pan_x;
 233+	double zoom_pan_y;
 234+} MonitorState;
 235+
 236+struct Monitor {
 237+	struct wl_list link;
 238+	struct wlr_output *wlr_output;
 239+	struct wlr_scene_output *scene_output;
 240+	struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */
 241+	struct wl_listener frame;
 242+	struct wl_listener destroy;
 243+	struct wl_listener request_state;
 244+	struct wl_listener destroy_lock_surface;
 245+	struct wlr_session_lock_surface_v1 *lock_surface;
 246+	struct wlr_box m; /* monitor area, layout-relative */
 247+	struct wlr_box w; /* window area, layout-relative */
 248+	struct wl_list layers[4]; /* LayerSurface.link */
 249+	const Layout *lt[2];
 250+	unsigned int seltags;
 251+	unsigned int sellt;
 252+	uint32_t tagset[2];
 253+	float mfact;
 254+	int gamma_lut_changed;
 255+	int nmaster;
 256+	char ltsymbol[16];
 257+	int asleep;
 258+	/* infinite_canvas */
 259+	CanvasOffset *canvas;
 260+	/* infinite_canvas_end */
 261+	/* zoom */
 262+	double zoom_scale;
 263+	double zoom_target;
 264+	double zoom_pan_x, zoom_pan_y;
 265+	double zoom_anchor_fx, zoom_anchor_fy;
 266+	double zoom_anchor_lx, zoom_anchor_ly;
 267+	double zoom_anim_t;
 268+	double zoom_start_scale;
 269+	double zoom_start_pan_x, zoom_start_pan_y;
 270+	int zoom_popups_dirty;
 271+	/* zoom end */
 272+#ifdef TILING
 273+	int enablegaps;       /* enable gaps, used by togglegaps */
 274+	int gappih;           /* horizontal gap between windows */
 275+	int gappiv;           /* vertical gap between windows */
 276+	int gappoh;           /* horizontal outer gaps */
 277+	int gappov;           /* vertical outer gaps */
 278+#endif
 279+};
 280+
 281+typedef struct {
 282+	const char *name;
 283+	float mfact;
 284+	int nmaster;
 285+	float scale;
 286+	const Layout *lt;
 287+	enum wl_output_transform rr;
 288+	int x, y;
 289+	int resx;
 290+	int resy;
 291+	float rate;
 292+	int mode;
 293+	int adaptive;
 294+} MonitorRule;
 295+
 296+typedef struct {
 297+	struct wlr_pointer_constraint_v1 *constraint;
 298+	struct wl_listener destroy;
 299+} PointerConstraint;
 300+
 301+typedef struct {
 302+	const char *id;
 303+	const char *title;
 304+	uint32_t tags;
 305+	int isfloating;
 306+	int monitor;
 307+} Rule;
 308+
 309+typedef struct {
 310+	struct wlr_scene_tree *scene;
 311+
 312+	struct wlr_session_lock_v1 *lock;
 313+	struct wl_listener new_surface;
 314+	struct wl_listener unlock;
 315+	struct wl_listener destroy;
 316+} SessionLock;
 317+
 318+/* tablet-input */
 319+typedef struct {
 320+    uint32_t button;
 321+    uint32_t state;
 322+    void (*func)(const Arg *);
 323+    const Arg arg;
 324+} TabletPadButton;
 325+
 326+typedef struct {
 327+    uint32_t button;
 328+    uint32_t state;
 329+    void (*func)(const Arg *);
 330+    const Arg arg;
 331+} TabletButton;
 332+/* tablet-input end */
 333+
 334+/* function declarations */
 335+static void applybounds(Client *c, struct wlr_box *bbox);
 336+static void applyrules(Client *c);
 337+static void arrange(Monitor *m);
 338+static void arrangelayer(Monitor *m, struct wl_list *list,
 339+		struct wlr_box *usable_area, int exclusive);
 340+static void arrangelayers(Monitor *m);
 341+static void axisnotify(struct wl_listener *listener, void *data);
 342+static void buttonpress(struct wl_listener *listener, void *data);
 343+static void chvt(const Arg *arg);
 344+static void checkidleinhibitor(struct wlr_surface *exclude);
 345+static void cleanup(void);
 346+static void cleanupmon(struct wl_listener *listener, void *data);
 347+static void cleanuplisteners(void);
 348+static void closemon(Monitor *m);
 349+static void commitlayersurfacenotify(struct wl_listener *listener, void *data);
 350+static void commitnotify(struct wl_listener *listener, void *data);
 351+static void commitpopup(struct wl_listener *listener, void *data);
 352+static void createdecoration(struct wl_listener *listener, void *data);
 353+static void createidleinhibitor(struct wl_listener *listener, void *data);
 354+static void createkeyboard(struct wlr_keyboard *keyboard);
 355+static KeyboardGroup *createkeyboardgroup(void);
 356+static void createlayersurface(struct wl_listener *listener, void *data);
 357+static void createlocksurface(struct wl_listener *listener, void *data);
 358+static void createmon(struct wl_listener *listener, void *data);
 359+static void createnotify(struct wl_listener *listener, void *data);
 360+static void createpointer(struct wlr_pointer *pointer);
 361+static void createpointerconstraint(struct wl_listener *listener, void *data);
 362+static void createpopup(struct wl_listener *listener, void *data);
 363+static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
 364+static void cursorframe(struct wl_listener *listener, void *data);
 365+static void cursorwarptohint(void);
 366+static void destroydecoration(struct wl_listener *listener, void *data);
 367+static void destroydragicon(struct wl_listener *listener, void *data);
 368+static void destroyidleinhibitor(struct wl_listener *listener, void *data);
 369+static void destroylayersurfacenotify(struct wl_listener *listener, void *data);
 370+static void destroylock(SessionLock *lock, int unlocked);
 371+static void destroylocksurface(struct wl_listener *listener, void *data);
 372+static void destroynotify(struct wl_listener *listener, void *data);
 373+static void destroypointerconstraint(struct wl_listener *listener, void *data);
 374+static void destroysessionlock(struct wl_listener *listener, void *data);
 375+static void destroykeyboardgroup(struct wl_listener *listener, void *data);
 376+static Monitor *dirtomon(enum wlr_direction dir);
 377+static void focusclient(Client *c, int lift);
 378+static void focusmon(const Arg *arg);
 379+static void focusstack(const Arg *arg);
 380+static Client *focustop(Monitor *m);
 381+static void fullscreennotify(struct wl_listener *listener, void *data);
 382+static void gpureset(struct wl_listener *listener, void *data);
 383+static void handlesig(int signo);
 384+static void incnmaster(const Arg *arg);
 385+static void inputdevice(struct wl_listener *listener, void *data);
 386+static int keybinding(uint32_t mods, xkb_keysym_t sym);
 387+static void keypress(struct wl_listener *listener, void *data);
 388+static void keypressmod(struct wl_listener *listener, void *data);
 389+static int keyrepeat(void *data);
 390+static void killclient(const Arg *arg);
 391+static void locksession(struct wl_listener *listener, void *data);
 392+static void mapnotify(struct wl_listener *listener, void *data);
 393+static void maximizenotify(struct wl_listener *listener, void *data);
 394+static void monocle(Monitor *m);
 395+static void motionabsolute(struct wl_listener *listener, void *data);
 396+static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx,
 397+		double sy, double sx_unaccel, double sy_unaccel);
 398+static void motionrelative(struct wl_listener *listener, void *data);
 399+static void moveresize(const Arg *arg);
 400+static void outputmgrapply(struct wl_listener *listener, void *data);
 401+static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test);
 402+static void outputmgrtest(struct wl_listener *listener, void *data);
 403+static void pointerfocus(Client *c, struct wlr_surface *surface,
 404+		double sx, double sy, uint32_t time);
 405+static void printstatus(void);
 406+static void powermgrsetmode(struct wl_listener *listener, void *data);
 407+static void quit(const Arg *arg);
 408+static void rendermon(struct wl_listener *listener, void *data);
 409+static void requestdecorationmode(struct wl_listener *listener, void *data);
 410+static void requeststartdrag(struct wl_listener *listener, void *data);
 411+static void requestmonstate(struct wl_listener *listener, void *data);
 412+static void resize(Client *c, struct wlr_box geo, int interact);
 413+static void run(char *startup_cmd);
 414+static void setcursor(struct wl_listener *listener, void *data);
 415+static void setcursorshape(struct wl_listener *listener, void *data);
 416+static void setfloating(Client *c, int floating);
 417+static void setfullscreen(Client *c, int fullscreen);
 418+static void setlayout(const Arg *arg);
 419+static void setmfact(const Arg *arg);
 420+static void setmon(Client *c, Monitor *m, uint32_t newtags);
 421+static void setpsel(struct wl_listener *listener, void *data);
 422+static void setsel(struct wl_listener *listener, void *data);
 423+static void setup(void);
 424+static void spawn(const Arg *arg);
 425+static void startdrag(struct wl_listener *listener, void *data);
 426+static void tag(const Arg *arg);
 427+static void tagmon(const Arg *arg);
 428+#ifdef TILING
 429+static void tile(Monitor *m);
 430+static void togglefloating(const Arg *arg);
 431+#endif // togglefloating is in #ifdef too because why would you need it without tiling?
 432+static void togglefullscreen(const Arg *arg);
 433+static void togglefakefullscreen(const Arg *arg);
 434+static void snaptoposition(const Arg *arg);
 435+static void toggletag(const Arg *arg);
 436+static void toggleview(const Arg *arg);
 437+static void unlocksession(struct wl_listener *listener, void *data);
 438+static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
 439+static void unmapnotify(struct wl_listener *listener, void *data);
 440+static void updatemons(struct wl_listener *listener, void *data);
 441+static void updatetitle(struct wl_listener *listener, void *data);
 442+static void urgent(struct wl_listener *listener, void *data);
 443+static void view(const Arg *arg);
 444+static void virtualkeyboard(struct wl_listener *listener, void *data);
 445+static void virtualpointer(struct wl_listener *listener, void *data);
 446+static Monitor *xytomon(double x, double y);
 447+static void xytonode(double x, double y, struct wlr_surface **psurface,
 448+		Client **pc, LayerSurface **pl, double *nx, double *ny);
 449+static void swapmaster(const Arg *arg);
 450+/* infinite_canvas */
 451+static int getcurrenttag(Monitor *m);
 452+static void canvas_move_window(Client *c, int x, int y);
 453+static void snap_edges(Client *c, Monitor *m, int *nx, int *ny);
 454+static void resize_magnetically(Client *c, Monitor *m, struct wlr_box *geo);
 455+static void homecanvas(const Arg *arg);
 456+static void movecanvas(const Arg *arg);
 457+static void movewinbykeys(const Arg *arg);
 458+static void resizewinbykeys(const Arg *arg);
 459+static void movecanvasmouse(const Arg *arg);
 460+static void centerwindow(const Arg *arg);
 461+static void bringintoview(Client *c);
 462+static void save_canvas_positions(Monitor *m);
 463+static void restore_canvas_positions(Monitor *m);
 464+/* infinite_canvas_end */
 465+/* zoom */
 466+static void zoom(const Arg *arg);
 467+static void zoomreset(const Arg *arg);
 468+static void zoom_apply(Monitor *m);
 469+static void zoom_update_scene_client(Client *c);
 470+static void zoom_scale_buffers(struct wlr_scene_buffer *buf, int sx, int sy, void *data);
 471+static void zoom_frame(Monitor *m);
 472+static void popup_zoom_commit(struct wl_listener *listener, void *data);
 473+static void popup_zoom_destroy(struct wl_listener *listener, void *data);
 474+/* zoom end */
 475+/* spawnregion */
 476+static void spawnregion(const Arg *arg);
 477+static void spawnregion_update_rect(void);
 478+static void spawnregion_finish(void);
 479+/* spawnregion_end */
 480+#ifdef TILING
 481+void arrangegaps(Monitor *m);
 482+static void defaultgaps(const Arg *arg);
 483+static void incgaps(const Arg *arg);
 484+static void incigaps(const Arg *arg);
 485+static void incihgaps(const Arg *arg);
 486+static void incivgaps(const Arg *arg);
 487+static void incogaps(const Arg *arg);
 488+static void incohgaps(const Arg *arg);
 489+static void incovgaps(const Arg *arg);
 490+static void preparegaps(Monitor *m);
 491+static void setgaps(int oh, int ov, int ih, int iv);
 492+static void togglegaps(const Arg *arg);
 493+#endif
 494+/* tablet-input */
 495+static void createtablet(struct wlr_input_device *device);
 496+static void destroytablet(struct wl_listener *listener, void *data);
 497+static void destroytabletpad(struct wl_listener *listener, void *data);
 498+static void destroytabletsurfacenotify(struct wl_listener *listener, void *data);
 499+static void destroytablettool(struct wl_listener *listener, void *data);
 500+static void tablettoolmotion(struct wlr_tablet_v2_tablet_tool *tool, bool change_x, bool change_y, double x, double y, double dx, double dy);
 501+static void tablettoolproximity(struct wl_listener *listener, void *data);
 502+static void tabletpadbutton(struct wl_listener *listener, void *data);
 503+static void tablettoolaxis(struct wl_listener *listener, void *data);
 504+static void tablettoolbutton(struct wl_listener *listener, void *data);
 505+static void tablettooltip(struct wl_listener *listener, void *data);
 506+/* tablet-input end */
 507+
 508+/* variables */
 509+static pid_t child_pid = -1;
 510+static int locked;
 511+static void *exclusive_focus;
 512+static struct wl_display *dpy;
 513+static struct wl_event_loop *event_loop;
 514+static struct wlr_backend *backend;
 515+static struct wlr_scene *scene;
 516+static struct wlr_scene_tree *layers[NUM_LAYERS];
 517+static struct wlr_scene_tree *drag_icon;
 518+/* Map from ZWLR_LAYER_SHELL_* constants to Lyr* enum */
 519+static const int layermap[] = { LyrBg, LyrBottom, LyrTop, LyrOverlay };
 520+static struct wlr_renderer *drw;
 521+static struct wlr_allocator *alloc;
 522+static struct wlr_compositor *compositor;
 523+static struct wlr_session *session;
 524+
 525+/* tablet-input */
 526+static struct wlr_tablet_manager_v2 *tablet_mgr;
 527+static struct wlr_tablet_v2_tablet *tablet = NULL;
 528+static struct wlr_tablet_v2_tablet_tool *tablet_tool = NULL;
 529+static struct wlr_tablet_v2_tablet_pad *tablet_pad = NULL;
 530+static struct wlr_surface *tablet_curr_surface = NULL;
 531+static struct wl_listener destroy_tablet_surface_listener = {.notify = destroytabletsurfacenotify};
 532+
 533+static struct wl_listener tablet_device_destroy = {.notify = destroytablet};
 534+static struct wl_listener tablet_pad_destroy = {.notify = destroytabletpad};
 535+static struct wl_listener tablet_pad_button = {.notify = tabletpadbutton};
 536+static struct wl_listener tablet_tool_axis = {.notify = tablettoolaxis};
 537+static struct wl_listener tablet_tool_button = {.notify = tablettoolbutton};
 538+static struct wl_listener tablet_tool_destroy = {.notify = destroytablettool};
 539+static struct wl_listener tablet_tool_proximity = {.notify = tablettoolproximity};
 540+static struct wl_listener tablet_tool_tip = {.notify = tablettooltip};
 541+/* tablet-input end */
 542+
 543+static struct wlr_xdg_shell *xdg_shell;
 544+static struct wlr_xdg_activation_v1 *activation;
 545+static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr;
 546+static struct wl_list clients; /* tiling order */
 547+static struct wl_list fstack;  /* focus order */
 548+static struct wlr_idle_notifier_v1 *idle_notifier;
 549+static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr;
 550+static struct wlr_layer_shell_v1 *layer_shell;
 551+static struct wlr_output_manager_v1 *output_mgr;
 552+static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;
 553+static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr;
 554+static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr;
 555+static struct wlr_output_power_manager_v1 *power_mgr;
 556+
 557+static struct wlr_pointer_constraints_v1 *pointer_constraints;
 558+static struct wlr_pointer_gestures_v1 *pointer_gestures;
 559+static struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr;
 560+static struct wlr_pointer_constraint_v1 *active_constraint;
 561+
 562+static struct wlr_cursor *cursor;
 563+static struct wlr_xcursor_manager *cursor_mgr;
 564+
 565+static struct wlr_scene_rect *root_bg;
 566+static struct wlr_session_lock_manager_v1 *session_lock_mgr;
 567+static struct wlr_scene_rect *locked_bg;
 568+static struct wlr_session_lock_v1 *cur_lock;
 569+
 570+static struct wlr_seat *seat;
 571+static KeyboardGroup *kb_group;
 572+static unsigned int cursor_mode;
 573+static Client *grabc;
 574+static int grabcx, grabcy; /* client-relative */
 575+static struct wl_event_source *openanim_timer = NULL;
 576+static Client *openanim_client = NULL;
 577+static uint64_t openanim_start_ms = 0;
 578+static int openanim_running = 0;
 579+/* zoom */
 580+static double resize_grab_world_x = 0.0;
 581+static double resize_grab_world_y = 0.0;
 582+static int resize_snap_x_target = 0;
 583+static int resize_snap_y_target = 0;
 584+typedef struct {
 585+	struct wl_list link;
 586+	struct wl_listener commit;
 587+	struct wl_listener destroy;
 588+	Client *client;
 589+	struct wlr_xdg_popup *popup;
 590+	struct wlr_scene_node *node;
 591+} PopupZoomData;
 592+static struct wl_list popup_zoom_list;
 593+/* zoom end */
 594+
 595+/* infinite_canvas */
 596+static int canvas_panning = 0;
 597+static double canvas_pan_last_x = 0, canvas_pan_last_y = 0;
 598+static float canvas_pan_multiplier = 1.0f;
 599+static float canvas_pan_accum_x = 0.0f, canvas_pan_accum_y = 0.0f;
 600+/* infinite_canvas_end */
 601+/* spawnregion */
 602+static int spawnregion_active = 0;
 603+static double spawnregion_x1 = 0, spawnregion_y1 = 0;
 604+static double spawnregion_x2 = 0, spawnregion_y2 = 0;
 605+static struct wlr_scene_rect *spawnregion_rect = NULL;
 606+static struct wlr_box pending_spawn_geo = {0};
 607+static int has_pending_spawn_geo = 0;
 608+Client *waiting_geo_client = NULL;
 609+/* spawnregion_end */
 610+
 611+static struct wlr_output_layout *output_layout;
 612+static struct wlr_box sgeom;
 613+static struct wl_list mons;
 614+static Monitor *selmon;
 615+static struct wl_list savedstates;
 616+
 617+#ifdef TILING
 618+static int resizelock = 0;   /* do not actually resize during arrange */
 619+#endif
 620+
 621+/* global event handlers */
 622+static struct wl_listener cursor_axis = {.notify = axisnotify};
 623+static struct wl_listener cursor_button = {.notify = buttonpress};
 624+static struct wl_listener cursor_frame = {.notify = cursorframe};
 625+static struct wl_listener cursor_motion = {.notify = motionrelative};
 626+static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute};
 627+static struct wl_listener gpu_reset = {.notify = gpureset};
 628+static struct wl_listener layout_change = {.notify = updatemons};
 629+static struct wl_listener new_idle_inhibitor = {.notify = createidleinhibitor};
 630+static struct wl_listener new_input_device = {.notify = inputdevice};
 631+static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard};
 632+static struct wl_listener new_virtual_pointer = {.notify = virtualpointer};
 633+static struct wl_listener new_pointer_constraint = {.notify = createpointerconstraint};
 634+static struct wl_listener new_output = {.notify = createmon};
 635+static struct wl_listener new_xdg_toplevel = {.notify = createnotify};
 636+static struct wl_listener new_xdg_popup = {.notify = createpopup};
 637+static struct wl_listener new_xdg_decoration = {.notify = createdecoration};
 638+static struct wl_listener new_layer_surface = {.notify = createlayersurface};
 639+static struct wl_listener output_mgr_apply = {.notify = outputmgrapply};
 640+static struct wl_listener output_mgr_test = {.notify = outputmgrtest};
 641+static struct wl_listener output_power_mgr_set_mode = {.notify = powermgrsetmode};
 642+static struct wl_listener request_activate = {.notify = urgent};
 643+static struct wl_listener request_cursor = {.notify = setcursor};
 644+static struct wl_listener request_set_psel = {.notify = setpsel};
 645+static struct wl_listener request_set_sel = {.notify = setsel};
 646+static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape};
 647+static struct wl_listener request_start_drag = {.notify = requeststartdrag};
 648+static struct wl_listener start_drag = {.notify = startdrag};
 649+static struct wl_listener new_session_lock = {.notify = locksession};
 650+
 651+#ifdef XWAYLAND
 652+static void activatex11(struct wl_listener *listener, void *data);
 653+static void associatex11(struct wl_listener *listener, void *data);
 654+static void configurex11(struct wl_listener *listener, void *data);
 655+static void createnotifyx11(struct wl_listener *listener, void *data);
 656+static void dissociatex11(struct wl_listener *listener, void *data);
 657+static void sethints(struct wl_listener *listener, void *data);
 658+static void xwaylandready(struct wl_listener *listener, void *data);
 659+static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11};
 660+static struct wl_listener xwayland_ready = {.notify = xwaylandready};
 661+static struct wlr_xwayland *xwayland;
 662+#endif
 663+
 664+/* zoom */
 665+#define SCROLL_UP 0x14b
 666+#define SCROLL_DOWN 0x14c
 667+/* zoom end */
 668+
 669+/* configuration, allows nested code to access above variables */
 670+#include "config.h"
 671+
 672+/* spawnregion, define it after config.h was included so SPAWNREGION_STYLE is defined */ 
 673+#if SPAWNREGION_STYLE == 2
 674+static struct wlr_scene_rect *spawnregion_border[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
 675+#endif
 676+/* spawnregion end */
 677+
 678+#ifndef SPAWNREGION_COLOR
 679+#define SPAWNREGION_COLOR { 0.2f, 0.5f, 1.0f, 0.35f }
 680+#endif
 681+
 682+/* zoom */
 683+#ifndef ZOOMMIN
 684+#define ZOOMMIN 0.1
 685+#endif
 686+#ifndef ZOOMMAX
 687+#define ZOOMMAX 5.0
 688+#endif
 689+#ifndef animatezoom
 690+#define animatezoom 1
 691+#endif
 692+#ifndef zoomduration
 693+#define zoomduration 0.18
 694+#endif
 695+#ifndef zoombezier
 696+#define zoombezier "0.22,1.0,0.36,1.0"
 697+#endif
 698+#ifndef movecanvasmouse_multiplier_is_affected_by_zoom
 699+#define movecanvasmouse_multiplier_is_affected_by_zoom 1
 700+#endif
 701+/* zoom end */
 702+
 703+/* attempt to encapsulate suck into one file */
 704+#include "client.h"
 705+
 706+/* function implementations */
 707+void
 708+applybounds(Client *c, struct wlr_box *bbox)
 709+{
 710+	/* set minimum possible */
 711+	c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width);
 712+	c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height);
 713+
 714+	if (c->geom.x >= bbox->x + bbox->width)
 715+		c->geom.x = bbox->x + bbox->width - c->geom.width;
 716+	if (c->geom.y >= bbox->y + bbox->height)
 717+		c->geom.y = bbox->y + bbox->height - c->geom.height;
 718+	if (c->geom.x + c->geom.width <= bbox->x)
 719+		c->geom.x = bbox->x;
 720+	if (c->geom.y + c->geom.height <= bbox->y)
 721+		c->geom.y = bbox->y;
 722+}
 723+
 724+void
 725+applyrules(Client *c)
 726+{
 727+	/* rule matching */
 728+	const char *appid, *title;
 729+	uint32_t newtags = 0;
 730+	int i;
 731+	const Rule *r;
 732+	Monitor *mon = selmon, *m;
 733+
 734+	appid = client_get_appid(c);
 735+	title = client_get_title(c);
 736+
 737+	for (r = rules; r < END(rules); r++) {
 738+		if ((!r->title || strstr(title, r->title))
 739+				&& (!r->id || strstr(appid, r->id))) {
 740+			c->isfloating = r->isfloating;
 741+			newtags |= r->tags;
 742+			i = 0;
 743+			wl_list_for_each(m, &mons, link) {
 744+				if (r->monitor == i++)
 745+					mon = m;
 746+			}
 747+		}
 748+	}
 749+
 750+	c->isfloating |= client_is_float_type(c);
 751+	setmon(c, mon, newtags);
 752+}
 753+
 754+void
 755+arrange(Monitor *m)
 756+{
 757+	Client *c;
 758+
 759+	if (!m->wlr_output->enabled)
 760+		return;
 761+
 762+	wl_list_for_each(c, &clients, link) {
 763+		if (c->mon == m) {
 764+			wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m) && c != waiting_geo_client);
 765+			client_set_suspended(c, !VISIBLEON(c, m));
 766+		}
 767+	}
 768+
 769+	wlr_scene_node_set_enabled(&m->fullscreen_bg->node,
 770+			(c = focustop(m)) && c->isfullscreen);
 771+
 772+	strncpy(m->ltsymbol, layouts[0].symbol, LENGTH(m->ltsymbol));
 773+
 774+	/* We move all clients (except fullscreen and unmanaged) to LyrTile while
 775+	 * in floating layout to avoid "real" floating clients be always on top */
 776+	wl_list_for_each(c, &clients, link) {
 777+		if (c->mon != m || c->scene->node.parent == layers[LyrFS])
 778+			continue;
 779+
 780+		wlr_scene_node_reparent(&c->scene->node,
 781+				(m->lt[m->sellt] && !m->lt[m->sellt]->arrange && c->isfloating)
 782+						? layers[LyrTile]
 783+						: (m->lt[m->sellt] && m->lt[m->sellt]->arrange && c->isfloating)
 784+								? layers[LyrFloat]
 785+								: c->scene->node.parent);
 786+	}
 787+
 788+	if (m->lt[m->sellt] && m->lt[m->sellt]->arrange) {
 789+#ifdef TILING
 790+    preparegaps(m);
 791+#endif
 792+		m->lt[m->sellt]->arrange(m);
 793+#ifdef TILING
 794+    arrangegaps(m);
 795+#endif
 796+  }
 797+	/* zoom */
 798+	if (layouts[m->sellt].arrange == NULL)
 799+		zoom_apply(m);
 800+	/* zoom end */
 801+	motionnotify(0, NULL, 0, 0, 0, 0);
 802+	checkidleinhibitor(NULL);
 803+}
 804+
 805+void
 806+arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive)
 807+{
 808+	LayerSurface *l;
 809+	struct wlr_box full_area = m->m;
 810+
 811+	wl_list_for_each(l, list, link) {
 812+		struct wlr_layer_surface_v1 *layer_surface = l->layer_surface;
 813+
 814+		if (!layer_surface->initialized)
 815+			continue;
 816+
 817+		if (exclusive != (layer_surface->current.exclusive_zone > 0))
 818+			continue;
 819+
 820+		wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, usable_area);
 821+		wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, l->scene->node.y);
 822+	}
 823+}
 824+
 825+void
 826+arrangelayers(Monitor *m)
 827+{
 828+	int i;
 829+	struct wlr_box usable_area = m->m;
 830+	LayerSurface *l;
 831+	uint32_t layers_above_shell[] = {
 832+		ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
 833+		ZWLR_LAYER_SHELL_V1_LAYER_TOP,
 834+	};
 835+	if (!m->wlr_output->enabled)
 836+		return;
 837+
 838+	/* Arrange exclusive surfaces from top->bottom */
 839+	for (i = 3; i >= 0; i--)
 840+		arrangelayer(m, &m->layers[i], &usable_area, 1);
 841+
 842+	if (!wlr_box_equal(&usable_area, &m->w)) {
 843+		m->w = usable_area;
 844+		arrange(m);
 845+	}
 846+
 847+	/* Arrange non-exclusive surfaces from top->bottom */
 848+	for (i = 3; i >= 0; i--)
 849+		arrangelayer(m, &m->layers[i], &usable_area, 0);
 850+
 851+	/* Find topmost keyboard interactive layer, if such a layer exists */
 852+	for (i = 0; i < (int)LENGTH(layers_above_shell); i++) {
 853+		wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) {
 854+			if (locked || !l->layer_surface->current.keyboard_interactive || !l->mapped)
 855+				continue;
 856+			/* Deactivate the focused client. */
 857+			focusclient(NULL, 0);
 858+			exclusive_focus = l;
 859+			client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat));
 860+			return;
 861+		}
 862+	}
 863+}
 864+
 865+void
 866+axisnotify(struct wl_listener *listener, void *data)
 867+{
 868+  /* click */
 869+  unsigned int click;
 870+  Client *c;
 871+  LayerSurface *l;
 872+  /* click end */
 873+	struct wlr_pointer_axis_event *event = data;
 874+	struct wlr_keyboard *keyboard;
 875+	uint32_t mods;
 876+	const Button *b;
 877+
 878+	wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
 879+  
 880+  /* click */
 881+  click = ClkRoot;
 882+	xytonode(cursor->x, cursor->y, NULL, &c, &l, NULL, NULL);
 883+	if (c)
 884+		click = ClkClient;
 885+	else if (l)
 886+		click = ClkLayerShell;
 887+  /* click end */
 888+
 889+	keyboard = wlr_seat_get_keyboard(seat);
 890+	mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
 891+
 892+	if (event->orientation == WL_POINTER_AXIS_VERTICAL_SCROLL) {
 893+		/* zoom */
 894+		unsigned int btn = (event->delta > 0 || event->delta_discrete > 0)
 895+				? SCROLL_DOWN : SCROLL_UP;
 896+		for (b = buttons; b < END(buttons); b++) {
 897+			if (CLEANMASK(mods) == CLEANMASK(b->mod)
 898+          //                  /       click       /
 899+					&& btn == b->button && click == b->click && b->func) {
 900+				b->func(&b->arg);
 901+				return;
 902+			}
 903+		}
 904+		/* zoom end */
 905+	}
 906+
 907+	wlr_seat_pointer_notify_axis(seat,
 908+			event->time_msec, event->orientation, event->delta,
 909+			event->delta_discrete, event->source, event->relative_direction);
 910+}
 911+
 912+void
 913+buttonpress(struct wl_listener *listener, void *data)
 914+{
 915+  /* click */
 916+	unsigned int click;
 917+  /* click end */
 918+	struct wlr_pointer_button_event *event = data;
 919+	struct wlr_keyboard *keyboard;
 920+	uint32_t mods;
 921+	Client *c;
 922+	LayerSurface *l;
 923+	const Button *b;
 924+
 925+	wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
 926+
 927+  /* click */
 928+  click = ClkRoot;
 929+	xytonode(cursor->x, cursor->y, NULL, &c, &l, NULL, NULL);
 930+	if (c)
 931+		click = ClkClient;
 932+	else if (l)
 933+		click = ClkLayerShell;
 934+	wlr_log(WLR_DEBUG, "buttonpress: c=%p l=%p click=%u (0=Client,1=LayerShell,2=Root)", (void*)c, (void*)l, click);
 935+  /* click end */
 936+
 937+	switch (event->state) {
 938+	case WL_POINTER_BUTTON_STATE_PRESSED:
 939+		cursor_mode = CurPressed;
 940+		selmon = xytomon(cursor->x, cursor->y);
 941+		if (locked)
 942+			break;
 943+
 944+		/* spawnregion */
 945+		if (spawnregion_active && event->button == BTN_LEFT) {
 946+			spawnregion_x1 = cursor->x;
 947+			spawnregion_y1 = cursor->y;
 948+			spawnregion_x2 = cursor->x;
 949+			spawnregion_y2 = cursor->y;
 950+#if SPAWNREGION_STYLE == 2
 951+			{
 952+				int i;
 953+				for (i = 0; i < 4; i++) {
 954+					if (!spawnregion_border[i]) {
 955+						const float *oc = spawnregion_outer_border_color;
 956+						spawnregion_border[i] = wlr_scene_rect_create(layers[LyrBlock],
 957+							1, 1, (float[4]){oc[0], oc[1], oc[2], oc[3]});
 958+					}
 959+				}
 960+				for (i = 4; i < 8; i++) {
 961+					if (!spawnregion_border[i]) {
 962+						const float *ic = spawnregion_inner_border_color;
 963+						spawnregion_border[i] = wlr_scene_rect_create(layers[LyrBlock],
 964+							1, 1, (float[4]){ic[0], ic[1], ic[2], ic[3]});
 965+					}
 966+				}
 967+			}
 968+#else
 969+			if (!spawnregion_rect)
 970+#  if SPAWNREGION_STYLE == 1
 971+				spawnregion_rect = wlr_scene_rect_create(layers[LyrBlock],
 972+					1, 1, (float[4])SPAWNREGION_COLOR);
 973+#  else
 974+				spawnregion_rect = wlr_scene_rect_create(layers[LyrBlock],
 975+					1, 1, (float[4]){0.2f, 0.5f, 1.0f, 0.0f});
 976+#  endif
 977+			wlr_scene_node_set_position(&spawnregion_rect->node,
 978+				(int)spawnregion_x1, (int)spawnregion_y1);
 979+			wlr_scene_rect_set_size(spawnregion_rect, 1, 1);
 980+			wlr_scene_node_set_enabled(&spawnregion_rect->node, 1);
 981+#endif
 982+			cursor_mode = CurSpawnRegion;
 983+			return;
 984+		}
 985+		/* spawnregion_end */
 986+
 987+		/* Change focus if the button was _pressed_ over a client */
 988+		xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL);
 989+		// if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) // not click
 990+    if (click == ClkClient && (!client_is_unmanaged(c) || client_wants_focus(c))) // click
 991+			focusclient(c, 1);
 992+
 993+		keyboard = wlr_seat_get_keyboard(seat);
 994+		mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
 995+		for (b = buttons; b < END(buttons); b++) {
 996+			if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
 997+          //                         /     click        /
 998+					event->button == b->button && click == b->click && b->func) {
 999+				b->func(&b->arg);
1000+				return;
1001+			}
1002+		}
1003+		break;
1004+	case WL_POINTER_BUTTON_STATE_RELEASED:
1005+		/* If you released any buttons, we exit interactive move/resize mode. */
1006+		/* TODO: should reset to the pointer focus's current setcursor */
1007+		if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
1008+			/* infinite_canvas */
1009+			if (canvas_panning) {
1010+				canvas_panning = 0;
1011+				wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
1012+				cursor_mode = CurNormal;
1013+				return;
1014+			}
1015+			/* infinite_canvas_end */
1016+			/* spawnregion */
1017+			if (cursor_mode == CurSpawnRegion) {
1018+				spawnregion_finish();
1019+				return;
1020+			}
1021+			/* spawnregion_end */
1022+			wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
1023+			cursor_mode = CurNormal;
1024+			/* infinite_canvas: a manual move/resize just finished
1025+			 * under whatever pan is currently active -- that's now
1026+			 * this window's natural framing for future teleports. */
1027+			if (grabc && grabc->mon) {
1028+				int tagidx = getcurrenttag(grabc->mon);
1029+				grabc->home_cx = grabc->mon->canvas[tagidx].cx;
1030+				grabc->home_cy = grabc->mon->canvas[tagidx].cy;
1031+			}
1032+			/* infinite_canvas_end */
1033+			/* Drop the window off on its new monitor */
1034+			selmon = xytomon(cursor->x, cursor->y);
1035+			setmon(grabc, selmon, 0);
1036+			grabc = NULL;
1037+			return;
1038+		}
1039+		cursor_mode = CurNormal;
1040+		break;
1041+	}
1042+	/* If the event wasn't handled by the compositor, notify the client with
1043+	 * pointer focus that a button press has occurred */
1044+	wlr_seat_pointer_notify_button(seat,
1045+			event->time_msec, event->button, event->state);
1046+}
1047+
1048+void
1049+chvt(const Arg *arg)
1050+{
1051+	wlr_session_change_vt(session, arg->ui);
1052+}
1053+
1054+void
1055+checkidleinhibitor(struct wlr_surface *exclude)
1056+{
1057+	int inhibited = 0, unused_lx, unused_ly;
1058+	struct wlr_idle_inhibitor_v1 *inhibitor;
1059+	wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) {
1060+		struct wlr_surface *surface = wlr_surface_get_root_surface(inhibitor->surface);
1061+		struct wlr_scene_tree *tree = surface->data;
1062+		if (exclude != surface && (bypass_surface_visibility || (!tree
1063+				|| wlr_scene_node_coords(&tree->node, &unused_lx, &unused_ly)))) {
1064+			inhibited = 1;
1065+			break;
1066+		}
1067+	}
1068+
1069+	wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited);
1070+}
1071+
1072+void
1073+cleanup(void)
1074+{
1075+	cleanuplisteners();
1076+#ifdef XWAYLAND
1077+	wlr_xwayland_destroy(xwayland);
1078+	xwayland = NULL;
1079+#endif
1080+	wl_display_destroy_clients(dpy);
1081+	if (child_pid > 0) {
1082+		kill(-child_pid, SIGTERM);
1083+		waitpid(child_pid, NULL, 0);
1084+	}
1085+	wlr_xcursor_manager_destroy(cursor_mgr);
1086+
1087+	destroykeyboardgroup(&kb_group->destroy, NULL);
1088+
1089+	/* If it's not destroyed manually, it will cause a use-after-free of wlr_seat.
1090+	 * Destroy it until it's fixed on the wlroots side */
1091+	wlr_backend_destroy(backend);
1092+
1093+	wl_display_destroy(dpy);
1094+	/* Destroy after the wayland display (when the monitors are already destroyed)
1095+	   to avoid destroying them with an invalid scene output. */
1096+	wlr_scene_node_destroy(&scene->tree.node);
1097+}
1098+
1099+void
1100+cleanupmon(struct wl_listener *listener, void *data)
1101+{
1102+	Monitor *m = wl_container_of(listener, m, destroy);
1103+	LayerSurface *l, *tmp;
1104+	size_t i;
1105+
1106+	/* m->layers[i] are intentionally not unlinked */
1107+	for (i = 0; i < LENGTH(m->layers); i++) {
1108+		wl_list_for_each_safe(l, tmp, &m->layers[i], link)
1109+			wlr_layer_surface_v1_destroy(l->layer_surface);
1110+	}
1111+
1112+	wl_list_remove(&m->destroy.link);
1113+	wl_list_remove(&m->frame.link);
1114+	wl_list_remove(&m->link);
1115+	wl_list_remove(&m->request_state.link);
1116+	if (m->lock_surface)
1117+		destroylocksurface(&m->destroy_lock_surface, NULL);
1118+	m->wlr_output->data = NULL;
1119+	wlr_output_layout_remove(output_layout, m->wlr_output);
1120+	wlr_scene_output_destroy(m->scene_output);
1121+
1122+	closemon(m);
1123+	wlr_scene_node_destroy(&m->fullscreen_bg->node);
1124+	/* infinite_canvas */
1125+	{
1126+		MonitorState *ms, *tmp_ms;
1127+		wl_list_for_each_safe(ms, tmp_ms, &savedstates, link) {
1128+			if (strcmp(ms->name, m->wlr_output->name) == 0) {
1129+				wl_list_remove(&ms->link);
1130+				free(ms->canvas);
1131+				free(ms);
1132+				break;
1133+			}
1134+		}
1135+		ms = ecalloc(1, sizeof(MonitorState));
1136+		strncpy(ms->name, m->wlr_output->name, sizeof(ms->name) - 1);
1137+		ms->seltags = m->seltags;
1138+		ms->sellt = m->sellt;
1139+		ms->tagset[0] = m->tagset[0];
1140+		ms->tagset[1] = m->tagset[1];
1141+		ms->mfact = m->mfact;
1142+		ms->nmaster = m->nmaster;
1143+		strncpy(ms->ltsymbol, m->ltsymbol, sizeof(ms->ltsymbol));
1144+		ms->lt[0] = m->lt[0];
1145+		ms->lt[1] = m->lt[1];
1146+		ms->canvas = m->canvas;
1147+		m->canvas = NULL;
1148+		ms->zoom_scale = m->zoom_scale;
1149+		ms->zoom_target = m->zoom_target;
1150+		ms->zoom_pan_x = m->zoom_pan_x;
1151+		ms->zoom_pan_y = m->zoom_pan_y;
1152+		wl_list_insert(&savedstates, &ms->link);
1153+	}
1154+	/* infinite_canvas_end */
1155+	free(m);
1156+}
1157+
1158+void
1159+cleanuplisteners(void)
1160+{
1161+	wl_list_remove(&cursor_axis.link);
1162+	wl_list_remove(&cursor_button.link);
1163+	wl_list_remove(&cursor_frame.link);
1164+	wl_list_remove(&cursor_motion.link);
1165+	wl_list_remove(&cursor_motion_absolute.link);
1166+	wl_list_remove(&gpu_reset.link);
1167+	wl_list_remove(&new_idle_inhibitor.link);
1168+	wl_list_remove(&layout_change.link);
1169+	wl_list_remove(&new_input_device.link);
1170+	wl_list_remove(&new_virtual_keyboard.link);
1171+	wl_list_remove(&new_virtual_pointer.link);
1172+	wl_list_remove(&new_pointer_constraint.link);
1173+	wl_list_remove(&new_output.link);
1174+	wl_list_remove(&new_xdg_toplevel.link);
1175+	wl_list_remove(&new_xdg_decoration.link);
1176+	wl_list_remove(&new_xdg_popup.link);
1177+	wl_list_remove(&new_layer_surface.link);
1178+	wl_list_remove(&output_mgr_apply.link);
1179+	wl_list_remove(&output_mgr_test.link);
1180+	wl_list_remove(&output_power_mgr_set_mode.link);
1181+	wl_list_remove(&request_activate.link);
1182+	wl_list_remove(&request_cursor.link);
1183+	wl_list_remove(&request_set_psel.link);
1184+	wl_list_remove(&request_set_sel.link);
1185+	wl_list_remove(&request_set_cursor_shape.link);
1186+	wl_list_remove(&request_start_drag.link);
1187+	wl_list_remove(&start_drag.link);
1188+	wl_list_remove(&new_session_lock.link);
1189+#ifdef XWAYLAND
1190+	wl_list_remove(&new_xwayland_surface.link);
1191+	wl_list_remove(&xwayland_ready.link);
1192+#endif
1193+}
1194+
1195+void
1196+closemon(Monitor *m)
1197+{
1198+	/* update selmon if needed and
1199+	 * move closed monitor's clients to the focused one */
1200+	Client *c;
1201+	int i = 0, nmons = wl_list_length(&mons);
1202+	if (!nmons) {
1203+		selmon = NULL;
1204+	} else if (m == selmon) {
1205+		do /* don't switch to disabled mons */
1206+			selmon = wl_container_of(mons.next, selmon, link);
1207+		while (!selmon->wlr_output->enabled && i++ < nmons);
1208+
1209+		if (!selmon->wlr_output->enabled)
1210+			selmon = NULL;
1211+	}
1212+
1213+	wl_list_for_each(c, &clients, link) {
1214+		if (c->isfloating && c->geom.x > m->m.width)
1215+			resize(c, (struct wlr_box){.x = c->geom.x - m->w.width, .y = c->geom.y,
1216+					.width = c->geom.width, .height = c->geom.height}, 0);
1217+		if (c->mon == m)
1218+			setmon(c, selmon, c->tags);
1219+	}
1220+	focusclient(focustop(selmon), 1);
1221+	printstatus();
1222+}
1223+
1224+void
1225+commitlayersurfacenotify(struct wl_listener *listener, void *data)
1226+{
1227+	LayerSurface *l = wl_container_of(listener, l, surface_commit);
1228+	struct wlr_layer_surface_v1 *layer_surface = l->layer_surface;
1229+	struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->current.layer]];
1230+	struct wlr_layer_surface_v1_state old_state;
1231+
1232+	if (l->layer_surface->initial_commit) {
1233+		client_set_scale(layer_surface->surface, l->mon->wlr_output->scale);
1234+
1235+		/* Temporarily set the layer's current state to pending
1236+		 * so that we can easily arrange it */
1237+		old_state = l->layer_surface->current;
1238+		l->layer_surface->current = l->layer_surface->pending;
1239+		arrangelayers(l->mon);
1240+		l->layer_surface->current = old_state;
1241+		return;
1242+	}
1243+
1244+	if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped)
1245+		return;
1246+	l->mapped = layer_surface->surface->mapped;
1247+
1248+	if (scene_layer != l->scene->node.parent) {
1249+		wlr_scene_node_reparent(&l->scene->node, scene_layer);
1250+		wl_list_remove(&l->link);
1251+		wl_list_insert(&l->mon->layers[layer_surface->current.layer], &l->link);
1252+		wlr_scene_node_reparent(&l->popups->node, (layer_surface->current.layer
1253+				< ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer));
1254+	}
1255+
1256+	arrangelayers(l->mon);
1257+}
1258+
1259+void
1260+commitnotify(struct wl_listener *listener, void *data)
1261+{
1262+	Client *c = wl_container_of(listener, c, commit);
1263+
1264+	if (c->surface.xdg->initial_commit) {
1265+		/*
1266+		 * Get the monitor this client will be rendered on
1267+		 * Note that if the user set a rule in which the client is placed on
1268+		 * a different monitor based on its title, this will likely select
1269+		 * a wrong monitor.
1270+		 */
1271+		applyrules(c);
1272+		if (c->mon) {
1273+			client_set_scale(client_surface(c), c->mon->wlr_output->scale);
1274+		}
1275+		setmon(c, NULL, 0); /* Make sure to reapply rules in mapnotify() */
1276+
1277+		wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel,
1278+				WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
1279+		if (c->decoration)
1280+			requestdecorationmode(&c->set_decoration_mode, c->decoration);
1281+		wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0);
1282+		return;
1283+	}
1284+
1285+	resize(c, c->geom, (c->isfloating && !c->isfullscreen));
1286+
1287+	/* mark a pending resize as completed */
1288+	if (c->resize && c->resize <= c->surface.xdg->current.configure_serial)
1289+		c->resize = 0;
1290+
1291+	/* zoom */
1292+	if (c->mon && fabs(c->mon->zoom_scale - 1.0) >= 1e-9)
1293+		wlr_scene_node_for_each_buffer(&c->scene->node, zoom_scale_buffers, c);
1294+	/* zoom end */
1295+}
1296+
1297+void
1298+commitpopup(struct wl_listener *listener, void *data)
1299+{
1300+	struct wlr_surface *surface = data;
1301+	struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface);
1302+	LayerSurface *l = NULL;
1303+	Client *c = NULL;
1304+	struct wlr_box box;
1305+	int type = -1;
1306+
1307+	if (!popup->base->initial_commit)
1308+		return;
1309+
1310+	type = toplevel_from_wlr_surface(popup->base->surface, &c, &l);
1311+	if (!popup->parent || type < 0)
1312+		return;
1313+	popup->base->surface->data = wlr_scene_xdg_surface_create(
1314+			popup->parent->data, popup->base);
1315+	if ((l && !l->mon) || (c && !c->mon)) {
1316+		wlr_xdg_popup_destroy(popup);
1317+		return;
1318+	}
1319+	box = type == LayerShell ? l->mon->m : c->mon->w;
1320+	box.x -= (type == LayerShell ? l->scene->node.x : c->geom.x);
1321+	box.y -= (type == LayerShell ? l->scene->node.y : c->geom.y);
1322+	/* zoom */
1323+	if (type != LayerShell && c->mon && fabs(c->mon->zoom_scale - 1.0) >= 1e-9) {
1324+		Monitor *_m = c->mon;
1325+		double inv_s = 1.0 / _m->zoom_scale;
1326+		box.x      = (int)llround(-_m->zoom_pan_x * inv_s) - c->geom.x;
1327+		box.y      = (int)llround(-_m->zoom_pan_y * inv_s) - c->geom.y;
1328+		box.width  = MAX(1, (int)llround((double)_m->m.width  * inv_s));
1329+		box.height = MAX(1, (int)llround((double)_m->m.height * inv_s));
1330+	}
1331+	/* zoom end */
1332+	wlr_xdg_popup_unconstrain_from_box(popup, &box);
1333+	/* zoom */
1334+	if (c && c->mon) {
1335+		struct wlr_scene_tree *ptree = popup->parent->data;
1336+		struct wlr_scene_node *pnode;
1337+		PopupZoomData *pzd;
1338+		pnode = wl_container_of(ptree->children.prev, pnode, link);
1339+		pzd = ecalloc(1, sizeof(*pzd));
1340+		pzd->client = c;
1341+		pzd->popup  = popup;
1342+		pzd->node   = pnode;
1343+		pzd->commit.notify  = popup_zoom_commit;
1344+		pzd->destroy.notify = popup_zoom_destroy;
1345+		wl_list_insert(&popup_zoom_list, &pzd->link);
1346+		wl_signal_add(&popup->base->surface->events.commit, &pzd->commit);
1347+		wl_signal_add(&popup->base->events.destroy, &pzd->destroy);
1348+		popup_zoom_commit(&pzd->commit, NULL);
1349+	}
1350+	/* zoom end */
1351+	wl_list_remove(&listener->link);
1352+	free(listener);
1353+}
1354+
1355+void
1356+createdecoration(struct wl_listener *listener, void *data)
1357+{
1358+	struct wlr_xdg_toplevel_decoration_v1 *deco = data;
1359+	Client *c = deco->toplevel->base->data;
1360+	c->decoration = deco;
1361+
1362+	LISTEN(&deco->events.request_mode, &c->set_decoration_mode, requestdecorationmode);
1363+	LISTEN(&deco->events.destroy, &c->destroy_decoration, destroydecoration);
1364+
1365+	requestdecorationmode(&c->set_decoration_mode, deco);
1366+}
1367+
1368+void
1369+createidleinhibitor(struct wl_listener *listener, void *data)
1370+{
1371+	struct wlr_idle_inhibitor_v1 *idle_inhibitor = data;
1372+	LISTEN_STATIC(&idle_inhibitor->events.destroy, destroyidleinhibitor);
1373+
1374+	checkidleinhibitor(NULL);
1375+}
1376+
1377+void
1378+createkeyboard(struct wlr_keyboard *keyboard)
1379+{
1380+	/* Set the keymap to match the group keymap */
1381+	wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap);
1382+
1383+	/* Add the new keyboard to the group */
1384+	wlr_keyboard_group_add_keyboard(kb_group->wlr_group, keyboard);
1385+}
1386+
1387+KeyboardGroup *
1388+createkeyboardgroup(void)
1389+{
1390+	KeyboardGroup *group = ecalloc(1, sizeof(*group));
1391+	struct xkb_context *context;
1392+	struct xkb_keymap *keymap;
1393+
1394+	group->wlr_group = wlr_keyboard_group_create();
1395+	group->wlr_group->data = group;
1396+
1397+	/* Prepare an XKB keymap and assign it to the keyboard group. */
1398+	context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
1399+	if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules,
1400+				XKB_KEYMAP_COMPILE_NO_FLAGS)))
1401+		die("failed to compile keymap");
1402+
1403+	wlr_keyboard_set_keymap(&group->wlr_group->keyboard, keymap);
1404+	xkb_keymap_unref(keymap);
1405+	xkb_context_unref(context);
1406+
1407+	wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard, repeat_rate, repeat_delay);
1408+
1409+	/* Set up listeners for keyboard events */
1410+	LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress);
1411+	LISTEN(&group->wlr_group->keyboard.events.modifiers, &group->modifiers, keypressmod);
1412+
1413+	group->key_repeat_source = wl_event_loop_add_timer(event_loop, keyrepeat, group);
1414+
1415+	/* A seat can only have one keyboard, but this is a limitation of the
1416+	 * Wayland protocol - not wlroots. We assign all connected keyboards to the
1417+	 * same wlr_keyboard_group, which provides a single wlr_keyboard interface for
1418+	 * all of them. Set this combined wlr_keyboard as the seat keyboard.
1419+	 */
1420+	wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard);
1421+	return group;
1422+}
1423+
1424+void
1425+createlayersurface(struct wl_listener *listener, void *data)
1426+{
1427+	struct wlr_layer_surface_v1 *layer_surface = data;
1428+	LayerSurface *l;
1429+	struct wlr_surface *surface = layer_surface->surface;
1430+	struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->pending.layer]];
1431+
1432+	if (!layer_surface->output
1433+			&& !(layer_surface->output = selmon ? selmon->wlr_output : NULL)) {
1434+		wlr_layer_surface_v1_destroy(layer_surface);
1435+		return;
1436+	}
1437+
1438+	l = layer_surface->data = ecalloc(1, sizeof(*l));
1439+	l->type = LayerShell;
1440+	LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify);
1441+	LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify);
1442+	LISTEN(&layer_surface->events.destroy, &l->destroy, destroylayersurfacenotify);
1443+
1444+	l->layer_surface = layer_surface;
1445+	l->mon = layer_surface->output->data;
1446+	l->scene_layer = wlr_scene_layer_surface_v1_create(scene_layer, layer_surface);
1447+	l->scene = l->scene_layer->tree;
1448+	l->popups = surface->data = wlr_scene_tree_create(layer_surface->current.layer
1449+			< ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer);
1450+	l->scene->node.data = l->popups->node.data = l;
1451+
1452+	wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link);
1453+	wlr_surface_send_enter(surface, layer_surface->output);
1454+}
1455+
1456+void
1457+createlocksurface(struct wl_listener *listener, void *data)
1458+{
1459+	SessionLock *lock = wl_container_of(listener, lock, new_surface);
1460+	struct wlr_session_lock_surface_v1 *lock_surface = data;
1461+	Monitor *m = lock_surface->output->data;
1462+	struct wlr_scene_tree *scene_tree = lock_surface->surface->data
1463+			= wlr_scene_subsurface_tree_create(lock->scene, lock_surface->surface);
1464+	m->lock_surface = lock_surface;
1465+
1466+	wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y);
1467+	wlr_session_lock_surface_v1_configure(lock_surface, m->m.width, m->m.height);
1468+
1469+	LISTEN(&lock_surface->events.destroy, &m->destroy_lock_surface, destroylocksurface);
1470+
1471+	if (m == selmon)
1472+		client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat));
1473+}
1474+
1475+void
1476+createmon(struct wl_listener *listener, void *data)
1477+{
1478+	/* This event is raised by the backend when a new output (aka a display or
1479+	 * monitor) becomes available. */
1480+	struct wlr_output *wlr_output = data;
1481+  struct wlr_output_mode *mode = wl_container_of(wlr_output->modes.next, mode, link);
1482+	const MonitorRule *r;
1483+	size_t i;
1484+	struct wlr_output_state state;
1485+	Monitor *m;
1486+
1487+	if (!wlr_output_init_render(wlr_output, alloc, drw))
1488+		return;
1489+
1490+	m = wlr_output->data = ecalloc(1, sizeof(*m));
1491+	m->wlr_output = wlr_output;
1492+
1493+	for (i = 0; i < LENGTH(m->layers); i++)
1494+		wl_list_init(&m->layers[i]);
1495+ 
1496+#ifdef TILING
1497+	m->enablegaps = enablegaps;
1498+	m->gappih = gappih;
1499+	m->gappiv = gappiv;
1500+	m->gappoh = gappoh;
1501+	m->gappov = gappov;
1502+#endif
1503+	wlr_output_state_init(&state);
1504+	/* Initialize monitor state using configured rules */
1505+	m->tagset[0] = m->tagset[1] = 1;
1506+	for (r = monrules; r < END(monrules); r++) {
1507+		if (!r->name || strstr(wlr_output->name, r->name)) {
1508+			m->m.x = r->x;
1509+			m->m.y = r->y;
1510+			m->mfact = r->mfact;
1511+			m->nmaster = r->nmaster;
1512+			m->lt[0] = r->lt ? r->lt : &layouts[0];
1513+			m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]];
1514+			if (m->lt[m->sellt] && m->lt[m->sellt]->symbol) { strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol)); } else { strncpy(m->ltsymbol, "[]=", LENGTH(m->ltsymbol)); }
1515+			wlr_output_state_set_scale(&state, r->scale);
1516+			wlr_output_state_set_transform(&state, r->rr);
1517+
1518+			wlr_output_state_set_adaptive_sync_enabled(&state, r->adaptive);
1519+
1520+			if(r->mode == -1)
1521+				wlr_output_state_set_custom_mode(&state, r->resx, r->resy,
1522+				(int) (r->rate > 0 ? r->rate * 1000 : 0));
1523+			else if (!wl_list_empty(&wlr_output->modes)) {
1524+				for (int j = 0; j < r->mode; j++) {
1525+					mode = wl_container_of(mode->link.next, mode, link);
1526+				}
1527+				wlr_output_state_set_mode(&state, mode);
1528+			}
1529+
1530+			break;
1531+		}
1532+	}
1533+
1534+	/* Safety net: if no monrules entry matched this output's name (and
1535+	 * there's no wildcard fallback rule in config.h), m->lt[0]/m->lt[1]
1536+	 * are left NULL by ecalloc(). Every layout dereference elsewhere in
1537+	 * this file assumes they're never NULL, so guarantee that here. */
1538+	if (!m->lt[0])
1539+		m->lt[0] = &layouts[0];
1540+	if (!m->lt[1])
1541+		m->lt[1] = &layouts[LENGTH(layouts) > 1];
1542+	if (!m->ltsymbol[0]) {
1543+		if (m->lt[m->sellt] && m->lt[m->sellt]->symbol)
1544+			strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
1545+		else
1546+			strncpy(m->ltsymbol, "[]=", LENGTH(m->ltsymbol));
1547+	}
1548+
1549+	/* infinite_canvas */
1550+	{
1551+		int restored = 0;
1552+		MonitorState *ms = NULL, *iter;
1553+		unsigned int _i;
1554+		wl_list_for_each(iter, &savedstates, link) {
1555+			if (strcmp(iter->name, wlr_output->name) == 0) {
1556+				ms = iter;
1557+				break;
1558+			}
1559+		}
1560+		if (ms) {
1561+			m->seltags = ms->seltags;
1562+			m->sellt = ms->sellt;
1563+			m->tagset[0] = ms->tagset[0];
1564+			m->tagset[1] = ms->tagset[1];
1565+			m->mfact = ms->mfact;
1566+			m->nmaster = ms->nmaster;
1567+			strncpy(m->ltsymbol, ms->ltsymbol, sizeof(m->ltsymbol));
1568+			m->lt[0] = ms->lt[0];
1569+			m->lt[1] = ms->lt[1];
1570+			m->canvas = ms->canvas;
1571+			ms->canvas = NULL;
1572+			m->zoom_scale = ms->zoom_scale;
1573+			m->zoom_target = ms->zoom_target;
1574+			m->zoom_pan_x = ms->zoom_pan_x;
1575+			m->zoom_pan_y = ms->zoom_pan_y;
1576+			wl_list_remove(&ms->link);
1577+			free(ms);
1578+			restored = 1;
1579+		} else {
1580+			m->canvas = ecalloc(TAGCOUNT, sizeof(CanvasOffset));
1581+			for (_i = 0; _i < (unsigned int)TAGCOUNT; _i++) {
1582+				m->canvas[_i].cx = 0;
1583+				m->canvas[_i].cy = 0;
1584+			}
1585+		}
1586+		if (!restored) {
1587+			m->zoom_scale = 1.0;
1588+			m->zoom_target = 1.0;
1589+			m->zoom_pan_x = 0.0;
1590+			m->zoom_pan_y = 0.0;
1591+		}
1592+		m->zoom_anim_t = 1.0;
1593+		m->zoom_start_scale = 1.0;
1594+		m->zoom_start_pan_x = 0.0;
1595+		m->zoom_start_pan_y = 0.0;
1596+		m->zoom_popups_dirty = 0;
1597+	}
1598+	/* infinite_canvas_end */
1599+	wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output));
1600+
1601+	/* Set up event listeners */
1602+	LISTEN(&wlr_output->events.frame, &m->frame, rendermon);
1603+	LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon);
1604+	LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate);
1605+
1606+	wlr_output_state_set_enabled(&state, 1);
1607+	wlr_output_commit_state(wlr_output, &state);
1608+	wlr_output_state_finish(&state);
1609+
1610+	wl_list_insert(&mons, &m->link);
1611+	printstatus();
1612+
1613+	/* The xdg-protocol specifies:
1614+	 *
1615+	 * If the fullscreened surface is not opaque, the compositor must make
1616+	 * sure that other screen content not part of the same surface tree (made
1617+	 * up of subsurfaces, popups or similarly coupled surfaces) are not
1618+	 * visible below the fullscreened surface.
1619+	 *
1620+	 */
1621+	/* updatemons() will resize and set correct position */
1622+	m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg);
1623+	wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0);
1624+
1625+	/* Adds this to the output layout in the order it was configured.
1626+	 *
1627+	 * The output layout utility automatically adds a wl_output global to the
1628+	 * display, which Wayland clients can see to find out information about the
1629+	 * output (such as DPI, scale factor, manufacturer, etc).
1630+	 */
1631+	m->scene_output = wlr_scene_output_create(scene, wlr_output);
1632+	if (m->m.x == -1 && m->m.y == -1)
1633+		wlr_output_layout_add_auto(output_layout, wlr_output);
1634+	else
1635+		wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y);
1636+}
1637+
1638+void
1639+createnotify(struct wl_listener *listener, void *data)
1640+{
1641+	/* This event is raised when a client creates a new toplevel (application window). */
1642+	struct wlr_xdg_toplevel *toplevel = data;
1643+	Client *c = NULL;
1644+
1645+	/* Allocate a Client for this surface */
1646+	c = toplevel->base->data = ecalloc(1, sizeof(*c));
1647+	c->surface.xdg = toplevel->base;
1648+
1649+	c->ibw = innerborderpx;
1650+  c->obw = outerborderpx;
1651+  c->bw = c->ibw + c->obw;
1652+
1653+	LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify);
1654+	LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify);
1655+	LISTEN(&toplevel->base->surface->events.unmap, &c->unmap, unmapnotify);
1656+	LISTEN(&toplevel->events.destroy, &c->destroy, destroynotify);
1657+	LISTEN(&toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify);
1658+	LISTEN(&toplevel->events.request_maximize, &c->maximize, maximizenotify);
1659+	LISTEN(&toplevel->events.set_title, &c->set_title, updatetitle);
1660+}
1661+
1662+typedef struct {
1663+	struct wl_listener pinch_begin;
1664+	struct wl_listener pinch_update;
1665+	struct wl_listener pinch_end;
1666+	struct wl_listener destroy;
1667+	struct wlr_pointer *pointer;
1668+} PinchListeners;
1669+
1670+static void
1671+pinchbegin(struct wl_listener *listener, void *data)
1672+{
1673+	struct wlr_pointer_pinch_begin_event *event = data;
1674+	(void)listener;
1675+	if (!pointer_gestures || !event)
1676+		return;
1677+	wlr_pointer_gestures_v1_send_pinch_begin(pointer_gestures, seat,
1678+		event->time_msec, event->fingers);
1679+}
1680+
1681+static void
1682+pinchupdate(struct wl_listener *listener, void *data)
1683+{
1684+	struct wlr_pointer_pinch_update_event *event = data;
1685+	(void)listener;
1686+	if (!pointer_gestures || !event)
1687+		return;
1688+	wlr_pointer_gestures_v1_send_pinch_update(pointer_gestures, seat,
1689+		event->time_msec, event->dx, event->dy,
1690+		event->scale, event->rotation);
1691+}
1692+
1693+static void
1694+pinchend(struct wl_listener *listener, void *data)
1695+{
1696+	struct wlr_pointer_pinch_end_event *event = data;
1697+	(void)listener;
1698+	if (!pointer_gestures || !event)
1699+		return;
1700+	wlr_pointer_gestures_v1_send_pinch_end(pointer_gestures, seat,
1701+		event->time_msec, event->cancelled);
1702+}
1703+
1704+static void
1705+pinchdestroy(struct wl_listener *listener, void *data)
1706+{
1707+	PinchListeners *pl = wl_container_of(listener, pl, destroy);
1708+	wl_list_remove(&pl->pinch_begin.link);
1709+	wl_list_remove(&pl->pinch_update.link);
1710+	wl_list_remove(&pl->pinch_end.link);
1711+	wl_list_remove(&pl->destroy.link);
1712+	free(pl);
1713+}
1714+
1715+void
1716+createpointer(struct wlr_pointer *pointer)
1717+{
1718+	struct libinput_device *device;
1719+	PinchListeners *pl;
1720+	if (wlr_input_device_is_libinput(&pointer->base)
1721+			&& (device = wlr_libinput_get_device_handle(&pointer->base))) {
1722+
1723+		if (libinput_device_config_tap_get_finger_count(device)) {
1724+			libinput_device_config_tap_set_enabled(device, tap_to_click);
1725+			libinput_device_config_tap_set_drag_enabled(device, tap_and_drag);
1726+			libinput_device_config_tap_set_drag_lock_enabled(device, drag_lock);
1727+			libinput_device_config_tap_set_button_map(device, button_map);
1728+		}
1729+
1730+		if (libinput_device_config_scroll_has_natural_scroll(device))
1731+			libinput_device_config_scroll_set_natural_scroll_enabled(device, natural_scrolling);
1732+
1733+		if (libinput_device_config_dwt_is_available(device))
1734+			libinput_device_config_dwt_set_enabled(device, disable_while_typing);
1735+
1736+		if (libinput_device_config_left_handed_is_available(device))
1737+			libinput_device_config_left_handed_set(device, left_handed);
1738+
1739+		if (libinput_device_config_middle_emulation_is_available(device))
1740+			libinput_device_config_middle_emulation_set_enabled(device, middle_button_emulation);
1741+
1742+		if (libinput_device_config_scroll_get_methods(device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL)
1743+			libinput_device_config_scroll_set_method(device, scroll_method);
1744+
1745+		if (libinput_device_config_click_get_methods(device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE)
1746+			libinput_device_config_click_set_method(device, click_method);
1747+
1748+		if (libinput_device_config_send_events_get_modes(device))
1749+			libinput_device_config_send_events_set_mode(device, send_events_mode);
1750+
1751+		if (libinput_device_config_accel_is_available(device)) {
1752+			libinput_device_config_accel_set_profile(device, accel_profile);
1753+			libinput_device_config_accel_set_speed(device, accel_speed);
1754+		}
1755+	}
1756+
1757+	wlr_cursor_attach_input_device(cursor, &pointer->base);
1758+
1759+	pl = ecalloc(1, sizeof(*pl));
1760+	pl->pointer = pointer;
1761+	pl->pinch_begin.notify = pinchbegin;
1762+	pl->pinch_update.notify = pinchupdate;
1763+	pl->pinch_end.notify = pinchend;
1764+	pl->destroy.notify = pinchdestroy;
1765+	wl_signal_add(&pointer->events.pinch_begin, &pl->pinch_begin);
1766+	wl_signal_add(&pointer->events.pinch_update, &pl->pinch_update);
1767+	wl_signal_add(&pointer->events.pinch_end, &pl->pinch_end);
1768+	wl_signal_add(&pointer->base.events.destroy, &pl->destroy);
1769+}
1770+
1771+void
1772+createpointerconstraint(struct wl_listener *listener, void *data)
1773+{
1774+	PointerConstraint *pointer_constraint = ecalloc(1, sizeof(*pointer_constraint));
1775+	pointer_constraint->constraint = data;
1776+	LISTEN(&pointer_constraint->constraint->events.destroy,
1777+			&pointer_constraint->destroy, destroypointerconstraint);
1778+}
1779+
1780+void
1781+createpopup(struct wl_listener *listener, void *data)
1782+{
1783+	/* This event is raised when a client (either xdg-shell or layer-shell)
1784+	 * creates a new popup. */
1785+	struct wlr_xdg_popup *popup = data;
1786+	LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup);
1787+}
1788+
1789+void
1790+cursorconstrain(struct wlr_pointer_constraint_v1 *constraint)
1791+{
1792+	if (active_constraint == constraint)
1793+		return;
1794+
1795+	if (active_constraint)
1796+		wlr_pointer_constraint_v1_send_deactivated(active_constraint);
1797+
1798+	active_constraint = constraint;
1799+	wlr_pointer_constraint_v1_send_activated(constraint);
1800+}
1801+
1802+void
1803+cursorframe(struct wl_listener *listener, void *data)
1804+{
1805+	/* This event is forwarded by the cursor when a pointer emits a frame
1806+	 * event. Frame events are sent after regular pointer events to group
1807+	 * multiple events together. For instance, two axis events may happen at the
1808+	 * same time, in which case a frame event won't be sent in between. */
1809+	/* Notify the client with pointer focus of the frame event. */
1810+	wlr_seat_pointer_notify_frame(seat);
1811+}
1812+
1813+void
1814+cursorwarptohint(void)
1815+{
1816+	Client *c = NULL;
1817+	double sx = active_constraint->current.cursor_hint.x;
1818+	double sy = active_constraint->current.cursor_hint.y;
1819+
1820+	toplevel_from_wlr_surface(active_constraint->surface, &c, NULL);
1821+	if (c && active_constraint->current.cursor_hint.enabled) {
1822+		wlr_cursor_warp(cursor, NULL, sx + c->geom.x + c->bw, sy + c->geom.y + c->bw);
1823+		wlr_seat_pointer_warp(active_constraint->seat, sx, sy);
1824+	}
1825+}
1826+
1827+void
1828+destroydecoration(struct wl_listener *listener, void *data)
1829+{
1830+	Client *c = wl_container_of(listener, c, destroy_decoration);
1831+
1832+	wl_list_remove(&c->destroy_decoration.link);
1833+	wl_list_remove(&c->set_decoration_mode.link);
1834+}
1835+
1836+void
1837+destroydragicon(struct wl_listener *listener, void *data)
1838+{
1839+	/* Focus enter isn't sent during drag, so refocus the focused node. */
1840+	focusclient(focustop(selmon), 1);
1841+	motionnotify(0, NULL, 0, 0, 0, 0);
1842+	wl_list_remove(&listener->link);
1843+	free(listener);
1844+}
1845+
1846+void
1847+destroyidleinhibitor(struct wl_listener *listener, void *data)
1848+{
1849+	/* `data` is the wlr_surface of the idle inhibitor being destroyed,
1850+	 * at this point the idle inhibitor is still in the list of the manager */
1851+	checkidleinhibitor(wlr_surface_get_root_surface(data));
1852+	wl_list_remove(&listener->link);
1853+	free(listener);
1854+}
1855+
1856+void
1857+destroylayersurfacenotify(struct wl_listener *listener, void *data)
1858+{
1859+	LayerSurface *l = wl_container_of(listener, l, destroy);
1860+
1861+	wl_list_remove(&l->link);
1862+	wl_list_remove(&l->destroy.link);
1863+	wl_list_remove(&l->unmap.link);
1864+	wl_list_remove(&l->surface_commit.link);
1865+	wlr_scene_node_destroy(&l->scene->node);
1866+	wlr_scene_node_destroy(&l->popups->node);
1867+	free(l);
1868+}
1869+
1870+void
1871+destroylock(SessionLock *lock, int unlock)
1872+{
1873+	wlr_seat_keyboard_notify_clear_focus(seat);
1874+	if ((locked = !unlock))
1875+		goto destroy;
1876+
1877+	wlr_scene_node_set_enabled(&locked_bg->node, 0);
1878+
1879+	focusclient(focustop(selmon), 0);
1880+	motionnotify(0, NULL, 0, 0, 0, 0);
1881+
1882+destroy:
1883+	wl_list_remove(&lock->new_surface.link);
1884+	wl_list_remove(&lock->unlock.link);
1885+	wl_list_remove(&lock->destroy.link);
1886+
1887+	wlr_scene_node_destroy(&lock->scene->node);
1888+	cur_lock = NULL;
1889+	free(lock);
1890+}
1891+
1892+void
1893+destroylocksurface(struct wl_listener *listener, void *data)
1894+{
1895+	Monitor *m = wl_container_of(listener, m, destroy_lock_surface);
1896+	struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface;
1897+
1898+	m->lock_surface = NULL;
1899+	wl_list_remove(&m->destroy_lock_surface.link);
1900+
1901+	if (lock_surface->surface != seat->keyboard_state.focused_surface)
1902+		return;
1903+
1904+	if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) {
1905+		surface = wl_container_of(cur_lock->surfaces.next, surface, link);
1906+		client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat));
1907+	} else if (!locked) {
1908+		focusclient(focustop(selmon), 1);
1909+	} else {
1910+		wlr_seat_keyboard_clear_focus(seat);
1911+	}
1912+}
1913+
1914+void
1915+destroynotify(struct wl_listener *listener, void *data)
1916+{
1917+	/* Called when the xdg_toplevel is destroyed. */
1918+	Client *c = wl_container_of(listener, c, destroy);
1919+	wl_list_remove(&c->destroy.link);
1920+	wl_list_remove(&c->set_title.link);
1921+	wl_list_remove(&c->fullscreen.link);
1922+#ifdef XWAYLAND
1923+	if (c->type != XDGShell) {
1924+		wl_list_remove(&c->activate.link);
1925+		wl_list_remove(&c->associate.link);
1926+		wl_list_remove(&c->configure.link);
1927+		wl_list_remove(&c->dissociate.link);
1928+		wl_list_remove(&c->set_hints.link);
1929+	} else
1930+#endif
1931+	{
1932+		wl_list_remove(&c->commit.link);
1933+		wl_list_remove(&c->map.link);
1934+		wl_list_remove(&c->unmap.link);
1935+		wl_list_remove(&c->maximize.link);
1936+	}
1937+	free(c);
1938+}
1939+
1940+void
1941+destroypointerconstraint(struct wl_listener *listener, void *data)
1942+{
1943+	PointerConstraint *pointer_constraint = wl_container_of(listener, pointer_constraint, destroy);
1944+
1945+	if (active_constraint == pointer_constraint->constraint) {
1946+		cursorwarptohint();
1947+		active_constraint = NULL;
1948+	}
1949+
1950+	wl_list_remove(&pointer_constraint->destroy.link);
1951+	free(pointer_constraint);
1952+}
1953+
1954+void
1955+destroysessionlock(struct wl_listener *listener, void *data)
1956+{
1957+	SessionLock *lock = wl_container_of(listener, lock, destroy);
1958+	destroylock(lock, 0);
1959+}
1960+
1961+void
1962+destroykeyboardgroup(struct wl_listener *listener, void *data)
1963+{
1964+	KeyboardGroup *group = wl_container_of(listener, group, destroy);
1965+	wl_event_source_remove(group->key_repeat_source);
1966+	wl_list_remove(&group->key.link);
1967+	wl_list_remove(&group->modifiers.link);
1968+	wl_list_remove(&group->destroy.link);
1969+	wlr_keyboard_group_destroy(group->wlr_group);
1970+	free(group);
1971+}
1972+
1973+Monitor *
1974+dirtomon(enum wlr_direction dir)
1975+{
1976+	struct wlr_output *next;
1977+	if (!wlr_output_layout_get(output_layout, selmon->wlr_output))
1978+		return selmon;
1979+	if ((next = wlr_output_layout_adjacent_output(output_layout,
1980+			dir, selmon->wlr_output, selmon->m.x, selmon->m.y)))
1981+		return next->data;
1982+	if ((next = wlr_output_layout_farthest_output(output_layout,
1983+			dir ^ (WLR_DIRECTION_LEFT|WLR_DIRECTION_RIGHT),
1984+			selmon->wlr_output, selmon->m.x, selmon->m.y)))
1985+		return next->data;
1986+	return selmon;
1987+}
1988+
1989+void
1990+focusclient(Client *c, int lift)
1991+{
1992+	struct wlr_surface *old = seat->keyboard_state.focused_surface;
1993+	int unused_lx, unused_ly, old_client_type;
1994+	Client *old_c = NULL;
1995+	LayerSurface *old_l = NULL;
1996+
1997+	if (locked)
1998+		return;
1999+
2000+	/* Raise client in stacking order if requested */
2001+	if (c && lift)
2002+		wlr_scene_node_raise_to_top(&c->scene->node);
2003+
2004+	if (c && client_surface(c) == old)
2005+		return;
2006+
2007+	if ((old_client_type = toplevel_from_wlr_surface(old, &old_c, &old_l)) == XDGShell) {
2008+		struct wlr_xdg_popup *popup, *tmp;
2009+		wl_list_for_each_safe(popup, tmp, &old_c->surface.xdg->popups, link)
2010+			wlr_xdg_popup_destroy(popup);
2011+	}
2012+
2013+	/* Put the new client atop the focus stack and select its monitor */
2014+	if (c && !client_is_unmanaged(c)) {
2015+		wl_list_remove(&c->flink);
2016+		wl_list_insert(&fstack, &c->flink);
2017+		selmon = c->mon;
2018+		c->isurgent = 0;
2019+
2020+		/* Don't change border color if there is an exclusive focus or we are
2021+		 * handling a drag operation */
2022+		if (!exclusive_focus && !seat->drag)
2023+			client_set_border_color(c, focused_inner_border_color, focused_outer_border_color);
2024+	}
2025+
2026+	/* Deactivate old client if focus is changing */
2027+	if (old && (!c || client_surface(c) != old)) {
2028+		/* If an overlay is focused, don't focus or activate the client,
2029+		 * but only update its position in fstack to render its border with focuscolor
2030+		 * and focus it after the overlay is closed. */
2031+		if (old_client_type == LayerShell && wlr_scene_node_coords(
2032+					&old_l->scene->node, &unused_lx, &unused_ly)
2033+				&& old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
2034+			return;
2035+		} else if (old_c && old_c == exclusive_focus && client_wants_focus(old_c)) {
2036+			return;
2037+		/* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg
2038+		 * and probably other clients */
2039+		} else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) {
2040+			client_set_border_color(old_c, unfocused_inner_border_color, unfocused_outer_border_color);
2041+
2042+			client_activate_surface(old, 0);
2043+		}
2044+	}
2045+	printstatus();
2046+
2047+	if (!c) {
2048+		/* With no client, all we have left is to clear focus */
2049+		wlr_seat_keyboard_notify_clear_focus(seat);
2050+		return;
2051+	}
2052+
2053+	/* Change cursor surface */
2054+	motionnotify(0, NULL, 0, 0, 0, 0);
2055+
2056+	/* Have a client, so focus its top-level wlr_surface */
2057+	client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat));
2058+
2059+	/* Activate the new client */
2060+	client_activate_surface(client_surface(c), 1);
2061+}
2062+
2063+void
2064+focusmon(const Arg *arg)
2065+{
2066+	int i = 0, nmons = wl_list_length(&mons);
2067+	if (nmons) {
2068+		do /* don't switch to disabled mons */
2069+			selmon = dirtomon(arg->i);
2070+		while (!selmon->wlr_output->enabled && i++ < nmons);
2071+	}
2072+	focusclient(focustop(selmon), 1);
2073+}
2074+
2075+void
2076+focusstack(const Arg *arg)
2077+{
2078+	/* Focus the next or previous client (in tiling order) on selmon */
2079+	Client *c, *sel = focustop(selmon);
2080+	if (!sel || (sel->isfullscreen && !client_has_children(sel)))
2081+		return;
2082+	if (arg->i > 0) {
2083+		wl_list_for_each(c, &sel->link, link) {
2084+			if (&c->link == &clients)
2085+				continue; /* wrap past the sentinel node */
2086+			if (VISIBLEON(c, selmon))
2087+				break; /* found it */
2088+		}
2089+	} else {
2090+		wl_list_for_each_reverse(c, &sel->link, link) {
2091+			if (&c->link == &clients)
2092+				continue; /* wrap past the sentinel node */
2093+			if (VISIBLEON(c, selmon))
2094+				break; /* found it */
2095+		}
2096+	}
2097+	/* If only one client is visible on selmon, then c == sel */
2098+	focusclient(c, 1);
2099+	/* infinite_canvas */
2100+	if (selmon && !selmon->lt[selmon->sellt]->arrange)
2101+		bringintoview(c);
2102+	/* infinite_canvas_end */
2103+}
2104+
2105+/* We probably should change the name of this: it sounds like it
2106+ * will focus the topmost client of this mon, when actually will
2107+ * only return that client */
2108+Client *
2109+focustop(Monitor *m)
2110+{
2111+	Client *c;
2112+	wl_list_for_each(c, &fstack, flink) {
2113+		if (VISIBLEON(c, m))
2114+			return c;
2115+	}
2116+	return NULL;
2117+}
2118+
2119+void
2120+fullscreennotify(struct wl_listener *listener, void *data)
2121+{
2122+	Client *c = wl_container_of(listener, c, fullscreen);
2123+	setfullscreen(c, client_wants_fullscreen(c));
2124+}
2125+
2126+void
2127+gpureset(struct wl_listener *listener, void *data)
2128+{
2129+	struct wlr_renderer *old_drw = drw;
2130+	struct wlr_allocator *old_alloc = alloc;
2131+	struct Monitor *m;
2132+	if (!(drw = wlr_renderer_autocreate(backend)))
2133+		die("couldn't recreate renderer");
2134+
2135+	if (!(alloc = wlr_allocator_autocreate(backend, drw)))
2136+		die("couldn't recreate allocator");
2137+
2138+	wl_list_remove(&gpu_reset.link);
2139+	wl_signal_add(&drw->events.lost, &gpu_reset);
2140+
2141+	wlr_compositor_set_renderer(compositor, drw);
2142+
2143+	wl_list_for_each(m, &mons, link) {
2144+		wlr_output_init_render(m->wlr_output, alloc, drw);
2145+	}
2146+
2147+	wlr_allocator_destroy(old_alloc);
2148+	wlr_renderer_destroy(old_drw);
2149+}
2150+
2151+void
2152+handlesig(int signo)
2153+{
2154+	if (signo == SIGCHLD)
2155+		while (waitpid(-1, NULL, WNOHANG) > 0);
2156+	else if (signo == SIGINT || signo == SIGTERM)
2157+		quit(NULL);
2158+}
2159+
2160+void
2161+incnmaster(const Arg *arg)
2162+{
2163+	if (!arg || !selmon)
2164+		return;
2165+	selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
2166+	arrange(selmon);
2167+}
2168+
2169+void
2170+inputdevice(struct wl_listener *listener, void *data)
2171+{
2172+	/* This event is raised by the backend when a new input device becomes
2173+	 * available. */
2174+	struct wlr_input_device *device = data;
2175+  /* tablet-input */
2176+  struct wlr_tablet_pad *pad = NULL;
2177+  /* tablet-input end */
2178+	uint32_t caps;
2179+
2180+	switch (device->type) {
2181+	case WLR_INPUT_DEVICE_KEYBOARD:
2182+		createkeyboard(wlr_keyboard_from_input_device(device));
2183+		break;
2184+	case WLR_INPUT_DEVICE_POINTER:
2185+		createpointer(wlr_pointer_from_input_device(device));
2186+		break;
2187+  /* tablet-input */
2188+  case WLR_INPUT_DEVICE_TABLET:
2189+		createtablet(device);
2190+		break;
2191+	case WLR_INPUT_DEVICE_TABLET_PAD:
2192+		pad = wlr_tablet_pad_from_input_device(device);
2193+		tablet_pad = wlr_tablet_pad_create(tablet_mgr, seat, device);
2194+		wl_signal_add(&pad->events.button,  &tablet_pad_button);
2195+		wl_signal_add(&device->events.destroy, &tablet_pad_destroy);
2196+		break;
2197+  /* tablet-input end */
2198+	default:
2199+		/* TODO handle other input device types */
2200+		break;
2201+	}
2202+
2203+	/* We need to let the wlr_seat know what our capabilities are, which is
2204+	 * communiciated to the client. In leeloo we always have a cursor, even if
2205+	 * there are no pointer devices, so we always include that capability. */
2206+	/* TODO do we actually require a cursor? */
2207+	caps = WL_SEAT_CAPABILITY_POINTER;
2208+	if (!wl_list_empty(&kb_group->wlr_group->devices))
2209+		caps |= WL_SEAT_CAPABILITY_KEYBOARD;
2210+	wlr_seat_set_capabilities(seat, caps);
2211+}
2212+
2213+int
2214+keybinding(uint32_t mods, xkb_keysym_t sym)
2215+{
2216+	/*
2217+	 * Here we handle compositor keybindings. This is when the compositor is
2218+	 * processing keys, rather than passing them on to the client for its own
2219+	 * processing.
2220+	 */
2221+	const Key *k;
2222+	for (k = keys; k < END(keys); k++) {
2223+		if (CLEANMASK(mods) == CLEANMASK(k->mod)
2224+				&& xkb_keysym_to_lower(sym) == xkb_keysym_to_lower(k->keysym)
2225+				&& k->func) {
2226+			k->func(&k->arg);
2227+			return 1;
2228+		}
2229+	}
2230+	return 0;
2231+}
2232+
2233+void
2234+keypress(struct wl_listener *listener, void *data)
2235+{
2236+	int i;
2237+	/* This event is raised when a key is pressed or released. */
2238+	KeyboardGroup *group = wl_container_of(listener, group, key);
2239+	struct wlr_keyboard_key_event *event = data;
2240+
2241+	/* Translate libinput keycode -> xkbcommon */
2242+	uint32_t keycode = event->keycode + 8;
2243+	/* Get a list of keysyms based on the keymap for this keyboard */
2244+	const xkb_keysym_t *syms;
2245+	int nsyms = xkb_state_key_get_syms(
2246+			group->wlr_group->keyboard.xkb_state, keycode, &syms);
2247+
2248+	int handled = 0;
2249+	uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard);
2250+
2251+	wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
2252+
2253+	/* On _press_ if there is no active screen locker,
2254+	 * attempt to process a compositor keybinding. */
2255+	if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
2256+		for (i = 0; i < nsyms; i++)
2257+			handled = keybinding(mods, syms[i]) || handled;
2258+	}
2259+
2260+	if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) {
2261+		group->mods = mods;
2262+		group->keysyms = syms;
2263+		group->nsyms = nsyms;
2264+		wl_event_source_timer_update(group->key_repeat_source,
2265+				group->wlr_group->keyboard.repeat_info.delay);
2266+	} else {
2267+		group->nsyms = 0;
2268+		wl_event_source_timer_update(group->key_repeat_source, 0);
2269+	}
2270+
2271+	if (handled)
2272+		return;
2273+
2274+	wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard);
2275+	/* Pass unhandled keycodes along to the client. */
2276+	wlr_seat_keyboard_notify_key(seat, event->time_msec,
2277+			event->keycode, event->state);
2278+}
2279+
2280+void
2281+keypressmod(struct wl_listener *listener, void *data)
2282+{
2283+	/* This event is raised when a modifier key, such as shift or alt, is
2284+	 * pressed. We simply communicate this to the client. */
2285+	KeyboardGroup *group = wl_container_of(listener, group, modifiers);
2286+
2287+	wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard);
2288+	/* Send modifiers to the client. */
2289+	wlr_seat_keyboard_notify_modifiers(seat,
2290+			&group->wlr_group->keyboard.modifiers);
2291+}
2292+
2293+int
2294+keyrepeat(void *data)
2295+{
2296+	KeyboardGroup *group = data;
2297+	int i;
2298+	if (!group->nsyms || group->wlr_group->keyboard.repeat_info.rate <= 0)
2299+		return 0;
2300+
2301+	wl_event_source_timer_update(group->key_repeat_source,
2302+			1000 / group->wlr_group->keyboard.repeat_info.rate);
2303+
2304+	for (i = 0; i < group->nsyms; i++)
2305+		keybinding(group->mods, group->keysyms[i]);
2306+
2307+	return 0;
2308+}
2309+
2310+void
2311+killclient(const Arg *arg)
2312+{
2313+	Client *sel = focustop(selmon);
2314+	if (sel)
2315+		client_send_close(sel);
2316+}
2317+
2318+void
2319+locksession(struct wl_listener *listener, void *data)
2320+{
2321+	struct wlr_session_lock_v1 *session_lock = data;
2322+	SessionLock *lock;
2323+	wlr_scene_node_set_enabled(&locked_bg->node, 1);
2324+	if (cur_lock) {
2325+		wlr_session_lock_v1_destroy(session_lock);
2326+		return;
2327+	}
2328+	lock = session_lock->data = ecalloc(1, sizeof(*lock));
2329+	focusclient(NULL, 0);
2330+
2331+	lock->scene = wlr_scene_tree_create(layers[LyrBlock]);
2332+	cur_lock = lock->lock = session_lock;
2333+	locked = 1;
2334+
2335+	LISTEN(&session_lock->events.new_surface, &lock->new_surface, createlocksurface);
2336+	LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock);
2337+	LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession);
2338+
2339+	wlr_session_lock_v1_send_locked(session_lock);
2340+}
2341+
2342+static uint64_t
2343+leeloo_monotonic_ms(void)
2344+{
2345+	struct timespec ts;
2346+	clock_gettime(CLOCK_MONOTONIC, &ts);
2347+	return (uint64_t)ts.tv_sec * 1000ULL + (uint64_t)ts.tv_nsec / 1000000ULL;
2348+}
2349+
2350+static void
2351+openanim_buffers(struct wlr_scene_buffer *buf, int sx, int sy, void *data)
2352+{
2353+	Client *c = data;
2354+	double t, k;
2355+	int tw, th;
2356+	(void)sx;
2357+	(void)sy;
2358+	if (!c || !buf->buffer || c != openanim_client || !openanim_running)
2359+		return;
2360+
2361+	t = (double)(leeloo_monotonic_ms() - openanim_start_ms) / 140.0;
2362+	if (t < 0.0)
2363+		t = 0.0;
2364+	if (t > 1.0)
2365+		t = 1.0;
2366+
2367+	/* Subtle 94% -> 100% ease-out. */
2368+	k = 0.94 + 0.06 * (1.0 - pow(1.0 - t, 3.0));
2369+	if (t >= 1.0) {
2370+		wlr_scene_buffer_set_dest_size(buf, 0, 0);
2371+		wlr_scene_buffer_set_opacity(buf, 1.0f);
2372+		return;
2373+	}
2374+
2375+	tw = MAX(1, (int)llround((double)buf->buffer->width * k));
2376+	th = MAX(1, (int)llround((double)buf->buffer->height * k));
2377+	wlr_scene_buffer_set_dest_size(buf, tw, th);
2378+	wlr_scene_buffer_set_opacity(buf, (float)k);
2379+}
2380+
2381+static int
2382+openanim_tick(void *data)
2383+{
2384+	Client *c = data;
2385+	uint64_t now;
2386+	if (!c || c != openanim_client || !c->scene_surface) {
2387+		openanim_running = 0;
2388+		openanim_client = NULL;
2389+		return 0;
2390+	}
2391+
2392+	now = leeloo_monotonic_ms();
2393+	wlr_scene_node_for_each_buffer(&c->scene_surface->node, openanim_buffers, c);
2394+	if (now - openanim_start_ms >= 140) {
2395+		openanim_running = 0;
2396+		wlr_scene_node_for_each_buffer(&c->scene_surface->node, openanim_buffers, c);
2397+		openanim_client = NULL;
2398+		wl_event_source_timer_update(openanim_timer, 0);
2399+		return 0;
2400+	}
2401+	wl_event_source_timer_update(openanim_timer, 16);
2402+	return 0;
2403+}
2404+
2405+static void
2406+start_open_animation(Client *c)
2407+{
2408+	if (!c || !c->scene_surface)
2409+		return;
2410+	if (!openanim_timer)
2411+		openanim_timer = wl_event_loop_add_timer(event_loop, openanim_tick, c);
2412+	if (!openanim_timer)
2413+		return;
2414+	openanim_client = c;
2415+	openanim_start_ms = leeloo_monotonic_ms();
2416+	openanim_running = 1;
2417+	wl_event_source_timer_update(openanim_timer, 0);
2418+}
2419+
2420+void
2421+mapnotify(struct wl_listener *listener, void *data)
2422+{
2423+	/* Called when the surface is mapped, or ready to display on-screen. */
2424+	Client *p = NULL;
2425+	Client *w, *c = wl_container_of(listener, c, map);
2426+	Monitor *m;
2427+	int i;
2428+  
2429+	/* Create scene tree for this client and its border */
2430+	c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]);
2431+	/* Enabled later by a call to arrange() */
2432+	wlr_scene_node_set_enabled(&c->scene->node, client_is_unmanaged(c));
2433+	c->scene_surface = c->type == XDGShell
2434+			? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg)
2435+			: wlr_scene_subsurface_tree_create(c->scene, client_surface(c));
2436+	c->scene->node.data = c->scene_surface->node.data = c;
2437+
2438+	client_get_geometry(c, &c->geom);
2439+
2440+	/* Handle unmanaged clients first so we can return prior create borders */
2441+	if (client_is_unmanaged(c)) {
2442+		/* Unmanaged clients always are floating */
2443+		wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]);
2444+		wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
2445+		client_set_size(c, c->geom.width, c->geom.height);
2446+		if (client_wants_focus(c)) {
2447+			focusclient(c, 1);
2448+			exclusive_focus = c;
2449+		}
2450+		goto unset_fullscreen;
2451+	}
2452+
2453+  for (i = 0; i < 4; i++) {
2454+    c->inner_border[i] = wlr_scene_rect_create(c->scene, 0, 0,
2455+      c->isurgent ? urgent_inner_border_color : unfocused_inner_border_color);
2456+    c->inner_border[i]->node.data = c;
2457+
2458+    c->outer_border[i] = wlr_scene_rect_create(c->scene, 0, 0,
2459+      c->isurgent ? urgent_outer_border_color : unfocused_outer_border_color);
2460+    c->outer_border[i]->node.data = c;
2461+  }
2462+
2463+	/* Initialize client geometry with room for border */
2464+	client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);
2465+
2466+	c->geom.width += 2 * c->bw;
2467+	c->geom.height += 2 * c->bw;
2468+
2469+	/* Insert this client into client lists. */
2470+	wl_list_insert(&clients, &c->link);
2471+	wl_list_insert(&fstack, &c->flink);
2472+
2473+	/* Set initial monitor, tags, floating status, and focus:
2474+	 * we always consider floating, clients that have parent and thus
2475+	 * we set the same tags and monitor as its parent.
2476+	 * If there is no parent, apply rules */
2477+	if ((p = client_get_parent(c))) {
2478+		c->isfloating = 1;
2479+		setmon(c, p->mon, p->tags);
2480+	} else {
2481+		applyrules(c);
2482+	}
2483+	printstatus();
2484+
2485+  /* spawnregion */
2486+  if (!client_is_unmanaged(c)) {
2487+		if (c->isfullscreen || (!c->isfloating && c->mon && c->mon->lt[c->mon->sellt]->arrange) || waiting_geo_client) {
2488+			wlr_scene_node_set_enabled(&c->scene->node, 1);
2489+		} else if (has_pending_spawn_geo) {
2490+			has_pending_spawn_geo = 0;
2491+			c->isfloating = 1;
2492+			if (!c->mon)
2493+				c->mon = selmon;
2494+			if (c->mon) {
2495+				struct wlr_box min_hint = {0};
2496+				int bw2 = 2 * (int)c->bw;
2497+				if (pending_spawn_geo.width  < min_hint.width  + bw2 && min_hint.width  > 0)
2498+					pending_spawn_geo.width  = min_hint.width  + bw2;
2499+				if (pending_spawn_geo.height < min_hint.height + bw2 && min_hint.height > 0)
2500+					pending_spawn_geo.height = min_hint.height + bw2;
2501+				c->geom = pending_spawn_geo;
2502+			}
2503+		} else {
2504+			wlr_scene_node_set_enabled(&c->scene->node, 0);
2505+			waiting_geo_client = c;
2506+			spawnregion(NULL);
2507+		}
2508+	}
2509+	/* spawnregion_end */
2510+unset_fullscreen:
2511+	m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y);
2512+	wl_list_for_each(w, &clients, link) {
2513+		if (w != c && w != p && w->isfullscreen && m == w->mon && (w->tags & c->tags))
2514+			setfullscreen(w, 0);
2515+	}
2516+
2517+	/* infinite_canvas: remember the pan active right now as this
2518+	 * window's own natural framing, so focusing it later teleports
2519+	 * back to exactly how it looked when placed -- independent of
2520+	 * whatever other windows' framing happens to be. */
2521+	if (m) {
2522+		int tagidx = getcurrenttag(m);
2523+		c->home_cx = m->canvas[tagidx].cx;
2524+		c->home_cy = m->canvas[tagidx].cy;
2525+	}
2526+	start_open_animation(c);
2527+
2528+}
2529+
2530+void
2531+maximizenotify(struct wl_listener *listener, void *data)
2532+{
2533+	/* This event is raised when a client would like to maximize itself,
2534+	 * typically because the user clicked on the maximize button on
2535+	 * client-side decorations. leeloo doesn't support maximization, but
2536+	 * to conform to xdg-shell protocol we still must send a configure.
2537+	 * Since xdg-shell protocol v5 we should ignore request of unsupported
2538+	 * capabilities, just schedule a empty configure when the client uses <5
2539+	 * protocol version
2540+	 * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */
2541+	Client *c = wl_container_of(listener, c, maximize);
2542+	if (c->surface.xdg->initialized
2543+			&& wl_resource_get_version(c->surface.xdg->toplevel->resource)
2544+					< XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION)
2545+		wlr_xdg_surface_schedule_configure(c->surface.xdg);
2546+}
2547+
2548+void
2549+monocle(Monitor *m)
2550+{
2551+	Client *c;
2552+	int n = 0;
2553+
2554+	wl_list_for_each(c, &clients, link) {
2555+		if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
2556+			continue;
2557+		resize(c, m->w, 0);
2558+		n++;
2559+	}
2560+	if (n)
2561+		snprintf(m->ltsymbol, LENGTH(m->ltsymbol), "[%d]", n);
2562+	if ((c = focustop(m)))
2563+		wlr_scene_node_raise_to_top(&c->scene->node);
2564+}
2565+
2566+void
2567+motionabsolute(struct wl_listener *listener, void *data)
2568+{
2569+	/* This event is forwarded by the cursor when a pointer emits an _absolute_
2570+	 * motion event, from 0..1 on each axis. This happens, for example, when
2571+	 * wlroots is running under a Wayland window rather than KMS+DRM, and you
2572+	 * move the mouse over the window. You could enter the window from any edge,
2573+	 * so we have to warp the mouse there. Also, some hardware emits these events. */
2574+	struct wlr_pointer_motion_absolute_event *event = data;
2575+	double lx, ly, dx, dy;
2576+
2577+	if (!event->time_msec) /* this is 0 with virtual pointers */
2578+		wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y);
2579+
2580+	wlr_cursor_absolute_to_layout_coords(cursor, &event->pointer->base, event->x, event->y, &lx, &ly);
2581+	dx = lx - cursor->x;
2582+	dy = ly - cursor->y;
2583+	motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy);
2584+}
2585+
2586+void
2587+motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
2588+		double dx_unaccel, double dy_unaccel)
2589+{
2590+	double sx = 0, sy = 0, sx_confined, sy_confined;
2591+	Client *c = NULL, *w = NULL;
2592+	LayerSurface *l = NULL;
2593+	struct wlr_surface *surface = NULL;
2594+	struct wlr_pointer_constraint_v1 *constraint;
2595+
2596+	/* Find the client under the pointer and send the event along. */
2597+	xytonode(cursor->x, cursor->y, &surface, &c, &l, &sx, &sy);
2598+
2599+	if (cursor_mode == CurPressed && !seat->drag
2600+			&& surface != seat->pointer_state.focused_surface
2601+			&& toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, &l) >= 0) {
2602+		c = w;
2603+		surface = seat->pointer_state.focused_surface;
2604+		/* zoom */
2605+		if (l) {
2606+			sx = cursor->x - l->scene->node.x;
2607+			sy = cursor->y - l->scene->node.y;
2608+		} else if (w && w->mon && fabs(w->mon->zoom_scale - 1.0) >= 1e-9) {
2609+			double s = w->mon->zoom_scale;
2610+			int scene_x = (int)llround((double)w->geom.x * s + w->mon->zoom_pan_x);
2611+			int scene_y = (int)llround((double)w->geom.y * s + w->mon->zoom_pan_y);
2612+			int bw_s    = MAX(1, (int)llround((double)w->bw * s));
2613+			int gw_s    = (int)llround((double)w->geom.width  * s);
2614+			int gh_s    = (int)llround((double)w->geom.height * s);
2615+			int inner_w = MAX(1, gw_s - 2 * bw_s);
2616+			int inner_h = MAX(1, gh_s - 2 * bw_s);
2617+			double cw   = (double)MAX(1, w->geom.width  - 2 * w->bw);
2618+			double ch   = (double)MAX(1, w->geom.height - 2 * w->bw);
2619+			sx = (cursor->x - (scene_x + bw_s)) * cw / (double)inner_w;
2620+			sy = (cursor->y - (scene_y + bw_s)) * ch / (double)inner_h;
2621+		} else {
2622+			sx = cursor->x - w->geom.x;
2623+			sy = cursor->y - w->geom.y;
2624+		}
2625+		/* zoom end */
2626+	}
2627+
2628+	/* time is 0 in internal calls meant to restore pointer focus. */
2629+	if (time) {
2630+		wlr_relative_pointer_manager_v1_send_relative_motion(
2631+				relative_pointer_mgr, seat, (uint64_t)time * 1000,
2632+				dx, dy, dx_unaccel, dy_unaccel);
2633+
2634+		wl_list_for_each(constraint, &pointer_constraints->constraints, link)
2635+			cursorconstrain(constraint);
2636+
2637+		if (active_constraint && cursor_mode != CurResize && cursor_mode != CurMove) {
2638+			toplevel_from_wlr_surface(active_constraint->surface, &c, NULL);
2639+			if (c && active_constraint->surface == seat->pointer_state.focused_surface) {
2640+				sx = cursor->x - c->geom.x - c->bw;
2641+				sy = cursor->y - c->geom.y - c->bw;
2642+				if (wlr_region_confine(&active_constraint->region, sx, sy,
2643+						sx + dx, sy + dy, &sx_confined, &sy_confined)) {
2644+					dx = sx_confined - sx;
2645+					dy = sy_confined - sy;
2646+				}
2647+
2648+				if (active_constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED)
2649+					return;
2650+			}
2651+		}
2652+
2653+		wlr_cursor_move(cursor, device, dx, dy);
2654+		wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
2655+
2656+		/* Update selmon (even while dragging a window) */
2657+		if (sloppyfocus)
2658+			selmon = xytomon(cursor->x, cursor->y);
2659+	}
2660+
2661+	/* Update drag icon's position */
2662+	wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
2663+
2664+	/* If we are currently grabbing the mouse, handle and return */
2665+	if (cursor_mode == CurSpawnRegion) {
2666+		spawnregion_x2 = cursor->x;
2667+		spawnregion_y2 = cursor->y;
2668+		spawnregion_update_rect();
2669+		return;
2670+	}
2671+	if (cursor_mode == CurMove) {
2672+		/* infinite_canvas */
2673+		if (canvas_panning) {
2674+			int tagidx;
2675+			double raw_dx, raw_dy;
2676+			double pdx_f, pdy_f;
2677+			int pdx, pdy;
2678+			Client *pc;
2679+			if (!selmon || selmon->lt[selmon->sellt]->arrange != NULL) {
2680+				canvas_panning = 0;
2681+				cursor_mode = CurNormal;
2682+				wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
2683+				return;
2684+			}
2685+			tagidx = getcurrenttag(selmon);
2686+			raw_dx = cursor->x - canvas_pan_last_x;
2687+			raw_dy = cursor->y - canvas_pan_last_y;
2688+			canvas_pan_last_x = cursor->x;
2689+			canvas_pan_last_y = cursor->y;
2690+			/* zoom */
2691+			if (movecanvasmouse_multiplier_is_affected_by_zoom) {
2692+				double s = selmon->zoom_scale;
2693+				if (fabs(s) < 1e-9) s = 1.0;
2694+				pdx_f = raw_dx * canvas_pan_multiplier / s;
2695+				pdy_f = raw_dy * canvas_pan_multiplier / s;
2696+			} else {
2697+				pdx_f = raw_dx * canvas_pan_multiplier;
2698+				pdy_f = raw_dy * canvas_pan_multiplier;
2699+			}
2700+			/* zoom end */
2701+			canvas_pan_accum_x += (float)pdx_f;
2702+			canvas_pan_accum_y += (float)pdy_f;
2703+			pdx = (int)canvas_pan_accum_x;
2704+			pdy = (int)canvas_pan_accum_y;
2705+			canvas_pan_accum_x -= pdx;
2706+			canvas_pan_accum_y -= pdy;
2707+			selmon->canvas[tagidx].cx += pdx;
2708+			selmon->canvas[tagidx].cy += pdy;
2709+			wl_list_for_each(pc, &clients, link) {
2710+				if (!VISIBLEON(pc, selmon))
2711+					continue;
2712+				pc->geom.x += pdx;
2713+				pc->geom.y += pdy;
2714+			}
2715+			/* zoom */
2716+			zoom_apply(selmon);
2717+			/* zoom end */
2718+		} else if (grabc) {
2719+			/* zoom */
2720+			{
2721+				double zmv_s = grabc->mon ? grabc->mon->zoom_scale : 1.0;
2722+				int zmv_nx, zmv_ny;
2723+				if (fabs(zmv_s) < 1e-9) zmv_s = 1.0;
2724+				zmv_nx = (int)llround((cursor->x - grabcx - (grabc->mon ? grabc->mon->zoom_pan_x : 0.0)) / zmv_s);
2725+				zmv_ny = (int)llround((cursor->y - grabcy - (grabc->mon ? grabc->mon->zoom_pan_y : 0.0)) / zmv_s);
2726+				if (grabc->mon)
2727+					snap_edges(grabc, grabc->mon, &zmv_nx, &zmv_ny);
2728+				canvas_move_window(grabc, zmv_nx, zmv_ny);
2729+			}
2730+			/* zoom end */
2731+		}
2732+		/* infinite_canvas_end */
2733+		return;
2734+	} else if (cursor_mode == CurResize) {
2735+		/* zoom */
2736+		if (grabc && grabc->mon) {
2737+			double rzs = grabc->mon->zoom_scale;
2738+			int rzsx, rzsy, new_w, new_h;
2739+			struct wlr_box geo;
2740+			if (fabs(rzs) < 1e-9) rzs = 1.0;
2741+			rzsx = (int)llround(resize_grab_world_x * rzs + grabc->mon->zoom_pan_x);
2742+			rzsy = (int)llround(resize_grab_world_y * rzs + grabc->mon->zoom_pan_y);
2743+			new_w = (int)llround((cursor->x - rzsx) / rzs);
2744+			new_h = (int)llround((cursor->y - rzsy) / rzs);
2745+			geo = (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
2746+				.width = new_w, .height = new_h};
2747+			resize_magnetically(grabc, grabc->mon, &geo);
2748+			resize(grabc, geo, 1);
2749+		} else {
2750+			struct wlr_box geo;
2751+			geo = (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
2752+				.width = (int)round(cursor->x) - grabc->geom.x,
2753+				.height = (int)round(cursor->y) - grabc->geom.y};
2754+			resize_magnetically(grabc, grabc->mon, &geo);
2755+			resize(grabc, geo, 1);
2756+		}
2757+		/* zoom end */
2758+		return;
2759+	}
2760+
2761+	/* If there's no client surface under the cursor, set the cursor image to a
2762+	 * default. This is what makes the cursor image appear when you move it
2763+	 * off of a client or over its border.
2764+	 * Don't reset the cursor while spawnregion is pending a draw. */
2765+	if (!surface && !seat->drag && !spawnregion_active)
2766+		wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
2767+
2768+	/* zoom */
2769+	if (c && !surface && c->mon && fabs(c->mon->zoom_scale - 1.0) >= 1e-9)
2770+		surface = client_surface(c);
2771+	/* zoom end */
2772+
2773+	pointerfocus(c, surface, sx, sy, time);
2774+}
2775+
2776+void
2777+motionrelative(struct wl_listener *listener, void *data)
2778+{
2779+	/* This event is forwarded by the cursor when a pointer emits a _relative_
2780+	 * pointer motion event (i.e. a delta) */
2781+	struct wlr_pointer_motion_event *event = data;
2782+	/* The cursor doesn't move unless we tell it to. The cursor automatically
2783+	 * handles constraining the motion to the output layout, as well as any
2784+	 * special configuration applied for the specific input device which
2785+	 * generated the event. You can pass NULL for the device if you want to move
2786+	 * the cursor around without any input. */
2787+	motionnotify(event->time_msec, &event->pointer->base, event->delta_x, event->delta_y,
2788+			event->unaccel_dx, event->unaccel_dy);
2789+}
2790+
2791+void
2792+moveresize(const Arg *arg)
2793+{
2794+	if (cursor_mode != CurNormal && cursor_mode != CurPressed)
2795+		return;
2796+	xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL);
2797+	if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
2798+		return;
2799+
2800+	setfloating(grabc, 1);
2801+	resize_snap_x_target = 0;
2802+	resize_snap_y_target = 0;
2803+	switch (cursor_mode = arg->ui) {
2804+	case CurMove: {
2805+		/* zoom */
2806+		Monitor *m = grabc->mon;
2807+		double s;
2808+		int mvsx, mvsy;
2809+		s = m ? m->zoom_scale : 1.0;
2810+		if (fabs(s) < 1e-9) s = 1.0;
2811+		mvsx = m ? (int)llround((double)grabc->geom.x * s + m->zoom_pan_x) : grabc->geom.x;
2812+		mvsy = m ? (int)llround((double)grabc->geom.y * s + m->zoom_pan_y) : grabc->geom.y;
2813+		grabcx = (int)round(cursor->x) - mvsx;
2814+		grabcy = (int)round(cursor->y) - mvsy;
2815+		/* zoom end */
2816+		wlr_cursor_set_xcursor(cursor, cursor_mgr, "all-scroll");
2817+		break;
2818+	}
2819+	case CurResize: {
2820+		/* zoom */
2821+		Monitor *m = grabc->mon;
2822+		double s;
2823+		int ex, ey;
2824+		s = m ? m->zoom_scale : 1.0;
2825+		if (fabs(s) < 1e-9) s = 1.0;
2826+		resize_grab_world_x = grabc->geom.x;
2827+		resize_grab_world_y = grabc->geom.y;
2828+		ex = m ? (int)llround((double)(grabc->geom.x + grabc->geom.width) * s + m->zoom_pan_x)
2829+		       : grabc->geom.x + grabc->geom.width;
2830+		ey = m ? (int)llround((double)(grabc->geom.y + grabc->geom.height) * s + m->zoom_pan_y)
2831+		       : grabc->geom.y + grabc->geom.height;
2832+		wlr_cursor_warp_closest(cursor, NULL, ex, ey);
2833+		/* zoom end */
2834+		wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
2835+		break;
2836+	}
2837+	}
2838+}
2839+
2840+void
2841+outputmgrapply(struct wl_listener *listener, void *data)
2842+{
2843+	struct wlr_output_configuration_v1 *config = data;
2844+	outputmgrapplyortest(config, 0);
2845+}
2846+
2847+void
2848+outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test)
2849+{
2850+	/*
2851+	 * Called when a client such as wlr-randr requests a change in output
2852+	 * configuration. This is only one way that the layout can be changed,
2853+	 * so any Monitor information should be updated by updatemons() after an
2854+	 * output_layout.change event, not here.
2855+	 */
2856+	struct wlr_output_configuration_head_v1 *config_head;
2857+	int ok = 1;
2858+
2859+	wl_list_for_each(config_head, &config->heads, link) {
2860+		struct wlr_output *wlr_output = config_head->state.output;
2861+		Monitor *m = wlr_output->data;
2862+		struct wlr_output_state state;
2863+
2864+		/* Ensure displays previously disabled by wlr-output-power-management-v1
2865+		 * are properly handled*/
2866+		m->asleep = 0;
2867+
2868+		wlr_output_state_init(&state);
2869+		wlr_output_state_set_enabled(&state, config_head->state.enabled);
2870+		if (!config_head->state.enabled)
2871+			goto apply_or_test;
2872+
2873+		if (config_head->state.mode)
2874+			wlr_output_state_set_mode(&state, config_head->state.mode);
2875+		else
2876+			wlr_output_state_set_custom_mode(&state,
2877+					config_head->state.custom_mode.width,
2878+					config_head->state.custom_mode.height,
2879+					config_head->state.custom_mode.refresh);
2880+
2881+		wlr_output_state_set_transform(&state, config_head->state.transform);
2882+		wlr_output_state_set_scale(&state, config_head->state.scale);
2883+		wlr_output_state_set_adaptive_sync_enabled(&state,
2884+				config_head->state.adaptive_sync_enabled);
2885+
2886+apply_or_test:
2887+		ok &= test ? wlr_output_test_state(wlr_output, &state)
2888+				: wlr_output_commit_state(wlr_output, &state);
2889+
2890+		/* Don't move monitors if position wouldn't change. This avoids
2891+		 * wlroots marking the output as manually configured.
2892+		 * wlr_output_layout_add does not like disabled outputs */
2893+		if (!test && wlr_output->enabled && (m->m.x != config_head->state.x || m->m.y != config_head->state.y))
2894+			wlr_output_layout_add(output_layout, wlr_output,
2895+					config_head->state.x, config_head->state.y);
2896+
2897+		wlr_output_state_finish(&state);
2898+	}
2899+
2900+	if (ok)
2901+		wlr_output_configuration_v1_send_succeeded(config);
2902+	else
2903+		wlr_output_configuration_v1_send_failed(config);
2904+	wlr_output_configuration_v1_destroy(config);
2905+
2906+	/* https://codeberg.org/dwl/dwl/issues/577 */
2907+	updatemons(NULL, NULL);
2908+}
2909+
2910+void
2911+outputmgrtest(struct wl_listener *listener, void *data)
2912+{
2913+	struct wlr_output_configuration_v1 *config = data;
2914+	outputmgrapplyortest(config, 1);
2915+}
2916+
2917+void
2918+pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
2919+		uint32_t time)
2920+{
2921+	struct timespec now;
2922+
2923+	if (surface != seat->pointer_state.focused_surface &&
2924+			sloppyfocus && time && c && !client_is_unmanaged(c))
2925+		focusclient(c, 1);
2926+
2927+	/* If surface is NULL, clear pointer focus */
2928+	if (!surface) {
2929+		wlr_seat_pointer_notify_clear_focus(seat);
2930+		return;
2931+	}
2932+
2933+	if (!time) {
2934+		clock_gettime(CLOCK_MONOTONIC, &now);
2935+		time = now.tv_sec * 1000 + now.tv_nsec / 1000000;
2936+	}
2937+
2938+	/* Let the client know that the mouse cursor has entered one
2939+	 * of its surfaces, and make keyboard focus follow if desired.
2940+	 * wlroots makes this a no-op if surface is already focused */
2941+	wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
2942+	wlr_seat_pointer_notify_motion(seat, time, sx, sy);
2943+}
2944+
2945+void
2946+printstatus(void)
2947+{
2948+	Monitor *m = NULL;
2949+	Client *c;
2950+	uint32_t occ, urg, sel;
2951+
2952+	wl_list_for_each(m, &mons, link) {
2953+		occ = urg = 0;
2954+		wl_list_for_each(c, &clients, link) {
2955+			if (c->mon != m)
2956+				continue;
2957+			occ |= c->tags;
2958+			if (c->isurgent)
2959+				urg |= c->tags;
2960+		}
2961+		if ((c = focustop(m))) {
2962+			printf("%s title %s\n", m->wlr_output->name, client_get_title(c));
2963+			printf("%s appid %s\n", m->wlr_output->name, client_get_appid(c));
2964+			printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen);
2965+			printf("%s floating %d\n", m->wlr_output->name, c->isfloating);
2966+			sel = c->tags;
2967+		} else {
2968+			printf("%s title \n", m->wlr_output->name);
2969+			printf("%s appid \n", m->wlr_output->name);
2970+			printf("%s fullscreen \n", m->wlr_output->name);
2971+			printf("%s floating \n", m->wlr_output->name);
2972+			sel = 0;
2973+		}
2974+
2975+		printf("%s selmon %u\n", m->wlr_output->name, m == selmon);
2976+		printf("%s tags %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32"\n",
2977+			m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg);
2978+		printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol);
2979+	}
2980+	fflush(stdout);
2981+}
2982+
2983+void
2984+powermgrsetmode(struct wl_listener *listener, void *data)
2985+{
2986+	struct wlr_output_power_v1_set_mode_event *event = data;
2987+	struct wlr_output_state state = {0};
2988+	Monitor *m = event->output->data;
2989+
2990+	if (!m)
2991+		return;
2992+
2993+	m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the output */
2994+	wlr_output_state_set_enabled(&state, event->mode);
2995+	wlr_output_commit_state(m->wlr_output, &state);
2996+
2997+	m->asleep = !event->mode;
2998+	updatemons(NULL, NULL);
2999+}
3000+
3001+void
3002+quit(const Arg *arg)
3003+{
3004+	wl_display_terminate(dpy);
3005+}
3006+
3007+void
3008+rendermon(struct wl_listener *listener, void *data)
3009+{
3010+	Monitor *m = wl_container_of(listener, m, frame);
3011+	Client *c;
3012+	struct wlr_output_state pending = {0};
3013+	struct timespec now;
3014+
3015+	/* zoom */
3016+	zoom_frame(m);
3017+	/* zoom end */
3018+
3019+	wl_list_for_each(c, &clients, link) {
3020+		if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c))
3021+			goto skip;
3022+	}
3023+
3024+	/* zoom */
3025+	if (fabs(m->zoom_scale - 1.0) > 1e-5)
3026+		zoom_apply(m);
3027+	/* zoom end */
3028+
3029+	/* Build the complete scene state first, then hand that fully-rendered state
3030+	 * to the output backend.  This separates rendering from DRM submission and
3031+	 * lets wlroots apply its explicit-sync state when the backend supports it.
3032+	 * It is the closest wlroots-native equivalent to waiting for frame
3033+	 * completion before queueing the next frame. */
3034+	if (!wlr_scene_output_build_state(m->scene_output, &pending, NULL))
3035+		goto skip;
3036+	if (!wlr_output_commit_state(m->wlr_output, &pending))
3037+		wlr_log(WLR_ERROR, "Failed to commit rendered frame on %s", m->wlr_output->name);
3038+
3039+skip:
3040+	clock_gettime(CLOCK_MONOTONIC, &now);
3041+	wlr_scene_output_send_frame_done(m->scene_output, &now);
3042+	wlr_output_state_finish(&pending);
3043+}
3044+
3045+void
3046+requestdecorationmode(struct wl_listener *listener, void *data)
3047+{
3048+	Client *c = wl_container_of(listener, c, set_decoration_mode);
3049+	if (c->surface.xdg->initialized)
3050+		wlr_xdg_toplevel_decoration_v1_set_mode(c->decoration,
3051+				WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
3052+}
3053+
3054+void
3055+requeststartdrag(struct wl_listener *listener, void *data)
3056+{
3057+	struct wlr_seat_request_start_drag_event *event = data;
3058+
3059+	if (wlr_seat_validate_pointer_grab_serial(seat, event->origin,
3060+			event->serial))
3061+		wlr_seat_start_pointer_drag(seat, event->drag, event->serial);
3062+	else
3063+		wlr_data_source_destroy(event->drag->source);
3064+}
3065+
3066+void
3067+requestmonstate(struct wl_listener *listener, void *data)
3068+{
3069+	struct wlr_output_event_request_state *event = data;
3070+	wlr_output_commit_state(event->output, event->state);
3071+	updatemons(NULL, NULL);
3072+}
3073+
3074+void
3075+resize(Client *c, struct wlr_box geo, int interact)
3076+{
3077+	struct wlr_box *bbox;
3078+	struct wlr_box clip;
3079+
3080+#ifdef TILING
3081+	if (resizelock) {
3082+		c->geom = geo;
3083+		return;
3084+	}
3085+#endif
3086+	if (!c->mon || !client_surface(c)->mapped)
3087+		return;
3088+
3089+	bbox = interact ? &sgeom : &c->mon->w;
3090+
3091+	client_set_bounds(c, geo.width, geo.height);
3092+	c->geom = geo;
3093+	/* zoom */
3094+	if (c->mon && c->mon->lt[c->mon->sellt]->arrange == NULL
3095+			&& fabs(c->mon->zoom_scale - 1.0) >= 1e-9) {
3096+		c->geom.width  = MAX(1 + 2 * (int)c->bw, c->geom.width);
3097+		c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height);
3098+	} else
3099+	/* zoom end */
3100+	if (!(c->isfloating && c->mon->lt[c->mon->sellt]->arrange == NULL) || cursor_mode == CurResize)
3101+		applybounds(c, bbox);
3102+
3103+	/* zoom */
3104+	zoom_update_scene_client(c);
3105+	/* zoom end */
3106+
3107+	c->resize = client_set_size(c, c->geom.width - 2 * c->bw,
3108+			c->geom.height - 2 * c->bw);
3109+	client_get_clip(c, &clip);
3110+	wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
3111+}
3112+
3113+void
3114+run(char *startup_cmd)
3115+{
3116+	/* Add a Unix socket to the Wayland display. */
3117+	const char *socket = wl_display_add_socket_auto(dpy);
3118+	if (!socket)
3119+		die("startup: display_add_socket_auto");
3120+	setenv("WAYLAND_DISPLAY", socket, 1);
3121+
3122+	/* Start the backend. This will enumerate outputs and inputs, become the DRM
3123+	 * master, etc */
3124+	if (!wlr_backend_start(backend))
3125+		die("startup: backend_start");
3126+
3127+	/* Now that the socket exists and the backend is started, run the startup command */
3128+	if (startup_cmd) {
3129+		int piperw[2];
3130+		if (pipe(piperw) < 0)
3131+			die("startup: pipe:");
3132+		if ((child_pid = fork()) < 0)
3133+			die("startup: fork:");
3134+		if (child_pid == 0) {
3135+			setsid();
3136+			dup2(piperw[0], STDIN_FILENO);
3137+			close(piperw[0]);
3138+			close(piperw[1]);
3139+			execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL);
3140+			die("startup: execl:");
3141+		}
3142+		dup2(piperw[1], STDOUT_FILENO);
3143+		close(piperw[1]);
3144+		close(piperw[0]);
3145+	}
3146+
3147+	/* Mark stdout as non-blocking to avoid the startup script
3148+	 * causing leeloo to freeze when a user neither closes stdin
3149+	 * nor consumes standard input in his startup script */
3150+
3151+	if (fd_set_nonblock(STDOUT_FILENO) < 0)
3152+		close(STDOUT_FILENO);
3153+
3154+	printstatus();
3155+
3156+	/* At this point the outputs are initialized, choose initial selmon based on
3157+	 * cursor position, and set default cursor image */
3158+	selmon = xytomon(cursor->x, cursor->y);
3159+
3160+	/* TODO hack to get cursor to display in its initial location (100, 100)
3161+	 * instead of (0, 0) and then jumping. Still may not be fully
3162+	 * initialized, as the image/coordinates are not transformed for the
3163+	 * monitor when displayed here */
3164+	wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y);
3165+	wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
3166+
3167+	/* Run the Wayland event loop. This does not return until you exit the
3168+	 * compositor. Starting the backend rigged up all of the necessary event
3169+	 * loop configuration to listen to libinput events, DRM events, generate
3170+	 * frame events at the refresh rate, and so on. */
3171+	wl_display_run(dpy);
3172+}
3173+
3174+void
3175+setcursor(struct wl_listener *listener, void *data)
3176+{
3177+	/* This event is raised by the seat when a client provides a cursor image */
3178+	struct wlr_seat_pointer_request_set_cursor_event *event = data;
3179+	/* If we're "grabbing" the cursor, don't use the client's image, we will
3180+	 * restore it after "grabbing" sending a leave event, followed by a enter
3181+	 * event, which will result in the client requesting set the cursor surface */
3182+  if (spawnregion_active)
3183+		return;
3184+	if (cursor_mode != CurNormal && cursor_mode != CurPressed)
3185+		return;
3186+	/* This can be sent by any client, so we check to make sure this one
3187+	 * actually has pointer focus first. If so, we can tell the cursor to
3188+	 * use the provided surface as the cursor image. It will set the
3189+	 * hardware cursor on the output that it's currently on and continue to
3190+	 * do so as the cursor moves between outputs. */
3191+	if (event->seat_client == seat->pointer_state.focused_client)
3192+		wlr_cursor_set_surface(cursor, event->surface,
3193+				event->hotspot_x, event->hotspot_y);
3194+}
3195+
3196+void
3197+setcursorshape(struct wl_listener *listener, void *data)
3198+{
3199+	struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data;
3200+
3201+  if (spawnregion_active)
3202+		return;
3203+	if (cursor_mode != CurNormal && cursor_mode != CurPressed)
3204+		return;
3205+	/* This can be sent by any client, so we check to make sure this one
3206+	 * actually has pointer focus first. If so, we can tell the cursor to
3207+	 * use the provided cursor shape. */
3208+	if (event->seat_client == seat->pointer_state.focused_client)
3209+		wlr_cursor_set_xcursor(cursor, cursor_mgr,
3210+				wlr_cursor_shape_v1_name(event->shape));
3211+}
3212+
3213+void
3214+setfloating(Client *c, int floating)
3215+{
3216+	Client *p = client_get_parent(c);
3217+	c->isfloating = floating;
3218+	/* If in floating layout do not change the client's layer */
3219+	if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange)
3220+		return;
3221+	wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
3222+			(p && p->isfullscreen) ? LyrFS
3223+			: c->isfloating ? LyrFloat : LyrTile]);
3224+	arrange(c->mon);
3225+	printstatus();
3226+}
3227+
3228+void
3229+setfullscreen(Client *c, int fullscreen)
3230+{
3231+	if (c->isfakefullscreen)
3232+		return; /* avoid clobbering c->prev while fake fullscreen owns it */
3233+	c->isfullscreen = fullscreen;
3234+	if (!c->mon || !client_surface(c)->mapped)
3235+		return;
3236+
3237+  c->bw = fullscreen ? 0 : (innerborderpx + outerborderpx);
3238+  c->ibw = fullscreen ? 0 : innerborderpx;
3239+  c->obw = fullscreen ? 0 : outerborderpx;
3240+
3241+	client_set_fullscreen(c, fullscreen);
3242+	wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen
3243+			? LyrFS : c->isfloating ? LyrFloat : LyrTile]);
3244+
3245+	if (fullscreen) {
3246+		c->prev = c->geom;
3247+		resize(c, c->mon->m, 0);
3248+	} else {
3249+		/* restore previous size instead of arrange for floating windows since
3250+		 * client positions are set by the user and cannot be recalculated */
3251+		resize(c, c->prev, 0);
3252+	}
3253+	arrange(c->mon);
3254+	printstatus();
3255+}
3256+
3257+void
3258+setlayout(const Arg *arg)
3259+{
3260+	/* infinite_canvas */
3261+	const Layout *old_layout;
3262+  const Layout *new_layout;
3263+  Client *_c;
3264+	/* infinite_canvas_end */
3265+	if (!selmon)
3266+		return;
3267+
3268+	/* infinite_canvas */
3269+	old_layout = selmon->lt[selmon->sellt];
3270+	/* infinite_canvas_end */
3271+
3272+	if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
3273+		selmon->sellt ^= 1;
3274+	if (arg && arg->v)
3275+		selmon->lt[selmon->sellt] = (Layout *)arg->v;
3276+
3277+	/* infinite_canvas */
3278+  new_layout = selmon->lt[selmon->sellt];
3279+	if (old_layout->arrange == NULL && new_layout->arrange != NULL) {
3280+	  save_canvas_positions(selmon);
3281+		homecanvas(NULL);
3282+		wl_list_for_each(_c, &clients, link)
3283+			if (_c->mon == selmon && !_c->isfullscreen)
3284+				_c->isfloating = 0;
3285+	} else if (old_layout->arrange != NULL && new_layout->arrange == NULL) {
3286+	  restore_canvas_positions(selmon);
3287+		wl_list_for_each(_c, &clients, link)
3288+			if (_c->mon == selmon)
3289+				_c->isfloating = 1;
3290+	}
3291+	/* infinite_canvas_end */
3292+
3293+	strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, LENGTH(selmon->ltsymbol));
3294+	arrange(selmon);
3295+	printstatus();
3296+}
3297+
3298+/* arg > 1.0 will set mfact absolutely */
3299+void
3300+setmfact(const Arg *arg)
3301+{
3302+	float f;
3303+
3304+	if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange)
3305+		return;
3306+	f = arg->f < 1.0f ? arg->f + selmon->mfact : arg->f - 1.0f;
3307+	if (f < 0.1 || f > 0.9)
3308+		return;
3309+	selmon->mfact = f;
3310+	arrange(selmon);
3311+}
3312+
3313+void
3314+setmon(Client *c, Monitor *m, uint32_t newtags)
3315+{
3316+	Monitor *oldmon = c->mon;
3317+
3318+	if (oldmon == m)
3319+		return;
3320+	c->mon = m;
3321+	c->prev = c->geom;
3322+
3323+	/* Scene graph sends surface leave/enter events on move and resize */
3324+	if (oldmon)
3325+		arrange(oldmon);
3326+	if (m) {
3327+		/* Make sure window actually overlaps with the monitor */
3328+		resize(c, c->geom, 0);
3329+		c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */
3330+#if CENTER_NEW_WINDOWS
3331+    c->prev.x = (m->w.width - c->prev.width) / 2 + m->m.x;
3332+		c->prev.y = (m->w.height - c->prev.height) / 2 + m->m.y;
3333+#endif
3334+		setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */
3335+		setfloating(c, c->isfloating);
3336+		/* infinite_canvas: this window's home pan was captured under the
3337+		 * OLD monitor's independent canvas scale; that's meaningless on
3338+		 * the new monitor, so re-anchor it here exactly like a freshly
3339+		 * placed window (see mapnotify()), or bringintoview() will
3340+		 * compute a wrong/garbage shift for this window going forward. */
3341+		{
3342+			int tagidx = getcurrenttag(m);
3343+			c->home_cx = m->canvas[tagidx].cx;
3344+			c->home_cy = m->canvas[tagidx].cy;
3345+		}
3346+	}
3347+	focusclient(focustop(selmon), 1);
3348+}
3349+
3350+void
3351+setpsel(struct wl_listener *listener, void *data)
3352+{
3353+	/* This event is raised by the seat when a client wants to set the selection,
3354+	 * usually when the user copies something. wlroots allows compositors to
3355+	 * ignore such requests if they so choose, but in leeloo we always honor them
3356+	 */
3357+	struct wlr_seat_request_set_primary_selection_event *event = data;
3358+	wlr_seat_set_primary_selection(seat, event->source, event->serial);
3359+}
3360+
3361+void
3362+setsel(struct wl_listener *listener, void *data)
3363+{
3364+	/* This event is raised by the seat when a client wants to set the selection,
3365+	 * usually when the user copies something. wlroots allows compositors to
3366+	 * ignore such requests if they so choose, but in leeloo we always honor them
3367+	 */
3368+	struct wlr_seat_request_set_selection_event *event = data;
3369+	wlr_seat_set_selection(seat, event->source, event->serial);
3370+}
3371+
3372+void
3373+setup(void)
3374+{
3375+	int drm_fd, i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
3376+	struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
3377+	sigemptyset(&sa.sa_mask);
3378+
3379+	for (i = 0; i < (int)LENGTH(sig); i++)
3380+		sigaction(sig[i], &sa, NULL);
3381+
3382+	wlr_log_init(log_level, NULL);
3383+
3384+	/* The Wayland display is managed by libwayland. It handles accepting
3385+	 * clients from the Unix socket, managing Wayland globals, and so on. */
3386+	dpy = wl_display_create();
3387+	event_loop = wl_display_get_event_loop(dpy);
3388+
3389+	/* The backend is a wlroots feature which abstracts the underlying input and
3390+	 * output hardware. The autocreate option will choose the most suitable
3391+	 * backend based on the current environment, such as opening an X11 window
3392+	 * if an X11 server is running. */
3393+	if (!(backend = wlr_backend_autocreate(event_loop, &session)))
3394+		die("couldn't create backend");
3395+
3396+	/* Initialize the scene graph used to lay out windows */
3397+	scene = wlr_scene_create();
3398+	root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, rootcolor);
3399+	for (i = 0; i < NUM_LAYERS; i++)
3400+		layers[i] = wlr_scene_tree_create(&scene->tree);
3401+	drag_icon = wlr_scene_tree_create(&scene->tree);
3402+	wlr_scene_node_place_below(&drag_icon->node, &layers[LyrBlock]->node);
3403+
3404+	/* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user
3405+	 * can also specify a renderer using the WLR_RENDERER env var.
3406+	 * The renderer is responsible for defining the various pixel formats it
3407+	 * supports for shared memory, this configures that for clients. */
3408+	if (!(drw = wlr_renderer_autocreate(backend)))
3409+		die("couldn't create renderer");
3410+	wl_signal_add(&drw->events.lost, &gpu_reset);
3411+
3412+	/* Create shm, drm and linux_dmabuf interfaces by ourselves.
3413+	 * The simplest way is to call:
3414+	 *      wlr_renderer_init_wl_display(drw);
3415+	 * but we need to create the linux_dmabuf interface manually to integrate it
3416+	 * with wlr_scene. */
3417+	wlr_renderer_init_wl_shm(drw, dpy);
3418+
3419+	if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) {
3420+		wlr_drm_create(dpy, drw);
3421+		wlr_scene_set_linux_dmabuf_v1(scene,
3422+				wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw));
3423+	}
3424+
3425+	if ((drm_fd = wlr_renderer_get_drm_fd(drw)) >= 0 && drw->features.timeline
3426+			&& backend->features.timeline)
3427+		wlr_linux_drm_syncobj_manager_v1_create(dpy, 1, drm_fd);
3428+
3429+	/* Autocreates an allocator for us.
3430+	 * The allocator is the bridge between the renderer and the backend. It
3431+	 * handles the buffer creation, allowing wlroots to render onto the
3432+	 * screen */
3433+	if (!(alloc = wlr_allocator_autocreate(backend, drw)))
3434+		die("couldn't create allocator");
3435+
3436+	/* This creates some hands-off wlroots interfaces. The compositor is
3437+	 * necessary for clients to allocate surfaces and the data device manager
3438+	 * handles the clipboard. Each of these wlroots interfaces has room for you
3439+	 * to dig your fingers in and play with their behavior if you want. Note that
3440+	 * the clients cannot set the selection directly without compositor approval,
3441+	 * see the setsel() function. */
3442+	compositor = wlr_compositor_create(dpy, 6, drw);
3443+	wlr_subcompositor_create(dpy);
3444+	wlr_data_device_manager_create(dpy);
3445+	wlr_export_dmabuf_manager_v1_create(dpy);
3446+	wlr_screencopy_manager_v1_create(dpy);
3447+	wlr_data_control_manager_v1_create(dpy);
3448+	wlr_ext_data_control_manager_v1_create(dpy, 1);
3449+	wlr_primary_selection_v1_device_manager_create(dpy);
3450+	wlr_viewporter_create(dpy);
3451+	wlr_single_pixel_buffer_manager_v1_create(dpy);
3452+	wlr_fractional_scale_manager_v1_create(dpy, 1);
3453+	wlr_presentation_create(dpy, backend, 2);
3454+	wlr_alpha_modifier_v1_create(dpy);
3455+
3456+	/* Initializes the interface used to implement urgency hints */
3457+	activation = wlr_xdg_activation_v1_create(dpy);
3458+	wl_signal_add(&activation->events.request_activate, &request_activate);
3459+
3460+	wlr_scene_set_gamma_control_manager_v1(scene, wlr_gamma_control_manager_v1_create(dpy));
3461+
3462+	power_mgr = wlr_output_power_manager_v1_create(dpy);
3463+	wl_signal_add(&power_mgr->events.set_mode, &output_power_mgr_set_mode);
3464+
3465+	/* Creates an output layout, which is a wlroots utility for working with an
3466+	 * arrangement of screens in a physical layout. */
3467+	output_layout = wlr_output_layout_create(dpy);
3468+	wl_signal_add(&output_layout->events.change, &layout_change);
3469+
3470+	wlr_xdg_output_manager_v1_create(dpy, output_layout);
3471+
3472+	/* Configure a listener to be notified when new outputs are available on the
3473+	 * backend. */
3474+	wl_list_init(&mons);
3475+	wl_list_init(&savedstates);
3476+	wl_signal_add(&backend->events.new_output, &new_output);
3477+
3478+	/* Set up our client lists, the xdg-shell and the layer-shell. The xdg-shell is a
3479+	 * Wayland protocol which is used for application windows. For more
3480+	 * detail on shells, refer to the article:
3481+	 *
3482+	 * https://drewdevault.com/2018/07/29/Wayland-shells.html
3483+	 */
3484+	wl_list_init(&clients);
3485+	wl_list_init(&fstack);
3486+	/* zoom */
3487+	wl_list_init(&popup_zoom_list);
3488+	/* zoom end */
3489+
3490+	xdg_shell = wlr_xdg_shell_create(dpy, 6);
3491+	wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel);
3492+	wl_signal_add(&xdg_shell->events.new_popup, &new_xdg_popup);
3493+
3494+	layer_shell = wlr_layer_shell_v1_create(dpy, 3);
3495+	wl_signal_add(&layer_shell->events.new_surface, &new_layer_surface);
3496+
3497+	idle_notifier = wlr_idle_notifier_v1_create(dpy);
3498+
3499+	idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy);
3500+	wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &new_idle_inhibitor);
3501+
3502+	session_lock_mgr = wlr_session_lock_manager_v1_create(dpy);
3503+	wl_signal_add(&session_lock_mgr->events.new_lock, &new_session_lock);
3504+	locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height,
3505+			(float [4]){0.1f, 0.1f, 0.1f, 1.0f});
3506+	wlr_scene_node_set_enabled(&locked_bg->node, 0);
3507+
3508+	/* Use decoration protocols to negotiate server-side decorations */
3509+	wlr_server_decoration_manager_set_default_mode(
3510+			wlr_server_decoration_manager_create(dpy),
3511+			WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
3512+	xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy);
3513+	wl_signal_add(&xdg_decoration_mgr->events.new_toplevel_decoration, &new_xdg_decoration);
3514+
3515+	pointer_constraints = wlr_pointer_constraints_v1_create(dpy);
3516+	pointer_gestures = wlr_pointer_gestures_v1_create(dpy);
3517+	wl_signal_add(&pointer_constraints->events.new_constraint, &new_pointer_constraint);
3518+
3519+	relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy);
3520+  
3521+  /* tablet-input */
3522+  tablet_mgr = wlr_tablet_v2_create(dpy);
3523+  /* tablet-input end */
3524+
3525+	/*
3526+	 * Creates a cursor, which is a wlroots utility for tracking the cursor
3527+	 * image shown on screen.
3528+	 */
3529+	cursor = wlr_cursor_create();
3530+	wlr_cursor_attach_output_layout(cursor, output_layout);
3531+
3532+	/* Creates an xcursor manager, another wlroots utility which loads up
3533+	 * Xcursor themes to source cursor images from and makes sure that cursor
3534+	 * images are available at all scale factors on the screen (necessary for
3535+	 * HiDPI support). Scaled cursors will be loaded with each output. */
3536+	cursor_mgr = wlr_xcursor_manager_create(getenv("XCURSOR_THEME"),
3537+			getenv("XCURSOR_SIZE") ? atoi(getenv("XCURSOR_SIZE")) : 24);
3538+	setenv("XCURSOR_SIZE", getenv("XCURSOR_SIZE") ? getenv("XCURSOR_SIZE") : "24", 1);
3539+
3540+	/*
3541+	 * wlr_cursor *only* displays an image on screen. It does not move around
3542+	 * when the pointer moves. However, we can attach input devices to it, and
3543+	 * it will generate aggregate events for all of them. In these events, we
3544+	 * can choose how we want to process them, forwarding them to clients and
3545+	 * moving the cursor around. More detail on this process is described in
3546+	 * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html
3547+	 *
3548+	 * And more comments are sprinkled throughout the notify functions above.
3549+	 */
3550+	wl_signal_add(&cursor->events.motion, &cursor_motion);
3551+	wl_signal_add(&cursor->events.motion_absolute, &cursor_motion_absolute);
3552+	wl_signal_add(&cursor->events.button, &cursor_button);
3553+	wl_signal_add(&cursor->events.axis, &cursor_axis);
3554+	wl_signal_add(&cursor->events.frame, &cursor_frame);
3555+  
3556+  /* tablet-input */
3557+  wl_signal_add(&cursor->events.tablet_tool_proximity, &tablet_tool_proximity);
3558+	wl_signal_add(&cursor->events.tablet_tool_axis, &tablet_tool_axis);
3559+	wl_signal_add(&cursor->events.tablet_tool_button, &tablet_tool_button);
3560+	wl_signal_add(&cursor->events.tablet_tool_tip, &tablet_tool_tip);
3561+  /* tablet-input end */
3562+
3563+	cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1);
3564+	wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape);
3565+
3566+	/*
3567+	 * Configures a seat, which is a single "seat" at which a user sits and
3568+	 * operates the computer. This conceptually includes up to one keyboard,
3569+	 * pointer, touch, and drawing tablet device. We also rig up a listener to
3570+	 * let us know when new input devices are available on the backend.
3571+	 */
3572+	wl_signal_add(&backend->events.new_input, &new_input_device);
3573+	virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);
3574+	wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard,
3575+			&new_virtual_keyboard);
3576+	virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy);
3577+	wl_signal_add(&virtual_pointer_mgr->events.new_virtual_pointer,
3578+			&new_virtual_pointer);
3579+
3580+	seat = wlr_seat_create(dpy, "seat0");
3581+	wl_signal_add(&seat->events.request_set_cursor, &request_cursor);
3582+	wl_signal_add(&seat->events.request_set_selection, &request_set_sel);
3583+	wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel);
3584+	wl_signal_add(&seat->events.request_start_drag, &request_start_drag);
3585+	wl_signal_add(&seat->events.start_drag, &start_drag);
3586+
3587+	kb_group = createkeyboardgroup();
3588+	wl_list_init(&kb_group->destroy.link);
3589+
3590+	output_mgr = wlr_output_manager_v1_create(dpy);
3591+	wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);
3592+	wl_signal_add(&output_mgr->events.test, &output_mgr_test);
3593+
3594+	/* Make sure XWayland clients don't connect to the parent X server,
3595+	 * e.g when running in the x11 backend or the wayland backend and the
3596+	 * compositor has Xwayland support */
3597+	unsetenv("DISPLAY");
3598+#ifdef XWAYLAND
3599+	/*
3600+	 * Initialise the XWayland X server.
3601+	 * It will be started when the first X client is started.
3602+	 */
3603+	if ((xwayland = wlr_xwayland_create(dpy, compositor, 1))) {
3604+		wl_signal_add(&xwayland->events.ready, &xwayland_ready);
3605+		wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface);
3606+
3607+		setenv("DISPLAY", xwayland->display_name, 1);
3608+	} else {
3609+		fprintf(stderr, "failed to setup XWayland X server, continuing without it\n");
3610+	}
3611+#endif
3612+}
3613+
3614+void
3615+spawn(const Arg *arg)
3616+{
3617+	if (fork() == 0) {
3618+		dup2(STDERR_FILENO, STDOUT_FILENO);
3619+		setsid();
3620+		execvp(((char **)arg->v)[0], (char **)arg->v);
3621+		die("leeloo: execvp %s failed:", ((char **)arg->v)[0]);
3622+	}
3623+}
3624+
3625+void
3626+startdrag(struct wl_listener *listener, void *data)
3627+{
3628+	struct wlr_drag *drag = data;
3629+	if (!drag->icon)
3630+		return;
3631+
3632+	drag->icon->data = &wlr_scene_drag_icon_create(drag_icon, drag->icon)->node;
3633+	LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon);
3634+}
3635+
3636+void
3637+tag(const Arg *arg)
3638+{
3639+	Client *sel = focustop(selmon);
3640+	if (!sel || (arg->ui & TAGMASK) == 0)
3641+		return;
3642+
3643+	sel->tags = arg->ui & TAGMASK;
3644+	/* infinite_canvas */
3645+	if (selmon && selmon->lt[selmon->sellt]->arrange == NULL) {
3646+		int _i;
3647+		for (_i = 0; _i < TAGCOUNT; _i++) {
3648+			if (arg->ui & (1u << _i)) {
3649+				sel->saved_cx = selmon->canvas[_i].cx + (selmon->w.width  - sel->geom.width)  / 2;
3650+				sel->saved_cy = selmon->canvas[_i].cy + (selmon->w.height - sel->geom.height) / 2;
3651+				sel->saved_cw = sel->geom.width;
3652+				sel->saved_ch = sel->geom.height;
3653+				sel->was_on_canvas = 1;
3654+				break;
3655+			}
3656+		}
3657+	}
3658+	/* infinite_canvas_end */
3659+	focusclient(focustop(selmon), 1);
3660+	arrange(selmon);
3661+	printstatus();
3662+}
3663+
3664+void
3665+tagmon(const Arg *arg)
3666+{
3667+	Client *sel = focustop(selmon);
3668+	if (sel)
3669+		setmon(sel, dirtomon(arg->i), 0);
3670+}
3671+
3672+#ifndef MAGNET_SNAP_DIST
3673+#define MAGNET_SNAP_DIST 12 /* on-screen pixels within which a dragged window's edge magnetically aligns to another edge */
3674+#endif
3675+
3676+/* Adjusts a candidate drag position (*nx, *ny) so that if any edge of the
3677+ * dragged window c is within MAGNET_SNAP_DIST screen-pixels of an edge of
3678+ * another visible window (or the monitor's own usable area), it snaps
3679+ * flush against it -- GNOME/driftwm style magnetic edge alignment. Unlike
3680+ * trysnap(), this never resizes the window or forces it into a half/quarter
3681+ * region; it only nudges position, and only when actually close to an edge. */
3682+#ifndef ALIGN_SNAP_DIST
3683+#define ALIGN_SNAP_DIST 60 /* on-screen pixels: how much top/bottom mismatch still counts as "close enough" to auto-align when snapping side-by-side against a window */
3684+#endif
3685+
3686+static void
3687+snap_edges(Client *c, Monitor *m, int *nx, int *ny)
3688+{
3689+	Client *o, *xpartner = NULL;
3690+	struct wlr_box cand;
3691+	int best_dx = 0, best_dy = 0, have_dx = 0, have_dy = 0;
3692+	int thresh, align_tol;
3693+
3694+	if (!c || !m)
3695+		return;
3696+
3697+	thresh = MAGNET_SNAP_DIST;
3698+	if (m->zoom_scale > 1e-9)
3699+		thresh = (int)llround(MAGNET_SNAP_DIST / m->zoom_scale);
3700+	align_tol = ALIGN_SNAP_DIST;
3701+	if (m->zoom_scale > 1e-9)
3702+		align_tol = (int)llround(ALIGN_SNAP_DIST / m->zoom_scale);
3703+
3704+	cand.x = *nx;
3705+	cand.y = *ny;
3706+	cand.width = c->geom.width;
3707+	cand.height = c->geom.height;
3708+
3709+	/* Snap against the monitor's own usable-area edges. */
3710+	{
3711+		struct wlr_box *w = &m->w;
3712+		int d;
3713+		d = abs(cand.x - w->x);
3714+		if (d <= thresh && (!have_dx || d < abs(best_dx))) { best_dx = w->x - cand.x; have_dx = 1; }
3715+		d = abs((cand.x + cand.width) - (w->x + w->width));
3716+		if (d <= thresh && (!have_dx || d < abs(best_dx))) { best_dx = (w->x + w->width) - (cand.x + cand.width); have_dx = 1; }
3717+		d = abs(cand.y - w->y);
3718+		if (d <= thresh && (!have_dy || d < abs(best_dy))) { best_dy = w->y - cand.y; have_dy = 1; }
3719+		d = abs((cand.y + cand.height) - (w->y + w->height));
3720+		if (d <= thresh && (!have_dy || d < abs(best_dy))) { best_dy = (w->y + w->height) - (cand.y + cand.height); have_dy = 1; }
3721+	}
3722+
3723+	/* Snap against every other visible window's edges, at whatever
3724+	 * size each window actually is -- no resizing involved. */
3725+	wl_list_for_each(o, &clients, link) {
3726+		int d;
3727+		if (o == c || !VISIBLEON(o, m))
3728+			continue;
3729+
3730+		/* Only snap horizontally if the two windows vertically overlap
3731+		 * (and vice versa) -- otherwise aligning to a window nowhere
3732+		 * near it vertically would look wrong, not like a real snap. */
3733+		if (cand.y < o->geom.y + o->geom.height && o->geom.y < cand.y + cand.height) {
3734+			d = abs(cand.x - o->geom.x);
3735+			if (d <= thresh && (!have_dx || d < abs(best_dx))) { best_dx = o->geom.x - cand.x; have_dx = 1; xpartner = o; }
3736+			d = abs(cand.x - (o->geom.x + o->geom.width));
3737+			if (d <= thresh && (!have_dx || d < abs(best_dx))) { best_dx = (o->geom.x + o->geom.width) - cand.x; have_dx = 1; xpartner = o; }
3738+			d = abs((cand.x + cand.width) - (o->geom.x + o->geom.width));
3739+			if (d <= thresh && (!have_dx || d < abs(best_dx))) { best_dx = (o->geom.x + o->geom.width) - (cand.x + cand.width); have_dx = 1; xpartner = o; }
3740+			d = abs((cand.x + cand.width) - o->geom.x);
3741+			if (d <= thresh && (!have_dx || d < abs(best_dx))) { best_dx = o->geom.x - (cand.x + cand.width); have_dx = 1; xpartner = o; }
3742+		}
3743+
3744+		if (cand.x < o->geom.x + o->geom.width && o->geom.x < cand.x + cand.width) {
3745+			d = abs(cand.y - o->geom.y);
3746+			if (d <= thresh && (!have_dy || d < abs(best_dy))) { best_dy = o->geom.y - cand.y; have_dy = 1; }
3747+			d = abs(cand.y - (o->geom.y + o->geom.height));
3748+			if (d <= thresh && (!have_dy || d < abs(best_dy))) { best_dy = (o->geom.y + o->geom.height) - cand.y; have_dy = 1; }
3749+			d = abs((cand.y + cand.height) - (o->geom.y + o->geom.height));
3750+			if (d <= thresh && (!have_dy || d < abs(best_dy))) { best_dy = (o->geom.y + o->geom.height) - (cand.y + cand.height); have_dy = 1; }
3751+			d = abs((cand.y + cand.height) - o->geom.y);
3752+			if (d <= thresh && (!have_dy || d < abs(best_dy))) { best_dy = o->geom.y - (cand.y + cand.height); have_dy = 1; }
3753+		}
3754+	}
3755+
3756+	/* Compound alignment: if we're snapping side-by-side against a
3757+	 * specific window (xpartner) and didn't already find a tight,
3758+	 * independent Y-edge snap, check whether that partner's top or
3759+	 * bottom edge is within a moderate tolerance -- close enough that
3760+	 * it looks like it was "meant" to line up (a bit higher/lower is
3761+	 * fine). If the mismatch is large (genuinely far apart vertically,
3762+	 * not just a small offset), leave the vertical position untouched. */
3763+	if (have_dx && xpartner && !have_dy) {
3764+		int top_d = abs(cand.y - xpartner->geom.y);
3765+		int bot_d = abs((cand.y + cand.height) - (xpartner->geom.y + xpartner->geom.height));
3766+		if (top_d <= align_tol || bot_d <= align_tol) {
3767+			if (top_d <= bot_d)
3768+				best_dy = xpartner->geom.y - cand.y;
3769+			else
3770+				best_dy = (xpartner->geom.y + xpartner->geom.height) - (cand.y + cand.height);
3771+			have_dy = 1;
3772+		}
3773+	}
3774+
3775+	*nx += best_dx;
3776+	*ny += best_dy;
3777+}
3778+
3779+#ifndef RESIZE_MAGNET_SNAP_DIST
3780+#define RESIZE_MAGNET_SNAP_DIST 48
3781+#endif
3782+#ifndef RESIZE_MAGNET_RELEASE_DIST
3783+#define RESIZE_MAGNET_RELEASE_DIST 80
3784+#endif
3785+
3786+/* When a floating window is already magnetically touching another window,
3787+ * resizing its lower/right edge acts like a shared divider.  Near the
3788+ * balanced size, the divider becomes sticky and snaps to the exact
3789+ * half-way point of the two-window cluster. */
3790+static void
3791+resize_magnetically(Client *c, Monitor *m, struct wlr_box *geo)
3792+{
3793+	Client *o, *right = NULL, *below = NULL;
3794+	int minw, minh, thresh, release;
3795+	int right_edge, bottom_edge;
3796+	int x_best = 0, y_best = 0;
3797+	int xdist = 0x3fffffff, ydist = 0x3fffffff;
3798+	int cluster_left, cluster_right, cluster_top, cluster_bottom;
3799+	int balance_x, balance_y;
3800+	int proposed_x, proposed_y;
3801+
3802+	if (!c || !m || !geo)
3803+		return;
3804+
3805+	thresh = RESIZE_MAGNET_SNAP_DIST;
3806+	release = RESIZE_MAGNET_RELEASE_DIST;
3807+	if (m->zoom_scale > 1e-9) {
3808+		thresh = (int)llround((double)RESIZE_MAGNET_SNAP_DIST / m->zoom_scale);
3809+		release = (int)llround((double)RESIZE_MAGNET_RELEASE_DIST / m->zoom_scale);
3810+	}
3811+
3812+	minw = 1 + 2 * (int)c->bw;
3813+	minh = 1 + 2 * (int)c->bw;
3814+
3815+	/* Find a window magnetically attached to the moving right edge. */
3816+	wl_list_for_each(o, &clients, link) {
3817+		int gap, overlap;
3818+		if (o == c || o->mon != m || !VISIBLEON(o, m) || o->isfullscreen)
3819+			continue;
3820+
3821+		overlap = MIN(c->geom.y + c->geom.height, o->geom.y + o->geom.height)
3822+			- MAX(c->geom.y, o->geom.y);
3823+		if (overlap <= 0)
3824+			continue;
3825+
3826+		gap = abs((c->geom.x + c->geom.width) - o->geom.x);
3827+		if (gap <= MAGNET_SNAP_DIST && o->geom.x >= c->geom.x + minw
3828+				&& gap < xdist) {
3829+			right = o;
3830+			xdist = gap;
3831+		}
3832+	}
3833+
3834+	/* Find a window magnetically attached to the moving bottom edge. */
3835+	wl_list_for_each(o, &clients, link) {
3836+		int gap, overlap;
3837+		if (o == c || o->mon != m || !VISIBLEON(o, m) || o->isfullscreen)
3838+			continue;
3839+
3840+		overlap = MIN(c->geom.x + c->geom.width, o->geom.x + o->geom.width)
3841+			- MAX(c->geom.x, o->geom.x);
3842+		if (overlap <= 0)
3843+			continue;
3844+
3845+		gap = abs((c->geom.y + c->geom.height) - o->geom.y);
3846+		if (gap <= MAGNET_SNAP_DIST && o->geom.y >= c->geom.y + minh
3847+				&& gap < ydist) {
3848+			below = o;
3849+			ydist = gap;
3850+		}
3851+	}
3852+
3853+	/* Horizontal cluster: c | right
3854+	 * Keep the shared divider intact and snap it to the exact 50/50 point
3855+	 * when the two widths are close enough. */
3856+	if (right) {
3857+		right_edge = geo->x + geo->width;
3858+		cluster_left = c->geom.x;
3859+		cluster_right = right->geom.x + right->geom.width;
3860+		balance_x = cluster_left + (cluster_right - cluster_left) / 2;
3861+		proposed_x = right_edge;
3862+
3863+		if (resize_snap_x_target) {
3864+			if (abs(proposed_x - resize_snap_x_target) <= release) {
3865+				proposed_x = resize_snap_x_target;
3866+			} else {
3867+				resize_snap_x_target = 0;
3868+			}
3869+		}
3870+
3871+		if (!resize_snap_x_target &&
3872+				abs((proposed_x - cluster_left) - right->geom.width) <= thresh) {
3873+			resize_snap_x_target = balance_x;
3874+			proposed_x = balance_x;
3875+		}
3876+
3877+		/* Respect minimum sizes on both sides. */
3878+		proposed_x = MAX(cluster_left + minw, proposed_x);
3879+		proposed_x = MIN(cluster_right - (1 + 2 * (int)right->bw), proposed_x);
3880+
3881+		if (resize_snap_x_target)
3882+			resize_snap_x_target = proposed_x;
3883+
3884+		geo->width = MAX(minw, proposed_x - c->geom.x);
3885+
3886+		/* Resize the partner so the magnetic connection stays intact. */
3887+		{
3888+			struct wlr_box other = right->geom;
3889+			other.x = proposed_x;
3890+			other.width = cluster_right - proposed_x;
3891+			if (other.width >= 1 + 2 * (int)right->bw)
3892+				resize(right, other, 1);
3893+		}
3894+	} else {
3895+		resize_snap_x_target = 0;
3896+	}
3897+
3898+	/* Vertical cluster: c
3899+	 *                  ---
3900+	 *                  below
3901+	 *
3902+	 * Same sticky 50/50 divider behavior for the bottom edge. */
3903+	if (below) {
3904+		bottom_edge = geo->y + geo->height;
3905+		cluster_top = c->geom.y;
3906+		cluster_bottom = below->geom.y + below->geom.height;
3907+		balance_y = cluster_top + (cluster_bottom - cluster_top) / 2;
3908+		proposed_y = bottom_edge;
3909+
3910+		if (resize_snap_y_target) {
3911+			if (abs(proposed_y - resize_snap_y_target) <= release) {
3912+				proposed_y = resize_snap_y_target;
3913+			} else {
3914+				resize_snap_y_target = 0;
3915+			}
3916+		}
3917+
3918+		if (!resize_snap_y_target &&
3919+				abs((proposed_y - cluster_top) - below->geom.height) <= thresh) {
3920+			resize_snap_y_target = balance_y;
3921+			proposed_y = balance_y;
3922+		}
3923+
3924+		proposed_y = MAX(cluster_top + minh, proposed_y);
3925+		proposed_y = MIN(cluster_bottom - (1 + 2 * (int)below->bw), proposed_y);
3926+
3927+		if (resize_snap_y_target)
3928+			resize_snap_y_target = proposed_y;
3929+
3930+		geo->height = MAX(minh, proposed_y - c->geom.y);
3931+
3932+		/* Resize the partner so the magnetic connection stays intact. */
3933+		{
3934+			struct wlr_box other = below->geom;
3935+			other.y = proposed_y;
3936+			other.height = cluster_bottom - proposed_y;
3937+			if (other.height >= 1 + 2 * (int)below->bw)
3938+				resize(below, other, 1);
3939+		}
3940+	} else {
3941+		resize_snap_y_target = 0;
3942+	}
3943+}
3944+
3945+
3946+#ifdef TILING
3947+void
3948+tile(Monitor *m)
3949+{
3950+	unsigned int mw, my, ty;
3951+	int i, n = 0;
3952+	Client *c;
3953+
3954+	wl_list_for_each(c, &clients, link)
3955+		if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
3956+			n++;
3957+	if (n == 0)
3958+		return;
3959+
3960+	if (n > m->nmaster)
3961+		mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0;
3962+	else
3963+		mw = m->w.width;
3964+	i = my = ty = 0;
3965+	wl_list_for_each(c, &clients, link) {
3966+		if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
3967+			continue;
3968+		if (i < m->nmaster) {
3969+			resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,
3970+				.height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0);
3971+			my += c->geom.height;
3972+		} else {
3973+			resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,
3974+				.width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0);
3975+			ty += c->geom.height;
3976+		}
3977+		i++;
3978+	}
3979+}
3980+
3981+void
3982+togglefloating(const Arg *arg)
3983+{
3984+	Client *sel = focustop(selmon);
3985+	/* return if fullscreen */
3986+	if (sel && !sel->isfullscreen)
3987+		setfloating(sel, !sel->isfloating);
3988+}
3989+#endif
3990+
3991+void
3992+togglefullscreen(const Arg *arg)
3993+{
3994+	Client *sel = focustop(selmon);
3995+	if (sel)
3996+		setfullscreen(sel, !sel->isfullscreen);
3997+}
3998+
3999+void
4000+togglefakefullscreen(const Arg *arg)
4001+{
4002+	Client *c = focustop(selmon);
4003+
4004+	if (!c || !c->mon || c->isfullscreen)
4005+		return; /* real fullscreen already owns the screen; don't fight it */
4006+
4007+	if (!c->isfakefullscreen) {
4008+		/* Fake fullscreen covers the whole usable monitor, but keeps Leeloo's
4009+		 * normal double border visible. Remember the old geometry first so the
4010+		 * exact window position and size can be restored when toggled off. */
4011+		c->prev = c->geom;
4012+		c->isfakefullscreen = 1;
4013+		if (!c->isfloating)
4014+			setfloating(c, 1);
4015+
4016+		c->bw = innerborderpx + outerborderpx;
4017+		c->ibw = innerborderpx;
4018+		c->obw = outerborderpx;
4019+		resize(c, c->mon->m, 0);
4020+	} else {
4021+		c->isfakefullscreen = 0;
4022+		c->bw = innerborderpx + outerborderpx;
4023+		c->ibw = innerborderpx;
4024+		c->obw = outerborderpx;
4025+		resize(c, c->prev, 0);
4026+	}
4027+	arrange(c->mon);
4028+	printstatus();
4029+}
4030+
4031+/* labwc-style directional snap state machine.
4032+ *
4033+ * The 8 snap states are:
4034+ *
4035+ *        TL   T   TR
4036+ *         L   F    R
4037+ *        BL   B   BR
4038+ *
4039+ * Directional keys move between adjacent states along the corresponding
4040+ * axis.  F is the bridge between opposite full-height/full-width states.
4041+ */
4042+void
4043+snaptoposition(const Arg *arg)
4044+{
4045+	Client *c = focustop(selmon);
4046+	struct wlr_box *w;
4047+	struct wlr_box left, right, top, bottom;
4048+	struct wlr_box tl, tr, bl, br;
4049+	struct wlr_box box, cur;
4050+	int state = -1;
4051+	int halfw, halfh, rightw, bottomh;
4052+
4053+	if (!c || !c->mon || c->isfullscreen || c->isfakefullscreen)
4054+		return;
4055+	if (!c->isfloating)
4056+		setfloating(c, 1);
4057+
4058+	w = &c->mon->w;
4059+
4060+	halfw = w->width / 2;
4061+	halfh = w->height / 2;
4062+	rightw = w->width - halfw;
4063+	bottomh = w->height - halfh;
4064+
4065+	left   = (struct wlr_box){w->x, w->y, halfw, w->height};
4066+	right  = (struct wlr_box){w->x + halfw, w->y, rightw, w->height};
4067+	top    = (struct wlr_box){w->x, w->y, w->width, halfh};
4068+	bottom = (struct wlr_box){w->x, w->y + halfh, w->width, bottomh};
4069+	tl     = (struct wlr_box){w->x, w->y, halfw, halfh};
4070+	tr     = (struct wlr_box){w->x + halfw, w->y, rightw, halfh};
4071+	bl     = (struct wlr_box){w->x, w->y + halfh, halfw, bottomh};
4072+	br     = (struct wlr_box){w->x + halfw, w->y + halfh, rightw, bottomh};
4073+
4074+	cur = c->geom;
4075+
4076+	/* c->geom stores the exact snap box, including the compositor border.
4077+	 * Use exact geometry matching here: >= would let a larger side or full-screen
4078+	 * box also match a corner state and break the directional state machine. */
4079+	if (cur.x == tl.x && cur.y == tl.y &&
4080+			cur.width == tl.width &&
4081+			cur.height == tl.height)
4082+		state = 1; /* top-left */
4083+	else if (cur.x == top.x && cur.y == top.y &&
4084+			cur.width == top.width &&
4085+			cur.height == top.height)
4086+		state = 2; /* top */
4087+	else if (cur.x == tr.x && cur.y == tr.y &&
4088+			cur.width == tr.width &&
4089+			cur.height == tr.height)
4090+		state = 3; /* top-right */
4091+	else if (cur.x == right.x && cur.y == right.y &&
4092+			cur.width == right.width &&
4093+			cur.height == right.height)
4094+		state = 4; /* right */
4095+	else if (cur.x == br.x && cur.y == br.y &&
4096+			cur.width == br.width &&
4097+			cur.height == br.height)
4098+		state = 5; /* bottom-right */
4099+	else if (cur.x == bottom.x && cur.y == bottom.y &&
4100+			cur.width == bottom.width &&
4101+			cur.height == bottom.height)
4102+		state = 6; /* bottom */
4103+	else if (cur.x == bl.x && cur.y == bl.y &&
4104+			cur.width == bl.width &&
4105+			cur.height == bl.height)
4106+		state = 7; /* bottom-left */
4107+	else if (cur.x == left.x && cur.y == left.y &&
4108+			cur.width == left.width &&
4109+			cur.height == left.height)
4110+		state = 0; /* left */
4111+	else if (cur.x == w->x && cur.y == w->y &&
4112+			cur.width == w->width &&
4113+			cur.height == w->height)
4114+		state = 8; /* fake/fullscreen snap bridge */
4115+
4116+	/* Unknown geometry: a directional key simply snaps into its requested
4117+	 * destination rather than trying to infer a previous state. */
4118+	if (state < 0) {
4119+		switch (arg->i) {
4120+		case SnapLeft:        box = left; break;
4121+		case SnapRight:       box = right; break;
4122+		case SnapTop:         box = top; break;
4123+		case SnapBottom:      box = bottom; break;
4124+		case SnapTopLeft:     box = tl; break;
4125+		case SnapTopRight:    box = tr; break;
4126+		case SnapBottomLeft:  box = bl; break;
4127+		case SnapBottomRight: box = br; break;
4128+		default: return;
4129+		}
4130+		resize(c, box, 0);
4131+		return;
4132+	}
4133+
4134+	/* Explicit directional state graph.  This keeps every edge deterministic
4135+	 * and avoids the old fullscreen/corner fall-through bugs. */
4136+	switch (arg->i) {
4137+	case SnapLeft:
4138+		switch (state) {
4139+		case 2: box = tl; break; /* T  -> TL */
4140+		case 3: box = top; break; /* TR -> T */
4141+		case 4: box = *w; break;
4142+		case 5: box = bottom; break; /* BR -> B */
4143+		case 6: box = bl; break; /* B  -> BL */
4144+		case 7: box = br; break; /* BL -> BR */
4145+		case 8: box = left; break; /* F  -> L */
4146+		default: return;
4147+		}
4148+		break;
4149+
4150+	case SnapRight:
4151+		switch (state) {
4152+		case 0: box = *w; break; /* L  -> F */
4153+		case 1: box = top; break; /* TL -> T */
4154+		case 2: box = tr; break; /* T  -> TR */
4155+		case 5: box = bl; break; /* BR -> BL */
4156+		case 6: box = br; break; /* B  -> BR */
4157+		case 7: box = bottom; break; /* BL -> B */
4158+		case 8: box = right; break; /* F  -> R */
4159+		default: return;
4160+		}
4161+		break;
4162+
4163+	case SnapTop:
4164+		switch (state) {
4165+		case 0: box = tl; break; /* L  -> TL */
4166+		case 1: box = top; break; /* TL -> T */
4167+		case 3: box = top; break; /* TR -> T */
4168+		case 4: box = tr; break; /* R  -> TR */
4169+		case 5: box = right; break; /* BR -> R */
4170+		case 6: box = *w; break; /* B  -> F */
4171+		case 7: box = left; break; /* BL -> L */
4172+		case 8: box = top; break; /* F  -> T */
4173+		default: return;
4174+		}
4175+		break;
4176+
4177+	case SnapBottom:
4178+		switch (state) {
4179+		case 0: box = bl; break; /* L  -> BL */
4180+		case 1: box = left; break; /* TL -> L */
4181+		case 2: box = *w; break; /* T  -> F */
4182+		case 3: box = right; break; /* TR -> R */
4183+		case 4: box = br; break; /* R  -> BR */
4184+		case 5: box = right; break; /* BR -> R */
4185+		case 7: box = bottom; break; /* BL -> B */
4186+		case 8: box = bottom; break; /* F  -> B */
4187+		default: return;
4188+		}
4189+		break;
4190+
4191+	case SnapTopLeft:     box = tl; break;
4192+	case SnapTopRight:    box = tr; break;
4193+	case SnapBottomLeft:  box = bl; break;
4194+	case SnapBottomRight: box = br; break;
4195+	default: return;
4196+	}
4197+
4198+	resize(c, box, 0);
4199+}
4200+
4201+void
4202+toggletag(const Arg *arg)
4203+{
4204+	uint32_t newtags;
4205+	Client *sel = focustop(selmon);
4206+	if (!sel || !(newtags = sel->tags ^ (arg->ui & TAGMASK)))
4207+		return;
4208+
4209+	sel->tags = newtags;
4210+	focusclient(focustop(selmon), 1);
4211+	arrange(selmon);
4212+	printstatus();
4213+}
4214+
4215+void
4216+toggleview(const Arg *arg)
4217+{
4218+	uint32_t newtagset;
4219+	if (!(newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0))
4220+		return;
4221+
4222+	selmon->tagset[selmon->seltags] = newtagset;
4223+	focusclient(focustop(selmon), 1);
4224+	arrange(selmon);
4225+	printstatus();
4226+}
4227+
4228+void
4229+unlocksession(struct wl_listener *listener, void *data)
4230+{
4231+	SessionLock *lock = wl_container_of(listener, lock, unlock);
4232+	destroylock(lock, 1);
4233+}
4234+
4235+void
4236+unmaplayersurfacenotify(struct wl_listener *listener, void *data)
4237+{
4238+	LayerSurface *l = wl_container_of(listener, l, unmap);
4239+
4240+	l->mapped = 0;
4241+	wlr_scene_node_set_enabled(&l->scene->node, 0);
4242+	if (l == exclusive_focus)
4243+		exclusive_focus = NULL;
4244+	if (l->layer_surface->output && (l->mon = l->layer_surface->output->data))
4245+		arrangelayers(l->mon);
4246+	if (l->layer_surface->surface == seat->keyboard_state.focused_surface)
4247+		focusclient(focustop(selmon), 1);
4248+	motionnotify(0, NULL, 0, 0, 0, 0);
4249+}
4250+
4251+void
4252+unmapnotify(struct wl_listener *listener, void *data)
4253+{
4254+	/* Called when the surface is unmapped, and should no longer be shown. */
4255+	Client *c = wl_container_of(listener, c, unmap);
4256+	if (c == grabc) {
4257+		cursor_mode = CurNormal;
4258+		grabc = NULL;
4259+	}
4260+
4261+	if (client_is_unmanaged(c)) {
4262+		if (c == exclusive_focus) {
4263+			exclusive_focus = NULL;
4264+			focusclient(focustop(selmon), 1);
4265+		}
4266+	} else {
4267+		wl_list_remove(&c->link);
4268+		setmon(c, NULL, 0);
4269+		wl_list_remove(&c->flink);
4270+	}
4271+  
4272+  if (c == waiting_geo_client)
4273+    waiting_geo_client = NULL;
4274+
4275+	wlr_scene_node_destroy(&c->scene->node);
4276+	printstatus();
4277+	motionnotify(0, NULL, 0, 0, 0, 0);
4278+}
4279+
4280+void
4281+updatemons(struct wl_listener *listener, void *data)
4282+{
4283+	/*
4284+	 * Called whenever the output layout changes: adding or removing a
4285+	 * monitor, changing an output's mode or position, etc. This is where
4286+	 * the change officially happens and we update geometry, window
4287+	 * positions, focus, and the stored configuration in wlroots'
4288+	 * output-manager implementation.
4289+	 */
4290+	struct wlr_output_configuration_v1 *config
4291+			= wlr_output_configuration_v1_create();
4292+	Client *c;
4293+	struct wlr_output_configuration_head_v1 *config_head;
4294+	Monitor *m;
4295+
4296+	/* First remove from the layout the disabled monitors */
4297+	wl_list_for_each(m, &mons, link) {
4298+		if (m->wlr_output->enabled || m->asleep)
4299+			continue;
4300+		config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);
4301+		config_head->state.enabled = 0;
4302+		/* Remove this output from the layout to avoid cursor enter inside it */
4303+		wlr_output_layout_remove(output_layout, m->wlr_output);
4304+		closemon(m);
4305+		m->m = m->w = (struct wlr_box){0};
4306+	}
4307+	/* Insert outputs that need to */
4308+	wl_list_for_each(m, &mons, link) {
4309+		if (m->wlr_output->enabled
4310+				&& !wlr_output_layout_get(output_layout, m->wlr_output))
4311+			wlr_output_layout_add_auto(output_layout, m->wlr_output);
4312+	}
4313+
4314+	/* Now that we update the output layout we can get its box */
4315+	wlr_output_layout_get_box(output_layout, NULL, &sgeom);
4316+
4317+	wlr_scene_node_set_position(&root_bg->node, sgeom.x, sgeom.y);
4318+	wlr_scene_rect_set_size(root_bg, sgeom.width, sgeom.height);
4319+
4320+	/* Make sure the clients are hidden when leeloo is locked */
4321+	wlr_scene_node_set_position(&locked_bg->node, sgeom.x, sgeom.y);
4322+	wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height);
4323+
4324+	wl_list_for_each(m, &mons, link) {
4325+		if (!m->wlr_output->enabled)
4326+			continue;
4327+		config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);
4328+
4329+		/* Get the effective monitor geometry to use for surfaces */
4330+		wlr_output_layout_get_box(output_layout, m->wlr_output, &m->m);
4331+		m->w = m->m;
4332+		wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y);
4333+
4334+		wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y);
4335+		wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height);
4336+
4337+		if (m->lock_surface) {
4338+			struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data;
4339+			wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y);
4340+			wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, m->m.height);
4341+		}
4342+
4343+		/* Calculate the effective monitor geometry to use for clients */
4344+		arrangelayers(m);
4345+		/* Don't move clients to the left output when plugging monitors */
4346+		arrange(m);
4347+		/* make sure fullscreen clients have the right size */
4348+		if ((c = focustop(m)) && c->isfullscreen)
4349+			resize(c, m->m, 0);
4350+
4351+		/* Try to re-set the gamma LUT when updating monitors,
4352+		 * it's only really needed when enabling a disabled output, but meh. */
4353+		m->gamma_lut_changed = 1;
4354+
4355+		config_head->state.x = m->m.x;
4356+		config_head->state.y = m->m.y;
4357+
4358+		if (!selmon) {
4359+			selmon = m;
4360+		}
4361+	}
4362+
4363+	if (selmon && selmon->wlr_output->enabled) {
4364+		wl_list_for_each(c, &clients, link) {
4365+			if (!c->mon && client_surface(c)->mapped)
4366+				setmon(c, selmon, c->tags);
4367+		}
4368+		focusclient(focustop(selmon), 1);
4369+		if (selmon->lock_surface) {
4370+			client_notify_enter(selmon->lock_surface->surface,
4371+					wlr_seat_get_keyboard(seat));
4372+			client_activate_surface(selmon->lock_surface->surface, 1);
4373+		}
4374+	}
4375+
4376+	/* FIXME: figure out why the cursor image is at 0,0 after turning all
4377+	 * the monitors on.
4378+	 * Move the cursor image where it used to be. It does not generate a
4379+	 * wl_pointer.motion event for the clients, it's only the image what it's
4380+	 * at the wrong position after all. */
4381+	wlr_cursor_move(cursor, NULL, 0, 0);
4382+
4383+	wlr_output_manager_v1_set_configuration(output_mgr, config);
4384+}
4385+
4386+void
4387+updatetitle(struct wl_listener *listener, void *data)
4388+{
4389+	Client *c = wl_container_of(listener, c, set_title);
4390+	if (c == focustop(c->mon))
4391+		printstatus();
4392+}
4393+
4394+void
4395+urgent(struct wl_listener *listener, void *data)
4396+{
4397+	struct wlr_xdg_activation_v1_request_activate_event *event = data;
4398+	Client *c = NULL;
4399+	toplevel_from_wlr_surface(event->surface, &c, NULL);
4400+	if (!c || c == focustop(selmon))
4401+		return;
4402+
4403+	c->isurgent = 1;
4404+	printstatus();
4405+
4406+	if (client_surface(c)->mapped)
4407+		client_set_border_color(c, urgent_inner_border_color, urgent_outer_border_color);
4408+}
4409+
4410+void
4411+view(const Arg *arg)
4412+{
4413+	if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
4414+		return;
4415+
4416+	/* infinite_canvas */
4417+	if (selmon->lt[selmon->sellt]->arrange == NULL)
4418+		save_canvas_positions(selmon);
4419+	/* infinite_canvas_end */
4420+
4421+	selmon->seltags ^= 1; /* toggle sel tagset */
4422+	if (arg->ui & TAGMASK)
4423+		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
4424+
4425+	/* infinite_canvas */
4426+	{
4427+		int _newtag = getcurrenttag(selmon);
4428+		Client *_c;
4429+		if (selmon->lt[selmon->sellt]->arrange != NULL) {
4430+			selmon->canvas[_newtag].cx = 0;
4431+			selmon->canvas[_newtag].cy = 0;
4432+		} else {
4433+			restore_canvas_positions(selmon);
4434+			wl_list_for_each(_c, &clients, link)
4435+				if (VISIBLEON(_c, selmon))
4436+					_c->isfloating = 1;
4437+		}
4438+	}
4439+	/* infinite_canvas_end */
4440+
4441+	focusclient(focustop(selmon), 1);
4442+	arrange(selmon);
4443+	printstatus();
4444+}
4445+
4446+void
4447+virtualkeyboard(struct wl_listener *listener, void *data)
4448+{
4449+	struct wlr_virtual_keyboard_v1 *kb = data;
4450+	/* virtual keyboards shouldn't share keyboard group */
4451+	KeyboardGroup *group = createkeyboardgroup();
4452+	/* Set the keymap to match the group keymap */
4453+	wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap);
4454+	LISTEN(&kb->keyboard.base.events.destroy, &group->destroy, destroykeyboardgroup);
4455+
4456+	/* Add the new keyboard to the group */
4457+	wlr_keyboard_group_add_keyboard(group->wlr_group, &kb->keyboard);
4458+}
4459+
4460+void
4461+virtualpointer(struct wl_listener *listener, void *data)
4462+{
4463+	struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
4464+	struct wlr_input_device *device = &event->new_pointer->pointer.base;
4465+
4466+	wlr_cursor_attach_input_device(cursor, device);
4467+	if (event->suggested_output)
4468+		wlr_cursor_map_input_to_output(cursor, device, event->suggested_output);
4469+}
4470+
4471+Monitor *
4472+xytomon(double x, double y)
4473+{
4474+	struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y);
4475+	return o ? o->data : NULL;
4476+}
4477+
4478+void
4479+xytonode(double x, double y, struct wlr_surface **psurface,
4480+		Client **pc, LayerSurface **pl, double *nx, double *ny)
4481+{
4482+	struct wlr_scene_node *node, *pnode;
4483+	struct wlr_surface *surface = NULL;
4484+	Client *c = NULL;
4485+	LayerSurface *l = NULL;
4486+	int layer;
4487+
4488+	for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) {
4489+		if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny)))
4490+			continue;
4491+
4492+		if (node->type == WLR_SCENE_NODE_BUFFER)
4493+			surface = wlr_scene_surface_try_from_buffer(
4494+					wlr_scene_buffer_from_node(node))->surface;
4495+		for (pnode = node; pnode && !c; pnode = &pnode->parent->node)
4496+			c = pnode->data;
4497+		if (c && c->type == LayerShell) {
4498+			l = (LayerSurface *)c;
4499+			c = NULL;
4500+		}
4501+	}
4502+
4503+	/* zoom */
4504+	if (c && surface && !c->isfullscreen
4505+			&& c->mon && fabs(c->mon->zoom_scale - 1.0) >= 1e-9 && nx && ny) {
4506+		Monitor *m = c->mon;
4507+		double s = m->zoom_scale;
4508+		if (surface == client_surface(c)) {
4509+			int scene_x = (int)llround((double)c->geom.x * s + m->zoom_pan_x);
4510+			int scene_y = (int)llround((double)c->geom.y * s + m->zoom_pan_y);
4511+			int bw_s    = MAX(1, (int)llround((double)c->bw * s));
4512+			int gw_s    = (int)llround((double)c->geom.width  * s);
4513+			int gh_s    = (int)llround((double)c->geom.height * s);
4514+			int inner_w = MAX(1, gw_s - 2 * bw_s);
4515+			int inner_h = MAX(1, gh_s - 2 * bw_s);
4516+			double cw   = (double)MAX(1, c->geom.width  - 2 * c->bw);
4517+			double ch   = (double)MAX(1, c->geom.height - 2 * c->bw);
4518+			double ox   = (double)(scene_x + bw_s);
4519+			double oy   = (double)(scene_y + bw_s);
4520+			*nx = (x - ox) * cw / (double)inner_w;
4521+			*ny = (y - oy) * ch / (double)inner_h;
4522+		} else {
4523+			int abs_nx = 0, abs_ny = 0;
4524+			if (node && wlr_scene_node_coords(node, &abs_nx, &abs_ny)) {
4525+				double cw = (double)MAX(1, c->geom.width  - 2 * c->bw);
4526+				double ch = (double)MAX(1, c->geom.height - 2 * c->bw);
4527+				int gw_s    = (int)llround((double)c->geom.width  * s);
4528+				int gh_s    = (int)llround((double)c->geom.height * s);
4529+				int bw_s    = MAX(1, (int)llround((double)c->bw * s));
4530+				int inner_w = MAX(1, gw_s - 2 * bw_s);
4531+				int inner_h = MAX(1, gh_s - 2 * bw_s);
4532+				*nx = (x - abs_nx) * cw / (double)inner_w;
4533+				*ny = (y - abs_ny) * ch / (double)inner_h;
4534+			}
4535+		}
4536+	}
4537+	/* zoom end */
4538+
4539+	if (psurface) *psurface = surface;
4540+	if (pc) *pc = c;
4541+	if (pl) *pl = l;
4542+}
4543+
4544+void
4545+swapmaster(const Arg *arg)
4546+{
4547+	Client *c, *sel = focustop(selmon);
4548+
4549+	if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating)
4550+		return;
4551+
4552+	/* Search for the first tiled window that is not sel, marking sel as
4553+	 * NULL if we pass it along the way */
4554+	wl_list_for_each(c, &clients, link) {
4555+		if (VISIBLEON(c, selmon) && !c->isfloating) {
4556+			if (c != sel)
4557+				break;
4558+			sel = NULL;
4559+		}
4560+	}
4561+
4562+	/* Return if no other tiled window was found */
4563+	if (&c->link == &clients)
4564+		return;
4565+
4566+	/* If we passed sel, move c to the front; otherwise, move sel to the
4567+	 * front */
4568+	if (!sel)
4569+		sel = c;
4570+	wl_list_remove(&sel->link);
4571+	wl_list_insert(&clients, &sel->link);
4572+
4573+	focusclient(sel, 1);
4574+	arrange(selmon);
4575+}
4576+
4577+#ifdef XWAYLAND
4578+void
4579+activatex11(struct wl_listener *listener, void *data)
4580+{
4581+	Client *c = wl_container_of(listener, c, activate);
4582+
4583+	/* Only "managed" windows can be activated */
4584+	if (!client_is_unmanaged(c))
4585+		wlr_xwayland_surface_activate(c->surface.xwayland, 1);
4586+}
4587+
4588+void
4589+associatex11(struct wl_listener *listener, void *data)
4590+{
4591+	Client *c = wl_container_of(listener, c, associate);
4592+
4593+	LISTEN(&client_surface(c)->events.map, &c->map, mapnotify);
4594+	LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify);
4595+}
4596+
4597+void
4598+configurex11(struct wl_listener *listener, void *data)
4599+{
4600+	Client *c = wl_container_of(listener, c, configure);
4601+	struct wlr_xwayland_surface_configure_event *event = data;
4602+	if (!client_surface(c) || !client_surface(c)->mapped) {
4603+		wlr_xwayland_surface_configure(c->surface.xwayland,
4604+				event->x, event->y, event->width, event->height);
4605+		return;
4606+	}
4607+	if (client_is_unmanaged(c)) {
4608+		wlr_scene_node_set_position(&c->scene->node, event->x, event->y);
4609+		wlr_xwayland_surface_configure(c->surface.xwayland,
4610+				event->x, event->y, event->width, event->height);
4611+		return;
4612+	}
4613+	if ((c->isfloating && c != grabc) || !c->mon->lt[c->mon->sellt]->arrange) {
4614+		resize(c, (struct wlr_box){.x = event->x - c->bw,
4615+				.y = event->y - c->bw, .width = event->width + c->bw * 2,
4616+				.height = event->height + c->bw * 2}, 0);
4617+	} else {
4618+		arrange(c->mon);
4619+	}
4620+}
4621+
4622+void
4623+createnotifyx11(struct wl_listener *listener, void *data)
4624+{
4625+	struct wlr_xwayland_surface *xsurface = data;
4626+	Client *c;
4627+
4628+	/* Allocate a Client for this surface */
4629+	c = xsurface->data = ecalloc(1, sizeof(*c));
4630+	c->surface.xwayland = xsurface;
4631+	c->type = X11;
4632+	c->bw = client_is_unmanaged(c) ? 0 : innerborderpx;
4633+
4634+	/* Listen to the various events it can emit */
4635+	LISTEN(&xsurface->events.associate, &c->associate, associatex11);
4636+	LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify);
4637+	LISTEN(&xsurface->events.dissociate, &c->dissociate, dissociatex11);
4638+	LISTEN(&xsurface->events.request_activate, &c->activate, activatex11);
4639+	LISTEN(&xsurface->events.request_configure, &c->configure, configurex11);
4640+	LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify);
4641+	LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints);
4642+	LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle);
4643+}
4644+
4645+void
4646+dissociatex11(struct wl_listener *listener, void *data)
4647+{
4648+	Client *c = wl_container_of(listener, c, dissociate);
4649+	wl_list_remove(&c->map.link);
4650+	wl_list_remove(&c->unmap.link);
4651+}
4652+
4653+void
4654+sethints(struct wl_listener *listener, void *data)
4655+{
4656+	Client *c = wl_container_of(listener, c, set_hints);
4657+	struct wlr_surface *surface = client_surface(c);
4658+	if (c == focustop(selmon) || !c->surface.xwayland->hints)
4659+		return;
4660+
4661+	c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints);
4662+	printstatus();
4663+
4664+	if (c->isurgent && surface && surface->mapped)
4665+		client_set_border_color(c, urgent_inner_border_color, urgent_outer_border_color);
4666+}
4667+
4668+void
4669+xwaylandready(struct wl_listener *listener, void *data)
4670+{
4671+	struct wlr_xcursor *xcursor;
4672+
4673+	/* assign the one and only seat */
4674+	wlr_xwayland_set_seat(xwayland, seat);
4675+
4676+	/* Set the default XWayland cursor to match the rest of leeloo. */
4677+	if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1)))
4678+		wlr_xwayland_set_cursor(xwayland,
4679+				xcursor->images[0]->buffer, xcursor->images[0]->width * 4,
4680+				xcursor->images[0]->width, xcursor->images[0]->height,
4681+				xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y);
4682+}
4683+#endif
4684+
4685+/* infinite_canvas */
4686+
4687+int
4688+getcurrenttag(Monitor *m)
4689+{
4690+	unsigned int i;
4691+	for (i = 0; i < (unsigned int)TAGCOUNT && !(m->tagset[m->seltags] & (1u << i)); i++);
4692+	return i < (unsigned int)TAGCOUNT ? (int)i : 0;
4693+}
4694+
4695+void
4696+canvas_move_window(Client *c, int x, int y)
4697+{
4698+	if (!c->mon || !client_surface(c)->mapped)
4699+		return;
4700+
4701+	c->geom.x = x;
4702+	c->geom.y = y;
4703+
4704+	/* zoom */
4705+	zoom_update_scene_client(c);
4706+	/* zoom end */
4707+}
4708+
4709+void
4710+homecanvas(const Arg *arg)
4711+{
4712+	Client *c;
4713+	int tagidx, cx, cy;
4714+	if (!selmon)
4715+		return;
4716+
4717+	tagidx = getcurrenttag(selmon);
4718+	cx = selmon->canvas[tagidx].cx;
4719+	cy = selmon->canvas[tagidx].cy;
4720+
4721+	wl_list_for_each(c, &clients, link) {
4722+		if (!(c->tags & (1u << tagidx)) || c->mon != selmon)
4723+			continue;
4724+		c->geom.x -= cx;
4725+		c->geom.y -= cy;
4726+	}
4727+
4728+	selmon->canvas[tagidx].cx = 0;
4729+	selmon->canvas[tagidx].cy = 0;
4730+
4731+	/* zoom */
4732+	zoom_apply(selmon);
4733+	/* zoom end */
4734+}
4735+
4736+#ifndef MOVE_CANVAS_STEP
4737+#define MOVE_CANVAS_STEP 120
4738+#endif
4739+
4740+void
4741+movecanvas(const Arg *arg)
4742+{
4743+	Client *c;
4744+	int tagidx, dx, dy;
4745+	if (!selmon || selmon->lt[selmon->sellt]->arrange != NULL)
4746+		return;
4747+
4748+	tagidx = getcurrenttag(selmon);
4749+	dx = 0;
4750+	dy = 0;
4751+
4752+	switch (arg->i) {
4753+	case 0: dx = -MOVE_CANVAS_STEP; break;
4754+	case 1: dx =  MOVE_CANVAS_STEP; break;
4755+	case 2: dy = -MOVE_CANVAS_STEP; break;
4756+	case 3: dy =  MOVE_CANVAS_STEP; break;
4757+	}
4758+
4759+	selmon->canvas[tagidx].cx -= dx;
4760+	selmon->canvas[tagidx].cy -= dy;
4761+
4762+	wl_list_for_each(c, &clients, link) {
4763+		if (!VISIBLEON(c, selmon))
4764+			continue;
4765+		c->geom.x -= dx;
4766+		c->geom.y -= dy;
4767+	}
4768+	/* zoom */
4769+	zoom_apply(selmon);
4770+	/* zoom end */
4771+}
4772+
4773+#ifndef WINMOVE_STEP_PX
4774+#define WINMOVE_STEP_PX 5 /* pixels nudged per keypress -- niri-style Ctrl+Alt+Arrow */
4775+#endif
4776+#ifndef WINRESIZE_STEP_PX
4777+#define WINRESIZE_STEP_PX 5 /* pixels resized per keypress -- niri-style Ctrl+Shift+Arrow */
4778+#endif
4779+
4780+/* Nudges the focused window by a fixed step in one direction (0=left,
4781+ * 1=right, 2=up, 3=down -- same convention as movecanvas()). Forces the
4782+ * window floating first, matching how interactive dragging already
4783+ * behaves, so the bind has a visible effect regardless of current layout. */
4784+void
4785+movewinbykeys(const Arg *arg)
4786+{
4787+	Client *c = focustop(selmon);
4788+	struct wlr_box geo;
4789+
4790+	if (!c || !c->mon || c->isfullscreen || c->isfakefullscreen)
4791+		return;
4792+	if (!c->isfloating)
4793+		setfloating(c, 1);
4794+
4795+	geo = c->geom;
4796+	switch (arg->i) {
4797+	case 0: geo.x -= WINMOVE_STEP_PX; break; /* left */
4798+	case 1: geo.x += WINMOVE_STEP_PX; break; /* right */
4799+	case 2: geo.y -= WINMOVE_STEP_PX; break; /* up */
4800+	case 3: geo.y += WINMOVE_STEP_PX; break; /* down */
4801+	default: return;
4802+	}
4803+	resize(c, geo, 1);
4804+}
4805+
4806+/* Resizes the focused window by a fixed step (0=left, 1=right, 2=up,
4807+ * 3=down). Follows the traditional i3/sway-style resize-mode convention:
4808+ * left/right adjust width (left shrinks, right grows), up/down adjust
4809+ * height (up shrinks, down grows) -- anchored at the window's current
4810+ * top-left corner, so only the size changes, not the position. */
4811+void
4812+resizewinbykeys(const Arg *arg)
4813+{
4814+	Client *c = focustop(selmon);
4815+	struct wlr_box geo;
4816+	int minw, minh;
4817+
4818+	if (!c || !c->mon || c->isfullscreen || c->isfakefullscreen)
4819+		return;
4820+	if (!c->isfloating)
4821+		setfloating(c, 1);
4822+
4823+	minw = 1 + 2 * (int)c->bw;
4824+	minh = 1 + 2 * (int)c->bw;
4825+	geo = c->geom;
4826+	switch (arg->i) {
4827+	case 0: geo.width = MAX(minw, geo.width - WINRESIZE_STEP_PX); break; /* left: shrink width */
4828+	case 1: geo.width += WINRESIZE_STEP_PX; break; /* right: grow width */
4829+	case 2: geo.height = MAX(minh, geo.height - WINRESIZE_STEP_PX); break; /* up: shrink height */
4830+	case 3: geo.height += WINRESIZE_STEP_PX; break; /* down: grow height */
4831+	default: return;
4832+	}
4833+	resize(c, geo, 1);
4834+}
4835+
4836+void
4837+movecanvasmouse(const Arg *arg)
4838+{
4839+	if (!selmon || selmon->lt[selmon->sellt]->arrange != NULL)
4840+		return;
4841+	if (cursor_mode != CurNormal && cursor_mode != CurPressed)
4842+		return;
4843+
4844+	canvas_pan_multiplier = arg ? arg->f : 1.0f;
4845+	canvas_pan_accum_x = 0.0f;
4846+	canvas_pan_accum_y = 0.0f;
4847+
4848+	wlr_cursor_set_xcursor(cursor, cursor_mgr, "all-scroll");
4849+	cursor_mode = CurMove;
4850+	grabc = NULL;
4851+	canvas_panning = 1;
4852+	canvas_pan_last_x = cursor->x;
4853+	canvas_pan_last_y = cursor->y;
4854+}
4855+
4856+void
4857+save_canvas_positions(Monitor *m)
4858+{
4859+	Client *c;
4860+	int tagidx = getcurrenttag(m);
4861+
4862+	m->canvas[tagidx].saved_cx = m->canvas[tagidx].cx;
4863+	m->canvas[tagidx].saved_cy = m->canvas[tagidx].cy;
4864+
4865+	wl_list_for_each(c, &clients, link) {
4866+		if (!VISIBLEON(c, m))
4867+			continue;
4868+		c->saved_cx = c->geom.x + m->canvas[tagidx].cx;
4869+		c->saved_cy = c->geom.y + m->canvas[tagidx].cy;
4870+		c->saved_cw = c->geom.width;
4871+		c->saved_ch = c->geom.height;
4872+		c->was_on_canvas = 1;
4873+	}
4874+}
4875+
4876+void
4877+restore_canvas_positions(Monitor *m)
4878+{
4879+	Client *c;
4880+	int tagidx = getcurrenttag(m);
4881+
4882+	m->canvas[tagidx].cx = m->canvas[tagidx].saved_cx;
4883+	m->canvas[tagidx].cy = m->canvas[tagidx].saved_cy;
4884+
4885+	wl_list_for_each(c, &clients, link) {
4886+		int tx, ty;
4887+
4888+		if (!VISIBLEON(c, m) || !c->was_on_canvas)
4889+			continue;
4890+		c->isfloating = 1;
4891+
4892+		tx = c->saved_cx - m->canvas[tagidx].cx;
4893+		ty = c->saved_cy - m->canvas[tagidx].cy;
4894+
4895+		c->geom.width  = c->saved_cw;
4896+		c->geom.height = c->saved_ch;
4897+
4898+		c->geom.x = tx;
4899+		c->geom.y = ty;
4900+
4901+		/* zoom */
4902+		zoom_update_scene_client(c);
4903+		/* zoom end */
4904+
4905+		c->resize = client_set_size(c,
4906+			c->geom.width  - 2 * c->bw,
4907+			c->geom.height - 2 * c->bw);
4908+	}
4909+}
4910+
4911+void
4912+centerwindow(const Arg *arg)
4913+{
4914+	Monitor *m;
4915+	Client *tmp;
4916+	int tagidx, screen_cx, screen_cy, win_cx, win_cy, dx, dy;
4917+	Client *c = (arg && arg->v) ? (Client *)arg->v : focustop(selmon);
4918+
4919+	if (!c || !c->mon || c->mon->lt[c->mon->sellt]->arrange != NULL)
4920+		return;
4921+
4922+	m = c->mon;
4923+	tagidx = getcurrenttag(m);
4924+
4925+	screen_cx = m->w.x + m->w.width  / 2;
4926+	screen_cy = m->w.y + m->w.height / 2;
4927+	win_cx    = c->geom.x + c->geom.width  / 2;
4928+	win_cy    = c->geom.y + c->geom.height / 2;
4929+
4930+	dx = screen_cx - win_cx;
4931+	dy = screen_cy - win_cy;
4932+
4933+	if (dx == 0 && dy == 0)
4934+		return;
4935+	wl_list_for_each(tmp, &clients, link) {
4936+		if (!VISIBLEON(tmp, m))
4937+			continue;
4938+		tmp->geom.x += dx;
4939+		tmp->geom.y += dy;
4940+	}
4941+
4942+	m->canvas[tagidx].cx += dx;
4943+	m->canvas[tagidx].cy += dy;
4944+
4945+	/* zoom */
4946+	zoom_apply(m);
4947+	/* zoom end */
4948+}
4949+
4950+void
4951+bringintoview(Client *c)
4952+{
4953+	Monitor *m;
4954+	Client *tmp;
4955+	int tagidx, dx, dy;
4956+	struct wlr_box *w, *g;
4957+
4958+	if (!c || !c->mon || c->mon->lt[c->mon->sellt]->arrange != NULL)
4959+		return;
4960+
4961+	m = c->mon;
4962+	w = &m->w;
4963+	g = &c->geom;
4964+
4965+	/* Only skip teleportation when the target window is FULLY visible.
4966+	 * A partially visible window must still trigger natural teleportation,
4967+	 * even if a corner/edge of it is visible on the current canvas. This
4968+	 * keeps focus and teleportation independent: fully visible nearby windows
4969+	 * are simply focused, while any clipped/off-canvas window is brought to
4970+	 * its own natural framing. */
4971+	if (g->x >= w->x && g->y >= w->y &&
4972+			g->x + g->width <= w->x + w->width &&
4973+			g->y + g->height <= w->y + w->height)
4974+		return; /* fully visible -- focus only, no teleport */
4975+
4976+	tagidx = getcurrenttag(m);
4977+
4978+	/* Each window remembers the pan (home_cx/home_cy) that was active
4979+	 * when it was placed or last manually moved -- its own natural
4980+	 * framing, independent of any other window's. Prefer restoring
4981+	 * exactly that pan: no viewport clamping, no edges, no padding. */
4982+	dx = c->home_cx - m->canvas[tagidx].cx;
4983+	dy = c->home_cy - m->canvas[tagidx].cy;
4984+
4985+	/* But if home-restore wouldn't actually reveal it (e.g. it was
4986+	 * placed off-screen to begin with, so "home" is off-screen too),
4987+	 * fall back to the minimal shift that brings its box into view. */
4988+	if (g->x + dx < w->x || g->y + dy < w->y ||
4989+			g->x + dx + g->width > w->x + w->width ||
4990+			g->y + dy + g->height > w->y + w->height) {
4991+		dx = 0;
4992+		dy = 0;
4993+		if (g->x < w->x)
4994+			dx = w->x - g->x;
4995+		else if (g->x + g->width > w->x + w->width)
4996+			dx = (w->x + w->width) - (g->x + g->width);
4997+		if (g->y < w->y)
4998+			dy = w->y - g->y;
4999+		else if (g->y + g->height > w->y + w->height)
5000+			dy = (w->y + w->height) - (g->y + g->height);
5001+	}
5002+
5003+	if (dx == 0 && dy == 0)
5004+		return; /* already framed exactly as it was */
5005+
5006+	wl_list_for_each(tmp, &clients, link) {
5007+		if (!VISIBLEON(tmp, m))
5008+			continue;
5009+		tmp->geom.x += dx;
5010+		tmp->geom.y += dy;
5011+	}
5012+
5013+	m->canvas[tagidx].cx += dx;
5014+	m->canvas[tagidx].cy += dy;
5015+
5016+	/* zoom */
5017+	zoom_apply(m);
5018+	/* zoom end */
5019+}
5020+
5021+/* infinite_canvas_end */
5022+
5023+/* zoom */
5024+
5025+void
5026+popup_zoom_destroy(struct wl_listener *listener, void *data)
5027+{
5028+	PopupZoomData *pzd = wl_container_of(listener, pzd, destroy);
5029+	wl_list_remove(&pzd->commit.link);
5030+	wl_list_remove(&pzd->destroy.link);
5031+	wl_list_remove(&pzd->link);
5032+	free(pzd);
5033+}
5034+
5035+void
5036+popup_zoom_commit(struct wl_listener *listener, void *data)
5037+{
5038+	double s, px, py;
5039+	Client *c;
5040+	Monitor *m;
5041+	PopupZoomData *pzd = wl_container_of(listener, pzd, commit);
5042+
5043+	if (!pzd->client || !pzd->client->mon || !pzd->node)
5044+		return;
5045+	if (!pzd->popup->base || !pzd->popup->base->surface->mapped)
5046+		return;
5047+
5048+	c = pzd->client;
5049+	m = c->mon;
5050+	s = m->zoom_scale;
5051+	wlr_xdg_popup_get_position(pzd->popup, &px, &py);
5052+
5053+	if (fabs(s - 1.0) < 1e-9) {
5054+		wlr_scene_node_set_position(pzd->node, (int)llround(px), (int)llround(py));
5055+		return;
5056+	}
5057+
5058+	/* zoom */
5059+	wlr_scene_node_set_position(pzd->node,
5060+		(int)llround(px * s),
5061+		(int)llround(py * s));
5062+	/* zoom end */
5063+}
5064+
5065+void
5066+zoom_scale_buffers(struct wlr_scene_buffer *buf, int sx, int sy, void *data)
5067+{
5068+	Client *c = data;
5069+	Monitor *m;
5070+	struct wlr_scene_surface *ss;
5071+	struct wlr_surface *surf;
5072+	double s;
5073+	int lw, lh;
5074+
5075+	(void)sx; (void)sy;
5076+
5077+	if (!c || !(m = c->mon) || !buf->buffer)
5078+		return;
5079+
5080+	if (c->isfullscreen) {
5081+		wlr_scene_buffer_set_dest_size(buf, 0, 0);
5082+		return;
5083+	}
5084+
5085+	s = m->zoom_scale;
5086+	if (fabs(s - 1.0) < 1e-9) {
5087+		wlr_scene_buffer_set_dest_size(buf, 0, 0);
5088+		return;
5089+	}
5090+
5091+	ss = wlr_scene_surface_try_from_buffer(buf);
5092+	if (ss && (surf = ss->surface)) {
5093+		if (surf->current.viewport.has_dst) {
5094+			lw = surf->current.viewport.dst_width;
5095+			lh = surf->current.viewport.dst_height;
5096+		} else {
5097+			lw = surf->current.width;
5098+			lh = surf->current.height;
5099+		}
5100+		if (lw <= 0 || lh <= 0) {
5101+			lw = buf->buffer->width;
5102+			lh = buf->buffer->height;
5103+		}
5104+	} else {
5105+		lw = buf->buffer->width;
5106+		lh = buf->buffer->height;
5107+	}
5108+
5109+	{
5110+		int _bw     = (int)llround((double)c->bw * s);
5111+		int gw      = (int)llround((double)c->geom.width  * s);
5112+		int gh      = (int)llround((double)c->geom.height * s);
5113+		int inner_w = MAX(1, gw - 2 * _bw);
5114+		int inner_h = MAX(1, gh - 2 * _bw);
5115+
5116+		if (ss && ss->surface == client_surface(c)) {
5117+			wlr_scene_buffer_set_dest_size(buf, inner_w, inner_h);
5118+			return;
5119+		}
5120+
5121+		{
5122+			double cw = (double)MAX(1, c->geom.width  - 2 * c->bw);
5123+			double ch = (double)MAX(1, c->geom.height - 2 * c->bw);
5124+			wlr_scene_buffer_set_dest_size(buf,
5125+				MAX(1, (int)llround((double)lw * (double)inner_w / cw)),
5126+				MAX(1, (int)llround((double)lh * (double)inner_h / ch)));
5127+		}
5128+	}
5129+}
5130+
5131+void
5132+zoom_update_scene_client(Client *c)
5133+{
5134+	Monitor *m = c->mon;
5135+	double s;
5136+	int gw, gh, w, h, ib, ob, ib_s, ob_s, bw_pos;
5137+
5138+	if (!m || !client_surface(c)->mapped)
5139+		return;
5140+
5141+	s  = m->zoom_scale;
5142+	w  = c->geom.width;
5143+	h  = c->geom.height;
5144+	ib = c->ibw;
5145+	ob = c->obw;
5146+
5147+	if (c->isfullscreen) {
5148+		wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
5149+		wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
5150+		wlr_scene_rect_set_size(c->inner_border[0], MAX(1, w - 2*ob), MAX(1, ib));
5151+		wlr_scene_node_set_position(&c->inner_border[0]->node, ob, ob);
5152+		wlr_scene_rect_set_size(c->inner_border[1], MAX(1, w - 2*ob), MAX(1, ib));
5153+		wlr_scene_node_set_position(&c->inner_border[1]->node, ob, MAX(0, h - ob - ib));
5154+		wlr_scene_rect_set_size(c->inner_border[2], MAX(1, ib), MAX(1, h - 2*ob));
5155+		wlr_scene_node_set_position(&c->inner_border[2]->node, ob, ob);
5156+		wlr_scene_rect_set_size(c->inner_border[3], MAX(1, ib), MAX(1, h - 2*ob));
5157+		wlr_scene_node_set_position(&c->inner_border[3]->node, MAX(0, w - ob - ib), ob);
5158+		wlr_scene_rect_set_size(c->outer_border[0], MAX(1, w), MAX(1, ob));
5159+		wlr_scene_node_set_position(&c->outer_border[0]->node, 0, 0);
5160+		wlr_scene_rect_set_size(c->outer_border[1], MAX(1, w), MAX(1, ob));
5161+		wlr_scene_node_set_position(&c->outer_border[1]->node, 0, MAX(0, h - ob));
5162+		wlr_scene_rect_set_size(c->outer_border[2], MAX(1, ob), MAX(1, h - 2*ob));
5163+		wlr_scene_node_set_position(&c->outer_border[2]->node, 0, ob);
5164+		wlr_scene_rect_set_size(c->outer_border[3], MAX(1, ob), MAX(1, h - 2*ob));
5165+		wlr_scene_node_set_position(&c->outer_border[3]->node, MAX(0, w - ob), ob);
5166+		return;
5167+	}
5168+
5169+	gw     = MAX(1, (int)llround((double)w  * s));
5170+	gh     = MAX(1, (int)llround((double)h  * s));
5171+	bw_pos = (int)llround((double)c->bw * s);
5172+  ib_s   = (int)llround((double)ib * s);
5173+  ob_s   = (int)llround((double)ob * s);
5174+
5175+	wlr_scene_node_set_position(&c->scene->node,
5176+			(int)llround((double)c->geom.x * s + m->zoom_pan_x),
5177+			(int)llround((double)c->geom.y * s + m->zoom_pan_y));
5178+	wlr_scene_node_set_position(&c->scene_surface->node, bw_pos, bw_pos);
5179+
5180+  wlr_scene_rect_set_size(c->inner_border[0], MAX(0, gw - 2*ob_s), ib_s);
5181+	wlr_scene_node_set_position(&c->inner_border[0]->node, ob_s, ob_s);
5182+	wlr_scene_rect_set_size(c->inner_border[1], MAX(1, gw - 2*ob_s), ib_s);
5183+	wlr_scene_node_set_position(&c->inner_border[1]->node, ob_s, MAX(0, gh - ob_s - ib_s));
5184+  wlr_scene_rect_set_size(c->inner_border[2], ib_s, MAX(0, gh - 2*ob_s));
5185+	wlr_scene_node_set_position(&c->inner_border[2]->node, ob_s, ob_s);
5186+	wlr_scene_rect_set_size(c->inner_border[3], ib_s, MAX(1, gh - 2*ob_s));
5187+	wlr_scene_node_set_position(&c->inner_border[3]->node, MAX(0, gw - ob_s - ib_s), ob_s);
5188+	wlr_scene_rect_set_size(c->outer_border[0], gw, ob_s);
5189+	wlr_scene_node_set_position(&c->outer_border[0]->node, 0, 0);
5190+	wlr_scene_rect_set_size(c->outer_border[1], gw, ob_s);
5191+	wlr_scene_node_set_position(&c->outer_border[1]->node, 0, MAX(0, gh - ob_s));
5192+  wlr_scene_rect_set_size(c->outer_border[2], ob_s, MAX(0, gh - 2*ob_s));
5193+	wlr_scene_node_set_position(&c->outer_border[2]->node, 0, ob_s);
5194+	wlr_scene_rect_set_size(c->outer_border[3], ob_s, MAX(1, gh - 2*ob_s));
5195+	wlr_scene_node_set_position(&c->outer_border[3]->node, MAX(0, gw - ob_s), ob_s);
5196+
5197+	/* touch dest_size only when zoom isnt 1 to avoid glitch in gpu apps */
5198+	if (fabs(s - 1.0) >= 1e-9)
5199+		wlr_scene_node_for_each_buffer(&c->scene->node, zoom_scale_buffers, c);
5200+}
5201+
5202+void
5203+zoom_apply(Monitor *m)
5204+{
5205+	Client *c;
5206+	PopupZoomData *pzd;
5207+
5208+	wl_list_for_each(c, &clients, link) {
5209+		if (c->mon == m && client_surface(c)->mapped)
5210+			zoom_update_scene_client(c);
5211+	}
5212+
5213+	wl_list_for_each(pzd, &popup_zoom_list, link) {
5214+		if (pzd->client && pzd->client->mon == m)
5215+			popup_zoom_commit(&pzd->commit, NULL);
5216+	}
5217+
5218+	/* zoom */
5219+	if (m->zoom_popups_dirty && m->zoom_anim_t >= 1.0) {
5220+		double inv_s = 1.0 / m->zoom_scale;
5221+		double vis_x = -m->zoom_pan_x * inv_s;
5222+		double vis_y = -m->zoom_pan_y * inv_s;
5223+		double vis_w = (double)m->m.width  * inv_s;
5224+		double vis_h = (double)m->m.height * inv_s;
5225+		wl_list_for_each(pzd, &popup_zoom_list, link) {
5226+			Client *pc;
5227+			struct wlr_box pbox;
5228+			if (!pzd->client || pzd->client->mon != m)
5229+				continue;
5230+			pc = pzd->client;
5231+			pbox.x      = (int)llround(vis_x) - pc->geom.x;
5232+			pbox.y      = (int)llround(vis_y) - pc->geom.y;
5233+			pbox.width  = MAX(1, (int)llround(vis_w));
5234+			pbox.height = MAX(1, (int)llround(vis_h));
5235+			wlr_xdg_popup_unconstrain_from_box(pzd->popup, &pbox);
5236+		}
5237+		m->zoom_popups_dirty = 0;
5238+	}
5239+	/* zoom end */
5240+}
5241+
5242+void
5243+zoom_frame(Monitor *m)
5244+{
5245+	double t, u, target_s, end_pan_x, end_pan_y;
5246+	double bx1, by1, bx2, by2;
5247+	double cx, bx, ax, cy, by, ay, s;
5248+	int i;
5249+
5250+	if (!m->lt[m->sellt] || m->lt[m->sellt]->arrange != NULL)
5251+		return;
5252+	if (m->zoom_anim_t >= 1.0)
5253+		return;
5254+
5255+	sscanf(zoombezier, "%lf,%lf,%lf,%lf", &bx1, &by1, &bx2, &by2);
5256+
5257+	target_s  = m->zoom_target;
5258+	end_pan_x = m->zoom_anchor_fx - m->zoom_anchor_lx * target_s;
5259+	end_pan_y = m->zoom_anchor_fy - m->zoom_anchor_ly * target_s;
5260+
5261+	/* zoom */
5262+	m->zoom_anim_t += 1.0 / (zoomduration *
5263+		((double)m->wlr_output->current_mode->refresh / 1000.0));
5264+	/* zoom end */
5265+	if (m->zoom_anim_t > 1.0)
5266+		m->zoom_anim_t = 1.0;
5267+
5268+	t = m->zoom_anim_t;
5269+
5270+	cx = 3.0 * bx1;
5271+	bx = 3.0 * (bx2 - bx1) - cx;
5272+	ax = 1.0 - cx - bx;
5273+	cy = 3.0 * by1;
5274+	by = 3.0 * (by2 - by1) - cy;
5275+	ay = 1.0 - cy - by;
5276+
5277+	s = t;
5278+	for (i = 0; i < 8; i++) {
5279+		double xs  = ((ax * s + bx) * s + cx) * s;
5280+		double dxs = (3.0 * ax * s + 2.0 * bx) * s + cx;
5281+		if (fabs(dxs) < 1e-9) break;
5282+		s -= (xs - t) / dxs;
5283+		if (s < 0.0) s = 0.0;
5284+		if (s > 1.0) s = 1.0;
5285+	}
5286+	u = ((ay * s + by) * s + cy) * s;
5287+
5288+	if (m->zoom_anim_t >= 1.0) {
5289+		m->zoom_scale = target_s;
5290+		m->zoom_pan_x = end_pan_x;
5291+		m->zoom_pan_y = end_pan_y;
5292+	} else {
5293+		m->zoom_scale = m->zoom_start_scale + (target_s  - m->zoom_start_scale) * u;
5294+		m->zoom_pan_x = m->zoom_start_pan_x + (end_pan_x - m->zoom_start_pan_x) * u;
5295+		m->zoom_pan_y = m->zoom_start_pan_y + (end_pan_y - m->zoom_start_pan_y) * u;
5296+	}
5297+
5298+	zoom_apply(m);
5299+
5300+	if (m->zoom_anim_t < 1.0)
5301+		wlr_output_schedule_frame(m->wlr_output);
5302+}
5303+
5304+void
5305+zoom(const Arg *arg)
5306+{
5307+	double old_s, delta, new_s, fx, fy;
5308+	if (!selmon || selmon->lt[selmon->sellt]->arrange != NULL)
5309+		return;
5310+
5311+	old_s = selmon->zoom_scale;
5312+	delta = arg ? arg->f : 0.0;
5313+	new_s = old_s + delta;
5314+
5315+	if (new_s < ZOOMMIN) new_s = ZOOMMIN;
5316+	if (new_s > ZOOMMAX) new_s = ZOOMMAX;
5317+
5318+	fx = selmon->w.x + selmon->w.width  / 2.0;
5319+	fy = selmon->w.y + selmon->w.height / 2.0;
5320+
5321+	selmon->zoom_anchor_fx = fx;
5322+	selmon->zoom_anchor_fy = fy;
5323+	selmon->zoom_anchor_lx = (fx - selmon->zoom_pan_x) / old_s;
5324+	selmon->zoom_anchor_ly = (fy - selmon->zoom_pan_y) / old_s;
5325+	selmon->zoom_target    = new_s;
5326+
5327+	if (!animatezoom) {
5328+		selmon->zoom_scale = new_s;
5329+		selmon->zoom_pan_x = fx - selmon->zoom_anchor_lx * new_s;
5330+		selmon->zoom_pan_y = fy - selmon->zoom_anchor_ly * new_s;
5331+		/* zoom */
5332+		selmon->zoom_anim_t = 1.0;
5333+		selmon->zoom_popups_dirty = 1;
5334+		/* zoom end */
5335+		zoom_apply(selmon);
5336+	} else {
5337+		selmon->zoom_start_scale = old_s;
5338+		selmon->zoom_start_pan_x = selmon->zoom_pan_x;
5339+		selmon->zoom_start_pan_y = selmon->zoom_pan_y;
5340+		/* zoom */
5341+		selmon->zoom_anim_t = 0.0;
5342+		selmon->zoom_popups_dirty = 1;
5343+		/* zoom end */
5344+		wlr_output_schedule_frame(selmon->wlr_output);
5345+	}
5346+}
5347+
5348+void
5349+zoomreset(const Arg *arg)
5350+{
5351+	double old_s, fx, fy;
5352+
5353+	if (!selmon || selmon->lt[selmon->sellt]->arrange != NULL)
5354+		return;
5355+
5356+	old_s = selmon->zoom_scale;
5357+	fx = selmon->w.x + selmon->w.width  / 2.0;
5358+	fy = selmon->w.y + selmon->w.height / 2.0;
5359+
5360+	selmon->zoom_anchor_fx = fx;
5361+	selmon->zoom_anchor_fy = fy;
5362+	selmon->zoom_anchor_lx = (fx - selmon->zoom_pan_x) / old_s;
5363+	selmon->zoom_anchor_ly = (fy - selmon->zoom_pan_y) / old_s;
5364+	selmon->zoom_target    = 1.0;
5365+
5366+	if (!animatezoom) {
5367+		selmon->zoom_scale = 1.0;
5368+		selmon->zoom_pan_x = fx - selmon->zoom_anchor_lx * 1.0;
5369+		selmon->zoom_pan_y = fy - selmon->zoom_anchor_ly * 1.0;
5370+		/* zoom */
5371+		selmon->zoom_anim_t = 1.0;
5372+		selmon->zoom_popups_dirty = 1;
5373+		/* zoom end */
5374+		zoom_apply(selmon);
5375+	} else {
5376+		selmon->zoom_start_scale = old_s;
5377+		selmon->zoom_start_pan_x = selmon->zoom_pan_x;
5378+		selmon->zoom_start_pan_y = selmon->zoom_pan_y;
5379+		/* zoom */
5380+		selmon->zoom_anim_t = 0.0;
5381+		selmon->zoom_popups_dirty = 1;
5382+		/* zoom end */
5383+		wlr_output_schedule_frame(selmon->wlr_output);
5384+	}
5385+}
5386+
5387+/* zoom end */
5388+
5389+void
5390+spawnregion_update_rect(void)
5391+{
5392+	int x, y, w, h;
5393+	x = (int)MIN(spawnregion_x1, spawnregion_x2);
5394+	y = (int)MIN(spawnregion_y1, spawnregion_y2);
5395+	w = (int)fabs(spawnregion_x2 - spawnregion_x1);
5396+	h = (int)fabs(spawnregion_y2 - spawnregion_y1);
5397+	if (w < 1) w = 1;
5398+	if (h < 1) h = 1;
5399+#if SPAWNREGION_STYLE == 2
5400+	{
5401+		int ob = (int)spawnregion_outerborderpx;
5402+		int ib = (int)spawnregion_innerborderpx;
5403+		int side_h = MAX(0, h - 2 * ib);
5404+		int i;
5405+		if (!spawnregion_border[0]) return;
5406+		for (i = 0; i < 8; i++)
5407+			wlr_scene_node_set_enabled(&spawnregion_border[i]->node, 1);
5408+		wlr_scene_node_set_position(&spawnregion_border[0]->node, x - ob, y - ob);
5409+		wlr_scene_rect_set_size(spawnregion_border[0], w + 2 * ob, ob);
5410+		wlr_scene_node_set_position(&spawnregion_border[1]->node, x - ob, y + h);
5411+		wlr_scene_rect_set_size(spawnregion_border[1], w + 2 * ob, ob);
5412+		wlr_scene_node_set_position(&spawnregion_border[2]->node, x - ob, y);
5413+		wlr_scene_rect_set_size(spawnregion_border[2], ob, h);
5414+		wlr_scene_node_set_position(&spawnregion_border[3]->node, x + w, y);
5415+		wlr_scene_rect_set_size(spawnregion_border[3], ob, h);
5416+		wlr_scene_node_set_position(&spawnregion_border[4]->node, x, y);
5417+		wlr_scene_rect_set_size(spawnregion_border[4], w, ib);
5418+		wlr_scene_node_set_position(&spawnregion_border[5]->node, x, y + h - ib);
5419+		wlr_scene_rect_set_size(spawnregion_border[5], w, ib);
5420+		wlr_scene_node_set_position(&spawnregion_border[6]->node, x, y + ib);
5421+		wlr_scene_rect_set_size(spawnregion_border[6], ib, side_h);
5422+		wlr_scene_node_set_position(&spawnregion_border[7]->node, x + w - ib, y + ib);
5423+		wlr_scene_rect_set_size(spawnregion_border[7], ib, side_h);
5424+	}
5425+#else
5426+	if (!spawnregion_rect)
5427+		return;
5428+	wlr_scene_node_set_position(&spawnregion_rect->node, x, y);
5429+	wlr_scene_rect_set_size(spawnregion_rect, w, h);
5430+#endif
5431+}
5432+
5433+void
5434+spawnregion_finish(void)
5435+{
5436+	int x, y, w, h;
5437+
5438+	if (spawnregion_rect)
5439+		wlr_scene_node_set_enabled(&spawnregion_rect->node, 0);
5440+#if SPAWNREGION_STYLE == 2
5441+	{
5442+		int i;
5443+		for (i = 0; i < 8; i++)
5444+			if (spawnregion_border[i])
5445+				wlr_scene_node_set_enabled(&spawnregion_border[i]->node, 0);
5446+	}
5447+#endif
5448+
5449+	spawnregion_active = 0;
5450+	cursor_mode = CurNormal;
5451+	wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
5452+
5453+	/* zoom */
5454+	if (selmon && selmon->lt[selmon->sellt]->arrange == NULL) {
5455+		double s = selmon->zoom_scale;
5456+		if (fabs(s) >= 1e-9 && fabs(s - 1.0) >= 1e-9) {
5457+			double lx1 = (spawnregion_x1 - selmon->zoom_pan_x) / s;
5458+			double ly1 = (spawnregion_y1 - selmon->zoom_pan_y) / s;
5459+			double lx2 = (spawnregion_x2 - selmon->zoom_pan_x) / s;
5460+			double ly2 = (spawnregion_y2 - selmon->zoom_pan_y) / s;
5461+			x = (int)MIN(lx1, lx2);
5462+			y = (int)MIN(ly1, ly2);
5463+			w = (int)fabs(lx2 - lx1);
5464+			h = (int)fabs(ly2 - ly1);
5465+			goto coords_done;
5466+		}
5467+	}
5468+	/* zoom end */
5469+	x = (int)MIN(spawnregion_x1, spawnregion_x2);
5470+	y = (int)MIN(spawnregion_y1, spawnregion_y2);
5471+	w = (int)fabs(spawnregion_x2 - spawnregion_x1);
5472+	h = (int)fabs(spawnregion_y2 - spawnregion_y1);
5473+	/* zoom */
5474+coords_done:
5475+	/* zoom end */
5476+
5477+	if (w < 10 || h < 10) {
5478+		if (waiting_geo_client) {
5479+			wlr_scene_node_set_enabled(&waiting_geo_client->scene->node, 1);
5480+			focusclient(waiting_geo_client, 1);
5481+			waiting_geo_client = NULL;
5482+		}
5483+		return;
5484+	}
5485+
5486+	pending_spawn_geo.x      = x;
5487+	pending_spawn_geo.y      = y;
5488+	pending_spawn_geo.width  = w;
5489+	pending_spawn_geo.height = h;
5490+	has_pending_spawn_geo    = 1;
5491+
5492+	if (waiting_geo_client) {
5493+		if (selmon)
5494+			waiting_geo_client->tags = selmon->tagset[selmon->seltags];
5495+		waiting_geo_client->isfloating = 1;
5496+		resize(waiting_geo_client, pending_spawn_geo, 0);
5497+		wlr_scene_node_set_enabled(&waiting_geo_client->scene->node, 1);
5498+		focusclient(waiting_geo_client, 1);
5499+		
5500+		waiting_geo_client = NULL;
5501+		has_pending_spawn_geo = 0;
5502+	}
5503+}
5504+
5505+void
5506+spawnregion(const Arg *arg)
5507+{
5508+	if (!selmon || selmon->lt[selmon->sellt]->arrange != NULL)
5509+		return;
5510+	if (cursor_mode != CurNormal && cursor_mode != CurPressed)
5511+		return;
5512+  if (!waiting_geo_client)
5513+    return;
5514+
5515+	spawnregion_active = 1;
5516+	has_pending_spawn_geo = 0;
5517+	wlr_cursor_set_xcursor(cursor, cursor_mgr, "crosshair");
5518+}
5519+
5520+/* spawnregion_end */
5521+
5522+/* 
5523+  gaps are from this patch:
5524+  https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/genericgaps/genericgaps-0.7.patch
5525+*/
5526+
5527+#ifdef TILING
5528+void
5529+defaultgaps(const Arg *arg)
5530+{
5531+	setgaps(gappoh, gappov, gappih, gappiv);
5532+}
5533+
5534+void
5535+incgaps(const Arg *arg)
5536+{
5537+	setgaps(
5538+		selmon->gappoh + arg->i,
5539+		selmon->gappov + arg->i,
5540+		selmon->gappih + arg->i,
5541+		selmon->gappiv + arg->i
5542+	);
5543+}
5544+
5545+void
5546+incigaps(const Arg *arg)
5547+{
5548+	setgaps(
5549+		selmon->gappoh,
5550+		selmon->gappov,
5551+		selmon->gappih + arg->i,
5552+		selmon->gappiv + arg->i
5553+	);
5554+}
5555+
5556+void
5557+incihgaps(const Arg *arg)
5558+{
5559+	setgaps(
5560+		selmon->gappoh,
5561+		selmon->gappov,
5562+		selmon->gappih + arg->i,
5563+		selmon->gappiv
5564+	);
5565+}
5566+
5567+void
5568+incivgaps(const Arg *arg)
5569+{
5570+	setgaps(
5571+		selmon->gappoh,
5572+		selmon->gappov,
5573+		selmon->gappih,
5574+		selmon->gappiv + arg->i
5575+	);
5576+}
5577+
5578+void
5579+incogaps(const Arg *arg)
5580+{
5581+	setgaps(
5582+		selmon->gappoh + arg->i,
5583+		selmon->gappov + arg->i,
5584+		selmon->gappih,
5585+		selmon->gappiv
5586+	);
5587+}
5588+
5589+void
5590+incohgaps(const Arg *arg)
5591+{
5592+	setgaps(
5593+		selmon->gappoh + arg->i,
5594+		selmon->gappov,
5595+		selmon->gappih,
5596+		selmon->gappiv
5597+	);
5598+}
5599+
5600+void
5601+incovgaps(const Arg *arg)
5602+{
5603+	setgaps(
5604+		selmon->gappoh,
5605+		selmon->gappov + arg->i,
5606+		selmon->gappih,
5607+		selmon->gappiv
5608+	);
5609+}
5610+
5611+void
5612+preparegaps(Monitor *m)
5613+{
5614+	Client *c;
5615+	int n;
5616+
5617+	if (!m->enablegaps)
5618+		return;
5619+
5620+	n = 0;
5621+	wl_list_for_each(c, &clients, link) {
5622+		if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
5623+			continue;
5624+		n++;
5625+	}
5626+
5627+	resizelock = 1;
5628+
5629+	if ((smartgaps && n == 1) || (!monoclegaps && m->lt[m->sellt]->arrange == monocle))
5630+		return;
5631+
5632+	m->w.width  -= m->gappih + 2 * m->gappoh;
5633+	m->w.height -= m->gappiv + 2 * m->gappov;
5634+}
5635+
5636+void
5637+setgaps(int oh, int ov, int ih, int iv)
5638+{
5639+	selmon->gappoh = MAX(oh, 0);
5640+	selmon->gappov = MAX(ov, 0);
5641+	selmon->gappih = MAX(ih, 0);
5642+	selmon->gappiv = MAX(iv, 0);
5643+	arrange(selmon);
5644+}
5645+
5646+void
5647+togglegaps(const Arg *arg)
5648+{
5649+	if (!selmon)
5650+		return;
5651+	selmon->enablegaps = !selmon->enablegaps;
5652+	arrange(selmon);
5653+}
5654+
5655+void
5656+arrangegaps(Monitor *m)
5657+{
5658+	Client *c;
5659+	int n, gaps;
5660+
5661+	if (!m->enablegaps)
5662+		return;
5663+
5664+	resizelock = 0;
5665+
5666+	n = 0;
5667+	wl_list_for_each(c, &clients, link) {
5668+		if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
5669+			continue;
5670+		n++;
5671+	}
5672+
5673+	gaps = !(smartgaps && n == 1) &&
5674+		(monoclegaps || m->lt[m->sellt]->arrange != monocle);
5675+	if (gaps) {
5676+		m->w.width  += m->gappih + 2 * m->gappoh;
5677+		m->w.height += m->gappiv + 2 * m->gappov;
5678+	}
5679+	wl_list_for_each(c, &clients, link) {
5680+		if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
5681+			continue;
5682+		if (gaps) {
5683+			c->geom.x      += c->mon->gappih + c->mon->gappoh;
5684+			c->geom.y      += c->mon->gappiv + c->mon->gappov;
5685+			c->geom.width  -= c->mon->gappih;
5686+			c->geom.height -= c->mon->gappiv;
5687+		}
5688+		resize(c, c->geom, 0);
5689+	}
5690+}
5691+#endif // why would you need gaps without tiling?
5692+
5693+/* tablet-input is from this patch: 
5694+   https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/tablet-input/tablet-input-0.8.patch 
5695+*/
5696+
5697+void
5698+createtablet(struct wlr_input_device *device)
5699+{
5700+	if (!tablet) {
5701+		struct libinput_device *device_handle = NULL;
5702+		if (!wlr_input_device_is_libinput(device) ||
5703+				!(device_handle = wlr_libinput_get_device_handle(device)))
5704+			return;
5705+		tablet = wlr_tablet_create(tablet_mgr, seat, device);
5706+		wl_signal_add(&tablet->wlr_device->events.destroy, &tablet_device_destroy);
5707+		if (libinput_device_config_send_events_get_modes(device_handle)) {
5708+			libinput_device_config_send_events_set_mode(device_handle, send_events_mode);
5709+			wlr_cursor_attach_input_device(cursor, device);
5710+		}
5711+	} else if (device == tablet->wlr_device) {
5712+		wlr_log(WLR_ERROR, "createtablet: duplicate device");
5713+	} else {
5714+		wlr_log(WLR_ERROR, "createtablet: already have one tablet");
5715+	}
5716+}
5717+
5718+void
5719+destroytablet(struct wl_listener *listener, void *data)
5720+{
5721+	wl_list_remove(&tablet_device_destroy.link);
5722+	wlr_cursor_detach_input_device(cursor, tablet->wlr_device);
5723+	tablet = NULL;
5724+}
5725+
5726+void
5727+destroytabletpad(struct wl_listener *listener, void *data)
5728+{
5729+	wl_list_remove(&tablet_pad_button.link);
5730+	wl_list_remove(&tablet_pad_destroy.link);
5731+	tablet_pad = NULL;
5732+}
5733+
5734+void
5735+destroytabletsurfacenotify(struct wl_listener *listener, void *data)
5736+{
5737+	if (tablet_curr_surface)
5738+		wl_list_remove(&destroy_tablet_surface_listener.link);
5739+	tablet_curr_surface = NULL;
5740+}
5741+
5742+void
5743+destroytablettool(struct wl_listener *listener, void *data)
5744+{
5745+	destroytabletsurfacenotify(NULL, NULL);
5746+	tablet_tool = NULL;
5747+}
5748+
5749+void
5750+tabletapplymap(double x, double y, struct wlr_input_device *dev)
5751+{
5752+	Client *p;
5753+	struct wlr_box geom = {0};
5754+	if (tabletmaptosurface && tablet_curr_surface) {
5755+		toplevel_from_wlr_surface(tablet_curr_surface, &p, NULL);
5756+		if (p) {
5757+			for (; client_get_parent(p); p = client_get_parent(p));
5758+			geom.x = p->geom.x + p->bw;
5759+			geom.y = p->geom.y + p->bw;
5760+			geom.width = p->geom.width - 2 * p->bw;
5761+			geom.height = p->geom.height - 2 * p->bw;
5762+			wlr_cursor_map_input_to_region(cursor, dev, &geom);
5763+		}
5764+	}
5765+	wlr_cursor_map_input_to_output(cursor, dev, selmon->wlr_output);
5766+}
5767+
5768+void
5769+tabletpadbutton(struct wl_listener *listener, void *data)
5770+{
5771+    struct wlr_tablet_pad_button_event *event = data;
5772+    const TabletPadButton *pb;
5773+
5774+    for (pb = tabletpadbuttons; pb < END(tabletpadbuttons); pb++) {
5775+        if (event->button == pb->button
5776+                && event->state == pb->state
5777+                && pb->func) {
5778+            pb->func(&pb->arg);
5779+        }
5780+    }
5781+
5782+    if (tablet_pad)
5783+        wlr_tablet_v2_tablet_pad_notify_button(tablet_pad,
5784+            event->button, event->time_msec,
5785+            (enum zwp_tablet_pad_v2_button_state)event->state);
5786+}
5787+
5788+void
5789+tablettoolmotion(struct wlr_tablet_v2_tablet_tool *tool, bool change_x, bool change_y,
5790+		double x, double y, double dx, double dy)
5791+{
5792+	struct wlr_surface *surface = NULL;
5793+	double sx, sy;
5794+
5795+	if (!change_x && !change_y)
5796+		return;
5797+
5798+	tabletapplymap(x, y, tablet->wlr_device);
5799+
5800+	x = (MAX(tablet_area[0], MIN(tablet_area[0] + tablet_area[2], x)) - tablet_area[0]) / tablet_area[2];
5801+	y = (MAX(tablet_area[1], MIN(tablet_area[1] + tablet_area[3], y)) - tablet_area[1]) / tablet_area[3];
5802+
5803+
5804+	// TODO: apply constraints
5805+	switch (tablet_tool->wlr_tool->type) {
5806+	case WLR_TABLET_TOOL_TYPE_LENS:
5807+	case WLR_TABLET_TOOL_TYPE_MOUSE:
5808+		wlr_cursor_move(cursor, tablet->wlr_device, dx, dy);
5809+		break;
5810+	default:
5811+		wlr_cursor_warp_absolute(cursor, tablet->wlr_device, change_x ? x : NAN, change_y ? y : NAN);
5812+		break;
5813+	}
5814+
5815+	motionnotify(0, NULL, 0, 0, 0, 0);
5816+
5817+	xytonode(cursor->x, cursor->y, &surface, NULL, NULL, &sx, &sy);
5818+	if (surface && !wlr_surface_accepts_tablet_v2(surface, tablet))
5819+		surface = NULL;
5820+
5821+	if (surface != tablet_curr_surface) {
5822+		if (tablet_curr_surface) {
5823+			// TODO: wait until all buttons released before leaving
5824+			if (tablet_tool)
5825+				wlr_tablet_v2_tablet_tool_notify_proximity_out(tablet_tool);
5826+			if (tablet_pad)
5827+				wlr_tablet_v2_tablet_pad_notify_leave(tablet_pad, tablet_curr_surface);
5828+			wl_list_remove(&destroy_tablet_surface_listener.link);
5829+		}
5830+		if (surface) {
5831+			if (tablet_pad)
5832+				wlr_tablet_v2_tablet_pad_notify_enter(tablet_pad, tablet, surface);
5833+			if (tablet_tool)
5834+				wlr_tablet_v2_tablet_tool_notify_proximity_in(tablet_tool, tablet, surface);
5835+			wl_signal_add(&surface->events.destroy, &destroy_tablet_surface_listener);
5836+		}
5837+		tablet_curr_surface = surface;
5838+	}
5839+
5840+	if (surface)
5841+		wlr_tablet_v2_tablet_tool_notify_motion(tablet_tool, sx, sy);
5842+}
5843+
5844+void
5845+tablettoolproximity(struct wl_listener *listener, void *data)
5846+{
5847+	struct wlr_tablet_tool_proximity_event *event = data;
5848+	struct wlr_tablet_tool *tool = event->tool;
5849+
5850+	if (!tablet_tool) {
5851+		tablet_tool = wlr_tablet_tool_create(tablet_mgr, seat, tool);
5852+		wl_signal_add(&tablet_tool->wlr_tool->events.destroy, &tablet_tool_destroy);
5853+		wl_signal_add(&tablet_tool->events.set_cursor, &request_cursor);
5854+	}
5855+
5856+	switch (event->state) {
5857+	case WLR_TABLET_TOOL_PROXIMITY_OUT:
5858+		wlr_tablet_v2_tablet_tool_notify_proximity_out(tablet_tool);
5859+		destroytabletsurfacenotify(NULL, NULL);
5860+		break;
5861+	case WLR_TABLET_TOOL_PROXIMITY_IN:
5862+		tablettoolmotion(tablet_tool, true, true, event->x, event->y, 0, 0);
5863+		break;
5864+	}
5865+}
5866+
5867+double tilt_x = 0;
5868+double tilt_y = 0;
5869+
5870+void
5871+tablettoolaxis(struct wl_listener *listener, void *data)
5872+{
5873+	struct wlr_tablet_tool_axis_event *event = data;
5874+
5875+	tablettoolmotion(tablet_tool,
5876+		event->updated_axes & WLR_TABLET_TOOL_AXIS_X,
5877+		event->updated_axes & WLR_TABLET_TOOL_AXIS_Y,
5878+		event->x, event->y, event->dx, event->dy);
5879+
5880+	if (event->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE)
5881+		wlr_tablet_v2_tablet_tool_notify_pressure(tablet_tool, event->pressure);
5882+	if (event->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE)
5883+		wlr_tablet_v2_tablet_tool_notify_distance(tablet_tool, event->distance);
5884+	if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_X)
5885+		tilt_x = event->tilt_x;
5886+	if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_Y)
5887+		tilt_y = event->tilt_y;
5888+	if (event->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y))
5889+		wlr_tablet_v2_tablet_tool_notify_tilt(tablet_tool, tilt_x, tilt_y);
5890+	if (event->updated_axes & WLR_TABLET_TOOL_AXIS_ROTATION)
5891+		wlr_tablet_v2_tablet_tool_notify_rotation(tablet_tool, event->rotation);
5892+	if (event->updated_axes & WLR_TABLET_TOOL_AXIS_SLIDER)
5893+		wlr_tablet_v2_tablet_tool_notify_slider(tablet_tool, event->slider);
5894+	if (event->updated_axes & WLR_TABLET_TOOL_AXIS_WHEEL)
5895+		wlr_tablet_v2_tablet_tool_notify_wheel(tablet_tool, event->wheel_delta, 0);
5896+}
5897+
5898+void
5899+tablettoolbutton(struct wl_listener *listener, void *data)
5900+{
5901+    struct wlr_tablet_tool_button_event *event = data;
5902+    const TabletButton *tb;
5903+
5904+    for (tb = tabletbuttons; tb < END(tabletbuttons); tb++) {
5905+        if (event->button == tb->button
5906+                && event->state == tb->state
5907+                && tb->func) {
5908+            tb->func(&tb->arg);
5909+        }
5910+    }
5911+
5912+    wlr_tablet_v2_tablet_tool_notify_button(tablet_tool, event->button,
5913+        (enum zwp_tablet_pad_v2_button_state)event->state);
5914+}
5915+
5916+void
5917+tablettooltip(struct wl_listener *listener, void *data)
5918+{
5919+	struct wlr_tablet_tool_tip_event *event = data;
5920+
5921+	if (!tablet_curr_surface) {
5922+		struct wlr_pointer_button_event fakeptrbtnevent = {
5923+			.button = BTN_LEFT,
5924+			.state = event->state == WLR_TABLET_TOOL_TIP_UP ?
5925+				WL_POINTER_BUTTON_STATE_RELEASED : WL_POINTER_BUTTON_STATE_PRESSED,
5926+			.time_msec = event->time_msec,
5927+		};
5928+		buttonpress(NULL, (void *)&fakeptrbtnevent);
5929+	}
5930+
5931+	if (event->state == WLR_TABLET_TOOL_TIP_UP) {
5932+		wlr_tablet_v2_tablet_tool_notify_up(tablet_tool);
5933+		return;
5934+	}
5935+
5936+	wlr_tablet_v2_tablet_tool_notify_down(tablet_tool);
5937+	wlr_tablet_tool_v2_start_implicit_grab(tablet_tool);
5938+}
5939+
5940+/* tablet-input end */
5941+int
5942+main(int argc, char *argv[])
5943+{
5944+	char *startup_cmd = NULL;
5945+	int c;
5946+
5947+	while ((c = getopt(argc, argv, "s:hdv")) != -1) {
5948+		if (c == 's')
5949+			startup_cmd = optarg;
5950+		else if (c == 'd')
5951+			log_level = WLR_DEBUG;
5952+		else if (c == 'v')
5953+			die("leeloo " VERSION);
5954+		else
5955+			goto usage;
5956+	}
5957+	if (optind < argc)
5958+		goto usage;
5959+
5960+	/* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */
5961+	if (!getenv("XDG_RUNTIME_DIR"))
5962+		die("XDG_RUNTIME_DIR must be set");
5963+	setup();
5964+	run(startup_cmd);
5965+	cleanup();
5966+	return EXIT_SUCCESS;
5967+
5968+usage:
5969+	die("Usage: %s [-v] [-d] [-s startup command]", argv[0]);
5970+}
+51, -0
 1@@ -0,0 +1,51 @@
 2+/* See LICENSE.dwm file for copyright and license details. */
 3+#include <stdarg.h>
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <string.h>
 7+#include <fcntl.h>
 8+
 9+#include "util.h"
10+
11+void
12+die(const char *fmt, ...) {
13+	va_list ap;
14+
15+	va_start(ap, fmt);
16+	vfprintf(stderr, fmt, ap);
17+	va_end(ap);
18+
19+	if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
20+		fputc(' ', stderr);
21+		perror(NULL);
22+	} else {
23+		fputc('\n', stderr);
24+	}
25+
26+	exit(1);
27+}
28+
29+void *
30+ecalloc(size_t nmemb, size_t size)
31+{
32+	void *p;
33+
34+	if (!(p = calloc(nmemb, size)))
35+		die("calloc:");
36+	return p;
37+}
38+
39+int
40+fd_set_nonblock(int fd) {
41+	int flags = fcntl(fd, F_GETFL);
42+	if (flags < 0) {
43+		perror("fcntl(F_GETFL):");
44+		return -1;
45+	}
46+	if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
47+		perror("fcntl(F_SETFL):");
48+		return -1;
49+	}
50+
51+	return 0;
52+}
+5, -0
1@@ -0,0 +1,5 @@
2+/* See LICENSE.dwm file for copyright and license details. */
3+
4+void die(const char *fmt, ...);
5+void *ecalloc(size_t nmemb, size_t size);
6+int fd_set_nonblock(int fd);