mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-15 02:02:08 -04:00
feat: Intelligent Dock Auto-hide
This commit is contained in:
@@ -366,6 +366,7 @@ Singleton {
|
|||||||
|
|
||||||
property bool showDock: false
|
property bool showDock: false
|
||||||
property bool dockAutoHide: false
|
property bool dockAutoHide: false
|
||||||
|
property bool dockSmartAutoHide: false
|
||||||
property bool dockGroupByApp: false
|
property bool dockGroupByApp: false
|
||||||
property bool dockOpenOnOverview: false
|
property bool dockOpenOnOverview: false
|
||||||
property int dockPosition: SettingsData.Position.Bottom
|
property int dockPosition: SettingsData.Position.Bottom
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ var SPEC = {
|
|||||||
|
|
||||||
showDock: { def: false },
|
showDock: { def: false },
|
||||||
dockAutoHide: { def: false },
|
dockAutoHide: { def: false },
|
||||||
|
dockSmartAutoHide: { def: false },
|
||||||
dockGroupByApp: { def: false },
|
dockGroupByApp: { def: false },
|
||||||
dockOpenOnOverview: { def: false },
|
dockOpenOnOverview: { def: false },
|
||||||
dockPosition: { def: 1 },
|
dockPosition: { def: 1 },
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Shapes
|
import QtQuick.Shapes
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
@@ -28,7 +29,7 @@ Variants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
property var modelData: item
|
property var modelData: item
|
||||||
property bool autoHide: SettingsData.dockAutoHide
|
property bool autoHide: SettingsData.dockAutoHide || SettingsData.dockSmartAutoHide
|
||||||
property real backgroundTransparency: SettingsData.dockTransparency
|
property real backgroundTransparency: SettingsData.dockTransparency
|
||||||
property bool groupByApp: SettingsData.dockGroupByApp
|
property bool groupByApp: SettingsData.dockGroupByApp
|
||||||
readonly property int borderThickness: SettingsData.dockBorderEnabled ? SettingsData.dockBorderThickness : 0
|
readonly property int borderThickness: SettingsData.dockBorderEnabled ? SettingsData.dockBorderThickness : 0
|
||||||
@@ -111,6 +112,133 @@ Variants {
|
|||||||
property bool contextMenuOpen: (dockVariants.contextMenu && dockVariants.contextMenu.visible && dockVariants.contextMenu.screen === modelData)
|
property bool contextMenuOpen: (dockVariants.contextMenu && dockVariants.contextMenu.visible && dockVariants.contextMenu.screen === modelData)
|
||||||
property bool revealSticky: false
|
property bool revealSticky: false
|
||||||
|
|
||||||
|
readonly property bool shouldHideForWindows: {
|
||||||
|
if (!SettingsData.dockSmartAutoHide)
|
||||||
|
return false;
|
||||||
|
if (!CompositorService.isNiri && !CompositorService.isHyprland)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const screenName = dock.modelData?.name ?? "";
|
||||||
|
const dockThickness = effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin;
|
||||||
|
const screenWidth = dock.screen?.width ?? 0;
|
||||||
|
const screenHeight = dock.screen?.height ?? 0;
|
||||||
|
|
||||||
|
if (CompositorService.isNiri) {
|
||||||
|
NiriService.windows;
|
||||||
|
|
||||||
|
let currentWorkspaceId = null;
|
||||||
|
for (let i = 0; i < NiriService.allWorkspaces.length; i++) {
|
||||||
|
const ws = NiriService.allWorkspaces[i];
|
||||||
|
if (ws.output === screenName && ws.is_active) {
|
||||||
|
currentWorkspaceId = ws.id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentWorkspaceId === null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (let i = 0; i < NiriService.windows.length; i++) {
|
||||||
|
const win = NiriService.windows[i];
|
||||||
|
if (win.workspace_id !== currentWorkspaceId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Get window position and size from layout data
|
||||||
|
const tilePos = win.layout?.tile_pos_in_workspace_view;
|
||||||
|
const winSize = win.layout?.window_size || win.layout?.tile_size;
|
||||||
|
|
||||||
|
if (tilePos && winSize) {
|
||||||
|
const winX = tilePos[0];
|
||||||
|
const winY = tilePos[1];
|
||||||
|
const winW = winSize[0];
|
||||||
|
const winH = winSize[1];
|
||||||
|
|
||||||
|
switch (SettingsData.dockPosition) {
|
||||||
|
case SettingsData.Position.Top:
|
||||||
|
if (winY < dockThickness)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case SettingsData.Position.Bottom:
|
||||||
|
if (winY + winH > screenHeight - dockThickness)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case SettingsData.Position.Left:
|
||||||
|
if (winX < dockThickness)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case SettingsData.Position.Right:
|
||||||
|
if (winX + winW > screenWidth - dockThickness)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (!win.is_floating) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hyprland implementation
|
||||||
|
const filtered = CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName);
|
||||||
|
|
||||||
|
if (filtered.length === 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (let i = 0; i < filtered.length; i++) {
|
||||||
|
const toplevel = filtered[i];
|
||||||
|
|
||||||
|
let hyprToplevel = null;
|
||||||
|
if (Hyprland.toplevels) {
|
||||||
|
const hyprToplevels = Array.from(Hyprland.toplevels.values);
|
||||||
|
for (let j = 0; j < hyprToplevels.length; j++) {
|
||||||
|
if (hyprToplevels[j].wayland === toplevel) {
|
||||||
|
hyprToplevel = hyprToplevels[j];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hyprToplevel?.lastIpcObject)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const ipc = hyprToplevel.lastIpcObject;
|
||||||
|
const at = ipc.at;
|
||||||
|
const size = ipc.size;
|
||||||
|
if (!at || !size)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const monX = hyprToplevel.monitor?.x ?? 0;
|
||||||
|
const monY = hyprToplevel.monitor?.y ?? 0;
|
||||||
|
|
||||||
|
const winX = at[0] - monX;
|
||||||
|
const winY = at[1] - monY;
|
||||||
|
const winW = size[0];
|
||||||
|
const winH = size[1];
|
||||||
|
|
||||||
|
switch (SettingsData.dockPosition) {
|
||||||
|
case SettingsData.Position.Top:
|
||||||
|
if (winY < dockThickness)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case SettingsData.Position.Bottom:
|
||||||
|
if (winY + winH > screenHeight - dockThickness)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case SettingsData.Position.Left:
|
||||||
|
if (winX < dockThickness)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case SettingsData.Position.Right:
|
||||||
|
if (winX + winW > screenWidth - dockThickness)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: revealHold
|
id: revealHold
|
||||||
interval: 250
|
interval: 250
|
||||||
@@ -122,6 +250,15 @@ Variants {
|
|||||||
if (CompositorService.isNiri && NiriService.inOverview && SettingsData.dockOpenOnOverview) {
|
if (CompositorService.isNiri && NiriService.inOverview && SettingsData.dockOpenOnOverview) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Smart auto-hide: show dock when no windows overlap, hide when they do
|
||||||
|
if (SettingsData.dockSmartAutoHide) {
|
||||||
|
if (shouldHideForWindows)
|
||||||
|
return dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky;
|
||||||
|
return true; // No overlapping windows - show dock
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular auto-hide: always hide unless hovering
|
||||||
return !autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky;
|
return !autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,10 +86,30 @@ Item {
|
|||||||
settingKey: "dockAutoHide"
|
settingKey: "dockAutoHide"
|
||||||
tags: ["dock", "autohide", "hide", "hover"]
|
tags: ["dock", "autohide", "hide", "hover"]
|
||||||
text: I18n.tr("Auto-hide Dock")
|
text: I18n.tr("Auto-hide Dock")
|
||||||
description: I18n.tr("Hide the dock when not in use and reveal it when hovering near the dock area")
|
description: I18n.tr("Always hide the dock and reveal it when hovering near the dock area")
|
||||||
checked: SettingsData.dockAutoHide
|
checked: SettingsData.dockAutoHide
|
||||||
visible: SettingsData.showDock
|
visible: SettingsData.showDock
|
||||||
onToggled: checked => SettingsData.set("dockAutoHide", checked)
|
onToggled: checked => {
|
||||||
|
if (checked && SettingsData.dockSmartAutoHide) {
|
||||||
|
SettingsData.set("dockSmartAutoHide", false);
|
||||||
|
}
|
||||||
|
SettingsData.set("dockAutoHide", checked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
settingKey: "dockSmartAutoHide"
|
||||||
|
tags: ["dock", "smart", "autohide", "windows", "overlap", "intelligent"]
|
||||||
|
text: I18n.tr("Intelligent Auto-hide")
|
||||||
|
description: I18n.tr("Show dock when floating windows don't overlap its area")
|
||||||
|
checked: SettingsData.dockSmartAutoHide
|
||||||
|
visible: SettingsData.showDock && (CompositorService.isNiri || CompositorService.isHyprland)
|
||||||
|
onToggled: checked => {
|
||||||
|
if (checked && SettingsData.dockAutoHide) {
|
||||||
|
SettingsData.set("dockAutoHide", false);
|
||||||
|
}
|
||||||
|
SettingsData.set("dockSmartAutoHide", checked);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
|
|||||||
@@ -4265,6 +4265,12 @@
|
|||||||
"reference": "Modules/Settings/DankBarTab.qml:1068",
|
"reference": "Modules/Settings/DankBarTab.qml:1068",
|
||||||
"comment": ""
|
"comment": ""
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"term": "Intelligent Auto-hide",
|
||||||
|
"context": "Intelligent Auto-hide",
|
||||||
|
"reference": "Modules/Settings/DockTab.qml:103",
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"term": "Interface:",
|
"term": "Interface:",
|
||||||
"context": "Interface:",
|
"context": "Interface:",
|
||||||
@@ -7415,6 +7421,12 @@
|
|||||||
"reference": "Modules/Settings/ThemeColorsTab.qml:1375",
|
"reference": "Modules/Settings/ThemeColorsTab.qml:1375",
|
||||||
"comment": ""
|
"comment": ""
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"term": "Show dock when windows don't overlap its area, hide when they do",
|
||||||
|
"context": "Show dock when windows don't overlap its area, hide when they do",
|
||||||
|
"reference": "Modules/Settings/DockTab.qml:104",
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"term": "Show launcher overlay when typing in Niri overview. Disable to use another launcher.",
|
"term": "Show launcher overlay when typing in Niri overview. Disable to use another launcher.",
|
||||||
"context": "Show launcher overlay when typing in Niri overview. Disable to use another launcher.",
|
"context": "Show launcher overlay when typing in Niri overview. Disable to use another launcher.",
|
||||||
|
|||||||
@@ -4976,6 +4976,13 @@
|
|||||||
"reference": "",
|
"reference": "",
|
||||||
"comment": ""
|
"comment": ""
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"term": "Intelligent Auto-hide",
|
||||||
|
"translation": "",
|
||||||
|
"context": "Intelligent Auto-hide",
|
||||||
|
"reference": "",
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"term": "Interface:",
|
"term": "Interface:",
|
||||||
"translation": "",
|
"translation": "",
|
||||||
@@ -8651,6 +8658,13 @@
|
|||||||
"reference": "",
|
"reference": "",
|
||||||
"comment": ""
|
"comment": ""
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"term": "Show dock when windows don't overlap its area, hide when they do",
|
||||||
|
"translation": "",
|
||||||
|
"context": "",
|
||||||
|
"reference": "",
|
||||||
|
"comment": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"term": "Show launcher overlay when typing in Niri overview. Disable to use another launcher.",
|
"term": "Show launcher overlay when typing in Niri overview. Disable to use another launcher.",
|
||||||
"translation": "",
|
"translation": "",
|
||||||
|
|||||||
Reference in New Issue
Block a user