pax_global_header00006660000000000000000000000064145324303340014513gustar00rootroot0000000000000052 comment=9f871a8e2b189cabb50da2130386937097e713a3 wcm-master/000077500000000000000000000000001453243033400131365ustar00rootroot00000000000000wcm-master/.github/000077500000000000000000000000001453243033400144765ustar00rootroot00000000000000wcm-master/.github/workflows/000077500000000000000000000000001453243033400165335ustar00rootroot00000000000000wcm-master/.github/workflows/ci.yaml000066400000000000000000000025771453243033400200250ustar00rootroot00000000000000name: CI on: [push, pull_request] jobs: test_musl_gcc: name: "Test with with GCC/musl/libstdc++/BFD on Alpine Linux" runs-on: ubuntu-latest container: alpine:edge steps: - run: echo 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories - run: apk --no-cache add git g++ binutils pkgconf meson ninja musl-dev gtk+3.0-dev gtkmm3-dev wayland-protocols wayfire-dev - name: WCM uses: actions/checkout@v2 with: repository: WayfireWM/wcm path: wcm - run: cd wcm && meson build --prefix=/usr && ninja -v -C build && ninja -v -C build install && cd .. test_code_style: name: "Check code style with uncrustify" runs-on: ubuntu-latest steps: - run: sudo apt-get update - run: sudo apt-get install -y git cmake gcc make - name: Build Uncrustify uses: actions/checkout@v2 with: repository: ammen99/uncrustify path: uncrustify - run: cd uncrustify && mkdir build && cd build && cmake .. && make && cd ../.. - name: Run Uncrustify Check uses: actions/checkout@v2 with: path: wcm - run: cd wcm && wget https://raw.githubusercontent.com/WayfireWM/wayfire/master/uncrustify.ini - run: cd wcm && git ls-files | grep "hpp$\|cpp$" | xargs ../uncrustify/build/uncrustify -c uncrustify.ini --no-backup --replace - run: cd wcm && git diff --exit-code wcm-master/.gitmodules000066400000000000000000000001571453243033400153160ustar00rootroot00000000000000[submodule "subprojects/wdisplays"] path = subprojects/wdisplays url = https://github.com/artizirk/wdisplays wcm-master/LICENSE000066400000000000000000000021311453243033400141400ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2019 Scott Moreau Copyright (c) 2023 Namor Niradnug Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. wcm-master/README.md000066400000000000000000000002601453243033400144130ustar00rootroot00000000000000# wcm Wayfire Config Manager is a Gtk3 application to configure wayfire. It writes the config file that wayfire reads to update option values. ![screenshot](/screenshot.png) wcm-master/icons/000077500000000000000000000000001453243033400142515ustar00rootroot00000000000000wcm-master/icons/desktop/000077500000000000000000000000001453243033400157225ustar00rootroot00000000000000wcm-master/icons/desktop/128x128/000077500000000000000000000000001453243033400166575ustar00rootroot00000000000000wcm-master/icons/desktop/128x128/wcm.png000066400000000000000000000234221453243033400201560ustar00rootroot00000000000000PNG  IHDR>abKGD pHYs  tIME 64s IDATxw|\ձǿ޻}ի-Ye*^%IQC ! Г@8!B-K,M,[n߽?Vekwve<~쏽{933gfWL&`Yfʹx< TUUb9KaR~ j_U_^^~f{HQH5 _m@II 7eʔYNJٵm۶[ZZ?cB**((j#c=r}WW} JKKV:yh .V?7nm>LRjޤ(JI"kFիܧ&WVVVp8X,sǻci߿v/^~}ݗPkG[[e…/+r4R xg!c $~_A \Y__[Iӧi&O~BVV2!s\:76m1-M:uߤ!0Kh鲃cB Bn??++UU:::ZiĒqvaq`Ri:f^UV(77vϟW+L~^5ۇ2;D)ݘP7aFVWW߳`dN|MӴd/GxU a7BPkwwMMM+9Fe `0(Zh+)| ,@c4-?77wŢEw8E`}Fmaa+Bxtqʘ/"P։(''Ԡa50L,Z˲l"'~Tsl'2%%-eee̙3@FF`P(t?xt>AxGlI%3##ѹs~d6n}t:͛7Md:d'@<۫5_ @zz(((8rѢEݪެ(uO78ߤ'_bUUEu..ҽ3PXXȖ-[(..>8;;!EQKhᇣSyH QW(@gW577{*++3t]t^x@tX-*4I{Qe?cO*JYXYI kӇF/*E"˵TUVZ3045gΜǏ) ]>6=Tբcn&w?4]ouVe Dfi p H)nCk֬uw^q MX`&izrEq98V˯es=3ی._d-"-YZxBW!`ppɊ+ڝ{v`5MJai)y>Z bpL͇j(|6L\D-PvŊ_`dKU՜5MFNU_>wsMX(.w7{~&KM($ =P]] c?̒%K(..>777@K4M,7@4޵w8s+qY!QbEO0G)ĔC(xeܹX,ۅ]ʼy4;ؓBG _?NㇷFSkeESKfi3.T l O(^f%-$Γ0 O0CMM͕0}srrn[C_=$PP0gW6kp}B%?Sqh7ݨl2w``8C)2P e* 0r'?Mʥb΄a !cӦM6}c3OiuSZCQ$o3߯!w{ F7S=RJX.RpG8 jp't Q(l A%&?pR/H=5XorU-a{*ީc;ëZU&RIX6JRYHr_}i1+rFD\k7rq=ʆW@ 66l(2σ-l"чx.(-"x >](ytg0XT. JDLLJcIhB*cutY^di`H_S9ǝRn&!]| '8MtN"%$ru#Բt/w9$XC~sO[S4 !ɰQKsH@`t.ƕo kRPݞ"îʩc{[&iS{ ͣz+JRn#sxam,dLKt~JDDDS~+}~ OH%d(8M! ~20;Ӎb-5b d Pt(; 2z#jbK7E"~uCbc*?'ՑcOZ#լj)I FdWci^ ) AڔfF;g_:HIӟ{)n=4+TPOi)>UCАCR-MOKxxZXaU}\opTnS3gT~YO$0! 7*i!CpFYũɽH TU>h ԮqF z> ^]Tibo!W#eV*mEBqrZ԰!G GP|&_M"JԥۧZZ-5V,#SjlvQy*9C+5)U,$`F4?vawLx ϝtr͍<|^3UɴG~^͙u%2A)eX0&Ee s|I7.o kylR^C24U«yzG/2re'昧n"iFUα-S`HI Uh4(..'~Vܧ<`!` r3XL' 7pnVZezS=b mN.zCqS5jW9TrqA7ffSfL H><-~FHHOl3X0=Sczt;88zc Q.rEqxfu>Qmn3>-aq= ϫSفJ\Cc qgww{ϧ%XYBX|RI@qsZ8j4S]:*@؇rs4]pVF+ߦe%a*|L2ȉPUmkGWsq$֑B *RSB|ya9_;PHD0F.Oɥ{bqDq3#k78زt!MێN8$ʸY\G">bx|`Hpwケxdz@t=W\dҘ|8L~^ط#(5@e6`" wpL#@OH E \wf\0gE5zQ%e NnH v=zQ3pAh]o{y>dOlVvf^63kij s6z"3!y Tf}kRܩn*]#q}v q탄GH(#_O1 ?]Uq: .l:(PP+"v4ۆ{-ß'Ix2HRݕ \!! į*+<*J=n`|VV 'eaj5 4sU^VɺA:MgE4l!ek0)}C Hڬ>\uS<\E^f`P ! 2҃|l^4T!6 a;7K*YQ댻fp1\C!`1_'4(]a65\UdU 7qp3[96\nv3fRSt 8:\V$re\0(',~ Oix./6Pg 9L0$;+ြB 3n_1isfy8^ ?7ӡXozU b6 CfD D`qŢC+-h?#H5EUyXdPuwowF褄4N3W:3HgN:IF4W;uG ㅆ|7߯j!i\׌[*h' x& u/.:ܽ5+mB.d%*bqoaIǙ\rޱϴSۗWumf 8qcGZ]q௯geaf7O ..nvgD{-uħu(BF<'kprr#Ei`K< 6_RÜu"ʍ@-owX,_yVq@ xN|mv+WPcⱕIX gi#\fBZU Ͽg,kfwR(uYp!g]2W-ѵ}*JY/mx?t:F.ėY%G12xǥlM^o$<ݭP硯4}lU4>"M'-%e0cnJwק#0khϧzcvDhbYtDDlbt31=z^ЃF. _iϖ?i!_`G?uNClW۵B[[hzU mv T wts(;䌨 &IO$E4lt_&ۋMJN_W™qC2jG2O{1 Eйc=Fǫ(,357'IK ﳒ[oda^?$Ļ )(Mr@-hz؅[(sh Ws>!O Jy,[c7r7t'[^l$1.gQ[JHػ )ǫߪѕJK`nN.\5/ Tn9xɢZg( v 4̐.xQUCyH 3'40[yũ>:j#olQfq2+`3m@k1S wN>3] sˡM f:y N冃T "4YYvZ-GFvG Ƥ9JFyL/N18&;`ri#;8m=f՘IMv96M ,A9= Ոspcđ* 1Ѷ 7l%q8;ݫ"$S.l A#Nrg Vvt?%ClIW/bQY3rvCoIN*dhP3nbR%ػgE\cةH%[=)PO.o010`~Lp{33ܒ_Ly?@E)yƔrW.;V,&==f ~IGQ OkKI6Zm$JLde{ i}6hp"yГZّBuG pGOMصO`>*]#Z0vؔkY5BYL! 7\&k*Fw]9$9쀾h!{szVhKԄ2>Ő!_yq}Yaz9Se'XF9n?E0`ެ 2#!+R9]. o1 XJޘKI2Q\)׼;9?s,,e-1&fDGe]1 >~#Uw9zL<4^}3Y&\ @>2dKhtIy<$+b3N #Kyi{f`6ljed(Qi4e$1&j;4ǻӅmEB\66oV~%69F<!*i[c]aIBX'KY {d'BkG:B׹,8,Ԉ DEG ?x3e{}.>ɘxd;y=iwEIٲkK'Ӏ-‚ V':E TwBsΣ&"d?vUկIk`$we rhJL9p`*xj<(8JFUnwp+Ȥ6=ցsk= ˞|'ѷaWTP"ei5Mw֞s5ɚ ɵ&ʵ0W6S[AS)뉪?0-" gyfipa& =\G'ERJBucLpv<@ 4,;E4bŘ0Cfq(N)!3=ȟ\EZJh' >i*O/,KB+V:=Dc;<­T,Xp,d.B0 g+%][E%(X.!%Wz[4^}+>`uOz8\:&+V;vo&`3g]GBD2!x-zH#p ǰ](Q: )Z[렣ˌl$\C~h͚5q+Y2C;NUw6t Qex B 1M\#gHɘ!dһ\޶jժdb^{R>)//_~O7il6^6o޼Wf1ʳ*1m# 83?rS嚸" mGz\@ pD0$bG1%aiA`@ pʕ+* @OOQӴY"t%vbJ]˷D& mRzzz.>TӴM&.HL*))IZKRRRNؾ F/.w0s6xQ'd|_766M+Puuuņa|ɽG&b `a & 'ؾ- FDQQhXa`MߡbGZ}bSSJ@&2R'+Bsrrضm[kkk/sssB*!c<(odQ,}LRBErc^5?ƹBkv> 0:TVV>n.LĄiя 3K^VZ_UUx$G! d?E`-uuu{ O ^Γ68EƸ/tuvvX[[{ޛxWiVQQ=k!4-ܵؼy3^Vh!i"- OcmpW^䗉_i2lذaf{\JX,G'bջ[].y 000ٗN ₂{V9c~s---յ# s[ZZʥ]0n:)))HES҄Bzϖdlٝ>l&z]+{EeD`T^oܹs]YY?>/Eض}l2 ql ƧrS^^~_R`v0wuuc9F8%LpB\iڂ>`)׮]C8e8)k) 544n4mU4`S--->1fD*uuun&{2H$ro,B[[[eYǔRUUUU*,,'L.xَp[˗/i]OŽ(|Nf(%N(S1[׮]{h)+GCwA$v^|Sߝ+ }89 \')k]Ou˗?vgG"?Q#I555>_ˋŀxP,(#D588xS{{{hGf8Dp8w.ZDqN̓Q 8t}̓ɑ{rL.:В%K.^xn]:$8M p3;8AmVUuk_dC.%ގjll8pOZ >n;\:Wyl^4rm%577, ޣc"84w\OAAgjjjUUuK(nsc3(ψ"8Mx?bds^Y`%m***e&J0."{s-nԢ[l^`KnMozӌgƷ/)rbFplb+.2kN.\U?Ҳm_ۻw1fFe+VCQ7 !\3ia _-GtgY+|yt)eܶ'֬YQ8 iFCCÁ{cc⊺TU],QIC+~XY}wE o.E9n֬Y~g0L=#{h0<˖-;p|J1#Dvrf$(ϕ5<uygUVVvwvv L(6<2Y__j VӴ=o4('6B,c1Wi3w+Xu.v.] >K /vL|.~AiiK.pF".iNծK|>mB9|!ODsN8(r(9uض Pp9,N9i 2>FI3qltGO"k c',ANZUP{J]0m?U# ݻ@]p-#B\oi J\>|\ߟ*IB& Û(<*jcºr8޵yk{Ļxd+v[|})(IgⲈ$g#%Lo-F[?(!O1ueee/q; p0g:::X`Rʟ9Nyg3SG9j y,~~O .Tl[`W8ً cz/I$'i1 &0eM?i1.;w׀ECܖ&խuJ0TJbsmVrL[Jﲋeg+h_*~8<}B Se-Oj ˖-Q !PJqɘ2~t{-ɤ2HE`df&E)e0;֭[w-`ח?pлYXXt]?/_I-8a V|ָGlf/߿'ɍt1L&O!ao(pzJEE^wg@ŋO4*  ݯ`|$Q(@dZÅ7e # "& CZ<χ{ۊdE@~n?r:7~|>ڲ5q~xJM Gri9/#N!:qii@Ӵb}}}#13:xo\kyyMd\޽Rc||kǡat*Εb^Sl.ܴh$@m&%% L&)Ǡ^h \Eew4:dOj:?y߂2.2^o}}G8S#p=MJ0-?̲M@,,7SPv Z8@4E!!TT@[꒣-rHE`LY'AXxOV31ssPλ2s1e&a TER=+AeYciA^TPm >},]&Lo =(%P؊ug B,!бѐ3|CAyB1Jy2%9AXNC8; S IoV*>7r9mQQ: }TкyaN9rJѳ](N?_mSRmKQ88OA@~Vl?'@ `nC_(N=$sS M& wq{-*F@HaS\}QKpD |DEb!OQΖ+6} DN(%86/}v7CrmPu ݽ:?Pr/"6i'5~@-2F&UHBȡJ ][-EJ'\o-zrd0I>uy;0!M]2%]p$-q0` 4)HPMRIRIspBR*F86TBI@RC!ZeSE-ɹu|&?YS{dд"\_,]X,%_cq2'TڇƷhH11T% 0ZHpR=`\3+awEsΠNu`فҰ,̕qvm*VC?ƺ._Y3.EVRiQů)ߤeRiUbA1ŭ-S.׍Se Jol}R`ڂ)hp>/[z @y`bm)!%g,- 탇†eatф<8M_uR0sw/|D7s&WK0Pjqn8uʣSwKSdŞ'T8p"$tt\HjD nR3'({\BS -E:6-ůk\uY;z{O2Q GF/_bhcIK>qJ  GAK#9W gS@:tMlN`r7.,& r_RCSWգգjHh~%gSx}"vj̀SAGQ@!`0kH$' {;GϑХMQ%mxH+IM[^<zu!cվBT@]lZ.nY{]ŽY"zɭCIG7RE{Q68LNO5#>9Ĵ:i7*ۆ@qT%%L/ڇ!.;'ڊ5mIS=a `-+NLoEԓCf IKurgIPװŁLۉ$TUJʽBx4M=\|#<Qb#dY [kj{c՘=sZ_)oK:xC<K3nZ24m*B<> NW; scU {uu]|z9nRmЇ[gIpLc"(yP dT3{2j"YO7XE0{FT"?ZKх4O̟uzu+ŝ9# %lzE*U@qultf J90&X5TYzhA7]4)/[r(6n.}d1*Ied =.w7uP^"x *d[1%{}ja!'u6"[fU鍤4H蒽9s`~0,zNfvI†/L,!9c*Ͽ 2NdJ@r/QDlbo!3ĩ, 3Qm] z֤pH <MQ8M+|8M2(CD#cN%XY5i(--e2Q3>400~FM[0(+ (_4COr#2ݽO|Y98:. ‘9cJ)H07Hm٬X:gqUZMW8l5T67{24z[nsT^~hY\څ{kkpkMgdn T"}yhYU`qsvy3axAm1odS* ר-՝~7fP7U{,\ũKHp^cn,_歧qܓ6=}4] d]]Hgtm̘O-8e.@S~cQCYR Dg.U0g_ `e|+vn{qk6-8r=QG& YUșgdk؄NL}E<% Oazr 3J=s_Rog00_Oa^cx?jT:>o3.sdqYAwγbK qũ M(T/i./Zv/ #K{$lC9g68˄ Ox'1Ĕr-iB2/h^*㆑Nuj,S_UjsgZJ܆($)zMKdAK.M$>Vbq%і2XcLeUT$ѴPX;tV4T 5^~Տe/4c#wtqв4&U%6l{-@h@Mȇ<WMi'yQ?2GM/~@fsŢtErbkCs}:1̋e B)𘼰:"pU2DUEtbY*Q@5M*49ZРr~&47ڂ8Vx[vx5LKt}&͉riTJ6ƚ/r8l7{5 m̪ʲ[>=?E8F'J;3L`go猚Q[wVG$L+V6*!T@#F#]rZ Y5UXHm.v@{7U%7"߬W\wJ B-犫n7YKLnp)w_5e\$M!Inr=OWxQ_Zn;8K1]4MV^bIDATscΨwit-aHɌ&N)j2%n=1A`V/Օ >35ECH(JkØ_ )Ř?K &T[ؔ D>+Fgpa"2..}wGvos F0(}[+`3/#z 4z5&p//L'DQݲ*繗u !5C'#-"!={]<߾/[»9W:$V=8YJon9~f(o1#ZK燩NfU%O>S<.trO?3l+ƾ̚]ض;/R%.inًSUH".p9lT.{,ׯI>Bme=fqsɆG2H'?;)'u2!~ w1]=N e`Qkq@]<^xƺvqX|9Vib)e_}׈ܑE%a?pn]?q1-MVlEhJG(Y`g'lo9_zgW*dE뫲;-YⰋYӤG 5x^7EƵd`rM2_㠷7K`u^wtQPmU>Ww}.rO2h(8ػ&E xRӞz`qA^dUdФKH@(k`MrΜGP&>J!pNOڌuܬ)_ cHC hO Ŕ'M<;0(7i__ٌ&dV}S&fb\C#8A/qI*$3`YD98&DT" KpUG25.. w笆ĆHpk6XůĜ@ ] m sm&И]FnVi q`sc:c %za?gK$ĩ\x/w} keASI_kOn"S`͆-)H7o=j2ΐwgPE"B` 3W ɛV?H$ذJLX]zܓSvmC,]wbVwip7l( t!.p%a6z2r0:eE -l5͞8=tqG'ړZgf\ˏOc }qx5pqp}U+}e@1,6c6 TXK %uk57'F%sQNITt( ߥT))H[VO.&a嘅`9!Yܤ#mPNwؓo+޷9SKgVԝ9򚨕Ln-Y*n6ާLi2o9*G6S sg ~G2ɡUnKہ,ڍݸG!Y84UVu ;(>:Sԛ1 Da+29[~EDk|)mm5nJ>|VȄ We{sTyPN#Kgσ]rĜ0lG^;rhK =tFFRIws1bTr8t 8˵kO"CB w 6En,[SjC$/>̈ƟѺǝ~99%{N BXR{L{QS/-cL*q KC];H Ǘr+*T&7̥^̏|^F/ƇEDŽo,a% /L9swۣe9k֔*Bϋ)N>&<f} +an.そ|g rR KJ~CEs$im`}W.Lg|]| nFm fW9ae9H5VOkꜦn=^M*'li$i+{OOcâ) A7IĭYCL^) =!*`o؉[3`.Q(8ФYOLX\f^ FYU J-.n-y`8^h$n9,H~G=l,r~qz KIMZ*LPxcb&9}YS8PS:B!}A .Mm1j.0}%}=\igxb[jKRk 8Dh̸m&Ԋ_광!xߌҫϕ\u^<5ePRhoLVasTJ(4vn [ 4yt̒֎D HDVɝ@EH ]ԋR'lU8~2j1 2NxBgJxl;0]U$&qMc}v/xБhHJ8.)$P(INEDS,]q ɇ߿/|E7|l6m+xB!cΉ5=*j'D+ˌS$Zd#Hs|zY*¸dɄ~!jƌ _l"k|k?QvjfHϦZlmmr]#(`"aTeObŐÖͤLw I!")1qq1dΟln~,ja;3Sg9^BJ)h{a*%I~~]CC7u]pzضe qvB$H(qJBi9B}h|Ye(LYM+tO6Qm̥1-eR0137R,+|?:|())$^lXCKi D -$9y^q ;aF/_vP>x<4ްaO@EEHfZZR9nsyJaa]mTG}7_._mcnxBt\51Mm``#}ؘR З-[vB>L~VdԐE*(Pٰx~%t1r~t{mށ' qǺuMi' ˉD"vggH䑢)e™ ,11C9wb֘I&Gr?5e2nU'YRo;w7]^^N__ߤ=&A}}=۷o`:/8E crsAA% 0i].!SvR_?4ޫt]N~ ~.Z?lԐEkk+drҿ=O>d򻀜[á*\'[X.W)*# %;X r0ULtغÝ嵅Dc*PYʇ_z%w<%LV^]]޽{ԅ x>2?9Mg~>+ک&GxO:T,&񺺺(yrI,\8W$"/BR exݖ`ntt9ipDlymq۶^[[۪@xCR[dɛE8+_7E*g>djB&p"PY05q|NQQ„m ,`~%azӶm`Æ ;g4a*((&prC PZ6p3}Y+XƑBJ*=P^^NWWW^ aʕ+۶mgEx^)e2Yvl MD#FeN6/ʹ~f%=W.ھ}'|rLS&yHGSMNK0-EeVmئxi[[[ϗq͋lٲs:ΕӵR amۊO uƂ/H(qݺuOљiXis[p8P(tmӲAqJG߻_Xٶ BWᷮ[A :g0~&*+V(oBuS6.g7.>OfԆJ)m?f͚3%+3qQ]k֬yG__Ee=%̋bD(s\MzhARZe=wњ5kt1fB΅^Hss[n(|0M"N2U3`CSr.΄0MHC[lyGss^x!9#xD0]b' }"0BPG{ٔv0PF6(t}d o͚5#坪GUU5Z[[_ B UU!R Ѓ-DߘHO[*tX2|rǎg߿ UU#*G۹B֭[w~<̲礜ul^E|yc:[Ȕl<lݺuB}]vG+=2ۈt:SSӻNUU+qqq}͎Q ؇+/eJ$7ر/d2tQRHpvFYYP(ݽNU;xT4%j|,!B@YÙqDwŮ]VYHi1FƗ-[qZ0IF,2;R /ᡞ H'Daܸqc͛C=&˗/i]O$QH"+c$!lJ[/]#YԾ.y±]耙巿ZjϾ}~^\\TVQ)6&׮]{E0s9ގmۯ?GͳgϮ|zoymG pݻw{cV4RWWWvozHBDF_ؽ{weY]= Y g4MbYӭ~=Z#L._BK5M-i[^vnJ1#&\>EQNB*{L&vΝ3)!i@eeRQQQlٲ-[@EEE]eeh"Sva,?$IENDB`wcm-master/icons/desktop/192x192/000077500000000000000000000000001453243033400166615ustar00rootroot00000000000000wcm-master/icons/desktop/192x192/wcm.png000066400000000000000000000455261453243033400201710ustar00rootroot00000000000000PNG  IHDRRlbKGD pHYs  tIME 57 IDATxw\gyyN޶],ra0`ۘbS $/B_!@B0`J1w˨X}%O/<f̶Y{_\Ҷss^`t]gٲe'}/ .]~ׯ7 .=g˖-CŃG0TUUE?Պi_?z9oinH]<24d@\pT*_W \pLf`{:;;=^4,;w}7lܸU__9K.-WUui[l~}hkXE'x^̝+ݻwP]]ojjr?Mjg=(UuFEQˇUUO&i\uU9rq΢[ߺrʍaܨi{5M6O`yg.gϞ=[4׶H="u}\3f.)7GFF~q`k]E̚ #ͯWf0Xטw箎_bE`fn\b&UUߨofQҶퟧݻމaPpnee[ku]oY(?Yt>̢I(3:::Pu6lx8躾L˲B?m)e7@$addd!/xNQ׮]{i7iv⌬ARe=lY֏wmƢE"^v~SS,]`0\(J\~@֤rgqc؝O:::,k/W:XrEBQ%s.52!< 3qCܿgϞ/齧"^&tJxзq !nBBKvFqyu"^A"##Fg"Ld2iڵk+D"?1 c͙rZ,#&c'j>Ltw e fMr92 ׯ/w\ !ΘXpX/ v ?YR\]{?04Vz{{hmm _d !g5n.i3om"z=|!DѶs~H$r9ZZZH$ ?X&3<<իWuc@?4Mk9}A#ϓ"D79O?Xv DFFF,8W^Dnzp\r$`Ht"B1ma稪zwjjjzFǙ!f t]c۶mX:0zoBx9)rwc3ѧD+ID8d@\WI)/.++˔ Mn` ,ZՇeee\.;5M{N+d/}40s0*U>*Gp_A>,`H)eY?fz(O}/[TVV20pL\B}7플G8HyC^2c"r ~*#(LB!)UBe!4 qIuA~mٶl6={<1fɕ#$8- ݤi4M[YI-ùb*%)2UYyC97CeaU_#[q J>2̓"0:hivQqH$w߿ SoMJyM0uRi | ω̟֚='u>% K?GD %l>"]oo7N;g^/Tj)_j5MVUՒL!p gJ :yIoEU>x>5P>QOuca~$kh^|=y erw9t*10 :˗ߪ(ʺRJ zs%u&>\V/㑧"̟F<|#"ř@6~QFiCRʴ8;7xjhaUUUJ\\.ͪbĠ:(^sܾZy2 YoF,|) Vȷ]n$_[0QJVc$E7 㢺+LJRl۞&YPh4:eM> lQd5/o"Rf~*/²> m${y ę.A'T]ꈢ-,8]{Oߛ<$/k~0[UUmgg[7wc)Wl"ZA4R$j%8"ɲm3}gΝfcM Mhjj:[dɍK.(RI {qGu|}/gNa̯=nxbjZjyW~&։$)3@-(JXӴ jkkvGGGw9CKK drڵEӺSp%K|NUB%p~>xL0sw}p}9LO'od9>#Z5؈6B0a#FO9*^3UUU:!NFU%pPq^y[8ؼnKs8ۤ.^h5 EQ"MHz``d2>GRhVz- [ߛ&)$"M*1YefZ&t=-|Z,ׂ0}6ÉDS (jANjssUa|BӴ+1xr;mRTɽvNo"9_ )1ceQN"_| NsO>|C5BRR\,FLr3<+,hLVGA:{.'RQϯ9c~AmϏqB˸xC2A<7E2c ,/%JBkzy[nbYq`hy[+rs/;ޏxn{EHqꇿ@/}F914CY8xWMp}oERڮ,T̯i%)n+ OKI9e V'gs#PלKz2;2cA(/HwRS"?NL4Gan@hKA0 6/}H +7$Xe3ɱ+:R#ZW5)H${,f7˛Et=jWT` K@JgI *1UN3vdӑ#1V"_]*k;] nmd Twuq.pyeçI:O=d>?#P&tE12A=I-@ܚCe0,E7G$h␳2B$LhZ'(dm3BRdy@-00T7-{q)K;Hs_)=V.Kq;;(%+y~KI~eǬr רa%\S08Txr42(K*ڊA3$ċ9TH uz.:.uFTIT9 < &Z# Dbuy|`mSq$6 ι,z=ٵׇi*3aDݲY-"\x`|9f&\cli#q_)(vx2 1YAGMwј17)D"7UcBØ8pRlT@`jca !u?ΊIjrwb?5#n4mb_%VF粒RS3Hkf gL)Uɲ4ӌ% }ɼI&]& Y0UR,G`"7,M?8Vx:Z E=_m!4(]8cT֙[۬{|Fu.gB/E׬%kKԒC=}i(D沯D`zu:h-hFc81Վ9GrQB.rI72nOtj}Y4E{\tL U6,籧ldڳy n_wBFF&9،DoQǏE5&ʔ1}9]2mgwSQU=a6iaNYa*?1aPE]p*8tm⋢y 1gž^::h &zg0(|Z~JUa?vi?EgBu:{ȭ9bfɪ\E]qg#>gN)-4Pf|0?UCԂR n61"0`}?oj;t9AU'lRC2̏E5jj|`S'a˓ӖB)K0=|=tws qpĉ\Q\jzpHk8wcht)ĴgvR7``ʄΖZ6PU`#kї? w X߀Z=uM?3ܧ.F:kAO[Nx3tRPԃ("]P9wgqQ1kiKx*j>j;?Ýa3:(X\'# s)XBP )vܼ@[r+g c,/~-tbïV0J x&!a^eYHU)&>Aԩ8?DpHzJd)X[1R1#ШhN#k Um=&վ, \IK渣 Ua߱E/v̟^uf29tV$TQu@C]p3WmV`8s2<LTEHWƹ.ƹ5q\ϱsp=%)X|Ca.M,D(9yxUa(Έ2XvG +;kCG9qS-PKk߈#>WK9:5>q/<̞a_ɘa@l-3_4aH5ނ)B`'N^`3r/kHhX*ty3B'ǵxòAٹ?d O9G 3<2sgXQTEMaQbhI\]e,n.ԭ/8IJ*Q׷556 @W$9[{jx۽kƟOW#?s-Wͮ@ "u;7/A\δDڦ&U!9/g ~^wK !e|&no=TNTgFWEQJjQp$>&Pg\nۙRH"B)âl G'$}מoy $]|e|&E3s XZTxrR,gA1mu;@TA~lZI(<&c)!Ӧ* +$m<"gϠHцuQ^42 "uqǚ\"6t8M5"j1eٙj#"zx V 9ns0D3D<Gh dJ2ːWXI\M)vՒ6O~ISG" S,uvT$櫲."l߹AqqUXLH*t3M,}I ?3t S̱tI%ij3TTD*Q!A.:{$S T0UQOÑrAuE >úOM0e G 5mlm4Ş0SannOԐ>ˎ=~t70#J>V2"zp/P1&!`{{$?z>- sQZiIPktڄ^^p]<>r Urۅ?Ωsߡ,Fh% mn5m)8*ߝsG:(CW\6De9- 8睁Cv ԓṡY$(&14F>i IDATLp$h<`AeŠ)qc6$ 13on:ߡ9 _cŲ uYR)AGI5H {4.aUzLq(AB`H&m4Fr\lM- F:Hڄ)TX:1h)9QZAfиT.8!#xq0|jǓb=8*ܘS +<SʦqN^{n3v1֡< %kʱiu5+6G$Sg*w$_n}`- \>axRd&-u W ,KCi GxǛz =LX:%):xHh !RAp`#!ȠGeH OǙI26L~3 W[rΆqFD"?U5)2^o$&~P6΁UIn 갺^2Gٯoq2H*Q$Ԛȁpaѝpu$aP)aŹ  Be)I R XY.5E.t$. iZ9Sp<̕zֺ$!R8f⑘lm, 7&JoqnMvh'iyb$&4-rE#CT2Mu\>9LUR|o  wP=\'B.dN%H|s5aeYrCVqǦ@]kV,dLr֪$$fN׷vbr#5~^E{ *w,wH򣰗GҧIJL&W yۺh`Z _ X)͆t'TYF56%fAyŭo߿8P'i\0''Q3DDq[\as L;>uf/+ Y3wX21'lR)s,LsUx;ȶ?3}sFe0qy?5|Hm:.vp&I"e2 ź5əI7 'X<]," keRK;z+04u3 Y|k4)i3YUxHC~dgD7&3M^dH {\ޏkI;~6\)Ώn" "&o+."#7|ܒp,^QC;y z'Yd;l#{d9x%#Qc`ȘF<܆I{ /0(BDn1'Gli&[ڼp-X9f7>لpfIKaxٸ`n}_ZHDTr~c }UEr8FC17VҠC PiomU˓S{w gLDevӑu+Q#\ӷ$AtݙR"g+0{8q 2^^`@zFA$o_C/7m鯪 *IǞ {o?':G=uONiPEe`OɁ8^3^f@2ᘻOW ar—E#xn{}#O6[غuK %pUTBғtkЗaRsԠ#)dh>),x.6TŧJ4K}$jss#Gt~'oq ,& ٱWsg3Jt;PǽD2aHXF6R,'M30cC`'fB Xݖzz먄D5PY[e]e% weǀV `K,KRƘʃ! Yg❲/ X Ņ:~*8ƖPr^^/~a+0W0UrK,4/bъދ'I2RW嬳Wf-6?raEA]'S*b9mVFyxtdž :,L؂I$U>7O<!/:Kw;Vy߹=X=[`CUCu洂T.$kIr>QV.qJӽTDKFC(yI%FQ)' 5b琏Y380]i P SRXG<<\w87C:@W% \+Ja>V_Բ瀯 */uK88ۇ;٘vϊ ^iL'5o4$D vk^ud~ꪶ$U5ʙJ)pn޽=SSU6nJ.v0tgZ%RB@hdf /тɐй[V_=tX}.bBa8\q01tЄPM{Bes>|NRZ;[(LP1C*Q\jVGW,'[Ayq _~^VDLeΫS[xڞ ^_cK(]F/xe8-Tܔ`Rͩ3:'!x3b^i:A/헴Թ;aʦ=|S#/C=ܣS(*N $IT2E>6 rbڕ'rUKc60MS›梆ؼLS]6i{^jGQD;m`:?A?H S$w*E>1C \]ˇd yK ޼-z.rQC#Qxkdxy}ᙚNOXBaۂ,8  ZOEؾlπ;62}^ f~lY:p4b eȩdm߇)|M,.sop<3[JPӳ]5KrJ;cL0A:X93?Ȃ#yõ\)3sOOj/!HMN+!-v9#+1S%c)Nm(s{L*<9j}9Y">+,OdM!-Sp{=-xf u$˗R((66C\!~$Ďݾyy3Fٌ{Gd,mlϭ"uǘ=,7ANm"n OUJR槽9̨gRoJA7?_}LE u5 ,GDdb4f8{MbZfnh[hLrx9&I6]Pț8^ݙ²x\$]ǚC.JOrImRͱ$aI(MS CO8UK³ۘ9syJ(ˁhRpa/|ui,-,?rVmGPU 1p͑`ײ{/!Z%b|<~L{Tam[sp R +0H4hF#հ@r9R$G9G'db)&U*p& 64‘¿bHc4|+x >rOke>cHQ/QsFWrDiK 3:CXfRGSTj,$%#+o)"B`#xfziYL' F9PL w~pM}+J-ټ鯫عO&lV8R`KJs"P[^GrH3^!*+HQ r'TLjJض.[s~ɯqkزyos'j#H}RRղZ)LټV dQIj1D%YOw';;˱%hZho5Oh8l/zZS_>CemAoN;8%TIT'tTjaX9ZAA4y:&$%(~8,7/y0ģOE'hx"?Qw੭=a*A4O62:% +&mgV !ʰOV3yZ\~evί|dJ}QnX)U'Du_rPԐVxZǀwV䱦իWCQB"{y.b&)*LjIM[,+˷Pa/ץttz&\]㌤ڵӐ?GDP]]M__L7dɒϩY_0RAYA.TKJExWnթd{[зf$l~ht/,X4Dդ4}RBShgh$h\EI~cq(TӓԾ{K KT14 1vmɅ/4Oh,e (xq=4|$ګ{g,pOQl\'@'}>߱l6ۺu+%h>I{{{i[.Z.^1o;B=bB6oJtN$?;T;>fOL&199bjjjNdYPHZ2ܮ (V [bR/e1Owʖ\׬Yp8lLNNN\luJiL4t{Dx -ro ! M.UyI8D"p80 h4DFVXD>p87BܖH!ІV]B72"p8n7fi7`0έmrdØ檭E&D:HI)EQn"%E@(4:q0b5b/DDŽ=>>9F Ḷd P@&9gq>11t\%!+c"p Ire٬TeUUow8缠 cT.(+̴cCUU3M9ο'ɷEem v#.8T8Z" Bt]?955uiei% LjbaBnY B!q)2B #N+eF~UUO J&H䨮˲\(JTVaG+I. FnEDcccw={D"755j PQ^~=pvfZbuhp NE +ΓAB#Dlh4zST*aYw>wEYreyM1vˠa1D> %0>L$O uV盀[˗#JH$r< XWWȲ&OcӠ؏:ĄZ !BL'N; @Эx[!O׮P(Rzf$i!d Bq o2~Ή~8_JB!j~몿0>xG= cM$Xlv iBqmQ$(Ş{0Ri'ԩS?b]vËN/I"ggg !!! :M)܀ ]bWROO/$ί`̌F֭{H/KTh j VS>Ü>tv,E,iӷCCCn~I6Hl1<#<9?iCCC ϪB%Y^{;c)7Y!%0Ca=yp8N+^!'QSSstݫ^WcוsqǏN1L{jF tQfx<BC,w8IJJieW3B`h4OY,`̼jmmp|Rz;i|n4W}s=C\m]|$Iw)+1ݚEj{\2f'jmnnJ1^ +x&v̲V,QJ*u*rc>JiB!/w?^|=ȟ3l^`a˖-px J黜s$IH PL9l6H8~͛7̙3KʅX>hiiYF)|19ROM<844 ,Yu%tI)T"Rݦi+ȝP@B!H@UU155lc\/$$Iش-BN4t:xx8 @^dɦ R M`dd1<ac{`p^wN0{pxxr]]]`addr_@G]]"ȹ~MNNnkhh-IҊ7`(ڹjժ#GO*;*Jc',3ITXn3s8@BFgsL˱_0Mͦ iV]>>^[zG\!g -*;i >&7q7>,qh Q9hHxD O5@H]urCO䚍C46n/",D;iaI?K=RG!YfChC WR 伴e#,[@u͋HLPtT5U< &]U(ي\^ V7w8qq Lsy8d%IE D|6 (:L`h^lTDbCp*DV8cX1I y 9SM8}~eJ3 rZ!ńG0 !Ʊc!LMgj4f'Ky8'G=QEbaO(oeVޮ+kDZ԰7 QihFF cU)Jc= -gEQ 64 Z]Gt):ŚQ>;g߅ ЖR 7@)8v2ap F5=2)3:$e):mւG|>)ECu[4K*-Ga9OQdk<^ף \⾻O33Gydh):h}42;h-rE0%G`Ge? \Wp4Z&-+cɝ+x 5 ؼ1-S/チ a3N\$*4pYbK猰kob,Zpϝg;ߋXT<_k˭K ~cxa_CJ%u<h Yx}G-|e9gX}Iׅ{jx,FJ~*Bp.M~w2J[{l`N45-s?xlop>T`]"q Q011f˵C`!=衣3pÑtwNe @-{\:^}\ G9=?e |^60b J#Ԅm֯& ^Cs+D0@O\  =sHo?{|tt(иZX˳.5h]&שruQ2Yd,Xg·!Mܵu@osgOwyn 1MNsHCKtA?a тp y^W2?8{K\~2ڠ.Vb~sa9Gtg]Ϯ(gsz~w"ʋ bB(17R`~@Cb&(MQ罼rgՃEFM O9]O,`lq,rVW ӦtqA䰟w.!C EW ">%S2J+xc!s+}l"=f ĸdnNA\i EPW^7A)=m5ќ.0Xu!sީ1,l!/gAf#*2\SZocCp4V@?<{|̟[ 5NSp`E D'ZR5]"V҂/OX  B!N'c/5<\RÆ $pPyN1 Mױ "#s@xخ&F/X5ii%|Fq-8@<H)9]*?N3>Y"hhccbqyV̜R=C'0%] 뱑BYhlʧ  M\H4L>b4nlbsvq = JC`8s@`)3+ F(%,Em@NN}rzq铄n-L".]8<թ!?X?ωԤ)G8{N?gΌ(Pt )'{`.WhrX\]Ί0Y %NX$`ϼƚ]>"E*37y"SUX=MxD2@w$vKOnIݴ2'xMSS5#?F&!= \O!n++S`[Oɮ~/P̝1,&5r;6crZN_B- ~\$̺s{f簘?#CeQ4뒉6M3/oΟ *QGKiߓ2>}nHpH hB14g˸K%%2Fl*@ U Ma,K$]6QS_@C^jm-R >œ-A>zF:\hzF~\JYA,2?ư#%DcsH[|eӔ7d[*  aY4[l=:˗ ekt:q!CE{~D[ovvvv>5mP b\.q>˛"-†eu#l\2y"^i:hK +QCSap^g2֖I Yb5/hƑTx^`dr+r%7lvq;N{+.P/)z.b1 Nc29 Gʃ\x~CRC L?8-uC07#f3lCNXd0;cw. 3in2 #aM[ t0qfqں|}Fph/o ss i_]q)~|NgF3ۻxsۼdUt!)veݝ?s{Q*1s @AlLqC|bq'5lkKGr\1 yiӷl*2(E| TbCq\qq7B$Vu"'l/+>ۄWgQQ!kKUk$?EX˙Ɛ MsfVYv6'їrpugukhL&k+3-pfF'xuRqEp6tQ" dQ715[(HㅋM}LaÜT9zT 9xU Ny骿o  \e ,5C播x{'={R%T ",Q .%WSI]Χ:u0sq&n_Zޮq1pqDHU)?ǽFbi"3*sf0%>#m│[!2M$A)ȏ#&(KL#q`Dw+}yG6_\AY:O ]\|^wΉДK@eU{ɰᐊ"w|oah~^m߱ ln!>AC3]*8oN?9D3*ge x 6l+K)Y{*ҫ=6;.J[vvR8< |tJs@?jB!52ttZ|)cLR]_?&'@ 5 ./C)0kn㶹JJ gAQ-go O0W|>~:*(؀q1=T= iQ>'<^xr:]w% &S3%X:)e$$&R%Ѕ]xJnPc!{_gp0Lk;Tu_h;vXsxe9xԝYSSCooomrL·ŝiXE|A0_~6 81Z}}}SӴA#@Z"# qj֏ 9eDm b@]de4ͯ555m=![c'xA8^ 'b,HT12. Rq89)ë/x<[Q/--uk4Ms7i؏+Kf(eYwuu==aٗ Bzl~ ){L`+yômVO(z8zz&P4S Y}a u)]]]=v)ebF6 $OQOA/Nޠph3qeP(' ouuul߾Zt1Y J&L 64niix\Q 6'O$񊡡Zo վWx޶)_}h ?u\,{H/"] !idO{ IENDB`wcm-master/icons/desktop/72x72/000077500000000000000000000000001453243033400165135ustar00rootroot00000000000000wcm-master/icons/desktop/72x72/wcm.png000066400000000000000000000130231453243033400200060ustar00rootroot00000000000000PNG  IHDRHHUGbKGD pHYs  tIME 7&Z-zIDATxyt\}?f׾Wٲl2 vh IXBBs iI,R%ppCIfi N`"[eY^d[6eYrnjFHfi9s}{766.ZzW~qQg~M^޽{_4F!D1Rjض{:::zF?P}}=ZsyDQYT(}j*v9H)4|ڶ8v @SS<ŋkKJJ+p8Lq_B;:::N~?i0@0@ 3!D-OZjӅ0vwww'&l79666I-Rʷ\.צ8o8bĦrmRt3@8Ė/_N[[˖-[R.= (e~lX֩9moo=; | èkjjzEJYW"^|S.a0r;H$2jN] FPƿG[x3u]0MMMD"bveb`'ORx<!OW8hc.u?_g{UeQ 2 #Ƶ^Y׻L8ak.`-^w{vʕkNǚW;XqNQٻϭhLCS (fEQ:L3{5|D3Jrgͣi;t e |{S;+V08s=$3=cpFWe-0$9]^˗ؼy3~z :s?m]BWRAy졲Lk:|@ ~C)ɯ;x"(ʱOY\I}.JD"Ӛϟ5k[ |nMhDg`HDz> 3FjI/` `I %)@X^+ !L ktuuhڹ<'o:1kN H vx8 7}}SF0yFN`| _j_vTO mt2RUaýu S.hm$@1SAcqG-Xxȍf >e륓>izTnUxyVg~`YjL;i맳 B(|&iјĴd"w ݸ(JaڂkȰ]eq :`1|n{zspl͏ OO )`w{>-dFFCA- $2&o4c IRAǀx^rmGJyф9+9|dz9Ȕ@dn%1!+NӛNjk"¦KKRLTXࠗwps+914=s8qΙ+ {$ ~95Lf` tАڃc .{›3.ӥȰ]O:IJC$§[pgX7og+fWQjc_ Z&m}~hE[e3Yc|˖3+N"!H$$J֌Xwv$1XЗw}Z%l=tWB)xlw`EXʫ&Xʯ(%b 6=!9WeY=sŷy=Ov7}|^&Ўl fj 8@ "ťQjhB=@$|ཽ|msm5E*;YNYq P%J-\{UwÙ2x _K_S[9CcZT%O0Ͼ)`!%ةhg`PzS7#F2F/PvJ#Ӏq!RPY_LzN ExVm)}Y2j^ >3&&,)On^},x(^[DƴB*LΎfsg%4Ş?Qʱ4mGf0tB!QE:S_([Jx礛}>G2€"F8qҍ.?$jɂsࠏFuzo,LoovKQ:hReX.5X}Q 5dE$5a1b?4;JXڐ 5CՊdb*!<͆0EVv])6]j_56) #&RP5`]/%~.ȕy`F2iR?{&ҁ!m$|#tQ䙫we'T.:Gw+eJ/S%ћ !dOnu8\>LS<@Rpu}Ksln>E1\C–$lA–hRQ[K2a&P #ȹOű3Ҡ8r[چQ^`TDMԠ?S䲩%XX?T*`@*`GS8# H44eSPYirUxU躚bU(h;-Jønfa?g\UEwp'y,1y߁]smξ),(N*w f̳kĩ]NFpE)oI}[?qx|,<T3ga fG<|7ɫZz!en\TUs᩵ۂ?7ۇ),K=@()Gܴ'bi 98uQJE.1P$+xx1rYF`!X +L?VA49[)^2+[~wcOے>S LJ<6?fdLI]A_?+,+ S[E;x~tee"('Gs2OE%Eܔ dہNn&`p⼕>/.v#K`dhѐQl>ym% : Onx0Px7}m ^^ʺY%4!aJ:"Q-RϓC1#.9vFޅ`XRSQ!v l ՘e[8hN |)ye}dJg/|m1û.`8o~>;yL B t*hxS8zzA*<?wR+ן:zt)0M|*}ZE?ukYuuu(//BqCv|C/f)$%J$rt6RK8'L'o:Qo_wXtO"8|bbٴi?OhB\:V hg 秒̥D&ہQ$f){0-#n^̞7qD[Z[[_޼y3Z9Hn#'245y[ɱуJ}w4"|#an&Bib-mf>c6 GAuɽ_:@Ҥ_+癟WkL[5g*epK b=,%2IYUWDmz[Z)()(+5 ,Kg26zUSS]x5/ ;y#Gp!-TlY=zD ΢ HXccZ}Gw&Kͼwd/S~8|<ں}3RQ0M`0Ymmm>22rm4L)_&kNgR?^F' :@5n PvQaYוReQc.0ݖe}}ǎ8>Yq鴞|>ibUUsJ)%h:)\gKbDzͶmߺsAZLʽk)R$o>V CTN{qvqlnnwb4?q>9;TB%;677L|nr/p,ٵk׃yr4yyhhhѮ]b#Aۄ,[JR.tMubfX)joot3mg}LM#N;wIENDB`wcm-master/icons/desktop/96x96/000077500000000000000000000000001453243033400165275ustar00rootroot00000000000000wcm-master/icons/desktop/96x96/wcm.png000066400000000000000000000216211453243033400200250ustar00rootroot00000000000000PNG  IHDR``w8bKGD pHYs  tIME 7 : IDATxy|WyˬI#Y#Zoq;$1!@( @&SrІ po(-&@6 )ڐ8e˖e[hl{njZF6')hsg----6mզM~2۷c!\jlٲE?~qߺMqۻwotsxz<4p 7cǎ12p_uKRʚM^E"gMR)R6G"`0b'imm}]`5kײo߾]֭[IӴiq!Dh$ t>H l`iq{yhϞ="sݒիWF`͚5-uuuu[w6ohcJP"hAfYBMRʋ͊h4:86NHd]|yy0ZJa![P.l7A~B ;(?#IJG]/>wladQ3H E *AT)m i8p`~VP}}=X~mݺu uB—Rk?s)T0[Ok[]SjU&FiK`2A!]JFj<-gŀ@ G>x≱ֆ'B|+>tM7''b t~@-y*i?'^_W04oecq08D`~4#šhd,믧mJXc'X.|YӴ-Ԗ1'=]m _N3R* Oj{KI9SrO/}x8 B~b @Qa;p/|™#ִo~>ѓlpmamfW%sOc~~U94o_Kq)fhUK-I0Q(@ ЅBKWvQǘ7ĕ6 = hDלຂPo 6;Qd]0٬$6j稣h^S~e)Ev D:_cO,Ԅ§خR~R\3Þi)#D fm5H8Q!=51R]ea;b\TZщ ?P1|8AJ?*C~vaGv#&xBWw[: ϜK]iMi>ˑ?lWL 􋥸n-(uXZs 7^',#=!m.C~@5BKcLFHixu#4Mh$SZA'IХbO4מo⩎LФb}(UuV" q$7 r` @*g|꣧˒ &Dq\6/x'WCgџ4@ ]q5tMT27j@^,БT'^| ~ bSBU~ĐμiXTJJJ Ϸ0̔0[:Mz{ <8lm˧wO<'1.*^NBt!L%1mɫz&V~TgOtrݬ8'IŒ,e66YkӬ97[/bQ14l e.0dke>{˺8VQN7t:B<.YdKe)6V1gˋE cTr +x7x?q %хwsAOS ¥Y>S(g,p:g PUeqٛrC9IJxҳPETK7KsY g048?QR#h:F?^9%"otLFTI?'p /ҍI^;ϋp^'_!zee;k6Dېv61i# sfRPb4@s*Sԗ ,?eokps,Ew \=WFk9#%..w|Ӑ(dϩytrfA.ml 8j'(8]x Zeټ!o o7򅯞TJlzPQ37tNz x45*a[ Ci.o"1, g +%̲k 鴆SmZyJWU<r[xxi+v%IWXFPd1!׮_ڗptWX]9C|ze@4~th.`M7K"=1TݏۼQ4]M .\tK?ELvĽrId5Nz įpF'= ' )_2XՅ@wA/I ENI-3  K*r5iA?x '!fM" 4 ơ 7 +荚9e{&<&,&0z=\z٢z]9z_0LM\8/e fQ;)* #1*c8SB@,n;*q%˒X$Gusx0($ Ѥ9i!|&b~"ʢCxg_ÖM1է*2_Drr.Y] RNzXNݺ _(_|#>tд땽! aeK|>ǁ>Zf%;$g7wr>},-~"#S;b2|FZ L8[l.-aB!{[6( eIr-9<_]H) k*"DB˓M>pAMR4q4EKGh*Mp! 0^`V&h"o)px[koh(篨b:Ozi=v`pCUtKys>roqx\ ]G ʽY.˅_gݒ)JE^&4;$8!cM/q̼ #%Xkݬ ' ȳ]5ԗ }[`h"Jn6p IEtʊuGMOhzmqyѓhK"GJ1 9\:|% ҎĔf/˒+ǐMf:L Cm V$xVw<Ȣ6Yu_^AE9k~Z|oH)/Ystv:܍j!3ȮʥRyщ#'˹e$S vt*\ƺZ~4MSJ,ߨUhaqJ1n Zr=~Nu{x ~H%>/'j,wVٺx^6" Rϸ6| bz `I;觶:C9tď\fF (Boz_>>IDATpQK)WE3"~u_QJ}?qOjź?fQPP[֮]Kkkkp82T&%$^jȰ ?@՝a$|e2;@|žA0+\F#B8J峅zC)řr{˄xTJ=8η^}FSn>1Mzl's8 >aa 3$NFNe(9k;ϛ2#{ޫYmoXfMiWK)oRwLBFR|Dp]^˲~#wcc*r 6KP+i!_^g;^7]sN _u9'X3,ݒg#.jSJC6::lbFƏ_i:]i>6&KJ)+Tr\|żl6E۶KNLy Xf v`ʕat]E1We=m;=xqFI ===D"n6z!?Rsu]wݽ΁8rȂ/cŊ L4~ øSJnz-˺-L>`Y٩&mhoT9@VAyɓ'zRӴ-M;e}ڊkpl;S0 o>g˗/oٸqmڴW----۾};aX(ucVIENDB`wcm-master/icons/desktop/meson.build000066400000000000000000000015641453243033400200720ustar00rootroot00000000000000install_data('wcm.png', install_dir: icon_dir) install_data(join_paths('48x48', 'wcm.png'), install_dir: join_paths(share_dir, 'icons', 'hicolor', '48x48', 'apps')) install_data(join_paths('64x64', 'wcm.png'), install_dir: join_paths(share_dir, 'icons', 'hicolor', '64x64', 'apps')) install_data(join_paths('72x72', 'wcm.png'), install_dir: join_paths(share_dir, 'icons', 'hicolor', '72x72', 'apps')) install_data(join_paths('96x96', 'wcm.png'), install_dir: join_paths(share_dir, 'icons', 'hicolor', '96x96', 'apps')) install_data(join_paths('128x128', 'wcm.png'), install_dir: join_paths(share_dir, 'icons', 'hicolor', '128x128', 'apps')) install_data(join_paths('160x160', 'wcm.png'), install_dir: join_paths(share_dir, 'icons', 'hicolor', '160x160', 'apps')) install_data(join_paths('192x192', 'wcm.png'), install_dir: join_paths(share_dir, 'icons', 'hicolor', '192x192', 'apps'))wcm-master/icons/desktop/wcm.png000066400000000000000000000327231453243033400172250ustar00rootroot00000000000000PNG  IHDRXbKGD pHYs  tIME  & IDATx]g|[~մdYdJBvF {2[H)@(oZh ] ! d8%ɶt!$$KW}%?s99B `0jiZDօAqV"NAvh wtk(wkI p=H)rʷ9'k!efdT"xC7Qqd\l6QRRgT:=oop:'dh4Vl?2 s6!RH$zOO.]M cITUUݒwe {?>IJl@] L bZϷZ=v2˲~"$YV a{"~\/κHCUVV>R. kP(R[[@ `WA$)Euu"N.K|ZZZaY6*HAf^TT'BHC)m뻩mquDd ga" q"HLt+>ܘ{@ wU=CVRRruAA݄\;tv˲1q5E[EIIc! G⪊IaaNKDqhhh"AxCR啗ߡjKa7RJ#~Ɏ%P+!\ϐ_ZUU60 dL G]@B2D=ѱt~!i(lI gÁ"D<Ȋ å@`˲ [Rn^ӳ=|0$3q|Ke K&M6LWzYq+dA& &aSɬ?idg/!tD>̀"W(GZ,$I_0qHqg̨|`0@ il !q<Ȱ L)zNwhʱh6vL6`0\g _, ",=CZUUҷG7\;bD&dW!D0AKRX"b9zO\q,BOwI'MmVxdjkk7H$\^pHZTG7ؒYH79//"4-D"C"A2Vj$&-)1<(Ij҈ 2$Fa'@&_t:m$*FE"(lTTTT*g2 }4qt )'”wj2.J=aF=cj}BPT3dGZwP5."r⻣v}X#$h4 $e@EيGhj\#J)F/Er6L6sad)&*VK^:WmEPamZD)yԎHWZ}tw0)T~( MT0I)7DDӋcpafj !/*Ð[G)?`I4AgA :|mVCTH$jOoE3eeeiK" 8p=ЍPnmPⷷաPsKhr,G6O~s\D.+JKK5wB Y)d=…SǴI~H1-mٮ wOȧ,vTbcsL.kIWWד,˲ 6ĢG !^qy[whp %~iS؁:?3jP (;? bXTC/:чED`BoiW⪛%~s0 4a:r'/g "VpQ"ñcLDVjW @\a8ϡe76`!ь9͢[G5*,I)e~K; P(rr!$ ./ oAMe'eѥ1 'cf2fi~2`os:Gxl6+++{2E(:{6ŀno(v1L\ {PP QJ7wvv^t:WnVuuuƇr^8A-}wɝ#K]v1dBF>yr؃ X)B1)1 "q 2jYfuŚa˟Wlx+.8,, #|D"ßy4pM7x)֍& G4X4,,-Ͻ/TlNl0$ųKK?TDnS?lor9(n=]t$wؼ]+W^"oF g8 (jϐK&ؕzq\6lցeZLK8IUa s~FN#"A׮čw"ʎ4r)E0$ `yNiDDT$wرK'/|8r4/Ԇuok nvȌ#do 6nHQ%hn9XbTyvK8,95iXD[%Ǫ)OT 6J..%. IjC oI}2EV'VeQz >*p)MJJN{]j8C ?^-F8~WĤ&C ׻xV*9'b/ג݊&ȐGw?L߽D^&ݟSPw[wQE3:9lCtLJzi* fP WX}a"'`dZy ,Jt~[=$ka9C^nk!hg"6hx,k GN`#/A(MdZSI f?h37ȉ?o//L+A‘Nfq'SZJz#-@ zJ{6"E182{QtoM ^N䋯1蒡EF-v$Yv/W}~]S t@ 4e8tg:1ZU/wJw >\n"&ZcpK|01)'FfE=.DяGOo*ƢOkwAOi$Hb1)}BlbKޮõa(. nX-Qyzd&9E4KHJ|5[S$XwzbܯeNUtY1/|:=H^^ Z`Rd88ϫZD >4b{迚܇J}H$Ht!-'N;aE vi wYVW&,]?S$HضS\oUՑ8fQ~f}W$xi[cy `":ϵy1 (%|mHI1hٵĀ_ٙ?'#rAIGOit]v@HTשaa9nQ~WUn1 zM 7R3ϴ1/$|IP85SBx 'I;= I`R_ƛMf5eB CCC`BMtم׎ٚ|;$қz|EH5WB8 5|^RmWM+DB1!̟793=P(AS6aZԀ'xx]948NrL[MAKɻ 1'$#GJ\c|Iגn0 PЅ|ó$qO[m`d܏jxqoQ^N.T.Yא ~%q35UW0<- BgX,9z&Fm$"ia[.$wBo#Z||XEF?fS/ڡ3\uvm _ޅ[>*AqB?OKÑdUW>QdjVGN iJVA.؇w-nvF>Ԫx!Cn6nI>9`r((,-]`x5C[pqioiXl0Űq6/IU_N)! ڼ$V, 8}TDŬASs ihCxD2 sl Ng)d*/+y]:thԞOp)N<" |ɚ fA:AfvPtd9`scjf٣g#)$sA'ӏ1wTcQfK̟i4"A`^ُO<oJ=G zv<Wve, $/G/qѲĺd ~Nc*\ ĈXj?o0 s{fV3GiR91)]S .=Up00MbMEڟ[<9Cn9nH=˻rZM rAU!~3W+:: 2ٴo9Q̯LTOH(0p¶?jjUv̟¼CM |Ķ]Z U+yg$ָf:guӗs9rupF->",7aX)΁эh#o衈oN,M%>AI/_t8SpKSB{%=p+ JǴ~D}f{e68rNߏ +0p=e#&3ΩwX;%@zzV AqR֥'9!&"1 O& 2b=5X v'3la (ŶZiQQٔbq 5Ao.G Q)(~k}UIO  C( cEqdHT:R% 8de%!|Upݍv; Gpj#!c+އ&#̜MKiW0XȇZ[mN3A&ɪHK2Vsw^ ;T*~iQzzY@0=[ȹnTl>~~QB~ xⴾ[+_p獭8!hl0N?މi=/'Vڨ5 $³Kzzо),^H= ~37V3o_׌@MPIcq'r,AWj<9eqG#FJGbU"NgE,qcyX\%^NHK! L 9:{ln"װv!-BAqqUϠ. $IBn i;viK:cu}+hlJ}sv|B=~%sQ yY%H?q:?_6$[}os(F+Vq>Yr*A5''twn'H_B̕S{QPJ %2v/R?`N:&Ϻkζ fi3R{B&9(`=5lMN(д#A@m(.Śm‰d*A=*x: vZwBeY nOT<;46q+զ) Cq!e8~޳Ɗ >lNy)6:u#Ot~->y"9Wl+nS'?SmG^=F9L#>L~L6DC(:&)NR^?J-Q.,[1NWJDSf5Itsn*w4jpŢpg nKY ^Ĉ_R/E_gi3.#M|(&QHHs!=xl_LެZ}T/:\a9vV Yj *p^wBJ1؍ xT#Ub'&B b0klRcɣXffuBB(:yTLtcLb)@!XGIs*O~v1hQΖ ŤV6}cnKr3Xff5<+ JL546kb?U^/H*q^lPhed"h A̡$'܌ÑsS+lQG#Y=e*K\ur{TIDAT'xf,$yX+~RBd8#DF ,dkEkcD MC؅ÐXq_N\I21ka~ansJUpWfZ}x&d@F%di% :EڒPވ UA♔H|mv'r6"!чA;S:G5!O! U8yK K(?xqykc h2Ýtُ7T+Izlm$yXEYЃQ3u`Rm%Ea (/lN=,/߈#Jwb%N\pzMR| zH_q֎4%+I7YN)ӑhVGBeL3뜰h}zX\mDʯX=(DVA<3,wb0ŔBE+U0Ɉ _r NX~EZ栴8"AA!gݎgvy<{<jYvnFwA->rrAra0[_>[\n94զ;A @q~}qB#[Ft଺~sfWoBJr ۅ#՗$i\QL{$)/IL8cN\2A iq~}ophIb="I -@pу"A9n='Wg~j gv3ō3;y=&lCxF^=Iv'{0bK!>dG$k&Vځ~Nǹ &+:XaL,ЗTPrU#g*mUyKxNc,7\o /TQ,%fcُfubۀ_鱹_V !0 xu 8rUa- $&@(at&;"WodAHzs)0R7` $G(&BBdaV(Pm$Fe J$/"V!NL&ڴ~̚oD ʼnչeS9TB{ڂVyKTJ >22F__ԍMqtWK񂷚Ir8ɧjQ)?o@$8tHdO_ɉ -FuXͣ +ױ"Av&-cJl%sԟ@aIEp"ABDR7 e )ԇ$AlZ*{=.HZJ<4%[`TG}. <4 SDV'"V Kru*$5q5"PL}X*sg/Adzhe &{Æ0#G=o:[`BEufb⑻GG=9B1 nZ9;px@w TϞHMWw{Pd/Y&'"ŵ+갶/ ;ъ:NґK<Û;ۋ7\ێ`,șiCa6u]aZ}Fɑq^%xÀG֗1(8JWǯ=?e00Џ $h2<gOq5q I`5l 8A@Mz˂Z/6b%x7Ob)SbY2¡v2 :ceya 4]I r8/^) Fl#j$Bm4qϗ巊dC#Jp͊z4 eiJ8Q%q,CATC( HERFn!5uήKI!d^sdiMJn w?\/e/o$WhFO֘[00,48T2.t һ#Ité󓻵XEoYVK}q#l JȀnH]Fa܁O>vȹհFqՅ=մ+ԋ%X6_k/A`Xvq=ڲIٗ;l|R3OtcQQ:|4p8"kx&ݠz̋2Jiע K:؊O}o@_+Ƌ$PQ(@^%vRcV`[g*h>AFl#6 eM=~ׂMΩV[$$ /Υ̅gw(C `ϰZaK1fc N}XK!{q`4c0BfDfAp &E M\=XpX*$Gci6B-b[P%c&|8^!'=@˱$tB3عK3fPRh4B8">2L=8xpȞRZVE/tA'p<<$1A9¨DuaHhY +„\WRlXV7߷zSJp8nߓX,Aqa$ͣ.\wmk&|iaPJw-y?Κp!;!ŕP;N'i)6hj\Ix:ك+/qn4Jm2F}+rtuu=ɲlVz$d]h4沲Z%<&q:8\@BL$4p/ϩ@g*U~@VEEE1 sVj2`x0^@ef,GPcHdnt~+ag[?Bʅx*1~0FF` Q)L+ZWR:fA)7'Aw\.WVUUݬn&\,6ْmqH"1^GX)QFSRUUGa%B[U4Wɶ<ŴfFї[ZZn BX:7G*jT*-΅!s9Z!1)rDg>Wc͙SY&I.X,BM䛔39Τp8n{1Dʜy444R(لA GgRgNǧ HX F=vWL;bXtpppE(zUєIz!'SO)MUI.hӻ_F95gp8r8u: Bbp8"bpo3V%q[omm} r;D@\.-//`0K)˜4c6AĬ$uέtv ˲\[cB8\un9JQ(3]m*azً]Ӥ$׈ٵkYcU.c oJ ,FoLVlǓhy"+sHD"uuuOeCciOrx`p,H$hلc6#lcD 6nf~iss`,1ݗF&T*ՁeNX{ r̳@ Ʊ|rnK^oJS3mh&a+=FtX?c {'~.˲UTd2YY&߿ j3e}.0D"===g>òqCj , 4:{}BaX.붶}>_x/ {.xޭh4T(@U$kG "l6o~&U EQ؁gN+d3'&z0PB"g+dï677.qx#"l>q32n%E}8CG,̐&lXt:wH}B.K,˯V5nn+a袈=zo<ߔJlO5H%F?|Z;VC$0 eee3 sXH$^WW׍CCCU 2ʎ+,,D"ir{wwB񑸪"AҭJJJ.((J֠:::bY6&HQF)(--]鮀;|>߳]]]wAqDd =pp8%$kl=L8wSOO~TWWߨei>@KK#,FU "DJu!1W8 ^jkk[* image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-animate.svg000066400000000000000000002271161453243033400213760ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus ( wcm-master/icons/plugins/plugin-annotate.svg000066400000000000000000000215501453243033400215630ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus State wcm-master/icons/plugins/plugin-autorotate-iio.svg000066400000000000000000000244451453243033400227250ustar00rootroot00000000000000 image/svg+xml wcm-master/icons/plugins/plugin-autostart.svg000066400000000000000000000112301453243033400217720ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-background-view.svg000066400000000000000000000277761453243033400230610ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-background.svg000066400000000000000000000130301453243033400220630ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-bench.svg000066400000000000000000000212241453243033400210270ustar00rootroot00000000000000 wcm-master/icons/plugins/plugin-blur.svg000066400000000000000000000155311453243033400207200ustar00rootroot00000000000000 image/svg+xml Jakub Steiner http://jimmac.musichall.cz window manager decoration behavior wcm-master/icons/plugins/plugin-command.svg000066400000000000000000000655301453243033400213760ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-core.svg000066400000000000000000000262221453243033400207030ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-crosshair.svg000066400000000000000000000120571453243033400217510ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-cube.svg000066400000000000000000000163541453243033400206760ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-dbus_interface.svg000066400000000000000000000167241453243033400227360ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-decoration.svg000066400000000000000000000145531453243033400221060ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-dock.svg000066400000000000000000000124131453243033400206700ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-example.svg000066400000000000000000000153131453243033400214050ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus E wcm-master/icons/plugins/plugin-expo.svg000066400000000000000000000230221453243033400207210ustar00rootroot00000000000000 image/svg+xml wcm-master/icons/plugins/plugin-extra-gestures.svg000066400000000000000000000266751453243033400227510ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-extra-protos.svg000066400000000000000000000137011453243033400224200ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-fast-switcher.svg000066400000000000000000000401711453243033400225350ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-fisheye.svg000066400000000000000000000452251453243033400214130ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-follow-focus.svg000066400000000000000000000362471453243033400224020ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-force-fullscreen.svg000066400000000000000000000211211453243033400232020ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-grid.svg000066400000000000000000000161571453243033400207060ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-hinge.svg000066400000000000000000000740061453243033400210500ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus Created by Oleksandr Panasovskyi from the Noun Project wcm-master/icons/plugins/plugin-idle.svg000066400000000000000000000270521453243033400206720ustar00rootroot00000000000000 image/svg+xml wcm-master/icons/plugins/plugin-input.svg000066400000000000000000001021521453243033400211070ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-invert.svg000066400000000000000000000140051453243033400212560ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-join-views.svg000066400000000000000000000546451453243033400220570ustar00rootroot00000000000000 image/svg+xml wcm-master/icons/plugins/plugin-keycolor.svg000066400000000000000000000245401453243033400216030ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-lxqt-shell.svg000066400000000000000000000054211453243033400220460ustar00rootroot00000000000000 wcm-master/icons/plugins/plugin-mag.svg000066400000000000000000000306361453243033400205230ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-move.svg000066400000000000000000000173131453243033400207220ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-obs.svg000066400000000000000000000420361453243033400205370ustar00rootroot00000000000000 image/svg+xml Jakub Steiner http://jimmac.musichall.cz Windows window manager decoration behavior wcm-master/icons/plugins/plugin-oswitch.svg000066400000000000000000000274131453243033400214360ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-panel.svg000066400000000000000000017605721453243033400210700ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus 12:00 wcm-master/icons/plugins/plugin-place.svg000066400000000000000000000137031453243033400210370ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-preserve-output.svg000066400000000000000000000316251453243033400231470ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-resize.svg000066400000000000000000000307061453243033400212560ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-scale-title-filter.svg000066400000000000000000000127451453243033400234510ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus AB AB wcm-master/icons/plugins/plugin-scale.svg000066400000000000000000001702721453243033400210470ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus Scale wcm-master/icons/plugins/plugin-showrepaint.svg000066400000000000000000000207411453243033400223160ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-simple-tile.svg000066400000000000000000000215511453243033400221770ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-switcher.svg000066400000000000000000000263551453243033400216120ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-view-shot.svg000066400000000000000000000217051453243033400217010ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-vswipe.svg000066400000000000000000000144311453243033400212670ustar00rootroot00000000000000 image/svg+xml wcm-master/icons/plugins/plugin-vswitch.svg000066400000000000000000000146011453243033400214400ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-water.svg000066400000000000000000000146631453243033400211030ustar00rootroot00000000000000 image/svg+xml wcm-master/icons/plugins/plugin-window-rules.svg000066400000000000000000000411201453243033400224040ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-winzoom.svg000066400000000000000000000555701453243033400214650ustar00rootroot00000000000000 image/svg+xml wcm-master/icons/plugins/plugin-wm-actions.svg000066400000000000000000000251041453243033400220320ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-wobbly.svg000066400000000000000000000142401453243033400212460ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-workarounds.svg000066400000000000000000000403271453243033400223330ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-workspace-names.svg000066400000000000000000000201341453243033400230460ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus A B C D wcm-master/icons/plugins/plugin-wrot.svg000066400000000000000000000316601453243033400207500ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/icons/plugins/plugin-zoom.svg000066400000000000000000000704631453243033400207450ustar00rootroot00000000000000 image/svg+xml Patrick Niklaus wcm-master/meson.build000066400000000000000000000033021453243033400152760ustar00rootroot00000000000000project('wcm', 'c', 'cpp', version : '0.9.0', default_options : 'cpp_std=c++17') add_global_arguments('-DWAYFIRE_CONFIG_FILE="' + get_option('wayfire_config_file_path') + '"', language : 'cpp') add_global_arguments('-DWF_SHELL_CONFIG_FILE="' + get_option('wf_shell_config_file_path') + '"', language : 'cpp') wayfire = dependency('wayfire') wf_shell = dependency('wf-shell', required : get_option('wf_shell')) wayfire_metadata_dir = wayfire.get_variable(pkgconfig: 'metadatadir') wayfire_sysconf_dir = wayfire.get_variable(pkgconfig: 'sysconfdir') share_dir = join_paths(get_option('prefix'), 'share') icon_dir = join_paths(share_dir, 'wayfire', 'icons') add_global_arguments('-DWAYFIRE_METADATADIR="' + wayfire_metadata_dir + '"', language : 'cpp') add_global_arguments('-DWAYFIRE_SYSCONFDIR="' + wayfire_sysconf_dir + '"', language : 'cpp') if wf_shell.found() wf_shell_metadata_dir = wf_shell.get_variable(pkgconfig: 'metadatadir') wf_shell_sysconf_dir = wf_shell.get_variable(pkgconfig: 'sysconfdir') add_project_arguments('-DHAVE_WFSHELL=1', language : 'cpp') add_global_arguments('-DWFSHELL_METADATADIR="' + wf_shell_metadata_dir + '"', language : 'cpp') add_global_arguments('-DWFSHELL_SYSCONFDIR="' + wf_shell_sysconf_dir + '"', language : 'cpp') endif add_global_arguments('-DICONDIR="' + icon_dir + '"', language : 'cpp') dependency('pkg-config', required : true) evdev = dependency('libevdev') add_project_arguments('-DICONDIR="' + icon_dir + '"', language : 'cpp') if get_option('enable_wdisplays') == true wdisplays = subproject('wdisplays') endif subdir('icons') subdir('proto') subdir('src') install_data('wayfire-config-manager.desktop', install_dir: join_paths(share_dir, 'applications')) wcm-master/meson_options.txt000066400000000000000000000007161453243033400165770ustar00rootroot00000000000000option('wf_shell', type: 'feature', value: 'auto', description: 'Build with wf-shell support') option('wayfire_config_file_path', type : 'string', value : '~/.config/wayfire.ini', description : 'Full path of wayfire config file') option('wf_shell_config_file_path', type : 'string', value : '~/.config/wf-shell.ini', description : 'Full path of wf-shell config file') option('enable_wdisplays', type : 'boolean', value : 'true', description : 'Build wdisplays') wcm-master/proto/000077500000000000000000000000001453243033400143015ustar00rootroot00000000000000wcm-master/proto/meson.build000066400000000000000000000022621453243033400164450ustar00rootroot00000000000000wayland_protos = dependency('wayland-protocols') wayland_client = dependency('wayland-client') wl_protocol_dir = wayland_protos.get_variable('pkgdatadir') wayland_scanner_dep = dependency('wayland-scanner', native: true) wayland_scanner = find_program( wayland_scanner_dep.get_variable('wayland_scanner'), native: true, ) wayland_scanner_code = generator( wayland_scanner, output: '@BASENAME@-protocol.c', arguments: ['private-code', '@INPUT@', '@OUTPUT@'], ) wayland_scanner_client = generator( wayland_scanner, output: '@BASENAME@-client-protocol.h', arguments: ['client-header', '@INPUT@', '@OUTPUT@'], ) client_protocols = [ join_paths(wl_protocol_dir, 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml'), ] wl_protos_client_src = [] wl_protos_headers = [] foreach xml : client_protocols wl_protos_headers += wayland_scanner_client.process(xml) wl_protos_client_src += wayland_scanner_code.process(xml) endforeach lib_wl_protos = static_library('wl_protos', wl_protos_client_src + wl_protos_headers, dependencies: [wayland_client]) # for the include directory wf_protos = declare_dependency( link_with: lib_wl_protos, sources: wl_protos_headers, )wcm-master/screenshot.png000066400000000000000000002616561453243033400160410ustar00rootroot00000000000000PNG  IHDR$;XPLTE3MiU `V6U@7U(A7UP P X IDATxw|[\J:=茠-d`ADDDDDDu8thHёA@F~Dȏv-1DDDDDDDqRmЮ` hinZ\p [Y'͡D[m "D呖5/LL8#-t?b80HDD b(RFX-DRhL(>OՃ" P !FL!C`"".Q $Z #cC !!}5fhw !"W8HRǺԃ_ ZX74DDN(P`E0z̀PSme@ADDDDDDGh#B",h@BzX(L7fP 1hJA@ư "=H4w! "԰ x,x?d47Uh. ((  4""I)5#7pxLehֺo\% c=4 #FX)1B(HAODDDDDDthUEz2B&> |RJM7쫯UJ}IkDK%,\٨2B"LLTPD0 v݈8U*t!>J]x^) !mD2,PP#<ԕ1DDp:0Pa)FXaD/Ea3sm»eo8CFX>>(H]zo+R@P"(oȰcIH43ΔʈB?8 +~aT-y$b TEV3 n(pP.BǵRUJH㺿.-#ǐW-wva?DXB !o] g """""NFp;Z B=<RJU@(P!u &!@P!EZNCy6W!¦v׀UEX5M`Tլ; '+֓ """"""^t~SY^m0FRHpV ߕt)"-hJ٪* Z $j4U,UJ BQ鬵ݞtDDDDDDDԙ0MZ+ -u/5]pJ)]}L *Nܲvoh)VG4ƃ!+jj#^_+?*"""""""H>sBDx<@z\]J#l+8gR aS}aid]ADDDDDDD]Ou4y2>0oDp0 Z Zm Fǎ]CA`OQ? &^_b,JDDDDDDD%A 3h @(Z!4WB# B&!cFu/)%&*#wQ_%h`i6iK_K8¿RJ50Qǖ """"""nh!J)#u.w3wP1 p!APv߅a׌6FǏ$"mHӁ6MPBbB """""""~ADn-VEeQ4^@:-M7JDDDDDDR%<ۃ3Id).pkZlBYeCh&q;zh(WF]OLJTv~Ҥw(b5#٠BGϋ:7+AE@ a E @6 % Z<21#T@`C(d?QQB6*lPlB;US<abClx5 zap8p$|7>N=ɋ`O6!<k*^:'{ҋߴoީu#P`D ^ߪڵHÍ^zH͋mOVTm~x=OARJYK @RpJ::^@zh @D7:aRўQ8N{:TM6`׮`ذp{X٧ 3w0Ulذ{ƛ1wׯÆpecKfr:t)ƏGAZQT\c=: *+˱zu7p?=2ڵkڵO"":zx Y @C%o#+Pnۜ5m%&zGX5E͡|aQAi Qbp7ߟxGJQ_V%*BMZъXDDkU ƧP"4)Q̜y -SO>Z~ޯ.ԩk׬AII1 #37x3[:68Fy(+[=ÂԻw,\z_x,o+{)w9׋uu~'_|&K<D#m`QGyUll2wV֭ &L8DULIFh뇬d=e*W\hͮ'P$B2cH<~|"" ;oJfhP7[ 6 Æ o|Ԩ1njϗs}۶=^=냀{=*C,W4<"%5.˖.Qs0n}wyƍ:l10+vÖ @,Fe~i$<9Ɉoy4=qWxRL CdkM!ǺqOiVfW@ƍB ) 1Mtl-=^-BmQ""֯__^ ) nGuI3zl@b|HKK9s1jhg;v᝷āvӱcvoχM67_GYYYğ\H)qabkPMvzuK.}m <=$&M:'Oٌm۶ⵗ_Fq Mc:o!=|L>_U˟i޳g7돉'7$N:i `]@Drαl3m5oww\$pa-ZE*7Qc/Ƕi:L#g1I` -Ubx 4M(B thԆ)4hC ꔟlQ_=lKfx^!C1իWcC$6_HIM%RJ";'kUUU().Y1tppy眃l|J\re 3jzcd =>h 9 '<B޽ p‰qϽAQ!1)~&?a"nTV688iAfO  ˆ&\ؠE~pԩ햛BpYYu{c믻>슘Ǖ ig"55E-~jظa=z MӠ( N8Zn$5cfk ,3[6jFgizFe5|zϘc74h=[=6eF"ͮ!m$h-[x0:-nڟנ))ݧ/лOuoۊ[ϝK/W_y9t]nر>d2'rr!++Ƴ<: ?s-)SuK.^|Y!o?(%K>e\;򐖖3<6E 5wmov_7oڄ/\={v#.Ίkszde;,>}o~yF{A忾7p4=@tlܸ j#G#ɖ"xѼƱsی|c}QBMA,CNkQmyRωC('B۽-:&:너`(ADDb} \6|E Mic1t0!r94ׯ9995k6&p"<7 -)GqI֬ pI'&^RRu]W:w]h5iuq?A} 31i(-);xpmX,PCmm}EZZ:wDQq߇>b`1|58Uxf5ǏR~˗/kױkZ鷜Ngkxm޵;Ə?X_  ?Чzo 6b;wqY`W_m:y,qPk6=X_ƿ3DDԺ׌=+la& |_U_co*dz/B<ɆNvaر&f_|Z  m;L[f_B:ŖMIOPDa}葕s+*CX8U٫WĆ|R9s7#&Ǿ}{7@돭[rC_AYiY6s.J ?Q}B3f+1mLOKKc/5VaaAL?aܸ1o@/׋5Vی|Q*nFUj8Z\؛U[ZF@"fܭVm\hxұ-or3JTVmmf݈Y{+$"$#hDDDbu38Bulܰ>غ_֢w> $o>EQ?܃m۷a„v{`67-\٧HM|io 眇!C" i,Vm~UW!܅]])H@^߫hR|^2( JCֽxʪh7J]Q}N4st1 "Na}}#o{2` ظ~}ḣ"zѻO_L2 ˗-ŋ/<q[|N8<" 2ӧĨQqf[zGt:a4 !nEeŋ FFz&ԓc:|½! BÁ%wvǎǟ~X_hIJhϷ-9n7*N8ǂGaV7ʪPVx*lW W&OXɅD÷Gp{vAR̭ڈ~ٍ/6c]n-m`/^<ƅc #iËfag-ot0B*$ B&&dE1 v7QPU)@S6|8bG:ؒap4l%B$P ***4m+ee))(/+UW_s=5WSkی|{I׵* TJ]P%!RHY%RzxxФ@EWP71%ag`vJTVV)%*[\Gudi8x χtL:?Ƕ[;mƝͶo[^s""U$"": :w.\pMO>mx>v1rp:kaCj~>w/D[]T`1ѣGX,qp:"77~#r|dl%:} E@$A&b=0ĂN_"""""jlQ0BJ>]"""""+$`0$voa0ADDDDD>d3=~P䮫`埗m^۽GJ ?T5\ _7R@@{6?P%%p8̳2rj}Q1 ?gΜt\@2` ADDDDtx` AD[q̘I=0]_RJ{NA_rٛ7myw t8 aE4#Šm]׻4( $B];v%%?Y|zYY7m:wnژ1c\.}!B5Dj 4-oF4%:C||^YVZG|EϚ:}Z*^RRc""""# jbݺu}f_s6}]8X` qf]4l!?3g^}vՆﻲ›_~YK:뜩}|m%hv$ߥ{n`΅={8zd]0g^Ə !0hРx(luԩ|^ܸacIPVVݾmk s'`wœouk^b0&ڸqCMfӈ͖l ozGZl(ma"|O][_ )VQF^JC={ZǪcݺ4? .|=ʗ[_qEO%Nz=޶m]Դ4SO==$))8EY+VCqq{UTPzO25EQ0` іmggeTmڴuyO?ΥmٲFuL4~]wPEL|R  """"j $-5/Blt$د(~ɇőے2cDxIlTJHw 4 #V %|>EƜLJJ2@mm$?v546mXޮF1vq6غu[mU×fM7VO4>lHzw mZ oє)SSlWxm_4]8jG%|>-48e;#ߵ6YW֓% cVRDi4Frri1G<6#'PUZ*/saO]'pbr|||3Qc AF ]{?c̖CR{5ZKguVР>}?Xukn\uu.RDDDDD]uOQQ;33Ӝ>C_:{o?vؤ=-'NL8qb番Qp8| $oa{BԜqI m\{]p7 #)saFJ>uwK뗗{4MAю6ݻw`fOU>pHIIQHQwj2P QGR⯏=\: {jz>qx_uϑSGtihw%N|}y`i)7tsc=6>##Ôc v~QF%N>=5`76dȐKGn[ӵPԸs;G[B׭sy?G[o֛oGnR+7fffA{NJ՞}SRRU5tRQ]i;%t]BYq/*4 Q,qϺɸoѽRE!ws.b h㠖UU'x|w5h43fΘ1#:0|ĄM7Wx듛7oYjUhȂ-7ߴ→z}211ј*"vܱcGm|U\\dͨk|Gvګw/PIaBXAE@$A&b]Q 6K}L'Bpz A7vBEUɤIU\.VVV4M~Zj0DeEm}tҶEAzzYb7>"""" E׵* THWA ]HY%RzxxФ@dya_AMKT:]0BRqqV8uˆϏ~uEEEr|DDDDDm.Dt]B4 OiAQtXnDDDDD5HQ 7 %AaADDDDta ADN6h<~fID[P@: UG47&+дK:$NWpa`&CѠ[F,:c&""""@:Q@DDDDDv """""".@ """""""r $1 """""".@ """""""r $1 """""".@ """""""r $1 """""".@ """""""r $ZcA37:9Q&Ktr|dwL>=Lq/_w&gʘgq>""""":]6F'`aQ߇F'wnU$uCE?C`""""rȿ9NI #>Üyg;Mt(R$tdxMkH6$nP:7IβBsM)ѡ "vAvn&:?N˫PF[_;Q ^]+S DQMP㌺ &t:[Tȯ1xXfVqIIu8j?Xl6[+C4BJ:dbtq[ ze:4Ǯ( ]{tt Qjд1g3~;Sk3k[);!:0 "jSTa"! HkԝnS̛wZSTgϭ{J܄[&;K[QjU kpysS8LbpX')>Fű:xZA& WBz;e2U(jK|?@0 "ѹ\)]@t (PXg\In&>^]j2tP !A1`0ցAžeC7jC$pg:pE<Θ{q6]:E ' 2ɖ`b AԵcJ uΟ^ObRV(: $bpxg:a Hė}.hD(BQ@ ! ROϫҫaPcH`4Xx? .L;[6@BUMbqlym+WTx^K :DxNmw.L!oWtֱ5j2!!R''><`Wѡй h`: %,&/ ښPXhi/`6{=L"(gR5Mjk|OY}.get}ГqJjG0Ψ A3G]1:HI\wu=kkkW^y؛Ξ3'ܳd(Athp-w3SUע{f^ߥk3^VK1 +}Wm<.C١t=nHC@@4 XѠi:,V$LtcZ`BJ!p9a6YNW-$+$:TvVFs8g xj]jZ>`0Li}W#C'y>Ʀ Lj); : QČ3쵵?^z lRʚ>c}ҥyDg%im~n[qZuf( BЀ: uh]\$ƍ˖.-uC:xHcWyҭIХ x(gBo"//+"ƍ4j4Sʷz 6T=}Tӥm޼ѻOoo]Uq &xE^zCJ R:֯_k.*,;vx/QT5XE.˪N8SO6 xkMEݵjY27w{q?VVZ u:}T˥8 =Uݿo_x383}_~la[urםvҒϧ~Zwis3RRSՃֽ ϓ_n!9؜jN)=N30Ż\eXo.0)Ͱy۷mMIIQO?̌>}UW;|+(ݼySMTJ͎9k~^z9)=gNʚ8ϼoAO ."n?wھc#)O'uKڛh",,0T;]Tv:n8۪,_jUyrrkpǟpBql;}@vvRjZgtٳ=3O޳gQU[pս]0G R<豓O:پ=/Ϲgng^,ÆOhmiiiu__UU֭[klzF&u1ISNIY辜kjjKG,f̎!!!!dBrr UQEBbtA(PHHH85=5CL&H'@QbI7mTݸX4)࿖_|q'riq2{NڢC3A;w0=C :xnEg?!cGs ?Y!Cchݾm{5jxl0ctp7ߥ3A1"cc]נT(!ǃXiYg: ۷onݖ]v9u~˖.-}g=Cɓ&omsߑ?_9q$O!+z{m^\g2;n/ 7=JΘK ׇݼŕPιFCB9qx\< wLu _~  MCm*&i,Qyw}2]w޹=XQ\^W*uth;*$^|}ex_pᅙ;v^|/4s`>N"ji~d\s %0 G t.3O,_SG% S"Tg*]#`SVeYp+V?!FU5&iʃo~ //6//9[Q^3vLR}=lYYY**+*K,TG%UqXgl` RJ(U5bbA1y;mP0Ld2CP&I|-vE: ***rسg 2OKIm8I{u^RR 5NfU5)_juy0ի@s3 aONCqW{)ߴ0D R4 <ʼnWwNc KRΊ>G[Q 8Yy㿙A?޶a=LYl޽{\v[ IDAT}otDUHPbʗ-__~E믽VbuB5A=P P}ʉ9mvxW3wSRH]@VK/-vXzĈNh1rdb0Ĵ3R#ɖd4 G%tx;/p}9ŋ\O\w z 1"ti×j E~zst뼺GM>i^b)%*aX&8]P`:*0&꜀*<]Q]]hf=4yzj0~?@h ύ://+o2` MJJ4("kjjB 7=YA9g!5U5߯?jciX<7Xq8<ݨ8J(je(+GbblMg]f&&%Uդ5o^Ye4:iv_i)Q@%v{\~o^{UD-ݎ!Aoo 2R.L{>#@!$n4v#fv+W/7nSfH$$$棶֩osCv ܏>Ȯ gq4hgM& ۱yʼj6S*:WQY)%C~YRZ^7I۾@:ԡ:բrvХxx1sN!CF@,)RZjsc[۾wQUsY2[vdGPElZ+ukqZk]Z[jVk*uZ7 *ȢkBe2z=?B0@B&!y?yə{όI{t4rWu֐83.wbb_+aZsix<M̂fPW]\4Ƣ&"1 5'gƢ #% tT@K('M1 ;TTNdϻ5? Z.B Ez_n;^ޯ3\.z)=hxcy7on:b ߰|{Js?j,iA=` k$v9j1زژ Iy Ͳ={"cǎ0#QHm[۶meAXYx7@}kB ō$"!!~UWҟ>cF{83ii8BE4)T)Pe)ţfaqs<ƏR38'ssZqnvÙq*D8BYEex/l8Ԡ}NN 23l~}xh?-=M3,S7+oiĠj:o9l~φq\.hl:3em٩FmuQdC[J^ Ky W.~K/ ̬S.\aQMvTDԇi*{+UxrclX4ޑF\YqRY:K|2@?(g|ҥ /(xܐᄈv… Wn "* *MaB88![ /|B(>)s'{뎭]~W_|gʱ{S~}ѥU#okuj Y & uߪT (pVf,f^gϧy{<f+55q(HЍx\ u)\.ohG#6ڿ۔4PH{#C_85! /Vc(E x?把ꄧ-x^vM&!pP=DykNgzںX܈stphUxc{L#+ݽv]w1W.=ބ%b;va>bڸUcҐAQ[wcb_(*p{_lEz<B --MWUM<"M-l@V$ B 2"`0aD ";* rN^(5qw]3E/~Rd#)RL|!`I bZꬹ5Ϟh֐h4j%r@cA[%kڨZ04;tUYYyXKo:2\}{=_ lPvB(JsEVKŮ@ך_iݙMD 0@19O{Kw筅!ӳ,5wgdv60XzWJ-H{ ]a `. 88vZ3"yfHDI DD᳼Zk|.WΩZor6tKQXQ H-4q2(pee:])w[%,BEEm0jд-{[0Mjk J6i,؀NT8yzpzQS "aY"nY{HQwgggj{A^u>˫;;{} nCs6G=kl #IJ`߽&δ*)P!Z/C(%Ҳ[j*krР56_Uum:χ#mGI sQvml黎)se ZG#&6 hN.U [T,}V_eC*N1fN0ƥz(D_W0VkK |օrVk +R|XfgE""#K.lfJ M."1il\0o;LbA_/F$zn=NRz>!- %N'Q/tZuK3vp6(FSն5#""""/MDDDDDDDCHQ1 """"""c ADDDDDDDI@% """""""J:DDDDDDDt $(HQ1 """"""c ADDDDDDDIvzevaEֱDtTbҞZEcR;1&"ASݹQOٔ#ӄ]W")-!eMm4zӞG!R3TDz%QHQMa8q|Aq@`IRX- +*`:uP Sw. Gͯ?٤l) K(~ uޗvO4/b ADGXf'RZBJH hOD#1 ܅U$oBDDDDta AD™edj633Xfp--cW9^h !espBmyKǜʟt1j*]?s{z칃.h9d}8|f ?WaEQADDDDtta AD"#s@agP5-#t]wÜ~q_Uƃ**Z' .,ͣף^d\w `Z־[(9˫-]Vw낁 U:n=%UQ 4!%PU *`҅PUhP a)սsH6\l*JB+k0~Z;@DۄP`;JqtAm5aI@S58NRp<4mR)%TM+ MUљ `A)?3SOHIqjh8r{DDDD@4+O=[w7/F" !"@liaJ`LD8B(܄@c̽}BFP HzXsiIIu,Yvɒ5=r6j7O;#7@DDDD__AD}(W7ŗa1hzǫat^˺};jaJ ˒0)iI_#!v OݽBư$VMv2@b%BH(V3gfa$rgegjcwn.;w튜sιٙ諯RY]]kiwYʎ[x\|%۶n \?r(egx\9o/ݲeK"""" $Ϻaezt˽Pn+wV_fO@_|ypGӗoE_kMh)ЊGX 5|+rCn"-OU@m )3.dsN2nxoQQiXߺuKhɩN1,(ngەO?a]'MM>}zoaCUUu <953g5]\ҟ0%-)da,IDDDD݆ļ݃zpηNex'*P[ؤ짾}lmמTY^F/>9;~wpmx&%RLK⏟wWW:qY쯤9WJxCq7G=xF|[}-**vz͛6lW_}r9qꔴbEv7ƍ-#^}ʇרϿ ܕ/~&??ߞi{':_""""0 >@5s~f6jWfjș:2xdo.Ì[VZ;E@M"x7#ߛnWĉNDc{CM,Etu%j ̌TUUZOh4Vl5j$""""I $=wb"<]_ ]wq(?7[ xӎp?ro )]ӡ*tMi0嬫iZR=]MuMlI.0 ^W`ܻϿމC| y`~Мm;д?߁y5hLJg^ŋlϾ;ѽ%$4`9 ô}Kv#.aiz,91DDDDD@% l.bكaX£:籸 8*VN6W3$V}ÃMZ.6wr-Ab}y5eAJ )CҰ<7:gwj04[G1 eȁÌax~kRȅu\?Tv6]kRUsK 眛3`@駞Wr-ٳg:ujڧ~ζ]{ui7 2=ڳa×A]+p\YB( EK;5?_3cșx㝏KP!ś UIɈjghˣ%ݸ)l4ZKQ ڝzqɩӁp9rWwrkg^Ϻkkkkc#5MHzGK?hž U :u˭ H$l?)Dxٲ3gfs}C7|3!""""jO{_ڄ@ ؄6!B!܀B'@>+m|." njV53Xtus|)-Uw3|pGZ`p5%x>閁QFf-hܺRzkZu;?yB_z g sISUMKX4 $ [[X]!"""":"% ":* $u """"" """""""J:DDDDDDDt $(HQ1 """"""c ADDDDDDDI@% """""""J:DDDDDDDt $(HQ1 """"""c ADDDDDDDI@% """""""J:DDDDDDDt $(HQ1 """"""c ADDDDDDDI@% """""""J:;@D__e"""""HQQ5} """"S6(HQ1 """"""c ADDDDDDDI@% """""""J:DDDDDDDt $(HQ1 """"""c ADDDDDDDI@% """""""J:DDDDDDDt $(HQ1 """"""c ADDDDDDDIv Ԣ)YIn%5[W2rm`V,UqdEKDDDDD!wz+yŎ(J@6|0*<DzE2=&""""n@z]hw^buXH3pAd;shۺ)wXե(֐ SLtjX,+:puõc&{zEaa ADI I婡;]jѲ4LJhÎg(ADDDDta ADIds( ݱ 5T{QHQr))隴ܐ9.}1WIDDDDD bQK"J miʀ5#0%t+t袗jx6iW])Nc_`g_3q$ߥ/˯D,袋Ϝ?훫bݹчY0q$ߴi: $4M4݌-CC9ikƠ}EZ$BM6CYn]u?mDԢ Dk[T *Xy*2jA 5c)݇iӧ@yEytת&Nζ >½q w\yUƏj*_~ʗ_z3mƍ*)%6l#lݺ5x&MSE@ccrG 4ꪫ N;,7o_[NN>p`/vTU}UW"V\k韝eٗ_Qpe짛HH̽/? -ܲqǎ """*D'8vI UD1'K a-ֻO3E48xUúkLTVPPӟ4b⤉RSSu0emkn3a±^),--qcq0 y?>UQaJǣ; DiPrm8cw!{짵ڟ}99;F5ޫ;TL=it:RRYYeADDDtd "q;K?2JUBDC !3x4hpغNjxG~0'j8iSO>)_z4}C=.é>S֢EnGtD;Sx+9N%Y7Mwledf^W999̬QK,}w*F8t:˲d~~6[ny4-[n8dȐOH{ٲz'lذ!o.g~lE5l %%#_~EnWN=)eTqM#K^R]!""" "qҔRZms<@Ŝ$FC"bHDMy(`GZ!/8qiӧ |b|^6nxoK[]ń zdwIg)ڵ3 /V#6&Zlܸ1`dd6/~ݺF9j@a_~yTmuVjHM?e{D+ʣO1jÚsp8d})¡鯯aPS|e0dWvv Li.>j|w- !"""` AD=N6TamYMurü q 1`UySA1lw_hw>O3f⧟~FYg}+;/yJ`iiz;YD36麮7/9zhݲhd>*@;܇ytܹsꉶITYyY]vi1]hѢꖯtrT&; }Y__ߥDDDD{8ez寊iŎ~KȖ:2l#< cX)ޗZ q'jsx0``'LNJ4Vud; i(b_خYᙧ.b .0oԨ]7yZ昱<2XUM^'Ӧv.**vN2%2k,t """# "qUAuq~o-U\4TŐTNHrЕㄗli'eY+.Ku8qeu~!8g"mjbiJUUEYYyQ_׬YӸf͚!C7p`\c+W'ڦ#sܹ# EF#f,ZzΜk  2ejU""""[8ezmL.ohDv 팍K;}qm6l ֭[8K׶n'\g" ۷o@q@y睗|f)HM܈U>nczfΜr,UUűN1 iigie˖%o-m>6:w[/Npxߨa#Fu]iiuhR\wcٲquCp8bCHV툈mlȵ8{ !PpـϪ&{,t*7vziӦ#-V~AFiII,o0Xgy翸c0\6{.}>L9$G+5jv?EW]X,&4EQ=TaÆRk`|\;bݺuAϧu&DJ#[?^V^]|yHعsg(XvC:ujԩ# ~/zh)n9k֩vC.t """#GHQϓwRK=v0<]*;T@@e0 XYf"þ#tԕܪXH_LImnqow[ٞ=m+++7n&ڦ<ᣏVqCz<-##CWEl۶-ṷ[H(زeKwbKccHDޓO?߾[l }][XB5(:# [MMMfcPl o▻v 7DDDDtiL8VP(B@؄6!B!܀B'@>+m|."kg+ƺLqDQB@Bg֞ӗnBW<,Y]]k&B"ml6*~rBłٕ6PUU㱸U]]upqnɵbQ.n~oѣ={PxGK_yʞ]~e jD AHRF11q47Ry'-Ar%vvGgz=&t(҂{ÈiH6{a{FKc"mbUVV=T&HIi=)7diiisW\YHzgۜADDDtc ADI#e+7n}!B]HRB%A4jۚq{y6_rȋx:rM25/δ9N^z饊@CBOob "J*tUc+6˦:e`W[*U5l7/bW}p( ;b|*{֐ ^!oXwȚmOӰWc o!z4}ԨўX4jmٲi/DDDD9!ADGpFe4}EZKmW#ۖtғ7_ADDDD݋" kJxf7-Rtα Vd:n}h|eHQ`l 1l """":z%% """""""J:DDDDDDDt $(HQ1 """"""c ADDDDDDDI@% """""""J:DDDDDDDt $(HQ1 """"""c ADDDDDDDI@% """""""J:DD] 7fvd $:KFQQtƛL瘱E"z#Uت^ua7pa!+vŊVC")iEEk]Kv\p\;1ϒ?5E@eKVwD0 "Jdž2._jEVmBb[%7r+$!ntj)3& -HHl]#=>dQC‘vUky $ "HiiYO>g~EVX'AR`T+q `AymfOtCcb~XeKX8|& 7: +6yو#Q7` ADBlzF"Q/uKZ2n exO;f'MN7A|CX'AW_9]^7> \~%^\GbX ]S%MDסSۄW't44.-tלBީ 6keʣa^۵p>u.ID"#sӛE (B/#x@O5]m7Fʸt_Rc13-I]#y^Uƒ+S;j[.ĚH0:> fjDI\.u)YY:;AΆ`d~п1 En =OUNoJi=.-=M9HG, ^awx]lmwz:|ҊGOeν!Vf 46(j0~¾VWW[|!+yKq8ԩDM · jJֲg/'"-eAx2lwv[_L9fH4}ʉSFZpaM N; .ky3Ⱥ7͸TU]\{ϹGHIYYYHkrVnf,{t c =^Lە; ք,Lڹ^ 0n/(I'ff?LsRaed Vcml PJ9Y۷o`Augݓt]sn /P}#C_; 2)x~k#"fST(@( @Vl2Evn~?sW1kemjj:3̺ Hsrs)ꫯ.x+~23Eu]S^@NMn;7hܮkpjɩz:twi:.}{p넁Q\Κ>T݈ay,HIAIgZZRyu)2,^\d^9ШQc<<,t$]*BXVC3$hn(@JR6קЮ3?%%LON7 E)3OظqCSqQqnGWinSVp8dΞ}! 05*P/MK VsfK^_` r0}ו\3k><_jeY8eDD)LgGu##W(LU‡۟3gfa$rgegjcwK.4dwIdٲZ?w c'NR0ezz~Y.Pll K/ _ۿ+5]\6{v?ǥΙsM!-[$P wy]vg4<:3X֓n?ĀQ=\S߼g[܎GQE߫?YcǍz<H("&N;n733h0-[Vv (ruYz+\yq*bWliix^}r)gl8ssMEj]tq믿^gOi]ټi?[NL ;@fw\, -C0ad TCcl7|}g :3x17:9BQn[paMKH؊DIMKO?́!ozW~; Dzjcu8 CƏ^tޡBlݺ%4|pyyvz}.^G_xEy ÔQG7mT{w3[kiw8+**`wFܒj2BMaH˲;t16EE?u붐/5U4:t]"--L  NQN #fS0LC]n̳W\p>syȑp.;5_v)()]e~r_® l}*4e)} 's'>\S @JW~,Kܵ3tnwO̘93:h#69yGԗpQ+F,㶐y`!z>;yTcB`Aعc'*u_Cnn. ^QHO'd(򫚔zci'H("6n,۳'2S2ϟn:ɩw-G sؕW\|BT9eIik45K򫫫c|x6CzsWb`VTZ=yRk6 Eu8w>ۍ =#vqǝã-ZXhUUձmp 6BჂD%z!ADԊ۔-)Y)iavmXBfyyy43 kM%K"3f~udƌ`&֮YӘk˷>NMIOHH)VY ("b׵ubYuW}UnAI(!6cLм_ϓp3;d9STǟdMO߰. (J){,_U辘8#=UmMm* 0֦cO/̿apj00 IpĞ >K/^);SMO7].Ţʊ.W9ޡwDG DDmجR`*+k=tɒګAS*+C9< LxhmRˡԊu{E~v"NŚg( ; SYNmX{ <8Gپ6M>c }7^ƚ0<ȣZiMNgR a[O^[_s >Z\.}zm`)xQTy&< TyѠ 4Gc._6e ?z*~xu ?wHc a{Vedg͚*SC NӐ'{{r-8eыPQkV__^vmiӒM;5i]]wew`LeBzְh24CSSÀӯ!0`ϾD7//SO|^_1 ?ፍ+֎ßxO8>fÆƪPg LLJ֛-oN"'')f82B#F8`ih~:9d&/"4$,Ts5V vܝ곐+&>-uCLӯȃ n ^y,{MM^4 gTVVƌiHOxѷ+$0 hl0J腓%d(p(kۛ';~}R}] nh{|:yً݃?k2RC YpaUWlQ^^LNN;6~-^.~QO<: r8mr.3̮-o`ʕ+oNK~7~55!L}xW\ws}݊̿6gݺu _|y;m[s͞N~%GC^fj"_~k^+=욂nGaAXJ둝3;պ߁vS!H~{RF7o^Z~w+ڜ ag.hVqc-[V=wm@i!G%:?(wŇ"tA^ӭpгpǟpBO~kG 嚫WՠaNXc/XK/˺袋2ȼeK,\tŊڙ3g冺t]Ra=Z֯3f7aEwᐹӦMK^re}WԄJ/~a[lȑUY99;k=+ϗ_.uӑзER~ILKC'wo-w`!=}A}}cP)}PW=LLCavʴK.uWSS{UWl{V8.ʸkHe˖~o}tKh}/!H! h,X؄6!BI!@2AIRj ؤ}(1gL!!((|FLӰS9r"mQ#H4uFˀ,Lkc~I:p9+eZ/pN۝R 5u7zQ^QIlL[<3v]\ p8\\4v'[úmCўCh4)e6@PR^(WJR!!aD& `0eySBEM"wJ~=l#i*ƚ=E}5.)pNw@Ҥɇ_$!l:,ʣUR ;rEBVG}ޝ#0 ֜C̊.;fy?#Gs:cҒ@#}͡g nt,;k^_7x=ϿC=@dFaB`'́1TeeU~o}[0 ~ap_U9)?+clq.H $3Ѐv4QLSfzvsI3flmۚ©)束^PPдa}>Pgޭu9p0(D6Jo/B۱D?(#b ADԎZ"ysk:eֵQY9'*4Bmr=$ #q7A9'xBb\\E|\oWtI0L+˝~$&%CW@u·NDwQgݻykҞ r6V{S0.W(a" ia]cm{>=o!7aS´,b&5:b AD%Gcqi9j&M֝iZ?A~w*?l|*lŞgY"&"|z]]zp8n^Male 8:R "@jn()o&5g`` ryP":| $!j,]v)%&&#d7lӼB5VP5RjQ!ÅKKPԺoi4xb)LS?\y~":(ejn79C[?uuTԄ0 "MĒ`P抭m~[IZ Vmذ:׊5,hi8XXٞajGK+j\D  """Q+!qW)# """""p(?Q1 """"""c ADDDDDDDQ@E """"""":DDDDDDDu $(HQ1 """"""c ADDDDDDDQ@E "$@\\5)9c!""""ML>8?˭aG+lvV|~bL4+,,jH)e96y‰'aq!`&JJWU09Q5wUHр6dHnB||OhϞF4)=c2q~BL:nA?!J+ J&v;={6.R|CK~ 6o^mڶ}W]86]Hрe[/7'meP-_\BC3bcc[oUCu}5vU%ͺT8"DRC LrNlj'_=hf&%sCnڼ/ф X ݎ1GP(Zz-1NjSl\Z{](bKia#"."_{|&Td<#xp7.4M59&0 4zQSSE+V`} daP7*ģ  a[e$R@ h)P PL`(T3p^w?~/jDDDDDHQ,6;%o/?0~OcM"C{cFUU%}/qZ{mYn,XQ&,MJH+J) M!̎ ܹst3wNs:]=#@ )1 GO?EMdl23|qc !X-vUaajiinYi+VPQ]YgΆG Mꭱ}B=#81C!7 7y@Y q̘utĆ}aY4X5 &#UR€‚!\kØ T RHa¯lj؈3NEƎ;:O+2S_7z7D/yeDc3h0L[pwM zO!&O u:,EHDB0# ` a) Riiฉ|.H$&%Z=onZ1<Hw "؄PJ)fv"31ǦC@݆sq%huʴD ? %~?IƻlFoP7pæۤ7yjDeee/WGgBDDDD $hS͍( #\ ֗42/֗6b1)86#>2u!^6ZQׂ~\om93`*%a"&Ɖ{gDg.s[ P-ۓ3'5?HL 0^qɒ5id3g~o_ys%%Ez< sϝ6c<to6|99 ""ty. aBJ )% j1>DžiqJi]sh lE5^ވY u>%0.Yaf!ikoΠA."W_WTToٞxO W 1n9e)I/XP`!7aDW~~Ѿ\EdzG?kԱ+T55ᝅMcƎdžw߽ vhDDDD40 O)yFH ٭D'O7eQVmFRfҟ3SR_-_8 qX'0B!8ؘ;h7(o7\is϶P(d%k;Ns/^Pλc]|PRR;pa"o{''1 """#e?hS?eZCSb TJ)54 Im[lfgNC26 EHԠd`cwCnO۩VU?ѵbږ |S?!PkQQQl #`Ϟ~/[V躡KJnDDDDDG x[,(..C; N6URJHMBJ &!Ł$'‚(nc=UpdrrrW\qy믽%hJpY,MTUUuAQ]ULi z_:M#2ƆMRj  l $h|Rņo6J i"`"R!iZ ع[a>!%\q`يeNuR;\RR|?3 &&FkXLLCٯjQ_b AD^ǜ7. CeegS8ӈ-n4QUdn\ Kpv\bç}*yOz̰uCHͽE{njopaÆe?""""@4W|yXWaM jhR@!( pkep| pgVlDf▩.߆nU\XW^yE,7++;j 'x\ ,wߓ/5!>ʖt?""""U6_ՋXVyхgU")<2l4x`Yb@&4)tԢc:JCwqh cQ]]wRi5 GZmr) 'OIh[oY+jyWf]w heAeeekψGDDDDz3 }KHRH 4V6!MqR8@ L@Z#6ib>/":ʥe ;M((|G:/68bwp˵hlظ8l(k¯?ۇ޺҆Ji l(8<{VZe1~3I~ӧ~Xt-"ᰪ~DDDD406MAuJ PhTJyRT@@PL&LDkբÇ5.pL!@BhB +" v88͙y?." <5ơYlv!ڷ윩 k)evREOXyϟwhڷj: /]})*+tXgo)-^NE;V gZhu f'01ahX񅧢K~R >,z Lz8P *  "CA`4)D/ =*#a ҫ.M[PYY`(1o­7\NY6C RDK xs}+w8}iXkbADDDD "t]֬]._݀:xMu9$Dډ[8c L|nA)0qVkd/^A8s0tHj*xUHр fbQo.BZ PuLWZ?*/>Km]l:2Mm6$`VUcCɧ%"""":0 Kus˶힛oεer|ZxpX]@Uum#1v j IDATL,YiG劷Ci*a """"<6$j몓32Ŏ;+׆KK*vB_{SG!0!P8 p( a=ܼ?QM-Aɻfͦ={Ks`4L]@@5  $hkh54xZ74O @E """"""":DDDDDDDu $(HQ1 """"""c ADDDDDDDQ@E """"""":DDDDDDDu $(HQ1 """"""c ADDDDDDDQ@E """"""":DDDDDDDu $(HQ1 """"""c ADDDDDDDQ@E@D]iX{ DDDDDttb AD}FJ-c """"lQ1 """"""c ADDDDDDDQ@E """"""":DDDDDDDu $(HQ1 """"""c ADDDDDDDQ@E """"""":DDDDDDDu $(HQ1 """"""c ADDDDDDDQ@ ~7I > hs }TBLPW6JO ";J@PJP"(3 PB5J51Buzɱ;=/4Ă ";͙A *: "ZC(tDD>ntt[>ADDDDDGDg: "\1aA(@5WHt[E!D_EB#}[0 R :J5mŇ>A #MHQ1좇pTQu㈈[JnntQ0(&4㒒o/BZ8}Z#4l&"†fONT8 8q?y!4M-_Rʨ]\v>ܘg{nLjj-'""""&VHQQhmNۯ-Npaˀ::TLo`3gH{n55>겲!\.kfFA"p˱6DwZ!LΧnz h!?(! BgbjFz7aO߄T-j#4Є@A)  bbcLHJFö2|# tXT6&$Tsz7W!&&V3ft9sMnέ 폱Z"!)x@eR$&&Zk;F!N;{kdBb@G S)466;F""""0 >#Ts fC Tz/^žJ 0!MUEPRBօ:ԑ~(۷/e/YaժU ?p)krV\Yr r\&LRB)[zŅs ɞ2eJBK ǣZe_|7gsNkej~͊nyPZZ f~ΕW] ?; `P ǵ^3~DŢ (ر/l_7ϙ5kVmۼ}{?HزeO?2t?X""""6ԒNs knYKjapȪ% `W!z$1VBJ6_J A{Dܺuwue?cb ;;vqMr)TIII F{'G vi;>놊L?!vY)1mڴo)pȍ6z37/}Ҥ -Xaw8R44I&'0l؇Z0줓ONjfXcǍ_ o #`ԨQq-xxbڪDDDDԫX!AD}%th._- @YlB )}Bl!fk6Doڱc{) #3^PPtS!{۾k.;%a\~e?t[JjaѢOj4M9*tH4; 0 L'RiqrbbJ/[V;xpzsW>[-UUU<z8ls}Fqp҉IXQ?V""""X!AD}Z w,-ęH>}HJB0 l^#?A5ODs @!>>^Z-&%mۛ<;%6n1cAo Ϙ|5d'&&Z6mYzuCgʲ?OZh ~zS<>Q_W 뺡V0q voWֆ׭[…Ur,cǎo_4PYYz,k>f# "3zH@4C"3Ή'&ѩh_gPU+ %0EftD -o}zFbbj,9v_Gijj2^K/,j aƹs/]_.?ns8˺^mm(E323-WֺIIq֞^'HQQh "fG'ukx#$̛͞@#@X5TDBt0c߈%ƎZMk.UU={W^)ۼiK/3fljg5+e ~ۖ_Zmܸxzat3wEkny6mϳ'@@NmMv*t!./ZɗűG[ÈښkL;QFޢba(MDYپ?TxlذaϰabxCddd'ZjK.^fݺT۝w=GnR]uuVVU u}lРAΖ;[9#;;۱gn?j=Cё` AD}GayS  wNLJSu;~PLH(%!`* $$LSl4S6Ln^sҤ xĉǹN=uz2azW 'pbgΜ^dI YUc„.غu71)z'&iǟxM1wl_Ypqg5+eԩ ͛;TobFgUqS7UCc櫯O<䤡C̞=;uٲ嵃9:kV |~co<{%g-.˯jپi Dg:!X[S)<˸0w,عX њX*(Ek Gy7#8oyi=/6gOڻƌu=P(,RJg-޺u7.6V[soYYY _bƍޮ36.+;޲e`ǎ={iw8)t)$O[PHt*8|i*ǣo۶o~}}/\Y*>>vRJsN_aaMMFaaO)ĄKNNCJ_O?[ eh?ɐX-455 >4F,//wuc>}aUg{Wl;=c۶M=`AAzCW͗4@hlB !qpA A $)Gl>|^DtHI ` 2K>5m}a]n0HՄnfӅVJ0 :ZWMk6ZfɔfD}]Y%BQ[S:3bZDzz= 55a0:11N-ٝbfMuu7ts9s7\*aBfuUU%Ti SlBMP (BB€2 `0oWra*$oCr:eT@ZBH0PXiTW,nkHl~lEjhSP,++ vOSSѶ7ú*)) t7|]W 0TYii$"""":RAD}&d)j3El ϚX,P TP*a*%-ZgnCK"""""VHQyG7ְ%+ZIܾR֊x́CvP O "3-!Ï~N"Mif:)j^2tVG$-3nZliMaaaw`7q맟Ə6͏h@svaBD@=6LH) ۷7-^fE5~W{\uDgO>tC* mՄ42;H2ہO^Ԗ$""""oN """"""c ADDDDDDDQ@E """"""":DDDDDDDu $(HQ1 """"""c ADDDDDDDQ@E """"""":DDDDDDDu $(HQ1 """"""c ADDDDDDDQ@ """wR1qʕjSqVXmR4Vӵ^`u*w ""A.G֔,-6 i1LekMʭՀQ/RqЩgf&./O7@@-"HMO8#|% ~8++`x!ÀtBw:LMGƈç&X6.}L5T0Nt!wOnRX׫V|qS{D "Єaq杜c'N!:T+f}J1&-\SPkx˛zDtx=F ^@1|jkkm+u5Hu`Xn $!>ց%5SZ[``ČXxf&F:^yp,s"ݛZ8UC 2qMKeu1+%z "дXٴ*dynү?bgV+@){fu$~βR̜r n,e&@# kX7P & Kec&@OʴnNj?! 8wO7&b,@CDv(3s;D h#a3sW"]NDwRȵ?7Ӈ8_} kc#cƋ%BPPpجp' /+ #B7Lqh< NPJg&<~~DVK!Z(sۼXS~VQqHK]D$8hAD=@Ehڄ$C7Cz5a>PכHp`  0fu ;㥐=LeXSý?< c B[Èan vcw_=^|o *k7aD&%p,hsğ_kBIv8wx obWi-RbqS!uɫWA: Ʊ'&ꘉº˪: #ڪ ti- t(ifΣ3gef].?\D"fG)xL9jXeFN<%~pauϿ6'==ݿPy#uvg7~yh>rp'ƢKZ/j4faT~@"t_wKeHQGoݻ7PXXO>PD^ۏKv|VuG7LU=T<-S6zz Bm۶~N̟mNJJ<0`~S*_{};3SJ7o0 !0kԝ;wvl4k֬dW^)ȩ=DDtݦ oRű1{li+?RyQYxk|/x !}r!~{^rruo<>ڽ{j3zg- !k&Oʞvmmico_g; ;;Ǟ_S6&ȸgHs@]~xaۂOY>;nvǩ'o;qUgd#''qWgEs|}/"D*%C6tovvZ9֝،8~c+ʃaDԏCe;y[nMW_uņ;v4r-v;߇e˖ v ӓkkk7n /<_L+$ep쏰mۍP^P$ZMp5pf9̳R֭[۸cyOC3gtcOQQ`޼RRܶ}wy2v_4e?9iii…VݿRL<5~DWJJؠXo%[Ɛ,+֎Txɗ{mUN_7$؇/qIF>s`G97-tt˯"kgaoժUGꫳcn9,Y\SPPD斟sΜ!1@zݺ%Ktzҙ7z6l>|Dl;w;[rruΜiyNQ_ɢ͛7ulBJiE~C^ AE*s|> IDATFdVhyh>_뙏xl^X|yq]KUUe&&%YgϚ2dȐծ|Ne8sM^{1/osΜ9ixoqwS1u ^D~͛^xQƠAW_}uߎۛzzғ׭~8p9smUU?hCsvZm--) ݽYӧH~饿&N:ŋմL9s;.eyw*?{Uw' !B/*+*bok_eW}}EVEwZ]]{HU)RB $!L&e&z=CBz&̚:9[.13FeO8ɚ7|s.&Iq 7W._^sM BNYօ@6jPf,ЫH&ܑw<Ч4_P`<` ˥{ b*Gm^vMuj-bԨQ^#Ly`yǎk~񥗲 Z|VŢx/d͚5+.##%8|9ӓF)$z8\{dp"OVv_Ȋkidgg_RRt 5:ٿ_ ]l E;#Z 9rh4*֮]S<&Nҳb(f_=;f]=+nڴiQKl;8} q;Q BI{+B 0,]  \ q0@]R~RdF*qiBݡ}Z~;QV}9Uod2uyFi $۷ϟ6ͶiӦKNN}oEo#g֬.\Xּ=>^(ܳgO#,^e?a&O~駕P]] pWk 8q`; .)RB$ tMX MP{b xӟ۬s%fN${_3Xݮ{6I>g>@ V;Ŭ)SD^1J^~Dnn^(;[NgG[ouuje4r`LcFFZ@ډZg&xl{ glցDo^p͹=43Zⓒ4SOow$>wܷv;~u\~1ߢ#PܫbJ~'NK.n^6'>i-99EY{I[#7|K|uuuGi9]`e͚iLeee9F,8um۶؄Mr_tt*%%U?ԍ;ּbr 3zkk/DZP B_;CpAgnͩo(]wD}1Lԩl׮qJRfcƌ5[,ngvj7mАkhQh9#9roy+2x,V2..N]_ Zݟ!$he*p w2 sa著NN\81pˌw{4hN|w<\JaZnmm5yƎm ?x}2?qu_yuO=#7zsؘX=ήee^ժugt}>?~.Զ`.*n!aUq8'؍XO3A ZFHIIm۠r 7r(w߭.!I2;oj 7`Swr8#F4_V;O˖-k FUyoRⳲ׭osCٽ{WQ8s#@cǍ]I8u˞=>7l O8z·ayy&F@^^i/{9P BIxQD9CՈc>F8Q{4^9 0zoߌ+t;|ja絏OnnnO8˚;l 5AUum]CQ=zLVc^d&(6gPNnJ.KPRkĹCe˝E4?ögFȚQDyLfB8ѡ+Hou?De/N 1O}ɤP*U3cf̜Nǐ158GB(gkey Giz|shc/<|Ie3.}$WUUvMV]UϘܛ((il2)T*߾"ktfPYUh˨/{gzjLFym.,/766vS1Nv,?nER fS+EcNaƯZZ=axƍ Lfl}[_}uK9!DŽnswX-qXkU)Miiy' z*@,in˽hT<䟋΄ӾB+3Ơj;W:X zH0dj:R+ڵkjaÌ&Mٳ}pp떭[q;8ɤUm۶njkjwMIv@C6!9ʂ!@5$zvu)ݪb8]0Jbbʘ؀Rs%OX}濁7cVX_^/5qeҥ՟~iew8>~&;;"1q7t]iil=IJNZV}Z8y4hPxI69{FT;e5YuX csM:N 1ւF,YбvM945&Ma:]D|>|whNnDj<8C_\TvW袋tgn=ٶW:\Q Fr&a %S-٢<-o[FN94yjG ''%%<[nq=sdg_smK#* #fQQѪpz[ormׄ3mjYY;#GֵJfٙp-[F \.XXX6l9b)'7׸`;(.iSeA{ϢrcRѫQdt/# Pw3Nq(>Ryiw=ήµ]oOJJ֮X6u:13ƬPbQu݉zՑ_%'e`h0;PQi_g7~oY18#C?}\9ٲ%F,7Zܔݙj:N.445Ϫq"# 3+K5?ÏW~EZ C7x\+I2[li|pxH7=4iOeadxl۾z epc8t՝؊mAZ VuP'8r[2&U \>k2ԁ4BntIuFFGMBo)?#>MׯϏ|z3ګ?b j:믷v PVV}/rg$Ibo'z:ӣV,_:pꙮ]zSTrg_cꪫbxkV;W\ٛK#'T) %lCQa|Lv9D2h „yY@{r:k;wrGN9XdqN᯺؛o9%\vm /[5>4)N3ղA4<}>;V-[Lf=ޛt${yX8֯_WwM7 ڴiS/p-[~i6mƪݻ1++Ke HĵՇ@q4}8qZp8qpFfY8J*~#;8]3w' >r_q_Z6xzL?v9G#ll+<  u$IƏ˰_+o<$寕+~sjl6+j` 3FBVΚ6繈H >.wv~3]]qZJAPpuuA"=NrӼIWFWKݾzb>n9PE'hyŬt:k`@㏇[Oٝp{VZ`2'ڶ יXʲ:04%3xc>X@@`diXO# yo{ߙ۠_Y{3Kw-ݦp>pG`>WfG0Nx?)-$Fυ 3^(-s˼m8#F~k)ʎ#'-Cb0c,^X 8I?A1ZpG_jxT~N-ݱ,ˬ}%wv~3]]c 3ss\^9;VPxIPq2j9Z2 .M8)g2 ok6Ya@$V]}beʕ6BvvA *>n.#ykQ2p( A9)T?lSwwc 9ˋ\ 4ܧS>|Hr䘋uCꖛ-k++xjUqMEȯ$}D)WyHJj4ºi^xq0CYGd×M>?2dCLG.\пcJ\YC%=MIT)܁mnmR4?[[΋S0RqϖGNz⋣rrr{mr54l3/)**jھm; / ' $!nUrwcf^uj`7f 6'/m 4LJmQA,[o[ɉգ`/9cq&Ibd#"gcզQ^I(#nEVJ!3\^hJxDGgjeBžtY'ǦjkT7 hN>ؓD O^˹^1nǎw  -Az|]W( A9I?)|̦Qlq6w9_&t9+&ZbՎs1m)EqI%IÓ1( Z/Q|˾ wS޸8BY僊u;!d)z!S(!*=hր5X[`p_fy_ }o}G BMjjbR@ ~on:Fmc݊] AtU7f9]U^_di~#P+ 7C1Y _L,$M(!=k>}_M邙TiOp q/Huq!*erS2#c $ ?T2NaP{ԋS>v[ymkbH "7$+}a'A:v G2{, 9Y6( A!x:~Ls}2YfY\ᄐS'X&!BxE p{{v4R S pwɤE̹irzi? !$]nUivnB鏯:xkse!!I;BV+'o !BN; B$!B!2( A!B!G B!B! 8 HB!B!dQ@B!B!B!Bp B!BȀ!B!B$!B!2( A!B!G B!B! 8 HB!B!dQ@B!B!B!Bp}kѨLFq'!B5!!..Z?ܳb?Vն1D--U3cFI;wKNƌ6PEe'R9Ͼ"SL xBmB ;G d@zd0l "T *rK@&\ڬ %'Bu3Hѿ1qT4YOB<1hޠ!*e-)Y5y.3nLZ荤xu̲EFK۶[^Yz\>"T*kVvzof gVw&^7*gP;rfhp`{LcUϬY~~N?WC^p#jSYwL{%S 9 8( #E6i ,Ay }BiKJjMa7^xN3#m)}Ҡs @suI/\%O xV&h~M|¿޾`*UyLBy#c"'H3i$QR_8tH25JKx:B* ~4nO_C9?)*ƍr桀!)Mf*+e˾+uʜHQ D9"݅upXMCu%'er(wSrK_,^^eY3F(Y/5::JȣJJKDĹC#&s3E{Ie<d}7yb yYA(T 'C#)J9O>2#sωUZmQQ*(޵qC B?3Z~^bZqcÆm7T'[F5ڪ*: g./mܴiXn>6.|p`g6VqRĬ,Pls{jz1vhIi\ ^[SBN6ɋ軞8T5PhEEpkZ~i{:_8:/ƌƌ`!2뷿u@c g<1?qT2)~o鑞,B**yzCCzDyN0/ꯀ'(n9opӓO>5'pC B0LQYW%ne5{~/,|Ŀ/6eaU^|%Q)):'oݲw,SVBy!:Z_}A W_K%nҋ_v(0tU<&~NLO|7xcѨwEEEMWڵkgW^yFm>dTnW~ڂk8uHo%Uy m:Qف<_~eu0@%vE_r8j+W.w<6ժ`_8=jp`8vXSS#W?FK5-ǡ% wq-?q"ZRAٝޣqy`9p'##CLPSm̘1[n-h_ 14kϛ YiIwر_z);:Xَyo 7RZZu54snc7ӱĕŃ)h2pbloV0$=spt/^zWazrn5 4y&O( 9ӓFf)$Rݻh2+zzAưa=pp%v] LϏv8=$ AyŪxz3J+)) 5111j 43>9i}EEҒOA99pwN{(uakO= 8y /BV\l'/`CB(vT/!(JSο->0&bZ|UM1q.a{ Ce[_vSl^n||Po׬\OsDƪ}hoѾЃ^?Κuu_xnx|G5:hu,wwBz{+B 0,]  \ q~<6u}}@-VC^jA%S {`8{[/WX8%Ib?ג_~eȥ]wҒŋ {әЃ{.7GάYW-\ >g>@ V;Ŭ)SD^:!ez-Gz9^{x}L9W{2 {fnkKqbm6{{'Nd}7ʗ.]Zz\|8^:qdk뺣79 >OxRg5<={4_V6idg~ZNJJֶ^xw??=m3%'h;&M~2 ׈Br_Vh߸o{(7/]Eऌ1m"`QFrEߡR&PT(}*4#Qڸac}nnAFc.ؾ8kZ11''.(Bw·ਃzk!,pS'Ƶ|?Q~7~zՎ@ qӦ 99P*\^ukk$3vxKoIB~ ZOytI;Cz0(V;jq즣[j1$=8^'ZλR_W\lYu,yb* j9Y9rVv$BցOG:riS&XW[w%9>7jiM !CB:.򨖼\\!1\8hfj7,PAyY}1AEen1:o߮0 c`4J1sf̌3۝ua<;Cyẇ'JpO+?nieǠWt^u C׵,+8]+Uxt&1y@w|je\5,o}:;GM`Pd6) s8Um(j\p,jE#>YŬh#Q#38+U6gPNnJ.KPoCݭWPIE5 ȏ>pM7?oÇ⋪~S#ri2o3t$ BHkPF}ܧ}gvAK>x';;۠P({`=sǜ9;P'|uHvI Z_.iMcz#G>́hե^}]w'xRyF >@G<*zCGGQ0&!4Ff />ލ8g$c63_¤B]녇z(?④G/>z8u dzz4T}>|whNnh3E4BN h.L3tT*eo&̝J<{G>_Te&C:^%%'k-V>lF< 4HӶ]MN䑪V'OQxEqcYN8ᴇ( A!7uknڴ  ĨuSoXB@ y233 &Mj:!))Y{K:CwIqqjɬ={v\ZZncSs}ǕƏpM8b6+gdOm`ޒ,|YT.| rVjṈbZֱh#/8o^711~|))u6.opSONFܛDhѢesܞ`oyw=ήµ]oOJJ֮X%1GX9~xˌfDMf=ή~Rx-zDȱCe& uߺj,xՈxj 6DP9GDD(sss i]u:13ƬPbQu݉zć[.Ydq (=ήϏͬ? OEGGx5ªjDN{?Lsn#_RT<L>=W_j0l0믿1tQ7%!BeE;l{1&wtcXSjVE]5cV]lsWKTgdd~T 㣏>:y;t䓏+ zﯽ>T8';~-W^T(دXEvjʕ+{wD!Q'sFٮZBS}}*3@b@hH2s ­xЕfϞmJȉ'ZG ŋƍg;)<t: _}mB!p>W~E~}~~}V㯿zmߞee S~޾Dgc<&"+#">@ꉖׯϏ|z3ګ?NgXIeKCGBuH풥KWP/k׆?[qϼ<{M:;vp/\Jى'PRu):Z9!1I3(!AcXGGǨݮٲNstUv?p<(N8Nqg9p&p0so+ f:rՙ;WP]Da ÕW^9/қF̍5jYdr}gѣ$/]ںn,f2Ahjl\ bjl6+j`sh:l6)5@WI8jU \4~uy\ʚy='z޳*ɏ{[[ӵhr#oPO2 ,&5۶oF^(3<3Baϯj~=<4wnJttG.hlR:k,!'TS?;VPd՜8h`P( i.A %m.|jwX0nwxe?VíCmHĪONjllmqiGVBeYfL  [UQq$yY\\叏,fz׷47WJNǏ7Ɛ?lS\\ju=_G۬V]T?lSwwBpDxEoWk.:H!  FDr3өp?6N7O{TaL.T%bJJH?! 홙iܜȸ8mLaK"JK|+W}۰aƎ]yY)S63R}NϒA&ghF#׽'].7$d5ݜ/ vm+T-T/38 RAQ.jka& EJQ>8& ܗ7 Ɂ%s랊C9$!HU;432''#R5"m18n͍k֬w޳ FD=0痧L9TUU\{W֔AC kJ+NC 'g]g#T8}δO~vYpyzaUC==/gӵ7$B=ږF~Vޛ/:=!A!'ηvx8!18"o--=`{5k׻:vl]bBx湿VEsr2lF݅V?(" $z=CuNw}>Aa۽B3GRS4kŸœ_j) AH F-dfZ "ihh+KYiF^{Oq5 4$S 3F* nW$hz^vǙR+:Ĺ)9,!' SJ8?:<pO|z=!A B SLM=8Sp\u; mB!U}?/Sh!⪪kH H2pdYRnȄH ^ (џY:{5c~=`1C??rd0͌Eߖs^$( A u$Sɲdgc`Ɓ9pPɁKJzO)~I ZI!w-?WΚ~T1f~dJ ]'lBެLP_,f_$X -DFtƦCeHL,Kʐ-;w0^:Ѫ߰ 98<*֌uTT#BO\Wq $S> !˒]nAPRBNP8Y켠(=}&z3D⫝̸A7U?l;sLۇfiF>:;B~]JiKJVkFjLf~)-`?oc1B k(`[k1b-Ȉ;X`lus׹O؋FZzܦwdࠫ6XǣA]2sKCH0Y U>BB(cx#c"'HPMm=0K!f$Ff=?~5ªTJt;!!Җ՚G_'xN3#m)IՕiRT쩨buq{>y_`~ FƦFrar:%9Z51z=$IcZt5U|kc~^ϩغ %XG/ K~@a8*yc/X[PzȯZc4!ͶZ'G'<2LHONrf]ѱǛB dݮ.:}GQ}M޳%&$! &EPTPlU,`bU{A@(*E@HHBfSv}gǒ$@|"fwʙ͞3ϜvIXaP+TK pSR֭Griii(Qŧ"Y/o:u*{ʺ1 Ǐw=rh s%^ϣo AQĺ?1ZeYS=EB2Zm}h̙W+y7Pa#\78"CN`NjHeځ>>Iwݘ]%eY:wR^v8cVV{et^9C(^={ qfbPj?@bNl8cxYtL,u07r}^'O=yGQAEk/p >|hͩjVĨyt7p E>l}3)\먦nY@d8UX\h Qwuhg.'YbwV@8EwLj%y,#BTSeLa[Txe453G]yEose֮[(0S5B2嗋kr g@.WBBYAXR `0Lx=$Z?k6222JNIlOFUZZؿGQAE_oCzV m! 飰m)CÃPmBeCEXuam7eL4ܱcwr_nE1Mmgi`@\bESGzeejM7ϲZ$Dl`LH`JNNV :^dIq 'O0nz1m@Vsi]:wQa‚ߖ-233]-);1,^~bdJDk?&!dD XSH%*b1Y1iDK(稨(S, \v]ɁMQN4-D~}ЩS'l߶'Ndc3wnu@cp,@"W/qf(Z$$nرFF/eIQGN4bl+W玊JaԨQ_|Y~<1Æק[gEM[Z>_14+ENR:wL&â}D%^ΐr t Mʑ_Q?gU|v/*}qAl\_o‹/ueǎeSxؘZAo[.uiT͇-j4>#cCickҒRM7:vtoHܵwؙ{*u&tN8۳gG"{ tvI ̽w};4}G% TkmI̠U RBKm۶ >p$P h8!p v@U#v6)8Wn4^. dʆ년0$ d mt8ϛw~}7L3f1===mgϞ]3tH =X,Ҏ[l)4hו+mЫwoMNN{m??v7h^Lt,11I1G:t>EH}aw?%=0%4xg2 ^9B9Mnlt $eH8Rg^_Ϸ̞W\\_0@ T.Olj9sV=]}9s7mXZ. BC/s# ػg7zj!.2=( 8Spa-ExuZpԱֵ_}罆npÆ +L)))F{2כx--iXcK5$Z C ?6AlΝdپ2d27x޳^DFR:O?}xqB`U*۹S'N ҥ'QTܑ#GׯٳM˖.-K"mIx:m~hi%~AHr(~!b^PvD g/RccAӕGӃIkEr5THy "oʲ,駟ZzzErzۯ 3tqa4yGLykH$R?p=8{gcg^yYkNI+/p8?#Fp"OS1>-Mwj?r糐rdz*`㇢rx@wnzqJvU{6,A|ԙ!%9J:FCPDJEr߽ʌrNhäp9{Y|YСC۷oطoW{QjڵɠikG -W\Tܪ@/.ؑ[fώ[ΧNEF¬3] <3& 1 ts@0iL$S֥j8eZu󉕕^5Z-/H٩ӦEO6RD(Uʳӝ9B җ`P+( :aYPsG\ $Ǧ(d1A#CNfN/CqM75j5{w`c|cƌx^s27u4h*(/]KVj~j5{EΝ:e mcd,@`AMw~\['^ԄhmY«*yyy,(o6Jº\n!޽1bZ-߽%/><{q4HP(8'ZX.wVTso?ir{yk(1_JJ_+ddž·Wt]b0(@R'MLp$W_йsgٱY^^ǽk3եKm V0@UcƎզT/קo奣.<؄iaaQU)DHx=R/Q9|˲ /č=Jg2`` /YfC&1Q[ƸX$ ".vn̨ik 9A^3k~Xŋ/?bHuc'|qqKRSw"(zo!qwd, zN@(EOhד^5?ߊ?3yz=ɜ=k \vUu,33ng׮F_qEp9R ۶m+׷6gO}`E pvb?WnWeP [VRpf+y?SA -C]U%ˋYۏպn3,.j *#pݺuݶe2Y'#ݻk$E]|lh7\p" )xn+(u 7O?/}Z?j ? e"VHxOxnۯvcd ҚRujZsop8Gy$ D_0zhU&%%I_ СC^XO>4ia~l5SF,_"//%6-0@ cFk|}ae˫ǝϟ??n>yU=>|~8gM u犎W=( |k׭uZc%QF%%%I}ܪ ?HqQNOOll$11b"(0"*rsOۯonE?F˃ޱggFo8uTKFFFJf͞r b򰿃l'??[\lO|e֭Upm{o u~McQx.xܹW_3=f捥<'aR322(LYFaعsbHACFQ2`@];%%vN601q]M{dO.NF ǥ#/С`طo~gL*ǎe }*`yK}=`ijݦ +WFp 8@bʊANN+,hI3XKhƟ2Ef :p8?ѣmz0؃ee;`>"ʦȮ<*ʀy3'㽟Vt DӪm޴TP7toM=ϧ3ڵb?Ζ>\ڵ{u9-H3f̈={vzʒa˖wU@iԷ~[zΜ#jU{_(`Yw.ZVNkj(2g,"ߩOg_=(=n繮k\+_lx涗n%f3f̈BSelHZE ED'`c%Ap`0"ѧC IDATxq{8WPTw߅r;݇o^K*!A!T2]k^[]#iƲ[n%~ǎNW疈K5$Z ҩ?#"Nb4_rD8%&lSPj/wM%iVRiARt8MaqQfVJ$Rf))S%"*eBgg45dz"VcJ%`$X '?xY|zԩS_,)OOOw\hI"{@6{ֺBkM0`K6}J=Qp?S?T2kV*Yv=hR^^^xO4{yE'߹`cGB7|Fc$ @W^~L&cu:_VVth]wy@Vs*/ b3>ӡPtG@8[j 7FTB0l]@!S$2N0_&J,x"Ͷ[˯6uW׃A΢~IVK@0@fo^d%Aq_)4  P;hMǏeRw<4=uICY*V7nG$@P;J"j޺U]ު}^mŊaOqy4׭[79˲ sr8zHC*ccT Gz=OaaA_f|dwmܥ{AuU,|?" J%}z.fਿ !@Xyd/.k_[DFE4|m\CR\r>OlISee T۱dMe sеHy-=9cuqU˽a~Ʒ tc Dea?Y,x܂{IAii uz^CXy^;ogo!g .^C`%rX|$ <A.]՞@0`Ƨ -5jtʕ+u9gBTCh@hI`"#cEO0Qlٲzɓ'=zʗ/[^L.gt"_Sg6f tUFl2u{-*]`}Jnx*TwH6lp<#1#FlڴY= 3Ӯʐu/;;IE"k+QleeeuSIIb?@hͧ~Zec/V@Beo{Md \/ɂH4ħqxu;W%u@qшQ+gTHα,s}YsLOLL~+{[GT Pٵ]buz"9,,T*`B "nBRSNq8s f"OoB՞029 )> Ba (<Xv+"AP"BӁ]#QK|HBݎR,qIsub9iIY>Z0ЀyF/X8} Ä tSMΡPlB7 o4νVJgN+V.IxAC͋y_&$tZn]y ԫ+P ׯw suEM>rUdl\zu_^stIWny YٹskcVȇ[͛7W3V‹/{j&%ۋIyz⧟~ZmVW[gǟ;\ӦN3s=?E_v5ܒ7RYuEe C$TB??@A!QzGCq8Y?QEE٬zPݻ Wo#q:NYf JگU0z@AkSYY)SA={6?aeF][QiFrXv_P 0"ptE]|{wOqS֧iu}lg ,JQTh@j҄u=z*9⭨f?e4}c{w(VޘV%ۢ /7x!9شy;MnEQEQmqײt3m?E]h@j_{:K R՜׭um5EYiY0٬ߗ?=((M!!Ry!0tZ:!\%҃,EQEQEC8bX-MYMQ( *eP((Z$8PjAj !.E]! T3WxCQEQEQ_!( `0C@}.4 aY7'0]((}@0~AGPEQEQEQ6((((ꜣ (((9((((ꜣ (((9((((ꜣ (((9((((ꜣ (((9((((ꜣ (((9((((w(7b|Ww;<)j)XuO& ,Ǐ2E]h@lÉ؍ ]Q BTâ %ECK*R\ceM/T"Y/wٴiF$( -tʈƤׯҍWrB6QsU❓-(.EQ5ЀEQ\Ǩp] i8q%jX8!a6@uNN`WYr}uY5 h- EQ⺩L2^S30Z;p$"BR (0U2`W঍vl*bu?_nB~LDQ!0Pun1 0kbY>xW`%(8 `R?vh.pࡹz.2%A8  HPu^pTb4%& ˰aݨD$>a/UGaδ:"Kcg(}WeFt lvi+~Q{- ϕn u,`1O HȊ qTDwYhؑشz^I rïU-* @qY(j4 AQya4%&*ZM$XeJhX\xXۖPQl^׮o s:0=I2옴_1I ',e𜄱ٚxN5"I1(tTuci&?>z䈫WA{6`KQ[tx}2~0"T6W봞=s87 B(X(* EQFd8Ͱ\!M2lx4\Ms1TfEפq5=N颂ts=Nx+\ngSՖ" @Cr&];tzɧ:T*.-_7gRg G"iӮ #+Md!C͟\VZ;ju|bb<=}w8ky\\,:&zsuT#8=WêmH4oZkw{=zj>QBŠa:y|ҋ\w(cj-D~}sh@iPt8BaZ-(e!(B0Б$0\5`͋[*~l.A‚x d C1Ag`Oi]"hfzs=%''/pTTO 0rHüt:^TSS{iHh>psםwuػg?.f\`2iQ^KC_/p >|W: `]9}$aն}GFFFO<)11I]+1jԨ@󅠽#s|sBP < aC 0*t3HL^_φiMǞ^e}sh}@B+N8wY(b0 #]6Gfv<36P R {S=qA:Lz岣$YU*$/UW]P(طؼysYu^73vҥ>Oݞ;v 99iӮLFS_,)9f˲!*Jjժx L ĕ+Vت>|w>^\PVZVt,몕+KNdǎkTk_5W 6 Au<˽dɒ@/( Z&[,f+ZҖ{ԭQQQɓXN#n;vXr1:ȿ曂G\.ZoCzV m+cr{8n8OnU0bpN9Fh8&[F?wTTVV F^y6|>}:{UބsBc'Ml1Yzݻv9֯O׬ˍ}%iO爪{u 稞T/*(< FZҋ0mCƥIB6 Pz~9m ~E%ϽEQTcYED#tMLTʃD^˃s #$ ts fc2p@} N5+b%2ӷuw8`rcǎ3tWj ܮ`0(Чo_믷>pa@ @Ox {nUk~jEdd fP >"f|뮍?~yȐ!={i偪>|XVۋ]2fXcwT8/5 /M̉'<=4og>rP%px񥗺3&j>}jG3vNLJT*++io =J{?;)b<63\'opnN!=:Wc!)N|w@ H~mK٥.9_ZFgdl(zh֚zy ..^ۋ.;QQ;^3˞iR6ooH=N5\3DJ}4^ƓxO~:<_bȘ* fm}UzZO=m ,AQ0…%e(/Ƿ'<` =%>IώyJ|2LP,ݥ|GE'5HFGDKW= }@kהXVYTIW/SRRG:\%?G^{]Erj?5;'~za uU%Wj+.U?ٳgc1:sOz-cdŖ-[ uJ[)--x̽^Wxr= ^cqq=zСC/K>^#F40gΜ8X0Ѫ'<>O;gnK >.[8B3I ̡'e,^q{Cznܑf#1O6/ˆ WRRRU߯QFGfee5[kM8n-p7zz~}7L3f1==^ɱ[/v绞Y0 "ð`Y,T?ÜitHajܸOv+Uh=oڿ Ƃ(*|gx>A/nLaM~Bcq Jzj'$17"N2DxaY:z{9f+H3}ǩw_q:t{ ֧{,[kNG$8ׯv ` vhVmg}{:ccXkd{$rIyYY`Ŋw$x.,w> V#01 F^7EY-z-vi.uJ?j(썭5󀄗0{nژQZuLCj Nkw\#;HE|uQ QIX$B"N#ZA7!AQu\D0<]~ܽ\AO=yu؃B?$Hְp q~qcGi;k(p:A&Shnm^o[% hK/,8qy֜r}WOA_^{i/_VWHӘ@0@~YK%&F60 `j/Q}>OܳgsAzB|>%}"(&.r~W>0w_&3O fw= In(w7n[/߭ļ&A&i&SFƆkO٫fĈCU7y/[KMs+4RY[Tq^-gܱGR/v糞Q{O.hkLǡ2?][|WN?TAM<|-pC6.ra5YuNߐ'yCj:0u>-`2f¨vFH _C}n ZQw(Fs;K'E4KǨaWs:_46&V6rI$yCDCϪq::NFkEUn[_[%#ZY.ЀE,tR%+g9R%gM09%,F<葚k s5M>пeI`y<GCQ-U7{v aj<ϏgN7^.*|0D jj[/7m*ݶuk}ߟXlH}绘f颷ߪN4yh[n#F %x& Pk煅E(IϞ=5<1 řHZe*ƛI_]ikTxM>}jqqr*7rӴiӢ7ʚ-.'OҲu#;ouvjzhcY!CfzbZcckfW8xͳnZezҵ*--ц."Y/_A' $7oml xqa[?ٚu@Vaݙ9ظP?'*"Œ 2cƎbYٲeKYsˇ}ki T79"cuk=oax, ro TA3u>ɠkI1}MO=ɝ<GF F@2t|YYi 6F2k/)hDK\`u:^ocKضZIyy%錤<1Fc$ pb bAq$\D^ChyMl對Ѷ@D2E=T 1Od 1U% Yhv¡Æ8hN\\W^+++vR*[o3 >\ϟE,ŗ^El޼R*0:w] HDH+>^]1ccws9'L'kO-vz}nXiX+d~ ǰun[&fL7D* mtDcX.>: ԝ1Y4"擢 MXVU":[MCxGr~? ;^-FTuuW f7bbc+ Ak'ز+\<D b" !JlGe/+d]ڗ:y#{Ko|޷رc^{c}3?keя|dﹳg>ٟF=y{?g_ ,-I+޵}ae~'on|~f_ZU{E7spYqx~-+ ߃_Ց>CtJSKv_[Xc7qPhr )QֲWIT[^!Y'/ST5o/0B^x/Xϭn;vу>?ɳKޮ0 ݷ{G[+4nӧOQ>T?8C{&*v13uYt_z [;tQql׶U*BItvZjĉuol~%BOj~}z|>O?t~xQ$?c=֢]XnƏ%{@MZLzKo7N sn.̾Zǿ*xfn>\:xX]_Iswy<@bj_>qKo~Շ'Jj_X^c;w>#V;_jZr 7cGm:<O!33ѣGgQoYZZN^{78E gn[xDE llS/@~Kf\%\zf:c] 733]LR,+4*231e0 &͂Ճ\`J ɣΟn+AX_||{򕓍Cy睻ŤZUW_]ϝ;j5۶MOo z9I_X=Kɩӧ{|5T/Y\\L[w\\%v9rdǏKrJj333Q7i[n>qĊa8q3}]V[X~}5`K^T..RC-nqvK/ٙߞYSe믾wqλ5L>[ ~zarr߿I09s&-7O~@ s=WZ;vlR}ݷ{-I(?? W$fʫ"*,4)m6vȴ,i wNLA.0j16>!6Ŏ;b277 gϞJE~…mLOO.^Z߰Z8vP)lw86 ӛ}=OFÈ|ꏵ1Q4rYY lZ%H(j^rq Rj}=SiUkT-1j Q6'xib6|Y#+/֛ծzRڿ@ֻڠ,ɋ% `eA{É5[K ]QbI"yvg7uzL䏥ޙcF)6bC1/H !]{1gkܦm6's;+#".l)[{N|i‹*$ʮy_JRD.lZgkDT++zl[+l?XݛJ .MIt:封D; )EmMkf~Zվ6Š$+%+Ki4ܽ.O\$ק8jLu{s88888.ycuwKi(!)vCZݣ1t(a}v@ZZeQHVTX0.i\҄dSؤIӒM z`c,uE]Zė%_TTOcVs7wIfniE7]壒x(oUGYFV$[Mk)v o lUHx6A(QCip)jxn|^D:_k[ $J4V_TwD\M;<\ryR"ɚ<+U\ -в4jEͺJ=!hOV1 YGrEfIjHL!P;fq;hVHϳyF!yzҪfpɥ4cp{$ydR,H ݽ"SdyFu΍ l5"R$r%f'g>Fi ]M/ ,ZADgF H{m#oٰJ".dZ2W \ȓ|KgH-j0{$:m:%"7h4"OgC0Ŗ <.ޯh B;GOD>?(bLiYX5 %ҹRVAX{Kpge 7^OaM-ҁVbUD@!ʫ#XCF$By&},I[2f_b2Jw$mEaDC0T(axgUCzs%I6ݒNybcC-˪#F6ʶ];mtTIyI PBT_*'&W杕}5(l^w͓HGj l͙( #Z![Ae;n dAEZ^p$4wl ծY:z $[P.PgeC}*5g[609[]- U Cj!0 lguj?'4lH{k6D"#ZQeѪ(~J$VHZv먄yCZyH3,޳#x!$ :)bo-=Ԯ "/Ο)X鸤TIt iF~ߌ>ANqW ^") #:>Dê$H/kLHD{֢A8VNё^"z~nkZByuF"tOB15'({UAs ]:V "odUîW;`cs\[! +| 6($x(vm>028;/wl;uP`s M?79ֺ߈]:XCc=CaFa=1lQB5xZ̥ (|mX-TJ/m6IENDB`wcm-master/src/000077500000000000000000000000001453243033400137255ustar00rootroot00000000000000wcm-master/src/main.cpp000066400000000000000000000003371453243033400153600ustar00rootroot00000000000000#include int main(int argc, char **argv) { auto app = Gtk::Application::create("org.gtk.wayfire-config-manager"); std::unique_ptr wcm = std::make_unique(app); return app->run(argc, argv); } wcm-master/src/meson.build000066400000000000000000000007511453243033400160720ustar00rootroot00000000000000xml = dependency('libxml-2.0', required: true) gtkmm = dependency('gtkmm-3.0', required: true) wf_config = dependency('wf-config', version: '>=0.6.0', required: true) xkbregistry = dependency('xkbregistry', required: true) dep_list = [xml, gtkmm, wf_config, wf_protos, evdev, xkbregistry] sources = files('main.cpp', 'metadata.cpp', 'wcm.cpp', 'utils.cpp') executable(meson.project_name(), sources, install : true, dependencies : dep_list) wcm-master/src/metadata.cpp000066400000000000000000000343731453243033400162230ustar00rootroot00000000000000/* * Copyright © 2020 Scott Moreau * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #include "wcm.hpp" #include #include Option::Option(xmlNode *cur_node, Plugin *plugin) { xmlNode *node; xmlChar *prop; this->plugin = plugin; prop = xmlGetProp(cur_node, (xmlChar*)"name"); if (prop) { this->name = (char*)prop; } free(prop); prop = xmlGetProp(cur_node, (xmlChar*)"type"); if (prop) { std::string type = (char*)prop; if (type == "int") { this->type = OPTION_TYPE_INT; this->data.min = -DBL_MAX; this->data.max = DBL_MAX; } else if (type == "double") { this->type = OPTION_TYPE_DOUBLE; this->data.min = -DBL_MAX; this->data.max = DBL_MAX; this->data.precision = 0.1; } else if (type == "bool") { this->type = OPTION_TYPE_BOOL; } else if (type == "string") { this->type = OPTION_TYPE_STRING; this->default_value = ""; this->data.hints = (hint_type)0; } else if (type == "button") { this->type = OPTION_TYPE_BUTTON; this->default_value = ""; } else if (type == "gesture") { this->type = OPTION_TYPE_GESTURE; this->default_value = ""; } else if (type == "activator") { this->type = OPTION_TYPE_ACTIVATOR; this->default_value = ""; } else if (type == "color") { this->type = OPTION_TYPE_COLOR; this->default_value = ""; } else if (type == "key") { this->type = OPTION_TYPE_KEY; this->default_value = ""; } else if (type == "dynamic-list") { this->type = OPTION_TYPE_DYNAMIC_LIST; } else { printf("WARN: [%s] unknown option type: %s\n", plugin->name.c_str(), prop); this->type = OPTION_TYPE_UNDEFINED; } } else { printf("WARN: [%s] no option type found\n", plugin->name.c_str()); this->type = OPTION_TYPE_UNDEFINED; } free(prop); prop = xmlGetProp(cur_node, (xmlChar*)"hidden"); if (prop && (std::string((char*)prop) == "true")) { this->hidden = true; } free(prop); for (node = cur_node->children; node; node = node->next) { if (node->type != XML_ELEMENT_NODE) { continue; } std::string node_name = (char*)node->name; if (node_name == "_short") { this->disp_name = (char*)node->children->content; } else if (node_name == "_long") { this->tooltip = (char*)node->children->content; } else if (node_name == "default") { if (!node->children) { continue; } switch (this->type) { case OPTION_TYPE_INT: this->default_value = atoi((char*)node->children->content); break; case OPTION_TYPE_BOOL: if (std::string((char*)node->children->content) == "true") { this->default_value = 1; } else if (std::string((char*)node->children->content) == "false") { this->default_value = 0; } else { this->default_value = atoi((char*)node->children->content); } if ((std::get(this->default_value) < 0) && (std::get(this->default_value) > 1)) { printf("WARN: [%s] unknown bool option default\n", plugin->name.c_str()); } break; case OPTION_TYPE_ACTIVATOR: case OPTION_TYPE_GESTURE: case OPTION_TYPE_STRING: case OPTION_TYPE_BUTTON: case OPTION_TYPE_COLOR: case OPTION_TYPE_KEY: this->default_value = (char*)node->children->content; break; case OPTION_TYPE_DOUBLE: this->default_value = atof((char*)node->children->content); break; default: break; } } else if ((node_name == "type") && (this->type == OPTION_TYPE_DYNAMIC_LIST)) { char *type = (char*)node->children->content; this->default_value = type; } else if (node_name == "min") { if (!node->children) { continue; } if ((this->type != OPTION_TYPE_INT) && (this->type != OPTION_TYPE_DOUBLE)) { printf("WARN: [%s] min defined for option type !int && !double\n", plugin->name.c_str()); } this->data.min = atof((char*)node->children->content); } else if (node_name == "max") { if (!node->children) { continue; } if ((this->type != OPTION_TYPE_INT) && (this->type != OPTION_TYPE_DOUBLE)) { printf("WARN: [%s] max defined for option type !int && !double\n", plugin->name.c_str()); } this->data.max = atof((char*)node->children->content); } else if (node_name == "precision") { if (!node->children) { continue; } if (this->type != OPTION_TYPE_DOUBLE) { printf("WARN: [%s] precision defined for option type !double\n", plugin->name.c_str()); } this->data.precision = atof((char*)node->children->content); } else if (node_name == "hint") { if (!node->children) { continue; } if ((this->type != OPTION_TYPE_STRING) && (this->type != OPTION_TYPE_DYNAMIC_LIST)) { printf("WARN: [%s] hint defined for option type !string\n", plugin->name.c_str()); } if (std::string((char*)node->children->content) == "file") { this->data.hints = (hint_type)(this->data.hints | HINT_FILE); } if (std::string((char*)node->children->content) == "directory") { this->data.hints = (hint_type)(this->data.hints | HINT_DIRECTORY); } } else if (node_name == "desc") { if ((this->type != OPTION_TYPE_INT) && (this->type != OPTION_TYPE_STRING)) { printf("WARN: [%s] desc defined for option type !int && !string\n", plugin->name.c_str()); } xmlNode *n; std::unique_ptr li = nullptr; std::unique_ptr ls = nullptr; for (n = node->children; n; n = n->next) { if (n->type == XML_ELEMENT_NODE) { if (this->type == OPTION_TYPE_INT) { int is_value = (std::string((char*)n->name) == "value"); int is_name = (std::string((char*)n->name) == "_name"); if (!li && (is_value || is_name)) { li = std::make_unique(); } if (is_value) { li->value = atoi((char*)n->children->content); } if (is_name) { li->name = strdup((char*)n->children->content); } } else if (this->type == OPTION_TYPE_STRING) { int is_value = (std::string((char*)n->name) == "value"); int is_name = (std::string((char*)n->name) == "_name"); if (!ls && (is_value || is_name)) { ls = std::make_unique(); } if (is_value) { ls->value = (char*)n->children->content; if (std::get(this->default_value).empty() && (this->str_labels.size() == 1)) { this->default_value = ls->value; } } if (is_name) { ls->name = (char*)n->children->content; } } } } if (li) { std::pair pair(li->name, li->value); int_labels.push_back(pair); } if (ls) { std::pair pair(ls->name, ls->value); str_labels.push_back(pair); } } } } Option::Option(option_type group_type, Plugin *plugin) : plugin(plugin), type( group_type) {} Option::~Option() { if (parent) { auto & children = parent->options; children.erase(std::remove(children.begin(), children.end(), this), children.end()); } } Option*Option::create_child_option(const std::string & name, option_type type) { auto *option = new Option(); option->name = name; option->parent = this; options.push_back(option); option->plugin = plugin; option->type = type; return option; } Plugin*Plugin::get_plugin_data(xmlNode *cur_node, Option *main_group, Plugin *plugin) { xmlChar *prop; bool children_handled = false; for (; cur_node; cur_node = cur_node->next) { if (cur_node->type != XML_ELEMENT_NODE) { continue; } std::string cur_node_name = (char*)cur_node->name; if (cur_node_name == "object") { return nullptr; } if (cur_node_name == "plugin") { plugin = new Plugin(); plugin->category = "Uncategorized"; prop = xmlGetProp(cur_node, (xmlChar*)"name"); if (prop) { plugin->name = (char*)prop; } free(prop); } else if (cur_node_name == "_short") { plugin->disp_name = (char*)cur_node->children->content; } else if (cur_node_name == "_long") { plugin->tooltip = (char*)cur_node->children->content; } else if (cur_node_name == "category") { if (!cur_node->children) { continue; } plugin->category = (char*)cur_node->children->content; } else if (cur_node_name == "option") { if (!main_group) { main_group = new Option(OPTION_TYPE_GROUP, plugin); main_group->name = "General"; plugin->option_groups.push_back(main_group); } children_handled = true; main_group->options.push_back(new Option(cur_node, plugin)); } else if (cur_node_name == "group") { xmlNode *node; Option *group = new Option(OPTION_TYPE_GROUP, plugin); for (node = cur_node->children; node; node = node->next) { if (node->type != XML_ELEMENT_NODE) { continue; } std::string node_name = (char*)node->name; if (node_name == "_short") { group->name = (char*)node->children->content; } else if (node_name == "option") { group->options.push_back(new Option(node, plugin)); } else if (node_name == "subgroup") { Option *subgroup = new Option(OPTION_TYPE_SUBGROUP, plugin); for (xmlNode *n = node->children; n; n = n->next) { if (n->type != XML_ELEMENT_NODE) { continue; } if (std::string((char*)n->name) == "_short") { subgroup->name = (char*)n->children->content; } else if (std::string((char*)n->name) == "option") { subgroup->options.push_back(new Option(n, plugin)); } } group->options.push_back(subgroup); } } children_handled = true; plugin->option_groups.push_back(group); } if (!children_handled) { plugin = get_plugin_data(cur_node->children, main_group, plugin); } } return plugin; } wcm-master/src/metadata.hpp000066400000000000000000000055251453243033400162250ustar00rootroot00000000000000#pragma once #include #include #include #include #include "utils.hpp" #include "wcm.hpp" enum plugin_type { PLUGIN_TYPE_NONE, PLUGIN_TYPE_WAYFIRE, PLUGIN_TYPE_WF_SHELL, }; enum option_type { OPTION_TYPE_UNDEFINED, OPTION_TYPE_INT, OPTION_TYPE_BOOL, OPTION_TYPE_DOUBLE, OPTION_TYPE_STRING, OPTION_TYPE_GESTURE, OPTION_TYPE_ACTIVATOR, OPTION_TYPE_BUTTON, OPTION_TYPE_KEY, OPTION_TYPE_COLOR, OPTION_TYPE_GROUP, OPTION_TYPE_SUBGROUP, OPTION_TYPE_DYNAMIC_LIST, }; enum mod_type { MOD_TYPE_NONE = 0, MOD_TYPE_SHIFT = 1 << 0, MOD_TYPE_CONTROL = 1 << 1, MOD_TYPE_ALT = 1 << 2, MOD_TYPE_SUPER = 1 << 3, }; enum hint_type { HINT_FILE = 1, HINT_DIRECTORY = 2, }; struct LabeledInt { int value; std::string name; }; struct LabeledString { int id; std::string value; std::string name; }; struct var_data { double min; double max; double precision; hint_type hints; }; using opt_data = std::variant; class Plugin; class Option { template void set_value(wf_section section, const value_type & value); template void set_value(wf_section section, ArgTypes... args) { throw std::logic_error("Unimplemented"); } public: Option(xmlNode *cur_node, Plugin *plugin); Option(option_type group_type, Plugin *plugin); Option() = default; ~Option(); Option *create_child_option(const std::string & name, option_type type); Plugin *plugin; std::string name; std::string disp_name; std::string tooltip; std::string binding; option_type type; mod_type mod_mask; opt_data default_value; var_data data; Option *parent; bool hidden = false; std::vector options; std::vector> int_labels; std::vector> str_labels; template void set_save(const ArgTypes &... args); }; class WCM; class Plugin { public: std::string name; std::string disp_name; std::string tooltip; std::string category; plugin_type type; bool enabled; std::vector option_groups; // widget of the plugin which is shown on the main page Gtk::Box widget = Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 5); Gtk::CheckButton enabled_check; Gtk::Button button; Gtk::Box button_layout = Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 5); Gtk::Image icon; Gtk::Label label; static Plugin *get_plugin_data(xmlNode *node, Option *main_group = nullptr, Plugin *plugin = nullptr); void init_widget(); inline bool is_core_plugin() { return name == "core" || name == "input" || name == "workarounds"; } }; wcm-master/src/utils.cpp000066400000000000000000000036601453243033400155760ustar00rootroot00000000000000#include "utils.hpp" #include #include bool find_string(std::string text, std::string pattern) { if (text.empty() || pattern.empty()) { return pattern.empty(); } std::transform(text.begin(), text.end(), text.begin(), ::tolower); std::transform(pattern.begin(), pattern.end(), pattern.begin(), ::tolower); return text.find(pattern) != std::string::npos; } bool begins_with(const std::string & str, const std::string & prefix) { return prefix.length() <= str.length() && str.substr(0, prefix.length()) == prefix; } using rxkb_context_ptr = std::unique_ptr; std::map get_xkb_layouts(const std::string& ruleset) { rxkb_context_ptr context = {rxkb_context_new(rxkb_context_flags::RXKB_CONTEXT_NO_FLAGS), &rxkb_context_unref}; if (!rxkb_context_parse(context.get(), ruleset.c_str())) { return {}; } std::map layouts; for (rxkb_layout *layout = rxkb_layout_first(context.get()); layout != nullptr; layout = rxkb_layout_next(layout)) { if (rxkb_layout_get_variant(layout) == nullptr) { layouts.emplace(rxkb_layout_get_name(layout), rxkb_layout_get_description(layout)); } } return layouts; } std::map get_xkb_models(const std::string& ruleset) { rxkb_context_ptr context = {rxkb_context_new(rxkb_context_flags::RXKB_CONTEXT_NO_FLAGS), &rxkb_context_unref}; if (!rxkb_context_parse(context.get(), ruleset.c_str())) { return {}; } std::map models; for (rxkb_model *model = rxkb_model_first(context.get()); model != nullptr; model = rxkb_model_next(model)) { models.emplace(rxkb_model_get_name(model), rxkb_model_get_description(model)); } return models; } wcm-master/src/utils.hpp000066400000000000000000000021301453243033400155720ustar00rootroot00000000000000#pragma once #include #include #include using wf_section = std::shared_ptr; /*! * Simple fuzzy-search. Finds `pattern` in `text`. Always returns `true` when * `pattern` is empty. */ bool find_string(std::string text, std::string pattern); bool begins_with(const std::string & str, const std::string & prefix); std::map get_xkb_layouts(const std::string& ruleset); std::map get_xkb_models(const std::string& ruleset); /*! * Button with text and icon. */ class PrettyButton : public Gtk::Button { public: PrettyButton(const Glib::ustring & text, const Glib::ustring & icon, Gtk::IconSize icon_size = Gtk::ICON_SIZE_BUTTON) : label(text) { image.set_from_icon_name(icon, icon_size); layout.pack_start(image); layout.pack_start(label); layout.set_halign(Gtk::ALIGN_CENTER); add(layout); } private: Gtk::Box layout = Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 5); Gtk::Image image; Gtk::Label label; }; wcm-master/src/wcm.cpp000066400000000000000000001563341453243033400152330ustar00rootroot00000000000000#include "wcm.hpp" #include "utils.hpp" #include #include #include #include #include #include #define OUTPUT_CONFIG_PROGRAM "wdisplays" constexpr int OPTION_LABEL_SIZE = 200; bool KeyEntry::check_and_confirm(const std::string & key_str) { if ((key_str.find_first_not_of(' ') != std::string::npos) && (key_str.front() != '<') && ((key_str.find("BTN") != std::string::npos) || (key_str.find("KEY") != std::string::npos))) { auto dialog = Gtk::MessageDialog("Attempting to bind \"" + key_str + '"' + " without modifier. You will be unable to use this key/button " "for anything else! Are you sure?", true, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO); return dialog.run() == Gtk::RESPONSE_YES; } return true; } mod_type KeyEntry::get_mod_from_keyval(guint keyval) { if ((keyval == GDK_KEY_Shift_L) || (keyval == GDK_KEY_Shift_R)) { return MOD_TYPE_SHIFT; } if ((keyval == GDK_KEY_Control_L) || (keyval == GDK_KEY_Control_R)) { return MOD_TYPE_CONTROL; } if ((keyval == GDK_KEY_Alt_L) || (keyval == GDK_KEY_Alt_R) || (keyval == GDK_KEY_Meta_L) || (keyval == GDK_KEY_Meta_R)) { return MOD_TYPE_ALT; } if ((keyval == GDK_KEY_Super_L) || (keyval == GDK_KEY_Super_R)) { return MOD_TYPE_SUPER; } return MOD_TYPE_NONE; } std::string KeyEntry::grab_key() { static const auto HW_OFFSET = 8; auto grab_dialog = Gtk::Dialog("Waiting for Binding", true); auto label = Gtk::Label("none"); grab_dialog.get_content_area()->pack_start(label); label.show(); uint mod_mask = 0; std::string key_btn_string; auto cur_state_string = [&mod_mask] { std::string text; if (mod_mask & MOD_TYPE_SHIFT) { text += " "; } if (mod_mask & MOD_TYPE_CONTROL) { text += " "; } if (mod_mask & MOD_TYPE_ALT) { text += " "; } if (mod_mask & MOD_TYPE_SUPER) { text += " "; } return text; }; auto update_label = [=, &label] { const auto text = cur_state_string(); label.set_text(text.empty() ? "(No modifiers pressed)" : text); }; update_label(); grab_dialog.signal_key_release_event().connect([&] (GdkEventKey *event) { mod_mask &= ~get_mod_from_keyval(event->keyval); update_label(); return false; }); grab_dialog.signal_key_press_event().connect( [&] (GdkEventKey *event) { auto new_mod = get_mod_from_keyval(event->keyval); mod_mask |= new_mod; if (new_mod == MOD_TYPE_NONE) { key_btn_string = libevdev_event_code_get_name(EV_KEY, event->hardware_keycode - HW_OFFSET); grab_dialog.response(Gtk::RESPONSE_ACCEPT); } else { update_label(); } return true; }, false); grab_dialog.signal_button_press_event().connect([&] (GdkEventButton *event) { key_btn_string.clear(); switch (event->button) { case GDK_BUTTON_PRIMARY: key_btn_string = "BTN_LEFT"; break; case GDK_BUTTON_MIDDLE: key_btn_string = "BTN_MIDDLE"; break; case GDK_BUTTON_SECONDARY: key_btn_string = "BTN_RIGHT"; break; case 4: key_btn_string = "BTN_SIDE"; break; case 5: key_btn_string = "BTN_EXTRA"; break; default: break; } grab_dialog.response(Gtk::RESPONSE_ACCEPT); return true; }); grab_dialog.show(); if (!WCM::get_instance()->lock_input(&grab_dialog)) { return ""; } grab_dialog.fullscreen(); auto result = grab_dialog.run(); WCM::get_instance()->unlock_input(); if (result == Gtk::RESPONSE_ACCEPT) { return cur_state_string() + key_btn_string; } return ""; } KeyEntry::KeyEntry() { add(grab_layout); add(edit_layout); set_transition_type(Gtk::STACK_TRANSITION_TYPE_CROSSFADE); grab_label.set_ellipsize(Pango::ELLIPSIZE_END); grab_button.add(grab_label); grab_button.signal_clicked().connect([=] { const auto value = grab_key(); if (!value.empty() && check_and_confirm(value)) { set_value(value); } }); edit_button.set_image_from_icon_name("gtk-edit"); edit_button.set_tooltip_text("Edit binding"); edit_button.signal_clicked().connect([=] { entry.set_text(get_value()); set_visible_child(edit_layout); }); grab_layout.pack_start(grab_button, true, true); grab_layout.pack_start(edit_button, false, false); edit_layout.pack_start(entry, true, true); ok_button.set_image_from_icon_name("gtk-ok"); ok_button.set_tooltip_text("Save binding"); ok_button.signal_clicked().connect([=] { const std::string value = entry.get_text(); if (check_and_confirm(value)) { set_value(value); set_visible_child(grab_layout); } }); cancel_button.set_image_from_icon_name("gtk-cancel"); cancel_button.set_tooltip_text("Cancel"); cancel_button.signal_clicked().connect([=] { set_visible_child(grab_layout); }); edit_layout.pack_start(cancel_button, false, false); edit_layout.pack_start(ok_button, false, false); } static void add_comma_with_space(Glib::ustring& text) { auto last_non_space = std::find_if_not(text.rbegin(), text.rend(), [] (char ch) { return std::isspace(ch); }); if ((last_non_space != text.rend()) && (*last_non_space != ',')) { text += ','; } if (!text.empty() && (*text.end() == ',')) { text += ' '; } } LayoutsEntry::LayoutsEntry() { for (const auto & [name, description] : get_xkb_layouts(WCM::get_instance()->get_xkb_rules())) { layouts.emplace_back(name + " — " + description); layouts.back().signal_activate().connect([name = name, this] () { auto text = get_text(); add_comma_with_space(text); set_text(text + name); }); } set_tooltip_text("Open context menu to choose layout"); signal_populate_popup().connect([&] (Gtk::Menu *menu) { menu->append(separator); for (auto & layout_item : layouts) { menu->append(layout_item); } menu->show_all(); }); } XkbModelEntry::XkbModelEntry() { for (const auto & [name, description] : get_xkb_models(WCM::get_instance()->get_xkb_rules())) { models.emplace_back(name + " — " + description); models.back().signal_activate().connect([name = name, this] () { set_text(name); }); } set_tooltip_text("Open context menu to choose model"); signal_populate_popup().connect([&] (Gtk::Menu *menu) { menu->append(separator); for (auto & model_item : models) { menu->append(model_item); } menu->show_all(); }); } std::ostream& operator <<(std::ostream & out, const wf::color_t & color) { return out << "rgba(" << color.r << ", " << color.g << ", " << color.b << ", " << color.a << ")"; } template void Option::set_value(wf_section section, const value_type & value) { std::cout << section->get_name() << "." << name << " = " << value << "; "; section->get_option(name)->set_value_str(wf::option_type::to_string( value)); std::cout << section->get_option(name)->get_value_str() << "; "; } template void Option::set_save(const ArgTypes &... args) { auto section = WCM::get_instance()->get_config_section(plugin); if (!section) { return; } std::cout << __PRETTY_FUNCTION__ << ": \n "; set_value(section, args...); WCM::get_instance()->save_config(plugin); } OptionWidget::OptionWidget(Option *option) : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 10) { name_label.set_text(option->disp_name); name_label.set_tooltip_markup(option->tooltip); name_label.set_size_request(OPTION_LABEL_SIZE); name_label.set_alignment(Gtk::ALIGN_START); reset_button.set_image_from_icon_name("edit-clear"); reset_button.set_tooltip_text("Reset to default"); pack_start(name_label, false, false); Gtk::Box::pack_end(reset_button, false, false); auto section = WCM::get_instance()->get_config_section(option->plugin); auto wf_option = section->get_option(option->name); switch (option->type) { case OPTION_TYPE_INT: { auto value_optional = wf::option_type::from_string( wf_option->get_value_str()); int value = value_optional ? value_optional.value() : std::get( option->default_value); if (option->int_labels.empty()) { auto spin_button = std::make_unique( Gtk::Adjustment::create(value, option->data.min, option->data.max, 1)); spin_button->signal_value_changed().connect( [=, widget = spin_button.get()] { option->set_save(widget->get_value_as_int()); }); reset_button.signal_clicked().connect( [=, widget = spin_button.get()] { widget->set_value(std::get(option->default_value)); }); pack_end(std::move(spin_button)); } else { auto combo_box = std::make_unique(); for (const auto & [name, _] : option->int_labels) { combo_box->append(name); } combo_box->set_active(value); combo_box->signal_changed().connect([=, widget = combo_box.get()] { for (const auto & [name, int_value] : option->int_labels) { if (name == widget->get_active_text()) { option->set_save(int_value); } } }); reset_button.signal_clicked().connect( [=, widget = combo_box.get()] { widget->set_active(std::get(option->default_value)); }); pack_end(std::move(combo_box), true, true); } } break; case OPTION_TYPE_BOOL: { auto value_optional = wf::option_type::from_string( wf_option->get_value_str()); bool value = value_optional ? value_optional.value() : std::get( option->default_value); auto check_button = std::make_unique(); check_button->set_active(value); check_button->signal_toggled().connect( [=, widget = check_button.get()] { option->set_save(widget->get_active()); }); reset_button.signal_clicked().connect( [=, widget = check_button.get()] { widget->set_active(std::get(option->default_value)); }); pack_end(std::move(check_button)); } break; case OPTION_TYPE_DOUBLE: { auto value_optional = wf::option_type::from_string( wf_option->get_value_str()); double value = value_optional ? value_optional.value() : std::get( option->default_value); auto spin_box = std::make_unique( Gtk::Adjustment::create(value, option->data.min, option->data.max, option->data.precision), option->data.precision, 3); spin_box->signal_changed().connect([=, widget = spin_box.get()] { option->set_save(widget->get_value()); }); reset_button.signal_clicked().connect( [=, widget = spin_box.get()] { widget->set_value(std::get(option->default_value)); }); pack_end(std::move(spin_box)); } break; case OPTION_TYPE_ACTIVATOR: case OPTION_TYPE_BUTTON: case OPTION_TYPE_KEY: { auto key_entry = std::make_unique(); key_entry->set_value(wf_option->get_value_str()); key_entry->signal_changed().connect( [=, widget = key_entry.get()] { option->set_save(widget->get_value()); }); reset_button.signal_clicked().connect( [=, widget = key_entry.get()] { widget->set_value(std::get(option->default_value)); }); pack_end(std::move(key_entry), true, true); } break; case OPTION_TYPE_GESTURE: case OPTION_TYPE_STRING: { if (option->str_labels.empty()) { std::unique_ptr entry; if (option->name == "xkb_layout") { entry = std::make_unique(); } else if (option->name == "xkb_model") { entry = std::make_unique(); } else { entry = std::make_unique(); } entry->set_text(wf_option->get_value_str()); entry->signal_changed().connect( [=, widget = entry.get()] { option->set_save(widget->get_text()); }); auto run_dialog = [=, widget = entry.get()] (const Glib::ustring & label, Gtk::FileChooserAction action) { auto dialog = Gtk::FileChooserDialog(label, action); dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL); dialog.add_button("Open", Gtk::RESPONSE_ACCEPT); if (dialog.run() == Gtk::RESPONSE_ACCEPT) { widget->set_text(dialog.get_filename()); } }; if (option->data.hints & HINT_DIRECTORY) { auto dir_choose_button = std::make_unique(); dir_choose_button->set_image_from_icon_name("folder-open"); dir_choose_button->set_tooltip_text("Choose Directory"); dir_choose_button->signal_clicked().connect( [=] { run_dialog("Select Folder", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); }); pack_end(std::move(dir_choose_button)); } if (option->data.hints & HINT_FILE) { auto file_choose_button = std::make_unique(); file_choose_button->set_image_from_icon_name("text-x-generic"); file_choose_button->set_tooltip_text("Choose File"); file_choose_button->signal_clicked().connect( [=] { run_dialog("Select File", Gtk::FILE_CHOOSER_ACTION_OPEN); }); pack_end(std::move(file_choose_button)); } reset_button.signal_clicked().connect( [=, widget = entry.get()] { widget->set_text(std::get(option->default_value)); }); pack_end(std::move(entry), true, true); } else { auto combo_box = std::make_unique(); for (const auto & [name, str_value] : option->str_labels) { combo_box->append(str_value, name); if (str_value == wf_option->get_value_str()) { combo_box->set_active_id(str_value); } } combo_box->signal_changed().connect( [=, widget = combo_box.get()] { option->set_save(widget->get_active_id()); }); reset_button.signal_clicked().connect( [=, widget = combo_box.get()] { widget->set_active_id(wf_option->get_default_value_str()); }); pack_end(std::move(combo_box), true, true); } } break; case OPTION_TYPE_COLOR: { auto value_optional = wf::option_type::from_string( wf_option->get_value_str()); wf::color_t value = value_optional ? value_optional.value() : wf::option_type::from_string(std::get(option-> default_value)).value(); Gdk::RGBA rgba; rgba.set_rgba(value.r, value.g, value.b, value.a); auto color_button = std::make_unique(rgba); color_button->set_use_alpha(true); color_button->set_title(option->disp_name); color_button->property_rgba().signal_changed().connect([=, widget = color_button.get()] { auto rgba = widget->get_rgba(); wf::color_t color = {rgba.get_red(), rgba.get_green(), rgba.get_blue(), rgba.get_alpha()}; option->set_save(color); }); reset_button.signal_clicked().connect([=, widget = color_button.get()] { auto color = wf::option_type::from_string(std::get( option->default_value)).value(); Gdk::RGBA rgba; rgba.set_rgba(color.r, color.g, color.b, color.a); widget->set_rgba(rgba); }); pack_end(std::move(color_button)); } break; default: break; } } AutostartDynamicList::AutostartWidget::AutostartWidget(Option *option) : Gtk::Box( Gtk::ORIENTATION_HORIZONTAL, 10) { command_entry.set_text(std::get(option->default_value)); command_entry.signal_changed().connect([=] { option->set_save(command_entry.get_text()); }); choose_button.set_image_from_icon_name("application-x-executable"); choose_button.set_tooltip_text("Choose Executable"); choose_button.signal_clicked().connect([&] { auto dialog = Gtk::FileChooserDialog("Choose Executable"); dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL); dialog.add_button("Open", Gtk::RESPONSE_ACCEPT); if (dialog.run() == Gtk::RESPONSE_ACCEPT) { command_entry.set_text(dialog.get_filename()); } }); run_button.set_image_from_icon_name("media-playback-start"); run_button.set_tooltip_text("Run command"); run_button.signal_clicked().connect([=] { Glib::spawn_command_line_async(command_entry.get_text()); }); remove_button.set_image_from_icon_name("list-remove"); remove_button.set_tooltip_text("Remove from autostart list"); remove_button.signal_clicked().connect([=] { auto section = WCM::get_instance()->get_config_section(option->plugin); section->unregister_option(section->get_option(option->name)); WCM::get_instance()->save_config(option->plugin); delete option; ((AutostartDynamicList*)get_parent())->remove(this); }); pack_start(command_entry, true, true); pack_start(choose_button, false, false); pack_start(run_button, false, false); pack_start(remove_button, false, false); } BindingsDynamicList::BindingWidget::BindingWidget(const std::string & cmd_name, Option *option, wf_section section) { const auto command = "command_" + cmd_name; const auto regular_binding_name = "binding_" + cmd_name; const auto repeat_binding_name = "repeatable_binding_" + cmd_name; const auto always_binding_name = "always_binding_" + cmd_name; auto executable_opt = section->get_option(command); auto regular_opt = section->get_option_or(regular_binding_name); auto repeatable_opt = section->get_option_or(repeat_binding_name); auto always_opt = section->get_option_or(always_binding_name); auto [wf_opt, opt_name] = always_opt ? std::tie(always_opt, always_binding_name) : repeatable_opt ? std::tie(repeatable_opt, repeat_binding_name) : std::tie(regular_opt, regular_binding_name); binding_wf_opt = wf_opt; if (!binding_wf_opt) { binding_wf_opt = std::make_shared>( regular_binding_name, "none"); } add(expander); expander.add(vbox); if (executable_opt->get_value_str().empty()) { expander.set_expanded(); } vbox.property_margin().set_value(5); Option *key_option = option->create_child_option(opt_name, OPTION_TYPE_ACTIVATOR); key_entry = std::make_unique(); key_entry->set_value(binding_wf_opt->get_value_str()); key_entry->signal_changed().connect([=] { key_option->set_save(key_entry->get_value()); }); Option *command_option = option->create_child_option(command, OPTION_TYPE_STRING); type_label.set_size_request(OPTION_LABEL_SIZE); type_label.set_alignment(Gtk::ALIGN_START); type_box.pack_start(type_label, false, false); type_combo_box.append("Regular"); type_combo_box.append("Repeat"); type_combo_box.append("Always"); type_combo_box.set_active(always_opt ? 2 : repeatable_opt ? 1 : 0); type_combo_box.signal_changed().connect([=] { section->unregister_option(binding_wf_opt); auto type = type_combo_box.get_active_row_number(); key_option->name = type == 2 ? always_binding_name : type == 1 ? repeat_binding_name : regular_binding_name; binding_wf_opt = std::make_shared>(key_option->name, binding_wf_opt->get_value_str()); section->register_new_option(binding_wf_opt); WCM::get_instance()->save_config(option->plugin); }); type_box.pack_start(type_combo_box, true, true); vbox.pack_start(type_box, false, false); binding_label.set_size_request(OPTION_LABEL_SIZE); binding_label.set_alignment(Gtk::ALIGN_START); binding_box.pack_start(binding_label, false, false); binding_box.pack_start(*key_entry, true, true); vbox.pack_start(binding_box, false, false); command_label.set_size_request(OPTION_LABEL_SIZE); command_label.set_alignment(Gtk::ALIGN_START); command_box.pack_start(command_label, false, false); expander.set_label("Command " + cmd_name); command_entry.signal_changed().connect([=] { expander.set_label("Command " + cmd_name + ": " + command_entry.get_text()); auto *label = (Gtk::Label*)expander.get_label_widget(); label->set_ellipsize(Pango::ELLIPSIZE_END); label->set_tooltip_text(command_entry.get_text()); }); command_entry.set_text(executable_opt->get_value_str()); command_entry.signal_changed().connect([=] { command_option->set_save(command_entry.get_text()); }); command_box.pack_start(command_entry, true, true); remove_button.set_image_from_icon_name("list-remove"); remove_button.signal_clicked().connect([=] { ((BindingsDynamicList*)get_parent())->remove(this); section->unregister_option(always_opt); section->unregister_option(repeatable_opt); section->unregister_option(regular_opt); section->unregister_option(executable_opt); WCM::get_instance()->save_config(option->plugin); }); command_box.pack_start(remove_button, false, false); vbox.pack_start(command_box); } template VswitchBindingsDynamicList::BindingWidget::BindingWidget(std::shared_ptr section, Option *option, int workspace_index) : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 10) { Option *key_option = option->create_child_option(OPTION_PREFIX + std::to_string( workspace_index), OPTION_TYPE_KEY); binding_wf_opt = section->get_option(key_option->name); key_entry.set_value(binding_wf_opt->get_value_str()); key_entry.signal_changed().connect([=] { key_option->set_save(key_entry.get_value()); }); label.set_alignment(Gtk::ALIGN_START); remove_button.set_image_from_icon_name("list-remove"); remove_button.signal_clicked().connect([=] () { ((VswitchBindingsDynamicList*)get_parent())->remove(this); section->unregister_option(binding_wf_opt); WCM::get_instance()->save_config(option->plugin); }); workspace_spin_button.set_tooltip_text("Workspace Index"); workspace_spin_button.set_value(workspace_index); workspace_spin_button.signal_value_changed().connect([=] { section->unregister_option(binding_wf_opt); key_option->name = OPTION_PREFIX + std::to_string(workspace_spin_button.get_value_as_int()); binding_wf_opt = std::make_shared>(key_option->name, binding_wf_opt->get_value_str()); section->register_new_option(binding_wf_opt); WCM::get_instance()->save_config(option->plugin); }); pack_start(label, false, false); pack_start(workspace_spin_button, false, false); pack_end(remove_button, false, false); pack_end(key_entry); } DynamicListBase::DynamicListBase() : Gtk::Box(Gtk::ORIENTATION_VERTICAL, 10) { add_button.set_image_from_icon_name("list-add"); add_box.pack_end(add_button, false, false); pack_end(add_box, false, false); } AutostartDynamicList::AutostartDynamicList(Option *option) { std::shared_ptr section = WCM::get_instance()->get_config_section(option->plugin); if (!section) { return; } auto wf_option = std::dynamic_pointer_cast(section->get_option( "autostart")); auto autostart_names = wf_option->get_value(); option->options.clear(); for (const auto & [opt_name, executable] : autostart_names) { if (std::get(option->default_value) != "string") { continue; } Option *dyn_opt = option->create_child_option(opt_name, OPTION_TYPE_STRING); dyn_opt->default_value = executable; pack_widget(std::make_unique(dyn_opt)); } add_button.set_tooltip_text("Add new command"); add_button.signal_clicked().connect([=] { static const std::string prefix = "autostart"; int i = 0; while (section->get_option_or(prefix + std::to_string(i))) { ++i; } const auto name = prefix + std::to_string(i); const std::string executable = ""; section->register_new_option(std::make_shared>( name, executable)); WCM::get_instance()->save_config(option->plugin); Option *dyn_opt = option->create_child_option(name, OPTION_TYPE_STRING); dyn_opt->default_value = executable; pack_widget(std::make_unique(dyn_opt)); show_all(); }); } BindingsDynamicList::BindingsDynamicList(Option *option) { std::shared_ptr section = WCM::get_instance()->get_config_section(option->plugin); if (!section) { return; } std::vector command_names; static const std::string exec_prefix = "command_"; for (const auto & command : section->get_registered_options()) { if (begins_with(command->get_name(), exec_prefix)) { command_names.push_back(command->get_name().substr(exec_prefix.length())); } } option->options.clear(); for (const auto & cmd_name : command_names) { pack_widget(std::make_unique(cmd_name, option, section)); } add_button.signal_clicked().connect([=] { int i = 0; while (section->get_option_or(exec_prefix + std::to_string(i))) { ++i; } const auto cmd_name = std::to_string(i); section->register_new_option(std::make_shared>( exec_prefix + cmd_name, "")); section->register_new_option( std::make_shared>("binding_" + cmd_name, "none")); WCM::get_instance()->save_config(option->plugin); pack_widget(std::make_unique(cmd_name, option, section)); show_all(); }); } template<> const std::string VswitchBindingsDynamicList::OPTION_PREFIX = "binding_"; template<> const std::string VswitchBindingsDynamicList::OPTION_PREFIX = "with_win_"; template<> const std::string VswitchBindingsDynamicList::OPTION_PREFIX = "send_win_"; template<> const Glib::ustring VswitchBindingsWidget::LABEL_TEXT = "Go To Workspace"; template<> const Glib::ustring VswitchBindingsWidget::LABEL_TEXT = "Go To Workspace With Window"; template<> const Glib::ustring VswitchBindingsWidget::LABEL_TEXT = "Send Window To Workspace"; template VswitchBindingsDynamicList::VswitchBindingsDynamicList(Option *option) { auto section = WCM::get_instance()->get_config_section(option->plugin); option->options.clear(); for (auto vswitch_option : section->get_registered_options()) { if (begins_with(vswitch_option->get_name(), OPTION_PREFIX)) { try { std::cerr << vswitch_option->get_name().substr(OPTION_PREFIX.size()) << std::endl; int workspace_index = std::stoi(vswitch_option->get_name().substr(OPTION_PREFIX.size())); pack_widget(std::make_unique(section, option, workspace_index)); } catch (const std::invalid_argument& e) { std::cerr << "Invalid workspace index: " << e.what() << std::endl; } } } add_button.signal_clicked().connect([=] { int workspace_index = 1; while (section->get_option_or(OPTION_PREFIX + std::to_string(workspace_index))) { ++workspace_index; } Option *binding_option = option->create_child_option(OPTION_PREFIX + std::to_string(workspace_index), OPTION_TYPE_STRING); section->register_new_option(std::make_shared>(binding_option->name, "")); pack_widget(std::make_unique(section, binding_option, workspace_index)); show_all(); WCM::get_instance()->save_config(option->plugin); }); } template VswitchBindingsWidget::VswitchBindingsWidget(Option *option) : dynamic_list(option) { set_label(LABEL_TEXT + " Bindings"); dynamic_list.property_margin().set_value(5); add(dynamic_list); } OptionSubgroupWidget::OptionSubgroupWidget(Option *subgroup) { add(expander); expander.set_label(subgroup->name); expander.add(expander_layout); for (Option *option : subgroup->options) { option_widgets.emplace_back(option); expander_layout.pack_start(option_widgets.back()); } } OptionGroupWidget::OptionGroupWidget(Option *group) { add(options_layout); options_layout.property_margin().set_value(10); set_vexpand(); for (Option *option : group->options) { if (option->hidden) { continue; } bool fill_expand = false; if ((option->type == OPTION_TYPE_SUBGROUP) && !option->options.empty()) { option_widgets.push_back(std::make_unique(option)); } else if (option->type == OPTION_TYPE_DYNAMIC_LIST) { std::cout << option->name << std::endl; if (option->name == "autostart") { option_widgets.push_back(std::make_unique( option)); } else if (option->name == "bindings") { option_widgets.push_back(std::make_unique( option)); } else if (option->name == "workspace_bindings") { option_widgets.push_back(std::make_unique>( option)); } else if (option->name == "workspace_bindings_win") { option_widgets.push_back(std::make_unique>( option)); } else if (option->name == "bindings_win") { option_widgets.push_back(std::make_unique>( option)); } // TODO other dynamic lists else { continue; } fill_expand = true; } else { option_widgets.push_back(std::make_unique(option)); } options_layout.pack_start(*option_widgets.back(), fill_expand, fill_expand); } } PluginPage::PluginPage(Plugin *plugin) { set_scrollable(); for (auto *group : plugin->option_groups) { if ((group->type != OPTION_TYPE_GROUP) || group->hidden) { continue; } groups.emplace_back(group); append_page(groups.back(), group->name); } } MainPage::Category::Category(const Glib::ustring & name, const Glib::ustring & icon_name) : name(name) { label.set_markup("" + name + ""); image.set_from_icon_name(icon_name, Gtk::ICON_SIZE_DND); title_box.pack_start(image); title_box.pack_start(label); title_box.set_halign(Gtk::ALIGN_START); vbox.pack_start(title_box); vbox.pack_start(flowbox); vbox.set_margin_top(10); vbox.set_margin_bottom(10); flowbox.set_selection_mode(Gtk::SELECTION_NONE); flowbox.set_halign(Gtk::ALIGN_START); flowbox.set_min_children_per_line(3); } void Plugin::init_widget() { label.set_text(disp_name); label.set_ellipsize(Pango::ELLIPSIZE_END); icon.set(WCM::get_instance()->find_icon("plugin-" + name + ".svg")); button_layout.pack_start(icon); button_layout.pack_start(label); button_layout.set_halign(Gtk::ALIGN_START); button.set_tooltip_markup(tooltip); button.set_relief(Gtk::RELIEF_NONE); button.add(button_layout); enabled_check.set_active(enabled); widget.set_halign(Gtk::ALIGN_START); widget.pack_start(enabled_check, false, false); if (!is_core_plugin() && (type == PLUGIN_TYPE_WAYFIRE)) { enabled_check.signal_toggled().connect( [=] { WCM::get_instance()->set_plugin_enabled(this, enabled_check.get_active()); }); } else { enabled_check.set_sensitive(false); // enabled_check.set_opacity(0); } widget.pack_start(button); button.signal_clicked().connect([=] { WCM::get_instance()->open_page(this); }); } void MainPage::Category::add_plugin(Plugin *plugin) { plugin->init_widget(); flowbox.add(plugin->widget); } MainPage::MainPage(const std::vector & plugins) : plugins(plugins) { add(vbox); for (auto *plugin : plugins) { std::find_if(categories.begin(), categories.end() - 1, [=] (const Category & cat) { return cat.name == plugin->category; })->add_plugin(plugin); size_group->add_widget(plugin->widget); } vbox.add(categories[0].vbox); for (int i = 1; i < NUM_CATEGORIES; ++i) { vbox.add(separators[i - 1]); vbox.add(categories[i].vbox); } // hide empty categories signal_show().connect([=] { set_filter(""); }); } void MainPage::set_filter(const Glib::ustring & filter) { std::map category_visible; for (const auto & cat : categories) { category_visible.insert({cat.name, false}); } for (auto *plug : plugins) { bool plug_visible = find_string(plug->name, filter) || find_string( plug->disp_name, filter) || find_string(plug->tooltip, filter); // the parent of `plug->widget` is `Gtk::FlowBoxItem` plug->widget.get_parent()->set_visible(plug_visible); category_visible[plug->category] |= plug_visible; } categories[0].vbox.set_visible(category_visible[categories[0].name]); for (int i = 0; i < NUM_CATEGORIES - 1; ++i) { separators[i].set_visible(category_visible[categories[i].name]); categories[i + 1].vbox.set_visible(category_visible[categories[i + 1].name]); } } void WCM::parse_config(wf::config::config_manager_t & config_manager) { for (auto & s : config_manager.get_all_sections()) { xmlNode *root_element = wf::config::xml::get_section_xml_node(s); if (!root_element) { continue; } root_element = root_element->parent; std::string root_name = (char*)root_element->name; if ((root_element->type == XML_ELEMENT_NODE) && ((root_name == "wayfire") || (root_name == "wf-shell"))) { printf("Loading %s plugin: %s\n", root_element->name, s->get_name().c_str()); Plugin *p = Plugin::get_plugin_data(root_element); if (p) { plugins.push_back(p); } else { continue; } if (root_name == "wayfire") { p->type = PLUGIN_TYPE_WAYFIRE; } else if (root_name == "wf-shell") { p->type = PLUGIN_TYPE_WF_SHELL; } else { // Should be unreachable because `root_name` is "wayfire" or // "wf-shell" p->type = PLUGIN_TYPE_NONE; } } } } std::string::size_type find_plugin(Plugin *p, const std::string & plugins) { std::string::size_type pos = 0; while (true) { pos = plugins.find(p->name, pos); if (pos == std::string::npos) { break; } if (((pos == 0) || (plugins[pos - 1] == ' ')) && ((pos + p->name.length() == plugins.length()) || (plugins[pos + p->name.length()] == ' '))) { return pos; } pos += p->name.length(); } return std::string::npos; } bool plugin_enabled(Plugin *p, const std::string & plugins) { return p->is_core_plugin() || p->type == PLUGIN_TYPE_WF_SHELL || find_plugin(p, plugins) != std::string::npos; } WCM::WCM(Glib::RefPtr app) { if (instance) { throw std::logic_error("WCM should not be initialized more than once"); } instance = this; app->add_main_option_entry([this] (const Glib::ustring &, const Glib::ustring & value, bool) { wf_config_file = value; return true; }, "config", 'c', "Wayfire config file to use", "file"); app->add_main_option_entry([this] (const Glib::ustring &, const Glib::ustring & value, bool) { wf_shell_config_file = value; return true; }, "shell-config", 's', "wf-shell config file to use", "file"); app->signal_startup().connect([this, app] () { load_config_files(); parse_config(); #if HAVE_WFSHELL parse_wfshell_config(); #endif if (!init_input_inhibitor()) { std::cerr << "Binding grabs will not work" << std::endl; } const auto plugins_str = wf_config_mgr.get_section("core")->get_option("plugins")->get_value_str(); for (auto *plugin : plugins) { plugin->enabled = plugin_enabled(plugin, plugins_str); } window = std::make_unique(app); auto icon = Gdk::Pixbuf::create_from_file(find_icon("wcm.png")); window->set_icon(icon); window->set_size_request(750, 550); window->set_default_size(1000, 580); window->set_title("Wayfire Config Manager"); create_main_layout(); window->show_all(); }); app->signal_activate().connect([&] { window->present(); }); } static void registry_add_object(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { WCM *wcm = (WCM*)data; if (strcmp(interface, zwp_keyboard_shortcuts_inhibit_manager_v1_interface.name) == 0) { wcm->set_inhibitor_manager((zwp_keyboard_shortcuts_inhibit_manager_v1*)wl_registry_bind( registry, name, &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1u)); } } static void registry_remove_object(void *data, struct wl_registry *registry, uint32_t name) {} static struct wl_registry_listener registry_listener = { ®istry_add_object, ®istry_remove_object }; bool WCM::init_input_inhibitor() { struct wl_display *display = gdk_wayland_display_get_wl_display( gdk_display_get_default()); if (!display) { std::cerr << "Failed to acquire wl_display for input inhibitor" << std::endl; return false; } struct wl_registry *registry = wl_display_get_registry(display); if (!registry) { std::cerr << "Failed to acquire wl_registry for input inhibitor" << std::endl; return false; } wl_registry_add_listener(registry, ®istry_listener, this); wl_display_dispatch(display); wl_display_roundtrip(display); if (!inhibitor_manager) { std::cerr << "Compositor does not advertise " << "zwp_keyboard_shortcuts_inhibit_manager_v1" << std::endl; return false; } return true; } bool WCM::lock_input(Gtk::Dialog *grab_dialog) { if (!inhibitor_manager) { std::cerr << "Compositor does not advertise zwp_keyboard_shortcuts_inhibit_manager_v1!" << std::endl; auto error_dialog = Gtk::Dialog( "Compositor does not advertise zwp_keyboard_shortcuts_inhibit_manager_v1!", *window, Gtk::DIALOG_DESTROY_WITH_PARENT); auto label = Gtk::Label("To use input binding capture, enable shortcuts-inhibit plugin."); error_dialog.get_content_area()->pack_start(label, true, true, 50); error_dialog.add_button("Ok", 0); label.show(); error_dialog.run(); return false; } if (shortcuts_inhibitor) { return false; } /* Lock input */ auto surface = gdk_wayland_window_get_wl_surface(gtk_widget_get_window(GTK_WIDGET(grab_dialog->gobj()))); auto seat = gdk_wayland_seat_get_wl_seat(gdk_device_get_seat(gtk_get_current_event_device())); shortcuts_inhibitor = zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts(inhibitor_manager, surface, seat); return true; } void WCM::unlock_input() { if (!shortcuts_inhibitor) { return; } zwp_keyboard_shortcuts_inhibitor_v1_destroy(shortcuts_inhibitor); wl_display_flush(gdk_wayland_display_get_wl_display(gdk_display_get_default())); shortcuts_inhibitor = nullptr; } void WCM::set_plugin_enabled(Plugin *plugin, bool enabled) { if (!plugin || plugin->is_core_plugin() || (plugin->type == PLUGIN_TYPE_WF_SHELL)) { return; } plugin->enabled = enabled; plugin->enabled_check.set_active(enabled); auto wf_opt = wf_config_mgr.get_section("core")->get_option("plugins"); std::string enabled_plugins = wf_opt->get_value_str(); if (!enabled) { auto pos = find_plugin(plugin, enabled_plugins); if (pos == std::string::npos) { return; } while (pos != std::string::npos) { enabled_plugins.erase( pos - ( /* remove space before */ pos != 0 ? 1 : 0), plugin->name.length() + (enabled_plugins.length() != plugin->name.length() ? 1 : 0)); pos = find_plugin(plugin, enabled_plugins); } } else { if (find_plugin(plugin, enabled_plugins) != std::string::npos) { return; } enabled_plugins.append((enabled_plugins.empty() ? "" : " ") + plugin->name); } wf_opt->set_value_str(enabled_plugins); save_to_file(wf_config_mgr, wf_config_file); } void WCM::create_main_layout() { window->signal_key_press_event().connect([] (GdkEventKey *event) { if (event->state & GDK_CONTROL_MASK && (event->keyval == GDK_KEY_q)) { std::exit(0); } return false; }); main_page = std::make_unique(plugins); filter_label.property_margin().set_value(10); filter_label.set_markup("Filter"); main_left_panel_layout.pack_start(filter_label, false, false); search_entry.property_margin().set_value(10); search_entry.signal_search_changed().connect([&] { main_page->set_filter(search_entry.get_text()); }); search_entry.signal_key_press_event().connect([&] (GdkEventKey *event) { if (event->keyval == GDK_KEY_Escape) { search_entry.set_text(""); } return false; }); main_left_panel_layout.pack_start(search_entry, false, false); close_button.property_margin().set_value(10); close_button.signal_clicked().connect([] { std::exit(0); }); main_left_panel_layout.pack_end(close_button, false, false); output_config_button.property_margin().set_value(10); output_config_button.signal_clicked().connect([] { Glib::spawn_command_line_async(OUTPUT_CONFIG_PROGRAM); }); main_left_panel_layout.pack_end(output_config_button, false, false); if (system("command -v " OUTPUT_CONFIG_PROGRAM " > /dev/null 2>&1") != 0) { output_config_button.set_sensitive(false); output_config_button.set_tooltip_markup( "Cannot find program wdisplays"); } plugin_left_panel_layout.pack_start(plugin_name_label, false, false); plugin_name_label.set_line_wrap(); plugin_name_label.set_max_width_chars(15); plugin_name_label.set_alignment(Gtk::ALIGN_CENTER); plugin_name_label.set_justify(Gtk::JUSTIFY_CENTER); plugin_name_label.property_margin().set_value(50); plugin_name_label.set_margin_bottom(25); plugin_left_panel_layout.pack_start(plugin_description_label, false, false); plugin_description_label.set_line_wrap(); plugin_description_label.set_max_width_chars(20); plugin_description_label.set_alignment(Gtk::ALIGN_CENTER); plugin_description_label.set_justify(Gtk::JUSTIFY_CENTER); plugin_description_label.set_margin_left(50); plugin_description_label.set_margin_right(50); plugin_left_panel_layout.pack_start(plugin_enabled_box, false, false); plugin_enabled_box.set_margin_top(25); plugin_enabled_box.pack_start(plugin_enabled_check); plugin_enabled_check.signal_toggled().connect([=] { if (current_plugin) { set_plugin_enabled(current_plugin, plugin_enabled_check.get_active()); } }); plugin_enabled_box.pack_start(plugin_enabled_label); plugin_enabled_box.set_halign(Gtk::ALIGN_CENTER); plugin_left_panel_layout.pack_end(back_button, false, false); back_button.property_margin().set_value(10); back_button.signal_clicked().connect([=] { open_page(); }); left_stack.add(main_left_panel_layout); left_stack.add(plugin_left_panel_layout); left_stack.set_size_request(250, -1); left_stack.set_transition_type(Gtk::STACK_TRANSITION_TYPE_CROSSFADE); main_stack.add(*main_page); main_stack.set_transition_type(Gtk::STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); global_layout.pack_start(left_stack, false, false); global_layout.pack_start(main_stack, true, true); window->add(global_layout); } void WCM::open_page(Plugin *plugin) { if (plugin) { plugin_enabled_box.set_visible( !plugin->is_core_plugin() && plugin->type != PLUGIN_TYPE_WF_SHELL); plugin_enabled_check.set_active(plugin->enabled); plugin_name_label.set_markup( "" + plugin->disp_name + ""); plugin_description_label.set_markup( "" + plugin->tooltip + ""); plugin_page = std::make_unique(plugin); main_stack.add(*plugin_page); plugin_page->show_all(); main_stack.set_visible_child(*plugin_page); left_stack.set_visible_child(plugin_left_panel_layout); } else { main_stack.set_visible_child(*main_page); left_stack.set_visible_child(main_left_panel_layout); } current_plugin = plugin; } static std::string wordexp_str(const char *str) { wordexp_t exp; wordexp(str, &exp, 0); std::string result = exp.we_wordv[0]; wordfree(&exp); return result; } void WCM::load_config_files() { const char *wf_config_file_override = getenv("WAYFIRE_CONFIG_FILE"); const char *wf_shell_config_file_override = getenv("WF_SHELL_CONFIG_FILE"); if (wf_config_file.empty()) { wf_config_file = wordexp_str(wf_config_file_override ? wf_config_file_override : WAYFIRE_CONFIG_FILE); } std::vector wayfire_xmldirs; if (char *plugin_xml_path = getenv("WAYFIRE_PLUGIN_XML_PATH")) { std::stringstream ss(plugin_xml_path); std::string entry; while (std::getline(ss, entry, ':')) { wayfire_xmldirs.push_back(entry); } } wayfire_xmldirs.push_back(WAYFIRE_METADATADIR); wf_config_mgr = wf::config::build_configuration(wayfire_xmldirs, WAYFIRE_SYSCONFDIR "/wayfire/defaults.ini", wf_config_file); if (wf_shell_config_file.empty()) { wf_shell_config_file = wordexp_str( wf_shell_config_file_override ? wf_shell_config_file_override : WF_SHELL_CONFIG_FILE); } #if HAVE_WFSHELL std::vector wf_shell_xmldirs(1, WFSHELL_METADATADIR); wf_shell_config_mgr = wf::config::build_configuration( wf_shell_xmldirs, WFSHELL_SYSCONFDIR "/wayfire/wf-shell-defaults.ini", wf_shell_config_file); #endif } /** * Adapted from wf-config internal source code. * * Go through all options in the section, try to match them against the prefix * of the compound option, thus build a new value and set it. */ void update_compound_from_section(wf::config::compound_option_t *compound, const std::shared_ptr & section) { auto options = section->get_registered_options(); std::vector> new_value; struct tuple_in_construction_t { // How many of the tuple elements were initialized size_t initialized = 0; std::vector values; }; std::map> new_values; const auto & entries = compound->get_entries(); for (size_t n = 0; n < entries.size(); n++) { const auto & prefix = entries[n]->get_prefix(); for (auto & opt : options) { if (wf::config::xml::get_option_xml_node(opt)) { continue; } if (begins_with(opt->get_name(), prefix)) { // We have found a match. // Find the suffix we should store values in. std::string suffix = opt->get_name().substr(prefix.size()); if (!new_values.count(suffix) && (n > 0)) { // Skip entries which did not have their first value set, // because these will not be fully constructed in the end. continue; } auto & tuple = new_values[suffix]; // Parse the value from the option, with the n-th type. if (!entries[n]->is_parsable(opt->get_value_str())) { continue; } if (n == 0) { // Push the suffix first tuple.push_back(suffix); } // Update the Nth entry in the tuple (+1 because the first entry // is the amount of initialized entries). tuple.push_back(opt->get_value_str()); } } } wf::config::compound_option_t::stored_type_t value; for (auto & e : new_values) { // Ignore entires which do not have all entries set if (e.second.size() != entries.size() + 1) { continue; } value.push_back(std::move(e.second)); } compound->set_value_untyped(value); } /** * Save the given configuration to the given file. * * Update the values of the compound options while doing this, as if * they were set from the config file. This is necessary because wf-config will only * save values in the compound list itself, not the options which represent the * entries in the list. */ void WCM::save_to_file(wf::config::config_manager_t & mgr, const std::string & file) { std::cout << "Saving to file " << file << std::endl; for (auto & section : mgr.get_all_sections()) { for (auto & opt : section->get_registered_options()) { auto as_compound = dynamic_cast(opt.get()); if (as_compound) { update_compound_from_section(as_compound, section); } } } wf::config::save_configuration_to_file(mgr, file); } bool WCM::save_config(Plugin *plugin) { if (plugin->type == PLUGIN_TYPE_WAYFIRE) { save_to_file(wf_config_mgr, wf_config_file); return true; } if (plugin->type == PLUGIN_TYPE_WF_SHELL) { save_to_file(wf_shell_config_mgr, wf_shell_config_file); return true; } return false; } std::shared_ptr WCM::get_config_section(Plugin *plugin) { if (plugin->type == PLUGIN_TYPE_WAYFIRE) { return wf_config_mgr.get_section(plugin->name); } #ifdef HAVE_WFSHELL if (plugin->type == PLUGIN_TYPE_WF_SHELL) { return wf_shell_config_mgr.get_section(plugin->name); } #endif return nullptr; } std::string WCM::find_icon(const std::string & name) { // first try to find it in the user's local folders std::string icon_path; std::string xdg_data_dir; char *c_xdg_data_dir = std::getenv("XDG_DATA_HOME"); char *c_user_home = std::getenv("HOME"); if (c_xdg_data_dir != NULL) { xdg_data_dir = c_xdg_data_dir; } else if (c_user_home != NULL) { xdg_data_dir = (std::string)c_user_home + "/.local/share/"; } if (!xdg_data_dir.empty()) { icon_path = xdg_data_dir + "/wayfire/icons/" + name; if (std::filesystem::exists(icon_path)) { return icon_path; } } return ICONDIR "/" + name; } wcm-master/src/wcm.hpp000066400000000000000000000256231453243033400152340ustar00rootroot00000000000000/* * Copyright © 2020 Scott Moreau * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #pragma once #include #include #include #include #include #include #include #include #include #include #include "metadata.hpp" class MainPage : public Gtk::ScrolledWindow { public: static const int NUM_CATEGORIES = 8; MainPage(const std::vector & plugins); void set_filter(const Glib::ustring & filter); private: struct Category { Glib::ustring name; Gtk::Box vbox = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 10); Gtk::Box title_box = Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 10); Gtk::Image image; Gtk::Label label; Gtk::FlowBox flowbox; Category(const Glib::ustring & name_string, const Glib::ustring & icon_name); void add_plugin(Plugin *plugin); }; const std::vector & plugins; Gtk::Box vbox = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 10); Glib::RefPtr size_group = Gtk::SizeGroup::create( Gtk::SIZE_GROUP_BOTH); std::array separators; std::array categories = { Category{"General", "preferences-system"}, {"Accessibility", "preferences-desktop-accessibility"}, {"Desktop", "preferences-desktop"}, {"Shell", "user-desktop"}, {"Effects", "applications-graphics"}, {"Window Management", "applications-accessories"}, {"Utility", "applications-other"}, {"Other", "applications-other"}}; }; class KeyEntry : public Gtk::Stack { Gtk::Box grab_layout = Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 10); Gtk::Label grab_label = Gtk::Label("(none)"); Gtk::Button grab_button; Gtk::Button edit_button; Gtk::Box edit_layout = Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 10); Gtk::Entry entry; Gtk::Button ok_button; Gtk::Button cancel_button; static mod_type get_mod_from_keyval(guint keyval); static bool check_and_confirm(const std::string & key_str); static std::string grab_key(); sigc::signal changed; public: KeyEntry(); inline sigc::signal signal_changed() { return changed; } inline std::string get_value() const { return grab_label.get_text(); } void set_value(const std::string & value) { grab_label.set_label(value); entry.set_text(value); changed.emit(); } }; class LayoutsEntry : public Gtk::Entry { Gtk::SeparatorMenuItem separator; std::vector layouts; public: LayoutsEntry(); }; class XkbModelEntry : public Gtk::Entry { Gtk::SeparatorMenuItem separator; std::vector models; public: XkbModelEntry(); }; class OptionWidget : public Gtk::Box { Gtk::Label name_label; std::vector> widgets; Gtk::Button reset_button; inline void pack_end(std::unique_ptr && widget, bool expand = false, bool fill = false) { Gtk::Box::pack_end(*widget, expand, fill); widgets.push_back(std::move(widget)); } public: OptionWidget(Option *option); }; class DynamicListBase : public Gtk::Box { protected: Gtk::Box add_box = Gtk::Box(Gtk::ORIENTATION_HORIZONTAL); Gtk::Button add_button; std::vector> widgets; inline void pack_widget(std::unique_ptr && widget) { pack_start(*widget, false, false); widgets.push_back(std::move(widget)); } inline void remove(Gtk::Widget *widget) { widgets.erase(std::find_if(widgets.begin(), widgets.end(), [=] (std::unique_ptr & w) { return w.get() == widget; })); } DynamicListBase(); }; class AutostartDynamicList : public DynamicListBase { struct AutostartWidget : public Gtk::Box { Gtk::Entry command_entry; Gtk::Button choose_button; Gtk::Button run_button; Gtk::Button remove_button; AutostartWidget(Option *option); }; public: explicit AutostartDynamicList(Option *option); }; class BindingsDynamicList : public DynamicListBase { struct BindingWidget : public Gtk::Frame { Gtk::Expander expander = Gtk::Expander("Command:"); Gtk::Box vbox = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 10); Gtk::Box type_box = Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 10); Gtk::Box binding_box = Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 10); Gtk::Box command_box = Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 10); Gtk::Label type_label = Gtk::Label("Type"); Gtk::Label binding_label = Gtk::Label("Binding"); Gtk::Label command_label = Gtk::Label("Command"); Gtk::ComboBoxText type_combo_box; std::unique_ptr key_entry; Gtk::Entry command_entry; Gtk::Button remove_button; std::shared_ptr binding_wf_opt; BindingWidget(const std::string & cmd_name, Option *option, wf_section section); }; public: explicit BindingsDynamicList(Option *option); }; enum class VswitchBindingKind { WITHOUT_WINDOW, WITH_WINDOW, SEND_WINDOW, }; template class VswitchBindingsDynamicList : public DynamicListBase { static const std::string OPTION_PREFIX; struct BindingWidget : public Gtk::Box { Gtk::Label label = Gtk::Label("Workspace"); Gtk::SpinButton workspace_spin_button = Gtk::SpinButton(Gtk::Adjustment::create(1, 1, 30)); KeyEntry key_entry; Gtk::Button remove_button; std::shared_ptr binding_wf_opt; BindingWidget(std::shared_ptr section, Option *option, int workspace_index); }; public: explicit VswitchBindingsDynamicList(Option *option); }; template class VswitchBindingsWidget : public Gtk::Frame { VswitchBindingsDynamicList dynamic_list; static const Glib::ustring LABEL_TEXT; public: explicit VswitchBindingsWidget(Option *option); }; class OptionSubgroupWidget : public Gtk::Frame { Gtk::Expander expander; Gtk::Box expander_layout = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 10); std::vector option_widgets; public: OptionSubgroupWidget(Option *subgroup); }; class OptionGroupWidget : public Gtk::ScrolledWindow { Gtk::Box options_layout = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 10); std::vector> option_widgets; public: OptionGroupWidget(Option *group); }; class PluginPage : public Gtk::Notebook { std::vector groups; public: PluginPage(Plugin *plugin); }; class WCM { private: void parse_config(wf::config::config_manager_t & config_manager); bool init_input_inhibitor(); void create_main_layout(); void save_to_file(wf::config::config_manager_t & mgr, const std::string & file); // these objects can be used when widgets are destroyed and emit `signal_changed` // causing saving config // so these objects should be destroyed after widgets wf::config::config_manager_t wf_config_mgr; wf::config::config_manager_t wf_shell_config_mgr; std::string wf_config_file; std::string wf_shell_config_file; std::vector plugins; Plugin *current_plugin = nullptr; std::unique_ptr window; Gtk::Box global_layout; Gtk::Stack main_stack; /* for animated transition */ std::unique_ptr main_page; std::unique_ptr plugin_page; Gtk::Stack left_stack; /* for animated transition */ Gtk::Box main_left_panel_layout = Gtk::Box(Gtk::ORIENTATION_VERTICAL); Gtk::Label filter_label; Gtk::SearchEntry search_entry; PrettyButton close_button = PrettyButton("Close", "window-close"); PrettyButton output_config_button = PrettyButton("Configure Outputs", "computer"); Gtk::Box plugin_left_panel_layout = Gtk::Box(Gtk::ORIENTATION_VERTICAL); Gtk::Label plugin_name_label; Gtk::Label plugin_description_label; Gtk::Box plugin_enabled_box = Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 10); Gtk::CheckButton plugin_enabled_check; Gtk::Label plugin_enabled_label = Gtk::Label("Use This Plugin"); PrettyButton back_button = PrettyButton("Back", "go-previous"); cairo_surface_t *grab_window_surface = nullptr; zwp_keyboard_shortcuts_inhibitor_v1 *shortcuts_inhibitor = nullptr; zwp_keyboard_shortcuts_inhibit_manager_v1 *inhibitor_manager = nullptr; // WCM is a singleton static inline WCM *instance = nullptr; public: WCM(Glib::RefPtr app); static inline WCM *get_instance() { if (instance == nullptr) { throw std::logic_error( "Cannot get an instance of WCM before it's initialized"); } return instance; } void open_page(Plugin *plugin = nullptr); void set_plugin_enabled(Plugin *plugin, bool enabled); std::string find_icon(const std::string & icon_name); void load_config_files(); inline void parse_config() { parse_config(wf_config_mgr); } std::shared_ptr get_config_section(Plugin *plugin); #if HAVE_WFSHELL inline void parse_wfshell_config() { parse_config(wf_shell_config_mgr); } #endif bool save_config(Plugin *plugin); inline std::string get_xkb_rules() { return wf_config_mgr.get_section("input")->get_option("xkb_rules")->get_value_str(); } inline void set_inhibitor_manager(zwp_keyboard_shortcuts_inhibit_manager_v1 *value) { inhibitor_manager = value; } bool lock_input(Gtk::Dialog *grab_dialog); void unlock_input(); }; wcm-master/subprojects/000077500000000000000000000000001453243033400155015ustar00rootroot00000000000000wcm-master/subprojects/wdisplays/000077500000000000000000000000001453243033400175205ustar00rootroot00000000000000wcm-master/wayfire-config-manager.desktop000066400000000000000000000002051453243033400210470ustar00rootroot00000000000000[Desktop Entry] Name=Wayfire Config Manager Comment=Configure Wayfire Settings Exec=wcm Icon=wcm Type=Application Categories=Utility;