mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 21:42:51 -05:00
spotlight: fix clipping and add context menu keyboard navigation (#840)
* spotlight: fix clipping and add context menu keyboard navigation * prime: also detect nvidia-offload command * spotlight: fix review nitpicks
This commit is contained in:
@@ -11,8 +11,10 @@ Item {
|
|||||||
property alias appLauncher: appLauncher
|
property alias appLauncher: appLauncher
|
||||||
property alias searchField: searchField
|
property alias searchField: searchField
|
||||||
property alias fileSearchController: fileSearchController
|
property alias fileSearchController: fileSearchController
|
||||||
|
property alias resultsView: resultsView
|
||||||
property var parentModal: null
|
property var parentModal: null
|
||||||
property string searchMode: "apps"
|
property string searchMode: "apps"
|
||||||
|
property bool usePopupContextMenu: false
|
||||||
|
|
||||||
function resetScroll() {
|
function resetScroll() {
|
||||||
if (searchMode === "apps") {
|
if (searchMode === "apps") {
|
||||||
@@ -146,6 +148,18 @@ Item {
|
|||||||
fileSearchController.openSelected();
|
fileSearchController.openSelected();
|
||||||
}
|
}
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
|
} else if (event.key === Qt.Key_Menu) {
|
||||||
|
if (searchMode === "apps" && appLauncher.model.count > 0) {
|
||||||
|
const selectedApp = appLauncher.model.get(appLauncher.selectedIndex);
|
||||||
|
const menu = usePopupContextMenu ? popupContextMenu : layerContextMenuLoader.item;
|
||||||
|
|
||||||
|
if (selectedApp && menu && resultsView) {
|
||||||
|
const itemPos = resultsView.getSelectedItemPosition();
|
||||||
|
const contentPos = resultsView.mapToItem(spotlightKeyHandler, itemPos.x, itemPos.y);
|
||||||
|
menu.show(contentPos.x, contentPos.y, selectedApp, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,6 +192,52 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SpotlightContextMenuPopup {
|
||||||
|
id: popupContextMenu
|
||||||
|
|
||||||
|
parent: spotlightKeyHandler
|
||||||
|
appLauncher: spotlightKeyHandler.appLauncher
|
||||||
|
parentHandler: spotlightKeyHandler
|
||||||
|
searchField: spotlightKeyHandler.searchField
|
||||||
|
visible: false
|
||||||
|
z: 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: usePopupContextMenu && popupContextMenu.visible
|
||||||
|
hoverEnabled: true
|
||||||
|
z: 999
|
||||||
|
onClicked: popupContextMenu.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: layerContextMenuLoader
|
||||||
|
active: !spotlightKeyHandler.usePopupContextMenu
|
||||||
|
asynchronous: false
|
||||||
|
sourceComponent: Component {
|
||||||
|
SpotlightContextMenu {
|
||||||
|
appLauncher: spotlightKeyHandler.appLauncher
|
||||||
|
parentHandler: spotlightKeyHandler
|
||||||
|
parentModal: spotlightKeyHandler.parentModal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: parentModal
|
||||||
|
function onSpotlightOpenChanged() {
|
||||||
|
if (parentModal && !parentModal.spotlightOpen) {
|
||||||
|
if (layerContextMenuLoader.item) {
|
||||||
|
layerContextMenuLoader.item.hide();
|
||||||
|
}
|
||||||
|
popupContextMenu.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enabled: parentModal !== null
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Theme.spacingM
|
anchors.margins: Theme.spacingM
|
||||||
@@ -397,8 +457,22 @@ Item {
|
|||||||
id: resultsView
|
id: resultsView
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
appLauncher: spotlightKeyHandler.appLauncher
|
appLauncher: spotlightKeyHandler.appLauncher
|
||||||
contextMenu: contextMenu
|
|
||||||
visible: searchMode === "apps"
|
visible: searchMode === "apps"
|
||||||
|
|
||||||
|
onItemRightClicked: (index, modelData, mouseX, mouseY) => {
|
||||||
|
const menu = usePopupContextMenu ? popupContextMenu : layerContextMenuLoader.item;
|
||||||
|
|
||||||
|
if (menu?.show) {
|
||||||
|
const isPopup = menu.contentItem !== undefined;
|
||||||
|
|
||||||
|
if (isPopup) {
|
||||||
|
const localPos = popupContextMenu.parent.mapFromItem(null, mouseX, mouseY);
|
||||||
|
menu.show(localPos.x, localPos.y, modelData, false);
|
||||||
|
} else {
|
||||||
|
menu.show(mouseX, mouseY, modelData, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSearchResults {
|
FileSearchResults {
|
||||||
@@ -410,31 +484,6 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SpotlightContextMenu {
|
|
||||||
id: contextMenu
|
|
||||||
|
|
||||||
appLauncher: spotlightKeyHandler.appLauncher
|
|
||||||
parentHandler: spotlightKeyHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: contextMenu.visible
|
|
||||||
z: 999
|
|
||||||
onClicked: () => {
|
|
||||||
contextMenu.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
|
|
||||||
x: contextMenu.x
|
|
||||||
y: contextMenu.y
|
|
||||||
width: contextMenu.width
|
|
||||||
height: contextMenu.height
|
|
||||||
onClicked: () => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: filenameTooltipLoader
|
id: filenameTooltipLoader
|
||||||
|
|
||||||
|
|||||||
@@ -1,338 +1,117 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Modals.Spotlight
|
||||||
import qs.Widgets
|
|
||||||
|
|
||||||
Popup {
|
PanelWindow {
|
||||||
id: contextMenu
|
id: root
|
||||||
|
|
||||||
|
WlrLayershell.namespace: "dms:spotlight-context-menu"
|
||||||
|
WlrLayershell.layer: WlrLayershell.Overlay
|
||||||
|
WlrLayershell.exclusiveZone: -1
|
||||||
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||||
|
|
||||||
property var currentApp: null
|
|
||||||
property var appLauncher: null
|
property var appLauncher: null
|
||||||
property var parentHandler: null
|
property var parentHandler: null
|
||||||
readonly property var desktopEntry: (currentApp && !currentApp.isPlugin && appLauncher && appLauncher._uniqueApps && currentApp.appIndex >= 0 && currentApp.appIndex < appLauncher._uniqueApps.length) ? appLauncher._uniqueApps[currentApp.appIndex] : null
|
property var parentModal: null
|
||||||
|
property real menuPositionX: 0
|
||||||
|
property real menuPositionY: 0
|
||||||
|
|
||||||
|
readonly property real shadowBuffer: 5
|
||||||
|
|
||||||
|
screen: parentModal?.effectiveScreen
|
||||||
|
|
||||||
function show(x, y, app) {
|
function show(x, y, app, fromKeyboard) {
|
||||||
currentApp = app
|
fromKeyboard = fromKeyboard || false;
|
||||||
contextMenu.x = x + 4
|
menuContent.currentApp = app;
|
||||||
contextMenu.y = y + 4
|
|
||||||
contextMenu.open()
|
let screenX = x;
|
||||||
|
let screenY = y;
|
||||||
|
|
||||||
|
if (parentModal) {
|
||||||
|
if (fromKeyboard) {
|
||||||
|
screenX = x + parentModal.alignedX;
|
||||||
|
screenY = y + parentModal.alignedY;
|
||||||
|
} else {
|
||||||
|
screenX = x + (parentModal.alignedX - shadowBuffer);
|
||||||
|
screenY = y + (parentModal.alignedY - shadowBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menuPositionX = screenX;
|
||||||
|
menuPositionY = screenY;
|
||||||
|
|
||||||
|
menuContent.selectedMenuIndex = fromKeyboard ? 0 : -1;
|
||||||
|
menuContent.keyboardNavigation = true;
|
||||||
|
visible = true;
|
||||||
|
|
||||||
|
if (parentHandler) {
|
||||||
|
parentHandler.enabled = false;
|
||||||
|
}
|
||||||
|
Qt.callLater(() => {
|
||||||
|
menuContent.keyboardHandler.forceActiveFocus();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
contextMenu.close()
|
if (parentHandler) {
|
||||||
|
parentHandler.enabled = true;
|
||||||
|
}
|
||||||
|
visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
width: Math.max(180, menuColumn.implicitWidth + Theme.spacingS * 2)
|
visible: false
|
||||||
height: menuColumn.implicitHeight + Theme.spacingS * 2
|
color: "transparent"
|
||||||
padding: 0
|
anchors {
|
||||||
closePolicy: Popup.CloseOnPressOutside
|
top: true
|
||||||
modal: false
|
left: true
|
||||||
dim: false
|
right: true
|
||||||
|
bottom: true
|
||||||
|
}
|
||||||
|
|
||||||
background: Rectangle {
|
onVisibleChanged: {
|
||||||
radius: Theme.cornerRadius
|
if (!visible && parentHandler) {
|
||||||
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
parentHandler.enabled = true;
|
||||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
|
||||||
border.width: 1
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.topMargin: 4
|
|
||||||
anchors.leftMargin: 2
|
|
||||||
anchors.rightMargin: -2
|
|
||||||
anchors.bottomMargin: -4
|
|
||||||
radius: parent.radius
|
|
||||||
color: Qt.rgba(0, 0, 0, 0.15)
|
|
||||||
z: -1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enter: Transition {
|
SpotlightContextMenuContent {
|
||||||
NumberAnimation {
|
id: menuContent
|
||||||
property: "opacity"
|
|
||||||
from: 0
|
x: {
|
||||||
to: 1
|
const left = 10;
|
||||||
duration: Theme.shortDuration
|
const right = root.width - width - 10;
|
||||||
easing.type: Theme.emphasizedEasing
|
const want = menuPositionX;
|
||||||
|
return Math.max(left, Math.min(right, want));
|
||||||
}
|
}
|
||||||
|
y: {
|
||||||
|
const top = 10;
|
||||||
|
const bottom = root.height - height - 10;
|
||||||
|
const want = menuPositionY;
|
||||||
|
return Math.max(top, Math.min(bottom, want));
|
||||||
|
}
|
||||||
|
|
||||||
|
appLauncher: root.appLauncher
|
||||||
|
|
||||||
|
opacity: root.visible ? 1 : 0
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.emphasizedEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onHideRequested: root.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
exit: Transition {
|
MouseArea {
|
||||||
NumberAnimation {
|
|
||||||
property: "opacity"
|
|
||||||
from: 1
|
|
||||||
to: 0
|
|
||||||
duration: Theme.shortDuration
|
|
||||||
easing.type: Theme.emphasizedEasing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: menuColumn
|
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Theme.spacingS
|
z: -1
|
||||||
spacing: 1
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
onClicked: root.hide()
|
||||||
Rectangle {
|
|
||||||
width: parent.width
|
|
||||||
height: 32
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: pinMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: pinRow
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: Theme.spacingS
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
name: {
|
|
||||||
if (!desktopEntry)
|
|
||||||
return "push_pin"
|
|
||||||
|
|
||||||
const appId = desktopEntry.id || desktopEntry.execString || ""
|
|
||||||
return SessionData.isPinnedApp(appId) ? "keep_off" : "push_pin"
|
|
||||||
}
|
|
||||||
size: Theme.iconSize - 2
|
|
||||||
color: Theme.surfaceText
|
|
||||||
opacity: 0.7
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: {
|
|
||||||
if (!desktopEntry)
|
|
||||||
return I18n.tr("Pin to Dock")
|
|
||||||
|
|
||||||
const appId = desktopEntry.id || desktopEntry.execString || ""
|
|
||||||
return SessionData.isPinnedApp(appId) ? I18n.tr("Unpin from Dock") : I18n.tr("Pin to Dock")
|
|
||||||
}
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Normal
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: pinMouseArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: () => {
|
|
||||||
if (!desktopEntry)
|
|
||||||
return
|
|
||||||
|
|
||||||
const appId = desktopEntry.id || desktopEntry.execString || ""
|
|
||||||
if (SessionData.isPinnedApp(appId))
|
|
||||||
SessionData.removePinnedApp(appId)
|
|
||||||
else
|
|
||||||
SessionData.addPinnedApp(appId)
|
|
||||||
contextMenu.hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width - Theme.spacingS * 2
|
|
||||||
height: 5
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
color: "transparent"
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: parent.width
|
|
||||||
height: 1
|
|
||||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: desktopEntry && desktopEntry.actions ? desktopEntry.actions : []
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width
|
|
||||||
height: 32
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: actionMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: actionRow
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: Theme.spacingS
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
Item {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
width: Theme.iconSize - 2
|
|
||||||
height: Theme.iconSize - 2
|
|
||||||
visible: modelData.icon && modelData.icon !== ""
|
|
||||||
|
|
||||||
IconImage {
|
|
||||||
anchors.fill: parent
|
|
||||||
source: modelData.icon ? Quickshell.iconPath(modelData.icon, true) : ""
|
|
||||||
smooth: true
|
|
||||||
asynchronous: true
|
|
||||||
visible: status === Image.Ready
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: modelData.name || ""
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Normal
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: actionMouseArea
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
if (modelData && desktopEntry) {
|
|
||||||
SessionService.launchDesktopAction(desktopEntry, modelData)
|
|
||||||
if (appLauncher && contextMenu.currentApp) {
|
|
||||||
appLauncher.appLaunched(contextMenu.currentApp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
contextMenu.hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
visible: desktopEntry && desktopEntry.actions && desktopEntry.actions.length > 0
|
|
||||||
width: parent.width - Theme.spacingS * 2
|
|
||||||
height: 5
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
color: "transparent"
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: parent.width
|
|
||||||
height: 1
|
|
||||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width
|
|
||||||
height: 32
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: launchMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: launchRow
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: Theme.spacingS
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
name: "launch"
|
|
||||||
size: Theme.iconSize - 2
|
|
||||||
color: Theme.surfaceText
|
|
||||||
opacity: 0.7
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: I18n.tr("Launch")
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Normal
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: launchMouseArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: () => {
|
|
||||||
if (contextMenu.currentApp && appLauncher)
|
|
||||||
appLauncher.launchApp(contextMenu.currentApp)
|
|
||||||
|
|
||||||
contextMenu.hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
visible: SessionService.hasPrimeRun
|
|
||||||
width: parent.width - Theme.spacingS * 2
|
|
||||||
height: 5
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
color: "transparent"
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: parent.width
|
|
||||||
height: 1
|
|
||||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
visible: SessionService.hasPrimeRun
|
|
||||||
width: parent.width
|
|
||||||
height: 32
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: primeRunMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: primeRunRow
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: Theme.spacingS
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
name: "memory"
|
|
||||||
size: Theme.iconSize - 2
|
|
||||||
color: Theme.surfaceText
|
|
||||||
opacity: 0.7
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: I18n.tr("Launch on dGPU")
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Normal
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: primeRunMouseArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: () => {
|
|
||||||
if (desktopEntry) {
|
|
||||||
SessionService.launchDesktopEntry(desktopEntry, true)
|
|
||||||
if (appLauncher && contextMenu.currentApp) {
|
|
||||||
appLauncher.appLaunched(contextMenu.currentApp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
contextMenu.hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
292
quickshell/Modals/Spotlight/SpotlightContextMenuContent.qml
Normal file
292
quickshell/Modals/Spotlight/SpotlightContextMenuContent.qml
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var currentApp: null
|
||||||
|
property var appLauncher: null
|
||||||
|
property int selectedMenuIndex: 0
|
||||||
|
property bool keyboardNavigation: false
|
||||||
|
|
||||||
|
signal hideRequested()
|
||||||
|
|
||||||
|
readonly property var desktopEntry: (currentApp && !currentApp.isPlugin && appLauncher && appLauncher._uniqueApps && currentApp.appIndex >= 0 && currentApp.appIndex < appLauncher._uniqueApps.length) ? appLauncher._uniqueApps[currentApp.appIndex] : null
|
||||||
|
|
||||||
|
readonly property var menuItems: {
|
||||||
|
const items = [];
|
||||||
|
const appId = desktopEntry ? (desktopEntry.id || desktopEntry.execString || "") : "";
|
||||||
|
const isPinned = SessionData.isPinnedApp(appId);
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
type: "item",
|
||||||
|
icon: isPinned ? "keep_off" : "push_pin",
|
||||||
|
text: isPinned ? I18n.tr("Unpin from Dock") : I18n.tr("Pin to Dock"),
|
||||||
|
action: togglePin
|
||||||
|
});
|
||||||
|
|
||||||
|
if (desktopEntry && desktopEntry.actions) {
|
||||||
|
items.push({
|
||||||
|
type: "separator"
|
||||||
|
});
|
||||||
|
for (let i = 0; i < desktopEntry.actions.length; i++) {
|
||||||
|
const act = desktopEntry.actions[i];
|
||||||
|
items.push({
|
||||||
|
type: "item",
|
||||||
|
text: act.name || "",
|
||||||
|
action: () => launchAction(act)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
type: "separator",
|
||||||
|
hidden: !desktopEntry || !desktopEntry.actions || desktopEntry.actions.length === 0
|
||||||
|
});
|
||||||
|
items.push({
|
||||||
|
type: "item",
|
||||||
|
icon: "launch",
|
||||||
|
text: I18n.tr("Launch"),
|
||||||
|
action: launchCurrentApp
|
||||||
|
});
|
||||||
|
|
||||||
|
if (SessionService.nvidiaCommand) {
|
||||||
|
items.push({
|
||||||
|
type: "separator"
|
||||||
|
});
|
||||||
|
items.push({
|
||||||
|
type: "item",
|
||||||
|
icon: "memory",
|
||||||
|
text: I18n.tr("Launch on dGPU"),
|
||||||
|
action: launchWithNvidia
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property int visibleItemCount: {
|
||||||
|
let count = 0;
|
||||||
|
for (let i = 0; i < menuItems.length; i++) {
|
||||||
|
if (menuItems[i].type === "item" && !menuItems[i].hidden) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectNext() {
|
||||||
|
if (visibleItemCount > 0) {
|
||||||
|
selectedMenuIndex = (selectedMenuIndex + 1) % visibleItemCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPrevious() {
|
||||||
|
if (visibleItemCount > 0) {
|
||||||
|
selectedMenuIndex = (selectedMenuIndex - 1 + visibleItemCount) % visibleItemCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function togglePin() {
|
||||||
|
if (!desktopEntry)
|
||||||
|
return;
|
||||||
|
const appId = desktopEntry.id || desktopEntry.execString || "";
|
||||||
|
if (SessionData.isPinnedApp(appId))
|
||||||
|
SessionData.removePinnedApp(appId);
|
||||||
|
else
|
||||||
|
SessionData.addPinnedApp(appId);
|
||||||
|
hideRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
function launchCurrentApp() {
|
||||||
|
if (currentApp && appLauncher)
|
||||||
|
appLauncher.launchApp(currentApp);
|
||||||
|
hideRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
function launchWithNvidia() {
|
||||||
|
if (desktopEntry) {
|
||||||
|
SessionService.launchDesktopEntry(desktopEntry, true);
|
||||||
|
if (appLauncher && currentApp) {
|
||||||
|
appLauncher.appLaunched(currentApp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hideRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
function launchAction(action) {
|
||||||
|
if (desktopEntry) {
|
||||||
|
SessionService.launchDesktopAction(desktopEntry, action);
|
||||||
|
if (appLauncher && currentApp) {
|
||||||
|
appLauncher.appLaunched(currentApp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hideRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
function activateSelected() {
|
||||||
|
let itemIndex = 0;
|
||||||
|
for (let i = 0; i < menuItems.length; i++) {
|
||||||
|
if (menuItems[i].type === "item" && !menuItems[i].hidden) {
|
||||||
|
if (itemIndex === selectedMenuIndex) {
|
||||||
|
menuItems[i].action();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
itemIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property alias keyboardHandler: keyboardHandler
|
||||||
|
|
||||||
|
implicitWidth: Math.max(180, menuColumn.implicitWidth + Theme.spacingS * 2)
|
||||||
|
implicitHeight: menuColumn.implicitHeight + Theme.spacingS * 2
|
||||||
|
|
||||||
|
width: implicitWidth
|
||||||
|
height: implicitHeight
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: menuContainer
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: 4
|
||||||
|
anchors.leftMargin: 2
|
||||||
|
anchors.rightMargin: -2
|
||||||
|
anchors.bottomMargin: -4
|
||||||
|
radius: parent.radius
|
||||||
|
color: Qt.rgba(0, 0, 0, 0.15)
|
||||||
|
z: -1
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: keyboardHandler
|
||||||
|
anchors.fill: parent
|
||||||
|
focus: keyboardNavigation
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Down) {
|
||||||
|
selectNext();
|
||||||
|
event.accepted = true;
|
||||||
|
} else if (event.key === Qt.Key_Up) {
|
||||||
|
selectPrevious();
|
||||||
|
event.accepted = true;
|
||||||
|
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||||
|
activateSelected();
|
||||||
|
event.accepted = true;
|
||||||
|
} else if (event.key === Qt.Key_Escape) {
|
||||||
|
hideRequested();
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: menuColumn
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingS
|
||||||
|
spacing: 1
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: menuItems
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: modelData.type === "separator" ? 5 : 32
|
||||||
|
visible: !modelData.hidden
|
||||||
|
|
||||||
|
property int itemIndex: {
|
||||||
|
let count = 0;
|
||||||
|
for (let i = 0; i < index; i++) {
|
||||||
|
if (menuItems[i].type === "item" && !menuItems[i].hidden) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
visible: modelData.type === "separator"
|
||||||
|
width: parent.width - Theme.spacingS * 2
|
||||||
|
height: parent.height
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.width
|
||||||
|
height: 1
|
||||||
|
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
visible: modelData.type === "item"
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: {
|
||||||
|
if (keyboardNavigation && selectedMenuIndex === itemIndex) {
|
||||||
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2);
|
||||||
|
}
|
||||||
|
return mouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent";
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Theme.spacingS
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: Theme.iconSize - 2
|
||||||
|
height: Theme.iconSize - 2
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
visible: modelData.icon !== undefined && modelData.icon !== ""
|
||||||
|
name: modelData.icon || ""
|
||||||
|
size: Theme.iconSize - 2
|
||||||
|
color: Theme.surfaceText
|
||||||
|
opacity: 0.7
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: modelData.text || ""
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Normal
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
elide: Text.ElideRight
|
||||||
|
width: parent.width - (Theme.iconSize - 2) - Theme.spacingS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onEntered: {
|
||||||
|
keyboardNavigation = false;
|
||||||
|
selectedMenuIndex = itemIndex;
|
||||||
|
}
|
||||||
|
onClicked: modelData.action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
88
quickshell/Modals/Spotlight/SpotlightContextMenuPopup.qml
Normal file
88
quickshell/Modals/Spotlight/SpotlightContextMenuPopup.qml
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell
|
||||||
|
import qs.Common
|
||||||
|
import qs.Modals.Spotlight
|
||||||
|
|
||||||
|
Popup {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var appLauncher: null
|
||||||
|
property var parentHandler: null
|
||||||
|
property var searchField: null
|
||||||
|
|
||||||
|
function show(x, y, app, fromKeyboard) {
|
||||||
|
fromKeyboard = fromKeyboard || false;
|
||||||
|
menuContent.currentApp = app;
|
||||||
|
|
||||||
|
root.x = x + 4;
|
||||||
|
root.y = y + 4;
|
||||||
|
|
||||||
|
menuContent.selectedMenuIndex = fromKeyboard ? 0 : -1;
|
||||||
|
menuContent.keyboardNavigation = true;
|
||||||
|
|
||||||
|
if (parentHandler) {
|
||||||
|
parentHandler.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpened: {
|
||||||
|
Qt.callLater(() => {
|
||||||
|
menuContent.keyboardHandler.forceActiveFocus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
if (parentHandler) {
|
||||||
|
parentHandler.enabled = true;
|
||||||
|
}
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
width: menuContent.implicitWidth
|
||||||
|
height: menuContent.implicitHeight
|
||||||
|
padding: 0
|
||||||
|
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||||
|
modal: true
|
||||||
|
dim: false
|
||||||
|
background: Item {}
|
||||||
|
|
||||||
|
onClosed: {
|
||||||
|
if (parentHandler) {
|
||||||
|
parentHandler.enabled = true;
|
||||||
|
}
|
||||||
|
if (searchField) {
|
||||||
|
Qt.callLater(() => {
|
||||||
|
searchField.forceActiveFocus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enter: Transition {
|
||||||
|
NumberAnimation {
|
||||||
|
property: "opacity"
|
||||||
|
from: 0
|
||||||
|
to: 1
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.emphasizedEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit: Transition {
|
||||||
|
NumberAnimation {
|
||||||
|
property: "opacity"
|
||||||
|
from: 1
|
||||||
|
to: 0
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.emphasizedEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: SpotlightContextMenuContent {
|
||||||
|
id: menuContent
|
||||||
|
appLauncher: root.appLauncher
|
||||||
|
onHideRequested: root.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,8 @@ Rectangle {
|
|||||||
id: resultsContainer
|
id: resultsContainer
|
||||||
|
|
||||||
property var appLauncher: null
|
property var appLauncher: null
|
||||||
property var contextMenu: null
|
|
||||||
|
signal itemRightClicked(int index, var modelData, real mouseX, real mouseY)
|
||||||
|
|
||||||
function resetScroll() {
|
function resetScroll() {
|
||||||
resultsList.contentY = 0
|
resultsList.contentY = 0
|
||||||
@@ -17,6 +18,24 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSelectedItemPosition() {
|
||||||
|
if (!appLauncher) return { x: 0, y: 0 };
|
||||||
|
|
||||||
|
const selectedIndex = appLauncher.selectedIndex;
|
||||||
|
if (appLauncher.viewMode === "list") {
|
||||||
|
const itemY = selectedIndex * (resultsList.itemHeight + resultsList.itemSpacing) - resultsList.contentY;
|
||||||
|
return { x: resultsList.width / 2, y: itemY + resultsList.itemHeight / 2 };
|
||||||
|
} else if (gridLoader.item) {
|
||||||
|
const grid = gridLoader.item;
|
||||||
|
const row = Math.floor(selectedIndex / grid.actualColumns);
|
||||||
|
const col = selectedIndex % grid.actualColumns;
|
||||||
|
const itemX = col * grid.cellWidth + grid.leftMargin + grid.cellWidth / 2;
|
||||||
|
const itemY = row * grid.cellHeight - grid.contentY + grid.cellHeight / 2;
|
||||||
|
return { x: itemX, y: itemY };
|
||||||
|
}
|
||||||
|
return { x: 0, y: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
clip: true
|
clip: true
|
||||||
@@ -67,9 +86,8 @@ Rectangle {
|
|||||||
appLauncher.launchApp(modelData)
|
appLauncher.launchApp(modelData)
|
||||||
}
|
}
|
||||||
onItemRightClicked: (index, modelData, mouseX, mouseY) => {
|
onItemRightClicked: (index, modelData, mouseX, mouseY) => {
|
||||||
if (contextMenu)
|
resultsContainer.itemRightClicked(index, modelData, mouseX, mouseY);
|
||||||
contextMenu.show(mouseX, mouseY, modelData)
|
}
|
||||||
}
|
|
||||||
onKeyboardNavigationReset: () => {
|
onKeyboardNavigationReset: () => {
|
||||||
if (appLauncher)
|
if (appLauncher)
|
||||||
appLauncher.keyboardNavigationActive = false
|
appLauncher.keyboardNavigationActive = false
|
||||||
@@ -87,8 +105,7 @@ Rectangle {
|
|||||||
iconUnicodeScale: 0.8
|
iconUnicodeScale: 0.8
|
||||||
onItemClicked: (idx, modelData) => resultsList.itemClicked(idx, modelData)
|
onItemClicked: (idx, modelData) => resultsList.itemClicked(idx, modelData)
|
||||||
onItemRightClicked: (idx, modelData, mouseX, mouseY) => {
|
onItemRightClicked: (idx, modelData, mouseX, mouseY) => {
|
||||||
const modalPos = resultsContainer.parent.mapFromItem(null, mouseX, mouseY)
|
resultsList.itemRightClicked(idx, modelData, mouseX, mouseY)
|
||||||
resultsList.itemRightClicked(idx, modelData, modalPos.x, modalPos.y)
|
|
||||||
}
|
}
|
||||||
onKeyboardNavigationReset: resultsList.keyboardNavigationReset
|
onKeyboardNavigationReset: resultsList.keyboardNavigationReset
|
||||||
}
|
}
|
||||||
@@ -103,6 +120,14 @@ Rectangle {
|
|||||||
anchors.margins: Theme.spacingS
|
anchors.margins: Theme.spacingS
|
||||||
visible: appLauncher && appLauncher.viewMode === "grid"
|
visible: appLauncher && appLauncher.viewMode === "grid"
|
||||||
active: appLauncher && appLauncher.viewMode === "grid"
|
active: appLauncher && appLauncher.viewMode === "grid"
|
||||||
|
asynchronous: false
|
||||||
|
|
||||||
|
onLoaded: {
|
||||||
|
if (item) {
|
||||||
|
item.appLauncher = Qt.binding(() => resultsContainer.appLauncher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onWidthChanged: {
|
onWidthChanged: {
|
||||||
if (visible && Math.abs(width - _lastWidth) > 1) {
|
if (visible && Math.abs(width - _lastWidth) > 1) {
|
||||||
_lastWidth = width
|
_lastWidth = width
|
||||||
@@ -116,6 +141,8 @@ Rectangle {
|
|||||||
DankGridView {
|
DankGridView {
|
||||||
id: resultsGrid
|
id: resultsGrid
|
||||||
|
|
||||||
|
property var appLauncher: null
|
||||||
|
|
||||||
property int currentIndex: appLauncher ? appLauncher.selectedIndex : -1
|
property int currentIndex: appLauncher ? appLauncher.selectedIndex : -1
|
||||||
property int columns: appLauncher ? appLauncher.gridColumns : 4
|
property int columns: appLauncher ? appLauncher.gridColumns : 4
|
||||||
property bool adaptiveColumns: false
|
property bool adaptiveColumns: false
|
||||||
@@ -167,9 +194,8 @@ Rectangle {
|
|||||||
appLauncher.launchApp(modelData)
|
appLauncher.launchApp(modelData)
|
||||||
}
|
}
|
||||||
onItemRightClicked: (index, modelData, mouseX, mouseY) => {
|
onItemRightClicked: (index, modelData, mouseX, mouseY) => {
|
||||||
if (contextMenu)
|
resultsContainer.itemRightClicked(index, modelData, mouseX, mouseY);
|
||||||
contextMenu.show(mouseX, mouseY, modelData)
|
}
|
||||||
}
|
|
||||||
onKeyboardNavigationReset: () => {
|
onKeyboardNavigationReset: () => {
|
||||||
if (appLauncher)
|
if (appLauncher)
|
||||||
appLauncher.keyboardNavigationActive = false
|
appLauncher.keyboardNavigationActive = false
|
||||||
@@ -188,8 +214,7 @@ Rectangle {
|
|||||||
currentIndex: resultsGrid.currentIndex
|
currentIndex: resultsGrid.currentIndex
|
||||||
onItemClicked: (idx, modelData) => resultsGrid.itemClicked(idx, modelData)
|
onItemClicked: (idx, modelData) => resultsGrid.itemClicked(idx, modelData)
|
||||||
onItemRightClicked: (idx, modelData, mouseX, mouseY) => {
|
onItemRightClicked: (idx, modelData, mouseX, mouseY) => {
|
||||||
const modalPos = resultsContainer.parent.mapFromItem(null, mouseX, mouseY)
|
resultsGrid.itemRightClicked(idx, modelData, mouseX, mouseY)
|
||||||
resultsGrid.itemRightClicked(idx, modelData, modalPos.x, modalPos.y)
|
|
||||||
}
|
}
|
||||||
onKeyboardNavigationReset: resultsGrid.keyboardNavigationReset
|
onKeyboardNavigationReset: resultsGrid.keyboardNavigationReset
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -749,7 +749,7 @@ DankPopout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
visible: SessionService.hasPrimeRun
|
visible: SessionService.nvidiaCommand
|
||||||
width: parent.width - Theme.spacingS * 2
|
width: parent.width - Theme.spacingS * 2
|
||||||
height: 5
|
height: 5
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
@@ -764,11 +764,11 @@ DankPopout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
visible: SessionService.hasPrimeRun
|
visible: SessionService.nvidiaCommand
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 32
|
height: 32
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: primeRunMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
color: nvidiaMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
@@ -794,7 +794,7 @@ DankPopout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: primeRunMouseArea
|
id: nvidiaMouseArea
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ PanelWindow {
|
|||||||
if (!root.desktopEntry?.actions || root.desktopEntry.actions.length === 0) {
|
if (!root.desktopEntry?.actions || root.desktopEntry.actions.length === 0) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return !root.hidePin || (!root.isDmsWindow && root.desktopEntry && SessionService.hasPrimeRun)
|
return !root.hidePin || (!root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand)
|
||||||
}
|
}
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 1
|
height: 1
|
||||||
@@ -405,10 +405,10 @@ PanelWindow {
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
visible: {
|
visible: {
|
||||||
const hasPrimeRun = !root.isDmsWindow && root.desktopEntry && SessionService.hasPrimeRun
|
const hasNvidia = !root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand
|
||||||
const hasWindow = root.appData && (root.appData.type === "window" || (root.appData.type === "grouped" && root.appData.windowCount > 0))
|
const hasWindow = root.appData && (root.appData.type === "window" || (root.appData.type === "grouped" && root.appData.windowCount > 0))
|
||||||
const hasPinOption = !root.hidePin
|
const hasPinOption = !root.hidePin
|
||||||
const hasContentAbove = hasPinOption || hasPrimeRun
|
const hasContentAbove = hasPinOption || hasNvidia
|
||||||
return hasContentAbove && hasWindow
|
return hasContentAbove && hasWindow
|
||||||
}
|
}
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -417,11 +417,11 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
visible: !root.isDmsWindow && root.desktopEntry && SessionService.hasPrimeRun
|
visible: !root.isDmsWindow && root.desktopEntry && SessionService.nvidiaCommand
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 28
|
height: 28
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: primeRunArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
color: nvidiaArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
@@ -438,7 +438,7 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: primeRunArea
|
id: nvidiaArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ Scope {
|
|||||||
id: spotlightContent
|
id: spotlightContent
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 0
|
anchors.margins: 0
|
||||||
|
usePopupContextMenu: true
|
||||||
|
|
||||||
property var fakeParentModal: QtObject {
|
property var fakeParentModal: QtObject {
|
||||||
property bool spotlightOpen: spotlightContainer.visible
|
property bool spotlightOpen: spotlightContainer.visible
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ Singleton {
|
|||||||
property bool inhibitorAvailable: true
|
property bool inhibitorAvailable: true
|
||||||
property bool idleInhibited: false
|
property bool idleInhibited: false
|
||||||
property string inhibitReason: "Keep system awake"
|
property string inhibitReason: "Keep system awake"
|
||||||
property bool hasPrimeRun: false
|
property string nvidiaCommand: ""
|
||||||
|
|
||||||
readonly property bool nativeInhibitorAvailable: {
|
readonly property bool nativeInhibitorAvailable: {
|
||||||
try {
|
try {
|
||||||
@@ -109,7 +109,23 @@ Singleton {
|
|||||||
command: ["which", "prime-run"]
|
command: ["which", "prime-run"]
|
||||||
|
|
||||||
onExited: function (exitCode) {
|
onExited: function (exitCode) {
|
||||||
hasPrimeRun = (exitCode === 0);
|
if (exitCode === 0) {
|
||||||
|
nvidiaCommand = "prime-run"
|
||||||
|
} else {
|
||||||
|
detectNvidiaOffloadProcess.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: detectNvidiaOffloadProcess
|
||||||
|
running: false
|
||||||
|
command: ["which", "nvidia-offload"]
|
||||||
|
|
||||||
|
onExited: function (exitCode) {
|
||||||
|
if (exitCode === 0) {
|
||||||
|
nvidiaCommand = "nvidia-offload"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,10 +161,10 @@ Singleton {
|
|||||||
return /[;&|<>()$`\\"']/.test(prefix);
|
return /[;&|<>()$`\\"']/.test(prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
function launchDesktopEntry(desktopEntry, usePrimeRun) {
|
function launchDesktopEntry(desktopEntry, useNvidia) {
|
||||||
let cmd = desktopEntry.command;
|
let cmd = desktopEntry.command;
|
||||||
if (usePrimeRun && hasPrimeRun) {
|
if (useNvidia && nvidiaCommand) {
|
||||||
cmd = ["prime-run"].concat(cmd);
|
cmd = [nvidiaCommand].concat(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
const userPrefix = SettingsData.launchPrefix?.trim() || "";
|
const userPrefix = SettingsData.launchPrefix?.trim() || "";
|
||||||
@@ -176,10 +192,10 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function launchDesktopAction(desktopEntry, action, usePrimeRun) {
|
function launchDesktopAction(desktopEntry, action, useNvidia) {
|
||||||
let cmd = action.command;
|
let cmd = action.command;
|
||||||
if (usePrimeRun && hasPrimeRun) {
|
if (useNvidia && nvidiaCommand) {
|
||||||
cmd = ["prime-run"].concat(cmd);
|
cmd = [nvidiaCommand].concat(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
const userPrefix = SettingsData.launchPrefix?.trim() || "";
|
const userPrefix = SettingsData.launchPrefix?.trim() || "";
|
||||||
|
|||||||
@@ -95,10 +95,20 @@ Rectangle {
|
|||||||
onClicked: mouse => {
|
onClicked: mouse => {
|
||||||
if (mouse.button === Qt.LeftButton) {
|
if (mouse.button === Qt.LeftButton) {
|
||||||
root.itemClicked(root.index, root.model)
|
root.itemClicked(root.index, root.model)
|
||||||
} else if (mouse.button === Qt.RightButton && !root.isPlugin) {
|
}
|
||||||
|
}
|
||||||
|
onPressAndHold: mouse => {
|
||||||
|
if (!root.isPlugin) {
|
||||||
const globalPos = mapToItem(null, mouse.x, mouse.y)
|
const globalPos = mapToItem(null, mouse.x, mouse.y)
|
||||||
root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y)
|
root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onPressed: mouse => {
|
||||||
|
if (mouse.button === Qt.RightButton && !root.isPlugin) {
|
||||||
|
const globalPos = mapToItem(null, mouse.x, mouse.y)
|
||||||
|
root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y)
|
||||||
|
mouse.accepted = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,10 +105,20 @@ Rectangle {
|
|||||||
onClicked: mouse => {
|
onClicked: mouse => {
|
||||||
if (mouse.button === Qt.LeftButton) {
|
if (mouse.button === Qt.LeftButton) {
|
||||||
root.itemClicked(root.index, root.model)
|
root.itemClicked(root.index, root.model)
|
||||||
} else if (mouse.button === Qt.RightButton && !root.isPlugin) {
|
}
|
||||||
|
}
|
||||||
|
onPressAndHold: mouse => {
|
||||||
|
if (!root.isPlugin) {
|
||||||
const globalPos = mapToItem(null, mouse.x, mouse.y)
|
const globalPos = mapToItem(null, mouse.x, mouse.y)
|
||||||
root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y)
|
root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onPressed: mouse => {
|
||||||
|
if (mouse.button === Qt.RightButton && !root.isPlugin) {
|
||||||
|
const globalPos = mapToItem(null, mouse.x, mouse.y)
|
||||||
|
root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y)
|
||||||
|
mouse.accepted = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user