From 40cf8de1a802aa6f4a659d3d93943638cf12fd37 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Mon, 30 Jan 2023 14:46:56 +0100 Subject: [PATCH 01/56] Fix: Don't affect (or interact with) panel of unlock screen The panel gets set to the state it should have for the unlock screen before extension disable. Because of this the extension makes icons show, which shouldn't show. So fix that by not ordering the panel, if the current session mode isn't "user". Also generally don't interact with the panel, if the current session mode isn't "user". --- src/extension.js | 10 ++++++++++ src/extensionModules/BoxOrderManager.js | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/src/extension.js b/src/extension.js index e197917..73bfd24 100644 --- a/src/extension.js +++ b/src/extension.js @@ -94,6 +94,11 @@ class Extension { * @param {string} box - The box to order. */ #orderTopBarItems(box) { + // Only run, when in "user" session mode. + if(Main.sessionMode.currentMode !== "user") { + return; + } + // Get the valid box order. const validBoxOrder = this._boxOrderManager.createValidBoxOrder(box); @@ -147,6 +152,11 @@ class Extension { * orders the items of all top bar boxes. */ #handleNewItemsAndOrderTopBar() { + // Only run, when in "user" session mode. + if(Main.sessionMode.currentMode !== "user") { + return; + } + this._boxOrderManager.saveNewTopBarItems(); this.#orderTopBarItems("left"); this.#orderTopBarItems("center"); diff --git a/src/extensionModules/BoxOrderManager.js b/src/extensionModules/BoxOrderManager.js index 76ce2bb..9f04f33 100644 --- a/src/extensionModules/BoxOrderManager.js +++ b/src/extensionModules/BoxOrderManager.js @@ -184,6 +184,11 @@ var BoxOrderManager = GObject.registerClass({ * bar to the correct box orders. */ saveNewTopBarItems() { + // Only run, when in "user" session mode. + if(Main.sessionMode.currentMode !== "user") { + return; + } + // Load the configured box orders from settings. const boxOrders = { left: this.#settings.get_strv("left-box-order"), From 40846915e78fca864891c81b0879f2915304a481 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Mon, 30 Jan 2023 15:28:58 +0100 Subject: [PATCH 02/56] Fix: Check, if signal handler is connected for handler id, before dc. Do this to hopefully fix "No signal connection XX found" errors. --- src/extensionModules/BoxOrderManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extensionModules/BoxOrderManager.js b/src/extensionModules/BoxOrderManager.js index 9f04f33..19a0535 100644 --- a/src/extensionModules/BoxOrderManager.js +++ b/src/extensionModules/BoxOrderManager.js @@ -127,7 +127,7 @@ var BoxOrderManager = GObject.registerClass({ */ disconnectSignals() { for (const [handlerId, appIndicator] of this.#appIndicatorReadyHandlerIdMap) { - if (handlerId && appIndicator) { + if (handlerId && appIndicator?.signalHandlerIsConnected(handlerId)) { appIndicator.disconnect(handlerId); } } From 6bc40441a780b92091fa6838de32835d17c607df Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Mon, 30 Jan 2023 15:33:14 +0100 Subject: [PATCH 03/56] Other: Bump version to 6 --- src/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metadata.json b/src/metadata.json index bdc6ffd..8896e2e 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -2,7 +2,7 @@ "uuid": "top-bar-organizer@julian.gse.jsts.xyz", "name": "Top Bar Organizer", "description": "Organize the items of the top (menu)bar.", - "version": 5, + "version": 6, "shell-version": [ "42", "43" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", "url": "https://gitlab.gnome.org/julianschacher/top-bar-organizer" From 4be693a1343d0fceaff4f47dd79f0223af96f81e Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Mon, 30 Jan 2023 18:10:52 +0100 Subject: [PATCH 04/56] Docs: Add README with screenshot, extension desc. and installation notes --- README.md | 10 ++++++++++ ...s preferences in light theme 2023-01-30.jpg | Bin 0 -> 182150 bytes 2 files changed, 10 insertions(+) create mode 100644 README.md create mode 100644 res/Screenshot of GNOME Shell 43 with Top Bar Organizer v6 and its preferences in light theme 2023-01-30.jpg diff --git a/README.md b/README.md new file mode 100644 index 0000000..20527b4 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# Top Bar Organizer + +![Screenshot of GNOME Shell 43 with Top Bar Organizer v6 running and its preferences open. The GNOME Shell top bar items aren't all in their default location.](./res/Screenshot%20of%20GNOME%20Shell%2043%20with%20Top%20Bar%20Organizer%20v6%20and%20its%20preferences%20in%20light%20theme%202023-01-30.jpg) + +Top Bar Organizer allows you to organize the items of the GNOME Shell top (menu)bar. + +## Installation + +The extension is available on the [GNOME Extensions website](https://extensions.gnome.org/extension/4356/top-bar-organizer/). +Or you can also manually install a release from the [releases page](https://gitlab.gnome.org/julianschacher/top-bar-organizer/-/releases). diff --git a/res/Screenshot of GNOME Shell 43 with Top Bar Organizer v6 and its preferences in light theme 2023-01-30.jpg b/res/Screenshot of GNOME Shell 43 with Top Bar Organizer v6 and its preferences in light theme 2023-01-30.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bb9594d0b6db44a2e2f6e008e29c56c57fb3f514 GIT binary patch literal 182150 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

#EK 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

3xrlkxWhcN+(5J zyIoXDjC_`ze0-V>V`wu;(cQZ9;>1gj8=rnM+@<&=d$&v6 zHB*;uscvkSN?a$ulH9Xr<|LzgEX!_|XG`>UbSt$jTzKNPUvIZVbhVh%uYAzr#g(lr z^Kb5&sPgJW-J$J~?+SeOF-&WFX!fB;&v&(xkXPnm&o5G8Z>MRlnf*=GVy^DRmA6iK zTozq=PD<$X2}OkkOH~y8RLy49KdnBXD3xoR+HlvULcB*mp;g4IZMpAZCtki|3z83f zu#)R(T*t4t%<#Swhs17bC)XRbn-mEGIROlLN>`SQd3+~l4t&%Ao_)S zV&-?-$)J`Uwk~tc*54*#vy}28w>d;i>e(<=IUrqBu=TdG%FLG4)6;UzX17^Xyl>Ys z(s5(m-sau4Ec*2tx8Td2Hzr$1?0n^XM^*4bvGz_zxe1jXDT=DgEvpJQ9k?u6&|0&U z>$z?wpUFDs`X~FJgzlTvC;TAJU~iM5I8#vDiPFW+&b|v*9ApWcxLPSAi>=*;mnZqx z@g2w1I2KP_xNxHL#)Y$c`I#@XiRtmNeq}RNUTbq~L2{Z~x|K<*?j+j>y~f*i%~jrWz(^bM!}lB-;BVy0Y9iMi#Xsd39s%-P*@ zFi_gJH&yW3CY!4#MVrcvO#G`kUkgkxT(#Hc$)PHnuQD?_({$FSf=(kbu~?F|Gn~2L zTZ&m?^{)__6`n2;Zk?v?g>lkTwPOT0m?lYV=gv^9Z<@5C%`_{VM~}s~Y+CXeBmXe% za+8+m=^UQXc{`;!PDdvdoXNSByY2R-#)fvO28}?Dg8NEBR~9q6%~UIDSv#Ri)AP}q zDYN%Il<@vDJwrv^_nD57)Xw=#A6w7dS+MQ3lSry3jJS@T4MI`CS*AuOC4F#oi%LMuk3G{R{%3PFKm^Igqv(Z#W zR$$6n+1{-|&KsUy?bTkXbU1NR<2DiXClQ>Fn?!$zuxi|BSD93B+RQw?aOG*qlF5&+ zxo+yo;jg{&==635y)=FPI<^_yVW>v1e0#o;Q4 zsk3~td@$tr=hM*2L42~loceZSngI)t80n9I!+DRi(|_UP=*wq9T7tB5D%u{>{zdZV}_ zn)Ae*{G{?@O`BdQXjo2EQ+L%B-pYGgk2TzGaq&g&eay8^en<8#OnEwEVx-&Cb!U7J z3M{_j>{lhZn``NJse3uMcU&<#z2Hj3g)0wEY&hieA>n-5KbwqMr&UT+o^4Xq%UrZ? zdisU^>O&bR2S1yv{klX+Tj%Db*|U%L-%u=2V_C>!IZ2~SYGKDo@nlcI(8d?Xj&;nH zl6~=`v8RcxZLi0Lt3AmJ@3pn9d8e~tUdQG;Qk}`NYh`m>B7O^)%nw{`-FJuY%;9gk z0_9S2KD{2-1DCXS>55L~Z%gjwS+q5ct)o#(Qp8rEcguk-P687@>2O;eSRZn9k8q=1 z$+6B~T@!X3Y;zT5-yvtOqA_n#xy$5}X(r`Q0>m91F6lN+vN@qzcPM)EF1dD3$)bd9 z#;0ofyqnZCx?Y(~R6D%GIbi=o`G8LKpfrVy5;?X#$1@Hqhn-&Md$&lf+{ntlUplC# z;QS-`Gxjs;4gMwmIsCKzGygOCa6j@Cv@EQ+elecPuKGl4^XA zEG2Q_S5ML#6}M$ZY+C}3DY6;OF0uReI627lMMA}M_Zzt%98O52b}O~-6)l6}~K$qbum)5+gj#t@H53==6yeckXmgG*m89 zdAUExYwrhj0kdZ=PcNF(PPCoo)pF$ZN`75dE~B|SoLcJ6?ctUR`^BHTbjRC>D_^91 zdByHj{OL<-`^D?1RmEp>d~ff1CC?kX?>*sb&pNhx#mhbeJ9C4(66aYIuX(F8RlV>3 zDqVJA%NA8hS-~9_jyYVo^2Shy*KdO966u~a_Qo~5{B8>xUy77TeZAPXrc%;TOS#~K z{u-NpWht}9zLN_VE;cf;>4@6+B<*2O=;DB|$LH8K7+>|ByRfq;ijKrjSiv_bI2oFZ=~D%aoK<%>6F^XYhA=em+rU>Bg=-Duxa-#Mz!F zD@!)MWD2r4w(!Q;_5;V-3>U7Il9(vdlN@Gv;li7Y3aO0?A8eAla+l@F39YC6A|=v0 z@p{uQ<{qm-*tR8s9v9w~i=XGox0e zh1@yStMuIS%~aQlIJSgHT#Pg6nCLmP(OUGK|E@DCI$MtR_P&{FBm5+JrNxOk8*N*b z@G;9iHM+b$v90Tsc9>(`A-T|Q(MCO%=PQmaKVA5Jn$JYxE3GceP2Z`S@2u^XN?!L^ z%IDXO>$A+mQa38gGC7qvtf*>K_0i;7H_PjZgUXaImp}h!@O7)2((&%bE#uj?DoeDM zs@y%vvvtWzL7glPWj7NWUWW;5%31>_JZ5$~?Cj#n>>Rq-*-U=HmFFHx?n@lrIJTd- zDxvaC>DM8zjd`zr$Q%w_9F=39zT?CsofPT5Hfw7!6JzFpV{ZzX^%h07Z2Ok1>$-QT3gwxwL}#DNLNmMvD&FBEuf<#Hx*FY`~1nY(t_H?(zUeBxO?!TzUH z?Yxc}f5*jN_&Z-%>=#lxz99C;gdc)81#-S9*}iM`vuj>BQT&DTqhBV?ij#yd{0oxa zR;BpSmi<2i!#^hb2ABT~j9j)&{1;4ezVKR9iMh;kxh?0S_LoVxeUTNvi;0e{p!y4W z<_rHA|1dB4B5-sb+a6oK$roPOa?F!!E<5jdvVGx&D(=n~cI*p2SF?M*h-_c*!>)NU zzvJ>hY;FG-Ew!rn8()|_eBu6&CGNbF{Rid$3`#b(93Q?|`8zNDqOh$>R)3+KT-(Vn zLO+zW6fbqHH8L?=Z@93hT7oC-P;=FUW6KvdaqO0o+V_OV`NVa{*}OcZ+t%LrxY+fI z=bP?Vyb*6S6<0b>*}cwOW#tOF{-mTOc|QKiQlE`_4p}QMzL6X_vG>M}Clv-_bw|1{ zly79=T=B-&TDURA>7dbn=M|qsI$jvxGAyDRg`CT@^NZ+ncK97>r|g) z`)R3-$^{XhrYoClQM>&@omb<#@ahwHjP)C5hje~6oD^0r%Xh2yyL6;oYDoWvYf>i- ze!tl0RNK2br7*T9%)R=0;;7R<5qC&T`h&>}mn_S( z^zn_3%Z)~_>sW&R+Y&Rq*kR--`tQGjM$QBK7f&bBpQB^-fA+$F#0adf~8= zmzSSKnwK|YN=CAgtMIL5hHH`oj1_yDtaz$>nmFXzliyevSzV|u|X% zX>j$E0hnc!f4s5*I8i^%UA7p`zAN;{$R$;oHu8BYF% zB0tpMPKs^uSavnfw8vTWiO8qjyo&kPV8{JZC+!s7G7QC_M!KV6!OCJQzzxdVtD*pzrPVWmDCZCn1 zWjpy3`I`L%E)|$QXo*rh$hhEvlEq2ci{%;pGfum1k`j1O%O+v%Hb3Ba#xM4ZuIu); zs{Uu-(*LRb|;!oTCBlA8<9s-B5!es#u5nHzOSiimYdZmacCjL*$>>(o6c)E}(6UB}5t zS4bghf{Kz(M^f~}WiCga+&RuqJicdVhWSdq&?+-8D-BfM zaweR)_~)gZ_ey)B-Zon1CKv9QZMvGX1T=`55D*LFO*}?$v99EvFY_r z&Ys0KUNSvK$8DTq+4+`-@@-^(tNBN=>_VY}M=eM3DOvd!i>yt|#nRk&Z#eC`rGL5m zUa73I%vz>6-os`qB#LAWj9bNwS`0olb{Su>UuM@VlactJA!=@`NkZqz79%4^5xeFu z3N<`l6R!61l(>}0^fL=gv*&jHB5|zai}W6T<$(6Z62}rUvJ#TQD#S0^et1!EtYu=` zf~*^t?glK+=WjDzsMuTe;^K_ti}&1~D@#kuX(S)G7&`fpac7XiiHk|EQhWt$S)EGH za4em1ZQ7HKoEZ~31lDv3Iy7-8l{mS$PE7X|Ke6Uc%X?v^qRDYhb=r{8C`^xA&nsPb6aFy>49gQ1qQ&V#82Qyw~4wP-_mS1qWxwx>8w>RmS z%JDq5@9EBGvI|$;G+enY%3O(UdE&|^CCA!kCr1>VXyRyGt+{cf%AT+77E)!oH+s3> zDV_l{b9%4)UPT|Jf-*UpSd zLIP7byh>VLGFeG0aoloq+$rv&DdxG(FW0v##?X#cZ`q}?J9Bb0)tjy;-n^2(Mk!JB z7I)@s&U=rR9ymO)yRo!D!|(X+`x95*JG<@4VYN87Jr`4cbHC;;m+5tyvCqA>ZSF+o zf;TgdD6TzrKWX7R(`Rn!%E3)1i!3$Ia`)tz+B*N|R8IRC{z-)o{YBQqz;Vw!0_u zOmDRO&(QKQKhfm7^j*V*uw~kfm--!#SjaB3d{i}Q_G&95mxR0!;dI_Dx$8|5c}{Y< ze3JOqYct#Ypuq;aICrl#dF`G#iQL611zLWOil*eBIBB1xP$?4^XslCq_NUaE8}F?r zS`-~=w_apq(f&bEWaGIofxBK`rRMyR5S}vm;?4-e9aofWBfd%PR=A~bXOY$9gIlY5 zU3$X~D|9uz5}VzV5p~*0U_+>-$W)##1FK6aUFNbKz3r3Klh|6P8AvIVm{jvt@$&MN z{E%Z?(W~U{ByoIVPvgRg&Jr7B`|iHDqGTng!p|IKDRP4ePo`nk+v*}bQR`RhK z&fxyWqPG3w!i5u3vR8IWow&-&dq_s<@Q>B$8!pMY*?f@|aAXc&btU?nZlIQl3$Ny- zlDWcPj10m`6onZj4O$mjT$OY3eh{VNl&7xZT72NH zBhyL^5{hEJJlOnnevVVL`c%KgWs;f;&Bc|BmR~7ynQ>SyF;cv)g@55b{f(kKKDo*# zIIfghBY5&g*_w<#!HFj~ZsSpOiTre2=ulub)3aci7bkYMIm7Wo1sJml|N}h3& zN|E6rwk?f4*y8Nl8f@uXWQ= zeB1L_;_tCH85swD^`4gFlDzOHQq08b;pA<96Hf}g0?i<`Ey&1n>yX$gc6W=|65l+V ziOE-1ava*|J7XnpVDrU=Ps)QY%CaPQZHZD}{Q%7aZ zs--7oO`mPBu6JqYN{@rzq_0)QSekpxnm#f5&txu%IUDzMRf;8Ec*~Pi&~$6B&qlfA zWp;l(?-b1W*|%ONuc%Lz-$vpr_m=4=9z}nVKX9dzGkn99%HDu$p5C#prv5vw&d}pg z6|;7BmFYV%%}(O%Po|c8<3(WB-8*7q0LMSRZ72t{g33dwh;yva_6fbD6zkZ-!UfmSkrsvjfMk z@=BN59NW|GA@ZWc~oCa#>vA?)aD Z{LCfdOO=U{O5@4fZl@Q!@bdh>2>?{YhvEPL literal 0 HcmV?d00001 From 39face99579698ae1cb40fbea1cbc35819182e98 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Sun, 5 Feb 2023 17:49:55 +0100 Subject: [PATCH 05/56] Fix: Also interact with the panel, if the parent session mode is "user" Top Bar Organizer used to only interact with the panel, when the current session mode is "user". However Ubuntu uses "ubuntu" as its session mode, which made Top Bar Organizer not work. Fix this by also interacting with the panel, if the parent session mode is "user". See here for some docs on session modes: https://gjs.guide/extensions/topics/session-modes.html --- src/extension.js | 10 ++++++---- src/extensionModules/BoxOrderManager.js | 5 +++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/extension.js b/src/extension.js index 73bfd24..dad434c 100644 --- a/src/extension.js +++ b/src/extension.js @@ -94,8 +94,9 @@ class Extension { * @param {string} box - The box to order. */ #orderTopBarItems(box) { - // Only run, when in "user" session mode. - if(Main.sessionMode.currentMode !== "user") { + // Only run, when the session mode is "user" or the parent session mode + // is "user". + if(Main.sessionMode.currentMode !== "user" && Main.sessionMode.parentMode !== "user") { return; } @@ -152,8 +153,9 @@ class Extension { * orders the items of all top bar boxes. */ #handleNewItemsAndOrderTopBar() { - // Only run, when in "user" session mode. - if(Main.sessionMode.currentMode !== "user") { + // Only run, when the session mode is "user" or the parent session mode + // is "user". + if(Main.sessionMode.currentMode !== "user" && Main.sessionMode.parentMode !== "user") { return; } diff --git a/src/extensionModules/BoxOrderManager.js b/src/extensionModules/BoxOrderManager.js index 19a0535..a206739 100644 --- a/src/extensionModules/BoxOrderManager.js +++ b/src/extensionModules/BoxOrderManager.js @@ -184,8 +184,9 @@ var BoxOrderManager = GObject.registerClass({ * bar to the correct box orders. */ saveNewTopBarItems() { - // Only run, when in "user" session mode. - if(Main.sessionMode.currentMode !== "user") { + // Only run, when the session mode is "user" or the parent session mode + // is "user". + if(Main.sessionMode.currentMode !== "user" && Main.sessionMode.parentMode !== "user") { return; } From 470ebf761d22b0cdfae0e1777cf1c789e5b0c222 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Sun, 5 Feb 2023 18:18:45 +0100 Subject: [PATCH 06/56] Fix: Keep hidden items hidden --- src/extension.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/extension.js b/src/extension.js index dad434c..99cfaec 100644 --- a/src/extension.js +++ b/src/extension.js @@ -124,6 +124,9 @@ class Extension { // Get the indicator container associated with the current role. const associatedIndicatorContainer = Main.panel.statusArea[role].container; + // Save whether or not the indicator container is visible. + const isVisible = associatedIndicatorContainer.visible; + associatedIndicatorContainer.get_parent().remove_child(associatedIndicatorContainer); if (box === "right") { // If the target panel box is the right panel box, insert the @@ -142,6 +145,11 @@ class Extension { } else { panelBox.insert_child_at_index(associatedIndicatorContainer, i); } + + // Hide the indicator container again, if it wasn't visible. + if (!isVisible) { + associatedIndicatorContainer.hide(); + } } // To handle the case, where the box order got set to a permutation // of an outdated box order, it would be wise, if the caller updated the From fa379607ee7ea36bd21f7d7c6a116cde4f8624c8 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Mon, 6 Feb 2023 13:57:42 +0100 Subject: [PATCH 07/56] Other: Bump version to 7 --- src/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metadata.json b/src/metadata.json index 8896e2e..eb9407a 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -2,7 +2,7 @@ "uuid": "top-bar-organizer@julian.gse.jsts.xyz", "name": "Top Bar Organizer", "description": "Organize the items of the top (menu)bar.", - "version": 6, + "version": 7, "shell-version": [ "42", "43" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", "url": "https://gitlab.gnome.org/julianschacher/top-bar-organizer" From 5c8523322beb2fe4a524a14be98fd2de9bc0b060 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Thu, 20 Apr 2023 12:33:30 +0200 Subject: [PATCH 08/56] Update: Improve drag handle styling by using GNOME Settings style This also finally makes the style `` in `prefs-box-order-item-row.ui` actually do something. --- data/css/prefs.css | 9 +++++++++ package.sh | 1 + src/prefs.js | 11 +++++++++++ 3 files changed, 21 insertions(+) create mode 100644 data/css/prefs.css diff --git a/data/css/prefs.css b/data/css/prefs.css new file mode 100644 index 0000000..5cafea5 --- /dev/null +++ b/data/css/prefs.css @@ -0,0 +1,9 @@ +/* Taken from: https://gitlab.gnome.org/GNOME/gnome-control-center/-/blob/43.5/shell/style.css */ + +.drag-handle { + color: alpha(@theme_fg_color, 0.4); +} + +.drag-handle:backdrop { + color: alpha(@theme_unfocused_fg_color, 0.4); +} diff --git a/package.sh b/package.sh index 7c9739d..99392e9 100755 --- a/package.sh +++ b/package.sh @@ -9,4 +9,5 @@ gnome-extensions pack "$REAL_BASE_DIR/src" \ --extra-source extensionModules \ --extra-source prefsModules \ --extra-source ../data/ui \ + --extra-source ../data/css \ --schema ../data/org.gnome.shell.extensions.top-bar-organizer.gschema.xml diff --git a/src/prefs.js b/src/prefs.js index 309bbc6..e21e4df 100644 --- a/src/prefs.js +++ b/src/prefs.js @@ -1,11 +1,22 @@ "use strict"; /* exported buildPrefsWidget, init */ +const Gtk = imports.gi.Gtk; +const Gdk = imports.gi.Gdk; + const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); const PrefsPage = Me.imports.prefsModules.PrefsPage; +const provider = new Gtk.CssProvider(); +provider.load_from_path(Me.dir.get_path() + "/css/prefs.css"); +Gtk.StyleContext.add_provider_for_display( + Gdk.Display.get_default(), + provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION +); + function buildPrefsWidget() { return new PrefsPage.PrefsPage(); } From 51a89aec60e684f7d62d32731f01dd085139d306 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Thu, 20 Apr 2023 23:17:06 +0200 Subject: [PATCH 09/56] Feature: Support GNOME version 44 --- src/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metadata.json b/src/metadata.json index eb9407a..d8ba9de 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -3,7 +3,7 @@ "name": "Top Bar Organizer", "description": "Organize the items of the top (menu)bar.", "version": 7, - "shell-version": [ "42", "43" ], + "shell-version": [ "42", "43", "44" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", "url": "https://gitlab.gnome.org/julianschacher/top-bar-organizer" } From bf598f2a1569846fb161cbe837afb9982dd65d94 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Thu, 20 Apr 2023 23:19:02 +0200 Subject: [PATCH 10/56] Other: Bump version to 8 --- src/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metadata.json b/src/metadata.json index d8ba9de..c87a860 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -2,7 +2,7 @@ "uuid": "top-bar-organizer@julian.gse.jsts.xyz", "name": "Top Bar Organizer", "description": "Organize the items of the top (menu)bar.", - "version": 7, + "version": 8, "shell-version": [ "42", "43", "44" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", "url": "https://gitlab.gnome.org/julianschacher/top-bar-organizer" From 0b3aff665ae973c9e7b28124591e1a001d06160b Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Fri, 21 Apr 2023 00:46:59 +0200 Subject: [PATCH 11/56] Fix: Move provider add. to more correct place and remove prov. on dest. See here for the relevant review: https://extensions.gnome.org/review/40563 --- src/prefs.js | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/prefs.js b/src/prefs.js index e21e4df..f11f767 100644 --- a/src/prefs.js +++ b/src/prefs.js @@ -9,16 +9,26 @@ const Me = ExtensionUtils.getCurrentExtension(); const PrefsPage = Me.imports.prefsModules.PrefsPage; -const provider = new Gtk.CssProvider(); -provider.load_from_path(Me.dir.get_path() + "/css/prefs.css"); -Gtk.StyleContext.add_provider_for_display( - Gdk.Display.get_default(), - provider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION -); - function buildPrefsWidget() { - return new PrefsPage.PrefsPage(); + const provider = new Gtk.CssProvider(); + provider.load_from_path(Me.dir.get_path() + "/css/prefs.css"); + const defaultGdkDisplay = Gdk.Display.get_default(); + Gtk.StyleContext.add_provider_for_display( + defaultGdkDisplay, + provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + ); + + const prefsPage = new PrefsPage.PrefsPage(); + + prefsPage.connect("destroy", () => { + Gtk.StyleContext.remove_provider_for_display( + defaultGdkDisplay, + provider + ); + }); + + return prefsPage; } function init() { From ed10e7a14bdc8d90866987a6b2ecb7578e4b4a60 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Fri, 21 Apr 2023 00:56:12 +0200 Subject: [PATCH 12/56] Other: Bump version to 9 --- src/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metadata.json b/src/metadata.json index c87a860..beb577c 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -2,7 +2,7 @@ "uuid": "top-bar-organizer@julian.gse.jsts.xyz", "name": "Top Bar Organizer", "description": "Organize the items of the top (menu)bar.", - "version": 8, + "version": 9, "shell-version": [ "42", "43", "44" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", "url": "https://gitlab.gnome.org/julianschacher/top-bar-organizer" From 5d0aec54385b7e429611ae804b9d4d2f8d4a2461 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Fri, 12 May 2023 17:47:23 +0200 Subject: [PATCH 13/56] Docs: Mention community-maintained AUR package in README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 20527b4..fc8c8ba 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,5 @@ Top Bar Organizer allows you to organize the items of the GNOME Shell top (menu) The extension is available on the [GNOME Extensions website](https://extensions.gnome.org/extension/4356/top-bar-organizer/). Or you can also manually install a release from the [releases page](https://gitlab.gnome.org/julianschacher/top-bar-organizer/-/releases). + +There's also a community-maintained [AUR package](https://aur.archlinux.org/packages/gnome-shell-extension-top-bar-organizer) available. From 62e9609b2d123841d73113ac731db61a3e4fbf08 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Tue, 26 Sep 2023 23:25:06 +0200 Subject: [PATCH 14/56] Docs: Add newer, cut down and commented panel.js from GNOME Shell 45.0 --- docs/panel_45.0_2023-09-26.js | 344 ++++++++++++++++++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 docs/panel_45.0_2023-09-26.js diff --git a/docs/panel_45.0_2023-09-26.js b/docs/panel_45.0_2023-09-26.js new file mode 100644 index 0000000..bb44a90 --- /dev/null +++ b/docs/panel_45.0_2023-09-26.js @@ -0,0 +1,344 @@ +// My annotated and cut down `js/ui/panel.js` from gnome-shell/45.0. +// All annotations are what I guessed, interpreted and copied while reading the +// code and comparing to other `panel.js` versions and might be wrong. They are +// prefixed with "Annotation:" to indicate that they're my comments, not +// comments that orginally existed. + +// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/45.0/js/ui/panel.js +// On: 2023-09-26 +// License: This code is licensed under GPLv2. + +// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/45.0/js/ui/sessionMode.js +// On: 2023-09-26 +// License: This code is licensed under GPLv2. + +// I'm using the word "item" to refer to the thing, which gets added to the top +// (menu)bar / panel, where an item has a role/name and an indicator. + + +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import Clutter from 'gi://Clutter'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import GObject from 'gi://GObject'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import St from 'gi://St'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import * as CtrlAltTab from './ctrlAltTab.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import * as PopupMenu from './popupMenu.js'; +import * as PanelMenu from './panelMenu.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import * as Main from './main.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import {DateMenuButton} from './dateMenu.js'; +import {ATIndicator} from './status/accessibility.js'; +import {InputSourceIndicator} from './status/keyboard.js'; +import {DwellClickIndicator} from './status/dwellClick.js'; +import {ScreenRecordingIndicator, ScreenSharingIndicator} from './status/remoteAccess.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. +// Of note (for PANEL_ITEM_IMPLEMENTATIONS): +// const AppMenuButton = [...] +// const ActivitiesButton = [...] +// const QuickSettings = [...] + +const PANEL_ITEM_IMPLEMENTATIONS = { + 'activities': ActivitiesButton, + 'appMenu': AppMenuButton, + 'quickSettings': QuickSettings, + 'dateMenu': DateMenuButton, + 'a11y': ATIndicator, + 'keyboard': InputSourceIndicator, + 'dwellClick': DwellClickIndicator, + 'screenRecording': ScreenRecordingIndicator, + 'screenSharing': ScreenSharingIndicator, +}; + +// Annotation: Uses ESM export now. +export const Panel = GObject.registerClass( +class Panel extends St.Widget { + // Annotation: Initializes the top (menu)bar / panel. + // Does relevant stuff like: + // - Defining `this._leftBox`, `this._centerBox` and `this._rightBox`. + // - Finally calling `this._updatePanel()`. + // Compared to panel_43.2_2023-01-24.js: Nothing changed (except for + // formatting). + _init() { + super._init({ + name: 'panel', + reactive: true, + }); + + this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); + + this._sessionStyle = null; + + this.statusArea = {}; + + this.menuManager = new PopupMenu.PopupMenuManager(this); + + this._leftBox = new St.BoxLayout({name: 'panelLeft'}); + this.add_child(this._leftBox); + this._centerBox = new St.BoxLayout({name: 'panelCenter'}); + this.add_child(this._centerBox); + this._rightBox = new St.BoxLayout({name: 'panelRight'}); + this.add_child(this._rightBox); + + this.connect('button-press-event', this._onButtonPress.bind(this)); + this.connect('touch-event', this._onTouchEvent.bind(this)); + + Main.overview.connect('showing', () => { + this.add_style_pseudo_class('overview'); + }); + Main.overview.connect('hiding', () => { + this.remove_style_pseudo_class('overview'); + }); + + Main.layoutManager.panelBox.add(this); + Main.ctrlAltTabManager.addGroup(this, + _('Top Bar'), 'focus-top-bar-symbolic', + {sortGroup: CtrlAltTab.SortGroup.TOP}); + + Main.sessionMode.connect('updated', this._updatePanel.bind(this)); + + global.display.connect('workareas-changed', () => this.queue_relayout()); + this._updatePanel(); + } + + // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for + // this Extension. + + // Annotation: Gets called by `this._init()` to populate the top (menu)bar / + // panel initially. + // + // It does the following relevant stuff: + // - Calls `this._hideIndicators()` + // - Calls `this._updateBox()` for `this._leftBox`, `this._centerBox` and + // `this._rightBox` with `panel.left`, `panel.center` and `panel.right` to + // populate the boxes with items defined in `panel.left`, `panel.center` + // and `panel.right`. + // + // `panel.left`, `panel.center` and `panel.right` get set via the line + // `let panel = Main.sessionMode.panel`, which uses the panel of Mains + // (`js/ui/main.js`) instance of SessionMode (`js/ui/sessionMode.js`). + // + // And in `js/ui/sessionMode.js` (45.0, 2023-09-26) you have different + // modes with different panel configuration. For example the "user" mode + // with: + // ``` + // panel: { + // left: ['activities'], + // center: ['dateMenu'], + // right: ['screenRecording', 'screenSharing', 'dwellClick', 'a11y', 'keyboard', 'quickSettings'], + // }, + // ``` + // + // This way this function populates the top (menu)bar / panel with the + // default stuff you see on a fresh Gnome. + // + // Compared to panel_43.2_2023-01-24.js: Nothing changed. + _updatePanel() { + let panel = Main.sessionMode.panel; + this._hideIndicators(); + this._updateBox(panel.left, this._leftBox); + this._updateBox(panel.center, this._centerBox); + this._updateBox(panel.right, this._rightBox); + + if (panel.left.includes('dateMenu')) + Main.messageTray.bannerAlignment = Clutter.ActorAlign.START; + else if (panel.right.includes('dateMenu')) + Main.messageTray.bannerAlignment = Clutter.ActorAlign.END; + // Default to center if there is no dateMenu + else + Main.messageTray.bannerAlignment = Clutter.ActorAlign.CENTER; + + if (this._sessionStyle) + this.remove_style_class_name(this._sessionStyle); + + this._sessionStyle = Main.sessionMode.panelStyle; + if (this._sessionStyle) + this.add_style_class_name(this._sessionStyle); + } + + // Annotation: This function hides all items, which are in the top (menu)bar + // panel and in PANEL_ITEM_IMPLEMENTATIONS. + // + // Compared to panel_43.2_2023-01-24.js: Nothing changed. + _hideIndicators() { + for (let role in PANEL_ITEM_IMPLEMENTATIONS) { + let indicator = this.statusArea[role]; + if (!indicator) + continue; + indicator.container.hide(); + } + } + + // Annotation: This function takes a role (of an item) and returns a + // corresponding indicator, if either of two things are true: + // - The indicator is already in `this.statusArea`. + // Then it just returns the indicator by using `this.statusArea`. + // - The role is in PANEL_ITEM_IMPLEMENTATIONS. + // Then it creates a new indicator, adds it to `this.statusArea` and + // returns it. + // + // Compared to panel_43.2_2023-01-24.js: Nothing changed. + _ensureIndicator(role) { + let indicator = this.statusArea[role]; + if (!indicator) { + let constructor = PANEL_ITEM_IMPLEMENTATIONS[role]; + if (!constructor) { + // This icon is not implemented (this is a bug) + return null; + } + indicator = new constructor(this); + this.statusArea[role] = indicator; + } + return indicator; + } + + // Annotation: This function takes a list of items (or rather their roles) + // and adds the indicators of those items to a box (like `this._leftBox`) + // using `this._ensureIndicator()` to get the indicator corresponding to the + // given role. + // So only items with roles `this._ensureIndicator()` knows, get added. + // + // Compared to panel_43.2_2023-01-24.js: Nothing changed. + _updateBox(elements, box) { + let nChildren = box.get_n_children(); + + for (let i = 0; i < elements.length; i++) { + let role = elements[i]; + let indicator = this._ensureIndicator(role); + if (indicator == null) + continue; + + this._addToPanelBox(role, indicator, i + nChildren, box); + } + } + + // Annotation: This function adds the given item to the specified top + // (menu)bar / panel box and connects to "destroy" and "menu-set" events. + // + // It takes the following arguments: + // - role: The name of the item to add. + // - indicator: The indicator of the item to add. + // - position: Where in the box to add the item. + // - box: The box to add the item to. + // Can be one of the following: + // - `this._leftBox` + // - `this._centerBox` + // - `this._rightBox` + // + // Compared to panel_43.2_2023-01-24.js: Nothing changed. + _addToPanelBox(role, indicator, position, box) { + let container = indicator.container; + container.show(); + + let parent = container.get_parent(); + if (parent) + parent.remove_actor(container); + + + box.insert_child_at_index(container, position); + this.statusArea[role] = indicator; + let destroyId = indicator.connect('destroy', emitter => { + delete this.statusArea[role]; + emitter.disconnect(destroyId); + }); + indicator.connect('menu-set', this._onMenuSet.bind(this)); + this._onMenuSet(indicator); + } + + // Annotation: This function allows you to add an item to the top (menu)bar + // / panel. + // While per default it adds the item to the status area (the right box of + // the top bar), you can specify the box and add the item to any of the + // three boxes of the top bar. + // To add an item to the top bar, you need to give its role and indicator. + // + // This function takes the following arguments: + // - role: A name for the item to add. + // - indicator: The indicator for the item to add (must be an instance of + // PanelMenu.Button). + // - position: Where in the box to add the item. + // - box: The box to add the item to. + // Can be one of the following: + // - "left": referring to `this._leftBox` + // - "center": referring to `this._centerBox` + // - "right": referring to `this._rightBox` + // These boxes are what you see in the top bar as the left, right and + // center sections. + // + // Finally this function just calls `this._addToPanelBox()` for the actual + // work, so it basically just makes sure the input to + // `this._addToPanelBox()` is correct. + // + // Compared to panel_43.2_2023-01-24.js: Nothing changed. + addToStatusArea(role, indicator, position, box) { + if (this.statusArea[role]) + throw new Error(`Extension point conflict: there is already a status indicator for role ${role}`); + + if (!(indicator instanceof PanelMenu.Button)) + throw new TypeError('Status indicator must be an instance of PanelMenu.Button'); + + position ??= 0; + let boxes = { + left: this._leftBox, + center: this._centerBox, + right: this._rightBox, + }; + let boxContainer = boxes[box] || this._rightBox; + this.statusArea[role] = indicator; + this._addToPanelBox(role, indicator, position, boxContainer); + return indicator; + } + + // Compared to panel_43.2_2023-01-24.js: Nothing changed, except for the + // usage of === instead of ==. + _onMenuSet(indicator) { + if (!indicator.menu || indicator.menu._openChangedId) + return; + + this.menuManager.addMenu(indicator.menu); + + indicator.menu._openChangedId = indicator.menu.connect('open-state-changed', + (menu, isOpen) => { + let boxAlignment; + if (this._leftBox.contains(indicator.container)) + boxAlignment = Clutter.ActorAlign.START; + else if (this._centerBox.contains(indicator.container)) + boxAlignment = Clutter.ActorAlign.CENTER; + else if (this._rightBox.contains(indicator.container)) + boxAlignment = Clutter.ActorAlign.END; + + if (boxAlignment === Main.messageTray.bannerAlignment) + Main.messageTray.bannerBlocked = isOpen; + }); + } + + // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for + // this Extension. +}); From a1188d56842aa580bff2a118b7cc68021201f50a Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Mon, 2 Oct 2023 03:56:48 +0200 Subject: [PATCH 15/56] Breaking: Migrate extension to the new ESM system of GNOME 45 Migrate with the help of, among others, the following resources: https://blogs.gnome.org/shell-dev/2023/09/02/extensions-in-gnome-45/ https://gjs.guide/extensions/upgrading/gnome-shell-45.html Only support GNOME Shell version 45, since only 45 is compatible with the new ESM system. Since panel._originalAddToPanelBox is no longer valid, just overwrite using the prototype on disable. Add "sourceType": "module" to eslintrc.yml to get rid of: "Parsing error: 'import' and 'export' may appear only with 'sourceType: module'" See here: https://eslint.org/docs/latest/use/configure/language-options#specifying-parser-options --- .eslintrc.yml | 2 +- src/extension.js | 26 ++++------ src/extensionModules/BoxOrderManager.js | 15 +++--- src/metadata.json | 2 +- src/prefs.js | 47 +++++++++---------- src/prefsModules/PrefsBoxOrderItemRow.js | 21 ++++----- src/prefsModules/PrefsBoxOrderListBox.js | 27 ++++++----- .../PrefsBoxOrderListEmptyPlaceholder.js | 15 +++--- src/prefsModules/PrefsPage.js | 24 +++++----- src/prefsModules/ScrollManager.js | 8 ++-- 10 files changed, 85 insertions(+), 102 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index a0fbb75..f364ffc 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -3,6 +3,7 @@ env: extends: 'eslint:recommended' parserOptions: ecmaVersion: 2022 + sourceType: module rules: indent: - error @@ -49,5 +50,4 @@ rules: - error - always globals: - imports: readonly log: readonly diff --git a/src/extension.js b/src/extension.js index 99cfaec..7caa5b3 100644 --- a/src/extension.js +++ b/src/extension.js @@ -1,22 +1,16 @@ "use strict"; -/* exported init */ -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); +import * as Main from "resource:///org/gnome/shell/ui/main.js"; +import * as Panel from "resource:///org/gnome/shell/ui/panel.js"; +import { Extension } from "resource:///org/gnome/shell/extensions/extension.js"; -const Main = imports.ui.main; -const Panel = imports.ui.panel; - -const BoxOrderManager = Me.imports.extensionModules.BoxOrderManager; - -class Extension { - constructor() { - } +import BoxOrderManager from "./extensionModules/BoxOrderManager.js"; +export default class TopBarOrganizerExtension extends Extension { enable() { - this._settings = ExtensionUtils.getSettings(); + this._settings = this.getSettings(); - this._boxOrderManager = new BoxOrderManager.BoxOrderManager(); + this._boxOrderManager = new BoxOrderManager({}, this._settings); /// Stuff to do on startup(extension enable). // Initially handle new top bar items and order top bar boxes. @@ -46,7 +40,7 @@ class Extension { // Revert the overwrite of `Panel._addToPanelBox`. Panel.Panel.prototype._addToPanelBox = Panel.Panel.prototype._originalAddToPanelBox; // Set `Panel._originalAddToPanelBox` to `undefined`. - Panel._originalAddToPanelBox = undefined; + Panel.Panel.prototype._originalAddToPanelBox = undefined; // Disconnect signals. for (const handlerId of this._settingsHandlerIds) { @@ -177,7 +171,3 @@ class Extension { // top bar items at the beginning of this method, this isn't a concern. } } - -function init() { - return new Extension(); -} diff --git a/src/extensionModules/BoxOrderManager.js b/src/extensionModules/BoxOrderManager.js index a206739..adf8d1b 100644 --- a/src/extensionModules/BoxOrderManager.js +++ b/src/extensionModules/BoxOrderManager.js @@ -1,11 +1,8 @@ "use strict"; -/* exported BoxOrderManager */ -const GObject = imports.gi.GObject; +import GObject from "gi://GObject"; -const ExtensionUtils = imports.misc.extensionUtils; - -const Main = imports.ui.main; +import * as Main from "resource:///org/gnome/shell/ui/main.js"; /** * This class provides methods get, set and interact with box orders, while @@ -13,7 +10,7 @@ const Main = imports.ui.main; * what is really useable by the other extension code. * It's basically a heavy wrapper around the box orders stored in the settings. */ -var BoxOrderManager = GObject.registerClass({ +const BoxOrderManager = GObject.registerClass({ Signals: { "appIndicatorReady": {} } @@ -22,13 +19,13 @@ var BoxOrderManager = GObject.registerClass({ #appIndicatorItemApplicationRoleMap; #settings; - constructor(params = {}) { + constructor(params = {}, settings) { super(params); this.#appIndicatorReadyHandlerIdMap = new Map(); this.#appIndicatorItemApplicationRoleMap = new Map(); - this.#settings = ExtensionUtils.getSettings(); + this.#settings = settings; } /** @@ -271,3 +268,5 @@ var BoxOrderManager = GObject.registerClass({ saveBoxOrderToSettings(boxOrders.right, "right"); } }); + +export default BoxOrderManager; diff --git a/src/metadata.json b/src/metadata.json index beb577c..7122a84 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -3,7 +3,7 @@ "name": "Top Bar Organizer", "description": "Organize the items of the top (menu)bar.", "version": 9, - "shell-version": [ "42", "43", "44" ], + "shell-version": [ "45" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", "url": "https://gitlab.gnome.org/julianschacher/top-bar-organizer" } diff --git a/src/prefs.js b/src/prefs.js index f11f767..967277d 100644 --- a/src/prefs.js +++ b/src/prefs.js @@ -1,35 +1,32 @@ "use strict"; -/* exported buildPrefsWidget, init */ -const Gtk = imports.gi.Gtk; -const Gdk = imports.gi.Gdk; +import Gtk from "gi://Gtk"; +import Gdk from "gi://Gdk"; -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); +import { ExtensionPreferences } from "resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js"; -const PrefsPage = Me.imports.prefsModules.PrefsPage; +import PrefsPage from "./prefsModules/PrefsPage.js"; -function buildPrefsWidget() { - const provider = new Gtk.CssProvider(); - provider.load_from_path(Me.dir.get_path() + "/css/prefs.css"); - const defaultGdkDisplay = Gdk.Display.get_default(); - Gtk.StyleContext.add_provider_for_display( - defaultGdkDisplay, - provider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - ); - - const prefsPage = new PrefsPage.PrefsPage(); - - prefsPage.connect("destroy", () => { - Gtk.StyleContext.remove_provider_for_display( +export default class TopBarOrganizerPreferences extends ExtensionPreferences { + getPreferencesWidget() { + const provider = new Gtk.CssProvider(); + provider.load_from_path(this.metadata.dir.get_path() + "/css/prefs.css"); + const defaultGdkDisplay = Gdk.Display.get_default(); + Gtk.StyleContext.add_provider_for_display( defaultGdkDisplay, - provider + provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION ); - }); - return prefsPage; -} + const prefsPage = new PrefsPage(); -function init() { + prefsPage.connect("destroy", () => { + Gtk.StyleContext.remove_provider_for_display( + defaultGdkDisplay, + provider + ); + }); + + return prefsPage; + } } diff --git a/src/prefsModules/PrefsBoxOrderItemRow.js b/src/prefsModules/PrefsBoxOrderItemRow.js index d98286f..976e4ba 100644 --- a/src/prefsModules/PrefsBoxOrderItemRow.js +++ b/src/prefsModules/PrefsBoxOrderItemRow.js @@ -1,18 +1,15 @@ "use strict"; -/* exported PrefsBoxOrderItemRow */ -const Gtk = imports.gi.Gtk; -const Gdk = imports.gi.Gdk; -const Gio = imports.gi.Gio; -const GObject = imports.gi.GObject; -const Adw = imports.gi.Adw; +import Gtk from "gi://Gtk"; +import Gdk from "gi://Gdk"; +import Gio from "gi://Gio"; +import GObject from "gi://GObject"; +import Adw from "gi://Adw"; +import GLib from "gi://GLib"; -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -var PrefsBoxOrderItemRow = GObject.registerClass({ +const PrefsBoxOrderItemRow = GObject.registerClass({ GTypeName: "PrefsBoxOrderItemRow", - Template: Me.dir.get_child("ui").get_child("prefs-box-order-item-row.ui").get_uri(), + Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-item-row.ui", GLib.UriFlags.NONE), InternalChildren: [ "item-name-display-label" ] @@ -144,3 +141,5 @@ var PrefsBoxOrderItemRow = GObject.registerClass({ } } }); + +export default PrefsBoxOrderItemRow; diff --git a/src/prefsModules/PrefsBoxOrderListBox.js b/src/prefsModules/PrefsBoxOrderListBox.js index 11e2202..68cf7d4 100644 --- a/src/prefsModules/PrefsBoxOrderListBox.js +++ b/src/prefsModules/PrefsBoxOrderListBox.js @@ -1,18 +1,17 @@ "use strict"; -/* exported PrefsBoxOrderListBox */ -const Gtk = imports.gi.Gtk; -const GObject = imports.gi.GObject; +import Gtk from "gi://Gtk"; +import GObject from "gi://GObject"; +import GLib from "gi://GLib"; -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); +import { ExtensionPreferences } from "resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js"; -const PrefsBoxOrderItemRow = Me.imports.prefsModules.PrefsBoxOrderItemRow; -const PrefsBoxOrderListEmptyPlaceholder = Me.imports.prefsModules.PrefsBoxOrderListEmptyPlaceholder; +import PrefsBoxOrderItemRow from "./PrefsBoxOrderItemRow.js"; +import PrefsBoxOrderListEmptyPlaceholder from "./PrefsBoxOrderListEmptyPlaceholder.js"; -var PrefsBoxOrderListBox = GObject.registerClass({ +const PrefsBoxOrderListBox = GObject.registerClass({ GTypeName: "PrefsBoxOrderListBox", - Template: Me.dir.get_child("ui").get_child("prefs-box-order-list-box.ui").get_uri(), + Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-list-box.ui", GLib.UriFlags.NONE), Properties: { BoxOrder: GObject.ParamSpec.string( "box-order", @@ -32,11 +31,11 @@ var PrefsBoxOrderListBox = GObject.registerClass({ super(params); // Load the settings. - this.#settings = ExtensionUtils.getSettings(); + this.#settings = ExtensionPreferences.lookupByURL(import.meta.url).getSettings(); // Add a placeholder widget for the case, where no GtkListBoxRows are // present. - this.set_placeholder(new PrefsBoxOrderListEmptyPlaceholder.PrefsBoxOrderListEmptyPlaceholder()); + this.set_placeholder(new PrefsBoxOrderListEmptyPlaceholder()); } get boxOrder() { @@ -48,13 +47,13 @@ var PrefsBoxOrderListBox = GObject.registerClass({ // Load the settings here as well, since a `CONSTRUCT_ONLY` property // apparently can't access `this.#settings`. - const settings = ExtensionUtils.getSettings(); + const settings = ExtensionPreferences.lookupByURL(import.meta.url).getSettings(); // Get the actual box order for the given box order name from settings. const boxOrder = settings.get_strv(this._boxOrder); // Populate this GtkListBox with GtkListBoxRows for the items of the // given configured box order. for (const item of boxOrder) { - const listBoxRow = new PrefsBoxOrderItemRow.PrefsBoxOrderItemRow({}, item); + const listBoxRow = new PrefsBoxOrderItemRow({}, item); this.append(listBoxRow); } @@ -79,3 +78,5 @@ var PrefsBoxOrderListBox = GObject.registerClass({ this.#settings.set_strv(this.boxOrder, currentBoxOrder); } }); + +export default PrefsBoxOrderListBox; diff --git a/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js b/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js index cfeed56..2f32e2e 100644 --- a/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js +++ b/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js @@ -1,15 +1,12 @@ "use strict"; -/* exported PrefsBoxOrderListEmptyPlaceholder */ -const Gtk = imports.gi.Gtk; -const GObject = imports.gi.GObject; +import Gtk from "gi://Gtk"; +import GObject from "gi://GObject"; +import GLib from "gi://GLib"; -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -var PrefsBoxOrderListEmptyPlaceholder = GObject.registerClass({ +const PrefsBoxOrderListEmptyPlaceholder = GObject.registerClass({ GTypeName: "PrefsBoxOrderListEmptyPlaceholder", - Template: Me.dir.get_child("ui").get_child("prefs-box-order-list-empty-placeholder.ui").get_uri() + Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-list-empty-placeholder.ui", GLib.UriFlags.NONE) }, class PrefsBoxOrderListEmptyPlaceholder extends Gtk.Box { // Handle a new drop on `this` properly. // `value` is the thing getting dropped. @@ -29,3 +26,5 @@ var PrefsBoxOrderListEmptyPlaceholder = GObject.registerClass({ valueListBox.saveBoxOrderToSettings(); } }); + +export default PrefsBoxOrderListEmptyPlaceholder; diff --git a/src/prefsModules/PrefsPage.js b/src/prefsModules/PrefsPage.js index f9059b0..cd9e476 100644 --- a/src/prefsModules/PrefsPage.js +++ b/src/prefsModules/PrefsPage.js @@ -1,22 +1,18 @@ "use strict"; -/* exported PrefsPage */ -const Gtk = imports.gi.Gtk; -const GObject = imports.gi.GObject; -const Adw = imports.gi.Adw; +import Gtk from "gi://Gtk"; +import GObject from "gi://GObject"; +import Adw from "gi://Adw"; +import GLib from "gi://GLib"; -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -const ScrollManager = Me.imports.prefsModules.ScrollManager; +import ScrollManager from "./ScrollManager.js"; // Imports to make UI file work. -/* exported PrefsBoxOrderListBox */ -const PrefsBoxOrderListBox = Me.imports.prefsModules.PrefsBoxOrderListBox; +import PrefsBoxOrderListBox from "./PrefsBoxOrderListBox.js"; -var PrefsPage = GObject.registerClass({ +const PrefsPage = GObject.registerClass({ GTypeName: "PrefsPage", - Template: Me.dir.get_child("ui").get_child("prefs-page.ui").get_uri() + Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-page.ui", GLib.UriFlags.NONE) }, class PrefsPage extends Adw.PreferencesPage { constructor(params = {}) { super(params); @@ -34,7 +30,7 @@ var PrefsPage = GObject.registerClass({ // Pass `this.get_first_child()` to the ScrollManager, since this // `PrefsPage` extends an `Adw.PreferencesPage` and the first child of // an `Adw.PreferencesPage` is the built-in `Gtk.ScrolledWindow`. - const scrollManager = new ScrollManager.ScrollManager(this.get_first_child()); + const scrollManager = new ScrollManager(this.get_first_child()); /// Setup GtkDropControllerMotion event controller and make use of its /// events. @@ -86,3 +82,5 @@ var PrefsPage = GObject.registerClass({ this.add_controller(controller); } }); + +export default PrefsPage; diff --git a/src/prefsModules/ScrollManager.js b/src/prefsModules/ScrollManager.js index cd3bdce..07f221e 100644 --- a/src/prefsModules/ScrollManager.js +++ b/src/prefsModules/ScrollManager.js @@ -1,8 +1,8 @@ "use strict"; -/* exported ScrollManager */ -const GLib = imports.gi.GLib; -var ScrollManager = class ScrollManager { +import GLib from "gi://GLib"; + +export default class ScrollManager { #gtkScrolledWindow; #scrollUp; #scrollDown; @@ -86,4 +86,4 @@ var ScrollManager = class ScrollManager { this.stopScrollUp(); this.stopScrollDown(); } -}; +} From 9b7ab0614c275bf9718dbd4973225a595adf2fe3 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Wed, 4 Oct 2023 03:28:59 +0200 Subject: [PATCH 16/56] Feature: Add move up and down buttons to make the prefs keyboard access. Don't use CONSTRUCT_ONLY anymore to be able to use private properties (or any properties at all it seems). --- data/ui/prefs-box-order-item-row.ui | 10 ++ data/ui/prefs-page.ui | 9 +- src/prefsModules/PrefsBoxOrderItemRow.js | 52 +++++++---- src/prefsModules/PrefsBoxOrderListBox.js | 80 ++++++++++++++-- .../PrefsBoxOrderListEmptyPlaceholder.js | 9 +- src/prefsModules/PrefsPage.js | 93 ++++++++++++++++++- 6 files changed, 219 insertions(+), 34 deletions(-) diff --git a/data/ui/prefs-box-order-item-row.ui b/data/ui/prefs-box-order-item-row.ui index 86bf461..d8e6e73 100644 --- a/data/ui/prefs-box-order-item-row.ui +++ b/data/ui/prefs-box-order-item-row.ui @@ -42,6 +42,16 @@

+
+ + Move Up + row.move-up + + + Move Down + row.move-down + +
Forget diff --git a/data/ui/prefs-page.ui b/data/ui/prefs-page.ui index 288fa75..7eca8d0 100644 --- a/data/ui/prefs-page.ui +++ b/data/ui/prefs-page.ui @@ -13,8 +13,9 @@ - + left-box-order + @@ -26,8 +27,9 @@ - + center-box-order + @@ -39,8 +41,9 @@ - + right-box-order + diff --git a/src/prefsModules/PrefsBoxOrderItemRow.js b/src/prefsModules/PrefsBoxOrderItemRow.js index 976e4ba..0b4818e 100644 --- a/src/prefsModules/PrefsBoxOrderItemRow.js +++ b/src/prefsModules/PrefsBoxOrderItemRow.js @@ -7,13 +7,24 @@ import GObject from "gi://GObject"; import Adw from "gi://Adw"; import GLib from "gi://GLib"; -const PrefsBoxOrderItemRow = GObject.registerClass({ - GTypeName: "PrefsBoxOrderItemRow", - Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-item-row.ui", GLib.UriFlags.NONE), - InternalChildren: [ - "item-name-display-label" - ] -}, class PrefsBoxOrderItemRow extends Adw.ActionRow { +export default class PrefsBoxOrderItemRow extends Adw.ActionRow { + static { + GObject.registerClass({ + GTypeName: "PrefsBoxOrderItemRow", + Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-item-row.ui", GLib.UriFlags.NONE), + InternalChildren: [ + "item-name-display-label" + ], + Signals: { + "move": { + param_types: [GObject.TYPE_STRING] + } + } + }, this); + this.install_action("row.move-up", null, (self, _actionName, _param) => self.emit("move", "up")); + this.install_action("row.move-down", null, (self, _actionName, _param) => self.emit("move", "down")); + } + #drag_starting_point_x; #drag_starting_point_y; @@ -52,8 +63,9 @@ const PrefsBoxOrderItemRow = GObject.registerClass({ }); forgetAction.connect("activate", (_action, _params) => { const parentListBox = this.get_parent(); - parentListBox.remove(this); + parentListBox.removeRow(this); parentListBox.saveBoxOrderToSettings(); + parentListBox.determineRowMoveActionEnable(); }); actionGroup.add_action(forgetAction); @@ -101,7 +113,7 @@ const PrefsBoxOrderItemRow = GObject.registerClass({ const valuePosition = value.get_index(); // Remove the drop value from its list box. - valueListBox.remove(value); + valueListBox.removeRow(value); // Since an element got potentially removed from the list of `this`, // get the position of `this` again. @@ -115,31 +127,31 @@ const PrefsBoxOrderItemRow = GObject.registerClass({ || (ownListBox.boxOrder === "center-box-order" && valueListBox.boxOrder === "left-box-order")) { // If the list box of the drop value comes before the list // box of `this`, add the drop value after `this`. - ownListBox.insert(value, updatedOwnPosition + 1); + ownListBox.insertRow(value, updatedOwnPosition + 1); } else { // Otherwise, add the drop value where `this` currently is. - ownListBox.insert(value, updatedOwnPosition); + ownListBox.insertRow(value, updatedOwnPosition); } } else { if (valuePosition < ownPosition) { // If the drop value was before `this`, add the drop value // after `this`. - ownListBox.insert(value, updatedOwnPosition + 1); + ownListBox.insertRow(value, updatedOwnPosition + 1); } else { // Otherwise, add the drop value where `this` currently is. - ownListBox.insert(value, updatedOwnPosition); + ownListBox.insertRow(value, updatedOwnPosition); } } - /// Finally save the box order(/s) to settings. + /// Finally save the box order(/s) to settings and make sure move + /// actions are correctly enabled/disabled. ownListBox.saveBoxOrderToSettings(); - // If the list boxes of `this` and the drop value were different, - // save an updated box order for the list were the drop value was in - // as well. + ownListBox.determineRowMoveActionEnable(); + // If the list boxes of `this` and the drop value were different, handle + // the former list box of the drop value as well. if (ownListBox !== valueListBox) { valueListBox.saveBoxOrderToSettings(); + valueListBox.determineRowMoveActionEnable(); } } -}); - -export default PrefsBoxOrderItemRow; +} diff --git a/src/prefsModules/PrefsBoxOrderListBox.js b/src/prefsModules/PrefsBoxOrderListBox.js index 68cf7d4..5c08922 100644 --- a/src/prefsModules/PrefsBoxOrderListBox.js +++ b/src/prefsModules/PrefsBoxOrderListBox.js @@ -17,12 +17,18 @@ const PrefsBoxOrderListBox = GObject.registerClass({ "box-order", "Box Order", "The box order this PrefsBoxOrderListBox is associated with.", - GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY, + GObject.ParamFlags.READWRITE, "" ) + }, + Signals: { + "row-move": { + param_types: [PrefsBoxOrderItemRow, GObject.TYPE_STRING] + } } }, class PrefsBoxOrderListBox extends Gtk.ListBox { #settings; + #rowSignalHandlerIds = new Map(); /** * @param {Object} params @@ -45,21 +51,49 @@ const PrefsBoxOrderListBox = GObject.registerClass({ set boxOrder(value) { this._boxOrder = value; - // Load the settings here as well, since a `CONSTRUCT_ONLY` property - // apparently can't access `this.#settings`. - const settings = ExtensionPreferences.lookupByURL(import.meta.url).getSettings(); // Get the actual box order for the given box order name from settings. - const boxOrder = settings.get_strv(this._boxOrder); + const boxOrder = this.#settings.get_strv(this._boxOrder); // Populate this GtkListBox with GtkListBoxRows for the items of the // given configured box order. for (const item of boxOrder) { - const listBoxRow = new PrefsBoxOrderItemRow({}, item); - this.append(listBoxRow); + const row = new PrefsBoxOrderItemRow({}, item); + this.insertRow(row, -1); } + this.determineRowMoveActionEnable(); this.notify("box-order"); } + /** + * Inserts the given PrefsBoxOrderItemRow to this list box at the given + * position. + * Also handles stuff like connecting signals. + */ + insertRow(row, position) { + this.insert(row, position); + + const signalHandlerIds = []; + signalHandlerIds.push(row.connect("move", (row, direction) => { + this.emit("row-move", row, direction); + })); + + this.#rowSignalHandlerIds.set(row, signalHandlerIds); + } + + /** + * Removes the given PrefsBoxOrderItemRow from this list box. + * Also handles stuff like disconnecting signals. + */ + removeRow(row) { + const signalHandlerIds = this.#rowSignalHandlerIds.get(row); + + for (const id of signalHandlerIds) { + row.disconnect(id); + } + + this.remove(row); + } + /** * Saves the box order represented by `this` (and its * `PrefsBoxOrderItemRows`) to settings. @@ -77,6 +111,38 @@ const PrefsBoxOrderListBox = GObject.registerClass({ } this.#settings.set_strv(this.boxOrder, currentBoxOrder); } + + /** + * Determines whether or not each move action of each PrefsBoxOrderItemRow + * should be enabled or disabled. + */ + determineRowMoveActionEnable() { + for (let potentialPrefsBoxOrderItemRow of this) { + // Only process PrefsBoxOrderItemRows. + if (potentialPrefsBoxOrderItemRow.constructor.$gtype.name !== "PrefsBoxOrderItemRow") { + continue; + } + + const row = potentialPrefsBoxOrderItemRow; + + // If the current row is the topmost row in the topmost list box, + // then disable the move-up action. + if (row.get_index() === 0 && this.boxOrder === "left-box-order") { + row.action_set_enabled("row.move-up", false); + } else { // Else enable it. + row.action_set_enabled("row.move-up", true); + } + + // If the current row is the bottommost row in the bottommost list + // box, then disable the move-down action. + const rowNextSibling = row.get_next_sibling(); + if ((rowNextSibling instanceof PrefsBoxOrderListEmptyPlaceholder || rowNextSibling === null) && this.boxOrder === "right-box-order") { + row.action_set_enabled("row.move-down", false); + } else { // Else enable it. + row.action_set_enabled("row.move-down", true); + } + } + } }); export default PrefsBoxOrderListBox; diff --git a/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js b/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js index 2f32e2e..b04d256 100644 --- a/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js +++ b/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js @@ -16,14 +16,17 @@ const PrefsBoxOrderListEmptyPlaceholder = GObject.registerClass({ const valueListBox = value.get_parent(); // Remove the drop value from its list box. - valueListBox.remove(value); + valueListBox.removeRow(value); // Insert the drop value into the list box of `this`. - ownListBox.insert(value, 0); + ownListBox.insertRow(value, 0); - /// Finally save the box orders to settings. + /// Finally save the box orders to settings and make sure move actions + /// are correctly enabled/disabled. ownListBox.saveBoxOrderToSettings(); + ownListBox.determineRowMoveActionEnable(); valueListBox.saveBoxOrderToSettings(); + valueListBox.determineRowMoveActionEnable(); } }); diff --git a/src/prefsModules/PrefsPage.js b/src/prefsModules/PrefsPage.js index cd9e476..47f34a6 100644 --- a/src/prefsModules/PrefsPage.js +++ b/src/prefsModules/PrefsPage.js @@ -6,13 +6,19 @@ import Adw from "gi://Adw"; import GLib from "gi://GLib"; import ScrollManager from "./ScrollManager.js"; +import PrefsBoxOrderListEmptyPlaceholder from "./PrefsBoxOrderListEmptyPlaceholder.js"; // Imports to make UI file work. import PrefsBoxOrderListBox from "./PrefsBoxOrderListBox.js"; const PrefsPage = GObject.registerClass({ GTypeName: "PrefsPage", - Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-page.ui", GLib.UriFlags.NONE) + Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-page.ui", GLib.UriFlags.NONE), + InternalChildren: [ + "left-box-order-list-box", + "center-box-order-list-box", + "right-box-order-list-box" + ] }, class PrefsPage extends Adw.PreferencesPage { constructor(params = {}) { super(params); @@ -81,6 +87,91 @@ const PrefsPage = GObject.registerClass({ this.add_controller(controller); } + + onRowMove(listBox, row, direction) { + const rowPosition = row.get_index(); + + if (direction === "up") { // If the direction of the move is up. + // Handle the case, where the row is the topmost row in the list box. + if (rowPosition === 0) { + switch (listBox.boxOrder) { + // If the row is also in the topmost list box, then do + // nothing and return. + case "left-box-order": + log("The row is already the topmost row in the topmost box order."); + return; + // If the row is in the center list box, then move it up to + // the left one. + case "center-box-order": + listBox.removeRow(row); + this._left_box_order_list_box.insertRow(row, -1); + // First save the box order of the destination, then do + // "a save for clean up". + this._left_box_order_list_box.saveBoxOrderToSettings(); + this._left_box_order_list_box.determineRowMoveActionEnable(); + listBox.saveBoxOrderToSettings(); + listBox.determineRowMoveActionEnable(); + return; + // If the row is in the right list box, then move it up to + // the center one. + case "right-box-order": + listBox.removeRow(row); + this._center_box_order_list_box.insertRow(row, -1); + this._center_box_order_list_box.saveBoxOrderToSettings(); + this._center_box_order_list_box.determineRowMoveActionEnable(); + listBox.saveBoxOrderToSettings(); + listBox.determineRowMoveActionEnable(); + return; + } + } + + // Else just move the row up in the box. + listBox.removeRow(row); + listBox.insertRow(row, rowPosition - 1); + listBox.saveBoxOrderToSettings(); + listBox.determineRowMoveActionEnable(); + return; + } else { // Else the direction of the move must be down. + // Handle the case, where the row is the bottommost row in the list box. + const rowNextSibling = row.get_next_sibling(); + if (rowNextSibling instanceof PrefsBoxOrderListEmptyPlaceholder || rowNextSibling === null) { + switch (listBox.boxOrder) { + // If the row is also in the bottommost list box, then do + // nothing and return. + case "right-box-order": + log("The row is already the bottommost row in the bottommost box order."); + return; + // If the row is in the center list box, then move it down + // to the right one. + case "center-box-order": + listBox.removeRow(row); + this._right_box_order_list_box.insertRow(row, 0); + this._right_box_order_list_box.saveBoxOrderToSettings(); + this._right_box_order_list_box.determineRowMoveActionEnable(); + listBox.saveBoxOrderToSettings(); + listBox.determineRowMoveActionEnable(); + return; + // If the row is in the left list box, then move it down to + // the center one. + case "left-box-order": + listBox.removeRow(row); + this._center_box_order_list_box.insertRow(row, 0); + this._center_box_order_list_box.saveBoxOrderToSettings(); + this._center_box_order_list_box.determineRowMoveActionEnable(); + listBox.saveBoxOrderToSettings(); + listBox.determineRowMoveActionEnable(); + return; + } + } + + // Else just move the row down in the box. + listBox.removeRow(row); + listBox.insertRow(row, rowPosition + 1); + listBox.saveBoxOrderToSettings(); + listBox.determineRowMoveActionEnable(); + return; + } + } }); export default PrefsPage; From a77c6d2f2bb69213d935700e8008417b16fa5915 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Wed, 4 Oct 2023 03:37:36 +0200 Subject: [PATCH 17/56] Refactor: Install forget action using install_action as well --- data/ui/prefs-box-order-item-row.ui | 2 +- src/prefsModules/PrefsBoxOrderItemRow.js | 27 ++++++------------------ 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/data/ui/prefs-box-order-item-row.ui b/data/ui/prefs-box-order-item-row.ui index d8e6e73..239ac55 100644 --- a/data/ui/prefs-box-order-item-row.ui +++ b/data/ui/prefs-box-order-item-row.ui @@ -55,7 +55,7 @@
Forget - options.forget + row.forget
diff --git a/src/prefsModules/PrefsBoxOrderItemRow.js b/src/prefsModules/PrefsBoxOrderItemRow.js index 0b4818e..9f350c1 100644 --- a/src/prefsModules/PrefsBoxOrderItemRow.js +++ b/src/prefsModules/PrefsBoxOrderItemRow.js @@ -21,6 +21,12 @@ export default class PrefsBoxOrderItemRow extends Adw.ActionRow { } } }, this); + this.install_action("row.forget", null, (self, _actionName, _param) => { + const parentListBox = self.get_parent(); + parentListBox.removeRow(self); + parentListBox.saveBoxOrderToSettings(); + parentListBox.determineRowMoveActionEnable(); + }); this.install_action("row.move-up", null, (self, _actionName, _param) => self.emit("move", "up")); this.install_action("row.move-down", null, (self, _actionName, _param) => self.emit("move", "down")); } @@ -32,7 +38,6 @@ export default class PrefsBoxOrderItemRow extends Adw.ActionRow { super(params); this.#associateItem(item); - this.#setupActions(); } /** @@ -52,26 +57,6 @@ export default class PrefsBoxOrderItemRow extends Adw.ActionRow { } } - /** - * Setup actions. - */ - #setupActions() { - const actionGroup = new Gio.SimpleActionGroup(); - - const forgetAction = new Gio.SimpleAction({ - name: "forget" - }); - forgetAction.connect("activate", (_action, _params) => { - const parentListBox = this.get_parent(); - parentListBox.removeRow(this); - parentListBox.saveBoxOrderToSettings(); - parentListBox.determineRowMoveActionEnable(); - }); - actionGroup.add_action(forgetAction); - - this.insert_action_group("options", actionGroup); - } - onDragPrepare(_source, x, y) { const value = new GObject.Value(); value.init(PrefsBoxOrderItemRow); From 5ea8f4aabe07a86a1827d21ca6d410c0eb6f290c Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Wed, 4 Oct 2023 03:56:33 +0200 Subject: [PATCH 18/56] Refactor: Move GObject.registerClass calls into static init. blocks Do that since it standardizes the code and also is just cleaner. --- src/extensionModules/BoxOrderManager.js | 16 +++---- src/prefsModules/PrefsBoxOrderListBox.js | 42 ++++++++++--------- .../PrefsBoxOrderListEmptyPlaceholder.js | 16 +++---- src/prefsModules/PrefsPage.js | 26 ++++++------ 4 files changed, 54 insertions(+), 46 deletions(-) diff --git a/src/extensionModules/BoxOrderManager.js b/src/extensionModules/BoxOrderManager.js index adf8d1b..0525d08 100644 --- a/src/extensionModules/BoxOrderManager.js +++ b/src/extensionModules/BoxOrderManager.js @@ -10,11 +10,15 @@ import * as Main from "resource:///org/gnome/shell/ui/main.js"; * what is really useable by the other extension code. * It's basically a heavy wrapper around the box orders stored in the settings. */ -const BoxOrderManager = GObject.registerClass({ - Signals: { - "appIndicatorReady": {} +export default class BoxOrderManager extends GObject.Object { + static { + GObject.registerClass({ + Signals: { + "appIndicatorReady": {} + } + }, this); } -}, class BoxOrderManager extends GObject.Object { + #appIndicatorReadyHandlerIdMap; #appIndicatorItemApplicationRoleMap; #settings; @@ -267,6 +271,4 @@ const BoxOrderManager = GObject.registerClass({ saveBoxOrderToSettings(boxOrders.center, "center"); saveBoxOrderToSettings(boxOrders.right, "right"); } -}); - -export default BoxOrderManager; +} diff --git a/src/prefsModules/PrefsBoxOrderListBox.js b/src/prefsModules/PrefsBoxOrderListBox.js index 5c08922..444745e 100644 --- a/src/prefsModules/PrefsBoxOrderListBox.js +++ b/src/prefsModules/PrefsBoxOrderListBox.js @@ -9,24 +9,28 @@ import { ExtensionPreferences } from "resource:///org/gnome/Shell/Extensions/js/ import PrefsBoxOrderItemRow from "./PrefsBoxOrderItemRow.js"; import PrefsBoxOrderListEmptyPlaceholder from "./PrefsBoxOrderListEmptyPlaceholder.js"; -const PrefsBoxOrderListBox = GObject.registerClass({ - GTypeName: "PrefsBoxOrderListBox", - Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-list-box.ui", GLib.UriFlags.NONE), - Properties: { - BoxOrder: GObject.ParamSpec.string( - "box-order", - "Box Order", - "The box order this PrefsBoxOrderListBox is associated with.", - GObject.ParamFlags.READWRITE, - "" - ) - }, - Signals: { - "row-move": { - param_types: [PrefsBoxOrderItemRow, GObject.TYPE_STRING] - } +export default class PrefsBoxOrderListBox extends Gtk.ListBox { + static { + GObject.registerClass({ + GTypeName: "PrefsBoxOrderListBox", + Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-list-box.ui", GLib.UriFlags.NONE), + Properties: { + BoxOrder: GObject.ParamSpec.string( + "box-order", + "Box Order", + "The box order this PrefsBoxOrderListBox is associated with.", + GObject.ParamFlags.READWRITE, + "" + ) + }, + Signals: { + "row-move": { + param_types: [PrefsBoxOrderItemRow, GObject.TYPE_STRING] + } + } + }, this); } -}, class PrefsBoxOrderListBox extends Gtk.ListBox { + #settings; #rowSignalHandlerIds = new Map(); @@ -143,6 +147,4 @@ const PrefsBoxOrderListBox = GObject.registerClass({ } } } -}); - -export default PrefsBoxOrderListBox; +} diff --git a/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js b/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js index b04d256..8dd772b 100644 --- a/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js +++ b/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js @@ -4,10 +4,14 @@ import Gtk from "gi://Gtk"; import GObject from "gi://GObject"; import GLib from "gi://GLib"; -const PrefsBoxOrderListEmptyPlaceholder = GObject.registerClass({ - GTypeName: "PrefsBoxOrderListEmptyPlaceholder", - Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-list-empty-placeholder.ui", GLib.UriFlags.NONE) -}, class PrefsBoxOrderListEmptyPlaceholder extends Gtk.Box { +export default class PrefsBoxOrderListEmptyPlaceholder extends Gtk.Box { + static { + GObject.registerClass({ + GTypeName: "PrefsBoxOrderListEmptyPlaceholder", + Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-list-empty-placeholder.ui", GLib.UriFlags.NONE) + }, this); + } + // Handle a new drop on `this` properly. // `value` is the thing getting dropped. onDrop(_target, value, _x, _y) { @@ -28,6 +32,4 @@ const PrefsBoxOrderListEmptyPlaceholder = GObject.registerClass({ valueListBox.saveBoxOrderToSettings(); valueListBox.determineRowMoveActionEnable(); } -}); - -export default PrefsBoxOrderListEmptyPlaceholder; +} diff --git a/src/prefsModules/PrefsPage.js b/src/prefsModules/PrefsPage.js index 47f34a6..e871197 100644 --- a/src/prefsModules/PrefsPage.js +++ b/src/prefsModules/PrefsPage.js @@ -11,15 +11,19 @@ import PrefsBoxOrderListEmptyPlaceholder from "./PrefsBoxOrderListEmptyPlacehold // Imports to make UI file work. import PrefsBoxOrderListBox from "./PrefsBoxOrderListBox.js"; -const PrefsPage = GObject.registerClass({ - GTypeName: "PrefsPage", - Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-page.ui", GLib.UriFlags.NONE), - InternalChildren: [ - "left-box-order-list-box", - "center-box-order-list-box", - "right-box-order-list-box" - ] -}, class PrefsPage extends Adw.PreferencesPage { +export default class PrefsPage extends Adw.PreferencesPage { + static { + GObject.registerClass({ + GTypeName: "PrefsPage", + Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-page.ui", GLib.UriFlags.NONE), + InternalChildren: [ + "left-box-order-list-box", + "center-box-order-list-box", + "right-box-order-list-box" + ] + }, this); + } + constructor(params = {}) { super(params); @@ -172,6 +176,4 @@ const PrefsPage = GObject.registerClass({ return; } } -}); - -export default PrefsPage; +} From 88e510d54e0c63685bb533a3a4bd511ea071b268 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Thu, 5 Oct 2023 14:18:11 +0200 Subject: [PATCH 19/56] Other: Upgrade ESLint to latest version and run `npm update` --- package-lock.json | 1039 ++++++--------------------------------------- package.json | 2 +- 2 files changed, 124 insertions(+), 917 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5fc35e4..87fbe20 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "top-bar-organizer", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -9,18 +9,51 @@ "version": "1.0.0", "license": "GPL-3.0-or-later", "devDependencies": { - "eslint": "^8.32.0" + "eslint": "^8.50.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz", + "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -35,10 +68,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/js": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", + "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -104,9 +146,9 @@ } }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -297,49 +339,47 @@ } }, "node_modules/eslint": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.32.0.tgz", - "integrity": "sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==", + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", + "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.4.1", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.50.0", + "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -353,9 +393,9 @@ } }, "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -363,53 +403,32 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -419,9 +438,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -516,22 +535,23 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", + "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", "dev": true, "dependencies": { - "flatted": "^3.1.0", + "flatted": "^3.2.7", + "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=12.0.0" } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, "node_modules/fs.realpath": { @@ -573,9 +593,9 @@ } }, "node_modules/globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.22.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.22.0.tgz", + "integrity": "sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -587,10 +607,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "node_modules/has-flag": { @@ -688,16 +708,6 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, - "node_modules/js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -710,6 +720,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -722,6 +738,15 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -790,17 +815,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -913,18 +938,6 @@ } ] }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -1093,15 +1106,6 @@ "node": ">= 8" } }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -1120,802 +1124,5 @@ "url": "https://github.com/sponsors/sindresorhus" } } - }, - "dependencies": { - "@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "8.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.32.0.tgz", - "integrity": "sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.4.1", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - } - }, - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - } - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } } } diff --git a/package.json b/package.json index 3b57509..cf86174 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,6 @@ "author": "Julian Schacher", "license": "GPL-3.0-or-later", "devDependencies": { - "eslint": "^8.32.0" + "eslint": "^8.50.0" } } From d903274d735f94f5374fb5ee5840e20f6bb9bf33 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Thu, 5 Oct 2023 14:50:36 +0200 Subject: [PATCH 20/56] Other: Require trailing commas for multiline for most Require trailing commas for multiline for arrays, objects, imports and exports and disallow trailing commas for functions. Do this by updating the ESLint config and fixing new complaints. The reason for this change are the resulting future cleaner version diffs. Also see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Trailing_commas https://eslint.org/docs/latest/rules/comma-dangle --- .eslintrc.yml | 7 +++++++ src/extensionModules/BoxOrderManager.js | 8 ++++---- src/prefsModules/PrefsBoxOrderItemRow.js | 8 ++++---- src/prefsModules/PrefsBoxOrderListBox.js | 8 ++++---- src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js | 2 +- src/prefsModules/PrefsPage.js | 4 ++-- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index f364ffc..caf7992 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -49,5 +49,12 @@ rules: object-curly-spacing: - error - always + comma-dangle: + - error + - arrays: always-multiline + objects: always-multiline + imports: always-multiline + exports: always-multiline + functions: never globals: log: readonly diff --git a/src/extensionModules/BoxOrderManager.js b/src/extensionModules/BoxOrderManager.js index 0525d08..c6f371d 100644 --- a/src/extensionModules/BoxOrderManager.js +++ b/src/extensionModules/BoxOrderManager.js @@ -14,8 +14,8 @@ export default class BoxOrderManager extends GObject.Object { static { GObject.registerClass({ Signals: { - "appIndicatorReady": {} - } + "appIndicatorReady": {}, + }, }, this); } @@ -157,7 +157,7 @@ export default class BoxOrderManager extends GObject.Object { const indicatorContainers = [ Main.panel._leftBox.get_children(), Main.panel._centerBox.get_children(), - Main.panel._rightBox.get_children() + Main.panel._rightBox.get_children(), ].flat(); // Create an indicator containers set from the indicator containers for @@ -212,7 +212,7 @@ export default class BoxOrderManager extends GObject.Object { center: Main.panel._centerBox.get_children(), // Reverse this array, since the items in the left and center box // are logically LTR, while the items in the right box are RTL. - right: Main.panel._rightBox.get_children().reverse() + right: Main.panel._rightBox.get_children().reverse(), }; // This function goes through the indicator containers of the given box diff --git a/src/prefsModules/PrefsBoxOrderItemRow.js b/src/prefsModules/PrefsBoxOrderItemRow.js index 9f350c1..3e09cd5 100644 --- a/src/prefsModules/PrefsBoxOrderItemRow.js +++ b/src/prefsModules/PrefsBoxOrderItemRow.js @@ -13,13 +13,13 @@ export default class PrefsBoxOrderItemRow extends Adw.ActionRow { GTypeName: "PrefsBoxOrderItemRow", Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-item-row.ui", GLib.UriFlags.NONE), InternalChildren: [ - "item-name-display-label" + "item-name-display-label", ], Signals: { "move": { - param_types: [GObject.TYPE_STRING] - } - } + param_types: [GObject.TYPE_STRING], + }, + }, }, this); this.install_action("row.forget", null, (self, _actionName, _param) => { const parentListBox = self.get_parent(); diff --git a/src/prefsModules/PrefsBoxOrderListBox.js b/src/prefsModules/PrefsBoxOrderListBox.js index 444745e..59d4417 100644 --- a/src/prefsModules/PrefsBoxOrderListBox.js +++ b/src/prefsModules/PrefsBoxOrderListBox.js @@ -21,13 +21,13 @@ export default class PrefsBoxOrderListBox extends Gtk.ListBox { "The box order this PrefsBoxOrderListBox is associated with.", GObject.ParamFlags.READWRITE, "" - ) + ), }, Signals: { "row-move": { - param_types: [PrefsBoxOrderItemRow, GObject.TYPE_STRING] - } - } + param_types: [PrefsBoxOrderItemRow, GObject.TYPE_STRING], + }, + }, }, this); } diff --git a/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js b/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js index 8dd772b..0fa0db3 100644 --- a/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js +++ b/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js @@ -8,7 +8,7 @@ export default class PrefsBoxOrderListEmptyPlaceholder extends Gtk.Box { static { GObject.registerClass({ GTypeName: "PrefsBoxOrderListEmptyPlaceholder", - Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-list-empty-placeholder.ui", GLib.UriFlags.NONE) + Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-list-empty-placeholder.ui", GLib.UriFlags.NONE), }, this); } diff --git a/src/prefsModules/PrefsPage.js b/src/prefsModules/PrefsPage.js index e871197..397a253 100644 --- a/src/prefsModules/PrefsPage.js +++ b/src/prefsModules/PrefsPage.js @@ -19,8 +19,8 @@ export default class PrefsPage extends Adw.PreferencesPage { InternalChildren: [ "left-box-order-list-box", "center-box-order-list-box", - "right-box-order-list-box" - ] + "right-box-order-list-box", + ], }, this); } From b98f047d22fb4cccaacce4d806d09fdb1df9b858 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Thu, 5 Oct 2023 14:58:16 +0200 Subject: [PATCH 21/56] Other: Add new version 45 panel source code to .eslintignore --- .eslintignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintignore b/.eslintignore index 092c1f1..3cad190 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,4 @@ /docs/panel_master_2021-04-21.js /docs/panel_42.5_2022-10-22.js /docs/panel_43.2_2023-01-24.js +/docs/panel_45.0_2023-09-26.js From 7f86e92e85353a55703d554e61b10122428663e2 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Thu, 5 Oct 2023 14:59:46 +0200 Subject: [PATCH 22/56] Refactor: Clean up unused import --- src/prefsModules/PrefsBoxOrderItemRow.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/prefsModules/PrefsBoxOrderItemRow.js b/src/prefsModules/PrefsBoxOrderItemRow.js index 3e09cd5..c44f51f 100644 --- a/src/prefsModules/PrefsBoxOrderItemRow.js +++ b/src/prefsModules/PrefsBoxOrderItemRow.js @@ -2,7 +2,6 @@ import Gtk from "gi://Gtk"; import Gdk from "gi://Gdk"; -import Gio from "gi://Gio"; import GObject from "gi://GObject"; import Adw from "gi://Adw"; import GLib from "gi://GLib"; From c25f24b72f7b086533f0aa34d97662b961f23040 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Thu, 5 Oct 2023 15:06:47 +0200 Subject: [PATCH 23/56] Other: Make ESLint ignore unused import --- src/prefsModules/PrefsPage.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/prefsModules/PrefsPage.js b/src/prefsModules/PrefsPage.js index 397a253..1816cce 100644 --- a/src/prefsModules/PrefsPage.js +++ b/src/prefsModules/PrefsPage.js @@ -9,6 +9,7 @@ import ScrollManager from "./ScrollManager.js"; import PrefsBoxOrderListEmptyPlaceholder from "./PrefsBoxOrderListEmptyPlaceholder.js"; // Imports to make UI file work. +// eslint-disable-next-line import PrefsBoxOrderListBox from "./PrefsBoxOrderListBox.js"; export default class PrefsPage extends Adw.PreferencesPage { From 126ebfa9dbd9ccaee5e8604f7e26f00535988105 Mon Sep 17 00:00:00 2001 From: Julian Schacher Date: Thu, 5 Oct 2023 15:21:39 +0200 Subject: [PATCH 24/56] Other: Bump version to 10 --- src/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metadata.json b/src/metadata.json index 7122a84..e19bfff 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -2,7 +2,7 @@ "uuid": "top-bar-organizer@julian.gse.jsts.xyz", "name": "Top Bar Organizer", "description": "Organize the items of the top (menu)bar.", - "version": 9, + "version": 10, "shell-version": [ "45" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", "url": "https://gitlab.gnome.org/julianschacher/top-bar-organizer" From e374ad85b11822fe79ee7b65c3313293889f5ed1 Mon Sep 17 00:00:00 2001 From: June Date: Wed, 11 Sep 2024 02:50:03 +0200 Subject: [PATCH 25/56] other: change commit msg format to use lowercase tags and desc. start --- CONTRIBUTING.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 72a8f7e..3df8919 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,22 +9,22 @@ For code of this repo in `.js` files, stick to a textwidth of 80. The commit message format is as follows: ``` -Tag: Short description +tag: short description Longer description here if necessary ``` -The `Tag` should be one of the following: +The `tag` should be one of the following: -- `Fix` - for a bug fix. -- `Update` - for a backwards compatible enhancement. -- `Feature` (formerly also `New`) - for a new feature. -- `Breaking` - for a backwards-incompatible enhancement or feature. -- `Perf` - for a code change that improves performance. -- `Refactor` - for a code change that neither fixes a bug nor adds a feature (nor is `Perf`). -- `Build` - for changes that affect the build system or external dependencies. -- `Test` - for adding or correcting tests. -- `Docs` - for changes to documentation only. -- `Other` - for anything that isn't covered by the tags above. +- `fix` - for a bug fix. +- `update` - for a backwards compatible enhancement. +- `feature` (formerly also `New`) - for a new feature. +- `breaking` - for a backwards-incompatible enhancement or feature. +- `perf` - for a code change that improves performance. +- `refactor` - for a code change that neither fixes a bug nor adds a feature (nor is `perf`). +- `build` - for changes that affect the build system or external dependencies. +- `test` - for adding or correcting tests. +- `docs` - for changes to documentation only. +- `other` - for anything that isn't covered by the tags above. Those tags are an adapted version of the tags eslint () and of the tags Angular () uses. From d88034f3450244a7ebc772322d01c5007cba08d3 Mon Sep 17 00:00:00 2001 From: June Date: Wed, 11 Sep 2024 02:48:29 +0200 Subject: [PATCH 26/56] docs: add newer, cut down and commented panel.js from GNOME Shell 46.4 --- .eslintignore | 1 + docs/panel_46.4_2024-09-11.js | 322 ++++++++++++++++++++++++++++++++++ 2 files changed, 323 insertions(+) create mode 100644 docs/panel_46.4_2024-09-11.js diff --git a/.eslintignore b/.eslintignore index 3cad190..2e93655 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,3 +2,4 @@ /docs/panel_42.5_2022-10-22.js /docs/panel_43.2_2023-01-24.js /docs/panel_45.0_2023-09-26.js +/docs/panel_46.4_2024-09-11.js diff --git a/docs/panel_46.4_2024-09-11.js b/docs/panel_46.4_2024-09-11.js new file mode 100644 index 0000000..76c2640 --- /dev/null +++ b/docs/panel_46.4_2024-09-11.js @@ -0,0 +1,322 @@ +// My annotated and cut down js/ui/panel.js from gnome-shell/46.4. +// All annotations are what I guessed, interpreted and copied while reading the +// code and comparing to other panel.js versions and might be wrong. They are +// prefixed with "Annotation:" to indicate that they're my comments, not +// comments that orginally existed. + +// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/46.4/js/ui/panel.js +// On: 2024-09-11 +// License: This code is licensed under GPLv2. + +// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/46.4/js/ui/sessionMode.js +// On: 2023-09-11 +// License: This code is licensed under GPLv2. + +// I'm using the word "item" to refer to the thing, which gets added to the top +// (menu)bar / panel, where an item has a role/name and an indicator. + + +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import Clutter from 'gi://Clutter'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import GObject from 'gi://GObject'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import St from 'gi://St'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import * as CtrlAltTab from './ctrlAltTab.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import * as PopupMenu from './popupMenu.js'; +import * as PanelMenu from './panelMenu.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import * as Main from './main.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import {DateMenuButton} from './dateMenu.js'; +import {ATIndicator} from './status/accessibility.js'; +import {InputSourceIndicator} from './status/keyboard.js'; +import {DwellClickIndicator} from './status/dwellClick.js'; +import {ScreenRecordingIndicator, ScreenSharingIndicator} from './status/remoteAccess.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +// Of note (for PANEL_ITEM_IMPLEMENTATIONS): +// const AppMenuButton = [...] +// const ActivitiesButton = [...] +// const QuickSettings = [...] + +const PANEL_ITEM_IMPLEMENTATIONS = { + 'activities': ActivitiesButton, + 'appMenu': AppMenuButton, + 'quickSettings': QuickSettings, + 'dateMenu': DateMenuButton, + 'a11y': ATIndicator, + 'keyboard': InputSourceIndicator, + 'dwellClick': DwellClickIndicator, + 'screenRecording': ScreenRecordingIndicator, + 'screenSharing': ScreenSharingIndicator, +}; + +export const Panel = GObject.registerClass( +class Panel extends St.Widget { + // Annotation: Initializes the top (menu)bar / panel. + // Does relevant stuff like: + // - Defining this._leftBox, this._centerBox and this._rightBox. + // - Finally calling this._updatePanel(). + // Compared to panel_45.0_2023-09-26.js: Not much changed except from some + // slightly different function names/calls. + _init() { + super._init({ + name: 'panel', + reactive: true, + }); + + this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); + + this._sessionStyle = null; + + this.statusArea = {}; + + this.menuManager = new PopupMenu.PopupMenuManager(this); + + this._leftBox = new St.BoxLayout({name: 'panelLeft'}); + this.add_child(this._leftBox); + this._centerBox = new St.BoxLayout({name: 'panelCenter'}); + this.add_child(this._centerBox); + this._rightBox = new St.BoxLayout({name: 'panelRight'}); + this.add_child(this._rightBox); + + this.connect('button-press-event', this._onButtonPress.bind(this)); + this.connect('touch-event', this._onTouchEvent.bind(this)); + + Main.overview.connectObject('showing', + () => this.add_style_pseudo_class('overview'), + this); + Main.overview.connectObject('hiding', + () => this.remove_style_pseudo_class('overview'), + this); + + Main.layoutManager.panelBox.add_child(this); + Main.ctrlAltTabManager.addGroup(this, + _('Top Bar'), 'shell-focus-top-bar-symbolic', + {sortGroup: CtrlAltTab.SortGroup.TOP}); + + Main.sessionMode.connect('updated', this._updatePanel.bind(this)); + + global.display.connect('workareas-changed', () => this.queue_relayout()); + this._updatePanel(); + } + + // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for + // this Extension. + + // Annotation: Gets called by this._init() to populate the top (menu)bar / + // panel initially. + // + // It does the following relevant stuff: + // - Calls this._hideIndicators() + // - Calls this._updateBox() for this._leftBox, this._centerBox and + // this._rightBox with panel.left, panel.center and panel.right to + // populate the boxes with items defined in panel.left, panel.center and + // panel.right. + // + // panel.left, panel.center and panel.right get set via the line let panel + // = Main.sessionMode.panel, which uses the panel of Mains (js/ui/main.js) + // instance of SessionMode (js/ui/sessionMode.js). + // + // And in js/ui/sessionMode.js (46.4, 2024-09-11) you have different modes + // with different panel configuration. For example the "user" mode with: + // panel: { + // left: ['activities'], + // center: ['dateMenu'], + // right: ['screenRecording', 'screenSharing', 'dwellClick', 'a11y', 'keyboard', 'quickSettings'], + // } + // + // This way this function populates the top (menu)bar / panel with the + // default stuff you see on a fresh Gnome. + // + // Compared to panel_45.0_2023-09-26.js: Nothing changed. + _updatePanel() { + let panel = Main.sessionMode.panel; + this._hideIndicators(); + this._updateBox(panel.left, this._leftBox); + this._updateBox(panel.center, this._centerBox); + this._updateBox(panel.right, this._rightBox); + + if (panel.left.includes('dateMenu')) + Main.messageTray.bannerAlignment = Clutter.ActorAlign.START; + else if (panel.right.includes('dateMenu')) + Main.messageTray.bannerAlignment = Clutter.ActorAlign.END; + // Default to center if there is no dateMenu + else + Main.messageTray.bannerAlignment = Clutter.ActorAlign.CENTER; + + if (this._sessionStyle) + this.remove_style_class_name(this._sessionStyle); + + this._sessionStyle = Main.sessionMode.panelStyle; + if (this._sessionStyle) + this.add_style_class_name(this._sessionStyle); + } + + // Annotation: This function hides all items, which are in the top (menu)bar + // panel and in PANEL_ITEM_IMPLEMENTATIONS. + // + // Compared to panel_45.0_2023-09-26.js: Nothing changed. + _hideIndicators() { + for (let role in PANEL_ITEM_IMPLEMENTATIONS) { + let indicator = this.statusArea[role]; + if (!indicator) + continue; + indicator.container.hide(); + } + } + + // Annotation: This function takes a role (of an item) and returns a + // corresponding indicator, if either of two things are true: + // - The indicator is already in this.statusArea. + // Then it just returns the indicator by using this.statusArea. + // - The role is in PANEL_ITEM_IMPLEMENTATIONS. + // Then it creates a new indicator, adds it to this.statusArea and returns + // it. + // + // Compared to panel_45.0_2023-09-26.js: Nothing changed. + _ensureIndicator(role) { + let indicator = this.statusArea[role]; + if (!indicator) { + let constructor = PANEL_ITEM_IMPLEMENTATIONS[role]; + if (!constructor) { + // This icon is not implemented (this is a bug) + return null; + } + indicator = new constructor(this); + this.statusArea[role] = indicator; + } + return indicator; + } + + // Annotation: This function takes a list of items (or rather their roles) + // and adds the indicators of those items to a box (like this._leftBox) + // using this._ensureIndicator() to get the indicator corresponding to the + // given role. + // So only items with roles this._ensureIndicator() knows, get added. + // + // Compared to panel_45.0_2023-09-26.js: Nothing changed. + _updateBox(elements, box) { + let nChildren = box.get_n_children(); + + for (let i = 0; i < elements.length; i++) { + let role = elements[i]; + let indicator = this._ensureIndicator(role); + if (indicator == null) + continue; + + this._addToPanelBox(role, indicator, i + nChildren, box); + } + } + + // Annotation: This function adds the given item to the specified top + // (menu)bar / panel box and connects to "destroy" and "menu-set" events. + // + // It takes the following arguments: + // - role: The name of the item to add. + // - indicator: The indicator of the item to add. + // - position: Where in the box to add the item. + // - box: The box to add the item to. + // Can be one of the following: + // - this._leftBox + // - this._centerBox + // - this._rightBox + // + // Compared to panel_45.0_2023-09-26.js: The call of + // parent.remove_actor(container) changed to parent.remove_child(container). + _addToPanelBox(role, indicator, position, box) { + let container = indicator.container; + container.show(); + + let parent = container.get_parent(); + if (parent) + parent.remove_child(container); + + + box.insert_child_at_index(container, position); + this.statusArea[role] = indicator; + let destroyId = indicator.connect('destroy', emitter => { + delete this.statusArea[role]; + emitter.disconnect(destroyId); + }); + indicator.connect('menu-set', this._onMenuSet.bind(this)); + this._onMenuSet(indicator); + } + + // Annotation: This function allows you to add an item to the top (menu)bar + // / panel. + // While per default it adds the item to the status area (the right box of + // the top bar), you can specify the box and add the item to any of the + // three boxes of the top bar. + // To add an item to the top bar, you need to give its role and indicator. + // + // This function takes the following arguments: + // - role: A name for the item to add. + // - indicator: The indicator for the item to add (must be an instance of + // PanelMenu.Button). + // - position: Where in the box to add the item. + // - box: The box to add the item to. + // Can be one of the following: + // - "left": referring to this._leftBox + // - "center": referring to this._centerBox + // - "right": referring to this._rightBox + // These boxes are what you see in the top bar as the left, right and + // center sections. + // + // Finally this function just calls this._addToPanelBox() for the actual + // work, so it basically just makes sure the input to this._addToPanelBox() + // is correct. + // + // Compared to panel_45.0_2023-09-26.js: Nothing changed. + addToStatusArea(role, indicator, position, box) { + if (this.statusArea[role]) + throw new Error(`Extension point conflict: there is already a status indicator for role ${role}`); + + if (!(indicator instanceof PanelMenu.Button)) + throw new TypeError('Status indicator must be an instance of PanelMenu.Button'); + + position ??= 0; + let boxes = { + left: this._leftBox, + center: this._centerBox, + right: this._rightBox, + }; + let boxContainer = boxes[box] || this._rightBox; + this.statusArea[role] = indicator; + this._addToPanelBox(role, indicator, position, boxContainer); + return indicator; + } + + // Of note: + // _onMenuSet(indicator) { [...] } + + // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for + // this Extension. +}); From e04ac8a3ee1c1166b1be9fb209ee5a1e0dd01bb5 Mon Sep 17 00:00:00 2001 From: June Date: Wed, 11 Sep 2024 03:02:02 +0200 Subject: [PATCH 27/56] feature: support GNOME Shell version 46 There don't seem to be any changes relevant to the functionality of this extension. --- src/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metadata.json b/src/metadata.json index e19bfff..53234fc 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -3,7 +3,7 @@ "name": "Top Bar Organizer", "description": "Organize the items of the top (menu)bar.", "version": 10, - "shell-version": [ "45" ], + "shell-version": [ "45", "46" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", "url": "https://gitlab.gnome.org/julianschacher/top-bar-organizer" } From 1870a9510af67728ca6331591930765ca29e88a6 Mon Sep 17 00:00:00 2001 From: June Date: Wed, 11 Sep 2024 03:16:46 +0200 Subject: [PATCH 28/56] other: update my name --- README.md | 2 +- package.json | 4 ++-- src/metadata.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fc8c8ba..91ea15c 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,6 @@ Top Bar Organizer allows you to organize the items of the GNOME Shell top (menu) ## Installation The extension is available on the [GNOME Extensions website](https://extensions.gnome.org/extension/4356/top-bar-organizer/). -Or you can also manually install a release from the [releases page](https://gitlab.gnome.org/julianschacher/top-bar-organizer/-/releases). +Or you can also manually install a release from the [releases page](https://gitlab.gnome.org/june/top-bar-organizer/-/releases). There's also a community-maintained [AUR package](https://aur.archlinux.org/packages/gnome-shell-extension-top-bar-organizer) available. diff --git a/package.json b/package.json index cf86174..efcc3a5 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ }, "repository": { "type": "git", - "url": "git@gitlab.gnome.org:julianschacher/top-bar-organizer.git" + "url": "git@gitlab.gnome.org:june/top-bar-organizer.git" }, - "author": "Julian Schacher", + "author": "June", "license": "GPL-3.0-or-later", "devDependencies": { "eslint": "^8.50.0" diff --git a/src/metadata.json b/src/metadata.json index 53234fc..7f12ace 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -5,5 +5,5 @@ "version": 10, "shell-version": [ "45", "46" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", - "url": "https://gitlab.gnome.org/julianschacher/top-bar-organizer" + "url": "https://gitlab.gnome.org/june/top-bar-organizer" } From 8fb92d1bb17a7f8fde08c0b2a3856f028f879180 Mon Sep 17 00:00:00 2001 From: June Date: Wed, 11 Sep 2024 03:37:37 +0200 Subject: [PATCH 29/56] docs: exp. docs on creat. a new tag to cover how to create a new release Also generally fix up the docs and the git_annotated_tag_template a bit, make the tag template not include the shortlog anymore (as that doesn't make that much sense) and also provide a release_notes_template.md. --- docs/Creating_a_New_Release.md | 51 ++++++++++++++++++++++++++++++++++ docs/Creating_a_New_Tag.md | 22 --------------- docs/release_notes_template.md | 15 ++++++++++ git_annotated_tag_template | 8 +----- 4 files changed, 67 insertions(+), 29 deletions(-) create mode 100644 docs/Creating_a_New_Release.md delete mode 100644 docs/Creating_a_New_Tag.md create mode 100644 docs/release_notes_template.md diff --git a/docs/Creating_a_New_Release.md b/docs/Creating_a_New_Release.md new file mode 100644 index 0000000..38d7980 --- /dev/null +++ b/docs/Creating_a_New_Release.md @@ -0,0 +1,51 @@ +# Creating a Release + +## Create a Tag + +To create a new tag, do the following: + +1. Fill out `git_annotated_tag_template`. +2. Run the following command to tag the current commit with `vX`: + + ``` + git tag -a -F git_annotated_tag_template -s --cleanup=verbatim vX + ``` + +3. Restore `git_annotated_tag_template` to its original state: + + ``` + git restore git_annotated_tag_template + ``` + +4. Push the tag: + + ``` + git push --tags + ``` + +## Build a Release-ZIP + +1. Build the release-ZIP: + + ``` + ./package.sh + ``` + +2. Name the release-ZIP after the current version: + + ``` + mv top-bar-organizer@julian.gse.jsts.xyz.shell-extension.zip top-bar-organizer@julian.gse.jsts.xyz.shell-extension_vX.zip + ``` + +## Create a GitLab Release + +1. Go to the [Releases section of the repo](https://gitlab.gnome.org/june/top-bar-organizer/-/releases) and click on the "New Release" button. +2. Select the corresponding tag created earlier. +3. Name the release "Top Bar Organizer vX". +4. Copy the [release notes template](./release_notes_template.md) and fill it out. +5. Upload the release-ZIP created in the previous step as a release asset. +6. Create the release. + +## Uploading to the GNOME Extensions Website + +1. Go to the [upload page of the GNOME extensions website](https://extensions.gnome.org/upload/) and upload the release-ZIP. diff --git a/docs/Creating_a_New_Tag.md b/docs/Creating_a_New_Tag.md deleted file mode 100644 index 9cfb87d..0000000 --- a/docs/Creating_a_New_Tag.md +++ /dev/null @@ -1,22 +0,0 @@ -# Creating a New Tag - -To create a new tag, do the following: - -1. Fill out `git_annotated_tag_template`. -2. Run the following command: - - ``` - git tag -a -F git_annotated_tag_template -s --cleanup=verbatim [] - ``` - -3. Restore `git_annotated_tag_template` to its original state: - - ``` - git restore git_annotated_tag_template - ``` - -4. Push the new tag. - - ``` - git push --tags - ``` diff --git a/docs/release_notes_template.md b/docs/release_notes_template.md new file mode 100644 index 0000000..740ef00 --- /dev/null +++ b/docs/release_notes_template.md @@ -0,0 +1,15 @@ +Top Bar Organizer vX includes the following changes: + +# Relevant and/or Breaking Changes + +The following relevant and/or breaking changes of this version: + + + +# `git shortlog` + +The git shortlog for this version: + +``` + +``` diff --git a/git_annotated_tag_template b/git_annotated_tag_template index 7ad6f78..5f9a5c0 100644 --- a/git_annotated_tag_template +++ b/git_annotated_tag_template @@ -1,13 +1,7 @@ -Top Bar Organizer v1 includes the following changes: +Top Bar Organizer vX includes the following changes: # Relevant and/or Breaking Changes The following relevant and/or breaking changes of this version: - -# `git shortlog` - -The git shortlog for this version: - - From ea3942057f9a826af035ab9e81b52f9178995b5e Mon Sep 17 00:00:00 2001 From: June Date: Wed, 11 Sep 2024 03:51:31 +0200 Subject: [PATCH 30/56] docs: enhance the git annotated tag and release notes templates - Give them a better general structure by having a "Relevant and/or Breaking Changes" and an "Other Changes" section. - Use more minimal markup in the git annotated tag template as that works better for annotated tags. - Use nicer and more useful placeholder values. - Get rid of unnecessary descriptions. --- docs/release_notes_template.md | 15 +++++++++++++-- git_annotated_tag_template | 12 +++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/docs/release_notes_template.md b/docs/release_notes_template.md index 740ef00..66ac266 100644 --- a/docs/release_notes_template.md +++ b/docs/release_notes_template.md @@ -4,12 +4,23 @@ Top Bar Organizer vX includes the following changes: The following relevant and/or breaking changes of this version: - +## Breaking Change + +Description + +## Relevant Change + +Description + +# Other Changes + +- a change +- another change # `git shortlog` The git shortlog for this version: ``` - +git shortlog vX-1..vX ``` diff --git a/git_annotated_tag_template b/git_annotated_tag_template index 5f9a5c0..2c66d8d 100644 --- a/git_annotated_tag_template +++ b/git_annotated_tag_template @@ -1,7 +1,9 @@ -Top Bar Organizer vX includes the following changes: +Top Bar Organizer vX -# Relevant and/or Breaking Changes +Relevant and/or Breaking Changes: +- breaking change: description +- relevant change: description -The following relevant and/or breaking changes of this version: - - +Other Changes: +- a change +- another change From b358d2046d6225ef24e658860d06278d76901395 Mon Sep 17 00:00:00 2001 From: June Date: Wed, 11 Sep 2024 03:17:59 +0200 Subject: [PATCH 31/56] other: bump version to 11 --- src/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metadata.json b/src/metadata.json index 7f12ace..4248aa5 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -2,7 +2,7 @@ "uuid": "top-bar-organizer@julian.gse.jsts.xyz", "name": "Top Bar Organizer", "description": "Organize the items of the top (menu)bar.", - "version": 10, + "version": 11, "shell-version": [ "45", "46" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", "url": "https://gitlab.gnome.org/june/top-bar-organizer" From b762d6db221f229a69ecd87473259233336ad8a5 Mon Sep 17 00:00:00 2001 From: June Date: Wed, 11 Sep 2024 04:09:29 +0200 Subject: [PATCH 32/56] docs: fix description of release-ZIP upload process The release-ZIP needs to be uploaded in the release notes section, not in the release assets section (as that's apparently not possible). --- docs/Creating_a_New_Release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Creating_a_New_Release.md b/docs/Creating_a_New_Release.md index 38d7980..049afd2 100644 --- a/docs/Creating_a_New_Release.md +++ b/docs/Creating_a_New_Release.md @@ -43,7 +43,7 @@ To create a new tag, do the following: 2. Select the corresponding tag created earlier. 3. Name the release "Top Bar Organizer vX". 4. Copy the [release notes template](./release_notes_template.md) and fill it out. -5. Upload the release-ZIP created in the previous step as a release asset. +5. Drop the release-ZIP created in the previous step at the end of the release notes. 6. Create the release. ## Uploading to the GNOME Extensions Website From 62fd0141465b81673ab41ce9e6a47eb3d0a53505 Mon Sep 17 00:00:00 2001 From: June Date: Thu, 12 Sep 2024 21:44:26 +0200 Subject: [PATCH 33/56] docs: add newer, cut down and commented panel.js from GNOME Shell 47.rc --- .eslintignore | 1 + docs/panel_47.rc_2024-09-12.js | 317 +++++++++++++++++++++++++++++++++ 2 files changed, 318 insertions(+) create mode 100644 docs/panel_47.rc_2024-09-12.js diff --git a/.eslintignore b/.eslintignore index 2e93655..2b884b5 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,3 +3,4 @@ /docs/panel_43.2_2023-01-24.js /docs/panel_45.0_2023-09-26.js /docs/panel_46.4_2024-09-11.js +/docs/panel_47.rc_2024-09-12.js diff --git a/docs/panel_47.rc_2024-09-12.js b/docs/panel_47.rc_2024-09-12.js new file mode 100644 index 0000000..504cbb6 --- /dev/null +++ b/docs/panel_47.rc_2024-09-12.js @@ -0,0 +1,317 @@ +// My annotated and cut down js/ui/panel.js from gnome-shell/47.rc. +// All annotations are what I guessed, interpreted and copied while reading the +// code and comparing to other panel.js versions and might be wrong. They are +// prefixed with "Annotation:" to indicate that they're my comments, not +// comments that orginally existed. + +// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/47.rc/js/ui/panel.js +// On: 2024-09-12 +// License: This code is licensed under GPLv2. + +// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/47.rc/js/ui/sessionMode.js +// On: 2023-09-12 +// License: This code is licensed under GPLv2. + +// I'm using the word "item" to refer to the thing, which gets added to the top +// (menu)bar / panel, where an item has a role/name and an indicator. + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import Clutter from 'gi://Clutter'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import GObject from 'gi://GObject'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import St from 'gi://St'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import * as CtrlAltTab from './ctrlAltTab.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import * as PopupMenu from './popupMenu.js'; +import * as PanelMenu from './panelMenu.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import * as Main from './main.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import {DateMenuButton} from './dateMenu.js'; +import {ATIndicator} from './status/accessibility.js'; +import {InputSourceIndicator} from './status/keyboard.js'; +import {DwellClickIndicator} from './status/dwellClick.js'; +import {ScreenRecordingIndicator, ScreenSharingIndicator} from './status/remoteAccess.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +// Of note (for PANEL_ITEM_IMPLEMENTATIONS): +// const AppMenuButton = [...] +// const ActivitiesButton = [...] +// const QuickSettings = [...] + +const PANEL_ITEM_IMPLEMENTATIONS = { + 'activities': ActivitiesButton, + 'appMenu': AppMenuButton, + 'quickSettings': QuickSettings, + 'dateMenu': DateMenuButton, + 'a11y': ATIndicator, + 'keyboard': InputSourceIndicator, + 'dwellClick': DwellClickIndicator, + 'screenRecording': ScreenRecordingIndicator, + 'screenSharing': ScreenSharingIndicator, +}; + +export const Panel = GObject.registerClass( +class Panel extends St.Widget { + // Annotation: Initializes the top (menu)bar / panel. + // Does relevant stuff like: + // - Defining this._leftBox, this._centerBox and this._rightBox. + // - Finally calling this._updatePanel(). + // Compared to panel_46.4_2024-09-11.js: Nothing changed. + _init() { + super._init({ + name: 'panel', + reactive: true, + }); + + this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); + + this._sessionStyle = null; + + this.statusArea = {}; + + this.menuManager = new PopupMenu.PopupMenuManager(this); + + this._leftBox = new St.BoxLayout({name: 'panelLeft'}); + this.add_child(this._leftBox); + this._centerBox = new St.BoxLayout({name: 'panelCenter'}); + this.add_child(this._centerBox); + this._rightBox = new St.BoxLayout({name: 'panelRight'}); + this.add_child(this._rightBox); + + this.connect('button-press-event', this._onButtonPress.bind(this)); + this.connect('touch-event', this._onTouchEvent.bind(this)); + + Main.overview.connectObject('showing', + () => this.add_style_pseudo_class('overview'), + this); + Main.overview.connectObject('hiding', + () => this.remove_style_pseudo_class('overview'), + this); + + Main.layoutManager.panelBox.add_child(this); + Main.ctrlAltTabManager.addGroup(this, + _('Top Bar'), 'shell-focus-top-bar-symbolic', + {sortGroup: CtrlAltTab.SortGroup.TOP}); + + Main.sessionMode.connect('updated', this._updatePanel.bind(this)); + + global.display.connect('workareas-changed', () => this.queue_relayout()); + this._updatePanel(); + } + + // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for + // this Extension. + + // Annotation: Gets called by this._init() to populate the top (menu)bar / + // panel initially. + // + // It does the following relevant stuff: + // - Calls this._hideIndicators() + // - Calls this._updateBox() for this._leftBox, this._centerBox and + // this._rightBox with panel.left, panel.center and panel.right to + // populate the boxes with items defined in panel.left, panel.center and + // panel.right. + // + // panel.left, panel.center and panel.right get set via the line let panel + // = Main.sessionMode.panel, which uses the panel of Mains (js/ui/main.js) + // instance of SessionMode (js/ui/sessionMode.js). + // + // And in js/ui/sessionMode.js (47.rc, 2024-09-12) you have different modes + // with different panel configuration. For example the "user" mode with: + // panel: { + // left: ['activities'], + // center: ['dateMenu'], + // right: ['screenRecording', 'screenSharing', 'dwellClick', 'a11y', 'keyboard', 'quickSettings'], + // } + // + // This way this function populates the top (menu)bar / panel with the + // default stuff you see on a fresh Gnome. + // + // Compared to panel_46.4_2024-09-11.js: Nothing changed. + _updatePanel() { + let panel = Main.sessionMode.panel; + this._hideIndicators(); + this._updateBox(panel.left, this._leftBox); + this._updateBox(panel.center, this._centerBox); + this._updateBox(panel.right, this._rightBox); + + if (panel.left.includes('dateMenu')) + Main.messageTray.bannerAlignment = Clutter.ActorAlign.START; + else if (panel.right.includes('dateMenu')) + Main.messageTray.bannerAlignment = Clutter.ActorAlign.END; + // Default to center if there is no dateMenu + else + Main.messageTray.bannerAlignment = Clutter.ActorAlign.CENTER; + + if (this._sessionStyle) + this.remove_style_class_name(this._sessionStyle); + + this._sessionStyle = Main.sessionMode.panelStyle; + if (this._sessionStyle) + this.add_style_class_name(this._sessionStyle); + } + + // Annotation: This function hides all items, which are in the top (menu)bar + // panel and in PANEL_ITEM_IMPLEMENTATIONS. + // + // Compared to panel_46.4_2024-09-11.js: Nothing changed. + _hideIndicators() { + for (let role in PANEL_ITEM_IMPLEMENTATIONS) { + let indicator = this.statusArea[role]; + if (!indicator) + continue; + indicator.container.hide(); + } + } + + // Annotation: This function takes a role (of an item) and returns a + // corresponding indicator, if either of two things are true: + // - The indicator is already in this.statusArea. + // Then it just returns the indicator by using this.statusArea. + // - The role is in PANEL_ITEM_IMPLEMENTATIONS. + // Then it creates a new indicator, adds it to this.statusArea and returns + // it. + // + // Compared to panel_46.4_2024-09-11.js: Nothing changed. + _ensureIndicator(role) { + let indicator = this.statusArea[role]; + if (!indicator) { + let constructor = PANEL_ITEM_IMPLEMENTATIONS[role]; + if (!constructor) { + // This icon is not implemented (this is a bug) + return null; + } + indicator = new constructor(this); + this.statusArea[role] = indicator; + } + return indicator; + } + + // Annotation: This function takes a list of items (or rather their roles) + // and adds the indicators of those items to a box (like this._leftBox) + // using this._ensureIndicator() to get the indicator corresponding to the + // given role. + // So only items with roles this._ensureIndicator() knows, get added. + // + // Compared to panel_46.4_2024-09-11.js: Nothing changed. + _updateBox(elements, box) { + let nChildren = box.get_n_children(); + + for (let i = 0; i < elements.length; i++) { + let role = elements[i]; + let indicator = this._ensureIndicator(role); + if (indicator == null) + continue; + + this._addToPanelBox(role, indicator, i + nChildren, box); + } + } + + // Annotation: This function adds the given item to the specified top + // (menu)bar / panel box and connects to "destroy" and "menu-set" events. + // + // It takes the following arguments: + // - role: The name of the item to add. + // - indicator: The indicator of the item to add. + // - position: Where in the box to add the item. + // - box: The box to add the item to. + // Can be one of the following: + // - this._leftBox + // - this._centerBox + // - this._rightBox + // + // Compared to panel_46.4_2024-09-11.js: Nothing changed. + _addToPanelBox(role, indicator, position, box) { + let container = indicator.container; + container.show(); + + let parent = container.get_parent(); + if (parent) + parent.remove_child(container); + + + box.insert_child_at_index(container, position); + this.statusArea[role] = indicator; + let destroyId = indicator.connect('destroy', emitter => { + delete this.statusArea[role]; + emitter.disconnect(destroyId); + }); + indicator.connect('menu-set', this._onMenuSet.bind(this)); + this._onMenuSet(indicator); + } + + // Annotation: This function allows you to add an item to the top (menu)bar + // / panel. + // While per default it adds the item to the status area (the right box of + // the top bar), you can specify the box and add the item to any of the + // three boxes of the top bar. + // To add an item to the top bar, you need to give its role and indicator. + // + // This function takes the following arguments: + // - role: A name for the item to add. + // - indicator: The indicator for the item to add (must be an instance of + // PanelMenu.Button). + // - position: Where in the box to add the item. + // - box: The box to add the item to. + // Can be one of the following: + // - "left": referring to this._leftBox + // - "center": referring to this._centerBox + // - "right": referring to this._rightBox + // These boxes are what you see in the top bar as the left, right and + // center sections. + // + // Finally this function just calls this._addToPanelBox() for the actual + // work, so it basically just makes sure the input to this._addToPanelBox() + // is correct. + // + // Compared to panel_46.4_2024-09-11.js: Nothing changed. + addToStatusArea(role, indicator, position, box) { + if (this.statusArea[role]) + throw new Error(`Extension point conflict: there is already a status indicator for role ${role}`); + + if (!(indicator instanceof PanelMenu.Button)) + throw new TypeError('Status indicator must be an instance of PanelMenu.Button'); + + position ??= 0; + let boxes = { + left: this._leftBox, + center: this._centerBox, + right: this._rightBox, + }; + let boxContainer = boxes[box] || this._rightBox; + this.statusArea[role] = indicator; + this._addToPanelBox(role, indicator, position, boxContainer); + return indicator; + } + + // Of note: + // _onMenuSet(indicator) { [...] } + + // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for + // this Extension. +}); From 07355dcf195815a422e97813329364230fbb7061 Mon Sep 17 00:00:00 2001 From: June Date: Thu, 12 Sep 2024 22:55:05 +0200 Subject: [PATCH 34/56] feature: support GNOME Shell version 47 Checked the source of 47.rc and tested in GNOME OS and there don't seem to be any changes relevant to the functionality of this extension. --- src/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metadata.json b/src/metadata.json index 4248aa5..be500de 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -3,7 +3,7 @@ "name": "Top Bar Organizer", "description": "Organize the items of the top (menu)bar.", "version": 11, - "shell-version": [ "45", "46" ], + "shell-version": [ "45", "46", "47" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", "url": "https://gitlab.gnome.org/june/top-bar-organizer" } From 23baa41225356ca6068a24276e7549afe65579cc Mon Sep 17 00:00:00 2001 From: June Date: Thu, 12 Sep 2024 22:56:02 +0200 Subject: [PATCH 35/56] other: bump version to 12 --- src/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metadata.json b/src/metadata.json index be500de..e7a2fbf 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -2,7 +2,7 @@ "uuid": "top-bar-organizer@julian.gse.jsts.xyz", "name": "Top Bar Organizer", "description": "Organize the items of the top (menu)bar.", - "version": 11, + "version": 12, "shell-version": [ "45", "46", "47" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", "url": "https://gitlab.gnome.org/june/top-bar-organizer" From cc088f443c7cac4d95682b3ab41745b1f7d06f8c Mon Sep 17 00:00:00 2001 From: June Date: Thu, 26 Sep 2024 02:23:28 +0200 Subject: [PATCH 36/56] refactor: clearly dist. betw. an items role and the id used in settings Clearly distinguish between an items role, which is present in GNOME Shells top bar, call that a role, and the thing that is stored in the settings for an item, call that an items settings identifier. Refactor the code with these new names in mind to make it clearer. Also make the comments clearer. And finally simplify the code handling AppIndicator items by simply using the items settings identifier as the key in the roles map and with that getting rid of the confusing concept of a placeholder role, which is only relevant for the box order stored in settings. Just declaring it as an items settings identifier, which it is, is much clearer. --- src/extension.js | 13 +- src/extensionModules/BoxOrderManager.js | 187 ++++++++++++++---------- 2 files changed, 118 insertions(+), 82 deletions(-) diff --git a/src/extension.js b/src/extension.js index 7caa5b3..94778e9 100644 --- a/src/extension.js +++ b/src/extension.js @@ -16,9 +16,10 @@ export default class TopBarOrganizerExtension extends Extension { // Initially handle new top bar items and order top bar boxes. this.#handleNewItemsAndOrderTopBar(); - // Overwrite `Panel._addToPanelBox` method with one handling new items - // and also handle AppIndicators getting ready, to handle new items. + // Overwrite the `Panel._addToPanelBox` method with one handling new + // items. this.#overwritePanelAddToPanelBox(); + // Handle AppIndicators getting ready, to handle new AppIndicator items. this._boxOrderManager.connect("appIndicatorReady", () => { this.#handleNewItemsAndOrderTopBar(); }); @@ -95,7 +96,7 @@ export default class TopBarOrganizerExtension extends Extension { } // Get the valid box order. - const validBoxOrder = this._boxOrderManager.createValidBoxOrder(box); + const validBoxOrder = this._boxOrderManager.getValidBoxOrder(box); // Get the relevant box of `Main.panel`. let panelBox; @@ -111,10 +112,10 @@ export default class TopBarOrganizerExtension extends Extension { break; } - /// Go through the items (or rather their roles) of the validBoxOrder - /// and order the panelBox accordingly. + /// Go through the items of the validBoxOrder and order the GNOME Shell + /// top bar box accordingly. for (let i = 0; i < validBoxOrder.length; i++) { - const role = validBoxOrder[i]; + const role = validBoxOrder[i].role; // Get the indicator container associated with the current role. const associatedIndicatorContainer = Main.panel.statusArea[role].container; diff --git a/src/extensionModules/BoxOrderManager.js b/src/extensionModules/BoxOrderManager.js index c6f371d..90ad2a9 100644 --- a/src/extensionModules/BoxOrderManager.js +++ b/src/extensionModules/BoxOrderManager.js @@ -5,10 +5,18 @@ import GObject from "gi://GObject"; import * as Main from "resource:///org/gnome/shell/ui/main.js"; /** - * This class provides methods get, set and interact with box orders, while - * taking over the work of translating between what is stored in settings and - * what is really useable by the other extension code. - * It's basically a heavy wrapper around the box orders stored in the settings. + * A resolved box order item containing the items role and settings identifier. + * @typedef {Object} ResolvedBoxOrderItem + * @property {string} settingsId - The settings identifier of the item. + * @property {string} role - The role of the item. + */ + +/** + * This class provides an interfaces to the box orders stored in settings. + * It takes care of handling AppIndicator items and resolving from the internal + * item settings identifiers to roles. + * In the end this results in convenient functions, which are directly useful in + * other extension code. */ export default class BoxOrderManager extends GObject.Object { static { @@ -20,31 +28,33 @@ export default class BoxOrderManager extends GObject.Object { } #appIndicatorReadyHandlerIdMap; - #appIndicatorItemApplicationRoleMap; + #appIndicatorItemSettingsIdToRolesMap; #settings; constructor(params = {}, settings) { super(params); this.#appIndicatorReadyHandlerIdMap = new Map(); - this.#appIndicatorItemApplicationRoleMap = new Map(); + this.#appIndicatorItemSettingsIdToRolesMap = new Map(); this.#settings = settings; } /** - * Handles an AppIndicator/KStatusNotifierItem item by associating the role - * of the given item with the application of the - * AppIndicator/KStatusNotifier item and returning a placeholder role. - * In the case, where the application can't be determined, this method - * throws an error. However it also makes sure that once the app indicators - * "ready" signal emits, this classes "appIndicatorReady" signal emits as - * well. + * Handles an AppIndicator/KStatusNotifierItem item by deriving a settings + * identifier and then associating the role of the given item to the items + * settings identifier. + * It then returns the derived settings identifier. + * In the case, where the settings identifier can't be derived, because the + * application can't be determined, this method throws an error. However it + * then also makes sure that once the app indicators "ready" signal emits, + * this classes "appIndicatorReady" signal emits as well, such that it and + * other methods can be called again to properly handle the item. * @param {string} indicatorContainer - The container of the indicator of the * AppIndicator/KStatusNotifierItem item. * @param {string} role - The role of the AppIndicator/KStatusNotifierItem * item. - * @returns {string} The placeholder role. + * @returns {string} The derived items settings identifier. */ #handleAppIndicatorItem(indicatorContainer, role) { const appIndicator = indicatorContainer.get_child()._indicator; @@ -66,56 +76,75 @@ export default class BoxOrderManager extends GObject.Object { application = "dropbox-client"; } - // Associate the role with the application. - let roles = this.#appIndicatorItemApplicationRoleMap.get(application); + // Derive the items settings identifier from the application name. + const itemSettingsId = `appindicator-kstatusnotifieritem-${application}`; + + // Associate the role with the items settings identifier. + let roles = this.#appIndicatorItemSettingsIdToRolesMap.get(itemSettingsId); if (roles) { - // If the application already has an array of associated roles, just - // add the role to it, if needed. + // If the settings identifier already has an array of associated + // roles, just add the role to it, if needed. if (!roles.includes(role)) { roles.push(role); } } else { // Otherwise create a new array. - this.#appIndicatorItemApplicationRoleMap.set(application, [role]); + this.#appIndicatorItemSettingsIdToRolesMap.set(itemSettingsId, [role]); } - // Return the placeholder. - // A box order containing this placeholder can later be resolved to - // relevant roles using `#resolveAppIndicatorPlaceholders`. - return `appindicator-kstatusnotifieritem-${application}`; + // Return the item settings identifier. + return itemSettingsId; } /** - * Takes a box order and replaces AppIndicator placeholder roles with - * actual roles. - * @param {string[]} - The box order of which to replace placeholder roles. - * @returns {string[]} - A box order with all placeholder roles - * resolved/replaced to/with actual roles. + * Gets a resolved box order for the given top bar box, where all + * AppIndicator items got resolved using their roles, meaning they might be + * present multiple times or not at all depending on the roles stored. + * @param {string} box - The top bar box for which to get the resolved box order. + * Must be one of the following values: + * - "left" + * - "center" + * - "right" + * @returns {ResolvedBoxOrderItem[]} - The resolved box order. */ - #resolveAppIndicatorPlaceholders(boxOrder) { + #getResolvedBoxOrder(box) { + // Get the box order from settings. + let boxOrder = this.#settings.get_strv(`${box}-box-order`); + let resolvedBoxOrder = []; - for (const role of boxOrder) { - // If the role isn't a placeholder, just add it to the resolved box - // order. - if (!role.startsWith("appindicator-kstatusnotifieritem-")) { - resolvedBoxOrder.push(role); + for (const itemSettingsId of boxOrder) { + const resolvedBoxOrderItem = { + settingsId: itemSettingsId, + role: "", + }; + + // If the items settings identifier doesn't indicate that the item + // is an AppIndicator/KStatusNotifierItem item, then its identifier + // is the role and it can just be added to the resolved box order. + if (!itemSettingsId.startsWith("appindicator-kstatusnotifieritem-")) { + resolvedBoxOrderItem.role = resolvedBoxOrderItem.settingsId; + resolvedBoxOrder.push(resolvedBoxOrderItem); continue; } - /// If the role is a placeholder, replace it. - // First get the application this placeholder is associated with. - const application = role.replace("appindicator-kstatusnotifieritem-", ""); + // If the items settings identifier indicates otherwise, then handle + // the item specially. - // Then get the actual roles associated with this application. - let actualRoles = this.#appIndicatorItemApplicationRoleMap.get(application); + // Get the roles roles associated with the items settings id. + let roles = this.#appIndicatorItemSettingsIdToRolesMap.get(resolvedBoxOrderItem.settingsId); - // If there are no actual roles, continue. - if (!actualRoles) { + // If there are no roles associated, continue. + if (!roles) { continue; } - // Otherwise add the actual roles to the resolved box order. - resolvedBoxOrder.push(...actualRoles); + // Otherwise create a new resolved box order item for each role and + // add it to the resolved box order. + for (const role of roles) { + const newResolvedBoxOrderItem = JSON.parse(JSON.stringify(resolvedBoxOrderItem)); + newResolvedBoxOrderItem.role = role; + resolvedBoxOrder.push(newResolvedBoxOrderItem); + } } return resolvedBoxOrder; @@ -136,24 +165,23 @@ export default class BoxOrderManager extends GObject.Object { } /** - * This method returns a valid box order for the given top bar box. - * This means it returns a box order, where only roles are included, which - * have their associated indicator container already in some box of the - * Gnome Shell top bar. + * Gets a valid box order for the given top bar box, where all AppIndicator + * items got resolved and where only items are included, which are in some + * GNOME Shell top bar box. * @param {string} box - The top bar box to return the valid box order for. * Must be one of the following values: * - "left" * - "center" * - "right" - * @returns {string[]} - The valid box order. + * @returns {ResolvedBoxOrderItem[]} - The valid box order. */ - createValidBoxOrder(box) { + getValidBoxOrder(box) { // Get a resolved box order. - let boxOrder = this.#resolveAppIndicatorPlaceholders(this.#settings.get_strv(`${box}-box-order`)); + let resolvedBoxOrder = this.#getResolvedBoxOrder(box); // ToDo: simplify. // Get the indicator containers (of the items) currently present in the - // Gnome Shell top bar. + // GNOME Shell top bar. const indicatorContainers = [ Main.panel._leftBox.get_children(), Main.panel._centerBox.get_children(), @@ -164,16 +192,16 @@ export default class BoxOrderManager extends GObject.Object { // fast easy access. const indicatorContainerSet = new Set(indicatorContainers); - // Go through the box order and only add items to the valid box order, - // where their indicator is present in the Gnome Shell top bar - // currently. + // Go through the resolved box order and only add items to the valid box + // order, where their indicator is currently present in the GNOME Shell + // top bar. let validBoxOrder = []; - for (const role of boxOrder) { - // Get the indicator container associated with the current role. - const associatedIndicatorContainer = Main.panel.statusArea[role]?.container; + for (const item of resolvedBoxOrder) { + // Get the indicator container associated with the items role. + const associatedIndicatorContainer = Main.panel.statusArea[item.role]?.container; if (indicatorContainerSet.has(associatedIndicatorContainer)) { - validBoxOrder.push(role); + validBoxOrder.push(item); } } @@ -181,13 +209,13 @@ export default class BoxOrderManager extends GObject.Object { } /** - * This method saves all new items currently present in the Gnome Shell top - * bar to the correct box orders. + * This method saves all new items currently present in the GNOME Shell top + * bar to the settings. */ saveNewTopBarItems() { // Only run, when the session mode is "user" or the parent session mode // is "user". - if(Main.sessionMode.currentMode !== "user" && Main.sessionMode.parentMode !== "user") { + if (Main.sessionMode.currentMode !== "user" && Main.sessionMode.parentMode !== "user") { return; } @@ -198,7 +226,7 @@ export default class BoxOrderManager extends GObject.Object { right: this.#settings.get_strv("right-box-order"), }; - // Get roles (of items) currently present in the Gnome Shell top bar and + // Get roles (of items) currently present in the GNOME Shell top bar and // index them using their associated indicator container. let indicatorContainerRoleMap = new Map(); for (const role in Main.panel.statusArea) { @@ -206,7 +234,7 @@ export default class BoxOrderManager extends GObject.Object { } // Get the indicator containers (of the items) currently present in the - // Gnome Shell top bar boxes. + // GNOME Shell top bar boxes. const boxIndicatorContainers = { left: Main.panel._leftBox.get_children(), center: Main.panel._centerBox.get_children(), @@ -216,8 +244,8 @@ export default class BoxOrderManager extends GObject.Object { }; // This function goes through the indicator containers of the given box - // and adds roles of new items to the box order. - const addNewItemsToBoxOrder = (indicatorContainers, boxOrder, box) => { + // and adds new item settings identifiers to the given box order. + const addNewItemSettingsIdsToBoxOrder = (indicatorContainers, boxOrder, box) => { for (const indicatorContainer of indicatorContainers) { // First get the role associated with the current indicator // container. @@ -226,36 +254,43 @@ export default class BoxOrderManager extends GObject.Object { continue; } - // Handle an AppIndicator/KStatusNotifierItem item differently. + // Then get a settings identifier for the item. + let itemSettingsId; + // If the role indicates that the item is an + // AppIndicator/KStatusNotifierItem item, then handle it + // differently if (role.startsWith("appindicator-")) { try { - role = this.#handleAppIndicatorItem(indicatorContainer, role); + itemSettingsId = this.#handleAppIndicatorItem(indicatorContainer, role); } catch (e) { if (e.message !== "Application can't be determined.") { throw(e); } continue; } + } else { // Otherwise just use the role as the settings identifier. + itemSettingsId = role; } - // Add the role to the box order, if it isn't in in one already. - if (!boxOrders.left.includes(role) - && !boxOrders.center.includes(role) - && !boxOrders.right.includes(role)) { + // Add the items settings identifier to the box order, if it + // isn't in in one already. + if (!boxOrders.left.includes(itemSettingsId) + && !boxOrders.center.includes(itemSettingsId) + && !boxOrders.right.includes(itemSettingsId)) { if (box === "right") { // Add the items to the beginning for this array, since // its RTL. - boxOrder.unshift(role); + boxOrder.unshift(itemSettingsId); } else { - boxOrder.push(role); + boxOrder.push(itemSettingsId); } } } }; - addNewItemsToBoxOrder(boxIndicatorContainers.left, boxOrders.left, "left"); - addNewItemsToBoxOrder(boxIndicatorContainers.center, boxOrders.center, "center"); - addNewItemsToBoxOrder(boxIndicatorContainers.right, boxOrders.right, "right"); + addNewItemSettingsIdsToBoxOrder(boxIndicatorContainers.left, boxOrders.left, "left"); + addNewItemSettingsIdsToBoxOrder(boxIndicatorContainers.center, boxOrders.center, "center"); + addNewItemSettingsIdsToBoxOrder(boxIndicatorContainers.right, boxOrders.right, "right"); // This function saves the given box order to settings. const saveBoxOrderToSettings = (boxOrder, box) => { From 80f394d2d468def69a8c1c9551275c3742eb5f62 Mon Sep 17 00:00:00 2001 From: June Date: Thu, 26 Sep 2024 02:52:15 +0200 Subject: [PATCH 37/56] refactor: move logic for loading and saving box orders to priv. methods Move logic for loading and saving box orders from/to settings to private methods to have more readable code. --- src/extensionModules/BoxOrderManager.js | 62 +++++++++++++++++-------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/src/extensionModules/BoxOrderManager.js b/src/extensionModules/BoxOrderManager.js index 90ad2a9..5febb5f 100644 --- a/src/extensionModules/BoxOrderManager.js +++ b/src/extensionModules/BoxOrderManager.js @@ -40,6 +40,41 @@ export default class BoxOrderManager extends GObject.Object { this.#settings = settings; } + /** + * Gets a box order for the given top bar box from settings. + * @param {string} box - The top bar box for which to get the box order. + * Must be one of the following values: + * - "left" + * - "center" + * - "right" + * @returns {string[]} - The box order consisting of an array of item + * settings identifiers. + */ + #getBoxOrder(box) { + return this.#settings.get_strv(`${box}-box-order`); + } + + /** + * Save the given box order to settings, making sure to only save a changed + * box order, to avoid loops when listening on settings changes. + * @param {string} box - The top bar box for which to save the box order. + * Must be one of the following values: + * - "left" + * - "center" + * - "right" + * @param {string[]} boxOrder - The box order to save. Must be an array of + * item settings identifiers. + */ + #saveBoxOrder(box, boxOrder) { + const currentBoxOrder = this.#getBoxOrder(box); + + // Only save the given box order to settings, if it is different, to + // avoid loops when listening on settings changes. + if (JSON.stringify(boxOrder) !== JSON.stringify(currentBoxOrder)) { + this.#settings.set_strv(`${box}-box-order`, boxOrder); + } + } + /** * Handles an AppIndicator/KStatusNotifierItem item by deriving a settings * identifier and then associating the role of the given item to the items @@ -108,8 +143,7 @@ export default class BoxOrderManager extends GObject.Object { * @returns {ResolvedBoxOrderItem[]} - The resolved box order. */ #getResolvedBoxOrder(box) { - // Get the box order from settings. - let boxOrder = this.#settings.get_strv(`${box}-box-order`); + let boxOrder = this.#getBoxOrder(box); let resolvedBoxOrder = []; for (const itemSettingsId of boxOrder) { @@ -219,11 +253,11 @@ export default class BoxOrderManager extends GObject.Object { return; } - // Load the configured box orders from settings. + // Get the box orders. const boxOrders = { - left: this.#settings.get_strv("left-box-order"), - center: this.#settings.get_strv("center-box-order"), - right: this.#settings.get_strv("right-box-order"), + left: this.#getBoxOrder("left"), + center: this.#getBoxOrder("center"), + right: this.#getBoxOrder("right"), }; // Get roles (of items) currently present in the GNOME Shell top bar and @@ -292,18 +326,8 @@ export default class BoxOrderManager extends GObject.Object { addNewItemSettingsIdsToBoxOrder(boxIndicatorContainers.center, boxOrders.center, "center"); addNewItemSettingsIdsToBoxOrder(boxIndicatorContainers.right, boxOrders.right, "right"); - // This function saves the given box order to settings. - const saveBoxOrderToSettings = (boxOrder, box) => { - const currentBoxOrder = this.#settings.get_strv(`${box}-box-order`); - // Only save the updated box order to settings, if it is different, - // to avoid loops, when listening on settings changes. - if (JSON.stringify(currentBoxOrder) !== JSON.stringify(boxOrder)) { - this.#settings.set_strv(`${box}-box-order`, boxOrder); - } - }; - - saveBoxOrderToSettings(boxOrders.left, "left"); - saveBoxOrderToSettings(boxOrders.center, "center"); - saveBoxOrderToSettings(boxOrders.right, "right"); + this.#saveBoxOrder("left", boxOrders.left); + this.#saveBoxOrder("center", boxOrders.center); + this.#saveBoxOrder("right", boxOrders.right); } } From f619ce4fa7078d5c3332361e898c9e9767021950 Mon Sep 17 00:00:00 2001 From: June Date: Fri, 27 Sep 2024 03:24:47 +0200 Subject: [PATCH 38/56] feature: make it possible to (forcefully) hide or show top bar items This is only the core extension logic for now, settings UI still needs to follow. The logic only acts on the indicator container, not the indicator itself, meaning that e.g. a screen recording indicator, which is hidden on the indicator level, can be forcefully hidden, but not forcefully shown. Because of that and because forcefully hiding it breaks controls for screen recording, a potential settings implementation should exclude visiblity controls for some elements like e.g. the screen recording indicator. --- ...l.extensions.top-bar-organizer.gschema.xml | 8 +++++ src/extension.js | 30 ++++++++++++------- src/extensionModules/BoxOrderManager.js | 20 ++++++++++++- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/data/org.gnome.shell.extensions.top-bar-organizer.gschema.xml b/data/org.gnome.shell.extensions.top-bar-organizer.gschema.xml index 24e17fe..8b143e7 100644 --- a/data/org.gnome.shell.extensions.top-bar-organizer.gschema.xml +++ b/data/org.gnome.shell.extensions.top-bar-organizer.gschema.xml @@ -13,5 +13,13 @@ Order of items in the right box of the top bar. [] + + Top bar items to (forcefully) hide. + [] + + + Top bar items to (forcefully) show. + [] + diff --git a/src/extension.js b/src/extension.js index 94778e9..353cfe9 100644 --- a/src/extension.js +++ b/src/extension.js @@ -24,17 +24,19 @@ export default class TopBarOrganizerExtension extends Extension { this.#handleNewItemsAndOrderTopBar(); }); - // Handle changes of configured box orders. + // Handle changes of settings. this._settingsHandlerIds = []; - const addConfiguredBoxOrderChangeHandler = (box) => { - let handlerId = this._settings.connect(`changed::${box}-box-order`, () => { + const addSettingsChangeHandler = (settingsName) => { + const handlerId = this._settings.connect(`changed::${settingsName}`, () => { this.#handleNewItemsAndOrderTopBar(); }); this._settingsHandlerIds.push(handlerId); }; - addConfiguredBoxOrderChangeHandler("left"); - addConfiguredBoxOrderChangeHandler("center"); - addConfiguredBoxOrderChangeHandler("right"); + addSettingsChangeHandler("left-box-order"); + addSettingsChangeHandler("center-box-order"); + addSettingsChangeHandler("right-box-order"); + addSettingsChangeHandler("hide"); + addSettingsChangeHandler("show"); } disable() { @@ -115,9 +117,9 @@ export default class TopBarOrganizerExtension extends Extension { /// Go through the items of the validBoxOrder and order the GNOME Shell /// top bar box accordingly. for (let i = 0; i < validBoxOrder.length; i++) { - const role = validBoxOrder[i].role; + const item = validBoxOrder[i]; // Get the indicator container associated with the current role. - const associatedIndicatorContainer = Main.panel.statusArea[role].container; + const associatedIndicatorContainer = Main.panel.statusArea[item.role].container; // Save whether or not the indicator container is visible. const isVisible = associatedIndicatorContainer.visible; @@ -141,8 +143,16 @@ export default class TopBarOrganizerExtension extends Extension { panelBox.insert_child_at_index(associatedIndicatorContainer, i); } - // Hide the indicator container again, if it wasn't visible. - if (!isVisible) { + // Hide the indicator container... + // - ...if it wasn't visible before and the hide property of the + // item is "default". + // - if the hide property of the item is "hide". + // In all other cases have the item show. + // An e.g. screen recording indicator still wouldn't show tho, since + // this here acts on the indicator container, but a screen recording + // indicator is hidden on the indicator level. + if ((!isVisible && item.hide === "default") || + item.hide === "hide") { associatedIndicatorContainer.hide(); } } diff --git a/src/extensionModules/BoxOrderManager.js b/src/extensionModules/BoxOrderManager.js index 5febb5f..bb27391 100644 --- a/src/extensionModules/BoxOrderManager.js +++ b/src/extensionModules/BoxOrderManager.js @@ -5,10 +5,13 @@ import GObject from "gi://GObject"; import * as Main from "resource:///org/gnome/shell/ui/main.js"; /** - * A resolved box order item containing the items role and settings identifier. + * A resolved box order item containing the items role, settings identifier and + * additional information. * @typedef {Object} ResolvedBoxOrderItem * @property {string} settingsId - The settings identifier of the item. * @property {string} role - The role of the item. + * @property {string} hide - Whether the item should be (forcefully) hidden + * (hide), shown (show) or just be left as is (default). */ /** @@ -135,6 +138,7 @@ export default class BoxOrderManager extends GObject.Object { * Gets a resolved box order for the given top bar box, where all * AppIndicator items got resolved using their roles, meaning they might be * present multiple times or not at all depending on the roles stored. + * The items of the box order also have additional information stored. * @param {string} box - The top bar box for which to get the resolved box order. * Must be one of the following values: * - "left" @@ -145,13 +149,26 @@ export default class BoxOrderManager extends GObject.Object { #getResolvedBoxOrder(box) { let boxOrder = this.#getBoxOrder(box); + const itemsToHide = this.#settings.get_strv("hide"); + const itemsToShow = this.#settings.get_strv("show"); + let resolvedBoxOrder = []; for (const itemSettingsId of boxOrder) { const resolvedBoxOrderItem = { settingsId: itemSettingsId, role: "", + hide: "", }; + // Set the hide state of the item. + if (itemsToHide.includes(resolvedBoxOrderItem.settingsId)) { + resolvedBoxOrderItem.hide = "hide"; + } else if (itemsToShow.includes(resolvedBoxOrderItem.settingsId)) { + resolvedBoxOrderItem.hide = "show"; + } else { + resolvedBoxOrderItem.hide = "default"; + } + // If the items settings identifier doesn't indicate that the item // is an AppIndicator/KStatusNotifierItem item, then its identifier // is the role and it can just be added to the resolved box order. @@ -202,6 +219,7 @@ export default class BoxOrderManager extends GObject.Object { * Gets a valid box order for the given top bar box, where all AppIndicator * items got resolved and where only items are included, which are in some * GNOME Shell top bar box. + * The items of the box order also have additional information stored. * @param {string} box - The top bar box to return the valid box order for. * Must be one of the following values: * - "left" From 57e7fc51ea2ac0ab65829cc95166dce29573e28d Mon Sep 17 00:00:00 2001 From: June Date: Sun, 8 Jun 2025 20:57:58 +0200 Subject: [PATCH 39/56] docs: add newer, cut down and commented panel.js from GNOME Shell 48.2 --- docs/panel_48.2_2025-06-08.js | 322 ++++++++++++++++++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100644 docs/panel_48.2_2025-06-08.js diff --git a/docs/panel_48.2_2025-06-08.js b/docs/panel_48.2_2025-06-08.js new file mode 100644 index 0000000..7becfb8 --- /dev/null +++ b/docs/panel_48.2_2025-06-08.js @@ -0,0 +1,322 @@ +// My annotated and cut down js/ui/panel.js from gnome-shell/48.2. +// All annotations are what I guessed, interpreted and copied while reading the +// code and comparing to other panel.js versions and might be wrong. They are +// prefixed with "Annotation:" to indicate that they're my comments, not +// comments that orginally existed. + +// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/48.2/js/ui/panel.js +// On: 2025-06-08 +// License: This code is licensed under GPLv2. + +// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/48.2/js/ui/sessionMode.js +// On: 2025-06-08 +// License: This code is licensed under GPLv2. + +// I'm using the word "item" to refer to the thing, which gets added to the top +// (menu)bar / panel, where an item has a role/name and an indicator. + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import Clutter from 'gi://Clutter'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import GObject from 'gi://GObject'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import St from 'gi://St'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import * as CtrlAltTab from './ctrlAltTab.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import * as PopupMenu from './popupMenu.js'; +import * as PanelMenu from './panelMenu.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import * as Main from './main.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +import {DateMenuButton} from './dateMenu.js'; +import {ATIndicator} from './status/accessibility.js'; +import {InputSourceIndicator} from './status/keyboard.js'; +import {DwellClickIndicator} from './status/dwellClick.js'; +import {ScreenRecordingIndicator, ScreenSharingIndicator} from './status/remoteAccess.js'; + +// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this +// Extension. + +// Of note (for PANEL_ITEM_IMPLEMENTATIONS): +// const AppMenuButton = [...] +// const ActivitiesButton = [...] +// const QuickSettings = [...] + +const PANEL_ITEM_IMPLEMENTATIONS = { + 'activities': ActivitiesButton, + 'appMenu': AppMenuButton, + 'quickSettings': QuickSettings, + 'dateMenu': DateMenuButton, + 'a11y': ATIndicator, + 'keyboard': InputSourceIndicator, + 'dwellClick': DwellClickIndicator, + 'screenRecording': ScreenRecordingIndicator, + 'screenSharing': ScreenSharingIndicator, +}; + +export const Panel = GObject.registerClass( +class Panel extends St.Widget { + // Annotation: Initializes the top (menu)bar / panel. + // Does relevant stuff like: + // - Defining this._leftBox, this._centerBox and this._rightBox. + // - Finally calling this._updatePanel(). + // Compared to panel_47.rc_2024-09-12.js: connectObject instead of connect + // gets used, which shouldn't be relevant for this extension. + _init() { + super._init({ + name: 'panel', + reactive: true, + }); + + this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); + + this._sessionStyle = null; + + this.statusArea = {}; + + this.menuManager = new PopupMenu.PopupMenuManager(this); + + this._leftBox = new St.BoxLayout({name: 'panelLeft'}); + this.add_child(this._leftBox); + this._centerBox = new St.BoxLayout({name: 'panelCenter'}); + this.add_child(this._centerBox); + this._rightBox = new St.BoxLayout({name: 'panelRight'}); + this.add_child(this._rightBox); + + this.connect('button-press-event', this._onButtonPress.bind(this)); + this.connect('touch-event', this._onTouchEvent.bind(this)); + + Main.overview.connectObject('showing', + () => this.add_style_pseudo_class('overview'), + this); + Main.overview.connectObject('hiding', + () => this.remove_style_pseudo_class('overview'), + this); + + Main.layoutManager.panelBox.add_child(this); + Main.ctrlAltTabManager.addGroup(this, + _('Top Bar'), 'shell-focus-top-bar-symbolic', + {sortGroup: CtrlAltTab.SortGroup.TOP}); + + Main.sessionMode.connectObject('updated', + this._updatePanel.bind(this), + this); + + global.display.connectObject('workareas-changed', + () => this.queue_relayout(), + this); + this._updatePanel(); + } + + // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for + // this Extension. + + // Annotation: Gets called by this._init() to populate the top (menu)bar / + // panel initially. + // + // It does the following relevant stuff: + // - Calls this._hideIndicators() + // - Calls this._updateBox() for this._leftBox, this._centerBox and + // this._rightBox with panel.left, panel.center and panel.right to + // populate the boxes with items defined in panel.left, panel.center and + // panel.right. + // + // panel.left, panel.center and panel.right get set via the line let panel + // = Main.sessionMode.panel, which uses the panel of Mains (js/ui/main.js) + // instance of SessionMode (js/ui/sessionMode.js). + // + // And in js/ui/sessionMode.js (48.2, 2025-06-08) you have different modes + // with different panel configuration. For example the "user" mode with: + // panel: { + // left: ['activities'], + // center: ['dateMenu'], + // right: ['screenRecording', 'screenSharing', 'dwellClick', 'a11y', 'keyboard', 'quickSettings'], + // } + // + // This way this function populates the top (menu)bar / panel with the + // default stuff you see on a fresh Gnome. + // + // Compared to panel_47.rc_2024-09-12.js: Nothing changed. + _updatePanel() { + let panel = Main.sessionMode.panel; + this._hideIndicators(); + this._updateBox(panel.left, this._leftBox); + this._updateBox(panel.center, this._centerBox); + this._updateBox(panel.right, this._rightBox); + + if (panel.left.includes('dateMenu')) + Main.messageTray.bannerAlignment = Clutter.ActorAlign.START; + else if (panel.right.includes('dateMenu')) + Main.messageTray.bannerAlignment = Clutter.ActorAlign.END; + // Default to center if there is no dateMenu + else + Main.messageTray.bannerAlignment = Clutter.ActorAlign.CENTER; + + if (this._sessionStyle) + this.remove_style_class_name(this._sessionStyle); + + this._sessionStyle = Main.sessionMode.panelStyle; + if (this._sessionStyle) + this.add_style_class_name(this._sessionStyle); + } + + // Annotation: This function hides all items, which are in the top (menu)bar + // panel and in PANEL_ITEM_IMPLEMENTATIONS. + // + // Compared to panel_47.rc_2024-09-12.js: Nothing changed. + _hideIndicators() { + for (let role in PANEL_ITEM_IMPLEMENTATIONS) { + let indicator = this.statusArea[role]; + if (!indicator) + continue; + indicator.container.hide(); + } + } + + // Annotation: This function takes a role (of an item) and returns a + // corresponding indicator, if either of two things are true: + // - The indicator is already in this.statusArea. + // Then it just returns the indicator by using this.statusArea. + // - The role is in PANEL_ITEM_IMPLEMENTATIONS. + // Then it creates a new indicator, adds it to this.statusArea and returns + // it. + // + // Compared to panel_47.rc_2024-09-12.js: Nothing changed. + _ensureIndicator(role) { + let indicator = this.statusArea[role]; + if (!indicator) { + let constructor = PANEL_ITEM_IMPLEMENTATIONS[role]; + if (!constructor) { + // This icon is not implemented (this is a bug) + return null; + } + indicator = new constructor(this); + this.statusArea[role] = indicator; + } + return indicator; + } + + // Annotation: This function takes a list of items (or rather their roles) + // and adds the indicators of those items to a box (like this._leftBox) + // using this._ensureIndicator() to get the indicator corresponding to the + // given role. + // So only items with roles this._ensureIndicator() knows, get added. + // + // Compared to panel_47.rc_2024-09-12.js: Nothing changed. + _updateBox(elements, box) { + let nChildren = box.get_n_children(); + + for (let i = 0; i < elements.length; i++) { + let role = elements[i]; + let indicator = this._ensureIndicator(role); + if (indicator == null) + continue; + + this._addToPanelBox(role, indicator, i + nChildren, box); + } + } + + // Annotation: This function adds the given item to the specified top + // (menu)bar / panel box and connects to "destroy" and "menu-set" events. + // + // It takes the following arguments: + // - role: The name of the item to add. + // - indicator: The indicator of the item to add. + // - position: Where in the box to add the item. + // - box: The box to add the item to. + // Can be one of the following: + // - this._leftBox + // - this._centerBox + // - this._rightBox + // + // Compared to panel_47.rc_2024-09-12.js: Nothing changed. + _addToPanelBox(role, indicator, position, box) { + let container = indicator.container; + container.show(); + + let parent = container.get_parent(); + if (parent) + parent.remove_child(container); + + + box.insert_child_at_index(container, position); + this.statusArea[role] = indicator; + let destroyId = indicator.connect('destroy', emitter => { + delete this.statusArea[role]; + emitter.disconnect(destroyId); + }); + indicator.connect('menu-set', this._onMenuSet.bind(this)); + this._onMenuSet(indicator); + } + + // Annotation: This function allows you to add an item to the top (menu)bar + // / panel. + // While per default it adds the item to the status area (the right box of + // the top bar), you can specify the box and add the item to any of the + // three boxes of the top bar. + // To add an item to the top bar, you need to give its role and indicator. + // + // This function takes the following arguments: + // - role: A name for the item to add. + // - indicator: The indicator for the item to add (must be an instance of + // PanelMenu.Button). + // - position: Where in the box to add the item. + // - box: The box to add the item to. + // Can be one of the following: + // - "left": referring to this._leftBox + // - "center": referring to this._centerBox + // - "right": referring to this._rightBox + // These boxes are what you see in the top bar as the left, right and + // center sections. + // + // Finally this function just calls this._addToPanelBox() for the actual + // work, so it basically just makes sure the input to this._addToPanelBox() + // is correct. + // + // Compared to panel_47.rc_2024-09-12.js: Nothing changed. + addToStatusArea(role, indicator, position, box) { + if (this.statusArea[role]) + throw new Error(`Extension point conflict: there is already a status indicator for role ${role}`); + + if (!(indicator instanceof PanelMenu.Button)) + throw new TypeError('Status indicator must be an instance of PanelMenu.Button'); + + position ??= 0; + let boxes = { + left: this._leftBox, + center: this._centerBox, + right: this._rightBox, + }; + let boxContainer = boxes[box] || this._rightBox; + this.statusArea[role] = indicator; + this._addToPanelBox(role, indicator, position, boxContainer); + return indicator; + } + + // Of note: + // _onMenuSet(indicator) { [...] } + + // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for + // this Extension. +}); From 9c847c0988108bf61256ab61fc920f70ad6c174d Mon Sep 17 00:00:00 2001 From: June Date: Mon, 9 Jun 2025 00:22:48 +0200 Subject: [PATCH 40/56] feature: support GNOME Shell version 48 Checked the source of 48.2 and tested in Fedora 42 and there don't seem to be any changes relevant to the functionality of this extension. --- src/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metadata.json b/src/metadata.json index e7a2fbf..81e132c 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -3,7 +3,7 @@ "name": "Top Bar Organizer", "description": "Organize the items of the top (menu)bar.", "version": 12, - "shell-version": [ "45", "46", "47" ], + "shell-version": [ "45", "46", "47", "48" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", "url": "https://gitlab.gnome.org/june/top-bar-organizer" } From b17a805035aa860f7b00a998a9b196d7e1ab895e Mon Sep 17 00:00:00 2001 From: June Date: Mon, 9 Jun 2025 00:24:02 +0200 Subject: [PATCH 41/56] other: bump version to 13 --- src/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metadata.json b/src/metadata.json index 81e132c..a12d4c0 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -2,7 +2,7 @@ "uuid": "top-bar-organizer@julian.gse.jsts.xyz", "name": "Top Bar Organizer", "description": "Organize the items of the top (menu)bar.", - "version": 12, + "version": 13, "shell-version": [ "45", "46", "47", "48" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", "url": "https://gitlab.gnome.org/june/top-bar-organizer" From a58ddc6146d082e95e366f58b7a796db480250a5 Mon Sep 17 00:00:00 2001 From: June Date: Mon, 9 Jun 2025 18:33:10 +0200 Subject: [PATCH 42/56] other: add GNOME 48.2 panel source code file to .eslintignore --- .eslintignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintignore b/.eslintignore index 2b884b5..524273b 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,3 +4,4 @@ /docs/panel_45.0_2023-09-26.js /docs/panel_46.4_2024-09-11.js /docs/panel_47.rc_2024-09-12.js +/docs/panel_48.2_2025-06-08.js From 185a48c857aeadaca70bd66a80180459f821ac9c Mon Sep 17 00:00:00 2001 From: June Date: Mon, 9 Jun 2025 19:53:12 +0200 Subject: [PATCH 43/56] fix: use row title to make settings window not break for long item names Use the title of the PrefsBoxOrderItemRow (AdwActionRow) for the item name instead of a label in the prefix. Aside from generally being more correct, item names now wrap correctly, avoiding the settings window breaking (being cut off by default to the right with even the close button not showing, until resizing) with long item names. --- data/ui/prefs-box-order-item-row.ui | 6 ------ src/prefsModules/PrefsBoxOrderItemRow.js | 11 ++++------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/data/ui/prefs-box-order-item-row.ui b/data/ui/prefs-box-order-item-row.ui index 239ac55..0debab6 100644 --- a/data/ui/prefs-box-order-item-row.ui +++ b/data/ui/prefs-box-order-item-row.ui @@ -1,12 +1,6 @@