Shrink to a floating button instead of hiding

With "Shrink to Button" on, the dismiss key shrinks the window to just
itself: a see-through button that can be dragged anywhere. Tapping it
grows the keyboard back around it, kept on screen. KWin moves and
resizes the window through a one-off script, as Wayland clients can't
place themselves.

Also moves the window back on screen whenever it appears (KWin remembers
where the button was), and releases the mouse after a window manager
move or resize, which used to eat the next press on the grab bar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-31 01:05:37 +01:00
co-authored by Claude Opus 5.5
parent ac5f43ca5f
commit 032fbd8ba4
15 changed files with 401 additions and 14 deletions
+30 -6
View File
@@ -9,6 +9,8 @@ Window {
required property Settings settings
required property Diagnostics diagnostics
property var placement: null // FloatingWindow, set from C++
property var collapse: null // CollapseController, set from C++
readonly property bool collapsed: collapse?.collapsed ?? false
property bool settingsOpen: false
// Height of the key area, for C++ keeping key sizes when rows change.
readonly property real keysHeight: keyboard.height
@@ -16,23 +18,31 @@ Window {
// Transparent room above the keyboard for long-press popups on the top row.
readonly property real popupMargin: 90
// Outside this, input passes through to whatever is below the window.
readonly property rect inputRegion: keyboard.alternates.open
readonly property rect inputRegion: collapsed
? Qt.rect(floatingButton.x, floatingButton.y, floatingButton.width, floatingButton.height)
: keyboard.alternates.open
? Qt.rect(0, 0, width, height)
: Qt.rect(panel.x, panel.y, panel.width, panel.height)
// Empty when nothing shows through, so the compositor skips the blur.
readonly property rect blurRegion: settings.blurBackground && settings.backgroundOpacity < 1
readonly property rect blurRegion: !collapsed && settings.blurBackground && settings.backgroundOpacity < 1
? Qt.rect(panel.x, panel.y, panel.width, panel.height)
: Qt.rect(0, 0, 0, 0)
width: 1000
height: 340 + popupMargin
minimumWidth: 480
minimumHeight: 180 + popupMargin
// None while shrunk to the floating button.
minimumWidth: collapsed ? 0 : 480
minimumHeight: collapsed ? 0 : 180 + popupMargin
visible: false
color: "transparent"
onInputRegionChanged: placement?.setInputRegion(inputRegion)
onBlurRegionChanged: placement?.setBlurRegion(blurRegion, Theme.windowRadius)
// For CollapseController.
function dismissKeyRect() {
return keyboard.keyRect("dismiss");
}
onPlacementChanged: {
placement?.setInputRegion(inputRegion);
placement?.setBlurRegion(blurRegion, Theme.windowRadius);
@@ -41,6 +51,7 @@ Window {
Rectangle {
id: panel
anchors { fill: parent; topMargin: root.popupMargin }
visible: !root.collapsed
radius: Theme.windowRadius
color: Qt.rgba(Theme.background.r, Theme.background.g, Theme.background.b, root.settings.backgroundOpacity)
@@ -66,7 +77,7 @@ Window {
id: handle
anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
pillWidth: Math.min(120, width - 2 * (quickToggles.x + quickToggles.width + 12))
onDragStarted: root.startSystemMove()
onDragStarted: root.placement.startMove()
}
SettingsButton {
@@ -86,7 +97,20 @@ Window {
ResizeHandle {
anchors { right: parent.right; bottom: parent.bottom }
onDragStarted: root.startSystemResize(Qt.RightEdge | Qt.BottomEdge)
onDragStarted: root.placement.startResize(Qt.RightEdge | Qt.BottomEdge)
}
}
FloatingButton {
id: floatingButton
readonly property rect keyRect: root.collapse?.keyRect ?? Qt.rect(0, 0, 0, 0)
// Over the key while the window is full size, then in the shrunk window.
x: Math.max(0, Math.min(keyRect.x, root.width - width))
y: Math.max(0, Math.min(keyRect.y, root.height - height))
width: keyRect.width
height: keyRect.height
visible: root.collapsed
onTapped: root.collapse.expand()
onDragStarted: root.placement.startMove()
}
}