mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-27 13:37:48 -04:00
commit f9bcdfdce1ab4a028cd9ccc08bc5fc6748e2d9e8 Author: bbedward <[email protected]> Date: Thu Sep 17 16:37:31 2026 -0400 wallpaper: regenerate colors when the active light/dark wallpaper changes commit 0b2dd37971a7b360f26b1a302297335963282313 Author: bbedward <[email protected]> Date: Thu Sep 17 16:16:03 2026 -0400 lyrics: keep the active line in place when rows above resize, remember the lyrics view commit db56722c7af9cb50a9c779a39e12a54dc5a607a6 Author: bbedward <[email protected]> Date: Thu Sep 17 16:04:33 2026 -0400 lyrics: emphasize vocals per part instead of per group commit 934e0676d9d63f6a7cb314c693ac256c1b56e057 Author: bbedward <[email protected]> Date: Thu Sep 17 15:59:56 2026 -0400 lyrics: drop focus from overlapping lines when their vocals end commit 3fe092446b1f27d7acc1a0a2a2ecc5d19f455275 Author: bbedward <[email protected]> Date: Thu Sep 17 15:17:28 2026 -0400 media: add lyrics attribution, unison provider, shrink album art slightly when its low res commit f54b3e2c1dc589451f449218d4985758b88757b4 Author: bbedward <[email protected]> Date: Thu Sep 17 14:35:52 2026 -0400 media/zurvan: style changes commit 9ea5aecfba4c638e2f08ab288706d2fb3143ea0b Author: bbedward <[email protected]> Date: Thu Sep 17 14:02:03 2026 -0400 rebase fixes commit b2b04d12d2e9118346d0e5950b348aa222d58e50 Author: bbedward <[email protected]> Date: Thu Sep 17 13:46:03 2026 -0400 i18n: overhaul battery popout: redesign clipboard: fix style of pinned button and remove number sidebar commit 3057940bb28a29de22f90f5630a2c68113707d16 Author: bbedward <[email protected]> Date: Thu Sep 17 11:48:16 2026 -0400 displayconfig: show valid fractional scales only, fix custom setter commit 2bbe9e4b4c4278d1aca8632d650feba912a1c0af Author: bbedward <[email protected]> Date: Thu Sep 17 10:47:43 2026 -0400 media/zurvan: restyle commit 33299ef45261c4f0a7e8e663c1ed2f0996e3ac78 Author: purian23 <[email protected]> Date: Thu Sep 17 02:50:08 2026 -0400 refactor(clipboard): add click to open image previews & misc adjustments commit 9809aad3c466bf4974b887a37a806039e58b47ed Author: purian23 <[email protected]> Date: Thu Sep 17 02:35:20 2026 -0400 add(media): dynamic sizing - tests: start the fixture bus with dbus-broker or dbus-daemon commit 75a20eeb5a1299af1b0dd0d99cb374b4c5c8f15f Author: purian23 <[email protected]> Date: Thu Sep 17 00:30:04 2026 -0400 fix(dash): position bar-triggered popout once commit 1536691beb0bf2cd58fa3e1b2106eeeb9317a39c Author: purian23 <[email protected]> Date: Wed Sep 16 23:58:50 2026 -0400 dash & cc: operation freedom commit f3a2ae13bffbbdb92134af23138dc9a253f69e09 Author: bbedward <[email protected]> Date: Wed Sep 16 23:12:58 2026 -0400 lyrics: keep track identity independent of mpris length commit a59dd84908486f23e07172a6fca4c76eed27d31f Author: bbedward <[email protected]> Date: Wed Sep 16 22:41:44 2026 -0400 more zurvan changes commit fda890225576e6fc740946486c5c05cdc58ebd77 Author: bbedward <[email protected]> Date: Wed Sep 16 22:10:55 2026 -0400 media: more style changes commit 2170f055e3700466f87c0f6a072cb67e5e610574 Author: bbedward <[email protected]> Date: Wed Sep 16 20:00:36 2026 -0400 zurvan style tweaks commit 10795b2f2c41fcd1c24f5625324ff0ea7dd3e4ae Author: bbedward <[email protected]> Date: Wed Sep 16 18:32:48 2026 -0400 media: adjust styling of zurvan player commit 363eb10f7f53681d8f36fc6e9648205c9d5879d2 Author: bbedward <[email protected]> Date: Wed Sep 16 17:30:05 2026 -0400 lyrics: dont classify 401s as failures commit 0267c7110e14285fe4a611dbc78aee93e77e6ec8 Author: bbedward <[email protected]> Date: Wed Sep 16 17:07:34 2026 -0400 media: create the dank lyrics engine with multiple providers and priority support media: add zurvan style player and make it default commit 0aae835377cc96c5ec8383650df914058f604a42 Author: bbedward <[email protected]> Date: Wed Sep 16 10:22:36 2026 -0400 remove dumb test commit 8610121b1cb20b4b4b557170b7df52af39f4efff Author: bbedward <[email protected]> Date: Wed Sep 16 10:16:00 2026 -0400 notifications: redesign card header commit 868b73740a575d51577fa3aaff5abc1ccd53043c Author: bbedward <[email protected]> Date: Wed Sep 16 09:24:13 2026 -0400 clipboard: tweak image preview style commit 6de9a1ba7c306269889227b892703dc822049ac9 Author: purian23 <[email protected]> Date: Tue Sep 15 22:52:40 2026 -0400 clipboard: new size variants & image previews commit 05909190a2fb93a3a2c68fc711c07c3ffc09a529 Author: bbedward <[email protected]> Date: Tue Sep 15 19:14:41 2026 -0400 qs: drop the delegates the layout and output migrations left behind commit 6ca48caf7c2141e7e5f55a7d4634e0803a90c6b9 Author: bbedward <[email protected]> Date: Tue Sep 15 19:03:03 2026 -0400 config: one implementation of the compositor fragment mechanics commit 9f024c001e0c661a19c35b92bb36a6a9758f9d4d Author: bbedward <[email protected]> Date: Tue Sep 15 18:34:03 2026 -0400 compositor: name capabilities instead of checking identity in the ui commit 90067f14ed38e0cbf919e35cbf333f62240bc585 Author: bbedward <[email protected]> Date: Tue Sep 15 18:19:57 2026 -0400 settings: read every default from the spec commit 7f7ae95ed3093c5df7cb4bf5d23b718497a769ff Author: bbedward <[email protected]> Date: Tue Sep 15 15:47:13 2026 -0400 notifications: watch screen sharing from the service side commit a470ed448cbddb849922e80afdd2b13eb85f08f9 Author: bbedward <[email protected]> Date: Tue Sep 15 15:15:38 2026 -0400 rebase fix commit dc8f05fa0ca4650a40e32fb59614ca1b7df75f38 Author: bbedward <[email protected]> Date: Tue Sep 15 10:57:38 2026 -0400 dash: keep cards still when edit mode opens commit bc2001359613fd9b47ba0000a8f8f081d412a166 Author: bbedward <[email protected]> Date: Tue Sep 15 10:16:48 2026 -0400 settings: own the full spec again and merge the shared greeter keys settings: drop sidebar hints that repeat their own label cc/dash: change edit interface design slightly commit ee963f54b259eced7ec23701194539441b264db0 Author: purian23 <[email protected]> Date: Mon Sep 14 23:43:56 2026 -0400 settings: update island notification handling to use bar context commit 4d6f9fde4401001625f0352f97821ce5034a7e1c Author: bbedward <[email protected]> Date: Mon Sep 14 23:21:28 2026 -0400 greeter: read the shared settings schema instead of a duplicated one commit 70e4bdaec84efa3d68438ef235e46762cee38101 Author: bbedward <[email protected]> Date: Mon Sep 14 22:42:31 2026 -0400 osd, toast, launcher: start open motion after onFrameSwapped signal commit ddfd28b7be6dd4b0940512897d835107dbab1f23 Author: bbedward <[email protected]> Date: Mon Sep 14 21:12:37 2026 -0400 notifications: wait for onFrameSwapped signal before showing notification popup Lets the layer-surface map before rendering the body, resulting in better animation appearance commit 24efe6f8a18b36bb42c6b399086ffa5c5e2aa9c5 Author: purian23 <[email protected]> Date: Mon Sep 14 18:55:46 2026 -0400 notifications: adjust animation durations - Mapped the layer-shell surface - Fixed group chevron/dismiss button commit 52389ecf5cc586e912c26a345004814e37f4048a Author: bbedward <[email protected]> Date: Mon Sep 14 18:10:33 2026 -0400 dash: spacing tweak of tabbart commit 0285a70c1b07d09558c450c1eeb925a5c903069f Author: bbedward <[email protected]> Date: Mon Sep 14 17:55:43 2026 -0400 blah commit a1abc7a8df94032b01b51189b214aa21543f7218 Author: bbedward <[email protected]> Date: Mon Sep 14 17:40:10 2026 -0400 shrink window CSD height commit db20f7e9bb93c7dce503e410e82e15e7a03b1e7d Author: bbedward <[email protected]> Date: Mon Sep 14 17:16:16 2026 -0400 windows: center titles commit 7268712bdf58c5c1903606f24a392d64655a4ad5 Author: purian23 <[email protected]> Date: Mon Sep 14 16:45:44 2026 -0400 notifications: updated entry/exit paths - Added popout option in island mode - Fixed cards getting stuck & out of place when multiples arise at once commit 3a3f0b3061bd0a7ce895152ec5a056600e41e7e8 Author: bbedward <[email protected]> Date: Mon Sep 14 16:34:36 2026 -0400 battery: make cc variant consistent commit ee569ddef3bf2875d42347d18b57f493f492b243 Author: bbedward <[email protected]> Date: Mon Sep 14 16:15:42 2026 -0400 battery: remove bottom text footer thing commit 817c4e46eac52c95d91f418e3ddbafdab0888b5c Author: purian23 <[email protected]> Date: Mon Sep 14 15:34:18 2026 -0400 settings: rework interface style and bar hub layouts - Separate global surface styling from per-surface overrides on Interface style - Move bar management into the hub header and render island settings inline - Cut redirect banners down to one per page and point them at the right row commit 03a4e45d65aec83c927c7419a4a0f3f252e0e955 Author: bbedward <[email protected]> Date: Mon Sep 14 14:52:20 2026 -0400 launcher: fix inconsistency in niri overview variant commit e74246d058a5db215200606eb9f9c662706d8689 Author: bbedward <[email protected]> Date: Mon Sep 14 14:21:10 2026 -0400 plugins: eval symlinks in repo lookup commit 7dd2cddebf4819da51ff7da792560372f5d9a03e Author: bbedward <[email protected]> Date: Mon Sep 14 09:09:46 2026 -0400 update common commit a8c1f77fe2d952b1ec33e622b2951e5382860c9e Author: purian23 <[email protected]> Date: Mon Sep 14 02:05:09 2026 -0400 island: fix search input focus on launcher commit 2d1f8bf5338ca5e0a4a58f0f18b54b92dfe5e5ee Author: purian23 <[email protected]> Date: Mon Sep 14 01:29:05 2026 -0400 tooltips: add further label & accessibility parity commit 3ebfe85d57553b4803b52d5e5ea417b8abec5bcf Author: bbedward <[email protected]> Date: Sun Sep 13 23:28:29 2026 -0400 ui: drop tooltips from obvious icon buttons, keep labels on Accessible.name commit a8e7a072b2bad394c5c5d9fd60eaff5240ce37d4 Author: bbedward <[email protected]> Date: Sun Sep 13 22:55:28 2026 -0400 widgets: dim filled action buttons when disabled commit 0dc58825344ebfc5479d2a3bc75b5d2ae014131a Author: bbedward <[email protected]> Date: Sun Sep 13 22:45:34 2026 -0400 settings: one compositor include workflow for outputs, layout, input, window rules, cursor and binds commit 9fc8c8e53c18de18b33ccdfe1e1abed84e01b219 Author: purian23 <[email protected]> Date: Sun Sep 13 22:27:28 2026 -0400 theme: add focus ring settings & replace text fields w/search fields aligned to m3e specs commit 8359fea68230172b1c10df08831efdf944fbbd64 Author: bbedward <[email protected]> Date: Sun Sep 13 20:37:49 2026 -0400 auth: share one pam stack parser between the greeter, lock probe and polkit commit bf05136e78aada16e41a7d0b7164a7f543d65760 Author: bbedward <[email protected]> Date: Sun Sep 13 20:24:01 2026 -0400 tests: replace golden files and dump-only fixtures with hand-written assertions commit f2cd6a877b561a5078e7b6cbad8348e9165158ca Author: bbedward <[email protected]> Date: Sun Sep 13 19:15:02 2026 -0400 display: split DisplayService into brightness, night mode and refresh rate services commit fa7ce5fe836e4f00646c80eb3cb50ecc004f4524 Author: bbedward <[email protected]> Date: Sun Sep 13 18:19:26 2026 -0400 battery: m3e redesign commit 04576106158c009374d9564d18852cf7ea1f9284 Author: bbedward <[email protected]> Date: Sun Sep 13 17:21:32 2026 -0400 shell: one window model and one keyboard layout source hosts: put change handlers on the observed object instead of proxy properties commit e4750c767b27d4650b95d42930410ad090d6ca87 Author: bbedward <[email protected]> Date: Sun Sep 13 15:39:10 2026 -0400 shell: replace connections with bound property handlers in per-item and per-screen components commit 8efb05dc014f0d09b36d6112b03e6f4e1f60d1d2 Author: bbedward <[email protected]> Date: Sun Sep 13 13:43:10 2026 -0400 display config: move output parsing, identifiers and geometry into a pure model commit e9b8174812b2da316eeae42e3989f2f269ef5649 Author: bbedward <[email protected]> Date: Sun Sep 13 12:52:46 2026 -0400 slideout: build content on first open commit b899f307650cf5cc646de90ac666b6e1731bbc4f Author: bbedward <[email protected]> Date: Sun Sep 13 12:28:11 2026 -0400 services: stop using weakmap for workspace, window and term caches commit b90e9a4c2a72744685f79cf613ab80660721389f Author: bbedward <[email protected]> Date: Sun Sep 13 10:35:48 2026 -0400 workspaces: one model with per-compositor adapters, no compositor branches in widgets shell: stop hot reload while the session lock is held commit e200e17e96e06b4fd7e0dd596b50dcbbc254494a Author: purian23 <[email protected]> Date: Sun Sep 13 02:36:41 2026 -0400 dock: mix widgets between pinned apps - Pinned apps become individual units in edit mode with a saved per-dock order, while running windows stay one unit in compositor order. - Fix the Window.window Connections crash - Add right-click-to-edit empty dock space option and dock edit / editFor ipc commands commit cad3ba78727695419a4fe8a96c90146bbf5e6120 Author: bbedward <[email protected]> Date: Sun Sep 13 00:51:35 2026 -0400 launcher: create plugin instances only when a query needs them commit aed25c3c75d0c24a17a940c162a6956a372c4e0f Author: bbedward <[email protected]> Date: Sat Sep 12 23:45:19 2026 -0400 settings: rebuild about, printer, wifi, display and window rules pages on settings blocks popouts: drop inconsistent headers commit 3a20c2c9528fe1fed3464085492af3bebdcdf809 Author: bbedward <[email protected]> Date: Sat Sep 12 17:41:18 2026 -0400 launcher: consolidate host code and logic commit 4e53b470d5beaffa54687c8164e492ee41472e49 Author: bbedward <[email protected]> Date: Sat Sep 12 15:37:44 2026 -0400 surfaces: collapse connected/standalone popout and modal hosts typography: make font weight work and follow m3 weights settings: fix reset to default shifting rows commit ce71b5dc3ca0e96ee11b906b1ea3399d3d7d93ac Author: bbedward <[email protected]> Date: Sat Sep 12 15:02:25 2026 -0400 dock: move widgets, launcher, apps and trash as units in edit mode commit 6ebaef52d885744a45f3db7d48c3b6d0924993b2 Author: bbedward <[email protected]> Date: Sat Sep 12 13:24:31 2026 -0400 plugins: add examples for dash and dock commit 067cabc95991f5676a19746d3cad0700eb525082 Author: bbedward <[email protected]> Date: Sat Sep 12 12:25:59 2026 -0400 settings: fix v18 migration commit 55d07f3bba352972c768acdd7b6705f80fac4e0f Author: bbedward <[email protected]> Date: Sat Sep 12 12:09:56 2026 -0400 ci: fix fails commit 2e81531dd6980f0331af80fe5beca1d695c58f06 Author: bbedward <[email protected]> Date: Sat Sep 12 11:49:39 2026 -0400 surfaces: add windowRadius token to make surfaces actually follow settings and match the compositor windows surfaces: change default radius (Strength 50) from 12->16 settings: add result to default for everything settings: further re-organization and re-structuring position of things settings: remove dead keys dock: remove hardcoded border and respect border setting bar: add a third style and color options ci: hookup QML testing commit a2fd8abd37e0ff1ef67af9bfa4e7679e7aa338bd Author: bbedward <[email protected]> Date: Sat Sep 12 09:20:00 2026 -0400 dash: size surface width to the width of the largest tab commit 93394549a2cb3f7647b564ba71621e113c83e106 Author: bbedward <[email protected]> Date: Sat Sep 12 00:11:15 2026 -0400 bar/workspaces: restore old style, respect color choices, make pills default > segments commit 71f8351a3b11f8d06e45dd28db4d501e54a27f9a Author: purian23 <[email protected]> Date: Fri Sep 11 23:48:04 2026 -0400 dbar: initial M3E remaster pass on shared chrome w/dock & island commit 1711716073f660afd519ab0af88d3c8177f1a8c8 Author: bbedward <[email protected]> Date: Fri Sep 11 21:44:31 2026 -0400 dash: only show focus ring when KB navigating commit 6037de06471e7fa80ec36088e9e86cbf2e4d3941 Author: bbedward <[email protected]> Date: Fri Sep 11 21:41:53 2026 -0400 launcher: scope plugin and clipboard refreshes, paint the keystroke before plugin search commit 78c9ab990b7665e76762dadd65d1a1d23275a405 Author: bbedward <[email protected]> Date: Fri Sep 11 21:16:36 2026 -0400 launcher: one open-session reset, faster keystroke settle commit 01b15051363715bfb2bfe1d905b4b573fb4e49ac Author: bbedward <[email protected]> Date: Fri Sep 11 20:47:45 2026 -0400 dash: fix kb navigation on overview commit 27465074e1fa395a844cc3b804a362ee7a4e4f70 Author: bbedward <[email protected]> Date: Fri Sep 11 16:58:53 2026 -0400 dash: replace material shapes on resource cards with a ring gauge commit 5e41b85a1df69885c57a41ab44a43ef38b0c5560 Author: bbedward <[email protected]> Date: Fri Sep 11 16:33:48 2026 -0400 qml: share bases for registry browsers, fade windows and plugin list settings Fixes fade window focus, list setting load write-back and the missing Theme.onError commit be3542ab8fc1949a256d6498b5c4a0379b86e023 Author: bbedward <[email protected]> Date: Fri Sep 11 16:11:15 2026 -0400 popout: fix pixel jumps commit 2ad0e9e2f5b12f13f0acc9733c29c4c42d640df7 Author: bbedward <[email protected]> Date: Fri Sep 11 15:52:52 2026 -0400 popout: fade the surface fill with the content commit 4b11e21b1a09895f67ca1b6b858fe772500e4a2c Author: bbedward <[email protected]> Date: Fri Sep 11 15:13:14 2026 -0400 desktop widgets: read and write saved geometry through one path commit 21ed01bbb20627d4d68bbb704b9f2bb50b45c911 Author: bbedward <[email protected]> Date: Fri Sep 11 15:10:02 2026 -0400 surfaces: bind modal and popout backends to their handle commit 362859d810b768621061f0429c39b17ff3b00184 Author: bbedward <[email protected]> Date: Fri Sep 11 14:30:27 2026 -0400 notifications: move the popup context menu onto DankContextMenu commit 8942b622f5929e854fbcf145e7f34f4637904731 Author: bbedward <[email protected]> Date: Fri Sep 11 14:20:49 2026 -0400 colorpicker: design changes consolidate context menus commit 29be554d488aefd9a8f6e4e5f5d094147e3b214d Author: bbedward <[email protected]> Date: Fri Sep 11 12:48:02 2026 -0400 dash: add analog clock option commit 43748726983a466e19e4b642399ea040d4095de9 Author: bbedward <[email protected]> Date: Fri Sep 11 12:12:51 2026 -0400 popouts: fix spacing inconsistencies dash: redesign overview media card osd: more redesign dash/overview: remove row cap and make it dynamic commit 14a3a315d94336cac6e8eb77e08965503717d780 Author: bbedward <[email protected]> Date: Fri Sep 11 09:23:53 2026 -0400 shell: dedupe bar ipc handlers, weather resets, color options, launcher icons commit 9f2b6d4bbe6f5954a33b5853ecea0ef0ac4b483e Author: purian23 <[email protected]> Date: Thu Sep 10 23:52:39 2026 -0400 dock: add spacing option & update defaults commit 3e6cb55488a42ade23728bcf4d8608efab2e6e0f Author: bbedward <[email protected]> Date: Thu Sep 10 23:29:07 2026 -0400 session: collapse the monitor cycling setters onto one helper commit 613e756d8bf88b3c2e6ae7edcede4c680da72456 Author: bbedward <[email protected]> Date: Thu Sep 10 21:56:38 2026 -0400 dock: share the hover bounce animation across dock buttons commit 8d8f801874ddf5dcc3b299405de458183e758c7c Author: bbedward <[email protected]> Date: Thu Sep 10 21:46:44 2026 -0400 settings: share one picker window for bar and desktop widgets commit e3c90efbce4d7d11adf0cceefb8e9758e7d9099c Author: bbedward <[email protected]> Date: Thu Sep 10 21:24:10 2026 -0400 network: merge wired and wifi info modals commit 43f75e6a3dfc988f3adc8c7d659fff5529ed6db8 Author: purian23 <[email protected]> Date: Thu Sep 10 21:22:06 2026 -0400 island: unify new dashboard dynamic sizing & activities - New wallpaper carousel and Colum/Row options - Fixed island controller overlap in bar widget settings - Fixed island widgets click to hide activity - Expanded island IPC cyle targets commit 805611efca91bea029894436dad9baa6dd492461 Author: bbedward <[email protected]> Date: Thu Sep 10 19:40:27 2026 -0400 bar: share context menu window and tooltip offset across widgets also fix Media art glitches and things commit 17a08c4c7e56312d0b3a7732978223f569828aaf Author: bbedward <[email protected]> Date: Thu Sep 10 19:00:48 2026 -0400 osd/media: respect follow album accent option commit 6a753a7ab6304568f178bc3ec0910a9132020dd2 Author: bbedward <[email protected]> Date: Thu Sep 10 18:57:15 2026 -0400 theme: fix surface elevation commit af4f44eba649923bfb0928423a24fc6d115518c4 Author: bbedward <[email protected]> Date: Thu Sep 10 18:45:09 2026 -0400 m3e: redesign OSDs, Forms, etc. commit 1d2add180a661157b3c06a1221edae21bdbcb765 Author: bbedward <[email protected]> Date: Thu Sep 10 17:19:07 2026 -0400 rebase fixes commit ac39a7745cfe88bcfd3826f64cfd55ed41b18b3e Author: bbedward <[email protected]> Date: Thu Sep 10 16:51:16 2026 -0400 tray: share one item delegate and icon for both bar orientations commit 642eeb0f4b5d0a912fc44c134fc10adf8a5b5291 Author: bbedward <[email protected]> Date: Thu Sep 10 16:33:36 2026 -0400 bar: share one delegate for running apps in both orientations commit 7f69e42f3bef9025d411acfc768deb3865338922 Author: bbedward <[email protected]> Date: Thu Sep 10 15:56:33 2026 -0400 bar: share one monitor pill for cpu, ram, temp and disk widgets commit f5507dc3b2df6929521e87cd820eb45a3e3077ad Author: bbedward <[email protected]> Date: Thu Sep 10 14:03:00 2026 -0400 island: reuse widget model, surface palette and layout metrics in hosts commit aceac03ba0c9a2b0aa1a47f1b62a380fc785ec6d Author: bbedward <[email protected]> Date: Thu Sep 10 13:36:47 2026 -0400 osd: share one level osd for volume, brightness, mic and media commit 1b4a68d10c5b59f3ecf3e7c44974a2cb83964246 Author: bbedward <[email protected]> Date: Thu Sep 10 13:12:30 2026 -0400 shell: consolidate connected surface state into one slot store commit d7edc23cf14a10cd275fdf3888d24482d43a15f3 Author: bbedward <[email protected]> Date: Thu Sep 10 12:19:30 2026 -0400 shell: restore centered dash popout for center-section widgets commit d2f9405de9e7ade7db402826cfb0520249c58a2b Author: bbedward <[email protected]> Date: Thu Sep 10 12:11:29 2026 -0400 dash/media: always show placeholder player when no players are playing commit 55535082f53163914440e1e858aa78246bc4e40a Author: bbedward <[email protected]> Date: Thu Sep 10 12:08:10 2026 -0400 dock: fix sizing, exclusive zone, edit mode and multi-instance settings commit c82cc738ca2d20e7a4363b7abb86ad6d9e7bb172 Author: bbedward <[email protected]> Date: Thu Sep 10 11:08:40 2026 -0400 settings/plugins: redesign page commit 9c283e0f6c4b7d812362124fdd36fc15327ef03c Author: bbedward <[email protected]> Date: Wed Sep 9 20:44:26 2026 -0400 shell: route widget instances and support same-edge layouts commit 405a3b397c264688b2271d6acec881a4aea4864f Author: bbedward <[email protected]> Date: Wed Sep 9 18:05:37 2026 -0400 shell: share bar content and clock presentation commit 65a6d2df8e870af259b1542c896fce60be4f6cb6 Author: bbedward <[email protected]> Date: Wed Sep 9 15:49:23 2026 -0400 shell: centralize layout ownership commit 585aeb4e1cba737cc4007fc214ac1e109d3e0f19 Author: purian23 <[email protected]> Date: Wed Sep 9 18:05:13 2026 -0400 dock: initial m3e remaster commit a2e646f2fb364f042fb134e74e9014386b80971b Author: bbedward <[email protected]> Date: Wed Sep 9 14:58:38 2026 -0400 plugins: consolidate upgrade path commit 139253504c5f62d522fbc6109689c11ccaec7493 Author: bbedward <[email protected]> Date: Wed Sep 9 14:43:28 2026 -0400 settings: use icons on all outlined text fields commit a9c1e569b8428e4f3748da345200e8a62c90ba20 Author: bbedward <[email protected]> Date: Wed Sep 9 14:32:33 2026 -0400 launcher: fix KB navigation focus and modes commit ac64eb52d360322a0e952844b41b58532d5ae32f Author: bbedward <[email protected]> Date: Wed Sep 9 14:05:10 2026 -0400 m3e: remove inconsistent widget usage, adjust SystemUpdater rredesign, fix window decoration inconsistencies commit 0eac1d3e22cb879c7b7e9205fba0ed9c17b89dcd Author: bbedward <[email protected]> Date: Wed Sep 9 13:25:44 2026 -0400 server: consolidate ipc routing and subscription forwarding commit ed289e5c2c867eb2d6e1319d9517885e6e80d1a3 Author: bbedward <[email protected]> Date: Wed Sep 9 12:56:29 2026 -0400 plugins: redesign management and browsers with m3 expressive commit 7f3a526e2d38c24edbb5d51c4c9c550a0bc93752 Author: bbedward <[email protected]> Date: Wed Sep 9 11:00:07 2026 -0400 settings: fix inconsistent ripple effect radius commit 8f1fb8a11e92b1811808325c136199fef10d4a53 Author: bbedward <[email protected]> Date: Wed Sep 9 10:26:39 2026 -0400 aqueous: fix variant terms commit 2ba861947092cb657d983702c842e88ffc6fb0fa Author: bbedward <[email protected]> Date: Wed Sep 9 10:01:50 2026 -0400 running apps: fix delegate bug commit b37c925e85cb6902bbb3005d92a5b522e3648116 Author: bbedward <[email protected]> Date: Wed Sep 9 00:18:57 2026 -0400 bump dml-common commit 5e83c40c56c624df74306efc839d707ec8d6aa14 Author: bbedward <[email protected]> Date: Wed Sep 9 00:12:16 2026 -0400 settings: incorporate user & accounts tab, consolidate security, add M3E textfield commit 278370c7909226ca42f0a53cbd9ca2bd5f2fb4e7 Author: bbedward <[email protected]> Date: Tue Sep 8 18:17:25 2026 -0400 m3e: unify shell surfaces and refresh process monitoring commit e2d5860d3952da717ba9073e857133f2538a70b0 Author: bbedward <[email protected]> Date: Tue Sep 8 15:15:17 2026 -0400 notifications: fix expansion timing and simplify the header commit d8f29c221474c2884ec482d26c827de09d581539 Author: bbedward <[email protected]> Date: Tue Sep 8 14:53:11 2026 -0400 icon: install app icon under the conventional name (app id) commit ebeebb70fd4c7538ef5ea867116d9fa7118eee27 Author: bbedward <[email protected]> Date: Tue Sep 8 14:47:09 2026 -0400 notifications: refine card styling and separate app icons from image previews commit d6133d93ed314ca02a9a3b634872ee32484a0bb3 Author: bbedward <[email protected]> Date: Tue Sep 8 14:27:18 2026 -0400 settings: unify expressive rows and drag and drop commit 0a4d14752a2a1e8dd60b3056fd006d02d818d6a4 Author: bbedward <[email protected]> Date: Tue Sep 8 12:32:16 2026 -0400 settings: use native action button hover state commit dc8c4564cc964ab50ed28a3e9e4ca7b13ebfbcb1 Author: bbedward <[email protected]> Date: Tue Sep 8 09:55:42 2026 -0400 shell: refine weather, slider controls, and tooltips commit bec5c6ad0119e22a3cb69975d135d3b72654f77e Author: bbedward <[email protected]> Date: Mon Sep 7 18:43:39 2026 -0400 theme: tweak token values commit 8519cbc4bbb396a8b6779764ff0f5a0945156dcf Author: bbedward <[email protected]> Date: Mon Sep 7 13:43:53 2026 -0400 dankdash: fix grid sizing, controls, notifications, and popout blur commit f2405f2925aa63eba480cff4ddc55119818f8057 Author: bbedward <[email protected]> Date: Mon Sep 7 10:38:07 2026 -0400 dash: redesign media player and migrate its appearance options commit cb57ce04fbd50920a17d9a8ad33e4d20fc856021 Author: bbedward <[email protected]> Date: Mon Sep 7 09:07:01 2026 -0400 lock: add lock m3e redesign commit e89909e3743993dad1bdf17d57ab17f1122dfa3c Author: bbedward <[email protected]> Date: Sun Sep 6 21:24:48 2026 -0400 qs: more loaders, less repetition commit 288335fef67b523f51e22bb234c81bd8b88e7e2c Author: bbedward <[email protected]> Date: Sun Sep 6 20:16:41 2026 -0400 launcher: initial m3e redesign commit 5b7fc75c473491bf086b65a41416325697ae330c Author: purian23 <[email protected]> Date: Sun Sep 6 19:50:14 2026 -0400 feat(motion): new fluid animation variant - Refactored Popouts/Modals for performance passes commit 0fc4f51f4d0b1d297c1886b19be8062d279c505b Author: bbedward <[email protected]> Date: Sun Sep 6 15:36:22 2026 -0400 notifications: tweak animnation stacking behavior on popups commit 4369233794e3bebd890a2b830c6450d0a65eb31a Author: bbedward <[email protected]> Date: Sun Sep 6 15:15:55 2026 -0400 notifications: initial M3E redesign commit eb67a51779c543038ad885ecd406bfe21aecd1e2 Author: bbedward <[email protected]> Date: Sat Sep 5 15:10:37 2026 -0400 ddash: exhaustive overhaul of even more pieces of the system commit 14554a39effd677206f7a3c4b5944d2ae47c2b03 Author: bbedward <[email protected]> Date: Sat Sep 5 12:47:06 2026 -0400 settings: rebase fixes commit d6e0bb604bdb15ed94d77f9e1d85a26381ed6836 Author: bbedward <[email protected]> Date: Sat Sep 5 10:18:38 2026 -0400 ddash: initial rewrite commit 29903114d0d8849b25c6f6e9161765b0ad03da49 Author: bbedward <[email protected]> Date: Fri Sep 4 16:48:23 2026 -0400 cc: tweak s lider size commit 8d14a07864972e4b705e77b371d21f5fdb7c4c07 Author: bbedward <[email protected]> Date: Fri Sep 4 16:44:53 2026 -0400 cc: initial M3E re-design commit 976f968967166c61cec423f3bb3f7a28a5a9ac76 Author: bbedward <[email protected]> Date: Fri Sep 4 15:00:35 2026 -0400 settings: continue to iterate commit a99a1c5ad183e34435a20dd90f19ed84099a1070 Author: bbedward <[email protected]> Date: Fri Sep 4 09:44:55 2026 -0400 stash m3e work
2244 lines
79 KiB
QML
2244 lines
79 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import Quickshell.Hyprland
|
|
import Quickshell.Wayland
|
|
import Quickshell.Services.SystemTray
|
|
import Quickshell.Services.UPower
|
|
import qs.Common
|
|
import qs.Modules.DankDash
|
|
import qs.Services
|
|
import qs.Modules.Settings.DisplayConfig
|
|
|
|
Item {
|
|
id: root
|
|
readonly property var log: Log.scoped("DMSShellIPC")
|
|
|
|
required property var powerMenuModalLoader
|
|
required property var processListModalLoader
|
|
required property var controlCenterLoader
|
|
required property var dankDashPopoutLoader
|
|
required property var notepadSlideoutVariants
|
|
required property var hyprKeybindsModalLoader
|
|
required property var dankBarRepeater
|
|
required property var hyprlandOverviewLoader
|
|
required property var workspaceRenameModalLoader
|
|
required property var windowRuleModalLoader
|
|
|
|
function getPreferredBar(refPropertyName) {
|
|
const focusedScreenName = BarWidgetService.getFocusedScreenName();
|
|
|
|
const bars = [];
|
|
if (root.dankBarRepeater) {
|
|
for (let i = 0; i < root.dankBarRepeater.count; i++)
|
|
bars.push(...(root.dankBarRepeater.itemAt(i)?.item?.barVariants?.instances || []));
|
|
}
|
|
for (const screenName in BarWidgetService.frameHostedBars)
|
|
bars.push(...BarWidgetService.frameBarsForScreen(screenName));
|
|
|
|
let currentBar = null;
|
|
let islandBar = null;
|
|
for (const bar of bars) {
|
|
if (!bar)
|
|
continue;
|
|
|
|
const onFocusedScreen = focusedScreenName && bar.modelData?.name === focusedScreenName;
|
|
const hasRef = !refPropertyName || !!bar[refPropertyName];
|
|
if (!hasRef)
|
|
continue;
|
|
|
|
if (bar.isIsland) {
|
|
if (!islandBar || onFocusedScreen)
|
|
islandBar = bar;
|
|
continue;
|
|
}
|
|
|
|
currentBar = bar;
|
|
if (onFocusedScreen)
|
|
break;
|
|
}
|
|
|
|
return currentBar ?? islandBar;
|
|
}
|
|
|
|
readonly property var defaultAppMimeTypes: ({
|
|
browser: "x-scheme-handler/https",
|
|
fileManager: "inode/directory",
|
|
textEditor: "text/plain",
|
|
imageViewer: "image/png",
|
|
videoPlayer: "video/mp4",
|
|
musicPlayer: "audio/mpeg",
|
|
pdfReader: "application/pdf",
|
|
mail: "x-scheme-handler/mailto",
|
|
calendar: "x-scheme-handler/calendar"
|
|
})
|
|
|
|
function launchDesktopId(desktopId, appName) {
|
|
if (!desktopId || desktopId.length === 0) {
|
|
log.warn("No default app configured for:", appName);
|
|
return false;
|
|
}
|
|
|
|
let entry = DesktopEntries.heuristicLookup(desktopId);
|
|
if (!entry && desktopId.endsWith(".desktop")) {
|
|
entry = DesktopEntries.heuristicLookup(desktopId.slice(0, -8));
|
|
}
|
|
if (!entry) {
|
|
log.warn("Default app desktop entry not found:", desktopId, "for:", appName);
|
|
return false;
|
|
}
|
|
|
|
SessionService.launchDesktopEntry(entry);
|
|
AppUsageHistoryData.addAppUsage(entry);
|
|
return true;
|
|
}
|
|
|
|
function launchDefaultMimeApp(appName, mimeType) {
|
|
DMSService.sendRequest("mime.getDefault", {
|
|
"mimeType": mimeType
|
|
}, response => {
|
|
if (response.error) {
|
|
log.warn("Failed to resolve default app:", appName, response.error);
|
|
return;
|
|
}
|
|
const result = response.result || {};
|
|
root.launchDesktopId(result.desktopId || "", appName);
|
|
});
|
|
|
|
return `DEFAULTAPP_LAUNCH_REQUESTED: ${appName}`;
|
|
}
|
|
|
|
function parseIdleInhibitMinutes(duration) {
|
|
if (duration === undefined || duration === null)
|
|
return -1;
|
|
const trimmed = String(duration).trim();
|
|
if (!trimmed)
|
|
return -1;
|
|
const minutes = parseInt(trimmed, 10);
|
|
if (isNaN(minutes) || minutes <= 0 || String(minutes) !== trimmed)
|
|
return -1;
|
|
return minutes;
|
|
}
|
|
|
|
function idleInhibitStatusMessage() {
|
|
if (!SessionService.idleInhibited)
|
|
return "Idle inhibit is disabled";
|
|
if (SessionData.idleInhibitedUntil <= 0)
|
|
return "Idle inhibit is enabled indefinitely";
|
|
const remainingMs = Math.max(0, SessionData.idleInhibitedUntil - Date.now());
|
|
const remainingMin = Math.ceil(remainingMs / 60000);
|
|
return `Idle inhibit is enabled for ${remainingMin} more minute${remainingMin === 1 ? "" : "s"}`;
|
|
}
|
|
|
|
IpcHandler {
|
|
function browser(): string {
|
|
return root.launchDefaultMimeApp("browser", root.defaultAppMimeTypes.browser);
|
|
}
|
|
|
|
function fileManager(): string {
|
|
return root.launchDefaultMimeApp("fileManager", root.defaultAppMimeTypes.fileManager);
|
|
}
|
|
|
|
function textEditor(): string {
|
|
return root.launchDefaultMimeApp("textEditor", root.defaultAppMimeTypes.textEditor);
|
|
}
|
|
|
|
function imageViewer(): string {
|
|
return root.launchDefaultMimeApp("imageViewer", root.defaultAppMimeTypes.imageViewer);
|
|
}
|
|
|
|
function videoPlayer(): string {
|
|
return root.launchDefaultMimeApp("videoPlayer", root.defaultAppMimeTypes.videoPlayer);
|
|
}
|
|
|
|
function musicPlayer(): string {
|
|
return root.launchDefaultMimeApp("musicPlayer", root.defaultAppMimeTypes.musicPlayer);
|
|
}
|
|
|
|
function pdfReader(): string {
|
|
return root.launchDefaultMimeApp("pdfReader", root.defaultAppMimeTypes.pdfReader);
|
|
}
|
|
|
|
function mail(): string {
|
|
return root.launchDefaultMimeApp("mail", root.defaultAppMimeTypes.mail);
|
|
}
|
|
|
|
function calendar(): string {
|
|
return root.launchDefaultMimeApp("calendar", root.defaultAppMimeTypes.calendar);
|
|
}
|
|
|
|
target: "defaultApp"
|
|
}
|
|
|
|
IpcHandler {
|
|
function open() {
|
|
root.powerMenuModalLoader.active = true;
|
|
if (root.powerMenuModalLoader.item)
|
|
root.powerMenuModalLoader.item.openCentered();
|
|
|
|
return "POWERMENU_OPEN_SUCCESS";
|
|
}
|
|
|
|
function close() {
|
|
if (root.powerMenuModalLoader.item)
|
|
root.powerMenuModalLoader.item.close();
|
|
|
|
return "POWERMENU_CLOSE_SUCCESS";
|
|
}
|
|
|
|
function toggle() {
|
|
root.powerMenuModalLoader.active = true;
|
|
if (root.powerMenuModalLoader.item) {
|
|
if (root.powerMenuModalLoader.item.shouldBeVisible) {
|
|
root.powerMenuModalLoader.item.close();
|
|
} else {
|
|
root.powerMenuModalLoader.item.openCentered();
|
|
}
|
|
}
|
|
|
|
return "POWERMENU_TOGGLE_SUCCESS";
|
|
}
|
|
|
|
target: "powermenu"
|
|
}
|
|
|
|
IpcHandler {
|
|
function open(): string {
|
|
root.processListModalLoader.active = true;
|
|
Qt.callLater(() => {
|
|
if (root.processListModalLoader.item)
|
|
root.processListModalLoader.item.show();
|
|
});
|
|
|
|
return "PROCESSLIST_OPEN_SUCCESS";
|
|
}
|
|
|
|
function close(): string {
|
|
if (root.processListModalLoader.item)
|
|
root.processListModalLoader.item.hide();
|
|
|
|
return "PROCESSLIST_CLOSE_SUCCESS";
|
|
}
|
|
|
|
function toggle(): string {
|
|
root.processListModalLoader.active = true;
|
|
Qt.callLater(() => {
|
|
if (root.processListModalLoader.item)
|
|
root.processListModalLoader.item.toggle();
|
|
});
|
|
|
|
return "PROCESSLIST_TOGGLE_SUCCESS";
|
|
}
|
|
|
|
function focusOrToggle(): string {
|
|
root.processListModalLoader.active = true;
|
|
Qt.callLater(() => {
|
|
if (root.processListModalLoader.item)
|
|
root.processListModalLoader.item.focusOrToggle();
|
|
});
|
|
|
|
return "PROCESSLIST_FOCUS_OR_TOGGLE_SUCCESS";
|
|
}
|
|
|
|
target: "processlist"
|
|
}
|
|
|
|
IpcHandler {
|
|
function open(): string {
|
|
if (PopoutService.routeToIsland("controlcenter", null, false, ""))
|
|
return "CONTROL_CENTER_OPEN_SUCCESS";
|
|
const bar = root.getPreferredBar("controlCenterButtonRef");
|
|
if (bar) {
|
|
bar.triggerControlCenter();
|
|
return "CONTROL_CENTER_OPEN_SUCCESS";
|
|
}
|
|
return "CONTROL_CENTER_OPEN_FAILED";
|
|
}
|
|
|
|
function openWith(section: string): string {
|
|
if (PopoutService.routeToIsland("controlcenter", null, false, section))
|
|
return "CONTROL_CENTER_OPEN_SUCCESS";
|
|
const popout = root.controlCenterLoader.item;
|
|
if (popout?.shouldBeVisible) {
|
|
popout.expandedSection = section;
|
|
return "CONTROL_CENTER_OPEN_SUCCESS";
|
|
}
|
|
const bar = root.getPreferredBar("controlCenterButtonRef");
|
|
if (!bar)
|
|
return "CONTROL_CENTER_OPEN_FAILED";
|
|
bar.triggerControlCenter();
|
|
const opened = root.controlCenterLoader.item;
|
|
if (!opened)
|
|
return "CONTROL_CENTER_OPEN_SUCCESS";
|
|
if (opened.shouldBeVisible)
|
|
opened.expandedSection = section;
|
|
else
|
|
opened.pendingSection = section;
|
|
return "CONTROL_CENTER_OPEN_SUCCESS";
|
|
}
|
|
|
|
function back(): string {
|
|
const content = root.controlCenterLoader.item?.contentLoader?.item;
|
|
if (!content)
|
|
return "CONTROL_CENTER_BACK_FAILED";
|
|
content.goBack();
|
|
return "CONTROL_CENTER_BACK_SUCCESS";
|
|
}
|
|
|
|
function hide(): string {
|
|
if (PopoutService.closeIslandActivity("controlcenter"))
|
|
return "CONTROL_CENTER_HIDE_SUCCESS";
|
|
if (root.controlCenterLoader.item && root.controlCenterLoader.item.shouldBeVisible) {
|
|
root.controlCenterLoader.item.close();
|
|
return "CONTROL_CENTER_HIDE_SUCCESS";
|
|
}
|
|
return "CONTROL_CENTER_HIDE_FAILED";
|
|
}
|
|
|
|
function toggle(): string {
|
|
if (root.controlCenterLoader.item?.shouldBeVisible) {
|
|
root.controlCenterLoader.item.close();
|
|
return "CONTROL_CENTER_TOGGLE_SUCCESS";
|
|
}
|
|
if (PopoutService.routeToIsland("controlcenter", null, true, ""))
|
|
return "CONTROL_CENTER_TOGGLE_SUCCESS";
|
|
|
|
const bar = root.getPreferredBar("controlCenterButtonRef");
|
|
if (bar) {
|
|
bar.triggerControlCenter();
|
|
return "CONTROL_CENTER_TOGGLE_SUCCESS";
|
|
}
|
|
return "CONTROL_CENTER_TOGGLE_FAILED";
|
|
}
|
|
|
|
function status(): string {
|
|
if (PopoutService.islandControlCenterOpen)
|
|
return "visible";
|
|
return (root.controlCenterLoader.item && root.controlCenterLoader.item.shouldBeVisible) ? "visible" : "hidden";
|
|
}
|
|
|
|
target: "control-center"
|
|
}
|
|
|
|
IpcHandler {
|
|
// Screenshot region-select handshake
|
|
function begin(): string {
|
|
PopoutManager.screenshotActive = true;
|
|
return "SCREENSHOT_MODE_ON";
|
|
}
|
|
|
|
function end(): string {
|
|
PopoutManager.screenshotActive = false;
|
|
return "SCREENSHOT_MODE_OFF";
|
|
}
|
|
|
|
target: "screenshot"
|
|
}
|
|
|
|
IpcHandler {
|
|
function _resolveTabId(tab) {
|
|
return DashRegistry.resolveId(tab);
|
|
}
|
|
|
|
function _islandActivity(tabId) {
|
|
switch (tabId) {
|
|
case "overview":
|
|
return "home";
|
|
case "media":
|
|
case "wallpaper":
|
|
case "weather":
|
|
return tabId;
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
function _routeToIsland(tabId, toggle) {
|
|
const activity = _islandActivity(tabId);
|
|
if (activity === "")
|
|
return false;
|
|
return PopoutService.routeToIsland(activity, null, toggle);
|
|
}
|
|
|
|
function _resolvePosition(position) {
|
|
switch ((position || "").toLowerCase()) {
|
|
case "left":
|
|
return "left";
|
|
case "center":
|
|
return "center";
|
|
case "right":
|
|
return "right";
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
function _dashBar(position) {
|
|
if (position)
|
|
return root.getPreferredBar();
|
|
return root.getPreferredBar("clockButtonRef") || root.getPreferredBar();
|
|
}
|
|
|
|
function _openDash(tab, position) {
|
|
const tabId = _resolveTabId(tab);
|
|
if (!position && _routeToIsland(tabId, false))
|
|
return true;
|
|
|
|
const bar = _dashBar(position);
|
|
if (!bar)
|
|
return false;
|
|
|
|
const dash = root.dankDashPopoutLoader.item;
|
|
if (dash && dash.shouldBeVisible && dash.triggerScreen?.name === bar.screen?.name) {
|
|
if (position && bar.positionDash)
|
|
bar.positionDash(dash, position);
|
|
dash.requestTab(tabId);
|
|
if (dash.updateSurfacePosition)
|
|
dash.updateSurfacePosition();
|
|
return true;
|
|
}
|
|
|
|
return bar.triggerDashTab(tabId, position);
|
|
}
|
|
|
|
function _toggleDash(tab, position) {
|
|
if (root.dankDashPopoutLoader.item?.dashVisible) {
|
|
root.dankDashPopoutLoader.item.dashVisible = false;
|
|
return true;
|
|
}
|
|
|
|
const tabId = _resolveTabId(tab);
|
|
if (!position && _routeToIsland(tabId, true))
|
|
return true;
|
|
|
|
const bar = _dashBar(position);
|
|
if (!bar)
|
|
return false;
|
|
return bar.triggerDashTab(tabId, position);
|
|
}
|
|
|
|
function resolveTabIndex(tab: string): int {
|
|
return Math.max(0, DashRegistry.indexOf(_resolveTabId(tab)));
|
|
}
|
|
|
|
function open(tab: string): string {
|
|
return _openDash(tab, "") ? "DASH_OPEN_SUCCESS" : "DASH_OPEN_FAILED";
|
|
}
|
|
|
|
function openAt(tab: string, position: string): string {
|
|
return _openDash(tab, _resolvePosition(position)) ? "DASH_OPEN_SUCCESS" : "DASH_OPEN_FAILED";
|
|
}
|
|
|
|
function close(): string {
|
|
if (PopoutService.closeIslandActivity("home") || PopoutService.closeIslandActivity("media") || PopoutService.closeIslandActivity("wallpaper") || PopoutService.closeIslandActivity("weather"))
|
|
return "DASH_CLOSE_SUCCESS";
|
|
if (root.dankDashPopoutLoader.item) {
|
|
root.dankDashPopoutLoader.item.dashVisible = false;
|
|
return "DASH_CLOSE_SUCCESS";
|
|
}
|
|
return "DASH_CLOSE_FAILED";
|
|
}
|
|
|
|
function toggle(tab: string): string {
|
|
return _toggleDash(tab, "") ? "DASH_TOGGLE_SUCCESS" : "DASH_TOGGLE_FAILED";
|
|
}
|
|
|
|
function toggleAt(tab: string, position: string): string {
|
|
return _toggleDash(tab, _resolvePosition(position)) ? "DASH_TOGGLE_SUCCESS" : "DASH_TOGGLE_FAILED";
|
|
}
|
|
|
|
target: "dash"
|
|
}
|
|
|
|
IpcHandler {
|
|
function getFocusedScreenName() {
|
|
if (CompositorService.isHyprland && Hyprland.focusedMonitor) {
|
|
return Hyprland.focusedMonitor.name;
|
|
}
|
|
if (CompositorService.isNiri && NiriService.currentOutput) {
|
|
return NiriService.currentOutput;
|
|
}
|
|
if ((CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle) && I3.workspaces?.values) {
|
|
const focusedWs = I3.workspaces.values.find(ws => ws.focused === true);
|
|
return focusedWs?.monitor?.name || "";
|
|
}
|
|
if (CompositorService.isMango && MangoService.activeOutput) {
|
|
return MangoService.activeOutput;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
function getActiveNotepadInstance() {
|
|
if (root.notepadSlideoutVariants.instances.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
if (root.notepadSlideoutVariants.instances.length === 1) {
|
|
return root.notepadSlideoutVariants.instances[0];
|
|
}
|
|
|
|
var focusedScreen = getFocusedScreenName();
|
|
if (focusedScreen && root.notepadSlideoutVariants.instances.length > 0) {
|
|
for (var i = 0; i < root.notepadSlideoutVariants.instances.length; i++) {
|
|
var slideout = root.notepadSlideoutVariants.instances[i];
|
|
if (slideout.modelData && slideout.modelData.name === focusedScreen) {
|
|
return slideout;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < root.notepadSlideoutVariants.instances.length; i++) {
|
|
var slideout = root.notepadSlideoutVariants.instances[i];
|
|
if (slideout.isVisible) {
|
|
return slideout;
|
|
}
|
|
}
|
|
|
|
return root.notepadSlideoutVariants.instances[0];
|
|
}
|
|
|
|
function open(): string {
|
|
if (PopoutService.notepadResolvedMode === "popout") {
|
|
PopoutService.openNotepadPopout();
|
|
return "NOTEPAD_OPEN_SUCCESS";
|
|
}
|
|
var instance = getActiveNotepadInstance();
|
|
if (instance) {
|
|
instance.show();
|
|
return "NOTEPAD_OPEN_SUCCESS";
|
|
}
|
|
return "NOTEPAD_OPEN_FAILED";
|
|
}
|
|
|
|
function openFile(path: string): string {
|
|
if (!path)
|
|
return open();
|
|
if (PopoutService.notepadResolvedMode === "popout") {
|
|
PopoutService.openNotepadPopoutWithFile(path);
|
|
return "NOTEPAD_OPEN_FILE_SUCCESS";
|
|
}
|
|
var instance = getActiveNotepadInstance();
|
|
if (instance) {
|
|
instance.show();
|
|
instance.loadedItem?.openExternalFile(path);
|
|
return "NOTEPAD_OPEN_FILE_SUCCESS";
|
|
}
|
|
return "NOTEPAD_OPEN_FILE_FAILED";
|
|
}
|
|
|
|
function close(): string {
|
|
if (PopoutService.notepadResolvedMode === "popout") {
|
|
PopoutService.notepadPopout?.hide();
|
|
return "NOTEPAD_CLOSE_SUCCESS";
|
|
}
|
|
var instance = getActiveNotepadInstance();
|
|
if (instance) {
|
|
instance.hide();
|
|
return "NOTEPAD_CLOSE_SUCCESS";
|
|
}
|
|
return "NOTEPAD_CLOSE_FAILED";
|
|
}
|
|
|
|
function toggle(): string {
|
|
if (PopoutService.notepadResolvedMode === "popout") {
|
|
PopoutService.toggleNotepadPopout();
|
|
return "NOTEPAD_TOGGLE_SUCCESS";
|
|
}
|
|
var instance = getActiveNotepadInstance();
|
|
if (instance) {
|
|
instance.toggle();
|
|
return "NOTEPAD_TOGGLE_SUCCESS";
|
|
}
|
|
return "NOTEPAD_TOGGLE_FAILED";
|
|
}
|
|
|
|
function expand(): string {
|
|
var instance = getActiveNotepadInstance();
|
|
if (instance) {
|
|
instance.expandedWidth = true;
|
|
if (!instance.isVisible)
|
|
instance.show();
|
|
return "NOTEPAD_EXPAND_SUCCESS";
|
|
}
|
|
return "NOTEPAD_EXPAND_FAILED";
|
|
}
|
|
|
|
function collapse(): string {
|
|
var instance = getActiveNotepadInstance();
|
|
if (instance) {
|
|
instance.expandedWidth = false;
|
|
if (!instance.isVisible)
|
|
instance.show();
|
|
return "NOTEPAD_COLLAPSE_SUCCESS";
|
|
}
|
|
return "NOTEPAD_COLLAPSE_FAILED";
|
|
}
|
|
|
|
function toggleExpand(): string {
|
|
var instance = getActiveNotepadInstance();
|
|
if (instance) {
|
|
instance.expandedWidth = !instance.expandedWidth;
|
|
return "NOTEPAD_TOGGLE_EXPAND_SUCCESS";
|
|
}
|
|
return "NOTEPAD_TOGGLE_EXPAND_FAILED";
|
|
}
|
|
|
|
target: "notepad"
|
|
}
|
|
|
|
IpcHandler {
|
|
function toggle(): string {
|
|
SessionService.toggleIdleInhibit();
|
|
return root.idleInhibitStatusMessage();
|
|
}
|
|
|
|
function enable(): string {
|
|
SessionService.enableIdleInhibit();
|
|
return root.idleInhibitStatusMessage();
|
|
}
|
|
|
|
function enableFor(minutes: string): string {
|
|
const parsed = root.parseIdleInhibitMinutes(minutes);
|
|
if (parsed < 0)
|
|
return "Invalid duration. Use minutes, e.g. 60.";
|
|
SessionService.enableIdleInhibit(parsed);
|
|
return root.idleInhibitStatusMessage();
|
|
}
|
|
|
|
function disable(): string {
|
|
SessionService.disableIdleInhibit();
|
|
return "Idle inhibit is disabled";
|
|
}
|
|
|
|
function status(): string {
|
|
return root.idleInhibitStatusMessage();
|
|
}
|
|
|
|
function reason(newReason: string): string {
|
|
if (!newReason) {
|
|
return `Current reason: ${SessionService.inhibitReason}`;
|
|
}
|
|
|
|
SessionService.setInhibitReason(newReason);
|
|
return `Inhibit reason set to: ${newReason}`;
|
|
}
|
|
|
|
target: "inhibit"
|
|
}
|
|
|
|
IpcHandler {
|
|
function list(): string {
|
|
return MprisController.availablePlayers.map(p => p.identity).join("\n");
|
|
}
|
|
|
|
function play(): void {
|
|
MprisController.play();
|
|
}
|
|
|
|
function pause(): void {
|
|
MprisController.pause();
|
|
}
|
|
|
|
function playPause(): void {
|
|
MprisController.playPause();
|
|
}
|
|
|
|
function previous(): void {
|
|
MprisController.previousOrRewind();
|
|
}
|
|
|
|
function next(): void {
|
|
MprisController.next();
|
|
}
|
|
|
|
function stop(): void {
|
|
MprisController.stop();
|
|
}
|
|
|
|
function increment(step: string): string {
|
|
if (MprisController.activePlayer && MprisController.activePlayer.volumeSupported) {
|
|
const currentVolume = Math.round(MprisController.activePlayer.volume * 100);
|
|
const stepValue = parseInt(step || "5");
|
|
const newVolume = Math.max(0, Math.min(100, currentVolume + stepValue));
|
|
|
|
MprisController.activePlayer.volume = newVolume / 100;
|
|
return `Player volume increased to ${newVolume}%`;
|
|
}
|
|
}
|
|
|
|
function decrement(step: string): string {
|
|
if (MprisController.activePlayer && MprisController.activePlayer.volumeSupported) {
|
|
const currentVolume = Math.round(MprisController.activePlayer.volume * 100);
|
|
const stepValue = parseInt(step || "5");
|
|
const newVolume = Math.max(0, Math.min(100, currentVolume - stepValue));
|
|
|
|
MprisController.activePlayer.volume = newVolume / 100;
|
|
return `Player volume decreased to ${newVolume}%`;
|
|
}
|
|
}
|
|
|
|
function setvolume(percentage: string): string {
|
|
if (MprisController.activePlayer && MprisController.activePlayer.volumeSupported) {
|
|
const clampedVolume = Math.max(0, Math.min(100, percentage));
|
|
MprisController.activePlayer.volume = clampedVolume / 100;
|
|
return `Player volume set to ${clampedVolume}%`;
|
|
}
|
|
}
|
|
|
|
target: "mpris"
|
|
}
|
|
|
|
IpcHandler {
|
|
function toggle(provider: string): string {
|
|
if (!provider)
|
|
return "ERROR: No provider specified";
|
|
|
|
KeybindsService.loadCheatsheet(provider);
|
|
root.hyprKeybindsModalLoader.active = true;
|
|
|
|
if (!root.hyprKeybindsModalLoader.item)
|
|
return `KEYBINDS_TOGGLE_FAILED: ${provider}`;
|
|
|
|
if (root.hyprKeybindsModalLoader.item.shouldBeVisible)
|
|
root.hyprKeybindsModalLoader.item.close();
|
|
else
|
|
root.hyprKeybindsModalLoader.item.open();
|
|
return `KEYBINDS_TOGGLE_SUCCESS: ${provider}`;
|
|
}
|
|
|
|
function toggleWithPath(provider: string, path: string): string {
|
|
if (!provider)
|
|
return "ERROR: No provider specified";
|
|
|
|
KeybindsService.loadCheatsheet(provider);
|
|
root.hyprKeybindsModalLoader.active = true;
|
|
|
|
if (!root.hyprKeybindsModalLoader.item)
|
|
return `KEYBINDS_TOGGLE_FAILED: ${provider}`;
|
|
|
|
if (root.hyprKeybindsModalLoader.item.shouldBeVisible)
|
|
root.hyprKeybindsModalLoader.item.close();
|
|
else
|
|
root.hyprKeybindsModalLoader.item.open();
|
|
return `KEYBINDS_TOGGLE_SUCCESS: ${provider} (${path})`;
|
|
}
|
|
|
|
function open(provider: string): string {
|
|
if (!provider)
|
|
return "ERROR: No provider specified";
|
|
|
|
KeybindsService.loadCheatsheet(provider);
|
|
root.hyprKeybindsModalLoader.active = true;
|
|
|
|
if (!root.hyprKeybindsModalLoader.item)
|
|
return `KEYBINDS_OPEN_FAILED: ${provider}`;
|
|
|
|
root.hyprKeybindsModalLoader.item.open();
|
|
return `KEYBINDS_OPEN_SUCCESS: ${provider}`;
|
|
}
|
|
|
|
function openWithPath(provider: string, path: string): string {
|
|
if (!provider)
|
|
return "ERROR: No provider specified";
|
|
|
|
KeybindsService.loadCheatsheet(provider);
|
|
root.hyprKeybindsModalLoader.active = true;
|
|
|
|
if (!root.hyprKeybindsModalLoader.item)
|
|
return `KEYBINDS_OPEN_FAILED: ${provider}`;
|
|
|
|
root.hyprKeybindsModalLoader.item.open();
|
|
return `KEYBINDS_OPEN_SUCCESS: ${provider} (${path})`;
|
|
}
|
|
|
|
function close(): string {
|
|
if (!root.hyprKeybindsModalLoader.item)
|
|
return "KEYBINDS_CLOSE_FAILED";
|
|
|
|
root.hyprKeybindsModalLoader.item.close();
|
|
return "KEYBINDS_CLOSE_SUCCESS";
|
|
}
|
|
|
|
target: "keybinds"
|
|
}
|
|
|
|
IpcHandler {
|
|
function openBinds(): string {
|
|
if (!CompositorService.isHyprland)
|
|
return "HYPR_NOT_AVAILABLE";
|
|
|
|
KeybindsService.currentProvider = "hyprland";
|
|
KeybindsService.loadBinds();
|
|
root.hyprKeybindsModalLoader.active = true;
|
|
|
|
if (!root.hyprKeybindsModalLoader.item)
|
|
return "HYPR_KEYBINDS_OPEN_FAILED";
|
|
|
|
root.hyprKeybindsModalLoader.item.open();
|
|
return "HYPR_KEYBINDS_OPEN_SUCCESS";
|
|
}
|
|
|
|
function closeBinds(): string {
|
|
if (!CompositorService.isHyprland)
|
|
return "HYPR_NOT_AVAILABLE";
|
|
|
|
if (!root.hyprKeybindsModalLoader.item)
|
|
return "HYPR_KEYBINDS_CLOSE_FAILED";
|
|
|
|
root.hyprKeybindsModalLoader.item.close();
|
|
return "HYPR_KEYBINDS_CLOSE_SUCCESS";
|
|
}
|
|
|
|
function toggleBinds(): string {
|
|
if (!CompositorService.isHyprland)
|
|
return "HYPR_NOT_AVAILABLE";
|
|
|
|
KeybindsService.currentProvider = "hyprland";
|
|
KeybindsService.loadBinds();
|
|
root.hyprKeybindsModalLoader.active = true;
|
|
|
|
if (!root.hyprKeybindsModalLoader.item)
|
|
return "HYPR_KEYBINDS_TOGGLE_FAILED";
|
|
|
|
if (root.hyprKeybindsModalLoader.item.shouldBeVisible) {
|
|
root.hyprKeybindsModalLoader.item.close();
|
|
} else {
|
|
root.hyprKeybindsModalLoader.item.open();
|
|
}
|
|
return "HYPR_KEYBINDS_TOGGLE_SUCCESS";
|
|
}
|
|
|
|
function toggleOverview(): string {
|
|
if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) {
|
|
return "HYPR_NOT_AVAILABLE";
|
|
}
|
|
root.hyprlandOverviewLoader.item.overviewOpen = !root.hyprlandOverviewLoader.item.overviewOpen;
|
|
return root.hyprlandOverviewLoader.item.overviewOpen ? "OVERVIEW_OPEN_SUCCESS" : "OVERVIEW_CLOSE_SUCCESS";
|
|
}
|
|
|
|
function closeOverview(): string {
|
|
if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) {
|
|
return "HYPR_NOT_AVAILABLE";
|
|
}
|
|
root.hyprlandOverviewLoader.item.overviewOpen = false;
|
|
return "OVERVIEW_CLOSE_SUCCESS";
|
|
}
|
|
|
|
function openOverview(): string {
|
|
if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) {
|
|
return "HYPR_NOT_AVAILABLE";
|
|
}
|
|
root.hyprlandOverviewLoader.item.overviewOpen = true;
|
|
return "OVERVIEW_OPEN_SUCCESS";
|
|
}
|
|
|
|
target: "hypr"
|
|
}
|
|
|
|
// ! TODO - remove for v1.6
|
|
IpcHandler {
|
|
function wallpaper(): string {
|
|
if (PopoutService.routeToIsland("wallpaper", null, true))
|
|
return "WARN; deprecated, use dms ipc call dash toggle wallpaper instead";
|
|
const bar = root.getPreferredBar("clockButtonRef") || root.getPreferredBar();
|
|
if (bar) {
|
|
bar.triggerWallpaperBrowser();
|
|
return "WARN; deprecated, use dms ipc call dash toggle wallpaper instead";
|
|
}
|
|
return "ERROR: Failed to toggle wallpaper browser";
|
|
}
|
|
|
|
target: "dankdash"
|
|
}
|
|
|
|
function getBarConfig(selector: string, value: string): var {
|
|
const barSelectors = ["id", "name", "index"];
|
|
if (!barSelectors.includes(selector))
|
|
return {
|
|
error: "BAR_INVALID_SELECTOR"
|
|
};
|
|
const index = selector === "index" ? Number(value) : SettingsData.barConfigs.findIndex(bar => bar[selector] == value);
|
|
const barConfig = SettingsData.barConfigs?.[index];
|
|
if (!barConfig)
|
|
return {
|
|
error: "BAR_NOT_FOUND"
|
|
};
|
|
return {
|
|
barConfig
|
|
};
|
|
}
|
|
|
|
function withBarConfig(selector: string, value: string, allowIsland: bool, action: var): string {
|
|
const {
|
|
barConfig,
|
|
error
|
|
} = getBarConfig(selector, value);
|
|
if (error)
|
|
return error;
|
|
if (!allowIsland && SettingsData.isIslandBarConfig(barConfig))
|
|
return "BAR_IS_ISLAND";
|
|
return action(barConfig);
|
|
}
|
|
|
|
IpcHandler {
|
|
function reveal(selector: string, value: string): string {
|
|
return withBarConfig(selector, value, false, bar => {
|
|
SettingsData.updateBarConfig(bar.id, {
|
|
visible: true
|
|
});
|
|
return "BAR_SHOW_SUCCESS";
|
|
});
|
|
}
|
|
|
|
function hide(selector: string, value: string): string {
|
|
return withBarConfig(selector, value, false, bar => {
|
|
SettingsData.updateBarConfig(bar.id, {
|
|
visible: false
|
|
});
|
|
return "BAR_HIDE_SUCCESS";
|
|
});
|
|
}
|
|
|
|
function toggle(selector: string, value: string): string {
|
|
return withBarConfig(selector, value, false, bar => {
|
|
SettingsData.updateBarConfig(bar.id, {
|
|
visible: !bar.visible
|
|
});
|
|
return !bar.visible ? "BAR_SHOW_SUCCESS" : "BAR_HIDE_SUCCESS";
|
|
});
|
|
}
|
|
|
|
function status(selector: string, value: string): string {
|
|
return withBarConfig(selector, value, true, bar => bar.visible ? "visible" : "hidden");
|
|
}
|
|
|
|
function autoHide(selector: string, value: string): string {
|
|
return withBarConfig(selector, value, false, bar => {
|
|
SettingsData.updateBarConfig(bar.id, {
|
|
autoHide: true
|
|
});
|
|
return "BAR_AUTO_HIDE_SUCCESS";
|
|
});
|
|
}
|
|
|
|
function manualHide(selector: string, value: string): string {
|
|
return withBarConfig(selector, value, false, bar => {
|
|
SettingsData.updateBarConfig(bar.id, {
|
|
autoHide: false
|
|
});
|
|
return "BAR_MANUAL_HIDE_SUCCESS";
|
|
});
|
|
}
|
|
|
|
function toggleAutoHide(selector: string, value: string): string {
|
|
return withBarConfig(selector, value, false, bar => {
|
|
SettingsData.updateBarConfig(bar.id, {
|
|
autoHide: !bar.autoHide
|
|
});
|
|
return bar.autoHide ? "BAR_MANUAL_HIDE_SUCCESS" : "BAR_AUTO_HIDE_SUCCESS";
|
|
});
|
|
}
|
|
|
|
function toggleReveal(selector: string, value: string): string {
|
|
return withBarConfig(selector, value, false, bar => {
|
|
if (!bar.autoHide)
|
|
return "BAR_AUTO_HIDE_DISABLED";
|
|
if (!(bar.visible ?? true)) {
|
|
SettingsData.updateBarConfig(bar.id, {
|
|
visible: true
|
|
});
|
|
SettingsData.setBarIpcReveal(bar.id, true);
|
|
return "BAR_REVEAL_SUCCESS";
|
|
}
|
|
const revealed = SettingsData.toggleBarIpcReveal(bar.id);
|
|
return revealed ? "BAR_REVEAL_SUCCESS" : "BAR_TUCK_SUCCESS";
|
|
});
|
|
}
|
|
|
|
function getPosition(selector: string, value: string): string {
|
|
return withBarConfig(selector, value, true, bar => ["top", "bottom", "left", "right"][bar.position] || "unknown");
|
|
}
|
|
|
|
function setPosition(selector: string, value: string, position: string): string {
|
|
return withBarConfig(selector, value, true, bar => {
|
|
const positionMap = {
|
|
"top": SettingsData.Position.Top,
|
|
"bottom": SettingsData.Position.Bottom,
|
|
"left": SettingsData.Position.Left,
|
|
"right": SettingsData.Position.Right
|
|
};
|
|
const posValue = positionMap[position.toLowerCase()];
|
|
if (posValue === undefined)
|
|
return "BAR_INVALID_POSITION";
|
|
SettingsData.updateBarConfig(bar.id, {
|
|
position: posValue
|
|
});
|
|
return "BAR_POSITION_SET_SUCCESS";
|
|
});
|
|
}
|
|
|
|
target: "bar"
|
|
}
|
|
|
|
// Outside the handler so it stays a helper rather than a callable dock command.
|
|
function dockConfigFor(selector: string): var {
|
|
return SettingsData.dockConfigForAction(BarWidgetService.getFocusedScreenName(), selector);
|
|
}
|
|
|
|
IpcHandler {
|
|
target: "dock"
|
|
|
|
function reveal(): string {
|
|
return revealFor("");
|
|
}
|
|
function hide(): string {
|
|
return hideFor("");
|
|
}
|
|
function toggle(): string {
|
|
return toggleFor("");
|
|
}
|
|
function status(): string {
|
|
return statusFor("");
|
|
}
|
|
function revealFor(selector: string): string {
|
|
const config = root.dockConfigFor(selector);
|
|
if (!config)
|
|
return "DOCK_NOT_FOUND";
|
|
SettingsData.updateDockConfig(config.id, {
|
|
enabled: true
|
|
});
|
|
return "DOCK_SHOW_SUCCESS";
|
|
}
|
|
function hideFor(selector: string): string {
|
|
const config = root.dockConfigFor(selector);
|
|
if (!config)
|
|
return "DOCK_NOT_FOUND";
|
|
SettingsData.updateDockConfig(config.id, {
|
|
enabled: false
|
|
});
|
|
return "DOCK_HIDE_SUCCESS";
|
|
}
|
|
function toggleFor(selector: string): string {
|
|
const config = root.dockConfigFor(selector);
|
|
if (!config)
|
|
return "DOCK_NOT_FOUND";
|
|
return config.enabled ? hideFor(config.id) : revealFor(config.id);
|
|
}
|
|
function statusFor(selector: string): string {
|
|
const config = root.dockConfigFor(selector);
|
|
return config ? (config.enabled ? "visible" : "hidden") : "DOCK_NOT_FOUND";
|
|
}
|
|
function edit(): string {
|
|
return editFor("");
|
|
}
|
|
function editFor(selector: string): string {
|
|
const config = root.dockConfigFor(selector);
|
|
if (!config)
|
|
return "DOCK_NOT_FOUND";
|
|
if (!config.enabled)
|
|
return "DOCK_HIDDEN";
|
|
BarWidgetService.dockEditRequested(config.id);
|
|
return "DOCK_EDIT_SUCCESS";
|
|
}
|
|
function autoHide(): string {
|
|
return autoHideFor("", true);
|
|
}
|
|
function manualHide(): string {
|
|
return autoHideFor("", false);
|
|
}
|
|
function toggleAutoHide(): string {
|
|
const config = root.dockConfigFor("");
|
|
if (!config)
|
|
return "DOCK_NOT_FOUND";
|
|
return autoHideFor(config.id, !config.autoHide);
|
|
}
|
|
function autoHideFor(selector: string, enabled: bool): string {
|
|
const config = root.dockConfigFor(selector);
|
|
if (!config)
|
|
return "DOCK_NOT_FOUND";
|
|
SettingsData.updateDockConfig(config.id, {
|
|
autoHide: enabled,
|
|
smartAutoHide: false
|
|
});
|
|
return enabled ? "BAR_AUTO_HIDE_SUCCESS" : "BAR_MANUAL_HIDE_SUCCESS";
|
|
}
|
|
}
|
|
|
|
IpcHandler {
|
|
function open(): string {
|
|
PopoutService.openSettings();
|
|
return "SETTINGS_OPEN_SUCCESS";
|
|
}
|
|
|
|
function openWith(tab: string): string {
|
|
if (!tab)
|
|
return "SETTINGS_OPEN_FAILED: No tab specified";
|
|
if (!SettingsTabs.resolvePage(tab))
|
|
return `SETTINGS_OPEN_FAILED: Unknown tab ${tab}`;
|
|
PopoutService.openSettingsWithTab(tab);
|
|
return `SETTINGS_OPEN_SUCCESS: ${tab}`;
|
|
}
|
|
|
|
function close(): string {
|
|
PopoutService.closeSettings();
|
|
return "SETTINGS_CLOSE_SUCCESS";
|
|
}
|
|
|
|
function toggle(): string {
|
|
PopoutService.toggleSettings();
|
|
return "SETTINGS_TOGGLE_SUCCESS";
|
|
}
|
|
|
|
function toggleWith(tab: string): string {
|
|
if (!tab)
|
|
return "SETTINGS_TOGGLE_FAILED: No tab specified";
|
|
if (!SettingsTabs.resolvePage(tab))
|
|
return `SETTINGS_TOGGLE_FAILED: Unknown tab ${tab}`;
|
|
PopoutService.toggleSettingsWithTab(tab);
|
|
return `SETTINGS_TOGGLE_SUCCESS: ${tab}`;
|
|
}
|
|
|
|
function focusOrToggle(): string {
|
|
PopoutService.focusOrToggleSettings();
|
|
return "SETTINGS_FOCUS_OR_TOGGLE_SUCCESS";
|
|
}
|
|
|
|
function focusOrToggleWith(tab: string): string {
|
|
if (!tab)
|
|
return "SETTINGS_FOCUS_OR_TOGGLE_FAILED: No tab specified";
|
|
if (!SettingsTabs.resolvePage(tab))
|
|
return `SETTINGS_FOCUS_OR_TOGGLE_FAILED: Unknown tab ${tab}`;
|
|
PopoutService.focusOrToggleSettingsWithTab(tab);
|
|
return `SETTINGS_FOCUS_OR_TOGGLE_SUCCESS: ${tab}`;
|
|
}
|
|
|
|
function tabs(): string {
|
|
return SettingsTabs.listPageIds().join("\n");
|
|
}
|
|
|
|
function get(key: string): string {
|
|
return JSON.stringify(SettingsData?.[key]);
|
|
}
|
|
|
|
function dump(): string {
|
|
return SettingsData.getCurrentSettingsJson();
|
|
}
|
|
|
|
function dumpSession(): string {
|
|
return SessionData.getCurrentSessionJson();
|
|
}
|
|
|
|
function set(key: string, value: string): string {
|
|
if (!(key in SettingsData)) {
|
|
log.warn("Cannot set property, not found:", key);
|
|
return "SETTINGS_INVALID_KEY";
|
|
}
|
|
|
|
const typeName = typeof SettingsData?.[key];
|
|
|
|
try {
|
|
switch (typeName) {
|
|
case "boolean":
|
|
if (value === "true" || value === "false")
|
|
value = (value === "true");
|
|
else
|
|
throw `${value} is not a Boolean`;
|
|
break;
|
|
case "number":
|
|
value = Number(value);
|
|
if (isNaN(value))
|
|
throw `${value} is not a Number`;
|
|
break;
|
|
case "string":
|
|
value = String(value);
|
|
break;
|
|
case "object":
|
|
// NOTE: Parsing lists is messed up upstream and not sure if we want
|
|
// to make sure objects are well structured or just let people set
|
|
// whatever they want but risking messed up settings.
|
|
// Objects & Arrays are disabled for now
|
|
// https://github.com/quickshell-mirror/quickshell/pull/22
|
|
throw "Setting Objects and Arrays not supported";
|
|
default:
|
|
throw "Unsupported type";
|
|
}
|
|
|
|
log.warn("Setting:", key, value);
|
|
SettingsData[key] = value;
|
|
SettingsData.saveSettings();
|
|
return "SETTINGS_SET_SUCCESS";
|
|
} catch (e) {
|
|
log.warn("Failed to set property:", key, "error:", e);
|
|
return "SETTINGS_SET_FAILURE";
|
|
}
|
|
}
|
|
|
|
target: "settings"
|
|
}
|
|
|
|
IpcHandler {
|
|
function browse(type: string) {
|
|
const modal = PopoutService.settingsModal;
|
|
if (modal) {
|
|
if (type === "wallpaper") {
|
|
modal.openWallpaperBrowser(false);
|
|
} else if (type === "profile") {
|
|
modal.openProfileBrowser(false);
|
|
}
|
|
} else {
|
|
PopoutService.openSettings();
|
|
}
|
|
}
|
|
|
|
target: "file"
|
|
}
|
|
|
|
IpcHandler {
|
|
function toggle(widgetId: string): string {
|
|
if (!widgetId)
|
|
return "ERROR: No widget ID specified";
|
|
|
|
if (!BarWidgetService.hasWidget(widgetId))
|
|
return `WIDGET_NOT_FOUND: ${widgetId}`;
|
|
|
|
const success = BarWidgetService.triggerWidgetPopout(widgetId);
|
|
return success ? `WIDGET_TOGGLE_SUCCESS: ${widgetId}` : `WIDGET_TOGGLE_FAILED: ${widgetId}`;
|
|
}
|
|
|
|
function openWith(widgetId: string, mode: string): string {
|
|
if (!widgetId)
|
|
return "ERROR: No widget ID specified";
|
|
if (!BarWidgetService.hasWidget(widgetId))
|
|
return `WIDGET_NOT_FOUND: ${widgetId}`;
|
|
|
|
const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId);
|
|
if (!widget)
|
|
return `WIDGET_NOT_AVAILABLE: ${widgetId}`;
|
|
if (typeof widget.openWithMode !== "function")
|
|
return `WIDGET_OPEN_WITH_NOT_SUPPORTED: ${widgetId}`;
|
|
|
|
widget.openWithMode(mode || "all");
|
|
return `WIDGET_OPEN_WITH_SUCCESS: ${widgetId} ${mode}`;
|
|
}
|
|
|
|
function toggleWith(widgetId: string, mode: string): string {
|
|
if (!widgetId)
|
|
return "ERROR: No widget ID specified";
|
|
if (!BarWidgetService.hasWidget(widgetId))
|
|
return `WIDGET_NOT_FOUND: ${widgetId}`;
|
|
|
|
const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId);
|
|
if (!widget)
|
|
return `WIDGET_NOT_AVAILABLE: ${widgetId}`;
|
|
if (typeof widget.toggleWithMode !== "function")
|
|
return `WIDGET_TOGGLE_WITH_NOT_SUPPORTED: ${widgetId}`;
|
|
|
|
widget.toggleWithMode(mode || "all");
|
|
return `WIDGET_TOGGLE_WITH_SUCCESS: ${widgetId} ${mode}`;
|
|
}
|
|
|
|
function openQuery(widgetId: string, query: string): string {
|
|
if (!widgetId)
|
|
return "ERROR: No widget ID specified";
|
|
if (!BarWidgetService.hasWidget(widgetId))
|
|
return `WIDGET_NOT_FOUND: ${widgetId}`;
|
|
|
|
const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId);
|
|
if (!widget)
|
|
return `WIDGET_NOT_AVAILABLE: ${widgetId}`;
|
|
if (typeof widget.openWithQuery !== "function")
|
|
return `WIDGET_OPEN_QUERY_NOT_SUPPORTED: ${widgetId}`;
|
|
|
|
widget.openWithQuery(query || "");
|
|
return `WIDGET_OPEN_QUERY_SUCCESS: ${widgetId}`;
|
|
}
|
|
|
|
function toggleQuery(widgetId: string, query: string): string {
|
|
if (!widgetId)
|
|
return "ERROR: No widget ID specified";
|
|
if (!BarWidgetService.hasWidget(widgetId))
|
|
return `WIDGET_NOT_FOUND: ${widgetId}`;
|
|
|
|
const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId);
|
|
if (!widget)
|
|
return `WIDGET_NOT_AVAILABLE: ${widgetId}`;
|
|
if (typeof widget.toggleWithQuery !== "function")
|
|
return `WIDGET_TOGGLE_QUERY_NOT_SUPPORTED: ${widgetId}`;
|
|
|
|
widget.toggleWithQuery(query || "");
|
|
return `WIDGET_TOGGLE_QUERY_SUCCESS: ${widgetId}`;
|
|
}
|
|
|
|
function list(): string {
|
|
const widgets = BarWidgetService.getRegisteredWidgetIds();
|
|
if (widgets.length === 0)
|
|
return "No widgets registered";
|
|
|
|
const lines = [];
|
|
for (const widgetId of widgets) {
|
|
const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId);
|
|
let state = "";
|
|
if (widget?.effectiveVisible !== undefined)
|
|
state = widget.effectiveVisible ? " [visible]" : " [hidden]";
|
|
lines.push(widgetId + state);
|
|
}
|
|
return lines.join("\n");
|
|
}
|
|
|
|
function status(widgetId: string): string {
|
|
if (!widgetId)
|
|
return "ERROR: No widget ID specified";
|
|
|
|
if (!BarWidgetService.hasWidget(widgetId))
|
|
return `WIDGET_NOT_FOUND: ${widgetId}`;
|
|
|
|
const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId);
|
|
if (!widget)
|
|
return `WIDGET_NOT_AVAILABLE: ${widgetId}`;
|
|
|
|
if (!widget.popoutTarget)
|
|
return `WIDGET_NO_POPOUT: ${widgetId}`;
|
|
return widget.popoutTarget.shouldBeVisible ? "visible" : "hidden";
|
|
}
|
|
|
|
function reveal(widgetId: string): string {
|
|
if (!widgetId)
|
|
return "ERROR: No widget ID specified";
|
|
|
|
if (!BarWidgetService.hasWidget(widgetId))
|
|
return `WIDGET_NOT_FOUND: ${widgetId}`;
|
|
|
|
const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId);
|
|
if (!widget)
|
|
return `WIDGET_NOT_AVAILABLE: ${widgetId}`;
|
|
|
|
if (typeof widget.setVisibilityOverride === "function") {
|
|
widget.setVisibilityOverride(true);
|
|
return `WIDGET_REVEAL_SUCCESS: ${widgetId}`;
|
|
}
|
|
return `WIDGET_REVEAL_NOT_SUPPORTED: ${widgetId}`;
|
|
}
|
|
|
|
function hide(widgetId: string): string {
|
|
if (!widgetId)
|
|
return "ERROR: No widget ID specified";
|
|
|
|
if (!BarWidgetService.hasWidget(widgetId))
|
|
return `WIDGET_NOT_FOUND: ${widgetId}`;
|
|
|
|
const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId);
|
|
if (!widget)
|
|
return `WIDGET_NOT_AVAILABLE: ${widgetId}`;
|
|
|
|
if (typeof widget.setVisibilityOverride === "function") {
|
|
widget.setVisibilityOverride(false);
|
|
return `WIDGET_HIDE_SUCCESS: ${widgetId}`;
|
|
}
|
|
return `WIDGET_HIDE_NOT_SUPPORTED: ${widgetId}`;
|
|
}
|
|
|
|
function reset(widgetId: string): string {
|
|
if (!widgetId)
|
|
return "ERROR: No widget ID specified";
|
|
|
|
if (!BarWidgetService.hasWidget(widgetId))
|
|
return `WIDGET_NOT_FOUND: ${widgetId}`;
|
|
|
|
const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId);
|
|
if (!widget)
|
|
return `WIDGET_NOT_AVAILABLE: ${widgetId}`;
|
|
|
|
if (typeof widget.clearVisibilityOverride === "function") {
|
|
widget.clearVisibilityOverride();
|
|
return `WIDGET_RESET_SUCCESS: ${widgetId}`;
|
|
}
|
|
return `WIDGET_RESET_NOT_SUPPORTED: ${widgetId}`;
|
|
}
|
|
|
|
function visibility(widgetId: string): string {
|
|
if (!widgetId)
|
|
return "ERROR: No widget ID specified";
|
|
|
|
if (!BarWidgetService.hasWidget(widgetId))
|
|
return `WIDGET_NOT_FOUND: ${widgetId}`;
|
|
|
|
const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId);
|
|
if (!widget)
|
|
return `WIDGET_NOT_AVAILABLE: ${widgetId}`;
|
|
|
|
if (widget.effectiveVisible !== undefined)
|
|
return widget.effectiveVisible ? "visible" : "hidden";
|
|
return "unknown";
|
|
}
|
|
|
|
target: "widget"
|
|
}
|
|
|
|
IpcHandler {
|
|
function reload(pluginId: string): string {
|
|
if (!pluginId)
|
|
return "ERROR: No plugin ID specified";
|
|
|
|
if (!PluginService.availablePlugins[pluginId])
|
|
return `PLUGIN_NOT_FOUND: ${pluginId}`;
|
|
|
|
if (!PluginService.isPluginLoaded(pluginId)) {
|
|
const success = PluginService.enablePlugin(pluginId);
|
|
return success ? `PLUGIN_RELOAD_SUCCESS: ${pluginId}` : `PLUGIN_RELOAD_FAILED: ${pluginId}`;
|
|
}
|
|
|
|
const success = PluginService.reloadPlugin(pluginId);
|
|
return success ? `PLUGIN_RELOAD_SUCCESS: ${pluginId}` : `PLUGIN_RELOAD_FAILED: ${pluginId}`;
|
|
}
|
|
|
|
function enable(pluginId: string): string {
|
|
if (!pluginId)
|
|
return "ERROR: No plugin ID specified";
|
|
|
|
if (!PluginService.availablePlugins[pluginId])
|
|
return `PLUGIN_NOT_FOUND: ${pluginId}`;
|
|
|
|
const success = PluginService.enablePlugin(pluginId);
|
|
return success ? `PLUGIN_ENABLE_SUCCESS: ${pluginId}` : `PLUGIN_ENABLE_FAILED: ${pluginId}`;
|
|
}
|
|
|
|
function disable(pluginId: string): string {
|
|
if (!pluginId)
|
|
return "ERROR: No plugin ID specified";
|
|
|
|
if (!PluginService.availablePlugins[pluginId])
|
|
return `PLUGIN_NOT_FOUND: ${pluginId}`;
|
|
|
|
const success = PluginService.disablePlugin(pluginId);
|
|
return success ? `PLUGIN_DISABLE_SUCCESS: ${pluginId}` : `PLUGIN_DISABLE_FAILED: ${pluginId}`;
|
|
}
|
|
|
|
function toggle(pluginId: string): string {
|
|
if (!pluginId)
|
|
return "ERROR: No plugin ID specified";
|
|
|
|
if (!PluginService.availablePlugins[pluginId])
|
|
return `PLUGIN_NOT_FOUND: ${pluginId}`;
|
|
|
|
const success = PluginService.togglePlugin(pluginId);
|
|
return success ? `PLUGIN_TOGGLE_SUCCESS: ${pluginId}` : `PLUGIN_TOGGLE_FAILED: ${pluginId}`;
|
|
}
|
|
|
|
function list(): string {
|
|
const plugins = PluginService.getAvailablePlugins();
|
|
if (plugins.length === 0)
|
|
return "No plugins available";
|
|
return plugins.map(p => `${p.id} [${p.loaded ? "loaded" : "disabled"}]`).join("\n");
|
|
}
|
|
|
|
function status(pluginId: string): string {
|
|
if (!pluginId)
|
|
return "ERROR: No plugin ID specified";
|
|
|
|
if (!PluginService.availablePlugins[pluginId])
|
|
return `PLUGIN_NOT_FOUND: ${pluginId}`;
|
|
|
|
return PluginService.isPluginLoaded(pluginId) ? "loaded" : "disabled";
|
|
}
|
|
|
|
target: "plugins"
|
|
}
|
|
|
|
IpcHandler {
|
|
function toggle(): string {
|
|
if (PopoutService.systemUpdatePopout?.shouldBeVisible) {
|
|
PopoutService.systemUpdatePopout.close();
|
|
return "SYSTEMUPDATER_TOGGLE_SUCCESS";
|
|
}
|
|
const bar = root.getPreferredBar("systemUpdateButtonRef");
|
|
if (bar) {
|
|
bar.triggerSystemUpdate();
|
|
return "SYSTEMUPDATER_TOGGLE_SUCCESS";
|
|
}
|
|
return "SYSTEMUPDATER_TOGGLE_FAILED";
|
|
}
|
|
|
|
function open(): string {
|
|
if (PopoutService.systemUpdatePopout?.shouldBeVisible)
|
|
return "SYSTEMUPDATER_ALREADY_OPEN";
|
|
const bar = root.getPreferredBar("systemUpdateButtonRef");
|
|
if (bar) {
|
|
bar.triggerSystemUpdate();
|
|
return "SYSTEMUPDATER_OPEN_SUCCESS";
|
|
}
|
|
return "SYSTEMUPDATER_OPEN_FAILED";
|
|
}
|
|
|
|
function close(): string {
|
|
PopoutService.closeSystemUpdate();
|
|
return "SYSTEMUPDATER_CLOSE_SUCCESS";
|
|
}
|
|
|
|
function updatestatus(): string {
|
|
if (SystemUpdateService.isChecking) {
|
|
return "ERROR: already checking";
|
|
}
|
|
if (SystemUpdateService.backends.length === 0) {
|
|
return "ERROR: no package manager available";
|
|
}
|
|
SystemUpdateService.checkForUpdates();
|
|
return "SUCCESS: Now checking...";
|
|
}
|
|
|
|
target: "systemupdater"
|
|
}
|
|
|
|
IpcHandler {
|
|
function open(): string {
|
|
if (!PopoutService.clipboardHistoryModal) {
|
|
return "CLIPBOARD_NOT_AVAILABLE";
|
|
}
|
|
PopoutService.clipboardHistoryModal.show();
|
|
return "CLIPBOARD_OPEN_SUCCESS";
|
|
}
|
|
|
|
function close(): string {
|
|
if (!PopoutService.clipboardHistoryModal) {
|
|
return "CLIPBOARD_NOT_AVAILABLE";
|
|
}
|
|
PopoutService.clipboardHistoryModal.hide();
|
|
return "CLIPBOARD_CLOSE_SUCCESS";
|
|
}
|
|
|
|
function toggle(): string {
|
|
if (!PopoutService.clipboardHistoryModal) {
|
|
return "CLIPBOARD_NOT_AVAILABLE";
|
|
}
|
|
PopoutService.clipboardHistoryModal.toggle();
|
|
return "CLIPBOARD_TOGGLE_SUCCESS";
|
|
}
|
|
|
|
target: "clipboard"
|
|
}
|
|
|
|
// ! spotlight and launcher should be synonymous for backwards compat
|
|
IpcHandler {
|
|
function open(): string {
|
|
PopoutService.openDankLauncherV2();
|
|
return "LAUNCHER_OPEN_SUCCESS";
|
|
}
|
|
|
|
function close(): string {
|
|
PopoutService.closeDankLauncherV2();
|
|
return "LAUNCHER_CLOSE_SUCCESS";
|
|
}
|
|
|
|
function toggle(): string {
|
|
PopoutService.toggleDankLauncherV2();
|
|
return "LAUNCHER_TOGGLE_SUCCESS";
|
|
}
|
|
|
|
function openWith(mode: string): string {
|
|
if (!mode)
|
|
return "LAUNCHER_OPEN_FAILED: No mode specified";
|
|
PopoutService.openDankLauncherV2WithMode(mode);
|
|
return `LAUNCHER_OPEN_SUCCESS: ${mode}`;
|
|
}
|
|
|
|
function toggleWith(mode: string): string {
|
|
if (!mode)
|
|
return "LAUNCHER_TOGGLE_FAILED: No mode specified";
|
|
PopoutService.toggleDankLauncherV2WithMode(mode);
|
|
return `LAUNCHER_TOGGLE_SUCCESS: ${mode}`;
|
|
}
|
|
|
|
function openQuery(query: string): string {
|
|
PopoutService.openDankLauncherV2WithQuery(query);
|
|
return "LAUNCHER_OPEN_QUERY_SUCCESS";
|
|
}
|
|
|
|
function toggleQuery(query: string): string {
|
|
PopoutService.toggleDankLauncherV2WithQuery(query);
|
|
return "LAUNCHER_TOGGLE_QUERY_SUCCESS";
|
|
}
|
|
|
|
target: "launcher"
|
|
}
|
|
|
|
// ! spotlight and launcher should be synonymous for backwards compat
|
|
IpcHandler {
|
|
function open(): string {
|
|
PopoutService.openDankLauncherV2();
|
|
return "SPOTLIGHT_OPEN_SUCCESS";
|
|
}
|
|
|
|
function close(): string {
|
|
PopoutService.closeDankLauncherV2();
|
|
return "SPOTLIGHT_CLOSE_SUCCESS";
|
|
}
|
|
|
|
function toggle(): string {
|
|
PopoutService.toggleDankLauncherV2();
|
|
return "SPOTLIGHT_TOGGLE_SUCCESS";
|
|
}
|
|
|
|
function openWith(mode: string): string {
|
|
if (!mode)
|
|
return "SPOTLIGHT_OPEN_FAILED: No mode specified";
|
|
PopoutService.openDankLauncherV2WithMode(mode);
|
|
return `SPOTLIGHT_OPEN_SUCCESS: ${mode}`;
|
|
}
|
|
|
|
function toggleWith(mode: string): string {
|
|
if (!mode)
|
|
return "SPOTLIGHT_TOGGLE_FAILED: No mode specified";
|
|
PopoutService.toggleDankLauncherV2WithMode(mode);
|
|
return `SPOTLIGHT_TOGGLE_SUCCESS: ${mode}`;
|
|
}
|
|
|
|
function openQuery(query: string): string {
|
|
PopoutService.openDankLauncherV2WithQuery(query);
|
|
return "SPOTLIGHT_OPEN_QUERY_SUCCESS";
|
|
}
|
|
|
|
function toggleQuery(query: string): string {
|
|
PopoutService.toggleDankLauncherV2WithQuery(query);
|
|
return "SPOTLIGHT_TOGGLE_QUERY_SUCCESS";
|
|
}
|
|
|
|
target: "spotlight"
|
|
}
|
|
|
|
IpcHandler {
|
|
function open(): string {
|
|
PopoutService.openSpotlightBar();
|
|
return "SPOTLIGHT_BAR_OPEN_SUCCESS";
|
|
}
|
|
|
|
function close(): string {
|
|
PopoutService.closeSpotlightBar();
|
|
return "SPOTLIGHT_BAR_CLOSE_SUCCESS";
|
|
}
|
|
|
|
function toggle(): string {
|
|
PopoutService.toggleSpotlightBar();
|
|
return "SPOTLIGHT_BAR_TOGGLE_SUCCESS";
|
|
}
|
|
|
|
function openWith(mode: string): string {
|
|
if (!mode)
|
|
return "SPOTLIGHT_BAR_OPEN_FAILED: No mode specified";
|
|
PopoutService.openSpotlightBarWithMode(mode);
|
|
return `SPOTLIGHT_BAR_OPEN_SUCCESS: ${mode}`;
|
|
}
|
|
|
|
function toggleWith(mode: string): string {
|
|
if (!mode)
|
|
return "SPOTLIGHT_BAR_TOGGLE_FAILED: No mode specified";
|
|
PopoutService.toggleSpotlightBarWithMode(mode);
|
|
return `SPOTLIGHT_BAR_TOGGLE_SUCCESS: ${mode}`;
|
|
}
|
|
|
|
function openQuery(query: string): string {
|
|
PopoutService.openSpotlightBarWithQuery(query);
|
|
return "SPOTLIGHT_BAR_OPEN_QUERY_SUCCESS";
|
|
}
|
|
|
|
function toggleQuery(query: string): string {
|
|
PopoutService.toggleSpotlightBarWithQuery(query);
|
|
return "SPOTLIGHT_BAR_TOGGLE_QUERY_SUCCESS";
|
|
}
|
|
|
|
target: "spotlight-bar"
|
|
}
|
|
|
|
IpcHandler {
|
|
function info(message: string): string {
|
|
if (!message)
|
|
return "ERROR: No message specified";
|
|
|
|
ToastService.showInfo(message);
|
|
return "TOAST_INFO_SUCCESS";
|
|
}
|
|
|
|
function infoWith(message: string, details: string, command: string, category: string): string {
|
|
if (!message)
|
|
return "ERROR: No message specified";
|
|
|
|
ToastService.showInfo(message, details, command, category);
|
|
return "TOAST_INFO_SUCCESS";
|
|
}
|
|
|
|
function warn(message: string): string {
|
|
if (!message)
|
|
return "ERROR: No message specified";
|
|
|
|
ToastService.showWarning(message);
|
|
return "TOAST_WARN_SUCCESS";
|
|
}
|
|
|
|
function warnWith(message: string, details: string, command: string, category: string): string {
|
|
if (!message)
|
|
return "ERROR: No message specified";
|
|
|
|
ToastService.showWarning(message, details, command, category);
|
|
return "TOAST_WARN_SUCCESS";
|
|
}
|
|
|
|
function error(message: string): string {
|
|
if (!message)
|
|
return "ERROR: No message specified";
|
|
|
|
ToastService.showError(message);
|
|
return "TOAST_ERROR_SUCCESS";
|
|
}
|
|
|
|
function errorWith(message: string, details: string, command: string, category: string): string {
|
|
if (!message)
|
|
return "ERROR: No message specified";
|
|
|
|
ToastService.showError(message, details, command, category);
|
|
return "TOAST_ERROR_SUCCESS";
|
|
}
|
|
|
|
function hide(): string {
|
|
ToastService.hideToast();
|
|
return "TOAST_HIDE_SUCCESS";
|
|
}
|
|
|
|
function dismiss(category: string): string {
|
|
if (!category)
|
|
return "ERROR: No category specified";
|
|
|
|
ToastService.dismissCategory(category);
|
|
return "TOAST_DISMISS_SUCCESS";
|
|
}
|
|
|
|
function status(): string {
|
|
if (!ToastService.toastVisible)
|
|
return "hidden";
|
|
|
|
const levels = ["info", "warn", "error"];
|
|
return `visible:${levels[ToastService.currentLevel]}:${ToastService.currentMessage}`;
|
|
}
|
|
|
|
target: "toast"
|
|
}
|
|
|
|
IpcHandler {
|
|
function open(): string {
|
|
FirstLaunchService.showWelcome();
|
|
return "WELCOME_OPEN_SUCCESS";
|
|
}
|
|
|
|
function doctor(): string {
|
|
FirstLaunchService.showDoctor();
|
|
return "WELCOME_DOCTOR_SUCCESS";
|
|
}
|
|
|
|
function page(pageNum: string): string {
|
|
const num = parseInt(pageNum) || 0;
|
|
FirstLaunchService.showGreeter(num);
|
|
return `WELCOME_PAGE_SUCCESS: ${num}`;
|
|
}
|
|
|
|
target: "welcome"
|
|
}
|
|
|
|
IpcHandler {
|
|
function toggleOverlay(instanceId: string): string {
|
|
if (!instanceId)
|
|
return "ERROR: No instance ID specified";
|
|
|
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
|
if (!instance)
|
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
|
|
|
const currentValue = instance.config?.showOnOverlay ?? false;
|
|
SettingsData.updateDesktopWidgetInstanceConfig(instanceId, {
|
|
showOnOverlay: !currentValue
|
|
});
|
|
return !currentValue ? `DESKTOP_WIDGET_OVERLAY_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_OVERLAY_DISABLED: ${instanceId}`;
|
|
}
|
|
|
|
function setOverlay(instanceId: string, enabled: string): string {
|
|
if (!instanceId)
|
|
return "ERROR: No instance ID specified";
|
|
|
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
|
if (!instance)
|
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
|
|
|
const enabledBool = enabled === "true" || enabled === "1";
|
|
SettingsData.updateDesktopWidgetInstanceConfig(instanceId, {
|
|
showOnOverlay: enabledBool
|
|
});
|
|
return enabledBool ? `DESKTOP_WIDGET_OVERLAY_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_OVERLAY_DISABLED: ${instanceId}`;
|
|
}
|
|
|
|
function list(): string {
|
|
const instances = SettingsData.desktopWidgetInstances || [];
|
|
if (instances.length === 0)
|
|
return "No desktop widgets configured";
|
|
return instances.map(i => `${i.id} [${i.widgetType}] ${i.name || i.widgetType} ${i.enabled ? "[enabled]" : "[disabled]"}`).join("\n");
|
|
}
|
|
|
|
function status(instanceId: string): string {
|
|
if (!instanceId)
|
|
return "ERROR: No instance ID specified";
|
|
|
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
|
if (!instance)
|
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
|
|
|
const enabled = instance.enabled ?? true;
|
|
const overlay = instance.config?.showOnOverlay ?? false;
|
|
const overview = instance.config?.showOnOverview ?? false;
|
|
const clickThrough = instance.config?.clickThrough ?? false;
|
|
const syncPosition = instance.config?.syncPositionAcrossScreens ?? false;
|
|
return `enabled: ${enabled}, overlay: ${overlay}, overview: ${overview}, clickThrough: ${clickThrough}, syncPosition: ${syncPosition}`;
|
|
}
|
|
|
|
function enable(instanceId: string): string {
|
|
if (!instanceId)
|
|
return "ERROR: No instance ID specified";
|
|
|
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
|
if (!instance)
|
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
|
|
|
SettingsData.updateDesktopWidgetInstance(instanceId, {
|
|
enabled: true
|
|
});
|
|
return `DESKTOP_WIDGET_ENABLED: ${instanceId}`;
|
|
}
|
|
|
|
function disable(instanceId: string): string {
|
|
if (!instanceId)
|
|
return "ERROR: No instance ID specified";
|
|
|
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
|
if (!instance)
|
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
|
|
|
SettingsData.updateDesktopWidgetInstance(instanceId, {
|
|
enabled: false
|
|
});
|
|
return `DESKTOP_WIDGET_DISABLED: ${instanceId}`;
|
|
}
|
|
|
|
function toggleEnabled(instanceId: string): string {
|
|
if (!instanceId)
|
|
return "ERROR: No instance ID specified";
|
|
|
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
|
if (!instance)
|
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
|
|
|
const currentValue = instance.enabled ?? true;
|
|
SettingsData.updateDesktopWidgetInstance(instanceId, {
|
|
enabled: !currentValue
|
|
});
|
|
return !currentValue ? `DESKTOP_WIDGET_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_DISABLED: ${instanceId}`;
|
|
}
|
|
|
|
function toggleClickThrough(instanceId: string): string {
|
|
if (!instanceId)
|
|
return "ERROR: No instance ID specified";
|
|
|
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
|
if (!instance)
|
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
|
|
|
const currentValue = instance.config?.clickThrough ?? false;
|
|
SettingsData.updateDesktopWidgetInstanceConfig(instanceId, {
|
|
clickThrough: !currentValue
|
|
});
|
|
return !currentValue ? `DESKTOP_WIDGET_CLICK_THROUGH_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_CLICK_THROUGH_DISABLED: ${instanceId}`;
|
|
}
|
|
|
|
function setClickThrough(instanceId: string, enabled: string): string {
|
|
if (!instanceId)
|
|
return "ERROR: No instance ID specified";
|
|
|
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
|
if (!instance)
|
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
|
|
|
const enabledBool = enabled === "true" || enabled === "1";
|
|
SettingsData.updateDesktopWidgetInstanceConfig(instanceId, {
|
|
clickThrough: enabledBool
|
|
});
|
|
return enabledBool ? `DESKTOP_WIDGET_CLICK_THROUGH_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_CLICK_THROUGH_DISABLED: ${instanceId}`;
|
|
}
|
|
|
|
function toggleSyncPosition(instanceId: string): string {
|
|
if (!instanceId)
|
|
return "ERROR: No instance ID specified";
|
|
|
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
|
if (!instance)
|
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
|
|
|
const currentValue = instance.config?.syncPositionAcrossScreens ?? false;
|
|
SettingsData.updateDesktopWidgetInstanceConfig(instanceId, {
|
|
syncPositionAcrossScreens: !currentValue
|
|
});
|
|
return !currentValue ? `DESKTOP_WIDGET_SYNC_POSITION_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_SYNC_POSITION_DISABLED: ${instanceId}`;
|
|
}
|
|
|
|
function setSyncPosition(instanceId: string, enabled: string): string {
|
|
if (!instanceId)
|
|
return "ERROR: No instance ID specified";
|
|
|
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
|
if (!instance)
|
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
|
|
|
const enabledBool = enabled === "true" || enabled === "1";
|
|
SettingsData.updateDesktopWidgetInstanceConfig(instanceId, {
|
|
syncPositionAcrossScreens: enabledBool
|
|
});
|
|
return enabledBool ? `DESKTOP_WIDGET_SYNC_POSITION_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_SYNC_POSITION_DISABLED: ${instanceId}`;
|
|
}
|
|
|
|
target: "desktopWidget"
|
|
}
|
|
|
|
IpcHandler {
|
|
function open(): string {
|
|
root.workspaceRenameModalLoader.active = true;
|
|
if (root.workspaceRenameModalLoader.item) {
|
|
if (CompositorService.isAqueous)
|
|
return root.workspaceRenameModalLoader.item.show("") ? "WORKSPACE_RENAME_MODAL_OPENED" : "WORKSPACE_RENAME_UNAVAILABLE";
|
|
const ws = NiriService.workspaces[NiriService.focusedWorkspaceId];
|
|
root.workspaceRenameModalLoader.item.show(ws?.name || "");
|
|
return "WORKSPACE_RENAME_MODAL_OPENED";
|
|
}
|
|
return "WORKSPACE_RENAME_MODAL_NOT_FOUND";
|
|
}
|
|
|
|
function close(): string {
|
|
if (root.workspaceRenameModalLoader.item) {
|
|
root.workspaceRenameModalLoader.item.hide();
|
|
return "WORKSPACE_RENAME_MODAL_CLOSED";
|
|
}
|
|
return "WORKSPACE_RENAME_MODAL_NOT_FOUND";
|
|
}
|
|
|
|
function toggle(): string {
|
|
root.workspaceRenameModalLoader.active = true;
|
|
if (root.workspaceRenameModalLoader.item) {
|
|
if (root.workspaceRenameModalLoader.item.visible) {
|
|
root.workspaceRenameModalLoader.item.hide();
|
|
return "WORKSPACE_RENAME_MODAL_CLOSED";
|
|
}
|
|
if (CompositorService.isAqueous)
|
|
return root.workspaceRenameModalLoader.item.show("") ? "WORKSPACE_RENAME_MODAL_OPENED" : "WORKSPACE_RENAME_UNAVAILABLE";
|
|
const ws = NiriService.workspaces[NiriService.focusedWorkspaceId];
|
|
root.workspaceRenameModalLoader.item.show(ws?.name || "");
|
|
return "WORKSPACE_RENAME_MODAL_OPENED";
|
|
}
|
|
return "WORKSPACE_RENAME_MODAL_NOT_FOUND";
|
|
}
|
|
|
|
target: "workspace-rename"
|
|
}
|
|
|
|
IpcHandler {
|
|
function getFocusedWindow() {
|
|
const active = ToplevelManager.activeToplevel;
|
|
if (!active)
|
|
return null;
|
|
return {
|
|
appId: active.appId || "",
|
|
title: active.title || ""
|
|
};
|
|
}
|
|
|
|
function open(): string {
|
|
if (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isMango)
|
|
return "WINDOW_RULES_UNSUPPORTED_COMPOSITOR";
|
|
root.windowRuleModalLoader.active = true;
|
|
if (root.windowRuleModalLoader.item) {
|
|
root.windowRuleModalLoader.item.show(getFocusedWindow());
|
|
return "WINDOW_RULE_MODAL_OPENED";
|
|
}
|
|
return "WINDOW_RULE_MODAL_NOT_FOUND";
|
|
}
|
|
|
|
function close(): string {
|
|
if (root.windowRuleModalLoader.item) {
|
|
root.windowRuleModalLoader.item.hide();
|
|
return "WINDOW_RULE_MODAL_CLOSED";
|
|
}
|
|
return "WINDOW_RULE_MODAL_NOT_FOUND";
|
|
}
|
|
|
|
function toggle(): string {
|
|
if (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isMango)
|
|
return "WINDOW_RULES_UNSUPPORTED_COMPOSITOR";
|
|
root.windowRuleModalLoader.active = true;
|
|
if (root.windowRuleModalLoader.item) {
|
|
if (root.windowRuleModalLoader.item.visible) {
|
|
root.windowRuleModalLoader.item.hide();
|
|
return "WINDOW_RULE_MODAL_CLOSED";
|
|
}
|
|
root.windowRuleModalLoader.item.show(getFocusedWindow());
|
|
return "WINDOW_RULE_MODAL_OPENED";
|
|
}
|
|
return "WINDOW_RULE_MODAL_NOT_FOUND";
|
|
}
|
|
|
|
target: "window-rules"
|
|
}
|
|
|
|
IpcHandler {
|
|
function cycle(): string {
|
|
return NiriService.cycleSingleOutput();
|
|
}
|
|
|
|
function listProfiles(): string {
|
|
const profiles = DisplayConfigState.validatedProfiles;
|
|
const activeId = SessionData.getActiveDisplayProfile(CompositorService.compositor);
|
|
const matchedId = DisplayConfigState.matchedProfile;
|
|
const lines = [];
|
|
|
|
for (const id in profiles) {
|
|
const p = profiles[id];
|
|
if (!p.name)
|
|
continue;
|
|
const flags = [];
|
|
if (id === activeId)
|
|
flags.push("active");
|
|
if (id === matchedId)
|
|
flags.push("matched");
|
|
const flagStr = flags.length > 0 ? " [" + flags.join(",") + "]" : "";
|
|
lines.push(p.name + flagStr + " -> " + JSON.stringify(Object.keys(p.outputs)));
|
|
}
|
|
|
|
if (lines.length === 0)
|
|
return "No profiles configured";
|
|
return lines.join("\n");
|
|
}
|
|
|
|
function setProfile(profileName: string): string {
|
|
if (!profileName)
|
|
return "ERROR: No profile name specified";
|
|
|
|
if (SettingsData.displayProfileAutoSelect)
|
|
return "ERROR: Auto profile selection is enabled. Use toggleAuto first";
|
|
|
|
const profiles = DisplayConfigState.validatedProfiles;
|
|
let profileId = null;
|
|
|
|
for (const id in profiles) {
|
|
if (profiles[id].name === profileName) {
|
|
profileId = id;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!profileId)
|
|
return `ERROR: Profile not found: ${profileName}`;
|
|
|
|
DisplayConfigState.activateProfile(profileId);
|
|
return `PROFILE_SET_SUCCESS: ${profileName}`;
|
|
}
|
|
|
|
function cycleProfile(): string {
|
|
if (SettingsData.displayProfileAutoSelect)
|
|
return "ERROR: Auto profile selection is enabled. Use toggleAuto first";
|
|
|
|
const profiles = DisplayConfigState.validatedProfiles;
|
|
const ids = Object.keys(profiles).filter(id => profiles[id].name);
|
|
if (ids.length === 0)
|
|
return "ERROR: No profiles configured";
|
|
|
|
const activeId = SessionData.getActiveDisplayProfile(CompositorService.compositor);
|
|
const idx = ids.indexOf(activeId);
|
|
const nextId = ids[(idx + 1) % ids.length];
|
|
DisplayConfigState.activateProfile(nextId);
|
|
return `PROFILE_SET_SUCCESS: ${profiles[nextId].name}`;
|
|
}
|
|
|
|
function toggleAuto(): string {
|
|
SettingsData.displayProfileAutoSelect = !SettingsData.displayProfileAutoSelect;
|
|
SettingsData.saveSettings();
|
|
if (SettingsData.displayProfileAutoSelect)
|
|
DisplayConfigState.applyAutoConfig();
|
|
return `Auto profile selection: ${SettingsData.displayProfileAutoSelect ? "enabled" : "disabled"}`;
|
|
}
|
|
|
|
function status(): string {
|
|
const auto = SettingsData.displayProfileAutoSelect ? "on" : "off";
|
|
const activeId = SessionData.getActiveDisplayProfile(CompositorService.compositor);
|
|
const matchedId = DisplayConfigState.matchedProfile;
|
|
const profiles = DisplayConfigState.validatedProfiles;
|
|
const activeName = profiles[activeId]?.name || "none";
|
|
const matchedName = profiles[matchedId]?.name || "none";
|
|
const currentOutputs = JSON.stringify(DisplayConfigState.currentOutputSet);
|
|
|
|
return `auto: ${auto}\nactive: ${activeName}\nmatched: ${matchedName}\noutputs: ${currentOutputs}`;
|
|
}
|
|
|
|
function current(): string {
|
|
return JSON.stringify(DisplayConfigState.currentOutputSet);
|
|
}
|
|
|
|
function refresh(): string {
|
|
DisplayConfigState.currentOutputSet = DisplayConfigState.buildCurrentOutputSet();
|
|
DisplayConfigState.validateProfiles();
|
|
return "Refreshed output state";
|
|
}
|
|
|
|
target: "outputs"
|
|
}
|
|
|
|
IpcHandler {
|
|
target: "mic"
|
|
|
|
function setvolume(percentage: string): string {
|
|
return AudioService.setMicVolume(parseInt(percentage));
|
|
}
|
|
|
|
function increment(step: string): string {
|
|
return AudioService.incrementMicVolume(step);
|
|
}
|
|
|
|
function decrement(step: string): string {
|
|
return AudioService.decrementMicVolume(step);
|
|
}
|
|
|
|
function mute(): string {
|
|
return AudioService.toggleMicMute();
|
|
}
|
|
|
|
function status(): string {
|
|
if (!AudioService.source || !AudioService.source.audio) {
|
|
return "No audio source available";
|
|
}
|
|
|
|
const volume = Math.round(AudioService.source.audio.volume * 100);
|
|
const muteStatus = AudioService.source.audio.muted ? " (muted)" : "";
|
|
return `Microphone: ${volume}%${muteStatus}`;
|
|
}
|
|
}
|
|
|
|
IpcHandler {
|
|
function list(): string {
|
|
const items = SystemTray.items.values;
|
|
if (items.length === 0)
|
|
return "No tray items available";
|
|
|
|
return items.map(item => {
|
|
const id = item?.id || "";
|
|
const title = item?.tooltipTitle || "";
|
|
const fullKey = title ? `${id}::${title}` : id;
|
|
const hasMenu = item?.hasMenu ? " [menu]" : "";
|
|
return fullKey + hasMenu;
|
|
}).join("\n");
|
|
}
|
|
|
|
function activate(itemId: string): string {
|
|
const item = TrayMenuManager.findTrayItem(itemId);
|
|
if (!item)
|
|
return `ERROR: Tray item not found: ${itemId}`;
|
|
|
|
item.activate();
|
|
return `SUCCESS: Activated ${itemId}`;
|
|
}
|
|
|
|
function menu(itemId: string): string {
|
|
const item = TrayMenuManager.findTrayItem(itemId);
|
|
if (!item)
|
|
return `ERROR: Tray item not found: ${itemId}`;
|
|
|
|
if (!item.hasMenu)
|
|
return `ERROR: Tray item has no menu: ${itemId}`;
|
|
|
|
TrayMenuManager.requestOpenMenu(itemId, BarWidgetService.getFocusedScreenName());
|
|
return `SUCCESS: Requested menu ${itemId}`;
|
|
}
|
|
|
|
function status(itemId: string): string {
|
|
const item = TrayMenuManager.findTrayItem(itemId);
|
|
if (!item)
|
|
return `ERROR: Tray item not found: ${itemId}`;
|
|
|
|
const id = item?.id || "";
|
|
const title = item?.tooltipTitle || "";
|
|
const hasMenu = item?.hasMenu || false;
|
|
const onlyMenu = item?.onlyMenu || false;
|
|
|
|
return `id: ${id}\ntitle: ${title}\nhasMenu: ${hasMenu}\nonlyMenu: ${onlyMenu}`;
|
|
}
|
|
|
|
target: "tray"
|
|
}
|
|
|
|
IpcHandler {
|
|
function open(): string {
|
|
if (!PowerProfileWatcher.available)
|
|
return "ERROR: power-profiles-daemon not available";
|
|
|
|
PopoutService.openPowerProfileModal();
|
|
return "POWERPROFILE_OPEN_SUCCESS";
|
|
}
|
|
|
|
function close(): string {
|
|
PopoutService.closePowerProfileModal();
|
|
return "POWERPROFILE_CLOSE_SUCCESS";
|
|
}
|
|
|
|
function toggle(): string {
|
|
if (!PowerProfileWatcher.available)
|
|
return "ERROR: power-profiles-daemon not available";
|
|
|
|
PopoutService.togglePowerProfileModal();
|
|
return "POWERPROFILE_TOGGLE_SUCCESS";
|
|
}
|
|
|
|
function list(): string {
|
|
if (!PowerProfileWatcher.available)
|
|
return "ERROR: power-profiles-daemon not available";
|
|
|
|
return PowerProfileWatcher.availableProfiles.map(profile => PowerProfileWatcher.profileSlug(profile)).join("\n");
|
|
}
|
|
|
|
function status(): string {
|
|
if (!PowerProfileWatcher.available)
|
|
return "ERROR: power-profiles-daemon not available";
|
|
|
|
return PowerProfileWatcher.profileSlug(PowerProfiles.profile);
|
|
}
|
|
|
|
function set(profile: string): string {
|
|
if (!PowerProfileWatcher.available)
|
|
return "ERROR: power-profiles-daemon not available";
|
|
|
|
if (!profile)
|
|
return "ERROR: No profile specified";
|
|
|
|
const parsed = PowerProfileWatcher.parseProfileSlug(profile);
|
|
if (parsed === -1)
|
|
return "ERROR: Unknown power profile. Supported options: power-saver, balanced, performance";
|
|
|
|
if (parsed === PowerProfile.Performance && !PowerProfiles.hasPerformanceProfile)
|
|
return "ERROR: Performance profile not supported by hardware";
|
|
|
|
if (!PowerProfileWatcher.applyProfile(parsed))
|
|
return "ERROR: Failed to set power profile";
|
|
|
|
return "POWERPROFILE_SET_SUCCESS";
|
|
}
|
|
|
|
function cycle(): string {
|
|
if (!PowerProfileWatcher.available)
|
|
return "ERROR: power-profiles-daemon not available";
|
|
|
|
if (!PowerProfileWatcher.cycleProfile())
|
|
return "ERROR: Failed to set power profile";
|
|
|
|
return "POWERPROFILE_CYCLE_SUCCESS";
|
|
}
|
|
|
|
target: "powerprofile"
|
|
}
|
|
}
|