1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 13:32:50 -05:00

feat: Intelligent Dock Auto-hide

This commit is contained in:
purian23
2026-01-17 22:20:15 -05:00
parent 340d79000c
commit 7241877995
6 changed files with 188 additions and 3 deletions

View File

@@ -366,6 +366,7 @@ Singleton {
property bool showDock: false
property bool dockAutoHide: false
property bool dockSmartAutoHide: false
property bool dockGroupByApp: false
property bool dockOpenOnOverview: false
property int dockPosition: SettingsData.Position.Bottom

View File

@@ -231,6 +231,7 @@ var SPEC = {
showDock: { def: false },
dockAutoHide: { def: false },
dockSmartAutoHide: { def: false },
dockGroupByApp: { def: false },
dockOpenOnOverview: { def: false },
dockPosition: { def: 1 },

View File

@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Shapes
import Quickshell
import Quickshell.Hyprland
import Quickshell.Wayland
import qs.Common
import qs.Services
@@ -28,7 +29,7 @@ Variants {
}
property var modelData: item
property bool autoHide: SettingsData.dockAutoHide
property bool autoHide: SettingsData.dockAutoHide || SettingsData.dockSmartAutoHide
property real backgroundTransparency: SettingsData.dockTransparency
property bool groupByApp: SettingsData.dockGroupByApp
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 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 {
id: revealHold
interval: 250
@@ -122,6 +250,15 @@ Variants {
if (CompositorService.isNiri && NiriService.inOverview && SettingsData.dockOpenOnOverview) {
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;
}

View File

@@ -86,10 +86,30 @@ Item {
settingKey: "dockAutoHide"
tags: ["dock", "autohide", "hide", "hover"]
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
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 {

View File

@@ -4265,6 +4265,12 @@
"reference": "Modules/Settings/DankBarTab.qml:1068",
"comment": ""
},
{
"term": "Intelligent Auto-hide",
"context": "Intelligent Auto-hide",
"reference": "Modules/Settings/DockTab.qml:103",
"comment": ""
},
{
"term": "Interface:",
"context": "Interface:",
@@ -7415,6 +7421,12 @@
"reference": "Modules/Settings/ThemeColorsTab.qml:1375",
"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.",
"context": "Show launcher overlay when typing in Niri overview. Disable to use another launcher.",

View File

@@ -4976,6 +4976,13 @@
"reference": "",
"comment": ""
},
{
"term": "Intelligent Auto-hide",
"translation": "",
"context": "Intelligent Auto-hide",
"reference": "",
"comment": ""
},
{
"term": "Interface:",
"translation": "",
@@ -8651,6 +8658,13 @@
"reference": "",
"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.",
"translation": "",