This document will explain how to create your own plugin.
- All the plugins are stored/installed at
~/.config/nucleus-shell/plugins - Each plugin should consist of these five files:
Main.qml,PluginConfigData.qml,Settings.qmlandmanifest.json - If any of these files are not present the plugin will not work or break.
Main.qml: This is the root file of the plugin all the files and other stuff should be iniatated in this file. You can also have other files and folders under a plugin.
Settings.qml: This is the file which has all the customizable options (for the settings app). Example File:
import QtQuick
import QtQuick.Layouts
import qs.plugins
import qs.modules.widgets
ColumnLayout {
spacing: 15
StyledText {
text: "Example - Plugin"
font.pixelSize: 20
font.bold: true
}
StyledSwitchOption {
title: "Enabled"
description: "Enable or disable the Example Plugin."
prefField: "plugins.example.enabled" // here "example" is the plugin id.
}
}- Note that the pluginId should be the folderName of the plugin under
~/.config/nucleus-shell/plugins/<pluginName> - Example: If the plugin folderName is
~/.config/nucleus-shell/plugins/examplePluginthe id should also be examplePlugin everywhere else inOrder for it to work.
PluginConfigData.qml: This file stores all the configuration options for the plugin. Example File:
pragma Singleton
import QtQuick
QtObject {
readonly property string pluginName: "example" // Should be present at all times.
readonly property var defaults: ({ // All the properties should be stored here. Anything outside of it will not be recognized by the shell.
enabled: true
})
}- Note that the properties should be accessed like this:
Config.runtime.plugins.pluginId.propertyunder all the plugin files not asPluginConfigData.defaults.enabled(this will not work because it is only a placeholder not the actual stored json file which gets edited)
manifest.json: This file stores all the additional information for the plugin. If this file is not present the plugin will not be validated by the shell. Example file:
{
"id": "example",
"name": "Example Plugin",
"version": "0.1.0",
"author": "unknown",
"description": "A example plugin",
"requires_nucleus": ">=1.2.3" # Examples: >0.2.1, >=0.4.0, =0.5.1
}Currently if you try to import or iniatiate a file like this in Main.qml or any other file you'll see a error like:
qrc:/Main.qml:XX:XX: File(The Other Initiated file) is not a typeto fix this problem you can add this into each file which initiates other types:
property string pluginPath: Directories.shellConfig + "/plugins/examplePlugin"
Component.onCompleted: {
Qt.application.engine.addImportPath(pluginPath)
}but there is a chance that this might not work realiably also try using loaders with explicit file paths:
Loader {
source: Directories.shellConfig + "/plugins/example/File.qml"
}If you want to create plugins like: Better-PowerMenu, Better-Bar, etc., you can use the Contracts service to override modules.
import QtQuick
import Quickshell
import qs.services // For Contracts
Scope {
Component.onCompleted: {
// Replace the default bar with your own
Contracts.bar.override(Qt.resolvedUrl("./MyBar.qml"))
}
}Component.onCompleted: {
Contracts.bar.disable()
}Component.onCompleted: {
if (Config.runtime.plugins.examplePlugin?.enabled !== true)
return
Contracts.bar.override(Qt.resolvedUrl("./MyBar.qml"))
}Contracts.bar.override(Qt.resolvedUrl("./MyBar.qml"))
Contracts.powerMenu.override(Qt.resolvedUrl("./MyPowerMenu.qml"))
Contracts.launcher.override(Qt.resolvedUrl("./MyLauncher.qml"))
Contracts.overlays.override(Qt.resolvedUrl("./MyOverlays.qml"))
Contracts.sidebarLeft.override(Qt.resolvedUrl("./MySidebarLeft.qml"))
Contracts.sidebarRight.override(Qt.resolvedUrl("./MySidebarRight.qml"))
Contracts.lockScreen.override(Qt.resolvedUrl("./MyLockScreen.qml"))
Contracts.notifications.override(Qt.resolvedUrl("./MyNotifications.qml"))
Contracts.background.override(Qt.resolvedUrl("./MyBackground.qml"))
Contracts.dock.override(Qt.resolvedUrl("./MyDock.qml"))
// Overriding Settings, IPC, or Globals is not allowedYou can read the state of any slot at any time:
console.log(Contracts.bar.overridden) // true if overridden by a plugin
console.log(Contracts.bar.disabled) // true if disabled
console.log(Contracts.bar.source) // the currently active URLTo distribute your plugin under the shell's database(this repo or other repos).
-
Fork this repository and push your plugin to the forked repo. Once you think that your plugin is complete make a PR and wait for your PR to get merged.
-
Other custom plugin repo's can be created by the community containing other plugins. If the repository is good enough and has multiple cool plugins it will be added in the plugin fetch utility as a [community] repository. Also note that the repo's should not contain multiple plugins with the same id. If present the repository to have being fetched before with the same pluginId will override other plugins.