1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-05-03 02:52:07 -04:00

Compare commits

..

28 Commits

Author SHA1 Message Date
bbedward
ac0a8f3449 widgets: add openWith/toggleWith modes for dankbar widgets 2026-02-18 16:23:42 -05:00
bbedward
8e4a63db67 keybinds: fix escape in keybinds modal 2026-02-18 14:57:34 -05:00
bbedward
c02c63806f launcher v2: remove calc
cc: enhancements for plugins to size details
2026-02-18 14:48:20 -05:00
beluch-dev
42e5d7f6e9 fix: correct parameter name in Hyprland windowrule (no_initial_focus) (#1726)
##Description
This PR corrects the parameter name to match new Hyprland standard.

## Changes
-Before: 'noinitialfocus'
-After: 'no_initial_focus'
2026-02-18 13:41:12 -05:00
bbedward
d8cf1af422 plugins: fix settings focus loss 2026-02-18 13:36:23 -05:00
Evgeny Zemtsov
9723661c80 handle recycled server object IDs for workspace/group handles (#1725)
When switching tabs rapidly or closing multiple tabs, the taskbar shows
"ghost" workspaces — entries with no name, no coordinates, and no active
state. The ghosts appear at positions where workspaces were removed and
then recreated by the compositor.

When a compositor removes a workspace (sends `removed` event) and the
client calls Destroy(), the proxy is marked as zombie but stays in the
Context.objects map. For server-created objects (IDs >= 0xFF000000), the
server never sends `delete_id`, so the zombie proxy persists indefinitely.

When the compositor later creates a new workspace that gets a recycled
server object ID, GetProxy() returns the old zombie proxy. The dispatch
loop in GetDispatch() checks IsZombie() and silently drops ALL events
for zombie proxies — including property events (name, id, coordinates,
state, capabilities) intended for the new workspace. This causes the
ghost workspaces with empty properties in the UI.

Fix: check IsZombie() when handling `workspace` and `workspace_group`
events that carry a `new_id` argument. If the existing proxy is a
zombie, treat it as absent and create a fresh proxy via
registerServerProxy(), which replaces the zombie in the map. Subsequent
property events are then dispatched to the live proxy.
2026-02-18 12:51:17 -05:00
bbedward
81cba7ad97 popout: decouple shadow from content layer 2026-02-18 10:45:45 -05:00
bbedward
c23f58de40 popout: disable layer after animation 2026-02-18 10:34:07 -05:00
purian23
2cf67ca7da notifications: Maintain shadow during expansion 2026-02-18 10:27:57 -05:00
purian23
392bd850ea notifications: Update initial popup height surfaces 2026-02-18 10:16:11 -05:00
bbedward
3b2ad9d1bd running apps: fix scroll events being propagated
fixes #1724
2026-02-18 10:12:15 -05:00
bbedward
27b7474180 matugen: make v4 detection more resilient 2026-02-18 09:55:45 -05:00
bbedward
63948d728e process list: fix scaling with fonts
fixes #1721
2026-02-18 09:55:45 -05:00
purian23
d219d3b873 dankinstall: Fix Debian ARM64 detection 2026-02-18 09:41:36 -05:00
bbedward
93ab290bc1 matugen: detect emacs directory
fixes #1720
2026-02-18 09:23:13 -05:00
bbedward
7335c5d79a osd: optimize bindings 2026-02-18 09:04:39 -05:00
bbedward
242ead722a screenshot: adjust cursor CLI option to be more explicit 2026-02-17 22:28:19 -05:00
bbedward
8a6d9696a8 settings: workaround crash 2026-02-17 22:20:01 -05:00
purian23
896b7ea242 notifications: Tweak animation scale & settings 2026-02-17 22:05:19 -05:00
bbedward
0c7f4c7828 settings: guard internal writes from watcher 2026-02-17 22:03:36 -05:00
bbedward
3d35af2a87 cc: fix plugin reloading in bar position changes 2026-02-17 17:24:22 -05:00
bbedward
fed3c36f84 popout: anchor height changing popout surfaces to top and bottom 2026-02-17 17:18:07 -05:00
bbedward
414d81aa40 workspaces: fix named workspace icons 2026-02-17 16:02:13 -05:00
bbedward
d548803769 dankinstall: no_anim on dms layers 2026-02-17 15:32:08 -05:00
bbedward
1180258394 system updater: fix hide no update option 2026-02-17 13:53:17 -05:00
bbedward
48a566a24b launcher: fix kb navigation not always showing last delegate in view 2026-02-17 13:07:43 -05:00
bbedward
3bc5d1df81 doctor: add qt6-imageformats check 2026-02-17 12:58:09 -05:00
bbedward
c7222e2e86 bump version, codename, disable changelog 2026-02-17 12:02:36 -05:00
17 changed files with 185 additions and 114 deletions

View File

@@ -100,7 +100,7 @@ windowrule = float on, match:class ^(blueman-manager)$
windowrule = float on, match:class ^(org\.gnome\.Nautilus)$
windowrule = float on, match:class ^(xdg-desktop-portal)$
windowrule = noinitialfocus on, match:class ^(steam)$, match:title ^(notificationtoasts)
windowrule = no_initial_focus on, match:class ^(steam)$, match:title ^(notificationtoasts)
windowrule = pin on, match:class ^(steam)$, match:title ^(notificationtoasts)
windowrule = float on, match:class ^(firefox)$, match:title ^(Picture-in-Picture)$

View File

@@ -258,7 +258,7 @@ func (i *ExtWorkspaceManagerV1) Dispatch(opcode uint32, fd int, data []byte) {
l := 0
objectID := client.Uint32(data[l : l+4])
proxy := i.Context().GetProxy(objectID)
if proxy != nil {
if proxy != nil && !proxy.IsZombie() {
e.WorkspaceGroup = proxy.(*ExtWorkspaceGroupHandleV1)
} else {
groupHandle := &ExtWorkspaceGroupHandleV1{}
@@ -278,7 +278,7 @@ func (i *ExtWorkspaceManagerV1) Dispatch(opcode uint32, fd int, data []byte) {
l := 0
objectID := client.Uint32(data[l : l+4])
proxy := i.Context().GetProxy(objectID)
if proxy != nil {
if proxy != nil && !proxy.IsZombie() {
e.Workspace = proxy.(*ExtWorkspaceHandleV1)
} else {
wsHandle := &ExtWorkspaceHandleV1{}

View File

@@ -1 +1 @@
Saffron Bloom
The Wolverine

View File

@@ -859,6 +859,70 @@ Item {
return success ? `WIDGET_TOGGLE_SUCCESS: ${widgetId}` : `WIDGET_TOGGLE_FAILED: ${widgetId}`;
}
function openWith(widgetId: string, mode: string): string {
if (!widgetId)
return "ERROR: No widget ID specified";
if (!BarWidgetService.hasWidget(widgetId))
return `WIDGET_NOT_FOUND: ${widgetId}`;
const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId);
if (!widget)
return `WIDGET_NOT_AVAILABLE: ${widgetId}`;
if (typeof widget.openWithMode !== "function")
return `WIDGET_OPEN_WITH_NOT_SUPPORTED: ${widgetId}`;
widget.openWithMode(mode || "all");
return `WIDGET_OPEN_WITH_SUCCESS: ${widgetId} ${mode}`;
}
function toggleWith(widgetId: string, mode: string): string {
if (!widgetId)
return "ERROR: No widget ID specified";
if (!BarWidgetService.hasWidget(widgetId))
return `WIDGET_NOT_FOUND: ${widgetId}`;
const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId);
if (!widget)
return `WIDGET_NOT_AVAILABLE: ${widgetId}`;
if (typeof widget.toggleWithMode !== "function")
return `WIDGET_TOGGLE_WITH_NOT_SUPPORTED: ${widgetId}`;
widget.toggleWithMode(mode || "all");
return `WIDGET_TOGGLE_WITH_SUCCESS: ${widgetId} ${mode}`;
}
function openQuery(widgetId: string, query: string): string {
if (!widgetId)
return "ERROR: No widget ID specified";
if (!BarWidgetService.hasWidget(widgetId))
return `WIDGET_NOT_FOUND: ${widgetId}`;
const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId);
if (!widget)
return `WIDGET_NOT_AVAILABLE: ${widgetId}`;
if (typeof widget.openWithQuery !== "function")
return `WIDGET_OPEN_QUERY_NOT_SUPPORTED: ${widgetId}`;
widget.openWithQuery(query || "");
return `WIDGET_OPEN_QUERY_SUCCESS: ${widgetId}`;
}
function toggleQuery(widgetId: string, query: string): string {
if (!widgetId)
return "ERROR: No widget ID specified";
if (!BarWidgetService.hasWidget(widgetId))
return `WIDGET_NOT_FOUND: ${widgetId}`;
const widget = BarWidgetService.getWidgetOnFocusedScreen(widgetId);
if (!widget)
return `WIDGET_NOT_AVAILABLE: ${widgetId}`;
if (typeof widget.toggleWithQuery !== "function")
return `WIDGET_TOGGLE_QUERY_NOT_SUPPORTED: ${widgetId}`;
widget.toggleWithQuery(query || "");
return `WIDGET_TOGGLE_QUERY_SUCCESS: ${widgetId}`;
}
function list(): string {
const widgets = BarWidgetService.getRegisteredWidgetIds();
if (widgets.length === 0)

View File

@@ -125,13 +125,6 @@ Item {
}
readonly property var sectionDefinitions: [
{
id: "calculator",
title: I18n.tr("Calculator"),
icon: "calculate",
priority: 0,
defaultViewMode: "list"
},
{
id: "favorites",
title: I18n.tr("Pinned"),
@@ -681,12 +674,6 @@ Item {
return;
}
var calculatorResult = evaluateCalculator(searchQuery);
if (calculatorResult) {
calculatorResult._preScored = 12000;
allItems.push(calculatorResult);
}
var apps = searchApps(searchQuery);
for (var i = 0; i < apps.length; i++) {
if (searchQuery)
@@ -931,13 +918,6 @@ Item {
return Transform.transformFileResult(file, I18n.tr("Open"), I18n.tr("Open folder"), I18n.tr("Copy path"));
}
function evaluateCalculator(query) {
var calc = Utils.evaluateCalculator(query);
if (!calc)
return null;
return Transform.createCalculatorItem(calc, query, I18n.tr("Copy"));
}
function detectTrigger(query) {
if (!query || query.length === 0)
return {
@@ -1559,9 +1539,6 @@ Item {
case "file":
openFile(item.data?.path);
break;
case "calculator":
copyToClipboard(item.name);
break;
default:
return;
}

View File

@@ -101,35 +101,6 @@ function detectIconType(iconName) {
return "material";
}
function evaluateCalculator(query) {
if (!query || query.length === 0)
return null;
var mathExpr = query.replace(/[^0-9+\-*/().%\s^]/g, "");
if (mathExpr.length < 2)
return null;
var hasMath = /[+\-*/^%]/.test(query) && /\d/.test(query);
if (!hasMath)
return null;
try {
var sanitized = mathExpr.replace(/\^/g, "**");
var result = Function('"use strict"; return (' + sanitized + ')')();
if (typeof result === "number" && isFinite(result)) {
var displayResult = Number.isInteger(result) ? result.toString() : result.toFixed(6).replace(/\.?0+$/, "");
return {
expression: query,
result: result,
displayResult: displayResult
};
}
} catch (e) { }
return null;
}
function sortPluginIdsByOrder(pluginIds, order) {
if (!order || order.length === 0)
return pluginIds;

View File

@@ -190,32 +190,6 @@ function transformPluginItem(item, pluginId, selectLabel) {
};
}
function createCalculatorItem(calc, query, copyLabel) {
return {
id: "calculator_result",
type: "calculator",
name: calc.displayResult,
subtitle: query + " =",
icon: "calculate",
iconType: "material",
section: "calculator",
data: {
expression: calc.expression,
result: calc.result
},
actions: [],
primaryAction: {
name: copyLabel,
icon: "content_copy",
action: "copy"
},
_hName: "",
_hSub: "",
_hRich: false,
_preScored: undefined
};
}
function createPluginBrowseItem(pluginId, plugin, trigger, isBuiltIn, isAllowed, browseLabel, triggerLabel, noTriggerLabel) {
var rawIcon = isBuiltIn ? (plugin.cornerIcon || "extension") : (plugin.icon || "extension");
return {

View File

@@ -178,8 +178,6 @@ Rectangle {
if (!root.item)
return "";
switch (root.item.type) {
case "calculator":
return I18n.tr("Calc");
case "plugin":
return I18n.tr("Plugin");
case "file":

View File

@@ -91,7 +91,12 @@ DankModal {
id: searchField
Layout.alignment: Qt.AlignRight
leftIconName: "search"
keyForwardTargets: [root.modalFocusScope]
onTextEdited: searchDebounce.restart()
Keys.onEscapePressed: event => {
root.close();
event.accepted = true;
}
}
}

View File

@@ -8,10 +8,39 @@ DankPopout {
layerNamespace: "dms:app-launcher"
property string _pendingMode: ""
property string _pendingQuery: ""
function show() {
open();
}
function openWithMode(mode) {
_pendingMode = mode || "";
open();
}
function toggleWithMode(mode) {
if (shouldBeVisible) {
close();
return;
}
openWithMode(mode);
}
function openWithQuery(query) {
_pendingQuery = query || "";
open();
}
function toggleWithQuery(query) {
if (shouldBeVisible) {
close();
return;
}
openWithQuery(query);
}
popupWidth: 560
popupHeight: 640
triggerWidth: 40
@@ -30,15 +59,25 @@ DankPopout {
var lc = contentLoader.item?.launcherContent;
if (!lc)
return;
const query = _pendingQuery;
const mode = _pendingMode || "apps";
_pendingMode = "";
_pendingQuery = "";
if (lc.searchField) {
lc.searchField.text = "";
lc.searchField.text = query;
lc.searchField.forceActiveFocus();
}
if (lc.controller) {
lc.controller.searchMode = "apps";
lc.controller.searchMode = mode;
lc.controller.pluginFilter = "";
lc.controller.searchQuery = "";
lc.controller.performSearch();
if (query) {
lc.controller.setSearchQuery(query);
} else {
lc.controller.performSearch();
}
}
lc.resetScroll?.();
lc.actionPanel?.hide();

View File

@@ -15,18 +15,22 @@ Item {
property var pluginDetailInstance: null
property var widgetModel: null
property var collapseCallback: null
property real maxAvailableHeight: 9999
function getDetailHeight(section) {
const maxAvailable = parent ? parent.height - Theme.spacingS : 9999;
switch (true) {
case section === "wifi":
case section === "bluetooth":
case section === "builtin_vpn":
return Math.min(350, maxAvailable);
return Math.min(350, maxAvailableHeight);
case section.startsWith("brightnessSlider_"):
return Math.min(400, maxAvailable);
return Math.min(400, maxAvailableHeight);
case section.startsWith("plugin_"):
if (pluginDetailInstance?.ccDetailHeight)
return Math.min(pluginDetailInstance.ccDetailHeight, maxAvailableHeight);
return Math.min(250, maxAvailableHeight);
default:
return Math.min(250, maxAvailable);
return Math.min(250, maxAvailableHeight);
}
}

View File

@@ -31,11 +31,26 @@ Column {
spacing: editMode ? Theme.spacingL : Theme.spacingS
property real maxPopoutHeight: 9999
property var currentRowWidgets: []
property real currentRowWidth: 0
property int expandedRowIndex: -1
property var colorPickerModal: null
readonly property real _maxDetailHeight: {
const rows = layoutResult.rows;
let totalRowHeight = 0;
for (let i = 0; i < rows.length; i++) {
const sliderOnly = rows[i].every(w => {
const id = w.id || "";
return id === "volumeSlider" || id === "brightnessSlider" || id === "inputVolumeSlider";
});
totalRowHeight += sliderOnly ? 36 : 60;
}
const rowSpacing = Math.max(0, rows.length - 1) * spacing;
return Math.max(100, maxPopoutHeight - totalRowHeight - rowSpacing);
}
function calculateRowsAndWidgets() {
return LayoutUtils.calculateRowsAndWidgets(root, expandedSection, expandedWidgetIndex);
}
@@ -163,6 +178,7 @@ Column {
DetailHost {
id: detailHost
width: parent.width
maxAvailableHeight: root._maxDetailHeight
height: active ? (getDetailHeight(root.expandedSection) + Theme.spacingS) : 0
property bool active: {
if (root.expandedSection === "")

View File

@@ -116,6 +116,7 @@ DankPopout {
property alias bluetoothCodecSelector: bluetoothCodecSelector
color: "transparent"
clip: true
Rectangle {
anchors.fill: parent
@@ -166,6 +167,10 @@ DankPopout {
id: widgetGrid
width: parent.width
editMode: root.editMode
maxPopoutHeight: {
const screenHeight = (root.triggerScreen?.height ?? 1080);
return screenHeight - 100 - Theme.spacingL - headerPane.height - Theme.spacingS;
}
expandedSection: root.expandedSection
expandedWidgetIndex: root.expandedWidgetIndex
expandedWidgetData: root.expandedWidgetData

View File

@@ -642,24 +642,52 @@ Item {
popoutTarget: appDrawerLoader.item
parentScreen: barWindow.screen
hyprlandOverviewLoader: barWindow ? barWindow.hyprlandOverviewLoader : null
onClicked: {
function _preparePopout() {
appDrawerLoader.active = true;
// Use topBarContent.barConfig directly since widget barConfig binding doesn't work in Components
if (!appDrawerLoader.item)
return false;
const effectiveBarConfig = topBarContent.barConfig;
// Calculate barPosition from axis.edge
const barPosition = barWindow.axis?.edge === "left" ? 2 : (barWindow.axis?.edge === "right" ? 3 : (barWindow.axis?.edge === "top" ? 0 : 1));
if (appDrawerLoader.item && appDrawerLoader.item.setBarContext) {
if (appDrawerLoader.item.setBarContext)
appDrawerLoader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0);
}
if (appDrawerLoader.item && appDrawerLoader.item.setTriggerPosition) {
if (appDrawerLoader.item.setTriggerPosition) {
const globalPos = launcherButton.visualContent.mapToItem(null, 0, 0);
const currentScreen = barWindow.screen;
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barWindow.effectiveBarThickness, launcherButton.visualWidth, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig);
appDrawerLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, launcherButton.section, currentScreen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig);
}
if (appDrawerLoader.item) {
PopoutManager.requestPopout(appDrawerLoader.item, undefined, "appDrawer");
}
return true;
}
function openWithMode(mode) {
if (!_preparePopout())
return;
appDrawerLoader.item.openWithMode(mode);
}
function toggleWithMode(mode) {
if (!_preparePopout())
return;
appDrawerLoader.item.toggleWithMode(mode);
}
function openWithQuery(query) {
if (!_preparePopout())
return;
appDrawerLoader.item.openWithQuery(query);
}
function toggleWithQuery(query) {
if (!_preparePopout())
return;
appDrawerLoader.item.toggleWithQuery(query);
}
onClicked: {
if (!_preparePopout())
return;
PopoutManager.requestPopout(appDrawerLoader.item, undefined, "appDrawer");
}
}
}

View File

@@ -376,22 +376,12 @@ FocusScope {
return;
var isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher"));
if (isLauncher) {
pluginReloadTimer.pendingPluginId = pluginId;
pluginReloadTimer.restart();
pluginsTab.isReloading = true;
PluginService.reloadPlugin(pluginId);
}
}
}
Timer {
id: pluginReloadTimer
property string pendingPluginId: ""
interval: 500
onTriggered: {
if (pendingPluginId)
PluginService.reloadPlugin(pendingPluginId);
}
}
Connections {
target: DMSService
function onPluginsListReceived(plugins) {

View File

@@ -11,7 +11,7 @@ Singleton {
id: root
readonly property string currentVersion: "1.4"
readonly property bool changelogEnabled: true
readonly property bool changelogEnabled: false
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/DankMaterialShell"
readonly property string changelogMarkerPath: configDir + "/.changelog-" + currentVersion

View File

@@ -1 +1 @@
v1.4.1
v1.5-beta