mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-04 12:52:06 -04:00
Fixes two cases: - some apps (e.g., Zen browser use the "—" character at the end of webpage name) - in compact mode, when app has only appName, and not window name, we should display the appName to avoid empty title.
282 lines
10 KiB
QML
282 lines
10 KiB
QML
import QtQuick
|
|
import QtQuick.Effects
|
|
import Quickshell
|
|
import Quickshell.Wayland
|
|
import Quickshell.Widgets
|
|
import Quickshell.Hyprland
|
|
import qs.Common
|
|
import qs.Modules.Plugins
|
|
import qs.Services
|
|
import qs.Widgets
|
|
|
|
BasePill {
|
|
id: root
|
|
|
|
property var widgetData: null
|
|
property bool compactMode: widgetData?.focusedWindowCompactMode !== undefined ? widgetData.focusedWindowCompactMode : SettingsData.focusedWindowCompactMode
|
|
property int availableWidth: 400
|
|
readonly property int maxNormalWidth: 456
|
|
readonly property int maxCompactWidth: 288
|
|
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
|
|
property var activeDesktopEntry: null
|
|
property bool isHovered: mouseArea.containsMouse
|
|
property bool isAutoHideBar: false
|
|
|
|
readonly property real minTooltipY: {
|
|
if (!parentScreen || !isVerticalOrientation) {
|
|
return 0;
|
|
}
|
|
|
|
if (isAutoHideBar) {
|
|
return 0;
|
|
}
|
|
|
|
if (parentScreen.y > 0) {
|
|
return barThickness + (barSpacing || 4);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
updateDesktopEntry();
|
|
}
|
|
|
|
Connections {
|
|
target: DesktopEntries
|
|
function onApplicationsChanged() {
|
|
root.updateDesktopEntry();
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: root
|
|
function onActiveWindowChanged() {
|
|
root.updateDesktopEntry();
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: SettingsData
|
|
function onAppIdSubstitutionsChanged() {
|
|
root.updateDesktopEntry();
|
|
}
|
|
}
|
|
|
|
function updateDesktopEntry() {
|
|
if (activeWindow && activeWindow.appId) {
|
|
const moddedId = Paths.moddedAppId(activeWindow.appId);
|
|
activeDesktopEntry = DesktopEntries.heuristicLookup(moddedId);
|
|
} else {
|
|
activeDesktopEntry = null;
|
|
}
|
|
}
|
|
readonly property bool hasWindowsOnCurrentWorkspace: {
|
|
if (CompositorService.isNiri) {
|
|
let currentWorkspaceId = null;
|
|
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
|
|
const ws = NiriService.allWorkspaces[i];
|
|
if (ws.is_focused) {
|
|
currentWorkspaceId = ws.id;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!currentWorkspaceId) {
|
|
return false;
|
|
}
|
|
|
|
const workspaceWindows = NiriService.windows.filter(w => w.workspace_id === currentWorkspaceId);
|
|
return workspaceWindows.length > 0 && activeWindow && activeWindow.title;
|
|
}
|
|
|
|
if (CompositorService.isHyprland) {
|
|
if (!Hyprland.focusedWorkspace || !activeWindow || !activeWindow.title) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
if (!Hyprland.toplevels)
|
|
return false;
|
|
const hyprlandToplevels = Array.from(Hyprland.toplevels.values);
|
|
const activeHyprToplevel = hyprlandToplevels.find(t => t?.wayland === activeWindow);
|
|
|
|
if (!activeHyprToplevel || !activeHyprToplevel.workspace) {
|
|
return false;
|
|
}
|
|
|
|
return activeHyprToplevel.workspace.id === Hyprland.focusedWorkspace.id;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return activeWindow && activeWindow.title;
|
|
}
|
|
|
|
width: hasWindowsOnCurrentWorkspace ? (isVerticalOrientation ? barThickness : visualWidth) : 0
|
|
height: hasWindowsOnCurrentWorkspace ? (isVerticalOrientation ? visualHeight : barThickness) : 0
|
|
visible: hasWindowsOnCurrentWorkspace
|
|
|
|
content: Component {
|
|
Item {
|
|
implicitWidth: {
|
|
if (!root.hasWindowsOnCurrentWorkspace)
|
|
return 0;
|
|
if (root.isVerticalOrientation)
|
|
return root.widgetThickness - root.horizontalPadding * 2;
|
|
const baseWidth = contentRow.implicitWidth;
|
|
return compactMode ? Math.min(baseWidth, maxCompactWidth - root.horizontalPadding * 2) : Math.min(baseWidth, maxNormalWidth - root.horizontalPadding * 2);
|
|
}
|
|
implicitHeight: root.widgetThickness - root.horizontalPadding * 2
|
|
clip: false
|
|
|
|
IconImage {
|
|
id: appIcon
|
|
anchors.centerIn: parent
|
|
width: 18
|
|
height: 18
|
|
visible: root.isVerticalOrientation && activeWindow && status === Image.Ready
|
|
source: {
|
|
if (!activeWindow || !activeWindow.appId)
|
|
return "";
|
|
return Paths.getAppIcon(activeWindow.appId, activeDesktopEntry);
|
|
}
|
|
smooth: true
|
|
mipmap: true
|
|
asynchronous: true
|
|
layer.enabled: activeWindow && activeWindow.appId === "org.quickshell"
|
|
layer.smooth: true
|
|
layer.mipmap: true
|
|
layer.effect: MultiEffect {
|
|
saturation: 0
|
|
colorization: 1
|
|
colorizationColor: Theme.primary
|
|
}
|
|
}
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
size: 18
|
|
name: "sports_esports"
|
|
color: Theme.widgetTextColor
|
|
visible: root.isVerticalOrientation && activeWindow && activeWindow.appId && appIcon.status !== Image.Ready && Paths.isSteamApp(activeWindow.appId)
|
|
}
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
visible: root.isVerticalOrientation && activeWindow && activeWindow.appId && appIcon.status !== Image.Ready && !Paths.isSteamApp(activeWindow.appId)
|
|
text: {
|
|
if (!activeWindow || !activeWindow.appId)
|
|
return "?";
|
|
const appName = Paths.getAppName(activeWindow.appId, activeDesktopEntry);
|
|
return appName.charAt(0).toUpperCase();
|
|
}
|
|
font.pixelSize: 10
|
|
color: Theme.widgetTextColor
|
|
}
|
|
|
|
Row {
|
|
id: contentRow
|
|
anchors.centerIn: parent
|
|
spacing: Theme.spacingS
|
|
visible: !root.isVerticalOrientation
|
|
|
|
StyledText {
|
|
id: appText
|
|
text: {
|
|
if (!activeWindow || !activeWindow.appId)
|
|
return "";
|
|
return Paths.getAppName(activeWindow.appId, activeDesktopEntry);
|
|
}
|
|
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
|
color: Theme.widgetTextColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
elide: Text.ElideRight
|
|
maximumLineCount: 1
|
|
width: Math.min(implicitWidth, compactMode ? 80 : 180)
|
|
visible: !compactMode && text.length > 0
|
|
}
|
|
|
|
StyledText {
|
|
text: "•"
|
|
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
|
color: Theme.outlineButton
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
visible: !compactMode && appText.text && titleText.text
|
|
}
|
|
|
|
StyledText {
|
|
id: titleText
|
|
text: {
|
|
const title = activeWindow && activeWindow.title ? activeWindow.title : "";
|
|
const appName = appText.text;
|
|
|
|
if (compactMode && title === appName) {
|
|
return title;
|
|
}
|
|
|
|
if (!title || !appName) {
|
|
return title;
|
|
}
|
|
|
|
if (title.endsWith(appName)) {
|
|
return title.substring(0, title.length - appName.length).replace(/ (-|—) $/, "");
|
|
}
|
|
|
|
return title;
|
|
}
|
|
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText)
|
|
color: Theme.widgetTextColor
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
elide: Text.ElideRight
|
|
maximumLineCount: 1
|
|
width: Math.min(implicitWidth, compactMode ? 280 : 250)
|
|
visible: text.length > 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: mouseArea
|
|
anchors.fill: parent
|
|
hoverEnabled: root.isVerticalOrientation
|
|
acceptedButtons: Qt.NoButton
|
|
onEntered: {
|
|
if (root.isVerticalOrientation && activeWindow && activeWindow.appId && root.parentScreen) {
|
|
tooltipLoader.active = true;
|
|
if (tooltipLoader.item) {
|
|
const globalPos = mapToGlobal(width / 2, height / 2);
|
|
const currentScreen = root.parentScreen;
|
|
const screenX = currentScreen ? currentScreen.x : 0;
|
|
const screenY = currentScreen ? currentScreen.y : 0;
|
|
const relativeY = globalPos.y - screenY;
|
|
// Add minTooltipY offset to account for top bar
|
|
const adjustedY = relativeY + root.minTooltipY;
|
|
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS) : (currentScreen.width - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS);
|
|
|
|
const appName = Paths.getAppName(activeWindow.appId, activeDesktopEntry);
|
|
const title = activeWindow.title || "";
|
|
const tooltipText = appName + (title ? " • " + title : "");
|
|
|
|
const isLeft = root.axis?.edge === "left";
|
|
tooltipLoader.item.show(tooltipText, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft);
|
|
}
|
|
}
|
|
}
|
|
onExited: {
|
|
if (tooltipLoader.item) {
|
|
tooltipLoader.item.hide();
|
|
}
|
|
tooltipLoader.active = false;
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
id: tooltipLoader
|
|
active: false
|
|
sourceComponent: DankTooltip {}
|
|
}
|
|
}
|