mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-07-30 00:04:45 +00:00
Suppress shell chrome in gaming mode
Hide the navigation panel, status bar, and app drawer while gamingModeEnabled is active. The KWin convergent-windows script skips its window policy so game windows are not forcibly tiled or maximized. The Home button in gaming mode re-opens the Game Center overlay rather than the app drawer. A configurable hint nudges the user toward the HUD button after launching a game.
This commit is contained in:
parent
d901815c9d
commit
b0739dd9a7
4 changed files with 134 additions and 6 deletions
|
|
@ -25,12 +25,32 @@ import org.kde.kirigamiaddons.components as KirigamiAddonsComponents
|
||||||
|
|
||||||
import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio
|
import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio
|
||||||
|
|
||||||
|
import "./gaming"
|
||||||
|
|
||||||
import "./private"
|
import "./private"
|
||||||
|
|
||||||
ContainmentItem {
|
ContainmentItem {
|
||||||
id: root
|
id: root
|
||||||
property Folio.HomeScreen folio: root.plasmoid
|
property Folio.HomeScreen folio: root.plasmoid
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
property bool gameCenterOpen: false
|
||||||
|
property bool showGameCenterHint: false
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: gameCenterHintTimer
|
||||||
|
interval: 2600
|
||||||
|
onTriggered: root.showGameCenterHint = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: ShellSettings.Settings
|
||||||
|
function onGamingModeEnabledChanged() {
|
||||||
|
root.gameCenterOpen = ShellSettings.Settings.gamingModeEnabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
folio.FolioSettings.load();
|
folio.FolioSettings.load();
|
||||||
folio.FavouritesModel.load();
|
folio.FavouritesModel.load();
|
||||||
|
|
@ -89,6 +109,12 @@ ContainmentItem {
|
||||||
MobileShellState.ShellDBusClient.closeActionDrawer();
|
MobileShellState.ShellDBusClient.closeActionDrawer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ShellSettings.Settings.gamingModeEnabled) {
|
||||||
|
// In gaming mode Home/Menu should reopen the Game Center overlay.
|
||||||
|
root.gameCenterOpen = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ShellSettings.Settings.convergenceModeEnabled) {
|
if (ShellSettings.Settings.convergenceModeEnabled) {
|
||||||
// Convergence: toggle the app drawer as a layer-shell overlay
|
// Convergence: toggle the app drawer as a layer-shell overlay
|
||||||
// without disturbing open windows.
|
// without disturbing open windows.
|
||||||
|
|
@ -186,7 +212,7 @@ ContainmentItem {
|
||||||
// task panel containment; this window only provides the visible dock.
|
// task panel containment; this window only provides the visible dock.
|
||||||
Window {
|
Window {
|
||||||
id: dockOverlay
|
id: dockOverlay
|
||||||
visible: ShellSettings.Settings.convergenceModeEnabled
|
visible: ShellSettings.Settings.convergenceModeEnabled && !ShellSettings.Settings.gamingModeEnabled
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
width: Screen.width
|
width: Screen.width
|
||||||
height: Kirigami.Units.gridUnit * 3
|
height: Kirigami.Units.gridUnit * 3
|
||||||
|
|
@ -286,6 +312,7 @@ ContainmentItem {
|
||||||
Window {
|
Window {
|
||||||
id: drawerOverlay
|
id: drawerOverlay
|
||||||
visible: ShellSettings.Settings.convergenceModeEnabled
|
visible: ShellSettings.Settings.convergenceModeEnabled
|
||||||
|
&& !ShellSettings.Settings.gamingModeEnabled
|
||||||
&& folio.HomeScreenState.appDrawerOpenProgress > 0
|
&& folio.HomeScreenState.appDrawerOpenProgress > 0
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
width: Screen.width
|
width: Screen.width
|
||||||
|
|
@ -645,6 +672,68 @@ ContainmentItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Game Center overlay — full-screen grid of games shown when gaming mode
|
||||||
|
// is active. Sits at LayerTop so it covers running application windows
|
||||||
|
// without going above system notifications.
|
||||||
|
GameCenterOverlay {
|
||||||
|
id: gameCenterOverlay
|
||||||
|
folio: root.folio
|
||||||
|
visible: ShellSettings.Settings.gamingModeEnabled && root.gameCenterOpen
|
||||||
|
|
||||||
|
onGameStarted: root.gameCenterOpen = false
|
||||||
|
onDismissRequested: {
|
||||||
|
root.gameCenterOpen = false
|
||||||
|
if (ShellSettings.Settings.gamingDismissHintEnabled) {
|
||||||
|
root.showGameCenterHint = true
|
||||||
|
gameCenterHintTimer.restart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onVisibleChanged: {
|
||||||
|
if (!visible) {
|
||||||
|
folio.ApplicationListSearchModel.categoryFilter = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Small persistent button at the top-right corner of the screen that lets
|
||||||
|
// the user return to the Game Center after launching a game.
|
||||||
|
GamingHUD {
|
||||||
|
visible: ShellSettings.Settings.gamingModeEnabled && !root.gameCenterOpen
|
||||||
|
onOpenRequested: root.gameCenterOpen = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: gameCenterHint
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: Kirigami.Units.gridUnit * 2
|
||||||
|
visible: root.showGameCenterHint && ShellSettings.Settings.gamingDismissHintEnabled
|
||||||
|
opacity: visible ? 1 : 0
|
||||||
|
z: 2000
|
||||||
|
radius: Kirigami.Units.cornerRadius
|
||||||
|
color: Qt.rgba(0, 0, 0, 0.65)
|
||||||
|
border.width: 1
|
||||||
|
border.color: Qt.rgba(1, 1, 1, 0.2)
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad }
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitWidth: hintText.implicitWidth + Kirigami.Units.gridUnit * 2
|
||||||
|
implicitHeight: hintText.implicitHeight + Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
|
PlasmaComponents.Label {
|
||||||
|
id: hintText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: i18n("Gaming mode is still on. Use Home or the gamepad icon to reopen Game Center.")
|
||||||
|
color: "white"
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: Math.min(root.width * 0.8, Kirigami.Units.gridUnit * 30)
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MobileShell.HomeScreen {
|
MobileShell.HomeScreen {
|
||||||
id: homeScreen
|
id: homeScreen
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
|
||||||
|
|
@ -34,11 +34,17 @@ ContainmentItem {
|
||||||
// Whether the startup feedback is showing
|
// Whether the startup feedback is showing
|
||||||
readonly property bool showingStartupFeedback: MobileShellState.ShellDBusObject.startupFeedbackModel.activeWindowIsStartupFeedback
|
readonly property bool showingStartupFeedback: MobileShellState.ShellDBusObject.startupFeedbackModel.activeWindowIsStartupFeedback
|
||||||
|
|
||||||
|
readonly property bool gamingMode: ShellSettings.Settings.gamingModeEnabled
|
||||||
|
|
||||||
// Whether an app is maximized and showing (does not include startup feedback)
|
// Whether an app is maximized and showing (does not include startup feedback)
|
||||||
readonly property bool showingApp: windowMaximizedTracker.showingWindow && !showingStartupFeedback
|
readonly property bool showingApp: windowMaximizedTracker.showingWindow && !showingStartupFeedback
|
||||||
|
|
||||||
// Whether the currently showing app is in "fullscreen"
|
// Whether the currently showing app is in "fullscreen"
|
||||||
readonly property bool fullscreen: {
|
readonly property bool fullscreen: {
|
||||||
|
if (gamingMode) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// In convergence mode the status bar is always visible, like a desktop panel.
|
// In convergence mode the status bar is always visible, like a desktop panel.
|
||||||
if (ShellSettings.Settings.convergenceModeEnabled) {
|
if (ShellSettings.Settings.convergenceModeEnabled) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -69,7 +75,7 @@ ContainmentItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property real panelHeight: MobileShell.Constants.topPanelHeight
|
readonly property real panelHeight: gamingMode ? 0 : MobileShell.Constants.topPanelHeight
|
||||||
onPanelHeightChanged: setWindowProperties()
|
onPanelHeightChanged: setWindowProperties()
|
||||||
|
|
||||||
function setWindowProperties() {
|
function setWindowProperties() {
|
||||||
|
|
@ -123,6 +129,11 @@ ContainmentItem {
|
||||||
function onConvergenceModeEnabledChanged() {
|
function onConvergenceModeEnabledChanged() {
|
||||||
root.setWindowProperties();
|
root.setWindowProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onGamingModeEnabledChanged() {
|
||||||
|
root.setWindowProperties();
|
||||||
|
MobileShellState.ShellDBusClient.panelState = ShellSettings.Settings.gamingModeEnabled ? "hidden" : "default";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
|
@ -136,7 +147,7 @@ ContainmentItem {
|
||||||
// MaximizeArea by the panel height.
|
// MaximizeArea by the panel height.
|
||||||
Window {
|
Window {
|
||||||
id: topBarSpaceReserver
|
id: topBarSpaceReserver
|
||||||
visible: ShellSettings.Settings.convergenceModeEnabled
|
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: root.panelHeight
|
||||||
|
|
@ -152,6 +163,7 @@ ContainmentItem {
|
||||||
// Visual panel component
|
// Visual panel component
|
||||||
StatusPanel {
|
StatusPanel {
|
||||||
id: statusPanel
|
id: statusPanel
|
||||||
|
visible: !ShellSettings.Settings.gamingModeEnabled
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
containmentItem: root
|
containmentItem: root
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,14 @@ ContainmentItem {
|
||||||
|
|
||||||
readonly property bool inLandscape: MobileShell.Constants.navigationPanelOnSide(Screen.width, Screen.height)
|
readonly property bool inLandscape: MobileShell.Constants.navigationPanelOnSide(Screen.width, Screen.height)
|
||||||
|
|
||||||
readonly property real navigationPanelHeight: MobileShell.Constants.navigationPanelThickness
|
readonly property bool gamingMode: ShellSettings.Settings.gamingModeEnabled
|
||||||
|
|
||||||
|
readonly property real navigationPanelHeight: gamingMode ? 0 : MobileShell.Constants.navigationPanelThickness
|
||||||
onNavigationPanelHeightChanged: setWindowProperties()
|
onNavigationPanelHeightChanged: setWindowProperties()
|
||||||
|
|
||||||
readonly property real intendedWindowThickness: navigationPanelHeight
|
readonly property real intendedWindowThickness: navigationPanelHeight
|
||||||
readonly property real intendedWindowLength: inLandscape ? Screen.height : Screen.width
|
readonly property real intendedWindowLength: inLandscape ? Screen.height : Screen.width
|
||||||
readonly property real intendedWindowOffset: inLandscape ? MobileShell.Constants.topPanelHeight : 0; // offset for top panel
|
readonly property real intendedWindowOffset: (inLandscape && !gamingMode) ? MobileShell.Constants.topPanelHeight : 0; // offset for top panel
|
||||||
readonly property int intendedWindowLocation: inLandscape ? PlasmaCore.Types.RightEdge : PlasmaCore.Types.BottomEdge
|
readonly property int intendedWindowLocation: inLandscape ? PlasmaCore.Types.RightEdge : PlasmaCore.Types.BottomEdge
|
||||||
|
|
||||||
onIntendedWindowLengthChanged: maximizeTimer.restart() // ensure it always takes up the full length of the screen
|
onIntendedWindowLengthChanged: maximizeTimer.restart() // ensure it always takes up the full length of the screen
|
||||||
|
|
@ -136,6 +138,11 @@ ContainmentItem {
|
||||||
function onConvergenceModeEnabledChanged() {
|
function onConvergenceModeEnabledChanged() {
|
||||||
root.setWindowProperties();
|
root.setWindowProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onGamingModeEnabledChanged() {
|
||||||
|
root.setWindowProperties();
|
||||||
|
navigationPanel.offset = ShellSettings.Settings.gamingModeEnabled ? root.navigationPanelHeight : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: setWindowProperties();
|
Component.onCompleted: setWindowProperties();
|
||||||
|
|
@ -153,6 +160,7 @@ ContainmentItem {
|
||||||
Window {
|
Window {
|
||||||
id: dockSpaceReserver
|
id: dockSpaceReserver
|
||||||
visible: ShellSettings.Settings.convergenceModeEnabled
|
visible: ShellSettings.Settings.convergenceModeEnabled
|
||||||
|
&& !ShellSettings.Settings.gamingModeEnabled
|
||||||
&& !(ShellSettings.Settings.autoHidePanelsEnabled
|
&& !(ShellSettings.Settings.autoHidePanelsEnabled
|
||||||
&& windowMaximizedTracker.showingWindow)
|
&& windowMaximizedTracker.showingWindow)
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
@ -177,7 +185,9 @@ ContainmentItem {
|
||||||
return (windowMaximizedTracker.showingWindow || isCurrentWindowFullscreen) && !showingStartupFeedback
|
return (windowMaximizedTracker.showingWindow || isCurrentWindowFullscreen) && !showingStartupFeedback
|
||||||
}
|
}
|
||||||
readonly property alias isCurrentWindowFullscreen: windowMaximizedTracker.isCurrentWindowFullscreen
|
readonly property alias isCurrentWindowFullscreen: windowMaximizedTracker.isCurrentWindowFullscreen
|
||||||
readonly property bool fullscreen: isCurrentWindowFullscreen || (ShellSettings.Settings.autoHidePanelsEnabled && opaqueBar)
|
readonly property bool fullscreen: ShellSettings.Settings.gamingModeEnabled
|
||||||
|
|| isCurrentWindowFullscreen
|
||||||
|
|| (ShellSettings.Settings.autoHidePanelsEnabled && opaqueBar)
|
||||||
|
|
||||||
WindowPlugin.WindowMaximizedTracker {
|
WindowPlugin.WindowMaximizedTracker {
|
||||||
id: windowMaximizedTracker
|
id: windowMaximizedTracker
|
||||||
|
|
@ -205,6 +215,7 @@ ContainmentItem {
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: navigationPanel
|
id: navigationPanel
|
||||||
|
visible: !ShellSettings.Settings.gamingModeEnabled
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
property real offset: 0
|
property real offset: 0
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,12 @@ Loader {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ShellSettings.Settings.gamingModeEnabled) {
|
||||||
|
window.noBorder = true;
|
||||||
|
window.setMaximize(true, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ShellSettings.Settings.convergenceModeEnabled) {
|
if (ShellSettings.Settings.convergenceModeEnabled) {
|
||||||
window.noBorder = false;
|
window.noBorder = false;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -128,6 +134,16 @@ Loader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onGamingModeEnabledChanged() {
|
||||||
|
const windows = KWinComponents.Workspace.windows;
|
||||||
|
|
||||||
|
for (let i = 0; i < windows.length; i++) {
|
||||||
|
if (windows[i].normalWindow) {
|
||||||
|
root.run(windows[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue