Open app drawer over windows in convergence mode

Drawer is inside the homescreen, which sits behind windows.
Home button minimized everything to reach it. Render it in
a LayerTop window instead and skip the blanket minimizeAll
in the D-Bus handler.
This commit is contained in:
Marco Allegretti 2026-04-15 10:18:34 +02:00
parent c61642265b
commit 7fa2c20ab4
3 changed files with 128 additions and 41 deletions

View file

@ -80,6 +80,13 @@ Item {
target: MobileShellState.ShellDBusClient
function onOpenHomeScreenRequested() {
if (ShellSettings.Settings.convergenceModeEnabled) {
// In convergence mode let the containment handle everything
// via homeTriggered homeAction() without touching windows.
root.homeTriggered();
return;
}
if (windowMaximizedTracker.showingWindow) {
itemContainer.zoomIn();
}

View file

@ -515,26 +515,22 @@ Item {
transform: Translate { y: folderView.opacity > 0 ? 0 : folderView.height }
}
// Click-to-dismiss overlay for popup drawer in convergence mode
// Click-to-dismiss overlay (mobile only; convergence uses layer-shell overlay)
MouseArea {
anchors.fill: parent
anchors.bottomMargin: ShellSettings.Settings.convergenceModeEnabled ? favouritesBar.height : 0
visible: ShellSettings.Settings.convergenceModeEnabled && homeScreenState.appDrawerOpenProgress > 0
visible: !ShellSettings.Settings.convergenceModeEnabled
&& homeScreenState.appDrawerOpenProgress > 0
onClicked: folio.HomeScreenState.closeAppDrawer()
}
// bottom app drawer
// bottom app drawer (mobile only; convergence uses layer-shell overlay)
AppDrawer {
id: appDrawer
folio: root.folio
visible: !ShellSettings.Settings.convergenceModeEnabled
// Convergence: popup above dock; mobile: full-screen
property bool isPopup: ShellSettings.Settings.convergenceModeEnabled
property real popupWidth: Math.min(Kirigami.Units.gridUnit * 28, parent.width * 0.5)
property real popupHeight: Math.min(Kirigami.Units.gridUnit * 32, parent.height * 0.7)
width: isPopup ? popupWidth : parent.width
height: isPopup ? popupHeight : parent.height
width: parent.width
height: parent.height
homeScreen: root
@ -544,20 +540,11 @@ Item {
// position for animation
property real animationY: (1 - homeScreenState.appDrawerOpenProgress) * (Kirigami.Units.gridUnit * 2)
// Convergence popup position: above dock, left-aligned
property real popupX: root.leftMargin + Kirigami.Units.smallSpacing
property real popupY: (opacity > 0)
? parent.height - favouritesBar.height - popupHeight - Kirigami.Units.smallSpacing + animationY
: parent.height
// Full-screen position
property real fullX: 0
property real fullY: (opacity > 0) ? animationY : parent.height
x: 0
y: (opacity > 0) ? animationY : parent.height
x: isPopup ? popupX : fullX
y: isPopup ? popupY : fullY
headerHeight: Math.round(Kirigami.Units.gridUnit * (appDrawer.isPopup ? 3 : 4))
headerHeight: Math.round(Kirigami.Units.gridUnit * 4)
headerItem: AppDrawerHeader {
id: appDrawerHeader
folio: root.folio
@ -565,11 +552,11 @@ Item {
onReleaseFocusRequested: appDrawer.forceActiveFocus()
}
// Account for panels (popup handles its own margins)
topPadding: appDrawer.isPopup ? 0 : root.topMargin
bottomPadding: appDrawer.isPopup ? 0 : root.bottomMargin
leftPadding: appDrawer.isPopup ? 0 : root.leftMargin
rightPadding: appDrawer.isPopup ? 0 : root.rightMargin
// Account for panels
topPadding: root.topMargin
bottomPadding: root.bottomMargin
leftPadding: root.leftMargin
rightPadding: root.rightMargin
// Forward keyboard text to the search bar
Keys.onPressed: (event) => {

View file

@ -85,19 +85,36 @@ ContainmentItem {
MobileShellState.ShellDBusClient.closeActionDrawer();
}
if (ShellSettings.Settings.convergenceModeEnabled) {
// Convergence: toggle the app drawer as a layer-shell overlay
// without disturbing open windows.
switch (folio.HomeScreenState.viewState) {
case Folio.HomeScreenState.AppDrawerView:
folio.HomeScreenState.closeAppDrawer();
break;
case Folio.HomeScreenState.FolderView:
folio.HomeScreenState.closeFolder();
break;
case Folio.HomeScreenState.SearchWidgetView:
folio.HomeScreenState.closeSearchWidget();
break;
case Folio.HomeScreenState.SettingsView:
folio.HomeScreenState.closeSettingsView();
break;
default:
folio.HomeScreenState.openAppDrawer();
break;
}
return;
}
if (isInWindow) {
// Only minimize windows and go to homescreen when not in docked mode
if (!ShellSettings.Settings.convergenceModeEnabled) {
folio.HomeScreenState.closeFolder();
folio.HomeScreenState.closeSearchWidget();
folio.HomeScreenState.closeAppDrawer();
folio.HomeScreenState.goToPage(0, false);
WindowPlugin.WindowUtil.minimizeAll();
} else {
// In convergence mode, toggle "show desktop" (minimize all to reveal homescreen)
WindowPlugin.WindowUtil.minimizeAll();
}
// Always ensure settings view is closed
if (folio.HomeScreenState.viewState == Folio.HomeScreenState.SettingsView) {
@ -107,7 +124,7 @@ ContainmentItem {
} else { // If we are already on the homescreen
switch (folio.HomeScreenState.viewState) {
case Folio.HomeScreenState.PageView:
if (ShellSettings.Settings.convergenceModeEnabled || folio.HomeScreenState.currentPage === 0) {
if (folio.HomeScreenState.currentPage === 0) {
folio.HomeScreenState.openAppDrawer();
} else {
folio.HomeScreenState.goToPage(0, false);
@ -221,6 +238,82 @@ ContainmentItem {
}
}
// App-drawer overlay renders the popup drawer above application
// windows in convergence mode. Same pattern as the dock overlay:
// a fullscreen layer-shell surface at LayerTop so that it appears
// over normal windows without minimizing them.
Window {
id: drawerOverlay
visible: ShellSettings.Settings.convergenceModeEnabled
&& folio.HomeScreenState.appDrawerOpenProgress > 0
color: "transparent"
width: Screen.width
height: Screen.height
LayerShell.Window.scope: "drawer-overlay"
LayerShell.Window.layer: LayerShell.Window.LayerTop
LayerShell.Window.anchors: LayerShell.Window.AnchorTop | LayerShell.Window.AnchorBottom
| LayerShell.Window.AnchorLeft | LayerShell.Window.AnchorRight
LayerShell.Window.exclusionZone: -1
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityOnDemand
// Click outside the popup to dismiss
MouseArea {
anchors.fill: parent
onClicked: folio.HomeScreenState.closeAppDrawer()
}
AppDrawer {
id: overlayDrawer
folio: root.folio
homeScreen: folioHomeScreen
readonly property real popupWidth: Math.min(Kirigami.Units.gridUnit * 28, parent.width * 0.5)
readonly property real popupHeight: Math.min(Kirigami.Units.gridUnit * 32, parent.height * 0.7)
readonly property real dockHeight: Kirigami.Units.gridUnit * 3
width: popupWidth
height: popupHeight
opacity: folio.HomeScreenState.appDrawerOpenProgress < 0.5
? 0 : (folio.HomeScreenState.appDrawerOpenProgress - 0.5) * 2
property real animationY: (1 - folio.HomeScreenState.appDrawerOpenProgress) * (Kirigami.Units.gridUnit * 2)
x: Kirigami.Units.smallSpacing
y: (opacity > 0)
? parent.height - dockHeight - popupHeight - Kirigami.Units.smallSpacing + animationY
: parent.height
headerHeight: Math.round(Kirigami.Units.gridUnit * 3)
headerItem: AppDrawerHeader {
id: overlayDrawerHeader
folio: root.folio
onReleaseFocusRequested: overlayDrawer.forceActiveFocus()
}
Keys.onPressed: (event) => {
if (event.text.trim().length > 0) {
overlayDrawerHeader.addSearchText(event.text);
overlayDrawerHeader.forceActiveFocus();
event.accepted = true;
} else if (event.key === Qt.Key_Left || event.key === Qt.Key_Right
|| event.key === Qt.Key_Up || event.key === Qt.Key_Down) {
overlayDrawerHeader.forceActiveFocus();
event.accepted = true;
}
}
Connections {
target: folio.HomeScreenState
function onAppDrawerOpened() {
overlayDrawer.forceActiveFocus();
}
}
}
}
MobileShell.HomeScreen {
id: homeScreen
anchors.fill: parent