mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-07-31 00:34:45 +00:00
Harden gaming mode and fix startup crash
Strut windows committed zero height to layer-shell during early init, causing a protocol error and session exit. Wrap height and exclusionZone in Math.max(1, ...) for top bar and dock. Persisted gamingModeEnabled=true with hardcoded gameCenterOpen=false hid panels with no overlay visible. Initialize gameCenterOpen from the stored setting. Fix HUD visibility regression from an emergency visible:true override. Various null-guard and positioning fixes from static analysis across the gaming shell QML.
This commit is contained in:
parent
50ea5976ce
commit
70fa861b30
18 changed files with 129 additions and 52 deletions
7
Nebra.code-workspace
Normal file
7
Nebra.code-workspace
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -86,13 +86,15 @@ QQuickItem *AppletHost::fullRepresentationFor(const QString &pluginId)
|
||||||
|
|
||||||
m_containment->addApplet(applet);
|
m_containment->addApplet(applet);
|
||||||
auto *item = PlasmaQuick::AppletQuickItem::itemForApplet(applet);
|
auto *item = PlasmaQuick::AppletQuickItem::itemForApplet(applet);
|
||||||
m_items.insert(pluginId, item);
|
|
||||||
|
|
||||||
if (!item) {
|
if (!item) {
|
||||||
qWarning() << "AppletHost: no AppletQuickItem for" << pluginId;
|
qWarning() << "AppletHost: no AppletQuickItem for" << pluginId;
|
||||||
|
applet->deleteLater();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_items.insert(pluginId, item);
|
||||||
|
|
||||||
item->setPreloadFullRepresentation(true);
|
item->setPreloadFullRepresentation(true);
|
||||||
|
|
||||||
auto *fullRepItem = item->fullRepresentationItem();
|
auto *fullRepItem = item->fullRepresentationItem();
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,7 @@ Item {
|
||||||
shrinkSize: 0
|
shrinkSize: 0
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
if (!root.taskModel) return;
|
||||||
root.taskModel.requestActivate(root.taskModel.makeModelIndex(taskDelegate.index));
|
root.taskModel.requestActivate(root.taskModel.makeModelIndex(taskDelegate.index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,18 +181,27 @@ Item {
|
||||||
Controls.MenuItem {
|
Controls.MenuItem {
|
||||||
text: taskDelegate.model.IsMinimized ? i18n("Restore") : i18n("Minimize")
|
text: taskDelegate.model.IsMinimized ? i18n("Restore") : i18n("Minimize")
|
||||||
icon.name: taskDelegate.model.IsMinimized ? "window-restore" : "window-minimize"
|
icon.name: taskDelegate.model.IsMinimized ? "window-restore" : "window-minimize"
|
||||||
onTriggered: root.taskModel.requestToggleMinimized(root.taskModel.makeModelIndex(taskDelegate.index))
|
onTriggered: {
|
||||||
|
if (!root.taskModel) return;
|
||||||
|
root.taskModel.requestToggleMinimized(root.taskModel.makeModelIndex(taskDelegate.index))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Controls.MenuItem {
|
Controls.MenuItem {
|
||||||
text: taskDelegate.model.IsMaximized ? i18n("Restore") : i18n("Maximize")
|
text: taskDelegate.model.IsMaximized ? i18n("Restore") : i18n("Maximize")
|
||||||
icon.name: taskDelegate.model.IsMaximized ? "window-restore" : "window-maximize"
|
icon.name: taskDelegate.model.IsMaximized ? "window-restore" : "window-maximize"
|
||||||
onTriggered: root.taskModel.requestToggleMaximized(root.taskModel.makeModelIndex(taskDelegate.index))
|
onTriggered: {
|
||||||
|
if (!root.taskModel) return;
|
||||||
|
root.taskModel.requestToggleMaximized(root.taskModel.makeModelIndex(taskDelegate.index))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Controls.MenuSeparator {}
|
Controls.MenuSeparator {}
|
||||||
Controls.MenuItem {
|
Controls.MenuItem {
|
||||||
text: i18n("Close")
|
text: i18n("Close")
|
||||||
icon.name: "window-close"
|
icon.name: "window-close"
|
||||||
onTriggered: root.taskModel.requestClose(root.taskModel.makeModelIndex(taskDelegate.index))
|
onTriggered: {
|
||||||
|
if (!root.taskModel) return;
|
||||||
|
root.taskModel.requestClose(root.taskModel.makeModelIndex(taskDelegate.index))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -706,12 +706,16 @@ MouseArea {
|
||||||
x: {
|
x: {
|
||||||
if (!targetDelegate) return 0
|
if (!targetDelegate) return 0
|
||||||
var delegateGlobal = targetDelegate.mapToGlobal(0, 0)
|
var delegateGlobal = targetDelegate.mapToGlobal(0, 0)
|
||||||
return Math.max(0, Math.min(Screen.width - width, delegateGlobal.x + (targetDelegate.width - width) / 2))
|
var win = targetDelegate.Window.window
|
||||||
|
var scrW = win && win.screen ? win.screen.width : Screen.width
|
||||||
|
return Math.max(0, Math.min(scrW - width, delegateGlobal.x + (targetDelegate.width - width) / 2))
|
||||||
}
|
}
|
||||||
y: {
|
y: {
|
||||||
if (!targetDelegate) return 0
|
if (!targetDelegate) return 0
|
||||||
var delegateGlobal = targetDelegate.mapToGlobal(0, 0)
|
var delegateGlobal = targetDelegate.mapToGlobal(0, 0)
|
||||||
return Math.max(0, Math.min(Screen.height - height, delegateGlobal.y - height - Kirigami.Units.smallSpacing))
|
var win = targetDelegate.Window.window
|
||||||
|
var scrH = win && win.screen ? win.screen.height : Screen.height
|
||||||
|
return Math.max(0, Math.min(scrH - height, delegateGlobal.y - height - Kirigami.Units.smallSpacing))
|
||||||
}
|
}
|
||||||
|
|
||||||
onShowingChanged: {
|
onShowingChanged: {
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ Window {
|
||||||
text: i18n("Exit Gaming Mode")
|
text: i18n("Exit Gaming Mode")
|
||||||
display: QQC2.AbstractButton.TextBesideIcon
|
display: QQC2.AbstractButton.TextBesideIcon
|
||||||
Keys.onReturnPressed: clicked()
|
Keys.onReturnPressed: clicked()
|
||||||
|
Keys.onEnterPressed: clicked()
|
||||||
onClicked: root.requestExitGamingMode()
|
onClicked: root.requestExitGamingMode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -183,7 +184,10 @@ Window {
|
||||||
},
|
},
|
||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
text: i18n("Leave")
|
text: i18n("Leave")
|
||||||
onTriggered: ShellSettings.Settings.gamingModeEnabled = false
|
onTriggered: {
|
||||||
|
ShellSettings.Settings.gamingModeEnabled = false
|
||||||
|
theExitDialog.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
onClosed: exitGamingDialog.active = false
|
onClosed: exitGamingDialog.active = false
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ QQC2.ItemDelegate {
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!application) return
|
if (!application) return
|
||||||
if (application.icon !== "" && !application.running) {
|
if (application.icon && typeof application.icon === "string" && application.icon.length > 0 && !application.running) {
|
||||||
MobileShellState.ShellDBusClient.openAppLaunchAnimationWithPosition(
|
MobileShellState.ShellDBusClient.openAppLaunchAnimationWithPosition(
|
||||||
Plasmoid.screen,
|
Plasmoid.screen,
|
||||||
application.icon,
|
application.icon,
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,11 @@ Window {
|
||||||
|
|
||||||
signal openRequested()
|
signal openRequested()
|
||||||
|
|
||||||
width: Kirigami.Units.gridUnit * 4
|
// Guard against startup timing where Kirigami units may briefly be 0/NaN.
|
||||||
height: Kirigami.Units.gridUnit * 2
|
// LayerShell surfaces must never be committed with zero size.
|
||||||
|
readonly property real safeGridUnit: ((Kirigami.Units.gridUnit || 0) > 0) ? Kirigami.Units.gridUnit : 16
|
||||||
|
width: safeGridUnit * 4
|
||||||
|
height: safeGridUnit * 2
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
flags: Qt.FramelessWindowHint
|
flags: Qt.FramelessWindowHint
|
||||||
|
|
||||||
|
|
@ -25,7 +28,11 @@ Window {
|
||||||
LayerShell.Window.exclusionZone: 0
|
LayerShell.Window.exclusionZone: 0
|
||||||
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
|
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
|
||||||
|
|
||||||
opacity: visible ? 1 : 0
|
// Driven by the Loader in folio/qml/main.qml — set false to fade out
|
||||||
|
// before the Loader destroys the window.
|
||||||
|
property bool showing: true
|
||||||
|
|
||||||
|
opacity: showing ? 1 : 0
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad }
|
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,7 @@ Item {
|
||||||
id: resumeArea
|
id: resumeArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
z: -1
|
||||||
// Leave room for the close button
|
// Leave room for the close button
|
||||||
onClicked: {
|
onClicked: {
|
||||||
taskList.currentIndex = index
|
taskList.currentIndex = index
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,9 @@ ContainmentItem {
|
||||||
property Folio.HomeScreen folio: root.plasmoid
|
property Folio.HomeScreen folio: root.plasmoid
|
||||||
|
|
||||||
// Tracks whether the Game Center grid is visible within gaming mode.
|
// Tracks whether the Game Center grid is visible within gaming mode.
|
||||||
// Starts true when gaming mode turns on; set to false by a game launch.
|
// If gaming mode is already enabled at startup, open it immediately so
|
||||||
property bool gameCenterOpen: false
|
// the user is never left without controls.
|
||||||
|
property bool gameCenterOpen: ShellSettings.Settings.gamingModeEnabled
|
||||||
property bool showGameCenterHint: false
|
property bool showGameCenterHint: false
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
|
|
@ -52,6 +53,7 @@ ContainmentItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
root.gameCenterOpen = ShellSettings.Settings.gamingModeEnabled
|
||||||
folio.FolioSettings.load();
|
folio.FolioSettings.load();
|
||||||
folio.FavouritesModel.load();
|
folio.FavouritesModel.load();
|
||||||
folio.PageListModel.load();
|
folio.PageListModel.load();
|
||||||
|
|
@ -698,12 +700,13 @@ ContainmentItem {
|
||||||
|
|
||||||
// Small persistent button at the top-right corner of the screen that lets
|
// Small persistent button at the top-right corner of the screen that lets
|
||||||
// the user return to the Game Center after launching a game.
|
// the user return to the Game Center after launching a game.
|
||||||
// Wrapped in a Loader so the LayerShell Window is destroyed (not merely
|
// Keep the Loader active for the full duration of gaming mode so the
|
||||||
// hidden) when not needed — hiding a LayerShell window with AnchorTop|Right
|
// opacity Behavior in GamingHUD can animate both fade-in and fade-out.
|
||||||
// but no fixed height causes a Wayland protocol error (height=0).
|
|
||||||
Loader {
|
Loader {
|
||||||
active: ShellSettings.Settings.gamingModeEnabled && !root.gameCenterOpen
|
active: ShellSettings.Settings.gamingModeEnabled
|
||||||
sourceComponent: GamingHUD {
|
sourceComponent: GamingHUD {
|
||||||
|
visible: showing
|
||||||
|
showing: !root.gameCenterOpen
|
||||||
onOpenRequested: root.gameCenterOpen = true
|
onOpenRequested: root.gameCenterOpen = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,7 @@ Item {
|
||||||
context: Qt.ApplicationShortcut
|
context: Qt.ApplicationShortcut
|
||||||
onActivated: {
|
onActivated: {
|
||||||
if (drawer.actionDrawer.intendedToBeVisible) {
|
if (drawer.actionDrawer.intendedToBeVisible) {
|
||||||
|
drawer.actionDrawer.intendedToBeVisible = false;
|
||||||
drawer.actionDrawer.close();
|
drawer.actionDrawer.close();
|
||||||
} else {
|
} else {
|
||||||
drawer.actionDrawer.openToPinnedMode = false;
|
drawer.actionDrawer.openToPinnedMode = false;
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ ContainmentItem {
|
||||||
|
|
||||||
function onGamingModeEnabledChanged() {
|
function onGamingModeEnabledChanged() {
|
||||||
root.setWindowProperties();
|
root.setWindowProperties();
|
||||||
MobileShellState.ShellDBusClient.panelState = ShellSettings.Settings.gamingModeEnabled ? "hidden" : "default";
|
MobileShellState.ShellDBusClient.panelState = ShellSettings.Settings.gamingModeEnabled ? "hidden" : (fullscreen ? "hidden" : "default");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,13 +150,13 @@ ContainmentItem {
|
||||||
visible: ShellSettings.Settings.convergenceModeEnabled && !ShellSettings.Settings.gamingModeEnabled
|
visible: ShellSettings.Settings.convergenceModeEnabled && !ShellSettings.Settings.gamingModeEnabled
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
flags: Qt.FramelessWindowHint | Qt.WindowTransparentForInput
|
flags: Qt.FramelessWindowHint | Qt.WindowTransparentForInput
|
||||||
height: root.panelHeight
|
height: Math.max(1, root.panelHeight)
|
||||||
width: 1
|
width: 1
|
||||||
|
|
||||||
LayerShell.Window.scope: "topbar-space"
|
LayerShell.Window.scope: "topbar-space"
|
||||||
LayerShell.Window.layer: LayerShell.Window.LayerBottom
|
LayerShell.Window.layer: LayerShell.Window.LayerBottom
|
||||||
LayerShell.Window.anchors: LayerShell.Window.AnchorTop | LayerShell.Window.AnchorLeft | LayerShell.Window.AnchorRight
|
LayerShell.Window.anchors: LayerShell.Window.AnchorTop | LayerShell.Window.AnchorLeft | LayerShell.Window.AnchorRight
|
||||||
LayerShell.Window.exclusionZone: root.panelHeight
|
LayerShell.Window.exclusionZone: Math.max(1, root.panelHeight)
|
||||||
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
|
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ ContainmentItem {
|
||||||
|
|
||||||
function onGamingModeEnabledChanged() {
|
function onGamingModeEnabledChanged() {
|
||||||
root.setWindowProperties();
|
root.setWindowProperties();
|
||||||
navigationPanel.offset = ShellSettings.Settings.gamingModeEnabled ? root.navigationPanelHeight : 0;
|
navigationPanel.offset = ShellSettings.Settings.gamingModeEnabled ? MobileShell.Constants.navigationPanelThickness : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,13 +166,13 @@ ContainmentItem {
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
flags: Qt.FramelessWindowHint | Qt.WindowTransparentForInput
|
flags: Qt.FramelessWindowHint | Qt.WindowTransparentForInput
|
||||||
// height is set by layer-shell anchoring; provide a fallback.
|
// height is set by layer-shell anchoring; provide a fallback.
|
||||||
height: Kirigami.Units.gridUnit * 3
|
height: Math.max(1, MobileShell.Constants.navigationPanelThickness)
|
||||||
width: 1 // layer-shell stretches it via AnchorLeft|AnchorRight
|
width: 1 // layer-shell stretches it via AnchorLeft|AnchorRight
|
||||||
|
|
||||||
LayerShell.Window.scope: "dock-space"
|
LayerShell.Window.scope: "dock-space"
|
||||||
LayerShell.Window.layer: LayerShell.Window.LayerBottom
|
LayerShell.Window.layer: LayerShell.Window.LayerBottom
|
||||||
LayerShell.Window.anchors: LayerShell.Window.AnchorBottom | LayerShell.Window.AnchorLeft | LayerShell.Window.AnchorRight
|
LayerShell.Window.anchors: LayerShell.Window.AnchorBottom | LayerShell.Window.AnchorLeft | LayerShell.Window.AnchorRight
|
||||||
LayerShell.Window.exclusionZone: Kirigami.Units.gridUnit * 3
|
LayerShell.Window.exclusionZone: Math.max(1, MobileShell.Constants.navigationPanelThickness)
|
||||||
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
|
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ Loader {
|
||||||
|
|
||||||
property var currentWindow
|
property var currentWindow
|
||||||
|
|
||||||
// Window that needs geometry clamping after un-maximize in convergence
|
// Windows awaiting geometry clamping after un-maximize in convergence
|
||||||
// mode. Set in onMaximizedChanged and consumed by the timer below.
|
// mode. Using an array so concurrent un-maximizes are not lost.
|
||||||
property var pendingConstrainWindow: null
|
property var pendingConstrainWindows: []
|
||||||
|
|
||||||
// After a window is un-maximized in convergence mode, the dockSpaceReserver
|
// After a window is un-maximized in convergence mode, the dockSpaceReserver
|
||||||
// LayerShell surface needs one Wayland roundtrip to (re)commit its exclusive
|
// LayerShell surface needs one Wayland roundtrip to (re)commit its exclusive
|
||||||
|
|
@ -24,27 +24,30 @@ Loader {
|
||||||
id: constrainAfterRestoreTimer
|
id: constrainAfterRestoreTimer
|
||||||
interval: 200
|
interval: 200
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
const window = root.pendingConstrainWindow
|
const windows = root.pendingConstrainWindows.slice()
|
||||||
root.pendingConstrainWindow = null
|
root.pendingConstrainWindows = []
|
||||||
if (!window || window.deleted || !window.normalWindow) return
|
for (const window of windows) {
|
||||||
if (!ShellSettings.Settings.convergenceModeEnabled) return
|
if (!window || window.deleted || !window.normalWindow) continue
|
||||||
|
if (!ShellSettings.Settings.convergenceModeEnabled) continue
|
||||||
|
if (ShellSettings.Settings.gamingModeEnabled) continue
|
||||||
|
|
||||||
const output = window.output
|
const output = window.output
|
||||||
const desktop = window.desktops[0]
|
const desktop = window.desktops[0]
|
||||||
if (!output) return
|
if (!output) continue
|
||||||
if (!desktop) return
|
if (!desktop) continue
|
||||||
|
|
||||||
const maxRect = KWinComponents.Workspace.clientArea(
|
const maxRect = KWinComponents.Workspace.clientArea(
|
||||||
KWinComponents.Workspace.MaximizeArea, output, desktop)
|
KWinComponents.Workspace.MaximizeArea, output, desktop)
|
||||||
const geo = window.frameGeometry
|
const geo = window.frameGeometry
|
||||||
const maxBottom = maxRect.y + maxRect.height
|
const maxBottom = maxRect.y + maxRect.height
|
||||||
|
|
||||||
if (geo.y + geo.height > maxBottom) {
|
if (geo.y + geo.height > maxBottom) {
|
||||||
// Clip the bottom edge to MaximizeArea; preserve top position
|
// Clip the bottom edge to MaximizeArea; preserve top position
|
||||||
// and width. Ensure height is at least 100px to avoid
|
// and width. Ensure height is at least 100px to avoid
|
||||||
// pathological cases where the window starts above maxRect.
|
// pathological cases where the window starts above maxRect.
|
||||||
const newH = Math.max(100, maxBottom - geo.y)
|
const newH = Math.max(100, maxBottom - geo.y)
|
||||||
window.frameGeometry = Qt.rect(geo.x, geo.y, geo.width, newH)
|
window.frameGeometry = Qt.rect(geo.x, geo.y, geo.width, newH)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -97,6 +100,9 @@ Loader {
|
||||||
target: currentWindow
|
target: currentWindow
|
||||||
|
|
||||||
function onFullScreenChanged() {
|
function onFullScreenChanged() {
|
||||||
|
if (!currentWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
currentWindow.interactiveMoveResizeFinished.connect((currentWindow) => {
|
currentWindow.interactiveMoveResizeFinished.connect((currentWindow) => {
|
||||||
root.run(currentWindow);
|
root.run(currentWindow);
|
||||||
});
|
});
|
||||||
|
|
@ -104,6 +110,9 @@ Loader {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMaximizedChanged() {
|
function onMaximizedChanged() {
|
||||||
|
if (!currentWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!currentWindow.maximizable) {
|
if (!currentWindow.maximizable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -116,7 +125,7 @@ Loader {
|
||||||
// zone is re-committed over a Wayland roundtrip.
|
// zone is re-committed over a Wayland roundtrip.
|
||||||
if (ShellSettings.Settings.convergenceModeEnabled
|
if (ShellSettings.Settings.convergenceModeEnabled
|
||||||
&& ShellSettings.Settings.autoHidePanelsEnabled) {
|
&& ShellSettings.Settings.autoHidePanelsEnabled) {
|
||||||
root.pendingConstrainWindow = currentWindow
|
root.pendingConstrainWindows.push(currentWindow)
|
||||||
constrainAfterRestoreTimer.restart()
|
constrainAfterRestoreTimer.restart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -150,6 +159,9 @@ Loader {
|
||||||
target: KWinComponents.Workspace
|
target: KWinComponents.Workspace
|
||||||
|
|
||||||
function onWindowAdded(window) {
|
function onWindowAdded(window) {
|
||||||
|
if (!window) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (window.normalWindow) {
|
if (window.normalWindow) {
|
||||||
window.interactiveMoveResizeFinished.connect((window) => {
|
window.interactiveMoveResizeFinished.connect((window) => {
|
||||||
root.run(window);
|
root.run(window);
|
||||||
|
|
@ -159,6 +171,9 @@ Loader {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWindowActivated(window) {
|
function onWindowActivated(window) {
|
||||||
|
if (!window) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (window.normalWindow) {
|
if (window.normalWindow) {
|
||||||
currentWindow = window;
|
currentWindow = window;
|
||||||
window.interactiveMoveResizeFinished.connect((window) => {
|
window.interactiveMoveResizeFinished.connect((window) => {
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,14 @@
|
||||||
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
# SPDX-License-Identifier: EUPL-1.2
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
$XGETTEXT `find . -name \*.js -o -name \*.qml -o -name \*.cpp` -o $podir/plasma_org.kde.plasma.quicksetting.gaming.pot
|
set -e
|
||||||
|
: "${XGETTEXT:?XGETTEXT is not set}"
|
||||||
|
: "${podir:?podir is not set}"
|
||||||
|
|
||||||
|
mapfile -t files < <(find . \( -name '*.js' -o -name '*.qml' -o -name '*.cpp' \) -print)
|
||||||
|
if [[ ${#files[@]} -eq 0 ]]; then
|
||||||
|
echo "Messages.sh: no input files found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
"$XGETTEXT" "${files[@]}" -o "$podir/plasma_org.kde.plasma.quicksetting.gaming.pot"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ QS.QuickSetting {
|
||||||
|
|
||||||
function requestDisable() {
|
function requestDisable() {
|
||||||
confirmDisableDialog.active = true;
|
confirmDisableDialog.active = true;
|
||||||
confirmDisableDialog.item.open();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggle() {
|
function toggle() {
|
||||||
|
|
@ -33,6 +32,7 @@ QS.QuickSetting {
|
||||||
Loader {
|
Loader {
|
||||||
id: confirmDisableDialog
|
id: confirmDisableDialog
|
||||||
active: false
|
active: false
|
||||||
|
onLoaded: item.open()
|
||||||
|
|
||||||
sourceComponent: Kirigami.PromptDialog {
|
sourceComponent: Kirigami.PromptDialog {
|
||||||
id: theConfirmDialog
|
id: theConfirmDialog
|
||||||
|
|
@ -46,7 +46,10 @@ QS.QuickSetting {
|
||||||
},
|
},
|
||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
text: i18n("Leave")
|
text: i18n("Leave")
|
||||||
onTriggered: ShellSettings.Settings.gamingModeEnabled = false
|
onTriggered: {
|
||||||
|
ShellSettings.Settings.gamingModeEnabled = false
|
||||||
|
theConfirmDialog.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
onClosed: confirmDisableDialog.active = false
|
onClosed: confirmDisableDialog.active = false
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,14 @@
|
||||||
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
# SPDX-License-Identifier: EUPL-1.2
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
$XGETTEXT *.json contents/ui/*.qml -o $podir/plasma_mobile_qt.pot
|
set -e
|
||||||
|
: "${XGETTEXT:?XGETTEXT is not set}"
|
||||||
|
: "${podir:?podir is not set}"
|
||||||
|
|
||||||
|
shopt -s nullglob
|
||||||
|
files=(*.json contents/ui/*.qml)
|
||||||
|
if [[ ${#files[@]} -eq 0 ]]; then
|
||||||
|
echo "Messages.sh: no input files found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
"$XGETTEXT" "${files[@]}" -o "$podir/plasma_mobile_qt.pot"
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ import org.kde.plasma.private.mobileshell.quicksettingsplugin as QS
|
||||||
QS.QuickSetting {
|
QS.QuickSetting {
|
||||||
text: i18n("Launch Hint")
|
text: i18n("Launch Hint")
|
||||||
icon: "dialog-information"
|
icon: "dialog-information"
|
||||||
status: ""
|
status: ShellSettings.Settings.gamingDismissHintEnabled ? i18n("On") : i18n("Off")
|
||||||
enabled: ShellSettings.Settings.gamingDismissHintEnabled
|
enabled: true
|
||||||
available: ShellSettings.Settings.gamingModeEnabled
|
available: ShellSettings.Settings.gamingModeEnabled
|
||||||
|
|
||||||
function toggle() {
|
function toggle() {
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
SPDX-FileCopyrightText: 2026 Marco Allegretti.
|
SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
SPDX-License-Identifier: EUPL-1.2
|
SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue