dwl.c 119 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913
  1. /*
  2. * See LICENSE file for copyright and license details.
  3. */
  4. #include <getopt.h>
  5. #include <libinput.h>
  6. #include <linux/input-event-codes.h>
  7. #include <math.h>
  8. #include <libdrm/drm_fourcc.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/interfaces/wlr_keyboard.h>
  19. #include <wlr/render/allocator.h>
  20. #include <wlr/render/wlr_renderer.h>
  21. #include <wlr/types/wlr_alpha_modifier_v1.h>
  22. #include <wlr/types/wlr_compositor.h>
  23. #include <wlr/types/wlr_cursor.h>
  24. #include <wlr/types/wlr_cursor_shape_v1.h>
  25. #include <wlr/types/wlr_data_control_v1.h>
  26. #include <wlr/types/wlr_data_device.h>
  27. #include <wlr/types/wlr_drm.h>
  28. #include <wlr/types/wlr_export_dmabuf_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_output.h>
  39. #include <wlr/types/wlr_output_layout.h>
  40. #include <wlr/types/wlr_output_management_v1.h>
  41. #include <wlr/types/wlr_output_power_management_v1.h>
  42. #include <wlr/types/wlr_pointer.h>
  43. #include <wlr/types/wlr_pointer_constraints_v1.h>
  44. #include <wlr/types/wlr_presentation_time.h>
  45. #include <wlr/types/wlr_primary_selection.h>
  46. #include <wlr/types/wlr_primary_selection_v1.h>
  47. #include <wlr/types/wlr_relative_pointer_v1.h>
  48. #include <wlr/types/wlr_scene.h>
  49. #include <wlr/types/wlr_screencopy_v1.h>
  50. #include <wlr/types/wlr_seat.h>
  51. #include <wlr/types/wlr_server_decoration.h>
  52. #include <wlr/types/wlr_session_lock_v1.h>
  53. #include <wlr/types/wlr_single_pixel_buffer_v1.h>
  54. #include <wlr/types/wlr_subcompositor.h>
  55. #include <wlr/types/wlr_viewporter.h>
  56. #include <wlr/types/wlr_virtual_keyboard_v1.h>
  57. #include <wlr/types/wlr_virtual_pointer_v1.h>
  58. #include <wlr/types/wlr_xcursor_manager.h>
  59. #include <wlr/types/wlr_xdg_activation_v1.h>
  60. #include <wlr/types/wlr_xdg_decoration_v1.h>
  61. #include <wlr/types/wlr_xdg_output_v1.h>
  62. #include <wlr/types/wlr_xdg_shell.h>
  63. #include <wlr/util/box.h>
  64. #include <wlr/interfaces/wlr_buffer.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. #include "util.h"
  74. #include "drwl.h"
  75. /* macros */
  76. #define MAX(A, B) ((A) > (B) ? (A) : (B))
  77. #define MIN(A, B) ((A) < (B) ? (A) : (B))
  78. #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
  79. #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && (((C)->tags & (M)->tagset[(M)->seltags]) || C->issticky))
  80. #define LENGTH(X) (sizeof X / sizeof X[0])
  81. #define END(A) ((A) + LENGTH(A))
  82. #define TAGMASK ((1u << LENGTH(tags)) - 1)
  83. #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L)))
  84. #define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0)
  85. #define TEXTW(mon, text) (drwl_font_getwidth(mon->drw, text) + mon->lrpad)
  86. /* enums */
  87. enum { SchemeNorm, SchemeSel, SchemeUrg }; /* color schemes */
  88. enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
  89. enum { XDGShell, LayerShell, X11 }; /* client types */
  90. enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
  91. enum { ClkTagBar, ClkLtSymbol, ClkStatus, ClkTitle, ClkClient, ClkRoot }; /* clicks */
  92. #ifdef XWAYLAND
  93. enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,
  94. NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */
  95. #endif
  96. typedef union {
  97. int i;
  98. uint32_t ui;
  99. float f;
  100. const void *v;
  101. } Arg;
  102. typedef struct {
  103. unsigned int click;
  104. unsigned int mod;
  105. unsigned int button;
  106. void (*func)(const Arg *);
  107. const Arg arg;
  108. } Button;
  109. typedef struct Pertag Pertag;
  110. typedef struct Monitor Monitor;
  111. typedef struct {
  112. /* Must keep these three elements in this order */
  113. unsigned int type; /* XDGShell or X11* */
  114. struct wlr_box geom; /* layout-relative, includes border */
  115. Monitor *mon;
  116. struct wlr_scene_tree *scene;
  117. struct wlr_scene_rect *border[4]; /* top, bottom, left, right */
  118. struct wlr_scene_tree *scene_surface;
  119. struct wl_list link;
  120. struct wl_list flink;
  121. union {
  122. struct wlr_xdg_surface *xdg;
  123. struct wlr_xwayland_surface *xwayland;
  124. } surface;
  125. struct wlr_xdg_toplevel_decoration_v1 *decoration;
  126. struct wl_listener commit;
  127. struct wl_listener map;
  128. struct wl_listener maximize;
  129. struct wl_listener unmap;
  130. struct wl_listener destroy;
  131. struct wl_listener set_title;
  132. struct wl_listener fullscreen;
  133. struct wl_listener set_decoration_mode;
  134. struct wl_listener destroy_decoration;
  135. struct wlr_box prev; /* layout-relative, includes border */
  136. struct wlr_box bounds;
  137. #ifdef XWAYLAND
  138. struct wl_listener activate;
  139. struct wl_listener associate;
  140. struct wl_listener dissociate;
  141. struct wl_listener configure;
  142. struct wl_listener set_hints;
  143. #endif
  144. unsigned int bw;
  145. uint32_t tags;
  146. int isfloating, isurgent, isfullscreen, issticky;
  147. uint32_t resize; /* configure serial of a pending resize */
  148. unsigned int kblayout_idx;
  149. } Client;
  150. typedef struct {
  151. uint32_t mod;
  152. xkb_keysym_t keysym;
  153. void (*func)(const Arg *);
  154. const Arg arg;
  155. } Key;
  156. typedef struct {
  157. struct wl_list link;
  158. struct wlr_keyboard_group *wlr_group;
  159. int nsyms;
  160. const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */
  161. uint32_t mods; /* invalid if nsyms == 0 */
  162. struct wl_event_source *key_repeat_source;
  163. struct wl_listener modifiers;
  164. struct wl_listener key;
  165. struct wl_listener destroy;
  166. } KeyboardGroup;
  167. typedef struct {
  168. /* Must keep these three elements in this order */
  169. unsigned int type; /* LayerShell */
  170. struct wlr_box geom;
  171. Monitor *mon;
  172. struct wlr_scene_tree *scene;
  173. struct wlr_scene_tree *popups;
  174. struct wlr_scene_layer_surface_v1 *scene_layer;
  175. struct wl_list link;
  176. int mapped;
  177. struct wlr_layer_surface_v1 *layer_surface;
  178. struct wl_listener destroy;
  179. struct wl_listener unmap;
  180. struct wl_listener surface_commit;
  181. } LayerSurface;
  182. typedef struct {
  183. const char *symbol;
  184. void (*arrange)(Monitor *);
  185. } Layout;
  186. typedef struct {
  187. struct wlr_buffer base;
  188. struct wl_listener release;
  189. bool busy;
  190. Img *image;
  191. uint32_t data[];
  192. } Buffer;
  193. struct Monitor {
  194. struct wl_list link;
  195. struct wlr_output *wlr_output;
  196. struct wlr_scene_output *scene_output;
  197. struct wlr_scene_buffer *scene_buffer; /* bar buffer */
  198. struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */
  199. struct wl_listener frame;
  200. struct wl_listener destroy;
  201. struct wl_listener request_state;
  202. struct wl_listener destroy_lock_surface;
  203. struct wlr_session_lock_surface_v1 *lock_surface;
  204. struct wlr_box m; /* monitor area, layout-relative */
  205. struct {
  206. int width, height;
  207. int real_width, real_height; /* non-scaled */
  208. float scale;
  209. } b; /* bar area */
  210. struct wlr_box w; /* window area, layout-relative */
  211. struct wl_list layers[4]; /* LayerSurface.link */
  212. const Layout *lt[2];
  213. Pertag *pertag;
  214. unsigned int seltags;
  215. unsigned int sellt;
  216. uint32_t tagset[2];
  217. float mfact;
  218. int gamma_lut_changed;
  219. int nmaster;
  220. char ltsymbol[16];
  221. int asleep;
  222. Drwl *drw;
  223. Buffer *pool[2];
  224. int lrpad;
  225. };
  226. typedef struct {
  227. const char *name;
  228. float mfact;
  229. int nmaster;
  230. float scale;
  231. const Layout *lt;
  232. enum wl_output_transform rr;
  233. int x, y;
  234. } MonitorRule;
  235. typedef struct {
  236. struct wlr_pointer_constraint_v1 *constraint;
  237. struct wl_listener destroy;
  238. } PointerConstraint;
  239. typedef struct {
  240. const char *id;
  241. const char *title;
  242. uint32_t tags;
  243. int isfloating;
  244. int monitor;
  245. } Rule;
  246. typedef struct {
  247. struct wlr_scene_tree *scene;
  248. struct wlr_session_lock_v1 *lock;
  249. struct wl_listener new_surface;
  250. struct wl_listener unlock;
  251. struct wl_listener destroy;
  252. } SessionLock;
  253. /* function declarations */
  254. static void applybounds(Client *c, struct wlr_box *bbox);
  255. static void applyrules(Client *c);
  256. static void arrange(Monitor *m);
  257. static void arrangelayer(Monitor *m, struct wl_list *list,
  258. struct wlr_box *usable_area, int exclusive);
  259. static void arrangelayers(Monitor *m);
  260. static void autostartexec(void);
  261. static void axisnotify(struct wl_listener *listener, void *data);
  262. static bool baracceptsinput(struct wlr_scene_buffer *buffer, double *sx, double *sy);
  263. static void bufdestroy(struct wlr_buffer *buffer);
  264. static bool bufdatabegin(struct wlr_buffer *buffer, uint32_t flags,
  265. void **data, uint32_t *format, size_t *stride);
  266. static void bufdataend(struct wlr_buffer *buffer);
  267. static Buffer *bufmon(Monitor *m);
  268. static void bufrelease(struct wl_listener *listener, void *data);
  269. static void buttonpress(struct wl_listener *listener, void *data);
  270. static void chvt(const Arg *arg);
  271. static void checkidleinhibitor(struct wlr_surface *exclude);
  272. static void cleanup(void);
  273. static void cleanupmon(struct wl_listener *listener, void *data);
  274. static void closemon(Monitor *m);
  275. static void commitlayersurfacenotify(struct wl_listener *listener, void *data);
  276. static void commitnotify(struct wl_listener *listener, void *data);
  277. static void commitpopup(struct wl_listener *listener, void *data);
  278. static void createdecoration(struct wl_listener *listener, void *data);
  279. static void createidleinhibitor(struct wl_listener *listener, void *data);
  280. static void createkeyboard(struct wlr_keyboard *keyboard);
  281. static KeyboardGroup *createkeyboardgroup(void);
  282. static void createlayersurface(struct wl_listener *listener, void *data);
  283. static void createlocksurface(struct wl_listener *listener, void *data);
  284. static void createmon(struct wl_listener *listener, void *data);
  285. static void createnotify(struct wl_listener *listener, void *data);
  286. static void createpointer(struct wlr_pointer *pointer);
  287. static void createpointerconstraint(struct wl_listener *listener, void *data);
  288. static void createpopup(struct wl_listener *listener, void *data);
  289. static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
  290. static void cursorframe(struct wl_listener *listener, void *data);
  291. static void cursorwarptohint(void);
  292. static void destroydecoration(struct wl_listener *listener, void *data);
  293. static void destroydragicon(struct wl_listener *listener, void *data);
  294. static void destroyidleinhibitor(struct wl_listener *listener, void *data);
  295. static void destroylayersurfacenotify(struct wl_listener *listener, void *data);
  296. static void destroylock(SessionLock *lock, int unlocked);
  297. static void destroylocksurface(struct wl_listener *listener, void *data);
  298. static void destroynotify(struct wl_listener *listener, void *data);
  299. static void destroypointerconstraint(struct wl_listener *listener, void *data);
  300. static void destroysessionlock(struct wl_listener *listener, void *data);
  301. static void destroysessionmgr(struct wl_listener *listener, void *data);
  302. static void destroykeyboardgroup(struct wl_listener *listener, void *data);
  303. static Monitor *dirtomon(enum wlr_direction dir);
  304. static void drawbar(Monitor *m);
  305. static void drawbars(void);
  306. static void focusclient(Client *c, int lift);
  307. static void focusmon(const Arg *arg);
  308. static void focusstack(const Arg *arg);
  309. static Client *focustop(Monitor *m);
  310. static void fullscreennotify(struct wl_listener *listener, void *data);
  311. static void gpureset(struct wl_listener *listener, void *data);
  312. static void handlecursoractivity(void);
  313. static int hidecursor(void *data);
  314. static void handlesig(int signo);
  315. static void incnmaster(const Arg *arg);
  316. static void inputdevice(struct wl_listener *listener, void *data);
  317. static void kblayout(KeyboardGroup *kb);
  318. static int keybinding(uint32_t mods, xkb_keysym_t sym);
  319. static void keypress(struct wl_listener *listener, void *data);
  320. static void keypressmod(struct wl_listener *listener, void *data);
  321. static int keyrepeat(void *data);
  322. static void killclient(const Arg *arg);
  323. static void locksession(struct wl_listener *listener, void *data);
  324. static void mapnotify(struct wl_listener *listener, void *data);
  325. static void maximizenotify(struct wl_listener *listener, void *data);
  326. static void monocle(Monitor *m);
  327. static void movestack(const Arg *arg);
  328. static void motionabsolute(struct wl_listener *listener, void *data);
  329. static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx,
  330. double sy, double sx_unaccel, double sy_unaccel);
  331. static void motionrelative(struct wl_listener *listener, void *data);
  332. static void moveresize(const Arg *arg);
  333. unsigned int nextocctag(int);
  334. static void outputmgrapply(struct wl_listener *listener, void *data);
  335. static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test);
  336. static void outputmgrtest(struct wl_listener *listener, void *data);
  337. static void pointerfocus(Client *c, struct wlr_surface *surface,
  338. double sx, double sy, uint32_t time);
  339. static void powermgrsetmode(struct wl_listener *listener, void *data);
  340. static void quit(const Arg *arg);
  341. static void rendermon(struct wl_listener *listener, void *data);
  342. static void requestdecorationmode(struct wl_listener *listener, void *data);
  343. static void requeststartdrag(struct wl_listener *listener, void *data);
  344. static void requestmonstate(struct wl_listener *listener, void *data);
  345. static void resize(Client *c, struct wlr_box geo, int interact);
  346. static void run(char *startup_cmd);
  347. static void setcursor(struct wl_listener *listener, void *data);
  348. static void setcursorshape(struct wl_listener *listener, void *data);
  349. static void setfloating(Client *c, int floating);
  350. static void setfullscreen(Client *c, int fullscreen);
  351. static void setsticky(Client *c, int sticky);
  352. static void setgamma(struct wl_listener *listener, void *data);
  353. static void setlayout(const Arg *arg);
  354. static void setmfact(const Arg *arg);
  355. static void setmon(Client *c, Monitor *m, uint32_t newtags);
  356. static void setpsel(struct wl_listener *listener, void *data);
  357. static void setsel(struct wl_listener *listener, void *data);
  358. static void setup(void);
  359. static void spawn(const Arg *arg);
  360. static void startdrag(struct wl_listener *listener, void *data);
  361. static int statusin(int fd, unsigned int mask, void *data);
  362. static void tag(const Arg *arg);
  363. static void tagmon(const Arg *arg);
  364. static void tile(Monitor *m);
  365. static void togglebar(const Arg *arg);
  366. static void togglefloating(const Arg *arg);
  367. static void togglesticky(const Arg *arg);
  368. static void togglefullscreen(const Arg *arg);
  369. static void toggletag(const Arg *arg);
  370. static void toggleview(const Arg *arg);
  371. static void unlocksession(struct wl_listener *listener, void *data);
  372. static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
  373. static void unmapnotify(struct wl_listener *listener, void *data);
  374. static void updatemons(struct wl_listener *listener, void *data);
  375. static void updatebar(Monitor *m);
  376. static void updatetitle(struct wl_listener *listener, void *data);
  377. static void urgent(struct wl_listener *listener, void *data);
  378. static void view(const Arg *arg);
  379. static void viewnextocctag(const Arg *argint);
  380. static void virtualkeyboard(struct wl_listener *listener, void *data);
  381. static void virtualpointer(struct wl_listener *listener, void *data);
  382. static Monitor *xytomon(double x, double y);
  383. static void xytonode(double x, double y, struct wlr_surface **psurface,
  384. Client **pc, LayerSurface **pl, double *nx, double *ny);
  385. static void zoom(const Arg *arg);
  386. static void bstack(Monitor *m);
  387. static void bstackhoriz(Monitor *m);
  388. /* variables */
  389. static const char broken[] = "broken";
  390. static pid_t child_pid = -1;
  391. static int locked;
  392. static void *exclusive_focus;
  393. static struct wl_display *dpy;
  394. static struct wl_event_loop *event_loop;
  395. static struct wlr_backend *backend;
  396. static struct wlr_scene *scene;
  397. static struct wlr_scene_tree *layers[NUM_LAYERS];
  398. static struct wlr_scene_tree *drag_icon;
  399. /* Map from ZWLR_LAYER_SHELL_* constants to Lyr* enum */
  400. static const int layermap[] = { LyrBg, LyrBottom, LyrTop, LyrOverlay };
  401. static struct wlr_renderer *drw;
  402. static struct wlr_allocator *alloc;
  403. static struct wlr_compositor *compositor;
  404. static struct wlr_session *session;
  405. static struct wlr_xdg_shell *xdg_shell;
  406. static struct wlr_xdg_activation_v1 *activation;
  407. static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr;
  408. static struct wl_list clients; /* tiling order */
  409. static struct wl_list fstack; /* focus order */
  410. static struct wlr_idle_notifier_v1 *idle_notifier;
  411. static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr;
  412. static struct wlr_layer_shell_v1 *layer_shell;
  413. static struct wlr_output_manager_v1 *output_mgr;
  414. static struct wlr_gamma_control_manager_v1 *gamma_control_mgr;
  415. static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;
  416. static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr;
  417. static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr;
  418. static struct wlr_output_power_manager_v1 *power_mgr;
  419. static struct wlr_pointer_constraints_v1 *pointer_constraints;
  420. static struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr;
  421. static struct wlr_pointer_constraint_v1 *active_constraint;
  422. static struct wlr_cursor *cursor;
  423. static struct wlr_xcursor_manager *cursor_mgr;
  424. static struct wl_event_source *hide_source;
  425. static bool cursor_hidden = false;
  426. static struct {
  427. enum wp_cursor_shape_device_v1_shape shape;
  428. struct wlr_surface *surface;
  429. int hotspot_x;
  430. int hotspot_y;
  431. } last_cursor;
  432. static struct wlr_scene_rect *root_bg;
  433. static struct wlr_session_lock_manager_v1 *session_lock_mgr;
  434. static struct wlr_scene_rect *locked_bg;
  435. static struct wlr_session_lock_v1 *cur_lock;
  436. static struct wl_listener lock_listener = {.notify = locksession};
  437. static struct wlr_seat *seat;
  438. static KeyboardGroup *kb_group;
  439. static unsigned int cursor_mode;
  440. static Client *grabc;
  441. static int grabcx, grabcy; /* client-relative */
  442. static struct wlr_output_layout *output_layout;
  443. static struct wlr_box sgeom;
  444. static struct wl_list mons;
  445. static Monitor *selmon;
  446. static char stext[256];
  447. static struct wl_event_source *status_event_source;
  448. static const struct wlr_buffer_impl buffer_impl = {
  449. .destroy = bufdestroy,
  450. .begin_data_ptr_access = bufdatabegin,
  451. .end_data_ptr_access = bufdataend,
  452. };
  453. static unsigned int kblayout_idx = -1;
  454. #ifdef XWAYLAND
  455. static void activatex11(struct wl_listener *listener, void *data);
  456. static void associatex11(struct wl_listener *listener, void *data);
  457. static void configurex11(struct wl_listener *listener, void *data);
  458. static void createnotifyx11(struct wl_listener *listener, void *data);
  459. static void dissociatex11(struct wl_listener *listener, void *data);
  460. static xcb_atom_t getatom(xcb_connection_t *xc, const char *name);
  461. static void sethints(struct wl_listener *listener, void *data);
  462. static void xwaylandready(struct wl_listener *listener, void *data);
  463. static struct wlr_xwayland *xwayland;
  464. static xcb_atom_t netatom[NetLast];
  465. #endif
  466. /* configuration, allows nested code to access above variables */
  467. #include "config.h"
  468. /* attempt to encapsulate suck into one file */
  469. #include "client.h"
  470. static pid_t *autostart_pids;
  471. static size_t autostart_len;
  472. struct Pertag {
  473. unsigned int curtag, prevtag; /* current and previous tag */
  474. int nmasters[TAGCOUNT + 1]; /* number of windows in master area */
  475. float mfacts[TAGCOUNT + 1]; /* mfacts per tag */
  476. unsigned int sellts[TAGCOUNT + 1]; /* selected layouts */
  477. const Layout *ltidxs[TAGCOUNT + 1][2]; /* matrix of tags and layouts indexes */
  478. };
  479. /* function implementations */
  480. void
  481. applybounds(Client *c, struct wlr_box *bbox)
  482. {
  483. /* set minimum possible */
  484. c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width);
  485. c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height);
  486. if (c->geom.x >= bbox->x + bbox->width)
  487. c->geom.x = bbox->x + bbox->width - c->geom.width;
  488. if (c->geom.y >= bbox->y + bbox->height)
  489. c->geom.y = bbox->y + bbox->height - c->geom.height;
  490. if (c->geom.x + c->geom.width <= bbox->x)
  491. c->geom.x = bbox->x;
  492. if (c->geom.y + c->geom.height <= bbox->y)
  493. c->geom.y = bbox->y;
  494. }
  495. void
  496. applyrules(Client *c)
  497. {
  498. /* rule matching */
  499. const char *appid, *title;
  500. uint32_t newtags = 0;
  501. int i;
  502. const Rule *r;
  503. Monitor *mon = selmon, *m;
  504. c->isfloating = client_is_float_type(c);
  505. if (!(appid = client_get_appid(c)))
  506. appid = broken;
  507. if (!(title = client_get_title(c)))
  508. title = broken;
  509. for (r = rules; r < END(rules); r++) {
  510. if ((!r->title || strstr(title, r->title))
  511. && (!r->id || strstr(appid, r->id))) {
  512. c->isfloating = r->isfloating;
  513. newtags |= r->tags;
  514. i = 0;
  515. wl_list_for_each(m, &mons, link) {
  516. if (r->monitor == i++)
  517. mon = m;
  518. }
  519. }
  520. }
  521. if (mon) {
  522. c->geom.x = (mon->w.width - c->geom.width) / 2 + mon->m.x;
  523. c->geom.y = (mon->w.height - c->geom.height) / 2 + mon->m.y;
  524. }
  525. setmon(c, mon, newtags);
  526. }
  527. void
  528. arrange(Monitor *m)
  529. {
  530. Client *c;
  531. if (!m->wlr_output->enabled)
  532. return;
  533. wl_list_for_each(c, &clients, link) {
  534. if (c->mon == m) {
  535. wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m));
  536. client_set_suspended(c, !VISIBLEON(c, m));
  537. }
  538. }
  539. wlr_scene_node_set_enabled(&m->fullscreen_bg->node,
  540. (c = focustop(m)) && c->isfullscreen);
  541. strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
  542. /* We move all clients (except fullscreen and unmanaged) to LyrTile while
  543. * in floating layout to avoid "real" floating clients be always on top */
  544. wl_list_for_each(c, &clients, link) {
  545. if (c->mon != m || c->scene->node.parent == layers[LyrFS])
  546. continue;
  547. wlr_scene_node_reparent(&c->scene->node,
  548. (!m->lt[m->sellt]->arrange && c->isfloating)
  549. ? layers[LyrTile]
  550. : (m->lt[m->sellt]->arrange && c->isfloating)
  551. ? layers[LyrFloat]
  552. : c->scene->node.parent);
  553. }
  554. if (m->lt[m->sellt]->arrange)
  555. m->lt[m->sellt]->arrange(m);
  556. motionnotify(0, NULL, 0, 0, 0, 0);
  557. checkidleinhibitor(NULL);
  558. }
  559. void
  560. arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive)
  561. {
  562. LayerSurface *l;
  563. struct wlr_box full_area = m->m;
  564. wl_list_for_each(l, list, link) {
  565. struct wlr_layer_surface_v1 *layer_surface = l->layer_surface;
  566. if (exclusive != (layer_surface->current.exclusive_zone > 0))
  567. continue;
  568. wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, usable_area);
  569. wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, l->scene->node.y);
  570. l->geom.x = l->scene->node.x;
  571. l->geom.y = l->scene->node.y;
  572. }
  573. }
  574. void
  575. arrangelayers(Monitor *m)
  576. {
  577. int i;
  578. struct wlr_box usable_area = m->m;
  579. LayerSurface *l;
  580. uint32_t layers_above_shell[] = {
  581. ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
  582. ZWLR_LAYER_SHELL_V1_LAYER_TOP,
  583. };
  584. if (!m->wlr_output->enabled)
  585. return;
  586. if (m->scene_buffer->node.enabled) {
  587. usable_area.height -= m->b.real_height;
  588. usable_area.y += topbar ? m->b.real_height : 0;
  589. }
  590. /* Arrange exclusive surfaces from top->bottom */
  591. for (i = 3; i >= 0; i--)
  592. arrangelayer(m, &m->layers[i], &usable_area, 1);
  593. if (!wlr_box_equal(&usable_area, &m->w)) {
  594. m->w = usable_area;
  595. arrange(m);
  596. }
  597. /* Arrange non-exlusive surfaces from top->bottom */
  598. for (i = 3; i >= 0; i--)
  599. arrangelayer(m, &m->layers[i], &usable_area, 0);
  600. /* Find topmost keyboard interactive layer, if such a layer exists */
  601. for (i = 0; i < (int)LENGTH(layers_above_shell); i++) {
  602. wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) {
  603. if (locked || !l->layer_surface->current.keyboard_interactive || !l->mapped)
  604. continue;
  605. /* Deactivate the focused client. */
  606. focusclient(NULL, 0);
  607. exclusive_focus = l;
  608. client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat));
  609. return;
  610. }
  611. }
  612. }
  613. void
  614. autostartexec(void) {
  615. const char *const *p;
  616. size_t i = 0;
  617. /* count entries */
  618. for (p = autostart; *p; autostart_len++, p++)
  619. while (*++p);
  620. autostart_pids = calloc(autostart_len, sizeof(pid_t));
  621. for (p = autostart; *p; i++, p++) {
  622. if ((autostart_pids[i] = fork()) == 0) {
  623. setsid();
  624. execvp(*p, (char *const *)p);
  625. die("dwl: execvp %s:", *p);
  626. }
  627. /* skip arguments */
  628. while (*++p);
  629. }
  630. }
  631. void
  632. axisnotify(struct wl_listener *listener, void *data)
  633. {
  634. /* This event is forwarded by the cursor when a pointer emits an axis event,
  635. * for example when you move the scroll wheel. */
  636. struct wlr_pointer_axis_event *event = data;
  637. wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
  638. handlecursoractivity();
  639. /* TODO: allow usage of scroll whell for mousebindings, it can be implemented
  640. * checking the event's orientation and the delta of the event */
  641. /* Notify the client with pointer focus of the axis event. */
  642. wlr_seat_pointer_notify_axis(seat,
  643. event->time_msec, event->orientation, event->delta,
  644. event->delta_discrete, event->source, event->relative_direction);
  645. }
  646. bool
  647. baracceptsinput(struct wlr_scene_buffer *buffer, double *sx, double *sy)
  648. {
  649. return true;
  650. }
  651. void
  652. bufdestroy(struct wlr_buffer *wlr_buffer)
  653. {
  654. Buffer *buf = wl_container_of(wlr_buffer, buf, base);
  655. if (buf->busy)
  656. wl_list_remove(&buf->release.link);
  657. drwl_image_destroy(buf->image);
  658. free(buf);
  659. }
  660. bool
  661. bufdatabegin(struct wlr_buffer *wlr_buffer, uint32_t flags,
  662. void **data, uint32_t *format, size_t *stride)
  663. {
  664. Buffer *buf = wl_container_of(wlr_buffer, buf, base);
  665. if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE) return false;
  666. *data = buf->data;
  667. *stride = wlr_buffer->width * 4;
  668. *format = DRM_FORMAT_ARGB8888;
  669. return true;
  670. }
  671. void
  672. bufdataend(struct wlr_buffer *wlr_buffer)
  673. {
  674. }
  675. Buffer *
  676. bufmon(Monitor *m)
  677. {
  678. size_t i;
  679. Buffer *buf = NULL;
  680. for (i = 0; i < LENGTH(m->pool); i++) {
  681. if (m->pool[i]) {
  682. if (m->pool[i]->busy)
  683. continue;
  684. buf = m->pool[i];
  685. break;
  686. }
  687. buf = ecalloc(1, sizeof(Buffer) + (m->b.width * 4 * m->b.height));
  688. buf->image = drwl_image_create(NULL, m->b.width, m->b.height, buf->data);
  689. wlr_buffer_init(&buf->base, &buffer_impl, m->b.width, m->b.height);
  690. m->pool[i] = buf;
  691. break;
  692. }
  693. if (!buf)
  694. return NULL;
  695. buf->busy = true;
  696. LISTEN(&buf->base.events.release, &buf->release, bufrelease);
  697. wlr_buffer_lock(&buf->base);
  698. drwl_setimage(m->drw, buf->image);
  699. return buf;
  700. }
  701. void
  702. bufrelease(struct wl_listener *listener, void *data)
  703. {
  704. Buffer *buf = wl_container_of(listener, buf, release);
  705. buf->busy = false;
  706. wl_list_remove(&buf->release.link);
  707. }
  708. void
  709. buttonpress(struct wl_listener *listener, void *data)
  710. {
  711. unsigned int i = 0, x = 0, occ = 0;
  712. double cx;
  713. unsigned int click;
  714. struct wlr_pointer_button_event *event = data;
  715. struct wlr_keyboard *keyboard;
  716. struct wlr_scene_node *node;
  717. struct wlr_scene_buffer *buffer;
  718. uint32_t mods;
  719. Arg arg = {0};
  720. Client *c;
  721. const Button *b;
  722. wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
  723. handlecursoractivity();
  724. click = ClkRoot;
  725. xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL);
  726. if (c)
  727. click = ClkClient;
  728. switch (event->state) {
  729. case WL_POINTER_BUTTON_STATE_PRESSED:
  730. cursor_mode = CurPressed;
  731. selmon = xytomon(cursor->x, cursor->y);
  732. if (locked)
  733. break;
  734. if (!c && !exclusive_focus &&
  735. (node = wlr_scene_node_at(&layers[LyrBottom]->node, cursor->x, cursor->y, NULL, NULL)) &&
  736. (buffer = wlr_scene_buffer_from_node(node)) && buffer == selmon->scene_buffer) {
  737. cx = (cursor->x - selmon->m.x) * selmon->wlr_output->scale;
  738. wl_list_for_each(c, &clients, link) {
  739. if (c->mon != selmon)
  740. continue;
  741. occ |= c->tags == TAGMASK ? 0 : c->tags;
  742. }
  743. do {
  744. if (!(occ & 1 << i || selmon->tagset[selmon->seltags] & 1 << i))
  745. continue;
  746. x += TEXTW(selmon, tags[i]);
  747. } while (cursor->x >= x && ++i < LENGTH(tags));
  748. if (i < LENGTH(tags)) {
  749. click = ClkTagBar;
  750. arg.ui = 1 << i;
  751. } else if (cx < x + TEXTW(selmon, selmon->ltsymbol))
  752. click = ClkLtSymbol;
  753. else if (cx > selmon->b.width - (TEXTW(selmon, stext) - selmon->lrpad + 2)) {
  754. click = ClkStatus;
  755. } else
  756. click = ClkTitle;
  757. }
  758. /* Change focus if the button was _pressed_ over a client */
  759. xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL);
  760. if (click == ClkClient && (!client_is_unmanaged(c) || client_wants_focus(c)))
  761. focusclient(c, 1);
  762. keyboard = wlr_seat_get_keyboard(seat);
  763. mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
  764. for (b = buttons; b < END(buttons); b++) {
  765. if (CLEANMASK(mods) == CLEANMASK(b->mod) && event->button == b->button && click == b->click && b->func) {
  766. b->func(click == ClkTagBar && b->arg.i == 0 ? &arg : &b->arg);
  767. return;
  768. }
  769. }
  770. break;
  771. case WL_POINTER_BUTTON_STATE_RELEASED:
  772. /* If you released any buttons, we exit interactive move/resize mode. */
  773. /* TODO should reset to the pointer focus's current setcursor */
  774. if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
  775. wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
  776. cursor_mode = CurNormal;
  777. /* Drop the window off on its new monitor */
  778. selmon = xytomon(cursor->x, cursor->y);
  779. setmon(grabc, selmon, 0);
  780. return;
  781. } else {
  782. cursor_mode = CurNormal;
  783. }
  784. break;
  785. }
  786. /* If the event wasn't handled by the compositor, notify the client with
  787. * pointer focus that a button press has occurred */
  788. wlr_seat_pointer_notify_button(seat,
  789. event->time_msec, event->button, event->state);
  790. }
  791. void
  792. chvt(const Arg *arg)
  793. {
  794. wlr_session_change_vt(session, arg->ui);
  795. }
  796. void
  797. checkidleinhibitor(struct wlr_surface *exclude)
  798. {
  799. int inhibited = 0, unused_lx, unused_ly;
  800. struct wlr_idle_inhibitor_v1 *inhibitor;
  801. wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) {
  802. struct wlr_surface *surface = wlr_surface_get_root_surface(inhibitor->surface);
  803. struct wlr_scene_tree *tree = surface->data;
  804. if (exclude != surface && (bypass_surface_visibility || (!tree
  805. || wlr_scene_node_coords(&tree->node, &unused_lx, &unused_ly)))) {
  806. inhibited = 1;
  807. break;
  808. }
  809. }
  810. wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited);
  811. }
  812. void
  813. cleanup(void)
  814. {
  815. size_t i;
  816. #ifdef XWAYLAND
  817. wlr_xwayland_destroy(xwayland);
  818. xwayland = NULL;
  819. #endif
  820. wl_display_destroy_clients(dpy);
  821. /* kill child processes */
  822. for (i = 0; i < autostart_len; i++) {
  823. if (0 < autostart_pids[i]) {
  824. kill(autostart_pids[i], SIGTERM);
  825. waitpid(autostart_pids[i], NULL, 0);
  826. }
  827. }
  828. if (child_pid > 0) {
  829. kill(-child_pid, SIGTERM);
  830. waitpid(child_pid, NULL, 0);
  831. }
  832. wlr_xcursor_manager_destroy(cursor_mgr);
  833. destroykeyboardgroup(&kb_group->destroy, NULL);
  834. /* If it's not destroyed manually it will cause a use-after-free of wlr_seat.
  835. * Destroy it until it's fixed in the wlroots side */
  836. wlr_backend_destroy(backend);
  837. wl_display_destroy(dpy);
  838. /* Destroy after the wayland display (when the monitors are already destroyed)
  839. to avoid destroying them with an invalid scene output. */
  840. wlr_scene_node_destroy(&scene->tree.node);
  841. drwl_fini();
  842. }
  843. void
  844. cleanupmon(struct wl_listener *listener, void *data)
  845. {
  846. Monitor *m = wl_container_of(listener, m, destroy);
  847. LayerSurface *l, *tmp;
  848. size_t i;
  849. /* m->layers[i] are intentionally not unlinked */
  850. for (i = 0; i < LENGTH(m->layers); i++) {
  851. wl_list_for_each_safe(l, tmp, &m->layers[i], link)
  852. wlr_layer_surface_v1_destroy(l->layer_surface);
  853. }
  854. for (i = 0; i < LENGTH(m->pool); i++)
  855. wlr_buffer_drop(&m->pool[i]->base);
  856. drwl_setimage(m->drw, NULL);
  857. drwl_destroy(m->drw);
  858. wl_list_remove(&m->destroy.link);
  859. wl_list_remove(&m->frame.link);
  860. wl_list_remove(&m->link);
  861. wl_list_remove(&m->request_state.link);
  862. m->wlr_output->data = NULL;
  863. wlr_output_layout_remove(output_layout, m->wlr_output);
  864. wlr_scene_output_destroy(m->scene_output);
  865. free(m->pertag);
  866. closemon(m);
  867. wlr_scene_node_destroy(&m->fullscreen_bg->node);
  868. wlr_scene_node_destroy(&m->scene_buffer->node);
  869. free(m);
  870. }
  871. void
  872. closemon(Monitor *m)
  873. {
  874. /* update selmon if needed and
  875. * move closed monitor's clients to the focused one */
  876. Client *c;
  877. int i = 0, nmons = wl_list_length(&mons);
  878. if (!nmons) {
  879. selmon = NULL;
  880. } else if (m == selmon) {
  881. do /* don't switch to disabled mons */
  882. selmon = wl_container_of(mons.next, selmon, link);
  883. while (!selmon->wlr_output->enabled && i++ < nmons);
  884. if (!selmon->wlr_output->enabled)
  885. selmon = NULL;
  886. }
  887. wl_list_for_each(c, &clients, link) {
  888. if (c->isfloating && c->geom.x > m->m.width)
  889. resize(c, (struct wlr_box){.x = c->geom.x - m->w.width, .y = c->geom.y,
  890. .width = c->geom.width, .height = c->geom.height}, 0);
  891. if (c->mon == m)
  892. setmon(c, selmon, c->tags);
  893. }
  894. focusclient(focustop(selmon), 1);
  895. drawbars();
  896. }
  897. void
  898. commitlayersurfacenotify(struct wl_listener *listener, void *data)
  899. {
  900. LayerSurface *l = wl_container_of(listener, l, surface_commit);
  901. struct wlr_layer_surface_v1 *layer_surface = l->layer_surface;
  902. struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->current.layer]];
  903. struct wlr_layer_surface_v1_state old_state;
  904. if (l->layer_surface->initial_commit) {
  905. wlr_fractional_scale_v1_notify_scale(layer_surface->surface, l->mon->wlr_output->scale);
  906. wlr_surface_set_preferred_buffer_scale(layer_surface->surface, (int32_t)ceilf(l->mon->wlr_output->scale));
  907. /* Temporarily set the layer's current state to pending
  908. * so that we can easily arrange it */
  909. old_state = l->layer_surface->current;
  910. l->layer_surface->current = l->layer_surface->pending;
  911. arrangelayers(l->mon);
  912. l->layer_surface->current = old_state;
  913. return;
  914. }
  915. if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped)
  916. return;
  917. l->mapped = layer_surface->surface->mapped;
  918. if (scene_layer != l->scene->node.parent) {
  919. wlr_scene_node_reparent(&l->scene->node, scene_layer);
  920. wl_list_remove(&l->link);
  921. wl_list_insert(&l->mon->layers[layer_surface->current.layer], &l->link);
  922. wlr_scene_node_reparent(&l->popups->node, (layer_surface->current.layer
  923. < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer));
  924. }
  925. arrangelayers(l->mon);
  926. }
  927. void
  928. commitnotify(struct wl_listener *listener, void *data)
  929. {
  930. Client *c = wl_container_of(listener, c, commit);
  931. if (c->surface.xdg->initial_commit) {
  932. /*
  933. * Get the monitor this client will be rendered on
  934. * Note that if the user set a rule in which the client is placed on
  935. * a different monitor based on its title this will likely select
  936. * a wrong monitor.
  937. */
  938. applyrules(c);
  939. wlr_surface_set_preferred_buffer_scale(client_surface(c), (int)ceilf(c->mon->wlr_output->scale));
  940. wlr_fractional_scale_v1_notify_scale(client_surface(c), c->mon->wlr_output->scale);
  941. setmon(c, NULL, 0); /* Make sure to reapply rules in mapnotify() */
  942. wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
  943. wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0);
  944. if (c->decoration)
  945. requestdecorationmode(&c->set_decoration_mode, c->decoration);
  946. return;
  947. }
  948. if (client_surface(c)->mapped && c->mon)
  949. resize(c, c->geom, (c->isfloating && !c->isfullscreen));
  950. /* mark a pending resize as completed */
  951. if (c->resize && c->resize <= c->surface.xdg->current.configure_serial)
  952. c->resize = 0;
  953. }
  954. void
  955. commitpopup(struct wl_listener *listener, void *data)
  956. {
  957. struct wlr_surface *surface = data;
  958. struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface);
  959. LayerSurface *l = NULL;
  960. Client *c = NULL;
  961. struct wlr_box box;
  962. int type = -1;
  963. if (!popup->base->initial_commit)
  964. return;
  965. type = toplevel_from_wlr_surface(popup->base->surface, &c, &l);
  966. if (!popup->parent || type < 0)
  967. return;
  968. popup->base->surface->data = wlr_scene_xdg_surface_create(
  969. popup->parent->data, popup->base);
  970. if ((l && !l->mon) || (c && !c->mon))
  971. return;
  972. box = type == LayerShell ? l->mon->m : c->mon->w;
  973. box.x -= (type == LayerShell ? l->geom.x : c->geom.x);
  974. box.y -= (type == LayerShell ? l->geom.y : c->geom.y);
  975. wlr_xdg_popup_unconstrain_from_box(popup, &box);
  976. wl_list_remove(&listener->link);
  977. }
  978. void
  979. createdecoration(struct wl_listener *listener, void *data)
  980. {
  981. struct wlr_xdg_toplevel_decoration_v1 *deco = data;
  982. Client *c = deco->toplevel->base->data;
  983. c->decoration = deco;
  984. LISTEN(&deco->events.request_mode, &c->set_decoration_mode, requestdecorationmode);
  985. LISTEN(&deco->events.destroy, &c->destroy_decoration, destroydecoration);
  986. requestdecorationmode(&c->set_decoration_mode, deco);
  987. }
  988. void
  989. createidleinhibitor(struct wl_listener *listener, void *data)
  990. {
  991. struct wlr_idle_inhibitor_v1 *idle_inhibitor = data;
  992. LISTEN_STATIC(&idle_inhibitor->events.destroy, destroyidleinhibitor);
  993. checkidleinhibitor(NULL);
  994. }
  995. void
  996. createkeyboard(struct wlr_keyboard *keyboard)
  997. {
  998. /* Set the keymap to match the group keymap */
  999. wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap);
  1000. /* Add the new keyboard to the group */
  1001. wlr_keyboard_group_add_keyboard(kb_group->wlr_group, keyboard);
  1002. kblayout(kb_group);
  1003. }
  1004. KeyboardGroup *
  1005. createkeyboardgroup(void)
  1006. {
  1007. KeyboardGroup *group = ecalloc(1, sizeof(*group));
  1008. struct xkb_context *context;
  1009. struct xkb_keymap *keymap;
  1010. group->wlr_group = wlr_keyboard_group_create();
  1011. group->wlr_group->data = group;
  1012. /* Prepare an XKB keymap and assign it to the keyboard group. */
  1013. context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  1014. if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules,
  1015. XKB_KEYMAP_COMPILE_NO_FLAGS)))
  1016. die("failed to compile keymap");
  1017. wlr_keyboard_set_keymap(&group->wlr_group->keyboard, keymap);
  1018. xkb_keymap_unref(keymap);
  1019. xkb_context_unref(context);
  1020. wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard, repeat_rate, repeat_delay);
  1021. /* Set up listeners for keyboard events */
  1022. LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress);
  1023. LISTEN(&group->wlr_group->keyboard.events.modifiers, &group->modifiers, keypressmod);
  1024. group->key_repeat_source = wl_event_loop_add_timer(event_loop, keyrepeat, group);
  1025. /* A seat can only have one keyboard, but this is a limitation of the
  1026. * Wayland protocol - not wlroots. We assign all connected keyboards to the
  1027. * same wlr_keyboard_group, which provides a single wlr_keyboard interface for
  1028. * all of them. Set this combined wlr_keyboard as the seat keyboard.
  1029. */
  1030. wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard);
  1031. return group;
  1032. }
  1033. void
  1034. createlayersurface(struct wl_listener *listener, void *data)
  1035. {
  1036. struct wlr_layer_surface_v1 *layer_surface = data;
  1037. LayerSurface *l;
  1038. struct wlr_surface *surface = layer_surface->surface;
  1039. struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->pending.layer]];
  1040. if (!layer_surface->output
  1041. && !(layer_surface->output = selmon ? selmon->wlr_output : NULL)) {
  1042. wlr_layer_surface_v1_destroy(layer_surface);
  1043. return;
  1044. }
  1045. l = layer_surface->data = ecalloc(1, sizeof(*l));
  1046. l->type = LayerShell;
  1047. LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify);
  1048. LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify);
  1049. LISTEN(&layer_surface->events.destroy, &l->destroy, destroylayersurfacenotify);
  1050. l->layer_surface = layer_surface;
  1051. l->mon = layer_surface->output->data;
  1052. l->scene_layer = wlr_scene_layer_surface_v1_create(scene_layer, layer_surface);
  1053. l->scene = l->scene_layer->tree;
  1054. l->popups = surface->data = wlr_scene_tree_create(layer_surface->current.layer
  1055. < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer);
  1056. l->scene->node.data = l->popups->node.data = l;
  1057. wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link);
  1058. wlr_surface_send_enter(surface, layer_surface->output);
  1059. }
  1060. void
  1061. createlocksurface(struct wl_listener *listener, void *data)
  1062. {
  1063. SessionLock *lock = wl_container_of(listener, lock, new_surface);
  1064. struct wlr_session_lock_surface_v1 *lock_surface = data;
  1065. Monitor *m = lock_surface->output->data;
  1066. struct wlr_scene_tree *scene_tree = lock_surface->surface->data
  1067. = wlr_scene_subsurface_tree_create(lock->scene, lock_surface->surface);
  1068. m->lock_surface = lock_surface;
  1069. wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y);
  1070. wlr_session_lock_surface_v1_configure(lock_surface, m->m.width, m->m.height);
  1071. LISTEN(&lock_surface->events.destroy, &m->destroy_lock_surface, destroylocksurface);
  1072. if (m == selmon)
  1073. client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat));
  1074. }
  1075. void
  1076. createmon(struct wl_listener *listener, void *data)
  1077. {
  1078. /* This event is raised by the backend when a new output (aka a display or
  1079. * monitor) becomes available. */
  1080. struct wlr_output *wlr_output = data;
  1081. const MonitorRule *r;
  1082. size_t i;
  1083. struct wlr_output_state state;
  1084. Monitor *m;
  1085. if (!wlr_output_init_render(wlr_output, alloc, drw))
  1086. return;
  1087. m = wlr_output->data = ecalloc(1, sizeof(*m));
  1088. m->wlr_output = wlr_output;
  1089. for (i = 0; i < LENGTH(m->layers); i++)
  1090. wl_list_init(&m->layers[i]);
  1091. wlr_output_state_init(&state);
  1092. /* Initialize monitor state using configured rules */
  1093. m->tagset[0] = m->tagset[1] = 1;
  1094. for (r = monrules; r < END(monrules); r++) {
  1095. if (!r->name || strstr(wlr_output->name, r->name)) {
  1096. m->m.x = r->x;
  1097. m->m.y = r->y;
  1098. m->mfact = r->mfact;
  1099. m->nmaster = r->nmaster;
  1100. m->lt[0] = r->lt;
  1101. m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]];
  1102. strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
  1103. wlr_output_state_set_scale(&state, r->scale);
  1104. wlr_output_state_set_transform(&state, r->rr);
  1105. break;
  1106. }
  1107. }
  1108. /* The mode is a tuple of (width, height, refresh rate), and each
  1109. * monitor supports only a specific set of modes. We just pick the
  1110. * monitor's preferred mode; a more sophisticated compositor would let
  1111. * the user configure it. */
  1112. wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output));
  1113. /* Set up event listeners */
  1114. LISTEN(&wlr_output->events.frame, &m->frame, rendermon);
  1115. LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon);
  1116. LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate);
  1117. wlr_output_state_set_enabled(&state, 1);
  1118. wlr_output_commit_state(wlr_output, &state);
  1119. wlr_output_state_finish(&state);
  1120. if (!(m->drw = drwl_create()))
  1121. die("failed to create drwl context");
  1122. m->scene_buffer = wlr_scene_buffer_create(layers[LyrBottom], NULL);
  1123. m->scene_buffer->point_accepts_input = baracceptsinput;
  1124. updatebar(m);
  1125. wl_list_insert(&mons, &m->link);
  1126. drawbars();
  1127. m->pertag = calloc(1, sizeof(Pertag));
  1128. m->pertag->curtag = m->pertag->prevtag = 1;
  1129. for (i = 0; i <= TAGCOUNT; i++) {
  1130. m->pertag->nmasters[i] = m->nmaster;
  1131. m->pertag->mfacts[i] = m->mfact;
  1132. m->pertag->ltidxs[i][0] = m->lt[0];
  1133. m->pertag->ltidxs[i][1] = m->lt[1];
  1134. m->pertag->sellts[i] = m->sellt;
  1135. }
  1136. /* The xdg-protocol specifies:
  1137. *
  1138. * If the fullscreened surface is not opaque, the compositor must make
  1139. * sure that other screen content not part of the same surface tree (made
  1140. * up of subsurfaces, popups or similarly coupled surfaces) are not
  1141. * visible below the fullscreened surface.
  1142. *
  1143. */
  1144. /* updatemons() will resize and set correct position */
  1145. m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg);
  1146. wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0);
  1147. /* Adds this to the output layout in the order it was configured.
  1148. *
  1149. * The output layout utility automatically adds a wl_output global to the
  1150. * display, which Wayland clients can see to find out information about the
  1151. * output (such as DPI, scale factor, manufacturer, etc).
  1152. */
  1153. m->scene_output = wlr_scene_output_create(scene, wlr_output);
  1154. if (m->m.x == -1 && m->m.y == -1)
  1155. wlr_output_layout_add_auto(output_layout, wlr_output);
  1156. else
  1157. wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y);
  1158. }
  1159. void
  1160. createnotify(struct wl_listener *listener, void *data)
  1161. {
  1162. /* This event is raised when a client creates a new toplevel (application window). */
  1163. struct wlr_xdg_toplevel *toplevel = data;
  1164. Client *c = NULL;
  1165. struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat);
  1166. /* Allocate a Client for this surface */
  1167. c = toplevel->base->data = ecalloc(1, sizeof(*c));
  1168. c->surface.xdg = toplevel->base;
  1169. c->bw = borderpx;
  1170. c->kblayout_idx = kb ? kb->modifiers.group : 0;
  1171. LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify);
  1172. LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify);
  1173. LISTEN(&toplevel->base->surface->events.unmap, &c->unmap, unmapnotify);
  1174. LISTEN(&toplevel->events.destroy, &c->destroy, destroynotify);
  1175. LISTEN(&toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify);
  1176. LISTEN(&toplevel->events.request_maximize, &c->maximize, maximizenotify);
  1177. LISTEN(&toplevel->events.set_title, &c->set_title, updatetitle);
  1178. }
  1179. void
  1180. createpointer(struct wlr_pointer *pointer)
  1181. {
  1182. struct libinput_device *device;
  1183. if (wlr_input_device_is_libinput(&pointer->base)
  1184. && (device = wlr_libinput_get_device_handle(&pointer->base))) {
  1185. if (libinput_device_config_tap_get_finger_count(device)) {
  1186. libinput_device_config_tap_set_enabled(device, tap_to_click);
  1187. libinput_device_config_tap_set_drag_enabled(device, tap_and_drag);
  1188. libinput_device_config_tap_set_drag_lock_enabled(device, drag_lock);
  1189. libinput_device_config_tap_set_button_map(device, button_map);
  1190. }
  1191. if (libinput_device_config_scroll_has_natural_scroll(device))
  1192. libinput_device_config_scroll_set_natural_scroll_enabled(device, natural_scrolling);
  1193. if (libinput_device_config_dwt_is_available(device))
  1194. libinput_device_config_dwt_set_enabled(device, disable_while_typing);
  1195. if (libinput_device_config_left_handed_is_available(device))
  1196. libinput_device_config_left_handed_set(device, left_handed);
  1197. if (libinput_device_config_middle_emulation_is_available(device))
  1198. libinput_device_config_middle_emulation_set_enabled(device, middle_button_emulation);
  1199. if (libinput_device_config_scroll_get_methods(device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL)
  1200. libinput_device_config_scroll_set_method (device, scroll_method);
  1201. if (libinput_device_config_click_get_methods(device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE)
  1202. libinput_device_config_click_set_method (device, click_method);
  1203. if (libinput_device_config_send_events_get_modes(device))
  1204. libinput_device_config_send_events_set_mode(device, send_events_mode);
  1205. if (libinput_device_config_accel_is_available(device)) {
  1206. libinput_device_config_accel_set_profile(device, accel_profile);
  1207. libinput_device_config_accel_set_speed(device, accel_speed);
  1208. }
  1209. }
  1210. wlr_cursor_attach_input_device(cursor, &pointer->base);
  1211. }
  1212. void
  1213. createpointerconstraint(struct wl_listener *listener, void *data)
  1214. {
  1215. PointerConstraint *pointer_constraint = ecalloc(1, sizeof(*pointer_constraint));
  1216. pointer_constraint->constraint = data;
  1217. LISTEN(&pointer_constraint->constraint->events.destroy,
  1218. &pointer_constraint->destroy, destroypointerconstraint);
  1219. }
  1220. void
  1221. createpopup(struct wl_listener *listener, void *data)
  1222. {
  1223. /* This event is raised when a client (either xdg-shell or layer-shell)
  1224. * creates a new popup. */
  1225. struct wlr_xdg_popup *popup = data;
  1226. LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup);
  1227. }
  1228. void
  1229. cursorconstrain(struct wlr_pointer_constraint_v1 *constraint)
  1230. {
  1231. if (active_constraint == constraint)
  1232. return;
  1233. if (active_constraint)
  1234. wlr_pointer_constraint_v1_send_deactivated(active_constraint);
  1235. active_constraint = constraint;
  1236. wlr_pointer_constraint_v1_send_activated(constraint);
  1237. }
  1238. void
  1239. cursorframe(struct wl_listener *listener, void *data)
  1240. {
  1241. /* This event is forwarded by the cursor when a pointer emits an frame
  1242. * event. Frame events are sent after regular pointer events to group
  1243. * multiple events together. For instance, two axis events may happen at the
  1244. * same time, in which case a frame event won't be sent in between. */
  1245. /* Notify the client with pointer focus of the frame event. */
  1246. wlr_seat_pointer_notify_frame(seat);
  1247. }
  1248. void
  1249. cursorwarptohint(void)
  1250. {
  1251. Client *c = NULL;
  1252. double sx = active_constraint->current.cursor_hint.x;
  1253. double sy = active_constraint->current.cursor_hint.y;
  1254. toplevel_from_wlr_surface(active_constraint->surface, &c, NULL);
  1255. if (c && active_constraint->current.cursor_hint.enabled) {
  1256. wlr_cursor_warp(cursor, NULL, sx + c->geom.x + c->bw, sy + c->geom.y + c->bw);
  1257. wlr_seat_pointer_warp(active_constraint->seat, sx, sy);
  1258. }
  1259. }
  1260. void
  1261. destroydecoration(struct wl_listener *listener, void *data)
  1262. {
  1263. Client *c = wl_container_of(listener, c, destroy_decoration);
  1264. c->decoration = NULL;
  1265. wl_list_remove(&c->destroy_decoration.link);
  1266. wl_list_remove(&c->set_decoration_mode.link);
  1267. }
  1268. void
  1269. destroydragicon(struct wl_listener *listener, void *data)
  1270. {
  1271. /* Focus enter isn't sent during drag, so refocus the focused node. */
  1272. focusclient(focustop(selmon), 1);
  1273. motionnotify(0, NULL, 0, 0, 0, 0);
  1274. }
  1275. void
  1276. destroyidleinhibitor(struct wl_listener *listener, void *data)
  1277. {
  1278. /* `data` is the wlr_surface of the idle inhibitor being destroyed,
  1279. * at this point the idle inhibitor is still in the list of the manager */
  1280. checkidleinhibitor(wlr_surface_get_root_surface(data));
  1281. }
  1282. void
  1283. destroylayersurfacenotify(struct wl_listener *listener, void *data)
  1284. {
  1285. LayerSurface *l = wl_container_of(listener, l, destroy);
  1286. wl_list_remove(&l->link);
  1287. wl_list_remove(&l->destroy.link);
  1288. wl_list_remove(&l->unmap.link);
  1289. wl_list_remove(&l->surface_commit.link);
  1290. wlr_scene_node_destroy(&l->scene->node);
  1291. wlr_scene_node_destroy(&l->popups->node);
  1292. free(l);
  1293. }
  1294. void
  1295. destroylock(SessionLock *lock, int unlock)
  1296. {
  1297. wlr_seat_keyboard_notify_clear_focus(seat);
  1298. if ((locked = !unlock))
  1299. goto destroy;
  1300. wlr_scene_node_set_enabled(&locked_bg->node, 0);
  1301. focusclient(focustop(selmon), 0);
  1302. motionnotify(0, NULL, 0, 0, 0, 0);
  1303. destroy:
  1304. wl_list_remove(&lock->new_surface.link);
  1305. wl_list_remove(&lock->unlock.link);
  1306. wl_list_remove(&lock->destroy.link);
  1307. wlr_scene_node_destroy(&lock->scene->node);
  1308. cur_lock = NULL;
  1309. free(lock);
  1310. }
  1311. void
  1312. destroylocksurface(struct wl_listener *listener, void *data)
  1313. {
  1314. Monitor *m = wl_container_of(listener, m, destroy_lock_surface);
  1315. struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface;
  1316. m->lock_surface = NULL;
  1317. wl_list_remove(&m->destroy_lock_surface.link);
  1318. if (lock_surface->surface != seat->keyboard_state.focused_surface)
  1319. return;
  1320. if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) {
  1321. surface = wl_container_of(cur_lock->surfaces.next, surface, link);
  1322. client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat));
  1323. } else if (!locked) {
  1324. focusclient(focustop(selmon), 1);
  1325. } else {
  1326. wlr_seat_keyboard_clear_focus(seat);
  1327. }
  1328. }
  1329. void
  1330. destroynotify(struct wl_listener *listener, void *data)
  1331. {
  1332. /* Called when the xdg_toplevel is destroyed. */
  1333. Client *c = wl_container_of(listener, c, destroy);
  1334. wl_list_remove(&c->destroy.link);
  1335. wl_list_remove(&c->set_title.link);
  1336. wl_list_remove(&c->fullscreen.link);
  1337. #ifdef XWAYLAND
  1338. if (c->type != XDGShell) {
  1339. wl_list_remove(&c->activate.link);
  1340. wl_list_remove(&c->associate.link);
  1341. wl_list_remove(&c->configure.link);
  1342. wl_list_remove(&c->dissociate.link);
  1343. wl_list_remove(&c->set_hints.link);
  1344. } else
  1345. #endif
  1346. {
  1347. wl_list_remove(&c->commit.link);
  1348. wl_list_remove(&c->map.link);
  1349. wl_list_remove(&c->unmap.link);
  1350. }
  1351. free(c);
  1352. }
  1353. void
  1354. destroypointerconstraint(struct wl_listener *listener, void *data)
  1355. {
  1356. PointerConstraint *pointer_constraint = wl_container_of(listener, pointer_constraint, destroy);
  1357. if (active_constraint == pointer_constraint->constraint) {
  1358. cursorwarptohint();
  1359. active_constraint = NULL;
  1360. }
  1361. wl_list_remove(&pointer_constraint->destroy.link);
  1362. free(pointer_constraint);
  1363. }
  1364. void
  1365. destroysessionlock(struct wl_listener *listener, void *data)
  1366. {
  1367. SessionLock *lock = wl_container_of(listener, lock, destroy);
  1368. destroylock(lock, 0);
  1369. }
  1370. void
  1371. destroysessionmgr(struct wl_listener *listener, void *data)
  1372. {
  1373. wl_list_remove(&lock_listener.link);
  1374. wl_list_remove(&listener->link);
  1375. }
  1376. void
  1377. destroykeyboardgroup(struct wl_listener *listener, void *data)
  1378. {
  1379. KeyboardGroup *group = wl_container_of(listener, group, destroy);
  1380. wl_event_source_remove(group->key_repeat_source);
  1381. wlr_keyboard_group_destroy(group->wlr_group);
  1382. wl_list_remove(&group->key.link);
  1383. wl_list_remove(&group->modifiers.link);
  1384. wl_list_remove(&group->destroy.link);
  1385. free(group);
  1386. }
  1387. Monitor *
  1388. dirtomon(enum wlr_direction dir)
  1389. {
  1390. struct wlr_output *next;
  1391. if (!wlr_output_layout_get(output_layout, selmon->wlr_output))
  1392. return selmon;
  1393. if ((next = wlr_output_layout_adjacent_output(output_layout,
  1394. dir, selmon->wlr_output, selmon->m.x, selmon->m.y)))
  1395. return next->data;
  1396. if ((next = wlr_output_layout_farthest_output(output_layout,
  1397. dir ^ (WLR_DIRECTION_LEFT|WLR_DIRECTION_RIGHT),
  1398. selmon->wlr_output, selmon->m.x, selmon->m.y)))
  1399. return next->data;
  1400. return selmon;
  1401. }
  1402. void
  1403. drawbar(Monitor *m)
  1404. {
  1405. int x, w, tw = 0;
  1406. int boxs = m->drw->font->height / 9;
  1407. int boxw = m->drw->font->height / 6 + 2;
  1408. uint32_t i, occ = 0, urg = 0;
  1409. Client *c;
  1410. Buffer *buf;
  1411. if (!m->scene_buffer->node.enabled)
  1412. return;
  1413. if (!(buf = bufmon(m)))
  1414. return;
  1415. /* draw status first so it can be overdrawn by tags later */
  1416. if (m == selmon) { /* status is only drawn on selected monitor */
  1417. drwl_setscheme(m->drw, colors[SchemeNorm]);
  1418. tw = TEXTW(m, stext) - m->lrpad + 2; /* 2px right padding */
  1419. drwl_text(m->drw, m->b.width - tw, 0, tw, m->b.height, 0, stext, 0);
  1420. }
  1421. wl_list_for_each(c, &clients, link) {
  1422. if (c->mon != m)
  1423. continue;
  1424. occ |= c->tags == TAGMASK ? 0 : c->tags;
  1425. if (c->isurgent)
  1426. urg |= c->tags;
  1427. }
  1428. x = 0;
  1429. c = focustop(m);
  1430. for (i = 0; i < LENGTH(tags); i++) {
  1431. if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
  1432. continue;
  1433. w = TEXTW(m, tags[i]);
  1434. drwl_setscheme(m->drw, colors[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
  1435. drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, tags[i], urg & 1 << i);
  1436. x += w;
  1437. }
  1438. w = TEXTW(m, m->ltsymbol);
  1439. drwl_setscheme(m->drw, colors[SchemeNorm]);
  1440. x = drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, m->ltsymbol, 0);
  1441. if ((w = m->b.width - tw - x) > m->b.height) {
  1442. if (c) {
  1443. drwl_setscheme(m->drw, colors[m == selmon ? SchemeSel : SchemeNorm]);
  1444. drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, client_get_title(c), 0);
  1445. if (c && c->isfloating)
  1446. drwl_rect(m->drw, x + boxs, boxs, boxw, boxw, 0, 0);
  1447. } else {
  1448. drwl_setscheme(m->drw, colors[SchemeNorm]);
  1449. drwl_rect(m->drw, x, 0, w, m->b.height, 1, 1);
  1450. }
  1451. }
  1452. wlr_scene_buffer_set_dest_size(m->scene_buffer,
  1453. m->b.real_width, m->b.real_height);
  1454. wlr_scene_node_set_position(&m->scene_buffer->node, m->m.x,
  1455. m->m.y + (topbar ? 0 : m->m.height - m->b.real_height));
  1456. wlr_scene_buffer_set_buffer(m->scene_buffer, &buf->base);
  1457. wlr_buffer_unlock(&buf->base);
  1458. }
  1459. void
  1460. drawbars(void)
  1461. {
  1462. Monitor *m = NULL;
  1463. wl_list_for_each(m, &mons, link)
  1464. drawbar(m);
  1465. }
  1466. void
  1467. focusclient(Client *c, int lift)
  1468. {
  1469. /* Copied from wlroots/types/wlr_keyboard_group.c */
  1470. struct keyboard_group_device {
  1471. struct wlr_keyboard *keyboard;
  1472. struct wl_listener key;
  1473. struct wl_listener modifiers;
  1474. struct wl_listener keymap;
  1475. struct wl_listener repeat_info;
  1476. struct wl_listener destroy;
  1477. struct wl_list link; // wlr_keyboard_group.devices
  1478. };
  1479. struct wlr_surface *old = seat->keyboard_state.focused_surface;
  1480. int unused_lx, unused_ly, old_client_type;
  1481. Client *old_c = NULL;
  1482. LayerSurface *old_l = NULL;
  1483. struct keyboard_group_device *device;
  1484. struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat);
  1485. struct wlr_keyboard_group *group = kb ? wlr_keyboard_group_from_wlr_keyboard(kb) : NULL;
  1486. if (locked)
  1487. return;
  1488. /* Raise client in stacking order if requested */
  1489. if (c && lift)
  1490. wlr_scene_node_raise_to_top(&c->scene->node);
  1491. if (c && client_surface(c) == old)
  1492. return;
  1493. if ((old_client_type = toplevel_from_wlr_surface(old, &old_c, &old_l)) == XDGShell) {
  1494. struct wlr_xdg_popup *popup, *tmp;
  1495. wl_list_for_each_safe(popup, tmp, &old_c->surface.xdg->popups, link)
  1496. wlr_xdg_popup_destroy(popup);
  1497. }
  1498. /* Put the new client atop the focus stack and select its monitor */
  1499. if (c && !client_is_unmanaged(c)) {
  1500. wl_list_remove(&c->flink);
  1501. wl_list_insert(&fstack, &c->flink);
  1502. selmon = c->mon;
  1503. c->isurgent = 0;
  1504. client_restack_surface(c);
  1505. /* Don't change border color if there is an exclusive focus or we are
  1506. * handling a drag operation */
  1507. if (!exclusive_focus && !seat->drag)
  1508. client_set_border_color(c, (float[])COLOR(colors[SchemeSel][ColBorder]));
  1509. }
  1510. /* Deactivate old client if focus is changing */
  1511. if (old && (!c || client_surface(c) != old)) {
  1512. /* If an overlay is focused, don't focus or activate the client,
  1513. * but only update its position in fstack to render its border with its color
  1514. * and focus it after the overlay is closed. */
  1515. if (old_client_type == LayerShell && wlr_scene_node_coords(
  1516. &old_l->scene->node, &unused_lx, &unused_ly)
  1517. && old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
  1518. return;
  1519. } else if (old_c && old_c == exclusive_focus && client_wants_focus(old_c)) {
  1520. return;
  1521. /* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg
  1522. * and probably other clients */
  1523. } else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) {
  1524. client_set_border_color(old_c, (float[])COLOR(colors[SchemeNorm][ColBorder]));
  1525. client_activate_surface(old, 0);
  1526. }
  1527. }
  1528. drawbars();
  1529. /* Update keyboard layout */
  1530. if (group) {
  1531. // Update the first real device, because kb or group->kb is not a real
  1532. // keyboard and its effective layout gets overwritten
  1533. device = wl_container_of(group->devices.next, device, link);
  1534. wlr_keyboard_notify_modifiers(device->keyboard,
  1535. device->keyboard->modifiers.depressed,
  1536. device->keyboard->modifiers.latched,
  1537. device->keyboard->modifiers.locked,
  1538. c ? c->kblayout_idx : 0
  1539. );
  1540. }
  1541. if (!c) {
  1542. /* With no client, all we have left is to clear focus */
  1543. wlr_seat_keyboard_notify_clear_focus(seat);
  1544. return;
  1545. }
  1546. /* Change cursor surface */
  1547. motionnotify(0, NULL, 0, 0, 0, 0);
  1548. /* Have a client, so focus its top-level wlr_surface */
  1549. client_notify_enter(client_surface(c), kb);
  1550. /* Activate the new client */
  1551. client_activate_surface(client_surface(c), 1);
  1552. }
  1553. void
  1554. focusmon(const Arg *arg)
  1555. {
  1556. int i = 0, nmons = wl_list_length(&mons);
  1557. if (nmons) {
  1558. do /* don't switch to disabled mons */
  1559. selmon = dirtomon(arg->i);
  1560. while (!selmon->wlr_output->enabled && i++ < nmons);
  1561. }
  1562. focusclient(focustop(selmon), 1);
  1563. }
  1564. void
  1565. focusstack(const Arg *arg)
  1566. {
  1567. /* Focus the next or previous client (in tiling order) on selmon */
  1568. Client *c, *sel = focustop(selmon);
  1569. if (!sel || (sel->isfullscreen && !client_has_children(sel)))
  1570. return;
  1571. if (arg->i > 0) {
  1572. wl_list_for_each(c, &sel->link, link) {
  1573. if (&c->link == &clients)
  1574. continue; /* wrap past the sentinel node */
  1575. if (VISIBLEON(c, selmon))
  1576. break; /* found it */
  1577. }
  1578. } else {
  1579. wl_list_for_each_reverse(c, &sel->link, link) {
  1580. if (&c->link == &clients)
  1581. continue; /* wrap past the sentinel node */
  1582. if (VISIBLEON(c, selmon))
  1583. break; /* found it */
  1584. }
  1585. }
  1586. /* If only one client is visible on selmon, then c == sel */
  1587. focusclient(c, 1);
  1588. }
  1589. /* We probably should change the name of this, it sounds like
  1590. * will focus the topmost client of this mon, when actually will
  1591. * only return that client */
  1592. Client *
  1593. focustop(Monitor *m)
  1594. {
  1595. Client *c;
  1596. wl_list_for_each(c, &fstack, flink) {
  1597. if (VISIBLEON(c, m))
  1598. return c;
  1599. }
  1600. return NULL;
  1601. }
  1602. void
  1603. fullscreennotify(struct wl_listener *listener, void *data)
  1604. {
  1605. Client *c = wl_container_of(listener, c, fullscreen);
  1606. setfullscreen(c, client_wants_fullscreen(c));
  1607. }
  1608. void
  1609. gpureset(struct wl_listener *listener, void *data)
  1610. {
  1611. struct wlr_renderer *old_drw = drw;
  1612. struct wlr_allocator *old_alloc = alloc;
  1613. struct Monitor *m;
  1614. if (!(drw = wlr_renderer_autocreate(backend)))
  1615. die("couldn't recreate renderer");
  1616. if (!(alloc = wlr_allocator_autocreate(backend, drw)))
  1617. die("couldn't recreate allocator");
  1618. LISTEN_STATIC(&drw->events.lost, gpureset);
  1619. wlr_compositor_set_renderer(compositor, drw);
  1620. wl_list_for_each(m, &mons, link) {
  1621. wlr_output_init_render(m->wlr_output, alloc, drw);
  1622. }
  1623. wlr_allocator_destroy(old_alloc);
  1624. wlr_renderer_destroy(old_drw);
  1625. }
  1626. void
  1627. handlesig(int signo)
  1628. {
  1629. if (signo == SIGCHLD) {
  1630. siginfo_t in;
  1631. /* wlroots expects to reap the XWayland process itself, so we
  1632. * use WNOWAIT to keep the child waitable until we know it's not
  1633. * XWayland.
  1634. */
  1635. while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid
  1636. #ifdef XWAYLAND
  1637. && (!xwayland || in.si_pid != xwayland->server->pid)
  1638. #endif
  1639. ) {
  1640. pid_t *p, *lim;
  1641. waitpid(in.si_pid, NULL, 0);
  1642. if (in.si_pid == child_pid)
  1643. child_pid = -1;
  1644. if (!(p = autostart_pids))
  1645. continue;
  1646. lim = &p[autostart_len];
  1647. for (; p < lim; p++) {
  1648. if (*p == in.si_pid) {
  1649. *p = -1;
  1650. break;
  1651. }
  1652. }
  1653. }
  1654. } else if (signo == SIGINT || signo == SIGTERM) {
  1655. quit(NULL);
  1656. }
  1657. }
  1658. void
  1659. handlecursoractivity(void)
  1660. {
  1661. wl_event_source_timer_update(hide_source, cursor_timeout * 1000);
  1662. if (!cursor_hidden)
  1663. return;
  1664. cursor_hidden = false;
  1665. if (last_cursor.shape)
  1666. wlr_cursor_set_xcursor(cursor, cursor_mgr,
  1667. wlr_cursor_shape_v1_name(last_cursor.shape));
  1668. else
  1669. wlr_cursor_set_surface(cursor, last_cursor.surface,
  1670. last_cursor.hotspot_x, last_cursor.hotspot_y);
  1671. }
  1672. int
  1673. hidecursor(void *data)
  1674. {
  1675. wlr_cursor_unset_image(cursor);
  1676. cursor_hidden = true;
  1677. return 1;
  1678. }
  1679. void
  1680. incnmaster(const Arg *arg)
  1681. {
  1682. if (!arg || !selmon)
  1683. return;
  1684. selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
  1685. arrange(selmon);
  1686. }
  1687. void
  1688. inputdevice(struct wl_listener *listener, void *data)
  1689. {
  1690. /* This event is raised by the backend when a new input device becomes
  1691. * available. */
  1692. struct wlr_input_device *device = data;
  1693. uint32_t caps;
  1694. switch (device->type) {
  1695. case WLR_INPUT_DEVICE_KEYBOARD:
  1696. createkeyboard(wlr_keyboard_from_input_device(device));
  1697. break;
  1698. case WLR_INPUT_DEVICE_POINTER:
  1699. createpointer(wlr_pointer_from_input_device(device));
  1700. break;
  1701. default:
  1702. /* TODO handle other input device types */
  1703. break;
  1704. }
  1705. /* We need to let the wlr_seat know what our capabilities are, which is
  1706. * communiciated to the client. In dwl we always have a cursor, even if
  1707. * there are no pointer devices, so we always include that capability. */
  1708. /* TODO do we actually require a cursor? */
  1709. caps = WL_SEAT_CAPABILITY_POINTER;
  1710. if (!wl_list_empty(&kb_group->wlr_group->devices))
  1711. caps |= WL_SEAT_CAPABILITY_KEYBOARD;
  1712. wlr_seat_set_capabilities(seat, caps);
  1713. }
  1714. void
  1715. kblayout(KeyboardGroup *kb)
  1716. {
  1717. FILE *f;
  1718. Client *c;
  1719. unsigned int idx = kb->wlr_group->keyboard.modifiers.group;
  1720. // If layout did not change, do nothing
  1721. if (kblayout_idx == idx)
  1722. return;
  1723. kblayout_idx = idx;
  1724. // Update client layout
  1725. if ((c = focustop(selmon)))
  1726. c->kblayout_idx = kblayout_idx;
  1727. // Save current layout to kblayout_file
  1728. if (*kblayout_file && (f = fopen(kblayout_file, "w"))) {
  1729. fputs(xkb_keymap_layout_get_name(kb->wlr_group->keyboard.keymap,
  1730. idx), f);
  1731. fclose(f);
  1732. }
  1733. // Run kblayout_cmd
  1734. if (kblayout_cmd[0] && fork() == 0) {
  1735. execvp(kblayout_cmd[0], (char *const *)kblayout_cmd);
  1736. die("dwl: execvp %s failed:", kblayout_cmd[0]);
  1737. }
  1738. }
  1739. int
  1740. keybinding(uint32_t mods, xkb_keysym_t sym)
  1741. {
  1742. /*
  1743. * Here we handle compositor keybindings. This is when the compositor is
  1744. * processing keys, rather than passing them on to the client for its own
  1745. * processing.
  1746. */
  1747. const Key *k;
  1748. for (k = keys; k < END(keys); k++) {
  1749. if (CLEANMASK(mods) == CLEANMASK(k->mod)
  1750. && sym == k->keysym && k->func) {
  1751. k->func(&k->arg);
  1752. return 1;
  1753. }
  1754. }
  1755. return 0;
  1756. }
  1757. void
  1758. keypress(struct wl_listener *listener, void *data)
  1759. {
  1760. int i;
  1761. /* This event is raised when a key is pressed or released. */
  1762. KeyboardGroup *group = wl_container_of(listener, group, key);
  1763. struct wlr_keyboard_key_event *event = data;
  1764. /* Translate libinput keycode -> xkbcommon */
  1765. uint32_t keycode = event->keycode + 8;
  1766. /* Get a list of keysyms based on the keymap for this keyboard */
  1767. const xkb_keysym_t *syms;
  1768. int nsyms = xkb_state_key_get_syms(
  1769. group->wlr_group->keyboard.xkb_state, keycode, &syms);
  1770. int handled = 0;
  1771. uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard);
  1772. wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
  1773. /* On _press_ if there is no active screen locker,
  1774. * attempt to process a compositor keybinding. */
  1775. if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
  1776. for (i = 0; i < nsyms; i++)
  1777. handled = keybinding(mods, syms[i]) || handled;
  1778. }
  1779. if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) {
  1780. group->mods = mods;
  1781. group->keysyms = syms;
  1782. group->nsyms = nsyms;
  1783. wl_event_source_timer_update(group->key_repeat_source,
  1784. group->wlr_group->keyboard.repeat_info.delay);
  1785. } else {
  1786. group->nsyms = 0;
  1787. wl_event_source_timer_update(group->key_repeat_source, 0);
  1788. }
  1789. if (handled)
  1790. return;
  1791. wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard);
  1792. /* Pass unhandled keycodes along to the client. */
  1793. wlr_seat_keyboard_notify_key(seat, event->time_msec,
  1794. event->keycode, event->state);
  1795. }
  1796. void
  1797. keypressmod(struct wl_listener *listener, void *data)
  1798. {
  1799. /* This event is raised when a modifier key, such as shift or alt, is
  1800. * pressed. We simply communicate this to the client. */
  1801. KeyboardGroup *group = wl_container_of(listener, group, modifiers);
  1802. wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard);
  1803. /* Send modifiers to the client. */
  1804. wlr_seat_keyboard_notify_modifiers(seat,
  1805. &group->wlr_group->keyboard.modifiers);
  1806. kblayout(group);
  1807. }
  1808. int
  1809. keyrepeat(void *data)
  1810. {
  1811. KeyboardGroup *group = data;
  1812. int i;
  1813. if (!group->nsyms || group->wlr_group->keyboard.repeat_info.rate <= 0)
  1814. return 0;
  1815. wl_event_source_timer_update(group->key_repeat_source,
  1816. 1000 / group->wlr_group->keyboard.repeat_info.rate);
  1817. for (i = 0; i < group->nsyms; i++)
  1818. keybinding(group->mods, group->keysyms[i]);
  1819. return 0;
  1820. }
  1821. void
  1822. killclient(const Arg *arg)
  1823. {
  1824. Client *sel = focustop(selmon);
  1825. if (sel)
  1826. client_send_close(sel);
  1827. }
  1828. void
  1829. locksession(struct wl_listener *listener, void *data)
  1830. {
  1831. struct wlr_session_lock_v1 *session_lock = data;
  1832. SessionLock *lock;
  1833. wlr_scene_node_set_enabled(&locked_bg->node, 1);
  1834. if (cur_lock) {
  1835. wlr_session_lock_v1_destroy(session_lock);
  1836. return;
  1837. }
  1838. lock = session_lock->data = ecalloc(1, sizeof(*lock));
  1839. focusclient(NULL, 0);
  1840. lock->scene = wlr_scene_tree_create(layers[LyrBlock]);
  1841. cur_lock = lock->lock = session_lock;
  1842. locked = 1;
  1843. LISTEN(&session_lock->events.new_surface, &lock->new_surface, createlocksurface);
  1844. LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock);
  1845. LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession);
  1846. wlr_session_lock_v1_send_locked(session_lock);
  1847. }
  1848. void
  1849. mapnotify(struct wl_listener *listener, void *data)
  1850. {
  1851. /* Called when the surface is mapped, or ready to display on-screen. */
  1852. Client *p = NULL;
  1853. Client *w, *c = wl_container_of(listener, c, map);
  1854. Monitor *m;
  1855. int i;
  1856. /* Create scene tree for this client and its border */
  1857. c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]);
  1858. wlr_scene_node_set_enabled(&c->scene->node, c->type != XDGShell);
  1859. c->scene_surface = c->type == XDGShell
  1860. ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg)
  1861. : wlr_scene_subsurface_tree_create(c->scene, client_surface(c));
  1862. c->scene->node.data = c->scene_surface->node.data = c;
  1863. client_get_geometry(c, &c->geom);
  1864. /* Handle unmanaged clients first so we can return prior create borders */
  1865. if (client_is_unmanaged(c)) {
  1866. /* Unmanaged clients always are floating */
  1867. wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]);
  1868. wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
  1869. if (client_wants_focus(c)) {
  1870. focusclient(c, 1);
  1871. exclusive_focus = c;
  1872. }
  1873. goto unset_fullscreen;
  1874. }
  1875. for (i = 0; i < 4; i++) {
  1876. c->border[i] = wlr_scene_rect_create(c->scene, 0, 0,
  1877. (float[])COLOR(colors[c->isurgent ? SchemeUrg : SchemeNorm][ColBorder]));
  1878. c->border[i]->node.data = c;
  1879. }
  1880. /* Initialize client geometry with room for border */
  1881. client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);
  1882. c->geom.width += 2 * c->bw;
  1883. c->geom.height += 2 * c->bw;
  1884. /* Insert this client into client lists. */
  1885. wl_list_insert(&clients, &c->link);
  1886. wl_list_insert(&fstack, &c->flink);
  1887. /* Set initial monitor, tags, floating status, and focus:
  1888. * we always consider floating, clients that have parent and thus
  1889. * we set the same tags and monitor than its parent, if not
  1890. * try to apply rules for them */
  1891. if ((p = client_get_parent(c))) {
  1892. c->isfloating = 1;
  1893. if (p->mon) {
  1894. c->geom.x = (p->mon->w.width - c->geom.width) / 2 + p->mon->m.x;
  1895. c->geom.y = (p->mon->w.height - c->geom.height) / 2 + p->mon->m.y;
  1896. }
  1897. setmon(c, p->mon, p->tags);
  1898. } else {
  1899. applyrules(c);
  1900. }
  1901. drawbars();
  1902. unset_fullscreen:
  1903. m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y);
  1904. wl_list_for_each(w, &clients, link) {
  1905. if (w != c && w != p && w->isfullscreen && m == w->mon && (w->tags & c->tags))
  1906. setfullscreen(w, 0);
  1907. }
  1908. }
  1909. void
  1910. maximizenotify(struct wl_listener *listener, void *data)
  1911. {
  1912. /* This event is raised when a client would like to maximize itself,
  1913. * typically because the user clicked on the maximize button on
  1914. * client-side decorations. dwl doesn't support maximization, but
  1915. * to conform to xdg-shell protocol we still must send a configure.
  1916. * Since xdg-shell protocol v5 we should ignore request of unsupported
  1917. * capabilities, just schedule a empty configure when the client uses <5
  1918. * protocol version
  1919. * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */
  1920. Client *c = wl_container_of(listener, c, maximize);
  1921. if (c->surface.xdg->initialized
  1922. && wl_resource_get_version(c->surface.xdg->toplevel->resource)
  1923. < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION)
  1924. wlr_xdg_surface_schedule_configure(c->surface.xdg);
  1925. }
  1926. void
  1927. monocle(Monitor *m)
  1928. {
  1929. Client *c;
  1930. int n = 0;
  1931. wl_list_for_each(c, &clients, link) {
  1932. if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
  1933. continue;
  1934. resize(c, m->w, 0);
  1935. n++;
  1936. }
  1937. if (n)
  1938. snprintf(m->ltsymbol, LENGTH(m->ltsymbol), "[%d]", n);
  1939. if ((c = focustop(m)))
  1940. wlr_scene_node_raise_to_top(&c->scene->node);
  1941. }
  1942. void
  1943. movestack(const Arg *arg)
  1944. {
  1945. Client *c, *sel = focustop(selmon);
  1946. if (!sel) {
  1947. return;
  1948. }
  1949. if (wl_list_length(&clients) <= 1) {
  1950. return;
  1951. }
  1952. if (arg->i > 0) {
  1953. wl_list_for_each(c, &sel->link, link) {
  1954. if (VISIBLEON(c, selmon) || &c->link == &clients) {
  1955. break; /* found it */
  1956. }
  1957. }
  1958. } else {
  1959. wl_list_for_each_reverse(c, &sel->link, link) {
  1960. if (VISIBLEON(c, selmon) || &c->link == &clients) {
  1961. break; /* found it */
  1962. }
  1963. }
  1964. /* backup one client */
  1965. c = wl_container_of(c->link.prev, c, link);
  1966. }
  1967. wl_list_remove(&sel->link);
  1968. wl_list_insert(&c->link, &sel->link);
  1969. arrange(selmon);
  1970. }
  1971. void
  1972. motionabsolute(struct wl_listener *listener, void *data)
  1973. {
  1974. /* This event is forwarded by the cursor when a pointer emits an _absolute_
  1975. * motion event, from 0..1 on each axis. This happens, for example, when
  1976. * wlroots is running under a Wayland window rather than KMS+DRM, and you
  1977. * move the mouse over the window. You could enter the window from any edge,
  1978. * so we have to warp the mouse there. There is also some hardware which
  1979. * emits these events. */
  1980. struct wlr_pointer_motion_absolute_event *event = data;
  1981. double lx, ly, dx, dy;
  1982. if (!event->time_msec) /* this is 0 with virtual pointers */
  1983. wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y);
  1984. wlr_cursor_absolute_to_layout_coords(cursor, &event->pointer->base, event->x, event->y, &lx, &ly);
  1985. dx = lx - cursor->x;
  1986. dy = ly - cursor->y;
  1987. motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy);
  1988. }
  1989. void
  1990. motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
  1991. double dx_unaccel, double dy_unaccel)
  1992. {
  1993. double sx = 0, sy = 0, sx_confined, sy_confined;
  1994. Client *c = NULL, *w = NULL;
  1995. LayerSurface *l = NULL;
  1996. struct wlr_surface *surface = NULL;
  1997. struct wlr_pointer_constraint_v1 *constraint;
  1998. /* Find the client under the pointer and send the event along. */
  1999. xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy);
  2000. if (cursor_mode == CurPressed && !seat->drag
  2001. && surface != seat->pointer_state.focused_surface
  2002. && toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, &l) >= 0) {
  2003. c = w;
  2004. surface = seat->pointer_state.focused_surface;
  2005. sx = cursor->x - (l ? l->geom.x : w->geom.x);
  2006. sy = cursor->y - (l ? l->geom.y : w->geom.y);
  2007. }
  2008. /* time is 0 in internal calls meant to restore pointer focus. */
  2009. if (time) {
  2010. wlr_relative_pointer_manager_v1_send_relative_motion(
  2011. relative_pointer_mgr, seat, (uint64_t)time * 1000,
  2012. dx, dy, dx_unaccel, dy_unaccel);
  2013. wl_list_for_each(constraint, &pointer_constraints->constraints, link)
  2014. cursorconstrain(constraint);
  2015. if (active_constraint && cursor_mode != CurResize && cursor_mode != CurMove) {
  2016. toplevel_from_wlr_surface(active_constraint->surface, &c, NULL);
  2017. if (c && active_constraint->surface == seat->pointer_state.focused_surface) {
  2018. sx = cursor->x - c->geom.x - c->bw;
  2019. sy = cursor->y - c->geom.y - c->bw;
  2020. if (wlr_region_confine(&active_constraint->region, sx, sy,
  2021. sx + dx, sy + dy, &sx_confined, &sy_confined)) {
  2022. dx = sx_confined - sx;
  2023. dy = sy_confined - sy;
  2024. }
  2025. if (active_constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED)
  2026. return;
  2027. }
  2028. }
  2029. wlr_cursor_move(cursor, device, dx, dy);
  2030. wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
  2031. handlecursoractivity();
  2032. /* Update selmon (even while dragging a window) */
  2033. if (sloppyfocus)
  2034. selmon = xytomon(cursor->x, cursor->y);
  2035. }
  2036. /* Update drag icon's position */
  2037. wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y));
  2038. /* If we are currently grabbing the mouse, handle and return */
  2039. if (cursor_mode == CurMove) {
  2040. /* Move the grabbed client to the new position. */
  2041. resize(grabc, (struct wlr_box){.x = (int)round(cursor->x) - grabcx, .y = (int)round(cursor->y) - grabcy,
  2042. .width = grabc->geom.width, .height = grabc->geom.height}, 1);
  2043. return;
  2044. } else if (cursor_mode == CurResize) {
  2045. resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
  2046. .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1);
  2047. return;
  2048. }
  2049. /* If there's no client surface under the cursor, set the cursor image to a
  2050. * default. This is what makes the cursor image appear when you move it
  2051. * off of a client or over its border. */
  2052. if (!surface && !seat->drag && !cursor_hidden)
  2053. wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
  2054. pointerfocus(c, surface, sx, sy, time);
  2055. }
  2056. void
  2057. motionrelative(struct wl_listener *listener, void *data)
  2058. {
  2059. /* This event is forwarded by the cursor when a pointer emits a _relative_
  2060. * pointer motion event (i.e. a delta) */
  2061. struct wlr_pointer_motion_event *event = data;
  2062. /* The cursor doesn't move unless we tell it to. The cursor automatically
  2063. * handles constraining the motion to the output layout, as well as any
  2064. * special configuration applied for the specific input device which
  2065. * generated the event. You can pass NULL for the device if you want to move
  2066. * the cursor around without any input. */
  2067. motionnotify(event->time_msec, &event->pointer->base, event->delta_x, event->delta_y,
  2068. event->unaccel_dx, event->unaccel_dy);
  2069. }
  2070. void
  2071. moveresize(const Arg *arg)
  2072. {
  2073. if (cursor_mode != CurNormal && cursor_mode != CurPressed)
  2074. return;
  2075. xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL);
  2076. if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
  2077. return;
  2078. /* Float the window and tell motionnotify to grab it */
  2079. setfloating(grabc, 1);
  2080. switch (cursor_mode = arg->ui) {
  2081. case CurMove:
  2082. grabcx = (int)round(cursor->x) - grabc->geom.x;
  2083. grabcy = (int)round(cursor->y) - grabc->geom.y;
  2084. wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
  2085. break;
  2086. case CurResize:
  2087. /* Doesn't work for X11 output - the next absolute motion event
  2088. * returns the cursor to where it started */
  2089. wlr_cursor_warp_closest(cursor, NULL,
  2090. grabc->geom.x + grabc->geom.width,
  2091. grabc->geom.y + grabc->geom.height);
  2092. wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
  2093. break;
  2094. }
  2095. }
  2096. unsigned int
  2097. nextocctag(int direction)
  2098. {
  2099. unsigned int seltag = selmon->tagset[selmon->seltags];
  2100. unsigned int occ = 0, i;
  2101. Client *c;
  2102. wl_list_for_each(c, &clients, link)
  2103. occ |= c->tags;
  2104. for (i=0; i<TAGCOUNT; i++) {
  2105. seltag = (direction > 0) ?
  2106. (seltag == (1u << (TAGCOUNT - 1)) ? 1u : seltag << 1) :
  2107. (seltag == 1 ? (1u << (TAGCOUNT - 1)) : seltag >> 1);
  2108. if (seltag & occ)
  2109. break;
  2110. }
  2111. return seltag & TAGMASK;
  2112. }
  2113. void
  2114. outputmgrapply(struct wl_listener *listener, void *data)
  2115. {
  2116. struct wlr_output_configuration_v1 *config = data;
  2117. outputmgrapplyortest(config, 0);
  2118. }
  2119. void
  2120. outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test)
  2121. {
  2122. /*
  2123. * Called when a client such as wlr-randr requests a change in output
  2124. * configuration. This is only one way that the layout can be changed,
  2125. * so any Monitor information should be updated by updatemons() after an
  2126. * output_layout.change event, not here.
  2127. */
  2128. struct wlr_output_configuration_head_v1 *config_head;
  2129. int ok = 1;
  2130. wl_list_for_each(config_head, &config->heads, link) {
  2131. struct wlr_output *wlr_output = config_head->state.output;
  2132. Monitor *m = wlr_output->data;
  2133. struct wlr_output_state state;
  2134. /* Ensure displays previously disabled by wlr-output-power-management-v1
  2135. * are properly handled*/
  2136. m->asleep = 0;
  2137. wlr_output_state_init(&state);
  2138. wlr_output_state_set_enabled(&state, config_head->state.enabled);
  2139. if (!config_head->state.enabled)
  2140. goto apply_or_test;
  2141. if (config_head->state.mode)
  2142. wlr_output_state_set_mode(&state, config_head->state.mode);
  2143. else
  2144. wlr_output_state_set_custom_mode(&state,
  2145. config_head->state.custom_mode.width,
  2146. config_head->state.custom_mode.height,
  2147. config_head->state.custom_mode.refresh);
  2148. wlr_output_state_set_transform(&state, config_head->state.transform);
  2149. wlr_output_state_set_scale(&state, config_head->state.scale);
  2150. wlr_output_state_set_adaptive_sync_enabled(&state,
  2151. config_head->state.adaptive_sync_enabled);
  2152. apply_or_test:
  2153. ok &= test ? wlr_output_test_state(wlr_output, &state)
  2154. : wlr_output_commit_state(wlr_output, &state);
  2155. /* Don't move monitors if position wouldn't change, this to avoid
  2156. * wlroots marking the output as manually configured.
  2157. * wlr_output_layout_add does not like disabled outputs */
  2158. if (!test && wlr_output->enabled && (m->m.x != config_head->state.x || m->m.y != config_head->state.y))
  2159. wlr_output_layout_add(output_layout, wlr_output,
  2160. config_head->state.x, config_head->state.y);
  2161. wlr_output_state_finish(&state);
  2162. }
  2163. if (ok)
  2164. wlr_output_configuration_v1_send_succeeded(config);
  2165. else
  2166. wlr_output_configuration_v1_send_failed(config);
  2167. wlr_output_configuration_v1_destroy(config);
  2168. /* https://codeberg.org/dwl/dwl/issues/577 */
  2169. updatemons(NULL, NULL);
  2170. }
  2171. void
  2172. outputmgrtest(struct wl_listener *listener, void *data)
  2173. {
  2174. struct wlr_output_configuration_v1 *config = data;
  2175. outputmgrapplyortest(config, 1);
  2176. }
  2177. void
  2178. pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
  2179. uint32_t time)
  2180. {
  2181. struct timespec now;
  2182. if (surface != seat->pointer_state.focused_surface &&
  2183. sloppyfocus && time && c && !client_is_unmanaged(c))
  2184. focusclient(c, 0);
  2185. /* If surface is NULL, clear pointer focus */
  2186. if (!surface) {
  2187. wlr_seat_pointer_notify_clear_focus(seat);
  2188. return;
  2189. }
  2190. if (!time) {
  2191. clock_gettime(CLOCK_MONOTONIC, &now);
  2192. time = now.tv_sec * 1000 + now.tv_nsec / 1000000;
  2193. }
  2194. /* Let the client know that the mouse cursor has entered one
  2195. * of its surfaces, and make keyboard focus follow if desired.
  2196. * wlroots makes this a no-op if surface is already focused */
  2197. wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
  2198. wlr_seat_pointer_notify_motion(seat, time, sx, sy);
  2199. }
  2200. void
  2201. powermgrsetmode(struct wl_listener *listener, void *data)
  2202. {
  2203. struct wlr_output_power_v1_set_mode_event *event = data;
  2204. struct wlr_output_state state = {0};
  2205. Monitor *m = event->output->data;
  2206. if (!m)
  2207. return;
  2208. m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the ouput */
  2209. wlr_output_state_set_enabled(&state, event->mode);
  2210. wlr_output_commit_state(m->wlr_output, &state);
  2211. m->asleep = !event->mode;
  2212. }
  2213. void
  2214. quit(const Arg *arg)
  2215. {
  2216. wl_display_terminate(dpy);
  2217. }
  2218. void
  2219. rendermon(struct wl_listener *listener, void *data)
  2220. {
  2221. /* This function is called every time an output is ready to display a frame,
  2222. * generally at the output's refresh rate (e.g. 60Hz). */
  2223. Monitor *m = wl_container_of(listener, m, frame);
  2224. Client *c;
  2225. struct wlr_output_state pending = {0};
  2226. struct wlr_gamma_control_v1 *gamma_control;
  2227. struct timespec now;
  2228. /* Render if no XDG clients have an outstanding resize and are visible on
  2229. * this monitor. */
  2230. wl_list_for_each(c, &clients, link) {
  2231. if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c))
  2232. goto skip;
  2233. }
  2234. /*
  2235. * HACK: The "correct" way to set the gamma is to commit it together with
  2236. * the rest of the state in one go, but to do that we would need to rewrite
  2237. * wlr_scene_output_commit() in order to add the gamma to the pending
  2238. * state before committing, instead try to commit the gamma in one frame,
  2239. * and commit the rest of the state in the next one (or in the same frame if
  2240. * the gamma can not be committed).
  2241. */
  2242. if (m->gamma_lut_changed) {
  2243. gamma_control
  2244. = wlr_gamma_control_manager_v1_get_control(gamma_control_mgr, m->wlr_output);
  2245. m->gamma_lut_changed = 0;
  2246. if (!wlr_gamma_control_v1_apply(gamma_control, &pending))
  2247. goto commit;
  2248. if (!wlr_output_test_state(m->wlr_output, &pending)) {
  2249. wlr_gamma_control_v1_send_failed_and_destroy(gamma_control);
  2250. goto commit;
  2251. }
  2252. wlr_output_commit_state(m->wlr_output, &pending);
  2253. wlr_output_schedule_frame(m->wlr_output);
  2254. } else {
  2255. commit:
  2256. wlr_scene_output_commit(m->scene_output, NULL);
  2257. }
  2258. skip:
  2259. /* Let clients know a frame has been rendered */
  2260. clock_gettime(CLOCK_MONOTONIC, &now);
  2261. wlr_scene_output_send_frame_done(m->scene_output, &now);
  2262. wlr_output_state_finish(&pending);
  2263. }
  2264. void
  2265. requestdecorationmode(struct wl_listener *listener, void *data)
  2266. {
  2267. Client *c = wl_container_of(listener, c, set_decoration_mode);
  2268. if (c->surface.xdg->initialized)
  2269. wlr_xdg_toplevel_decoration_v1_set_mode(c->decoration,
  2270. WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
  2271. }
  2272. void
  2273. requeststartdrag(struct wl_listener *listener, void *data)
  2274. {
  2275. struct wlr_seat_request_start_drag_event *event = data;
  2276. if (wlr_seat_validate_pointer_grab_serial(seat, event->origin,
  2277. event->serial))
  2278. wlr_seat_start_pointer_drag(seat, event->drag, event->serial);
  2279. else
  2280. wlr_data_source_destroy(event->drag->source);
  2281. }
  2282. void
  2283. requestmonstate(struct wl_listener *listener, void *data)
  2284. {
  2285. struct wlr_output_event_request_state *event = data;
  2286. wlr_output_commit_state(event->output, event->state);
  2287. updatemons(NULL, NULL);
  2288. }
  2289. void
  2290. resize(Client *c, struct wlr_box geo, int interact)
  2291. {
  2292. struct wlr_box *bbox;
  2293. struct wlr_box clip;
  2294. if (!c->mon || !client_surface(c)->mapped)
  2295. return;
  2296. bbox = interact ? &sgeom : &c->mon->w;
  2297. client_set_bounds(c, geo.width, geo.height);
  2298. c->geom = geo;
  2299. applybounds(c, bbox);
  2300. /* Update scene-graph, including borders */
  2301. wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
  2302. wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
  2303. wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw);
  2304. wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw);
  2305. wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw);
  2306. wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw);
  2307. wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw);
  2308. wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw);
  2309. wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);
  2310. /* this is a no-op if size hasn't changed */
  2311. c->resize = client_set_size(c, c->geom.width - 2 * c->bw,
  2312. c->geom.height - 2 * c->bw);
  2313. client_get_clip(c, &clip);
  2314. wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
  2315. }
  2316. void
  2317. run(char *startup_cmd)
  2318. {
  2319. /* Add a Unix socket to the Wayland display. */
  2320. const char *socket = wl_display_add_socket_auto(dpy);
  2321. if (!socket)
  2322. die("startup: display_add_socket_auto");
  2323. setenv("WAYLAND_DISPLAY", socket, 1);
  2324. /* Start the backend. This will enumerate outputs and inputs, become the DRM
  2325. * master, etc */
  2326. if (!wlr_backend_start(backend))
  2327. die("startup: backend_start");
  2328. /* Now that the socket exists and the backend is started, run the startup command */
  2329. autostartexec();
  2330. if (startup_cmd) {
  2331. if ((child_pid = fork()) < 0)
  2332. die("startup: fork:");
  2333. if (child_pid == 0) {
  2334. close(STDIN_FILENO);
  2335. setsid();
  2336. execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL);
  2337. die("startup: execl:");
  2338. }
  2339. }
  2340. drawbars();
  2341. /* At this point the outputs are initialized, choose initial selmon based on
  2342. * cursor position, and set default cursor image */
  2343. selmon = xytomon(cursor->x, cursor->y);
  2344. /* TODO hack to get cursor to display in its initial location (100, 100)
  2345. * instead of (0, 0) and then jumping. still may not be fully
  2346. * initialized, as the image/coordinates are not transformed for the
  2347. * monitor when displayed here */
  2348. wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y);
  2349. wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
  2350. handlecursoractivity();
  2351. /* Run the Wayland event loop. This does not return until you exit the
  2352. * compositor. Starting the backend rigged up all of the necessary event
  2353. * loop configuration to listen to libinput events, DRM events, generate
  2354. * frame events at the refresh rate, and so on. */
  2355. wl_display_run(dpy);
  2356. }
  2357. void
  2358. setcursor(struct wl_listener *listener, void *data)
  2359. {
  2360. /* This event is raised by the seat when a client provides a cursor image */
  2361. struct wlr_seat_pointer_request_set_cursor_event *event = data;
  2362. /* If we're "grabbing" the cursor, don't use the client's image, we will
  2363. * restore it after "grabbing" sending a leave event, followed by a enter
  2364. * event, which will result in the client requesting set the cursor surface */
  2365. if (cursor_mode != CurNormal && cursor_mode != CurPressed)
  2366. return;
  2367. /* This can be sent by any client, so we check to make sure this one is
  2368. * actually has pointer focus first. If so, we can tell the cursor to
  2369. * use the provided surface as the cursor image. It will set the
  2370. * hardware cursor on the output that it's currently on and continue to
  2371. * do so as the cursor moves between outputs. */
  2372. if (event->seat_client == seat->pointer_state.focused_client) {
  2373. last_cursor.shape = 0;
  2374. last_cursor.surface = event->surface;
  2375. last_cursor.hotspot_x = event->hotspot_x;
  2376. last_cursor.hotspot_y = event->hotspot_y;
  2377. if (!cursor_hidden)
  2378. wlr_cursor_set_surface(cursor, event->surface,
  2379. event->hotspot_x, event->hotspot_y);
  2380. }
  2381. }
  2382. void
  2383. setcursorshape(struct wl_listener *listener, void *data)
  2384. {
  2385. struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data;
  2386. if (cursor_mode != CurNormal && cursor_mode != CurPressed)
  2387. return;
  2388. /* This can be sent by any client, so we check to make sure this one is
  2389. * actually has pointer focus first. If so, we can tell the cursor to
  2390. * use the provided cursor shape. */
  2391. if (event->seat_client == seat->pointer_state.focused_client) {
  2392. last_cursor.shape = event->shape;
  2393. last_cursor.surface = NULL;
  2394. if (!cursor_hidden)
  2395. wlr_cursor_set_xcursor(cursor, cursor_mgr,
  2396. wlr_cursor_shape_v1_name(event->shape));
  2397. }
  2398. }
  2399. void
  2400. setfloating(Client *c, int floating)
  2401. {
  2402. Client *p = client_get_parent(c);
  2403. c->isfloating = floating;
  2404. /* If in floating layout do not change the client's layer */
  2405. if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange)
  2406. return;
  2407. wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
  2408. (p && p->isfullscreen) ? LyrFS
  2409. : c->isfloating ? LyrFloat : LyrTile]);
  2410. arrange(c->mon);
  2411. drawbars();
  2412. }
  2413. void
  2414. setfullscreen(Client *c, int fullscreen)
  2415. {
  2416. c->isfullscreen = fullscreen;
  2417. if (!c->mon || !client_surface(c)->mapped)
  2418. return;
  2419. c->bw = fullscreen ? 0 : borderpx;
  2420. client_set_fullscreen(c, fullscreen);
  2421. wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen
  2422. ? LyrFS : c->isfloating ? LyrFloat : LyrTile]);
  2423. if (fullscreen) {
  2424. c->prev = c->geom;
  2425. resize(c, c->mon->m, 0);
  2426. } else {
  2427. /* restore previous size instead of arrange for floating windows since
  2428. * client positions are set by the user and cannot be recalculated */
  2429. resize(c, c->prev, 0);
  2430. }
  2431. arrange(c->mon);
  2432. drawbars();
  2433. }
  2434. void
  2435. setgamma(struct wl_listener *listener, void *data)
  2436. {
  2437. struct wlr_gamma_control_manager_v1_set_gamma_event *event = data;
  2438. Monitor *m = event->output->data;
  2439. if (!m)
  2440. return;
  2441. m->gamma_lut_changed = 1;
  2442. wlr_output_schedule_frame(m->wlr_output);
  2443. }
  2444. void
  2445. setsticky(Client *c, int sticky)
  2446. {
  2447. if(sticky && !c->issticky) {
  2448. c->issticky = 1;
  2449. } else if(!sticky && c->issticky) {
  2450. c->issticky = 0;
  2451. arrange(c->mon);
  2452. }
  2453. }
  2454. void
  2455. setlayout(const Arg *arg)
  2456. {
  2457. if (!selmon)
  2458. return;
  2459. if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
  2460. selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
  2461. if (arg && arg->v)
  2462. selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
  2463. strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, LENGTH(selmon->ltsymbol));
  2464. arrange(selmon);
  2465. drawbar(selmon);
  2466. }
  2467. /* arg > 1.0 will set mfact absolutely */
  2468. void
  2469. setmfact(const Arg *arg)
  2470. {
  2471. float f;
  2472. if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange)
  2473. return;
  2474. f = arg->f < 1.0f ? arg->f + selmon->mfact : arg->f - 1.0f;
  2475. if (f < 0.1 || f > 0.9)
  2476. return;
  2477. selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
  2478. arrange(selmon);
  2479. }
  2480. void
  2481. setmon(Client *c, Monitor *m, uint32_t newtags)
  2482. {
  2483. Monitor *oldmon = c->mon;
  2484. if (oldmon == m)
  2485. return;
  2486. c->mon = m;
  2487. c->prev = c->geom;
  2488. /* Scene graph sends surface leave/enter events on move and resize */
  2489. if (oldmon)
  2490. arrange(oldmon);
  2491. if (m) {
  2492. /* Make sure window actually overlaps with the monitor */
  2493. resize(c, c->geom, 0);
  2494. c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */
  2495. setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */
  2496. setfloating(c, c->isfloating);
  2497. }
  2498. focusclient(focustop(selmon), 1);
  2499. }
  2500. void
  2501. setpsel(struct wl_listener *listener, void *data)
  2502. {
  2503. /* This event is raised by the seat when a client wants to set the selection,
  2504. * usually when the user copies something. wlroots allows compositors to
  2505. * ignore such requests if they so choose, but in dwl we always honor
  2506. */
  2507. struct wlr_seat_request_set_primary_selection_event *event = data;
  2508. wlr_seat_set_primary_selection(seat, event->source, event->serial);
  2509. }
  2510. void
  2511. setsel(struct wl_listener *listener, void *data)
  2512. {
  2513. /* This event is raised by the seat when a client wants to set the selection,
  2514. * usually when the user copies something. wlroots allows compositors to
  2515. * ignore such requests if they so choose, but in dwl we always honor
  2516. */
  2517. struct wlr_seat_request_set_selection_event *event = data;
  2518. wlr_seat_set_selection(seat, event->source, event->serial);
  2519. }
  2520. void
  2521. setup(void)
  2522. {
  2523. int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
  2524. struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
  2525. sigemptyset(&sa.sa_mask);
  2526. for (i = 0; i < (int)LENGTH(sig); i++)
  2527. sigaction(sig[i], &sa, NULL);
  2528. wlr_log_init(log_level, NULL);
  2529. /* The Wayland display is managed by libwayland. It handles accepting
  2530. * clients from the Unix socket, manging Wayland globals, and so on. */
  2531. dpy = wl_display_create();
  2532. event_loop = wl_display_get_event_loop(dpy);
  2533. /* The backend is a wlroots feature which abstracts the underlying input and
  2534. * output hardware. The autocreate option will choose the most suitable
  2535. * backend based on the current environment, such as opening an X11 window
  2536. * if an X11 server is running. */
  2537. if (!(backend = wlr_backend_autocreate(event_loop, &session)))
  2538. die("couldn't create backend");
  2539. /* Initialize the scene graph used to lay out windows */
  2540. scene = wlr_scene_create();
  2541. root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, rootcolor);
  2542. for (i = 0; i < NUM_LAYERS; i++)
  2543. layers[i] = wlr_scene_tree_create(&scene->tree);
  2544. drag_icon = wlr_scene_tree_create(&scene->tree);
  2545. wlr_scene_node_place_below(&drag_icon->node, &layers[LyrBlock]->node);
  2546. /* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user
  2547. * can also specify a renderer using the WLR_RENDERER env var.
  2548. * The renderer is responsible for defining the various pixel formats it
  2549. * supports for shared memory, this configures that for clients. */
  2550. if (!(drw = wlr_renderer_autocreate(backend)))
  2551. die("couldn't create renderer");
  2552. LISTEN_STATIC(&drw->events.lost, gpureset);
  2553. /* Create shm, drm and linux_dmabuf interfaces by ourselves.
  2554. * The simplest way is call:
  2555. * wlr_renderer_init_wl_display(drw);
  2556. * but we need to create manually the linux_dmabuf interface to integrate it
  2557. * with wlr_scene. */
  2558. wlr_renderer_init_wl_shm(drw, dpy);
  2559. if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) {
  2560. wlr_drm_create(dpy, drw);
  2561. wlr_scene_set_linux_dmabuf_v1(scene,
  2562. wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw));
  2563. }
  2564. /* Autocreates an allocator for us.
  2565. * The allocator is the bridge between the renderer and the backend. It
  2566. * handles the buffer creation, allowing wlroots to render onto the
  2567. * screen */
  2568. if (!(alloc = wlr_allocator_autocreate(backend, drw)))
  2569. die("couldn't create allocator");
  2570. /* This creates some hands-off wlroots interfaces. The compositor is
  2571. * necessary for clients to allocate surfaces and the data device manager
  2572. * handles the clipboard. Each of these wlroots interfaces has room for you
  2573. * to dig your fingers in and play with their behavior if you want. Note that
  2574. * the clients cannot set the selection directly without compositor approval,
  2575. * see the setsel() function. */
  2576. compositor = wlr_compositor_create(dpy, 6, drw);
  2577. wlr_subcompositor_create(dpy);
  2578. wlr_data_device_manager_create(dpy);
  2579. wlr_export_dmabuf_manager_v1_create(dpy);
  2580. wlr_screencopy_manager_v1_create(dpy);
  2581. wlr_data_control_manager_v1_create(dpy);
  2582. wlr_primary_selection_v1_device_manager_create(dpy);
  2583. wlr_viewporter_create(dpy);
  2584. wlr_single_pixel_buffer_manager_v1_create(dpy);
  2585. wlr_fractional_scale_manager_v1_create(dpy, 1);
  2586. wlr_presentation_create(dpy, backend);
  2587. wlr_alpha_modifier_v1_create(dpy);
  2588. /* Initializes the interface used to implement urgency hints */
  2589. activation = wlr_xdg_activation_v1_create(dpy);
  2590. LISTEN_STATIC(&activation->events.request_activate, urgent);
  2591. gamma_control_mgr = wlr_gamma_control_manager_v1_create(dpy);
  2592. LISTEN_STATIC(&gamma_control_mgr->events.set_gamma, setgamma);
  2593. power_mgr = wlr_output_power_manager_v1_create(dpy);
  2594. LISTEN_STATIC(&power_mgr->events.set_mode, powermgrsetmode);
  2595. /* Creates an output layout, which a wlroots utility for working with an
  2596. * arrangement of screens in a physical layout. */
  2597. output_layout = wlr_output_layout_create(dpy);
  2598. LISTEN_STATIC(&output_layout->events.change, updatemons);
  2599. wlr_xdg_output_manager_v1_create(dpy, output_layout);
  2600. /* Configure a listener to be notified when new outputs are available on the
  2601. * backend. */
  2602. wl_list_init(&mons);
  2603. LISTEN_STATIC(&backend->events.new_output, createmon);
  2604. /* Set up our client lists, the xdg-shell and the layer-shell. The xdg-shell is a
  2605. * Wayland protocol which is used for application windows. For more
  2606. * detail on shells, refer to the article:
  2607. *
  2608. * https://drewdevault.com/2018/07/29/Wayland-shells.html
  2609. */
  2610. wl_list_init(&clients);
  2611. wl_list_init(&fstack);
  2612. xdg_shell = wlr_xdg_shell_create(dpy, 6);
  2613. LISTEN_STATIC(&xdg_shell->events.new_toplevel, createnotify);
  2614. LISTEN_STATIC(&xdg_shell->events.new_popup, createpopup);
  2615. layer_shell = wlr_layer_shell_v1_create(dpy, 3);
  2616. LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface);
  2617. idle_notifier = wlr_idle_notifier_v1_create(dpy);
  2618. idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy);
  2619. LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor);
  2620. session_lock_mgr = wlr_session_lock_manager_v1_create(dpy);
  2621. wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener);
  2622. LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr);
  2623. locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height,
  2624. (float [4]){0.1f, 0.1f, 0.1f, 1.0f});
  2625. wlr_scene_node_set_enabled(&locked_bg->node, 0);
  2626. /* Use decoration protocols to negotiate server-side decorations */
  2627. wlr_server_decoration_manager_set_default_mode(
  2628. wlr_server_decoration_manager_create(dpy),
  2629. WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
  2630. xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy);
  2631. LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration);
  2632. pointer_constraints = wlr_pointer_constraints_v1_create(dpy);
  2633. LISTEN_STATIC(&pointer_constraints->events.new_constraint, createpointerconstraint);
  2634. relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy);
  2635. /*
  2636. * Creates a cursor, which is a wlroots utility for tracking the cursor
  2637. * image shown on screen.
  2638. */
  2639. cursor = wlr_cursor_create();
  2640. wlr_cursor_attach_output_layout(cursor, output_layout);
  2641. /* Creates an xcursor manager, another wlroots utility which loads up
  2642. * Xcursor themes to source cursor images from and makes sure that cursor
  2643. * images are available at all scale factors on the screen (necessary for
  2644. * HiDPI support). Scaled cursors will be loaded with each output. */
  2645. cursor_mgr = wlr_xcursor_manager_create(NULL, 24);
  2646. setenv("XCURSOR_SIZE", "24", 1);
  2647. /*
  2648. * wlr_cursor *only* displays an image on screen. It does not move around
  2649. * when the pointer moves. However, we can attach input devices to it, and
  2650. * it will generate aggregate events for all of them. In these events, we
  2651. * can choose how we want to process them, forwarding them to clients and
  2652. * moving the cursor around. More detail on this process is described in
  2653. * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html
  2654. *
  2655. * And more comments are sprinkled throughout the notify functions above.
  2656. */
  2657. LISTEN_STATIC(&cursor->events.motion, motionrelative);
  2658. LISTEN_STATIC(&cursor->events.motion_absolute, motionabsolute);
  2659. LISTEN_STATIC(&cursor->events.button, buttonpress);
  2660. LISTEN_STATIC(&cursor->events.axis, axisnotify);
  2661. LISTEN_STATIC(&cursor->events.frame, cursorframe);
  2662. cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1);
  2663. LISTEN_STATIC(&cursor_shape_mgr->events.request_set_shape, setcursorshape);
  2664. hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy),
  2665. hidecursor, cursor);
  2666. /*
  2667. * Configures a seat, which is a single "seat" at which a user sits and
  2668. * operates the computer. This conceptually includes up to one keyboard,
  2669. * pointer, touch, and drawing tablet device. We also rig up a listener to
  2670. * let us know when new input devices are available on the backend.
  2671. */
  2672. LISTEN_STATIC(&backend->events.new_input, inputdevice);
  2673. virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);
  2674. LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard);
  2675. virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy);
  2676. LISTEN_STATIC(&virtual_pointer_mgr->events.new_virtual_pointer, virtualpointer);
  2677. seat = wlr_seat_create(dpy, "seat0");
  2678. LISTEN_STATIC(&seat->events.request_set_cursor, setcursor);
  2679. LISTEN_STATIC(&seat->events.request_set_selection, setsel);
  2680. LISTEN_STATIC(&seat->events.request_set_primary_selection, setpsel);
  2681. LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag);
  2682. LISTEN_STATIC(&seat->events.start_drag, startdrag);
  2683. kb_group = createkeyboardgroup();
  2684. wl_list_init(&kb_group->destroy.link);
  2685. output_mgr = wlr_output_manager_v1_create(dpy);
  2686. LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply);
  2687. LISTEN_STATIC(&output_mgr->events.test, outputmgrtest);
  2688. drwl_init();
  2689. status_event_source = wl_event_loop_add_fd(wl_display_get_event_loop(dpy),
  2690. STDIN_FILENO, WL_EVENT_READABLE, statusin, NULL);
  2691. /* Make sure XWayland clients don't connect to the parent X server,
  2692. * e.g when running in the x11 backend or the wayland backend and the
  2693. * compositor has Xwayland support */
  2694. unsetenv("DISPLAY");
  2695. #ifdef XWAYLAND
  2696. /*
  2697. * Initialise the XWayland X server.
  2698. * It will be started when the first X client is started.
  2699. */
  2700. if ((xwayland = wlr_xwayland_create(dpy, compositor, 1))) {
  2701. LISTEN_STATIC(&xwayland->events.ready, xwaylandready);
  2702. LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11);
  2703. setenv("DISPLAY", xwayland->display_name, 1);
  2704. } else {
  2705. fprintf(stderr, "failed to setup XWayland X server, continuing without it\n");
  2706. }
  2707. #endif
  2708. }
  2709. void
  2710. spawn(const Arg *arg)
  2711. {
  2712. if (fork() == 0) {
  2713. close(STDIN_FILENO);
  2714. dup2(STDERR_FILENO, STDOUT_FILENO);
  2715. setsid();
  2716. execvp(((char **)arg->v)[0], (char **)arg->v);
  2717. die("dwl: execvp %s failed:", ((char **)arg->v)[0]);
  2718. }
  2719. }
  2720. void
  2721. startdrag(struct wl_listener *listener, void *data)
  2722. {
  2723. struct wlr_drag *drag = data;
  2724. if (!drag->icon)
  2725. return;
  2726. drag->icon->data = &wlr_scene_drag_icon_create(drag_icon, drag->icon)->node;
  2727. LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon);
  2728. }
  2729. int
  2730. statusin(int fd, unsigned int mask, void *data)
  2731. {
  2732. char status[1024];
  2733. ssize_t n;
  2734. if (mask & WL_EVENT_ERROR)
  2735. die("status in event error");
  2736. if (mask & WL_EVENT_HANGUP)
  2737. wl_event_source_remove(status_event_source);
  2738. n = read(fd, status, sizeof(status) - 1);
  2739. if (n < 0 && errno != EWOULDBLOCK)
  2740. die("read:");
  2741. status[n] = '\0';
  2742. status[strcspn(status, "\n")] = '\0';
  2743. strncpy(stext, status, sizeof(stext));
  2744. drawbars();
  2745. return 0;
  2746. }
  2747. void
  2748. tag(const Arg *arg)
  2749. {
  2750. Client *sel = focustop(selmon);
  2751. if (!sel || (arg->ui & TAGMASK) == 0)
  2752. return;
  2753. sel->tags = arg->ui & TAGMASK;
  2754. focusclient(focustop(selmon), 1);
  2755. arrange(selmon);
  2756. drawbars();
  2757. }
  2758. void
  2759. tagmon(const Arg *arg)
  2760. {
  2761. Client *sel = focustop(selmon);
  2762. if (sel)
  2763. setmon(sel, dirtomon(arg->i), 0);
  2764. }
  2765. void
  2766. tile(Monitor *m)
  2767. {
  2768. unsigned int mw, my, ty;
  2769. int i, n = 0;
  2770. Client *c;
  2771. wl_list_for_each(c, &clients, link)
  2772. if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
  2773. n++;
  2774. if (n == 0)
  2775. return;
  2776. if (n > m->nmaster)
  2777. mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0;
  2778. else
  2779. mw = m->w.width;
  2780. i = my = ty = 0;
  2781. wl_list_for_each(c, &clients, link) {
  2782. if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
  2783. continue;
  2784. if (i < m->nmaster) {
  2785. resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,
  2786. .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0);
  2787. my += c->geom.height;
  2788. } else {
  2789. resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,
  2790. .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0);
  2791. ty += c->geom.height;
  2792. }
  2793. i++;
  2794. }
  2795. }
  2796. void
  2797. togglebar(const Arg *arg)
  2798. {
  2799. wlr_scene_node_set_enabled(&selmon->scene_buffer->node,
  2800. !selmon->scene_buffer->node.enabled);
  2801. arrangelayers(selmon);
  2802. }
  2803. void
  2804. togglefloating(const Arg *arg)
  2805. {
  2806. Client *sel = focustop(selmon);
  2807. /* return if fullscreen */
  2808. if (sel && !sel->isfullscreen)
  2809. setfloating(sel, !sel->isfloating);
  2810. }
  2811. void
  2812. togglefullscreen(const Arg *arg)
  2813. {
  2814. Client *sel = focustop(selmon);
  2815. if (sel)
  2816. setfullscreen(sel, !sel->isfullscreen);
  2817. }
  2818. void
  2819. togglesticky(const Arg *arg)
  2820. {
  2821. Client *c = focustop(selmon);
  2822. if(!c)
  2823. return;
  2824. setsticky(c, !c->issticky);
  2825. }
  2826. void
  2827. toggletag(const Arg *arg)
  2828. {
  2829. uint32_t newtags;
  2830. Client *sel = focustop(selmon);
  2831. if (!sel || !(newtags = sel->tags ^ (arg->ui & TAGMASK)))
  2832. return;
  2833. sel->tags = newtags;
  2834. focusclient(focustop(selmon), 1);
  2835. arrange(selmon);
  2836. drawbars();
  2837. }
  2838. void
  2839. toggleview(const Arg *arg)
  2840. {
  2841. uint32_t newtagset;
  2842. size_t i;
  2843. if (!(newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0))
  2844. return;
  2845. if (newtagset == (uint32_t)~0) {
  2846. selmon->pertag->prevtag = selmon->pertag->curtag;
  2847. selmon->pertag->curtag = 0;
  2848. }
  2849. /* test if the user did not select the same tag */
  2850. if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
  2851. selmon->pertag->prevtag = selmon->pertag->curtag;
  2852. for (i = 0; !(newtagset & 1 << i); i++) ;
  2853. selmon->pertag->curtag = i + 1;
  2854. }
  2855. /* apply settings for this view */
  2856. selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
  2857. selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
  2858. selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
  2859. selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
  2860. selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
  2861. selmon->tagset[selmon->seltags] = newtagset;
  2862. focusclient(focustop(selmon), 1);
  2863. arrange(selmon);
  2864. drawbars();
  2865. }
  2866. void
  2867. unlocksession(struct wl_listener *listener, void *data)
  2868. {
  2869. SessionLock *lock = wl_container_of(listener, lock, unlock);
  2870. destroylock(lock, 1);
  2871. }
  2872. void
  2873. unmaplayersurfacenotify(struct wl_listener *listener, void *data)
  2874. {
  2875. LayerSurface *l = wl_container_of(listener, l, unmap);
  2876. l->mapped = 0;
  2877. wlr_scene_node_set_enabled(&l->scene->node, 0);
  2878. if (l == exclusive_focus)
  2879. exclusive_focus = NULL;
  2880. if (l->layer_surface->output && (l->mon = l->layer_surface->output->data))
  2881. arrangelayers(l->mon);
  2882. if (l->layer_surface->surface == seat->keyboard_state.focused_surface)
  2883. focusclient(focustop(selmon), 1);
  2884. motionnotify(0, NULL, 0, 0, 0, 0);
  2885. }
  2886. void
  2887. unmapnotify(struct wl_listener *listener, void *data)
  2888. {
  2889. /* Called when the surface is unmapped, and should no longer be shown. */
  2890. Client *c = wl_container_of(listener, c, unmap);
  2891. if (c == grabc) {
  2892. cursor_mode = CurNormal;
  2893. grabc = NULL;
  2894. }
  2895. if (client_is_unmanaged(c)) {
  2896. if (c == exclusive_focus) {
  2897. exclusive_focus = NULL;
  2898. focusclient(focustop(selmon), 1);
  2899. }
  2900. } else {
  2901. wl_list_remove(&c->link);
  2902. setmon(c, NULL, 0);
  2903. wl_list_remove(&c->flink);
  2904. }
  2905. wlr_scene_node_destroy(&c->scene->node);
  2906. drawbars();
  2907. motionnotify(0, NULL, 0, 0, 0, 0);
  2908. }
  2909. void
  2910. updatemons(struct wl_listener *listener, void *data)
  2911. {
  2912. /*
  2913. * Called whenever the output layout changes: adding or removing a
  2914. * monitor, changing an output's mode or position, etc. This is where
  2915. * the change officially happens and we update geometry, window
  2916. * positions, focus, and the stored configuration in wlroots'
  2917. * output-manager implementation.
  2918. */
  2919. struct wlr_output_configuration_v1 *config
  2920. = wlr_output_configuration_v1_create();
  2921. Client *c;
  2922. struct wlr_output_configuration_head_v1 *config_head;
  2923. Monitor *m;
  2924. /* First remove from the layout the disabled monitors */
  2925. wl_list_for_each(m, &mons, link) {
  2926. if (m->wlr_output->enabled || m->asleep)
  2927. continue;
  2928. config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);
  2929. config_head->state.enabled = 0;
  2930. /* Remove this output from the layout to avoid cursor enter inside it */
  2931. wlr_output_layout_remove(output_layout, m->wlr_output);
  2932. closemon(m);
  2933. m->m = m->w = (struct wlr_box){0};
  2934. }
  2935. /* Insert outputs that need to */
  2936. wl_list_for_each(m, &mons, link) {
  2937. if (m->wlr_output->enabled
  2938. && !wlr_output_layout_get(output_layout, m->wlr_output))
  2939. wlr_output_layout_add_auto(output_layout, m->wlr_output);
  2940. }
  2941. /* Now that we update the output layout we can get its box */
  2942. wlr_output_layout_get_box(output_layout, NULL, &sgeom);
  2943. wlr_scene_node_set_position(&root_bg->node, sgeom.x, sgeom.y);
  2944. wlr_scene_rect_set_size(root_bg, sgeom.width, sgeom.height);
  2945. /* Make sure the clients are hidden when dwl is locked */
  2946. wlr_scene_node_set_position(&locked_bg->node, sgeom.x, sgeom.y);
  2947. wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height);
  2948. wl_list_for_each(m, &mons, link) {
  2949. if (!m->wlr_output->enabled)
  2950. continue;
  2951. config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);
  2952. /* Get the effective monitor geometry to use for surfaces */
  2953. wlr_output_layout_get_box(output_layout, m->wlr_output, &m->m);
  2954. m->w = m->m;
  2955. wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y);
  2956. wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y);
  2957. wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height);
  2958. if (m->lock_surface) {
  2959. struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data;
  2960. wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y);
  2961. wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, m->m.height);
  2962. }
  2963. /* Calculate the effective monitor geometry to use for clients */
  2964. arrangelayers(m);
  2965. /* Don't move clients to the left output when plugging monitors */
  2966. arrange(m);
  2967. /* make sure fullscreen clients have the right size */
  2968. if ((c = focustop(m)) && c->isfullscreen)
  2969. resize(c, m->m, 0);
  2970. /* Try to re-set the gamma LUT when updating monitors,
  2971. * it's only really needed when enabling a disabled output, but meh. */
  2972. m->gamma_lut_changed = 1;
  2973. config_head->state.x = m->m.x;
  2974. config_head->state.y = m->m.y;
  2975. if (!selmon) {
  2976. selmon = m;
  2977. }
  2978. }
  2979. if (selmon && selmon->wlr_output->enabled) {
  2980. wl_list_for_each(c, &clients, link) {
  2981. if (!c->mon && client_surface(c)->mapped)
  2982. setmon(c, selmon, c->tags);
  2983. }
  2984. focusclient(focustop(selmon), 1);
  2985. if (selmon->lock_surface) {
  2986. client_notify_enter(selmon->lock_surface->surface,
  2987. wlr_seat_get_keyboard(seat));
  2988. client_activate_surface(selmon->lock_surface->surface, 1);
  2989. }
  2990. }
  2991. if (stext[0] == '\0')
  2992. strncpy(stext, "dwl-"VERSION, sizeof(stext));
  2993. wl_list_for_each(m, &mons, link) {
  2994. updatebar(m);
  2995. drawbar(m);
  2996. }
  2997. /* FIXME: figure out why the cursor image is at 0,0 after turning all
  2998. * the monitors on.
  2999. * Move the cursor image where it used to be. It does not generate a
  3000. * wl_pointer.motion event for the clients, it's only the image what it's
  3001. * at the wrong position after all. */
  3002. wlr_cursor_move(cursor, NULL, 0, 0);
  3003. wlr_output_manager_v1_set_configuration(output_mgr, config);
  3004. }
  3005. void
  3006. updatebar(Monitor *m)
  3007. {
  3008. size_t i;
  3009. int rw, rh;
  3010. char fontattrs[12];
  3011. wlr_output_transformed_resolution(m->wlr_output, &rw, &rh);
  3012. m->b.width = rw;
  3013. m->b.real_width = (int)((float)m->b.width / m->wlr_output->scale);
  3014. wlr_scene_node_set_enabled(&m->scene_buffer->node, m->wlr_output->enabled ? showbar : 0);
  3015. for (i = 0; i < LENGTH(m->pool); i++)
  3016. if (m->pool[i]) {
  3017. wlr_buffer_drop(&m->pool[i]->base);
  3018. m->pool[i] = NULL;
  3019. }
  3020. if (m->b.scale == m->wlr_output->scale && m->drw)
  3021. return;
  3022. drwl_font_destroy(m->drw->font);
  3023. snprintf(fontattrs, sizeof(fontattrs), "dpi=%.2f", 96. * m->wlr_output->scale);
  3024. if (!(drwl_font_create(m->drw, LENGTH(fonts), fonts, fontattrs)))
  3025. die("Could not load font");
  3026. m->b.scale = m->wlr_output->scale;
  3027. m->lrpad = m->drw->font->height;
  3028. m->b.height = m->drw->font->height + 2;
  3029. m->b.real_height = (int)((float)m->b.height / m->wlr_output->scale);
  3030. }
  3031. void
  3032. updatetitle(struct wl_listener *listener, void *data)
  3033. {
  3034. Client *c = wl_container_of(listener, c, set_title);
  3035. if (c == focustop(c->mon))
  3036. drawbars();
  3037. }
  3038. void
  3039. urgent(struct wl_listener *listener, void *data)
  3040. {
  3041. struct wlr_xdg_activation_v1_request_activate_event *event = data;
  3042. Client *c = NULL;
  3043. toplevel_from_wlr_surface(event->surface, &c, NULL);
  3044. if (!c || c == focustop(selmon))
  3045. return;
  3046. c->isurgent = 1;
  3047. drawbars();
  3048. if (client_surface(c)->mapped)
  3049. client_set_border_color(c, (float[])COLOR(colors[SchemeUrg][ColBorder]));
  3050. }
  3051. void
  3052. view(const Arg *arg)
  3053. {
  3054. size_t i, tmptag;
  3055. if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
  3056. return;
  3057. selmon->seltags ^= 1; /* toggle sel tagset */
  3058. if (arg->ui & ~0) {
  3059. selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
  3060. selmon->pertag->prevtag = selmon->pertag->curtag;
  3061. if (arg->ui == TAGMASK)
  3062. selmon->pertag->curtag = 0;
  3063. else {
  3064. for (i = 0; !(arg->ui & 1 << i); i++) ;
  3065. selmon->pertag->curtag = i + 1;
  3066. }
  3067. } else {
  3068. tmptag = selmon->pertag->prevtag;
  3069. selmon->pertag->prevtag = selmon->pertag->curtag;
  3070. selmon->pertag->curtag = tmptag;
  3071. }
  3072. selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
  3073. selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
  3074. selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
  3075. selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
  3076. selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
  3077. focusclient(focustop(selmon), 1);
  3078. arrange(selmon);
  3079. drawbars();
  3080. }
  3081. void
  3082. viewnextocctag(const Arg *arg)
  3083. {
  3084. unsigned int tmp;
  3085. if ((tmp = nextocctag(arg->i)) == selmon->tagset[selmon->seltags])
  3086. return;
  3087. view(&(const Arg){.ui = tmp});
  3088. }
  3089. void
  3090. virtualkeyboard(struct wl_listener *listener, void *data)
  3091. {
  3092. struct wlr_virtual_keyboard_v1 *kb = data;
  3093. /* virtual keyboards shouldn't share keyboard group */
  3094. KeyboardGroup *group = createkeyboardgroup();
  3095. /* Set the keymap to match the group keymap */
  3096. wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap);
  3097. LISTEN(&kb->keyboard.base.events.destroy, &group->destroy, destroykeyboardgroup);
  3098. /* Add the new keyboard to the group */
  3099. wlr_keyboard_group_add_keyboard(group->wlr_group, &kb->keyboard);
  3100. }
  3101. void
  3102. virtualpointer(struct wl_listener *listener, void *data)
  3103. {
  3104. struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
  3105. struct wlr_input_device *device = &event->new_pointer->pointer.base;
  3106. wlr_cursor_attach_input_device(cursor, device);
  3107. if (event->suggested_output)
  3108. wlr_cursor_map_input_to_output(cursor, device, event->suggested_output);
  3109. handlecursoractivity();
  3110. }
  3111. Monitor *
  3112. xytomon(double x, double y)
  3113. {
  3114. struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y);
  3115. return o ? o->data : NULL;
  3116. }
  3117. void
  3118. xytonode(double x, double y, struct wlr_surface **psurface,
  3119. Client **pc, LayerSurface **pl, double *nx, double *ny)
  3120. {
  3121. struct wlr_scene_node *node, *pnode;
  3122. struct wlr_surface *surface = NULL;
  3123. struct wlr_scene_surface *scene_surface = NULL;
  3124. Client *c = NULL;
  3125. LayerSurface *l = NULL;
  3126. int layer;
  3127. for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) {
  3128. if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny)))
  3129. continue;
  3130. if (node->type == WLR_SCENE_NODE_BUFFER) {
  3131. scene_surface = wlr_scene_surface_try_from_buffer(
  3132. wlr_scene_buffer_from_node(node));
  3133. if (!scene_surface) continue;
  3134. surface = scene_surface->surface;
  3135. }
  3136. /* Walk the tree to find a node that knows the client */
  3137. for (pnode = node; pnode && !c; pnode = &pnode->parent->node)
  3138. c = pnode->data;
  3139. if (c && c->type == LayerShell) {
  3140. c = NULL;
  3141. l = pnode->data;
  3142. }
  3143. }
  3144. if (psurface) *psurface = surface;
  3145. if (pc) *pc = c;
  3146. if (pl) *pl = l;
  3147. }
  3148. void
  3149. zoom(const Arg *arg)
  3150. {
  3151. Client *c, *sel = focustop(selmon);
  3152. if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating)
  3153. return;
  3154. /* Search for the first tiled window that is not sel, marking sel as
  3155. * NULL if we pass it along the way */
  3156. wl_list_for_each(c, &clients, link) {
  3157. if (VISIBLEON(c, selmon) && !c->isfloating) {
  3158. if (c != sel)
  3159. break;
  3160. sel = NULL;
  3161. }
  3162. }
  3163. /* Return if no other tiled window was found */
  3164. if (&c->link == &clients)
  3165. return;
  3166. /* If we passed sel, move c to the front; otherwise, move sel to the
  3167. * front */
  3168. if (!sel)
  3169. sel = c;
  3170. wl_list_remove(&sel->link);
  3171. wl_list_insert(&clients, &sel->link);
  3172. focusclient(sel, 1);
  3173. arrange(selmon);
  3174. }
  3175. #ifdef XWAYLAND
  3176. void
  3177. activatex11(struct wl_listener *listener, void *data)
  3178. {
  3179. Client *c = wl_container_of(listener, c, activate);
  3180. /* Only "managed" windows can be activated */
  3181. if (!client_is_unmanaged(c))
  3182. wlr_xwayland_surface_activate(c->surface.xwayland, 1);
  3183. }
  3184. void
  3185. associatex11(struct wl_listener *listener, void *data)
  3186. {
  3187. Client *c = wl_container_of(listener, c, associate);
  3188. LISTEN(&client_surface(c)->events.map, &c->map, mapnotify);
  3189. LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify);
  3190. }
  3191. void
  3192. configurex11(struct wl_listener *listener, void *data)
  3193. {
  3194. Client *c = wl_container_of(listener, c, configure);
  3195. struct wlr_xwayland_surface_configure_event *event = data;
  3196. /* TODO: figure out if there is another way to do this */
  3197. if (!c->mon) {
  3198. wlr_xwayland_surface_configure(c->surface.xwayland,
  3199. event->x, event->y, event->width, event->height);
  3200. return;
  3201. }
  3202. if (c->isfloating || client_is_unmanaged(c))
  3203. resize(c, (struct wlr_box){.x = event->x, .y = event->y,
  3204. .width = event->width + c->bw * 2, .height = event->height + c->bw * 2}, 0);
  3205. else
  3206. arrange(c->mon);
  3207. }
  3208. void
  3209. createnotifyx11(struct wl_listener *listener, void *data)
  3210. {
  3211. struct wlr_xwayland_surface *xsurface = data;
  3212. Client *c;
  3213. /* Allocate a Client for this surface */
  3214. c = xsurface->data = ecalloc(1, sizeof(*c));
  3215. c->surface.xwayland = xsurface;
  3216. c->type = X11;
  3217. c->bw = client_is_unmanaged(c) ? 0 : borderpx;
  3218. /* Listen to the various events it can emit */
  3219. LISTEN(&xsurface->events.associate, &c->associate, associatex11);
  3220. LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify);
  3221. LISTEN(&xsurface->events.dissociate, &c->dissociate, dissociatex11);
  3222. LISTEN(&xsurface->events.request_activate, &c->activate, activatex11);
  3223. LISTEN(&xsurface->events.request_configure, &c->configure, configurex11);
  3224. LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify);
  3225. LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints);
  3226. LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle);
  3227. }
  3228. void
  3229. dissociatex11(struct wl_listener *listener, void *data)
  3230. {
  3231. Client *c = wl_container_of(listener, c, dissociate);
  3232. wl_list_remove(&c->map.link);
  3233. wl_list_remove(&c->unmap.link);
  3234. }
  3235. xcb_atom_t
  3236. getatom(xcb_connection_t *xc, const char *name)
  3237. {
  3238. xcb_atom_t atom = 0;
  3239. xcb_intern_atom_reply_t *reply;
  3240. xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name);
  3241. if ((reply = xcb_intern_atom_reply(xc, cookie, NULL)))
  3242. atom = reply->atom;
  3243. free(reply);
  3244. return atom;
  3245. }
  3246. void
  3247. sethints(struct wl_listener *listener, void *data)
  3248. {
  3249. Client *c = wl_container_of(listener, c, set_hints);
  3250. struct wlr_surface *surface = client_surface(c);
  3251. if (c == focustop(selmon))
  3252. return;
  3253. c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints);
  3254. drawbars();
  3255. if (c->isurgent && surface && surface->mapped)
  3256. client_set_border_color(c, (float[])COLOR(colors[SchemeUrg][ColBorder]));
  3257. }
  3258. void
  3259. xwaylandready(struct wl_listener *listener, void *data)
  3260. {
  3261. struct wlr_xcursor *xcursor;
  3262. xcb_connection_t *xc = xcb_connect(xwayland->display_name, NULL);
  3263. int err = xcb_connection_has_error(xc);
  3264. if (err) {
  3265. fprintf(stderr, "xcb_connect to X server failed with code %d\n. Continuing with degraded functionality.\n", err);
  3266. return;
  3267. }
  3268. /* Collect atoms we are interested in. If getatom returns 0, we will
  3269. * not detect that window type. */
  3270. netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG");
  3271. netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH");
  3272. netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR");
  3273. netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY");
  3274. /* assign the one and only seat */
  3275. wlr_xwayland_set_seat(xwayland, seat);
  3276. /* Set the default XWayland cursor to match the rest of dwl. */
  3277. if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1)))
  3278. wlr_xwayland_set_cursor(xwayland,
  3279. xcursor->images[0]->buffer, xcursor->images[0]->width * 4,
  3280. xcursor->images[0]->width, xcursor->images[0]->height,
  3281. xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y);
  3282. xcb_disconnect(xc);
  3283. }
  3284. #endif
  3285. int
  3286. main(int argc, char *argv[])
  3287. {
  3288. char *startup_cmd = NULL;
  3289. int c;
  3290. while ((c = getopt(argc, argv, "s:hdv")) != -1) {
  3291. if (c == 's')
  3292. startup_cmd = optarg;
  3293. else if (c == 'd')
  3294. log_level = WLR_DEBUG;
  3295. else if (c == 'v')
  3296. die("dwl " VERSION);
  3297. else
  3298. goto usage;
  3299. }
  3300. if (optind < argc)
  3301. goto usage;
  3302. /* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */
  3303. if (!getenv("XDG_RUNTIME_DIR"))
  3304. die("XDG_RUNTIME_DIR must be set");
  3305. setup();
  3306. run(startup_cmd);
  3307. cleanup();
  3308. return EXIT_SUCCESS;
  3309. usage:
  3310. die("Usage: %s [-v] [-d] [-s startup command]", argv[0]);
  3311. }
  3312. static void
  3313. bstack(Monitor *m)
  3314. {
  3315. int w, h, mh, mx, tx, ty, tw;
  3316. int i, n = 0;
  3317. Client *c;
  3318. wl_list_for_each(c, &clients, link)
  3319. if (VISIBLEON(c, m) && !c->isfloating)
  3320. n++;
  3321. if (n == 0)
  3322. return;
  3323. if (n > m->nmaster) {
  3324. mh = (int)round(m->nmaster ? m->mfact * m->w.height : 0);
  3325. tw = m->w.width / (n - m->nmaster);
  3326. ty = m->w.y + mh;
  3327. } else {
  3328. mh = m->w.height;
  3329. tw = m->w.width;
  3330. ty = m->w.y;
  3331. }
  3332. i = mx = 0;
  3333. tx = m-> w.x;
  3334. wl_list_for_each(c, &clients, link) {
  3335. if (!VISIBLEON(c, m) || c->isfloating)
  3336. continue;
  3337. if (i < m->nmaster) {
  3338. w = (m->w.width - mx) / (MIN(n, m->nmaster) - i);
  3339. resize(c, (struct wlr_box) { .x = m->w.x + mx, .y = m->w.y, .width = w, .height = mh }, 0);
  3340. mx += c->geom.width;
  3341. } else {
  3342. h = m->w.height - mh;
  3343. resize(c, (struct wlr_box) { .x = tx, .y = ty, .width = tw, .height = h }, 0);
  3344. if (tw != m->w.width)
  3345. tx += c->geom.width;
  3346. }
  3347. i++;
  3348. }
  3349. }
  3350. static void
  3351. bstackhoriz(Monitor *m) {
  3352. int w, mh, mx, tx, ty, th;
  3353. int i, n = 0;
  3354. Client *c;
  3355. wl_list_for_each(c, &clients, link)
  3356. if (VISIBLEON(c, m) && !c->isfloating)
  3357. n ++;
  3358. if (n == 0)
  3359. return;
  3360. if (n > m->nmaster) {
  3361. mh = (int)round(m->nmaster ? m->mfact * m->w.height : 0);
  3362. th = (m->w.height - mh) / (n - m->nmaster);
  3363. ty = m->w.y + mh;
  3364. } else {
  3365. th = mh = m->w.height;
  3366. ty = m->w.y;
  3367. }
  3368. i = mx = 0;
  3369. tx = m-> w.x;
  3370. wl_list_for_each(c, &clients, link) {
  3371. if (!VISIBLEON(c,m) || c->isfloating)
  3372. continue;
  3373. if (i < m->nmaster) {
  3374. w = (m->w.width - mx) / (MIN(n, m->nmaster) - i);
  3375. resize(c, (struct wlr_box) { .x = m->w.x + mx, .y = m->w.y, .width = w, .height = mh }, 0);
  3376. mx += c->geom.width;
  3377. } else {
  3378. resize(c, (struct wlr_box) { .x = tx, .y = ty, .width = m->w.width, .height = th }, 0);
  3379. if (th != m->w.height)
  3380. ty += c->geom.height;
  3381. }
  3382. i++;
  3383. }
  3384. }