Three DankMaterialShell plugins that render web content with Qt WebEngine and expose a small Qt WebChannel bridge to page JavaScript:
webviewBar: a DankBar widget whose popout hosts a webview.webviewControlCenter: a Control Center widget/detail panel that hosts a webview.webviewDesktop: a Desktop widget that hosts a webview.
Each plugin can render either a remote http:///https:// URL or one of the local HTML files shipped under that plugin's own html/ directory.
DankMaterialShell discovers plugins from QML directories under:
~/.config/DankMaterialShell/plugins/
Each direct child directory must contain a plugin.json manifest. This repository deliberately repeats the support QML files inside each plugin directory instead of creating a shared sibling directory under plugins/, because DMS scans each direct child and tries to load <dir>/plugin.json.
The manifests use the DMS documentation/schema fields:
idnamedescriptionversionauthortypecapabilitiescomponent- optional
settings - optional
requires_dms - optional
permissions
These plugin manifests also include a human-readable requires array for runtime prerequisites.
The renderer is WebEngineView from Qt WebEngine. Qt documents the QML import and APIs used here:
import QtWebEngineWebEngineView.urlWebEngineView.loadHtml()WebEngineView.newWindowRequestedWebEngineView.webChannel
The JavaScript bridge is WebChannel from Qt WebChannel. Qt documents:
import QtWebChannel 1.11registeredObjectsWebChannel.id- HTML clients can access QML object properties, signals, and public methods through
qwebchannel.js.
The bridge intentionally exposes only a narrow plugin API: context lookup, web popout open/close, close-self, runtime source changes, and selected DMS popout actions where the host injects a supported service.
These plugins are real WebEngine/WebChannel plugins. They do not implement a fake fallback webview.
The runtime needs Qt QML modules:
QtWebEngineQtWebChannel
On the current Arch workstation, the package names to try are:
sudo pacman -S qt6-webengine qt6-webchannelThe runtime also needs a Quickshell build equivalent to Quickshell PR #351, or a future Quickshell release containing the same initialization behavior. The original PR discussion used //@ pragma EnableQtWebEngineQuick; the tested mecattaf/quickshellX fork uses //@ pragma UseWebEngine instead, dynamically loads Qt6WebEngineQuick, and calls QtWebEngineQuick::initialize() before constructing QGuiApplication.
Putting either pragma in these plugin QML files is not enough. DMS plugins are loaded after Quickshell has already started, so WebEngineQuick initialization must be done by the host root shell.qml before application construction.
If the host crashes because of the PR #351 jemalloc issue after reporting successful QtWebEngineQuick initialization, the fix point is not plugin code. Build/test Quickshell without jemalloc, use a Quickshell build where Qt WebEngine works, or disable these plugins.
The repository includes a no-system-mutation test harness for the fork mentioned in PR #351:
./scripts/quickshellx-webengine-test.sh allOn Arch, the build/test preflight checks for git, cmake, ninja, qt6-base, qt6-declarative, qt6-wayland, qt6-webengine, qt6-webchannel, qt6-shadertools, cli11, and vulkan-headers. The script reports missing packages and exits; it never runs sudo.
The harness:
- clones
https://github.com/mecattaf/quickshellX.gitunder.quickshellx-test/; - builds it with
-DUSE_JEMALLOC=OFF; - installs it under
.quickshellx-test/prefix/; - copies
/usr/share/quickshell/dmsto.quickshellx-test/dms-root/; - inserts
//@ pragma UseWebEngineonly in that copied rootshell.qml; - copies these plugins to an isolated
XDG_CONFIG_HOME; - writes isolated DMS settings that enable the webview plugins for the test session;
- runs both a standalone WebEngine smoke config and the patched DMS root for a short duration.
It does not modify /usr/bin/qs, /usr/bin/quickshell, /usr/share/quickshell/dms, pacman state, or the normal user config. Logs are written under .quickshellx-test/logs/.
Cleanup:
./scripts/cleanup-quickshellx-webengine-test.shUseful overrides:
DMS_WEBVIEW_TEST_SECONDS=30 ./scripts/quickshellx-webengine-test.sh run-dms
QUICKSHELLX_REF=<branch-or-commit> ./scripts/quickshellx-webengine-test.sh allFrom this repository root:
./install.shThe installer only copies these exact plugin directories into ${XDG_CONFIG_HOME:-$HOME/.config}/DankMaterialShell/plugins:
plugins/WebviewBarplugins/WebviewControlCenterplugins/WebviewDesktop
It does not modify Quickshell, DMS root QML, shell configuration, package manager state, or the user's bar layout.
After installation:
- Open DMS Settings -> Plugins.
- Scan for plugins.
- Enable
webviewBar,webviewControlCenter, andwebviewDesktop. - Add
webviewBarto DankBar. - Add or enable the Control Center and Desktop surfaces through the DMS UI.
- Restart DMS or reload plugins.
Optional IPC reload commands:
dms ipc call plugins reload webviewBar
dms ipc call plugins reload webviewControlCenter
dms ipc call plugins reload webviewDesktop
dms ipc call plugins listRemote rendering accepts only http:// and https:// URLs.
Local rendering accepts only relative .html files under each plugin's own html/ directory, using paths such as ./html/bar.html or html/popup.html. Absolute paths, parent-directory traversal, file:, data:, javascript:, empty strings, and non-HTML files are rejected.
Page JavaScript cannot:
- run shell commands;
- write DMS settings;
- load arbitrary local files;
- access
pluginService; - access
popoutServicedirectly; - call arbitrary QML properties or methods.
Unknown or unavailable bridge actions return false or an empty string instead of throwing uncaught QML exceptions. Empty, missing, invalid, or failed sources show an in-plugin error panel instead of a blank webview.
Each plugin ships HTML examples that load:
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>The examples create window.dmsPluginReady, bind window.dmsPlugin = channel.objects.dmsPlugin, and then demonstrate local popouts, remote popouts, selected DMS popout actions, bridge context, and close-self behavior.
Remote pages are rendered as ordinary web pages. Their ability to call window.dmsPlugin depends on their own JavaScript and Content Security Policy.