mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-14 23:34:01 -04:00
* fix(frame): make connected mode honor the settings it overrides Several frame-mode behaviors contradicted what the settings UI shows: - Frame -> Blur gated blur for every shell surface in connected mode, including the Settings window, polkit, context menus, OSDs and toasts. WindowBlur now defaults to Background blur; only surfaces painted with the frame color (connected popouts, slideouts, Control Center) follow Frame -> Blur, and frame-owned surfaces are blurred by the frame as before. - The notepad slideout painted its own fill at the notepad transparency. On screens where the frame owns connected chrome it now claims a frame surface (new connected_arc slot 5), so the frame paints it flush with the cutout, with fillets, and follows the slide. - Notification popups painted a card surface on top of the frame body, stacking fills. That layer is transparent when the frame paints it. - Connected mode stripped shadow, border and corner styling from every bar, including bars on displays without a frame, and hid the rows. Styling is now stripped and restored per bar based on whether it covers a frame display, re-checked on screen, frame display and display-name-mode changes. - Auto popup gaps and Gap size were hidden in separate mode although they still apply there; they now hide only in connected mode. - The launcher style picker was hidden in connected mode while Island still overrode the connected launcher. Connected mode now always uses the connected launcher; the picker shows Full, disabled, with a note linking to the Bar layout picker. - The frame shadow ignored Shadows -> Apply to -> Bars. * fix(frame): address review feedback on connected mode - Skip bar style reconciliation while the screen list is empty, so a hotplug doesn't restore and re-strip every bar. - Replace the 16 copies of the connector blur anchor and cutout in FrameWindow with a ConnectorBlurRegion inline component. - Let connected mode use the island launcher again now that the island can sit in any bar. The picker offers Full and Island there and hides Spotlight, which opens the full launcher in that mode anyway; the note and the SettingsControlledBy bar target are dropped. * frame: address review findings on connected mode --------- Co-authored-by: purian23 <[email protected]>
1391 lines
39 KiB
QML
1391 lines
39 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import qs.Common
|
|
import qs.Modals
|
|
import qs.Modals.Changelog
|
|
import qs.Modals.Clipboard
|
|
import qs.Modals.Common
|
|
import qs.Modals.Greeter
|
|
import qs.Modals.Settings
|
|
import qs.Modals.DLauncherV2
|
|
import qs.Modules
|
|
import qs.Modules.AppDrawer
|
|
import qs.Modules.DDash
|
|
import qs.Modules.ControlCenter
|
|
import qs.Modules.Dock
|
|
import qs.Modules.Lock
|
|
import qs.Modules.Notepad
|
|
import qs.Modules.Notifications.Center
|
|
import qs.Widgets
|
|
import qs.Modules.Notifications.Popup
|
|
import qs.Modules.OSD
|
|
import qs.Modules.ProcessList
|
|
import qs.Modules.DBar.Popouts
|
|
import qs.Modules.WorkspaceOverlays
|
|
import qs.Modules.Settings.DisplayConfig
|
|
import qs.Services
|
|
|
|
Item {
|
|
id: root
|
|
readonly property var log: Log.scoped("DMSShell")
|
|
readonly property var _nightModeServiceRef: NightModeService
|
|
readonly property var _brightnessServiceRef: BrightnessService
|
|
readonly property var _refreshRateServiceRef: RefreshRateService
|
|
|
|
property var core: null
|
|
|
|
property bool osdSurfacesLoaded: false
|
|
property int pendingOsdResumeReloads: 0
|
|
readonly property var notificationPopupScreens: {
|
|
const screens = SettingsData.notificationFocusedMonitor ? Quickshell.screens : SettingsData.getFilteredScreens("notifications");
|
|
if (!SettingsData.dankIslandEnabled)
|
|
return screens;
|
|
return screens.filter(screen => !SettingsData.dankIslandHandlesNotifications(screen));
|
|
}
|
|
readonly property var legacySystemLevelOsdScreens: {
|
|
const screens = SettingsData.getFilteredScreens("osd");
|
|
if (!SettingsData.dankIslandEnabled)
|
|
return screens;
|
|
return screens.filter(screen => !SettingsData.dankIslandHandlesSystemOsd(screen));
|
|
}
|
|
|
|
function recreateOsdSurfaces() {
|
|
OSDManager.currentOSDsByScreen = ({});
|
|
osdSurfacesLoaded = false;
|
|
osdSurfaceReloadTimer.restart();
|
|
}
|
|
|
|
DesktopWidgetLayer {}
|
|
|
|
DesktopWidgetEditor {}
|
|
|
|
DesktopContextMenu {
|
|
Component.onCompleted: PopoutService.desktopContextMenu = this
|
|
}
|
|
|
|
Lock {
|
|
id: lock
|
|
}
|
|
|
|
Variants {
|
|
model: Quickshell.screens
|
|
|
|
delegate: Loader {
|
|
id: fadeWindowLoader
|
|
required property var modelData
|
|
readonly property FadeToLockWindow loadedWindow: item as FadeToLockWindow
|
|
active: SettingsData.fadeToLockEnabled
|
|
asynchronous: false
|
|
|
|
sourceComponent: FadeToLockWindow {
|
|
screen: fadeWindowLoader.modelData
|
|
|
|
onFadeCompleted: {
|
|
IdleService.lockRequested();
|
|
}
|
|
|
|
onFadeCancelled: {
|
|
root.log.debug("Fade to lock cancelled by user on screen:", fadeWindowLoader.modelData.name);
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: IdleService
|
|
enabled: fadeWindowLoader.loadedWindow !== null
|
|
|
|
function onFadeToLockRequested() {
|
|
if (fadeWindowLoader.loadedWindow) {
|
|
fadeWindowLoader.loadedWindow.startFade();
|
|
}
|
|
}
|
|
|
|
function onCancelFadeToLock() {
|
|
if (fadeWindowLoader.loadedWindow) {
|
|
fadeWindowLoader.loadedWindow.cancelFade();
|
|
}
|
|
}
|
|
|
|
function onDismissFadeToLock() {
|
|
if (fadeWindowLoader.loadedWindow) {
|
|
fadeWindowLoader.loadedWindow.dismiss();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Variants {
|
|
model: Quickshell.screens
|
|
|
|
delegate: Loader {
|
|
id: fadeDpmsWindowLoader
|
|
required property var modelData
|
|
readonly property FadeToDpmsWindow loadedWindow: item as FadeToDpmsWindow
|
|
active: SettingsData.fadeToDpmsEnabled
|
|
asynchronous: false
|
|
|
|
sourceComponent: FadeToDpmsWindow {
|
|
screen: fadeDpmsWindowLoader.modelData
|
|
|
|
onFadeCompleted: {
|
|
IdleService.requestMonitorOff();
|
|
}
|
|
|
|
onFadeCancelled: {
|
|
root.log.debug("Fade to DPMS cancelled by user on screen:", fadeDpmsWindowLoader.modelData.name);
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: IdleService
|
|
enabled: fadeDpmsWindowLoader.loadedWindow !== null
|
|
|
|
function onFadeToDpmsRequested() {
|
|
if (fadeDpmsWindowLoader.loadedWindow) {
|
|
fadeDpmsWindowLoader.loadedWindow.startFade();
|
|
}
|
|
}
|
|
|
|
function onCancelFadeToDpms() {
|
|
if (fadeDpmsWindowLoader.loadedWindow) {
|
|
fadeDpmsWindowLoader.loadedWindow.cancelFade();
|
|
}
|
|
}
|
|
|
|
function onRequestMonitorOn() {
|
|
if (!fadeDpmsWindowLoader.loadedWindow)
|
|
return;
|
|
fadeDpmsWindowLoader.loadedWindow.cancelFade();
|
|
}
|
|
|
|
function onMonitorsOffChanged() {
|
|
if (IdleService.monitorsOff)
|
|
return;
|
|
if (!fadeDpmsWindowLoader.loadedWindow)
|
|
return;
|
|
fadeDpmsWindowLoader.loadedWindow.dismiss();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: root.core
|
|
|
|
function on_BarLayoutStateJsonChanged() {
|
|
dockRecreateDebounce.restart();
|
|
}
|
|
|
|
function onSurfaceRecoveryPass() {
|
|
root.dockEnabled = false;
|
|
Qt.callLater(() => {
|
|
root.dockEnabled = true;
|
|
});
|
|
}
|
|
}
|
|
|
|
property bool dockEnabled: false
|
|
|
|
Timer {
|
|
id: dockRecreateDebounce
|
|
interval: 500
|
|
repeat: false
|
|
onTriggered: {
|
|
root.dockEnabled = false;
|
|
Qt.callLater(() => {
|
|
root.dockEnabled = true;
|
|
});
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: loginSoundTimer
|
|
// Half a second delay before playing login sound, otherwise the sound may be cut off
|
|
// 50 is the minimum that seems to work, but 500 is safer
|
|
interval: 500
|
|
repeat: false
|
|
onTriggered: {
|
|
AudioService.playLoginSoundIfApplicable();
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: osdResumeRecreateTimer
|
|
interval: 400
|
|
repeat: false
|
|
onTriggered: {
|
|
root.recreateOsdSurfaces();
|
|
root.pendingOsdResumeReloads--;
|
|
|
|
if (root.pendingOsdResumeReloads <= 0) {
|
|
root.pendingOsdResumeReloads = 0;
|
|
interval = 400;
|
|
return;
|
|
}
|
|
|
|
interval = 1400;
|
|
restart();
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: osdSurfaceReloadTimer
|
|
interval: 120
|
|
repeat: false
|
|
onTriggered: root.osdSurfacesLoaded = true
|
|
}
|
|
|
|
Timer {
|
|
id: osdStartupTimer
|
|
interval: 1000
|
|
repeat: false
|
|
onTriggered: root.osdSurfacesLoaded = true
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
dockEnabled = true;
|
|
loginSoundTimer.start();
|
|
osdStartupTimer.start();
|
|
if (SettingsData.controlCenterWidgets.some(widget => widget.id === "diskUsage" && widget.enabled !== false))
|
|
DgopService.initializeDiskMounts();
|
|
if (SettingsData.controlCenterWidgets.some(widget => widget.id === "user" && widget.enabled !== false && widget.uptime !== false))
|
|
DgopService.dgopAvailable;
|
|
|
|
// These are dummy references just to trigger the singletons onCompleted to trigger
|
|
PolkitService.polkitAvailable;
|
|
DisplayConfigState.hasOutputBackend;
|
|
PortalService.systemColorScheme;
|
|
DesktopService.isSystemd;
|
|
TrashService.count;
|
|
WallpaperCyclingService.cyclingActive;
|
|
ThemeAutoService.active;
|
|
WellbeingService.tracking;
|
|
}
|
|
|
|
Loader {
|
|
id: dockLoader
|
|
active: root.dockEnabled
|
|
asynchronous: false
|
|
|
|
sourceComponent: Dock {
|
|
contextMenu: dockContextMenuLoader.item ? dockContextMenuLoader.item : null
|
|
trashContextMenu: dockTrashContextMenuLoader.item ? dockTrashContextMenuLoader.item : null
|
|
}
|
|
|
|
onLoaded: {
|
|
if (item) {
|
|
dockContextMenuLoader.active = true;
|
|
if (SettingsData.dockConfigs.some(config => config.showTrash)) {
|
|
dockTrashContextMenuLoader.active = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
id: dankDashPopoutLoader
|
|
|
|
active: false
|
|
asynchronous: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.dankDashPopoutLoader = dankDashPopoutLoader;
|
|
}
|
|
|
|
onLoaded: {
|
|
if (item) {
|
|
PopoutService.dankDashPopout = item;
|
|
PopoutService._onDankDashPopoutLoaded();
|
|
}
|
|
}
|
|
|
|
sourceComponent: Component {
|
|
DDashPopout {
|
|
id: dankDashPopout
|
|
|
|
onPopoutClosed: PopoutService._scheduleUnload("dankDash")
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: dockContextMenuLoader
|
|
|
|
active: false
|
|
|
|
DockContextMenu {
|
|
id: dockContextMenu
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: dockTrashContextMenuLoader
|
|
|
|
active: false
|
|
|
|
DockTrashContextMenu {
|
|
id: dockTrashContextMenu
|
|
}
|
|
}
|
|
|
|
Binding {
|
|
target: BarWidgetService
|
|
property: "dockContextMenu"
|
|
value: dockContextMenuLoader.item
|
|
}
|
|
Binding {
|
|
target: BarWidgetService
|
|
property: "dockTrashContextMenu"
|
|
value: dockTrashContextMenuLoader.item
|
|
}
|
|
|
|
Connections {
|
|
target: SettingsData
|
|
function onDockConfigsChanged() {
|
|
if (SettingsData.dockConfigs.some(config => config.showTrash)) {
|
|
dockTrashContextMenuLoader.active = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: emptyTrashConfirmLoader
|
|
active: false
|
|
readonly property ConfirmModal loadedModal: item as ConfirmModal
|
|
|
|
ConfirmModal {
|
|
id: emptyTrashConfirm
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: TrashService
|
|
function onEmptyTrashConfirmRequested(itemCount) {
|
|
emptyTrashConfirmLoader.active = true;
|
|
if (!emptyTrashConfirmLoader.loadedModal)
|
|
return;
|
|
emptyTrashConfirmLoader.loadedModal.showWithOptions({
|
|
title: I18n.tr("Empty Trash"),
|
|
message: I18n.tr("Permanently delete %1 item(s)? This cannot be undone.", "empty trash confirmation message, %1 is a count").arg(itemCount),
|
|
confirmText: I18n.tr("Empty"),
|
|
cancelText: I18n.tr("Cancel"),
|
|
confirmColor: Theme.error,
|
|
onConfirm: () => TrashService.emptyTrash()
|
|
});
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: uninstallAppConfirmLoader
|
|
active: false
|
|
readonly property ConfirmModal loadedModal: item as ConfirmModal
|
|
|
|
ConfirmModal {
|
|
id: uninstallAppConfirm
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: AppSearchService
|
|
function onUninstallAppConfirmRequested(appId, appName, flatpakId) {
|
|
uninstallAppConfirmLoader.active = true;
|
|
const showDialog = () => {
|
|
if (uninstallAppConfirmLoader.loadedModal) {
|
|
uninstallAppConfirmLoader.loadedModal.showWithOptions({
|
|
title: I18n.tr("Uninstall %1?", "modal title for app uninstallation").arg(appName),
|
|
message: I18n.tr("%1 will be removed from your system.", "modal confirmation text for uninstalling an app").arg(appName),
|
|
confirmText: I18n.tr("Uninstall", "confirm button label to proceed with uninstallation"),
|
|
cancelText: I18n.tr("Cancel"),
|
|
confirmColor: Theme.error,
|
|
onConfirm: () => AppSearchService.uninstallFlatpak(appId, appName, flatpakId)
|
|
});
|
|
}
|
|
};
|
|
if (uninstallAppConfirmLoader.loadedModal)
|
|
showDialog();
|
|
else
|
|
Qt.callLater(showDialog);
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: notificationCenterLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.notificationCenterLoader = notificationCenterLoader;
|
|
}
|
|
|
|
NotificationCenterPopout {
|
|
id: notificationCenter
|
|
onPopoutClosed: PopoutService.unloadNotificationCenter()
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.notificationCenterPopout = notificationCenter;
|
|
}
|
|
}
|
|
}
|
|
|
|
Variants {
|
|
model: root.notificationPopupScreens
|
|
|
|
delegate: NotificationPopupManager {}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: controlCenterLoader
|
|
|
|
active: false
|
|
|
|
property var modalRef: colorPickerModal
|
|
property LazyLoader powerModalLoaderRef: powerMenuModalLoader
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.controlCenterLoader = controlCenterLoader;
|
|
}
|
|
|
|
ControlCenterPopout {
|
|
id: controlCenterPopout
|
|
colorPickerModal: controlCenterLoader.modalRef
|
|
powerMenuModalLoader: controlCenterLoader.powerModalLoaderRef
|
|
onPopoutClosed: PopoutService.unloadControlCenter()
|
|
|
|
onLockRequested: {
|
|
lock.activate();
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.controlCenterPopout = controlCenterPopout;
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: wifiPasswordModalLoader
|
|
active: false
|
|
readonly property WifiPasswordModal loadedModal: item as WifiPasswordModal
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.wifiPasswordModalLoader = wifiPasswordModalLoader;
|
|
}
|
|
|
|
WifiPasswordModal {
|
|
id: wifiPasswordModalItem
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.wifiPasswordModal = wifiPasswordModalItem;
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: wifiQRCodeModalLoader
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.wifiQRCodeModalLoader = wifiQRCodeModalLoader;
|
|
}
|
|
|
|
WifiQRCodeModal {
|
|
id: wifiQRCodeModalItem
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.wifiQRCodeModal = wifiQRCodeModalItem;
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: qrGeneratorModalLoader
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.qrGeneratorModalLoader = qrGeneratorModalLoader;
|
|
}
|
|
|
|
QRGeneratorModal {
|
|
id: qrGeneratorModalItem
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.qrGeneratorModal = qrGeneratorModalItem;
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: polkitAuthModalLoader
|
|
active: false
|
|
readonly property PolkitAuthModal loadedModal: item as PolkitAuthModal
|
|
|
|
PolkitAuthModal {
|
|
id: polkitAuthModal
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.polkitAuthModal = polkitAuthModal;
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: PolkitService.agent
|
|
enabled: PolkitService.polkitAvailable
|
|
|
|
function onAuthenticationRequestStarted() {
|
|
if (PopoutService.systemUpdatePopout?.shouldBeVisible)
|
|
return;
|
|
polkitAuthModalLoader.active = true;
|
|
if (polkitAuthModalLoader.loadedModal)
|
|
polkitAuthModalLoader.loadedModal.show();
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: bluetoothPairingModalLoader
|
|
active: false
|
|
|
|
Component.onCompleted: PopoutService.bluetoothPairingModalLoader = bluetoothPairingModalLoader
|
|
|
|
BluetoothPairingModal {
|
|
id: bluetoothPairingModal
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.bluetoothPairingModal = bluetoothPairingModal;
|
|
}
|
|
}
|
|
}
|
|
|
|
property string lastCredentialsToken: ""
|
|
property var lastCredentialsTime: 0
|
|
|
|
Connections {
|
|
target: NetworkService
|
|
|
|
function onCredentialsNeeded(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo) {
|
|
const alreadyShown = wifiPasswordModalLoader.loadedModal && wifiPasswordModalLoader.loadedModal.shouldBeVisible;
|
|
if (alreadyShown && token === root.lastCredentialsToken)
|
|
return;
|
|
|
|
wifiPasswordModalLoader.active = true;
|
|
if (!wifiPasswordModalLoader.loadedModal)
|
|
return;
|
|
|
|
if (alreadyShown && root.lastCredentialsToken !== "" && root.lastCredentialsToken !== token)
|
|
NetworkService.cancelCredentials(root.lastCredentialsToken);
|
|
|
|
root.lastCredentialsToken = token;
|
|
root.lastCredentialsTime = Date.now();
|
|
wifiPasswordModalLoader.loadedModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo);
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: networkInfoModalLoader
|
|
|
|
active: false
|
|
|
|
NetworkInfoModal {
|
|
id: networkInfoModal
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.networkInfoModal = networkInfoModal;
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: batteryPopoutLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.batteryPopoutLoader = batteryPopoutLoader;
|
|
}
|
|
|
|
BatteryPopout {
|
|
id: batteryPopout
|
|
onPopoutClosed: PopoutService.unloadBattery()
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.batteryPopout = batteryPopout;
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: layoutPopoutLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.layoutPopoutLoader = layoutPopoutLoader;
|
|
}
|
|
|
|
DWLLayoutPopout {
|
|
id: layoutPopout
|
|
onPopoutClosed: PopoutService.unloadLayoutPopout()
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.layoutPopout = layoutPopout;
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: vpnPopoutLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.vpnPopoutLoader = vpnPopoutLoader;
|
|
}
|
|
|
|
VpnPopout {
|
|
id: vpnPopout
|
|
onPopoutClosed: PopoutService.unloadVpn()
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.vpnPopout = vpnPopout;
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: colorPickerPopoutLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.colorPickerPopoutLoader = colorPickerPopoutLoader;
|
|
}
|
|
|
|
ColorPickerPopout {
|
|
id: colorPickerPopout
|
|
onPopoutClosed: PopoutService.unloadColorPicker()
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.colorPickerPopout = colorPickerPopout;
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: processListPopoutLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.processListPopoutLoader = processListPopoutLoader;
|
|
}
|
|
|
|
ProcessListPopout {
|
|
id: processListPopout
|
|
onPopoutClosed: PopoutService.unloadProcessListPopout()
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.processListPopout = processListPopout;
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: settingsModalLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.settingsModalLoader = settingsModalLoader;
|
|
}
|
|
|
|
onActiveChanged: {
|
|
if (active && item) {
|
|
PopoutService.settingsModal = item;
|
|
PopoutService._onSettingsModalLoaded();
|
|
}
|
|
}
|
|
|
|
SettingsModal {
|
|
id: settingsModal
|
|
property bool wasShown: false
|
|
|
|
onVisibleChanged: {
|
|
if (visible) {
|
|
wasShown = true;
|
|
} else if (wasShown) {
|
|
Qt.callLater(() => PopoutService.unloadSettingsNow());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: appDrawerLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.appDrawerLoader = appDrawerLoader;
|
|
}
|
|
|
|
AppDrawerPopout {
|
|
id: appDrawerPopout
|
|
onPopoutClosed: PopoutService.unloadAppDrawer()
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.appDrawerPopout = appDrawerPopout;
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: dankLauncherV2ModalLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.dankLauncherV2ModalLoader = dankLauncherV2ModalLoader;
|
|
}
|
|
|
|
DLauncherV2Modal {
|
|
id: dankLauncherV2Modal
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.dankLauncherV2Modal = dankLauncherV2Modal;
|
|
PopoutService._onDankLauncherV2ModalLoaded();
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: spotlightBarModalLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.spotlightBarModalLoader = spotlightBarModalLoader;
|
|
}
|
|
|
|
DLauncherV2ModalHost {
|
|
id: spotlightBarModal
|
|
connected: false
|
|
spotlight: true
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.spotlightBarModal = spotlightBarModal;
|
|
PopoutService._onSpotlightBarModalLoaded();
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: clipboardHistoryPopoutLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.clipboardHistoryPopoutLoader = clipboardHistoryPopoutLoader;
|
|
}
|
|
|
|
ClipboardHistoryPopout {
|
|
id: clipboardHistoryPopout
|
|
onPopoutClosed: PopoutService.unloadClipboardHistoryPopout()
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.clipboardHistoryPopout = clipboardHistoryPopout;
|
|
}
|
|
}
|
|
}
|
|
|
|
MuxModal {
|
|
id: muxModal
|
|
}
|
|
|
|
ClipboardHistoryModal {
|
|
id: clipboardHistoryModalPopup
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.clipboardHistoryModal = clipboardHistoryModalPopup;
|
|
}
|
|
}
|
|
|
|
NotificationModal {
|
|
id: notificationModal
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.notificationModal = notificationModal;
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: browserPickerModalLoader
|
|
active: false
|
|
readonly property BrowserPickerModal loadedModal: item as BrowserPickerModal
|
|
|
|
BrowserPickerModal {
|
|
id: browserPickerModal
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: filePickerModalLoader
|
|
active: false
|
|
readonly property AppPickerModal loadedModal: item as AppPickerModal
|
|
|
|
AppPickerModal {
|
|
id: filePickerModal
|
|
title: I18n.tr("Open with", "app picker title, followed by a list of apps") + "…"
|
|
viewMode: SettingsData.appPickerViewMode || "grid"
|
|
|
|
onViewModeChanged: {
|
|
SettingsData.set("appPickerViewMode", viewMode);
|
|
}
|
|
|
|
function shellEscape(str) {
|
|
return "'" + str.replace(/'/g, "'\\''") + "'";
|
|
}
|
|
|
|
onApplicationSelected: (app, filePath) => {
|
|
if (!app)
|
|
return;
|
|
const entry = SessionService.resolveDesktopId(app.appId);
|
|
if (entry) {
|
|
SessionService.launchDesktopEntry(entry, false, [filePath]);
|
|
return;
|
|
}
|
|
let cmd = app.exec || "";
|
|
const escapedPath = shellEscape(filePath);
|
|
const escapedUri = shellEscape("file://" + filePath);
|
|
|
|
let hasField = false;
|
|
if (cmd.includes("%f")) {
|
|
cmd = cmd.replace("%f", escapedPath);
|
|
hasField = true;
|
|
} else if (cmd.includes("%F")) {
|
|
cmd = cmd.replace("%F", escapedPath);
|
|
hasField = true;
|
|
} else if (cmd.includes("%u")) {
|
|
cmd = cmd.replace("%u", escapedUri);
|
|
hasField = true;
|
|
} else if (cmd.includes("%U")) {
|
|
cmd = cmd.replace("%U", escapedUri);
|
|
hasField = true;
|
|
}
|
|
|
|
cmd = cmd.replace(/%[ikc]/g, "");
|
|
|
|
if (!hasField) {
|
|
cmd += " " + escapedPath;
|
|
}
|
|
|
|
log.debug("FilePicker: Launching", cmd);
|
|
|
|
Quickshell.execDetached({
|
|
command: ["sh", "-c", cmd]
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: DMSService
|
|
function onOpenUrlRequested(url) {
|
|
if (url.startsWith("dms://theme/install/")) {
|
|
const themeId = url.replace("dms://theme/install/", "").split(/[?#]/)[0];
|
|
if (themeId) {
|
|
PopoutService.pendingThemeInstall = themeId;
|
|
PopoutService.openSettingsWithTab("theme");
|
|
}
|
|
return;
|
|
}
|
|
if (url.startsWith("dms://plugin/install/")) {
|
|
const pluginId = url.replace("dms://plugin/install/", "").split(/[?#]/)[0];
|
|
if (pluginId) {
|
|
PopoutService.pendingPluginInstall = pluginId;
|
|
PopoutService.openSettingsWithTab("plugins");
|
|
}
|
|
return;
|
|
}
|
|
if (url.startsWith("dms://wallpaper/install/")) {
|
|
const payload = url.replace("dms://wallpaper/install/", "").split(/[?#]/)[0];
|
|
if (payload) {
|
|
PopoutService.pendingWallpaperInstall = payload;
|
|
PopoutService.openSettingsWithTab("wallpaper");
|
|
}
|
|
return;
|
|
}
|
|
browserPickerModalLoader.active = true;
|
|
const picker = browserPickerModalLoader.loadedModal;
|
|
if (!picker)
|
|
return;
|
|
picker.url = url;
|
|
picker.open();
|
|
}
|
|
|
|
function onAppPickerRequested(data) {
|
|
root.log.debug("App picker requested with data:", JSON.stringify(data));
|
|
|
|
if (!data || !data.target) {
|
|
root.log.warn("Invalid app picker request data");
|
|
return;
|
|
}
|
|
|
|
filePickerModalLoader.active = true;
|
|
const picker = filePickerModalLoader.loadedModal;
|
|
if (!picker)
|
|
return;
|
|
picker.targetData = data.target;
|
|
picker.targetDataLabel = data.requestType || "file";
|
|
picker.mimeType = data.mimeType || "";
|
|
picker.rememberMimeTypes = [];
|
|
picker.categoryFilter = data.categories?.length > 0 ? data.categories : [];
|
|
picker.usageHistoryKey = "filePickerUsageHistory";
|
|
picker.open();
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: SessionService
|
|
|
|
function onSessionResumed() {
|
|
root.pendingOsdResumeReloads = 2;
|
|
osdResumeRecreateTimer.interval = 400;
|
|
osdResumeRecreateTimer.restart();
|
|
}
|
|
}
|
|
|
|
ColorPickerModal {
|
|
id: colorPickerModal
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.colorPickerModal = colorPickerModal;
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: workspaceRenameModalLoader
|
|
|
|
active: false
|
|
|
|
WorkspaceRenameModal {
|
|
id: workspaceRenameModal
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: windowRuleModalLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: PopoutService.windowRuleModalLoader = windowRuleModalLoader
|
|
|
|
WindowRuleModal {
|
|
id: windowRuleModal
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: processListModalLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: PopoutService.processListModalLoader = processListModalLoader
|
|
|
|
ProcessListModal {
|
|
id: processListModal
|
|
property bool wasShown: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.processListModal = processListModal;
|
|
}
|
|
|
|
onVisibleChanged: {
|
|
if (visible) {
|
|
wasShown = true;
|
|
} else if (wasShown) {
|
|
PopoutService.unloadProcessListModal();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: systemUpdateModalLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: PopoutService.systemUpdateModalLoader = systemUpdateModalLoader
|
|
|
|
SystemUpdateModal {
|
|
id: systemUpdateModal
|
|
property bool wasShown: false
|
|
|
|
Component.onCompleted: PopoutService.systemUpdateModal = systemUpdateModal
|
|
|
|
onVisibleChanged: {
|
|
if (systemUpdateModal.visible) {
|
|
wasShown = true;
|
|
} else if (wasShown) {
|
|
PopoutService.unloadSystemUpdateModal();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: systemUpdateLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.systemUpdateLoader = systemUpdateLoader;
|
|
}
|
|
|
|
SystemUpdatePopout {
|
|
id: systemUpdatePopout
|
|
onPopoutClosed: {
|
|
if (systemUpdatePopout._reopenAfterUpgrade) {
|
|
return;
|
|
}
|
|
PopoutService.unloadSystemUpdate();
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.systemUpdatePopout = systemUpdatePopout;
|
|
}
|
|
}
|
|
}
|
|
|
|
Variants {
|
|
id: notepadSlideoutVariants
|
|
model: SettingsData.getFilteredScreens("notepad")
|
|
|
|
delegate: DSlideout {
|
|
id: notepadSlideout
|
|
title: I18n.tr("Notepad")
|
|
slideoutWidth: 480
|
|
expandable: true
|
|
expandedWidthValue: 960
|
|
edgeGap: SettingsData.notepadEffectiveEdgeGap
|
|
frameSurfaceEnabled: true
|
|
slideEdge: SettingsData.notepadSlideoutSide
|
|
customTransparency: Theme.notepadTransparency
|
|
|
|
onIsVisibleChanged: {
|
|
if (isVisible)
|
|
PopoutService.notepadPopout?.hide();
|
|
}
|
|
|
|
content: Component {
|
|
Notepad {
|
|
slideout: notepadSlideout
|
|
onHideRequested: notepadSlideout.hide()
|
|
onPopoutRequested: {
|
|
notepadSlideout.hide();
|
|
PopoutService.openNotepadPopout();
|
|
}
|
|
}
|
|
}
|
|
|
|
function toggle() {
|
|
if (isVisible) {
|
|
hide();
|
|
} else {
|
|
show();
|
|
}
|
|
}
|
|
}
|
|
|
|
onInstancesChanged: PopoutService.notepadSlideouts = instances
|
|
Component.onCompleted: PopoutService.notepadSlideouts = instances
|
|
}
|
|
|
|
LazyLoader {
|
|
id: notepadPopoutLoader
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.notepadPopoutLoader = notepadPopoutLoader;
|
|
}
|
|
|
|
onActiveChanged: {
|
|
if (active && item) {
|
|
PopoutService.notepadPopout = item;
|
|
PopoutService._onNotepadPopoutLoaded();
|
|
}
|
|
}
|
|
|
|
NotepadPopoutWindow {}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: powerMenuModalLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.powerMenuModalLoader = powerMenuModalLoader;
|
|
}
|
|
|
|
PowerMenuModal {
|
|
id: powerMenuModal
|
|
|
|
onPowerActionRequested: (action, title, message) => root._executePowerAction(action)
|
|
onLockRequested: root._lockFromPowerMenu()
|
|
onSwitchUserRequested: root._switchUserFromPowerMenu()
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.powerMenuModal = powerMenuModal;
|
|
}
|
|
}
|
|
}
|
|
|
|
function _executePowerAction(action) {
|
|
PopoutService.closeControlCenter();
|
|
SessionService.executePowerAction(action);
|
|
}
|
|
|
|
function _lockFromPowerMenu() {
|
|
PopoutService.closeControlCenter();
|
|
lock.activate();
|
|
}
|
|
|
|
function _switchUserFromPowerMenu() {
|
|
switchUserModalLoader.active = true;
|
|
Qt.callLater(() => {
|
|
if (switchUserModalLoader.loadedModal)
|
|
switchUserModalLoader.loadedModal.showFromPowerMenu();
|
|
});
|
|
}
|
|
|
|
LazyLoader {
|
|
id: powerMenuPopoutLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.powerMenuPopoutLoader = powerMenuPopoutLoader;
|
|
}
|
|
|
|
PowerMenuPopout {
|
|
id: powerMenuPopout
|
|
|
|
onPowerActionRequested: action => root._executePowerAction(action)
|
|
onLockRequested: root._lockFromPowerMenu()
|
|
onSwitchUserRequested: root._switchUserFromPowerMenu()
|
|
onPopoutClosed: PopoutService.unloadPowerMenuPopout()
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.powerMenuPopout = powerMenuPopout;
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: durationPopoutLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.durationPopoutLoader = durationPopoutLoader;
|
|
}
|
|
|
|
DurationPopout {
|
|
id: durationPopout
|
|
onPopoutClosed: PopoutService.unloadDurationPopout()
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.durationPopout = durationPopout;
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: switchUserModalLoader
|
|
|
|
active: false
|
|
readonly property SwitchUserModal loadedModal: item as SwitchUserModal
|
|
|
|
SwitchUserModal {
|
|
id: switchUserModal
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: hyprKeybindsModalLoader
|
|
|
|
active: false
|
|
|
|
Component.onCompleted: PopoutService.keybindsModalLoader = hyprKeybindsModalLoader
|
|
|
|
KeybindsModal {
|
|
id: keybindsModal
|
|
|
|
Component.onCompleted: PopoutService.keybindsModal = keybindsModal
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: powerProfileModalLoader
|
|
|
|
active: false
|
|
|
|
PowerProfileModal {
|
|
id: powerProfileModal
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.powerProfileModal = powerProfileModal;
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
PopoutService.powerProfileModalLoader = powerProfileModalLoader;
|
|
}
|
|
}
|
|
|
|
DMSShellIPC {
|
|
powerMenuModalLoaderRef: powerMenuModalLoader
|
|
processListModalLoaderRef: processListModalLoader
|
|
controlCenterLoaderRef: controlCenterLoader
|
|
dankDashPopoutLoaderRef: dankDashPopoutLoader
|
|
notepadSlideoutVariantsRef: notepadSlideoutVariants
|
|
hyprKeybindsModalLoaderRef: hyprKeybindsModalLoader
|
|
dankBarRepeater: root.core?.dankBarRepeater ?? null
|
|
hyprlandOverviewLoader: root.core?.hyprlandOverviewLoader ?? null
|
|
workspaceRenameModalLoaderRef: workspaceRenameModalLoader
|
|
windowRuleModalLoaderRef: windowRuleModalLoader
|
|
}
|
|
|
|
Variants {
|
|
model: SettingsData.getFilteredScreens("toast")
|
|
|
|
delegate: Toast {}
|
|
}
|
|
|
|
Loader {
|
|
id: osdSurfacesLoader
|
|
active: root.osdSurfacesLoaded
|
|
asynchronous: false
|
|
|
|
sourceComponent: Component {
|
|
Item {
|
|
Variants {
|
|
model: SettingsData.osdVolumeEnabled ? root.legacySystemLevelOsdScreens : []
|
|
|
|
delegate: VolumeOSD {}
|
|
}
|
|
|
|
Variants {
|
|
model: SettingsData.osdMediaVolumeEnabled ? SettingsData.getFilteredScreens("osd") : []
|
|
|
|
delegate: MediaVolumeOSD {}
|
|
}
|
|
|
|
Variants {
|
|
model: SettingsData.osdMediaPlaybackEnabled ? SettingsData.getFilteredScreens("osd") : []
|
|
|
|
delegate: MediaPlaybackOSD {}
|
|
}
|
|
|
|
Variants {
|
|
model: (SettingsData.osdMicMuteEnabled || SettingsData.osdMicVolumeEnabled) ? root.legacySystemLevelOsdScreens : []
|
|
|
|
delegate: MicVolumeOSD {}
|
|
}
|
|
|
|
Variants {
|
|
model: SettingsData.osdBrightnessEnabled ? root.legacySystemLevelOsdScreens : []
|
|
|
|
delegate: BrightnessOSD {}
|
|
}
|
|
|
|
Variants {
|
|
model: SettingsData.osdIdleInhibitorEnabled ? root.legacySystemLevelOsdScreens : []
|
|
|
|
delegate: IdleInhibitorOSD {}
|
|
}
|
|
|
|
Variants {
|
|
model: SettingsData.osdPowerProfileEnabled ? root.legacySystemLevelOsdScreens : []
|
|
|
|
delegate: PowerProfileOSD {}
|
|
}
|
|
|
|
Variants {
|
|
model: SettingsData.osdCapsLockEnabled ? root.legacySystemLevelOsdScreens : []
|
|
|
|
delegate: CapsLockOSD {}
|
|
}
|
|
|
|
Variants {
|
|
model: SettingsData.osdAudioOutputEnabled ? SettingsData.getFilteredScreens("osd") : []
|
|
|
|
delegate: AudioOutputOSD {}
|
|
}
|
|
|
|
Variants {
|
|
model: SettingsData.osdWorkspaceEnabled ? SettingsData.getFilteredScreens("osd") : []
|
|
|
|
delegate: WorkspaceOSD {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: niriOverviewOverlayLoader
|
|
active: CompositorService.isNiri && SettingsData.niriOverviewOverlayEnabled
|
|
component: NiriOverviewOverlay {
|
|
id: niriOverviewOverlay
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
id: greeterLoader
|
|
active: false
|
|
readonly property GreeterModal loadedModal: item as GreeterModal
|
|
sourceComponent: GreeterModal {
|
|
onGreeterCompleted: greeterLoader.active = false
|
|
Component.onCompleted: show()
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
if (FirstLaunchService.shouldShowGreeter)
|
|
active = true;
|
|
}
|
|
|
|
Connections {
|
|
target: FirstLaunchService
|
|
function onGreeterRequested() {
|
|
if (greeterLoader.active && greeterLoader.loadedModal) {
|
|
greeterLoader.loadedModal.show();
|
|
return;
|
|
}
|
|
greeterLoader.active = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
id: changelogLoader
|
|
active: false
|
|
readonly property ChangelogModal loadedModal: item as ChangelogModal
|
|
sourceComponent: ChangelogModal {
|
|
onChangelogDismissed: changelogLoader.active = false
|
|
Component.onCompleted: show()
|
|
}
|
|
|
|
Connections {
|
|
target: ChangelogService
|
|
function onChangelogRequested() {
|
|
if (changelogLoader.active && changelogLoader.loadedModal) {
|
|
changelogLoader.loadedModal.show();
|
|
return;
|
|
}
|
|
changelogLoader.active = true;
|
|
}
|
|
}
|
|
}
|
|
}
|