WIP
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Wayland
|
||||
import QtQuick
|
||||
import qs.HyprChrome.Theme
|
||||
|
||||
// Primary application launcher — the one on SUPER_L.
|
||||
//
|
||||
// Migrated from widgets/launcher/ApplicationLauncher.qml. Two things changed in
|
||||
// the move, both because HyprChromeShell now owns the state its surfaces share:
|
||||
//
|
||||
// * no scrim of its own. The shell raises the single ChromeBackdrop for any
|
||||
// of its causes — expanded rail, polkit prompt, this — so opening the
|
||||
// launcher over an already-expanded rail reuses the scrim that is there
|
||||
// rather than laying a second dim on top of it.
|
||||
// * `active` is read by the shell, which uses it to raise that scrim, to
|
||||
// place this on the focused monitor, and to decide who gets the keyboard.
|
||||
//
|
||||
// The full-screen layer-shell adapter owns focus, DesktopEntries and execution;
|
||||
// AppLauncherContent stays an Item so the whole visual state can be rendered
|
||||
// headlessly (tests/AppLauncherHeadless.qml).
|
||||
Scope {
|
||||
id: root
|
||||
|
||||
property bool active: false
|
||||
|
||||
// Which output to appear on. Driven by the shell, which puts it on the
|
||||
// focused monitor — a launcher belongs where the user is looking, which is
|
||||
// not necessarily where the rail lives.
|
||||
property var screen: null
|
||||
|
||||
function toggle() { root.active = !root.active; }
|
||||
function close() { root.active = false; }
|
||||
|
||||
// The name is legacy: this was "variant 8" of eleven, and both SUPER_L (via
|
||||
// open_launcher.sh) and SUPER CTRL 8 still dispatch quickshell:launcher8.
|
||||
// Renaming it means editing hosts/terra/home/hyprland.nix AND the script
|
||||
// together, and neither takes effect until a deploy — so the shortcut would
|
||||
// be dead in the running session in between. Kept as-is deliberately.
|
||||
GlobalShortcut {
|
||||
name: "launcher8"
|
||||
description: "Toggle dense application command index"
|
||||
onPressed: root.toggle()
|
||||
}
|
||||
|
||||
PanelWindow {
|
||||
id: win
|
||||
|
||||
screen: root.screen
|
||||
visible: root.active
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
color: Theme.textAlpha(0)
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
property int selectedIndex: 0
|
||||
|
||||
function clampSelection(index) {
|
||||
if (model.apps.length === 0)
|
||||
return 0;
|
||||
return Math.max(0, Math.min(model.apps.length - 1, index));
|
||||
}
|
||||
|
||||
function move(delta) {
|
||||
const count = model.apps.length;
|
||||
if (count === 0)
|
||||
return;
|
||||
selectedIndex = ((selectedIndex + delta) % count + count) % count;
|
||||
}
|
||||
|
||||
function launch(index) {
|
||||
if (model.launch(index))
|
||||
root.active = false;
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
content.clearSearch();
|
||||
selectedIndex = 0;
|
||||
content.focusSearch();
|
||||
}
|
||||
}
|
||||
|
||||
AppModel {
|
||||
id: model
|
||||
search: content.query
|
||||
}
|
||||
|
||||
// Click-off dismissal. The scrim itself belongs to the shell and takes
|
||||
// no input (its mask is empty), so the catcher lives here: a
|
||||
// transparent full-surface MouseArea UNDER the content, which is what
|
||||
// keeps clicks on the launcher itself from closing it.
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root.close()
|
||||
}
|
||||
|
||||
AppLauncherContent {
|
||||
id: content
|
||||
|
||||
anchors.centerIn: parent
|
||||
width: 1080
|
||||
height: 620
|
||||
scale: Math.min(1, (parent.width - 64) / width, (parent.height - 64) / height)
|
||||
transformOrigin: Item.Center
|
||||
apps: model.apps
|
||||
selectedIndex: win.selectedIndex
|
||||
|
||||
onSelectionRequested: index => win.selectedIndex = win.clampSelection(index)
|
||||
onMoveRequested: delta => win.move(delta)
|
||||
onLaunchRequested: index => win.launch(index)
|
||||
onDismissRequested: root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user