fedora
This commit is contained in:
@@ -0,0 +1,346 @@
|
||||
pragma Singleton
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Modules.DesktopWidgets.Widgets
|
||||
import qs.Services.Noctalia
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
// Transient state - not persisted, resets on shell restart
|
||||
property bool editMode: false
|
||||
|
||||
// Signal emitted when plugin widgets are registered/unregistered
|
||||
signal pluginWidgetRegistryUpdated
|
||||
|
||||
// Component definitions
|
||||
property Component clockComponent: Component {
|
||||
DesktopClock {}
|
||||
}
|
||||
property Component mediaPlayerComponent: Component {
|
||||
DesktopMediaPlayer {}
|
||||
}
|
||||
property Component weatherComponent: Component {
|
||||
DesktopWeather {}
|
||||
}
|
||||
property Component systemStatComponent: Component {
|
||||
DesktopSystemStat {}
|
||||
}
|
||||
property Component audioVisualizerComponent: Component {
|
||||
DesktopAudioVisualizer {}
|
||||
}
|
||||
|
||||
// Widget registry object mapping widget names to components
|
||||
// Created in Component.onCompleted to ensure Components are ready
|
||||
property var widgets: ({})
|
||||
|
||||
// Explicit URLs for core widgets. Inline Component.url returns the parent
|
||||
// file's URL, so we need these for Loader.setSource() with initial properties.
|
||||
// Plugin widgets use their Component.url directly (loaded from actual files).
|
||||
readonly property string _widgetsDir: Quickshell.shellDir + "/Modules/DesktopWidgets/Widgets/"
|
||||
property var widgetUrls: ({})
|
||||
|
||||
Component.onCompleted: {
|
||||
// Initialize widgets object after Components are ready
|
||||
var widgetsObj = {};
|
||||
widgetsObj["Clock"] = clockComponent;
|
||||
widgetsObj["MediaPlayer"] = mediaPlayerComponent;
|
||||
widgetsObj["Weather"] = weatherComponent;
|
||||
widgetsObj["SystemStat"] = systemStatComponent;
|
||||
widgetsObj["AudioVisualizer"] = audioVisualizerComponent;
|
||||
widgets = widgetsObj;
|
||||
|
||||
var urlsObj = {};
|
||||
urlsObj["Clock"] = _widgetsDir + "DesktopClock.qml";
|
||||
urlsObj["MediaPlayer"] = _widgetsDir + "DesktopMediaPlayer.qml";
|
||||
urlsObj["Weather"] = _widgetsDir + "DesktopWeather.qml";
|
||||
urlsObj["SystemStat"] = _widgetsDir + "DesktopSystemStat.qml";
|
||||
urlsObj["AudioVisualizer"] = _widgetsDir + "DesktopAudioVisualizer.qml";
|
||||
widgetUrls = urlsObj;
|
||||
|
||||
Logger.i("DesktopWidgetRegistry", "Service started");
|
||||
}
|
||||
|
||||
property var widgetSettingsMap: ({
|
||||
"Clock": "WidgetSettings/ClockSettings.qml",
|
||||
"MediaPlayer": "WidgetSettings/MediaPlayerSettings.qml",
|
||||
"Weather": "WidgetSettings/WeatherSettings.qml",
|
||||
"SystemStat": "WidgetSettings/SystemStatSettings.qml",
|
||||
"AudioVisualizer": "WidgetSettings/AudioVisualizerSettings.qml"
|
||||
})
|
||||
|
||||
property var widgetMetadata: ({
|
||||
"Clock": {
|
||||
"showBackground": true,
|
||||
"roundedCorners": true,
|
||||
"clockStyle": "digital",
|
||||
"clockColor": "none",
|
||||
"useCustomFont": false,
|
||||
"customFont": "",
|
||||
"format": "HH:mm\\nd MMMM yyyy"
|
||||
},
|
||||
"MediaPlayer": {
|
||||
"showBackground": true,
|
||||
"roundedCorners": true,
|
||||
"visualizerType": "linear",
|
||||
"hideMode": "visible",
|
||||
"showButtons": true,
|
||||
"showAlbumArt": true,
|
||||
"showVisualizer": true
|
||||
},
|
||||
"Weather": {
|
||||
"showBackground": true,
|
||||
"roundedCorners": true
|
||||
},
|
||||
"SystemStat": {
|
||||
"showBackground": true,
|
||||
"roundedCorners": true,
|
||||
"statType": "CPU",
|
||||
"diskPath": "/",
|
||||
"layout": "bottom"
|
||||
},
|
||||
"AudioVisualizer": {
|
||||
"showBackground": true,
|
||||
"roundedCorners": true,
|
||||
"width": 320,
|
||||
"height": 72,
|
||||
"visualizerType": "linear",
|
||||
"hideWhenIdle": false,
|
||||
"colorName": "primary"
|
||||
}
|
||||
})
|
||||
|
||||
property var cpuIntensiveWidgets: ["SystemStat", "AudioVisualizer"]
|
||||
|
||||
// Plugin widget storage (mirroring BarWidgetRegistry pattern)
|
||||
property var pluginWidgets: ({})
|
||||
property var pluginWidgetMetadata: ({})
|
||||
|
||||
function init() {
|
||||
Logger.i("DesktopWidgetRegistry", "Service started");
|
||||
}
|
||||
|
||||
// Helper function to get widget component by name
|
||||
function getWidget(id) {
|
||||
return widgets[id] || null;
|
||||
}
|
||||
|
||||
// Helper function to check if widget exists
|
||||
function hasWidget(id) {
|
||||
return id in widgets;
|
||||
}
|
||||
|
||||
// Get list of available widget ids
|
||||
function getAvailableWidgets() {
|
||||
var keys = Object.keys(widgets);
|
||||
Logger.d("DesktopWidgetRegistry", "getAvailableWidgets() called, returning:", keys);
|
||||
return keys;
|
||||
}
|
||||
|
||||
// Helper function to check if widget has user settings
|
||||
function widgetHasUserSettings(id) {
|
||||
return widgetMetadata[id] !== undefined;
|
||||
}
|
||||
|
||||
function isCpuIntensive(id) {
|
||||
if (pluginWidgetMetadata[id]?.cpuIntensive)
|
||||
return true;
|
||||
return cpuIntensiveWidgets.indexOf(id) >= 0;
|
||||
}
|
||||
|
||||
// Check if a widget is a plugin widget
|
||||
function isPluginWidget(id) {
|
||||
return id.startsWith("plugin:");
|
||||
}
|
||||
|
||||
// Get list of plugin widget IDs
|
||||
function getPluginWidgets() {
|
||||
return Object.keys(pluginWidgets);
|
||||
}
|
||||
|
||||
// Get display name for a widget ID
|
||||
function getWidgetDisplayName(widgetId) {
|
||||
if (widgetId.startsWith("plugin:")) {
|
||||
var pluginId = widgetId.replace("plugin:", "");
|
||||
var manifest = PluginRegistry.getPluginManifest(pluginId);
|
||||
return manifest ? manifest.name : pluginId;
|
||||
}
|
||||
// Core widgets - return as-is (Clock, MediaPlayer, Weather, SystemStat)
|
||||
return widgetId;
|
||||
}
|
||||
|
||||
// Register a plugin desktop widget
|
||||
function registerPluginWidget(pluginId, component, metadata) {
|
||||
if (!pluginId || !component) {
|
||||
Logger.e("DesktopWidgetRegistry", "Cannot register plugin widget: invalid parameters");
|
||||
return false;
|
||||
}
|
||||
|
||||
var widgetId = "plugin:" + pluginId;
|
||||
|
||||
// Create new objects to trigger QML property change detection
|
||||
var newPluginWidgets = Object.assign({}, pluginWidgets);
|
||||
newPluginWidgets[widgetId] = component;
|
||||
pluginWidgets = newPluginWidgets;
|
||||
|
||||
var newPluginMetadata = Object.assign({}, pluginWidgetMetadata);
|
||||
newPluginMetadata[widgetId] = metadata || {};
|
||||
pluginWidgetMetadata = newPluginMetadata;
|
||||
|
||||
// Also add to main widgets object for unified access - reassign to trigger change
|
||||
var newWidgets = Object.assign({}, widgets);
|
||||
newWidgets[widgetId] = component;
|
||||
widgets = newWidgets;
|
||||
|
||||
var newMetadata = Object.assign({}, widgetMetadata);
|
||||
newMetadata[widgetId] = Object.assign({}, {
|
||||
"showBackground": true
|
||||
}, metadata || {});
|
||||
widgetMetadata = newMetadata;
|
||||
|
||||
Logger.i("DesktopWidgetRegistry", "Registered plugin widget:", widgetId);
|
||||
root.pluginWidgetRegistryUpdated();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Unregister a plugin desktop widget
|
||||
function unregisterPluginWidget(pluginId) {
|
||||
var widgetId = "plugin:" + pluginId;
|
||||
|
||||
if (!pluginWidgets[widgetId]) {
|
||||
Logger.w("DesktopWidgetRegistry", "Plugin widget not registered:", widgetId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create new objects without the widget to trigger QML property change detection
|
||||
var newPluginWidgets = Object.assign({}, pluginWidgets);
|
||||
delete newPluginWidgets[widgetId];
|
||||
pluginWidgets = newPluginWidgets;
|
||||
|
||||
var newPluginMetadata = Object.assign({}, pluginWidgetMetadata);
|
||||
delete newPluginMetadata[widgetId];
|
||||
pluginWidgetMetadata = newPluginMetadata;
|
||||
|
||||
var newWidgets = Object.assign({}, widgets);
|
||||
delete newWidgets[widgetId];
|
||||
widgets = newWidgets;
|
||||
|
||||
var newMetadata = Object.assign({}, widgetMetadata);
|
||||
delete newMetadata[widgetId];
|
||||
widgetMetadata = newMetadata;
|
||||
|
||||
Logger.i("DesktopWidgetRegistry", "Unregistered plugin widget:", widgetId);
|
||||
root.pluginWidgetRegistryUpdated();
|
||||
return true;
|
||||
}
|
||||
|
||||
function updateWidgetData(monitorName, widgetIndex, properties) {
|
||||
if (widgetIndex < 0 || !monitorName) {
|
||||
return;
|
||||
}
|
||||
|
||||
var monitorWidgets = Settings.data.desktopWidgets.monitorWidgets || [];
|
||||
var newMonitorWidgets = monitorWidgets.slice();
|
||||
|
||||
for (var i = 0; i < newMonitorWidgets.length; i++) {
|
||||
if (newMonitorWidgets[i].name === monitorName) {
|
||||
var widgets = (newMonitorWidgets[i].widgets || []).slice();
|
||||
if (widgetIndex < widgets.length) {
|
||||
widgets[widgetIndex] = Object.assign({}, widgets[widgetIndex], properties);
|
||||
newMonitorWidgets[i] = Object.assign({}, newMonitorWidgets[i], {
|
||||
"widgets": widgets
|
||||
});
|
||||
Settings.data.desktopWidgets.monitorWidgets = newMonitorWidgets;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property var currentSettingsDialog: null
|
||||
|
||||
function openWidgetSettings(screen, widgetIndex, widgetId, widgetData) {
|
||||
if (!widgetId || !screen) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (root.currentSettingsDialog) {
|
||||
root.currentSettingsDialog.close();
|
||||
root.currentSettingsDialog.destroy();
|
||||
root.currentSettingsDialog = null;
|
||||
}
|
||||
|
||||
var hasSettings = false;
|
||||
if (root.isPluginWidget(widgetId)) {
|
||||
var pluginId = widgetId.replace("plugin:", "");
|
||||
var manifest = PluginRegistry.getPluginManifest(pluginId);
|
||||
if (manifest && manifest.entryPoints && (manifest.entryPoints.desktopWidgetSettings || manifest.entryPoints.settings)) {
|
||||
hasSettings = true;
|
||||
}
|
||||
} else {
|
||||
hasSettings = root.widgetSettingsMap[widgetId] !== undefined;
|
||||
}
|
||||
|
||||
if (!hasSettings) {
|
||||
Logger.w("DesktopWidgetRegistry", "Widget does not have settings:", widgetId);
|
||||
return;
|
||||
}
|
||||
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (!popupMenuWindow) {
|
||||
Logger.e("DesktopWidgetRegistry", "No popup menu window found for screen");
|
||||
return;
|
||||
}
|
||||
|
||||
if (popupMenuWindow.hideDynamicMenu) {
|
||||
popupMenuWindow.hideDynamicMenu();
|
||||
}
|
||||
|
||||
var component = Qt.createComponent(Quickshell.shellDir + "/Modules/Panels/Settings/DesktopWidgets/DesktopWidgetSettingsDialog.qml");
|
||||
|
||||
function instantiateAndOpen() {
|
||||
var dialog = component.createObject(popupMenuWindow.dialogParent, {
|
||||
"widgetIndex": widgetIndex,
|
||||
"widgetData": widgetData,
|
||||
"widgetId": widgetId,
|
||||
"sectionId": screen.name,
|
||||
"screen": screen
|
||||
});
|
||||
|
||||
if (dialog) {
|
||||
root.currentSettingsDialog = dialog;
|
||||
dialog.updateWidgetSettings.connect((sec, idx, settings) => {
|
||||
root.updateWidgetData(sec, idx, settings);
|
||||
});
|
||||
popupMenuWindow.hasDialog = true;
|
||||
dialog.closed.connect(() => {
|
||||
popupMenuWindow.hasDialog = false;
|
||||
popupMenuWindow.close();
|
||||
if (root.currentSettingsDialog === dialog) {
|
||||
root.currentSettingsDialog = null;
|
||||
}
|
||||
dialog.destroy();
|
||||
});
|
||||
dialog.open();
|
||||
} else {
|
||||
Logger.e("DesktopWidgetRegistry", "Failed to create widget settings dialog");
|
||||
}
|
||||
}
|
||||
|
||||
if (component.status === Component.Ready) {
|
||||
instantiateAndOpen();
|
||||
} else if (component.status === Component.Error) {
|
||||
Logger.e("DesktopWidgetRegistry", "Error loading settings dialog component:", component.errorString());
|
||||
} else {
|
||||
component.statusChanged.connect(() => {
|
||||
if (component.status === Component.Ready) {
|
||||
instantiateAndOpen();
|
||||
} else if (component.status === Component.Error) {
|
||||
Logger.e("DesktopWidgetRegistry", "Error loading settings dialog component:", component.errorString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user