1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 05:25:41 -05:00

Compare commits

...

39 Commits

Author SHA1 Message Date
github-actions[bot]
6013c994a6 Update VERSION to v0.5.0 (from DMS) 2025-11-12 22:02:27 +00:00
bbedward
46c90628b9 systemtray: fix visibility when all items hidden 2025-11-12 16:52:14 -05:00
BB
d2d2dac5d1 [LICENSE] Relicense from GPL-3.0 to MIT (#686)
* Change license to MIT

* Add RELICENSE.md tracker

* update license and add change document
2025-11-12 16:33:34 -05:00
bbedward
fd3e7470f4 support for Hyprland workspaces 2025-11-12 16:05:50 -05:00
bbedward
b79e9f72ce Revert "feat: add configurable per-monitor workspace filtering and system tray monitor selection (#163)"
This reverts commit 68157ca636.
2025-11-12 15:52:04 -05:00
bbedward
77eb5dd3bf extws: fix animation 2025-11-12 15:32:43 -05:00
bbedward
b17c14a07b powermenu: make customizable + add dms restart 2025-11-12 15:29:39 -05:00
bbedward
494d90be22 powermenu: support keyboard shortcuts 2025-11-12 12:17:07 -05:00
bbedward
da7e599e65 powermenu: more intuitive layout 2025-11-12 12:08:42 -05:00
bbedward
e3b7360f39 system tray: add a way to hide certain icons 2025-11-12 11:14:41 -05:00
bbedward
367130882d notifs: fix inadvertant transparency 2025-11-12 08:19:11 -05:00
bbedward
d8563ba79d Merge branch 'master' of github.com:AvengeMedia/DankMaterialShell 2025-11-12 00:48:57 -05:00
bbedward
e527453964 powermenu: replace with grid style 2025-11-12 00:48:42 -05:00
purian23
88fe3c5fbd Add shell completions to Copr builds 2025-11-12 00:16:47 -05:00
bbedward
748faf92c1 add modal and notification layer overrides 2025-11-11 23:51:01 -05:00
bbedward
0126aded78 workflow: add shell completions to release artifacts 2025-11-11 22:57:24 -05:00
bbedward
695a75ea09 wayland: add wlr-output-management-unstable-v1 service + labwc info 2025-11-11 17:19:45 -05:00
bbedward
80e690f9fc workspaces: support ext-workspace-v1
- If available
- If not niri, hyprland, sway, or dwl
2025-11-11 16:21:08 -05:00
claymorwan
e8770b90ef feat: more layer namespaces (#693) 2025-11-11 14:33:47 -05:00
bbedward
eec9da42bf danktabbar: fix initial animation + respect animation speed
fixes #687
2025-11-11 13:27:26 -05:00
bbedward
1c8f0d6292 dankbar: keep sticky reveal when tray menu is open 2025-11-11 13:18:19 -05:00
bbedward
b753c8840b widgets: stop inertia with mouse wheel completely 2025-11-11 12:35:13 -05:00
bbedward
95589982a5 meta: more shadows, do not use QT 6.9 RectangularShadow 2025-11-11 12:10:42 -05:00
bbedward
37a10bd453 settings: fix escape key 2025-11-10 17:12:37 -05:00
bbedward
7abc76e92c launcher: tiny spacing fix 2025-11-10 16:55:45 -05:00
bbedward
7aa4467bda notifications: improve keyboard navigation with groups 2025-11-10 16:39:23 -05:00
bbedward
471938adb6 meta: replace rectangles with DankRectangle shapes 2025-11-10 16:16:25 -05:00
bbedward
201a7e3b34 icons: update spotify override 2025-11-10 15:23:44 -05:00
bbedward
11ec3723c3 popout: tweak shadow 2025-11-10 14:39:58 -05:00
bbedward
75eb736856 popout: add a shadow 2025-11-10 14:21:53 -05:00
bbedward
8fea126c20 runningapps: fix tooltip positioning
fixes #682
2025-11-10 13:57:03 -05:00
bbedward
cc02d09c4d dock: track hyprland addresses, fix closing, use ScriptModel 2025-11-10 12:26:14 -05:00
bbedward
af95631a1d modals: more focus fixes 2025-11-10 09:40:28 -05:00
bbedward
7b3d2ab85a settings: try to fix focus loss 2025-11-10 09:28:10 -05:00
bbedward
c52df96af9 brightness: fix persistence of exponent values 2025-11-10 08:58:27 -05:00
bbedward
dee5fa60af dankbar: fix some center position edge cases 2025-11-09 21:29:39 -05:00
bbedward
5e99fdd9c9 dankbar: fix even widget position 2025-11-09 21:10:43 -05:00
purian23
eb01fe757b Update dual widget center 2025-11-09 20:54:51 -05:00
purian23
c52483da2c Update Dankbar center widget positioning 2025-11-09 19:46:21 -05:00
64 changed files with 3268 additions and 2290 deletions

View File

@@ -79,7 +79,7 @@ jobs:
Release: 1%{?dist}
Summary: %{pkg_summary}
License: GPL-3.0-only
License: MIT
URL: https://github.com/AvengeMedia/DankMaterialShell
Source0: dms-qml.tar.gz
@@ -114,7 +114,7 @@ jobs:
%package -n dms-cli
Summary: DankMaterialShell CLI tool
License: GPL-3.0-only
License: MIT
URL: https://github.com/AvengeMedia/danklinux
%description -n dms-cli
@@ -172,6 +172,14 @@ jobs:
install -Dm755 %{_builddir}/dms-cli %{buildroot}%{_bindir}/dms
install -Dm755 %{_builddir}/dgop %{buildroot}%{_bindir}/dgop
# Shell completions
install -d %{buildroot}%{_datadir}/bash-completion/completions
install -d %{buildroot}%{_datadir}/zsh/site-functions
install -d %{buildroot}%{_datadir}/fish/vendor_completions.d
%{_builddir}/dms-cli completion bash > %{buildroot}%{_datadir}/bash-completion/completions/dms || :
%{_builddir}/dms-cli completion zsh > %{buildroot}%{_datadir}/zsh/site-functions/_dms || :
%{_builddir}/dms-cli completion fish > %{buildroot}%{_datadir}/fish/vendor_completions.d/dms.fish || :
install -Dm644 %{_builddir}/dms-qml/assets/systemd/dms.service %{buildroot}%{_userunitdir}/dms.service
install -dm755 %{buildroot}%{_datadir}/quickshell/dms
@@ -204,6 +212,9 @@ jobs:
%files -n dms-cli
%{_bindir}/dms
%{_datadir}/bash-completion/completions/dms
%{_datadir}/zsh/site-functions/_dms
%{_datadir}/fish/vendor_completions.d/dms.fish
%files -n dgop
%{_bindir}/dgop

View File

@@ -58,8 +58,8 @@ jobs:
## Assets
### Complete Packages
- **`dms-full-amd64.tar.gz`** - Complete package for x86_64 systems (CLI binaries + QML source + installation guide)
- **`dms-full-arm64.tar.gz`** - Complete package for ARM64 systems (CLI binaries + QML source + installation guide)
- **`dms-full-amd64.tar.gz`** - Complete package for x86_64 systems (CLI binaries + QML source + shell completions + installation guide)
- **`dms-full-arm64.tar.gz`** - Complete package for ARM64 systems (CLI binaries + QML source + shell completions + installation guide)
### Individual Components
- **`dms-cli-amd64.gz`** - DMS CLI binary for x86_64 systems
@@ -135,27 +135,28 @@ jobs:
# Generate checksum for QML package
(cd _release_assets && sha256sum dms-qml.tar.gz > dms-qml.tar.gz.sha256)
# Create full packages for each architecture
for arch in amd64 arm64; do
mkdir -p _temp_full/dms
mkdir -p _temp_full/bin
mkdir -p _temp_full/completions
# Extract QML source to temp directory
tar -xzf _release_assets/dms-qml.tar.gz -C _temp_full/dms
# Copy CLI binary if it exists
if [ -f "_dms_assets/dms-${arch}.gz" ]; then
gunzip -c "_dms_assets/dms-${arch}.gz" > _temp_full/bin/dms
chmod +x _temp_full/bin/dms
fi
# Copy distropkg binary if it exists
if [ -f "_dms_assets/dms-distropkg-${arch}.gz" ]; then
gunzip -c "_dms_assets/dms-distropkg-${arch}.gz" > _temp_full/bin/dms-distropkg
chmod +x _temp_full/bin/dms-distropkg
fi
# Create INSTALL.md
for completion in _dms_assets/completion.*; do
if [ -f "$completion" ]; then
cp "$completion" _temp_full/completions/
fi
done
cat > _temp_full/INSTALL.md << 'EOF'
# DankMaterialShell Installation
@@ -176,16 +177,23 @@ jobs:
2. **Install the DMS CLI binaries:**
```bash
sudo install -m 755 bin/dms /usr/local/bin/dms
# or install to a local directory:
mkdir -p ~/.local/bin
install -m 755 bin/dms ~/.local/bin/dms
```
3. **Start the shell:**
3. **Install shell completions (optional):**
```bash
# Bash
sudo install -m 644 completions/completion.bash /usr/share/bash-completion/completions/dms
# Fish
sudo install -m 644 completions/completion.fish /usr/share/fish/vendor_completions.d/dms.fish
# Zsh
sudo install -m 644 completions/completion.zsh /usr/share/zsh/site-functions/_dms
```
4. **Start the shell:**
```bash
dms run
# or directly with quickshell (will lack some dbus integrations & plugin management):
quickshell -p ~/.config/quickshell/dms
```
## Configuration

View File

@@ -53,7 +53,7 @@ Singleton {
// ! Spotify and maybe some other apps report the wrong app id in toplevels, hardcode special case
function moddedAppId(appId: string): string {
if (appId === "Spotify")
return "spotify-launcher"
return "spotify"
if (appId === "beepertexts")
return "beeper"
if (appId === "home assistant desktop")

View File

@@ -56,6 +56,7 @@ Singleton {
property string nightModeLocationProvider: ""
property var pinnedApps: []
property var hiddenTrayIds: []
property var recentColors: []
property bool showThirdPartyPlugins: false
property string launchPrefix: ""
@@ -140,6 +141,7 @@ Singleton {
nightModeUseIPLocation = settings.nightModeUseIPLocation !== undefined ? settings.nightModeUseIPLocation : false
nightModeLocationProvider = settings.nightModeLocationProvider !== undefined ? settings.nightModeLocationProvider : ""
pinnedApps = settings.pinnedApps !== undefined ? settings.pinnedApps : []
hiddenTrayIds = settings.hiddenTrayIds !== undefined ? settings.hiddenTrayIds : []
selectedGpuIndex = settings.selectedGpuIndex !== undefined ? settings.selectedGpuIndex : 0
nvidiaGpuTempEnabled = settings.nvidiaGpuTempEnabled !== undefined ? settings.nvidiaGpuTempEnabled : false
nonNvidiaGpuTempEnabled = settings.nonNvidiaGpuTempEnabled !== undefined ? settings.nonNvidiaGpuTempEnabled : false
@@ -209,6 +211,7 @@ Singleton {
"nightModeUseIPLocation": nightModeUseIPLocation,
"nightModeLocationProvider": nightModeLocationProvider,
"pinnedApps": pinnedApps,
"hiddenTrayIds": hiddenTrayIds,
"selectedGpuIndex": selectedGpuIndex,
"nvidiaGpuTempEnabled": nvidiaGpuTempEnabled,
"nonNvidiaGpuTempEnabled": nonNvidiaGpuTempEnabled,
@@ -277,7 +280,7 @@ Singleton {
}
function cleanupUnusedKeys() {
const validKeys = ["isLightMode", "wallpaperPath", "perMonitorWallpaper", "monitorWallpapers", "perModeWallpaper", "wallpaperPathLight", "wallpaperPathDark", "monitorWallpapersLight", "monitorWallpapersDark", "doNotDisturb", "nightModeEnabled", "nightModeTemperature", "nightModeHighTemperature", "nightModeAutoEnabled", "nightModeAutoMode", "nightModeStartHour", "nightModeStartMinute", "nightModeEndHour", "nightModeEndMinute", "latitude", "longitude", "nightModeUseIPLocation", "nightModeLocationProvider", "pinnedApps", "selectedGpuIndex", "nvidiaGpuTempEnabled", "nonNvidiaGpuTempEnabled", "enabledGpuPciIds", "wallpaperCyclingEnabled", "wallpaperCyclingMode", "wallpaperCyclingInterval", "wallpaperCyclingTime", "monitorCyclingSettings", "lastBrightnessDevice", "brightnessExponentialDevices", "brightnessUserSetValues", "launchPrefix", "wallpaperTransition", "includedTransitions", "recentColors", "showThirdPartyPlugins", "configVersion"]
const validKeys = ["isLightMode", "wallpaperPath", "perMonitorWallpaper", "monitorWallpapers", "perModeWallpaper", "wallpaperPathLight", "wallpaperPathDark", "monitorWallpapersLight", "monitorWallpapersDark", "doNotDisturb", "nightModeEnabled", "nightModeTemperature", "nightModeHighTemperature", "nightModeAutoEnabled", "nightModeAutoMode", "nightModeStartHour", "nightModeStartMinute", "nightModeEndHour", "nightModeEndMinute", "latitude", "longitude", "nightModeUseIPLocation", "nightModeLocationProvider", "pinnedApps", "hiddenTrayIds", "selectedGpuIndex", "nvidiaGpuTempEnabled", "nonNvidiaGpuTempEnabled", "enabledGpuPciIds", "wallpaperCyclingEnabled", "wallpaperCyclingMode", "wallpaperCyclingInterval", "wallpaperCyclingTime", "monitorCyclingSettings", "lastBrightnessDevice", "brightnessExponentialDevices", "brightnessUserSetValues", "brightnessExponentValues", "launchPrefix", "wallpaperTransition", "includedTransitions", "recentColors", "showThirdPartyPlugins", "configVersion"]
try {
const content = settingsFile.text()
@@ -639,6 +642,26 @@ Singleton {
return appId && pinnedApps.indexOf(appId) !== -1
}
function hideTrayId(trayId) {
if (!trayId) return
const current = [...hiddenTrayIds]
if (current.indexOf(trayId) === -1) {
current.push(trayId)
hiddenTrayIds = current
saveSettings()
}
}
function showTrayId(trayId) {
if (!trayId) return
hiddenTrayIds = hiddenTrayIds.filter(id => id !== trayId)
saveSettings()
}
function isHiddenTrayId(trayId) {
return trayId && hiddenTrayIds.indexOf(trayId) !== -1
}
function addRecentColor(color) {
const colorStr = color.toString()
let recent = recentColors.slice()

View File

@@ -292,6 +292,8 @@ Singleton {
property bool osdAlwaysShowValue: false
property bool powerActionConfirm: true
property var powerMenuActions: ["reboot", "logout", "poweroff", "lock", "suspend", "restart"]
property string powerMenuDefaultAction: "logout"
property string customPowerActionLock: ""
property string customPowerActionLogout: ""
property string customPowerActionSuspend: ""

View File

@@ -203,6 +203,8 @@ var SPEC = {
osdAlwaysShowValue: { def: false },
powerActionConfirm: { def: true },
powerMenuActions: { def: ["reboot", "logout", "poweroff", "lock", "suspend", "restart"] },
powerMenuDefaultAction: { def: "logout" },
customPowerActionLock: { def: "" },
customPowerActionLogout: { def: "" },
customPowerActionSuspend: { def: "" },

View File

@@ -482,6 +482,10 @@ Item {
}
}
onLockRequested: {
lock.activate()
}
function actionApply(action) {
switch (action) {
case "logout":

694
LICENSE
View File

@@ -1,674 +1,20 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.
MIT License
Copyright (c) 2025 Avenge Media LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR

View File

@@ -0,0 +1,23 @@
# DankMaterialShell License Change
Relicensing from GPL-3.0 to MIT.
Consent and documentation is available in [pull request #686](https://github.com/AvengeMedia/DankMaterialShell/pull/686) and is summarized below.
## Contributors
The project has 21 contributors requiring consent:
- 2 primary authors (10k+ lines each)
- 7 major contributors (1k+ lines or 10+ commits)
- 12 significant contributors (100+ lines)
- 2 derivative works (code adapted from other projects)
Contributors with <50 lines are excluded as they don't meet copyright thresholds. Automated bots don't hold copyright.
## Consent Status
All 21 contributors have provided consent. Three contributions were sufficiently reverted or rewritten by maintainers, making them eligible without original author consent.
## Reasoning
GPL-3.0 may require plugins to also be GPL-3.0 licensed. MIT allows plugin authors to choose their own licenses.

View File

@@ -4,6 +4,7 @@ import Quickshell.Hyprland
import Quickshell.Wayland
import qs.Common
import qs.Services
import qs.Widgets
PanelWindow {
id: root
@@ -52,11 +53,15 @@ PanelWindow {
closeTimer.stop()
shouldBeVisible = true
visible = true
focusScope.forceActiveFocus()
shouldHaveFocus = false
Qt.callLater(() => {
shouldHaveFocus = Qt.binding(() => shouldBeVisible)
})
}
function close() {
shouldBeVisible = false
shouldHaveFocus = false
closeTimer.restart()
}
@@ -70,7 +75,18 @@ PanelWindow {
visible: shouldBeVisible
color: "transparent"
WlrLayershell.layer: WlrLayershell.Top // if set to overlay -> virtual keyboards can be stuck under modal
WlrLayershell.layer: {
switch (Quickshell.env("DMS_MODAL_LAYER")) {
case "bottom":
return WlrLayershell.Bottom
case "overlay":
return WlrLayershell.Overlay
case "background":
return WlrLayershell.Background
default:
return WlrLayershell.Top
}
}
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: shouldHaveFocus ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
onVisibleChanged: {
@@ -209,21 +225,16 @@ PanelWindow {
}
}
Rectangle {
Item {
id: contentContainer
anchors.centerIn: parent
width: parent.width
height: parent.height
color: root.backgroundColor
radius: root.cornerRadius
border.color: root.borderColor
border.width: root.borderWidth
clip: false
layer.enabled: true
layer.smooth: false
layer.textureSize: Qt.size(width * root.dpr, height * root.dpr)
layer.textureMirroring: ShaderEffectSource.NoMirroring
opacity: root.shouldBeVisible ? 1 : 0
scale: modalContainer.scaleValue
x: Theme.snap(modalContainer.animX + (parent.width - width) * (1 - modalContainer.scaleValue) * 0.5, root.dpr)
@@ -237,6 +248,14 @@ PanelWindow {
}
}
DankRectangle {
anchors.fill: parent
color: root.backgroundColor
borderColor: root.borderColor
borderWidth: root.borderWidth
radius: root.cornerRadius
}
FocusScope {
anchors.fill: parent
focus: root.shouldBeVisible
@@ -304,20 +323,5 @@ PanelWindow {
event.accepted = true
}
}
onVisibleChanged: {
if (visible && shouldHaveFocus) {
Qt.callLater(() => focusScope.forceActiveFocus())
}
}
Connections {
function onShouldHaveFocusChanged() {
if (shouldHaveFocus && shouldBeVisible) {
Qt.callLater(() => focusScope.forceActiveFocus())
}
}
target: root
}
}
}

View File

@@ -1,4 +1,5 @@
import QtQuick
import Quickshell
import qs.Common
import qs.Modals.Common
import qs.Services
@@ -9,12 +10,17 @@ DankModal {
layerNamespace: "dms:power-menu"
property int selectedIndex: 0
property int optionCount: SessionService.hibernateSupported ? 5 : 4
property int selectedRow: 0
property int selectedCol: 0
property int selectedIndex: selectedRow * gridColumns + selectedCol
property rect parentBounds: Qt.rect(0, 0, 0, 0)
property var parentScreen: null
property var visibleActions: []
property int gridColumns: 3
property int gridRows: 2
signal powerActionRequested(string action, string title, string message)
signal lockRequested
function openCentered() {
parentBounds = Qt.rect(0, 0, 0, 0)
@@ -30,8 +36,114 @@ DankModal {
open()
}
function updateVisibleActions() {
const allActions = SettingsData.powerMenuActions || ["reboot", "logout", "poweroff", "lock", "suspend", "restart"]
visibleActions = allActions.filter(action => {
if (action === "hibernate" && !SessionService.hibernateSupported)
return false
return true
})
const count = visibleActions.length
switch (count) {
case 0:
gridColumns = 1
gridRows = 1
break
case 1:
case 2:
case 3:
gridColumns = 1
gridRows = count
break
case 4:
gridColumns = 2
gridRows = 2
break
default:
gridColumns = 3
gridRows = Math.ceil(count / 3)
break
}
}
function getDefaultActionIndex() {
const defaultAction = SettingsData.powerMenuDefaultAction || "logout"
const index = visibleActions.indexOf(defaultAction)
return index >= 0 ? index : 0
}
function getActionAtIndex(index) {
if (index < 0 || index >= visibleActions.length)
return ""
return visibleActions[index]
}
function getActionData(action) {
switch (action) {
case "reboot":
return {
"icon": "restart_alt",
"label": I18n.tr("Reboot"),
"key": "R"
}
case "logout":
return {
"icon": "logout",
"label": I18n.tr("Log Out"),
"key": "X"
}
case "poweroff":
return {
"icon": "power_settings_new",
"label": I18n.tr("Power Off"),
"key": "P"
}
case "lock":
return {
"icon": "lock",
"label": I18n.tr("Lock"),
"key": "L"
}
case "suspend":
return {
"icon": "bedtime",
"label": I18n.tr("Suspend"),
"key": "S"
}
case "hibernate":
return {
"icon": "ac_unit",
"label": I18n.tr("Hibernate"),
"key": "H"
}
case "restart":
return {
"icon": "refresh",
"label": I18n.tr("Restart DMS"),
"key": "D"
}
default:
return {
"icon": "help",
"label": action,
"key": "?"
}
}
}
function selectOption(action) {
close();
if (action === "lock") {
close()
lockRequested()
return
}
if (action === "restart") {
close()
Quickshell.execDetached(["dms", "restart"])
return
}
close()
const actions = {
"logout": {
"title": I18n.tr("Log Out"),
@@ -56,13 +168,12 @@ DankModal {
}
const selected = actions[action]
if (selected) {
root.powerActionRequested(action, selected.title, selected.message);
root.powerActionRequested(action, selected.title, selected.message)
}
}
shouldBeVisible: false
width: 320
width: Math.min(550, gridColumns * 180 + Theme.spacingS * (gridColumns - 1) + Theme.spacingL * 2)
height: contentLoader.item ? contentLoader.item.implicitHeight : 300
enableShadow: true
screen: parentScreen
@@ -75,382 +186,190 @@ DankModal {
}
return Qt.point(0, 0)
}
onBackgroundClicked: () => {
return close();
}
onBackgroundClicked: () => close()
onOpened: () => {
selectedIndex = 0;
Qt.callLater(() => modalFocusScope.forceActiveFocus());
}
modalFocusScope.Keys.onPressed: (event) => {
switch (event.key) {
case Qt.Key_Up:
case Qt.Key_Backtab:
selectedIndex = (selectedIndex - 1 + optionCount) % optionCount;
event.accepted = true;
break;
case Qt.Key_Down:
case Qt.Key_Tab:
selectedIndex = (selectedIndex + 1) % optionCount;
event.accepted = true;
break;
case Qt.Key_Return:
case Qt.Key_Enter:
const actions = ["logout", "suspend"];
if (SessionService.hibernateSupported) actions.push("hibernate");
actions.push("reboot", "poweroff");
if (selectedIndex < actions.length) {
selectOption(actions[selectedIndex]);
}
event.accepted = true;
break;
case Qt.Key_N:
if (event.modifiers & Qt.ControlModifier) {
selectedIndex = (selectedIndex + 1) % optionCount;
event.accepted = true;
}
break;
case Qt.Key_P:
if (event.modifiers & Qt.ControlModifier) {
selectedIndex = (selectedIndex - 1 + optionCount) % optionCount;
event.accepted = true;
}
break;
case Qt.Key_J:
if (event.modifiers & Qt.ControlModifier) {
selectedIndex = (selectedIndex + 1) % optionCount;
event.accepted = true;
}
break;
case Qt.Key_K:
if (event.modifiers & Qt.ControlModifier) {
selectedIndex = (selectedIndex - 1 + optionCount) % optionCount;
event.accepted = true;
}
break;
}
}
updateVisibleActions()
const defaultIndex = getDefaultActionIndex()
selectedRow = Math.floor(defaultIndex / gridColumns)
selectedCol = defaultIndex % gridColumns
Qt.callLater(() => modalFocusScope.forceActiveFocus())
}
Component.onCompleted: updateVisibleActions()
modalFocusScope.Keys.onPressed: event => {
switch (event.key) {
case Qt.Key_Left:
selectedCol = (selectedCol - 1 + gridColumns) % gridColumns
event.accepted = true
break
case Qt.Key_Right:
selectedCol = (selectedCol + 1) % gridColumns
event.accepted = true
break
case Qt.Key_Up:
case Qt.Key_Backtab:
selectedRow = (selectedRow - 1 + gridRows) % gridRows
event.accepted = true
break
case Qt.Key_Down:
case Qt.Key_Tab:
selectedRow = (selectedRow + 1) % gridRows
event.accepted = true
break
case Qt.Key_Return:
case Qt.Key_Enter:
selectOption(getActionAtIndex(selectedIndex))
event.accepted = true
break
case Qt.Key_N:
if (event.modifiers & Qt.ControlModifier) {
selectedCol = (selectedCol + 1) % gridColumns
event.accepted = true
}
break
case Qt.Key_P:
if (!(event.modifiers & Qt.ControlModifier)) {
selectOption("poweroff")
event.accepted = true
} else {
selectedCol = (selectedCol - 1 + gridColumns) % gridColumns
event.accepted = true
}
break
case Qt.Key_J:
if (event.modifiers & Qt.ControlModifier) {
selectedRow = (selectedRow + 1) % gridRows
event.accepted = true
}
break
case Qt.Key_K:
if (event.modifiers & Qt.ControlModifier) {
selectedRow = (selectedRow - 1 + gridRows) % gridRows
event.accepted = true
}
break
case Qt.Key_R:
selectOption("reboot")
event.accepted = true
break
case Qt.Key_X:
selectOption("logout")
event.accepted = true
break
case Qt.Key_L:
selectOption("lock")
event.accepted = true
break
case Qt.Key_S:
selectOption("suspend")
event.accepted = true
break
case Qt.Key_H:
selectOption("hibernate")
event.accepted = true
break
case Qt.Key_D:
selectOption("restart")
event.accepted = true
break
}
}
content: Component {
Item {
anchors.fill: parent
implicitHeight: mainColumn.implicitHeight + Theme.spacingL * 2
implicitHeight: buttonGrid.implicitHeight + Theme.spacingL * 2
Column {
id: mainColumn
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Grid {
id: buttonGrid
anchors.centerIn: parent
columns: root.gridColumns
columnSpacing: Theme.spacingS
rowSpacing: Theme.spacingS
Row {
width: parent.width
Repeater {
model: root.visibleActions
StyledText {
text: I18n.tr("Power Options")
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
required property int index
required property string modelData
Item {
width: parent.width - 150
height: 1
}
readonly property var actionData: root.getActionData(modelData)
readonly property bool isSelected: root.selectedIndex === index
readonly property bool showWarning: modelData === "reboot" || modelData === "poweroff"
DankActionButton {
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
onClicked: () => {
return close();
width: (root.width - Theme.spacingL * 2 - Theme.spacingS * (root.gridColumns - 1)) / root.gridColumns
height: 100
radius: Theme.cornerRadius
color: {
if (isSelected)
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
if (mouseArea.containsMouse)
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08)
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08)
}
border.color: isSelected ? Theme.primary : "transparent"
border.width: isSelected ? 2 : 0
Column {
anchors.centerIn: parent
spacing: Theme.spacingS
DankIcon {
name: parent.parent.actionData.icon
size: Theme.iconSize + 8
color: {
if (parent.parent.showWarning && mouseArea.containsMouse) {
return parent.parent.modelData === "poweroff" ? Theme.error : Theme.warning
}
return Theme.surfaceText
}
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: parent.parent.actionData.label
font.pixelSize: Theme.fontSizeMedium
color: {
if (parent.parent.showWarning && mouseArea.containsMouse) {
return parent.parent.modelData === "poweroff" ? Theme.error : Theme.warning
}
return Theme.surfaceText
}
font.weight: Font.Medium
anchors.horizontalCenter: parent.horizontalCenter
}
Rectangle {
width: 20
height: 16
radius: 4
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.1)
anchors.horizontalCenter: parent.horizontalCenter
StyledText {
text: parent.parent.parent.actionData.key
font.pixelSize: Theme.fontSizeSmall - 1
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
font.weight: Font.Medium
anchors.centerIn: parent
}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.selectedRow = Math.floor(index / root.gridColumns)
root.selectedCol = index % root.gridColumns
root.selectOption(modelData)
}
}
}
}
Column {
width: parent.width
spacing: Theme.spacingS
Rectangle {
width: parent.width
height: 50
radius: Theme.cornerRadius
color: {
if (selectedIndex === 0) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
} else if (logoutArea.containsMouse) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
} else {
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
}
}
border.color: selectedIndex === 0 ? Theme.primary : "transparent"
border.width: selectedIndex === 0 ? 1 : 0
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "logout"
size: Theme.iconSize
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Log Out")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: logoutArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: () => {
selectedIndex = 0;
selectOption("logout");
}
}
}
Rectangle {
width: parent.width
height: 50
radius: Theme.cornerRadius
color: {
if (selectedIndex === 1) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
} else if (suspendArea.containsMouse) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
} else {
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
}
}
border.color: selectedIndex === 1 ? Theme.primary : "transparent"
border.width: selectedIndex === 1 ? 1 : 0
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "bedtime"
size: Theme.iconSize
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Suspend")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: suspendArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: () => {
selectedIndex = 1;
selectOption("suspend");
}
}
}
Rectangle {
width: parent.width
height: 50
radius: Theme.cornerRadius
color: {
if (selectedIndex === 2) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
} else if (hibernateArea.containsMouse) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
} else {
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
}
}
border.color: selectedIndex === 2 ? Theme.primary : "transparent"
border.width: selectedIndex === 2 ? 1 : 0
visible: SessionService.hibernateSupported
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "ac_unit"
size: Theme.iconSize
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Hibernate")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: hibernateArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: () => {
selectedIndex = 2;
selectOption("hibernate");
}
}
}
Rectangle {
width: parent.width
height: 50
radius: Theme.cornerRadius
color: {
const rebootIndex = SessionService.hibernateSupported ? 3 : 2;
if (selectedIndex === rebootIndex) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
} else if (rebootArea.containsMouse) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
} else {
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
}
}
border.color: selectedIndex === (SessionService.hibernateSupported ? 3 : 2) ? Theme.primary : "transparent"
border.width: selectedIndex === (SessionService.hibernateSupported ? 3 : 2) ? 1 : 0
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "restart_alt"
size: Theme.iconSize
color: rebootArea.containsMouse ? Theme.warning : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Reboot")
font.pixelSize: Theme.fontSizeMedium
color: rebootArea.containsMouse ? Theme.warning : Theme.surfaceText
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: rebootArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: () => {
selectedIndex = SessionService.hibernateSupported ? 3 : 2;
selectOption("reboot");
}
}
}
Rectangle {
width: parent.width
height: 50
radius: Theme.cornerRadius
color: {
const powerOffIndex = SessionService.hibernateSupported ? 4 : 3;
if (selectedIndex === powerOffIndex) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
} else if (powerOffArea.containsMouse) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
} else {
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
}
}
border.color: selectedIndex === (SessionService.hibernateSupported ? 4 : 3) ? Theme.primary : "transparent"
border.width: selectedIndex === (SessionService.hibernateSupported ? 4 : 3) ? 1 : 0
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "power_settings_new"
size: Theme.iconSize
color: powerOffArea.containsMouse ? Theme.error : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Power Off")
font.pixelSize: Theme.fontSizeMedium
color: powerOffArea.containsMouse ? Theme.error : Theme.surfaceText
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: powerOffArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: () => {
selectedIndex = SessionService.hibernateSupported ? 4 : 3;
selectOption("poweroff");
}
}
}
}
Item {
height: Theme.spacingS
}
}
}
}
}

View File

@@ -76,10 +76,10 @@ Item {
checked: SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration
enabled: SessionService.loginctlAvailable
onToggled: checked => {
if (SessionService.loginctlAvailable) {
SettingsData.set("loginctlLockIntegration", checked)
}
}
if (SessionService.loginctlAvailable) {
SettingsData.set("loginctlLockIntegration", checked)
}
}
}
DankToggle {
@@ -185,16 +185,16 @@ Item {
}
onValueChanged: value => {
const index = timeoutOptions.indexOf(value)
if (index >= 0) {
const timeout = timeoutValues[index]
if (powerCategory.currentIndex === 0) {
SettingsData.set("acLockTimeout", timeout)
} else {
SettingsData.set("batteryLockTimeout", timeout)
}
}
}
const index = timeoutOptions.indexOf(value)
if (index >= 0) {
const timeout = timeoutValues[index]
if (powerCategory.currentIndex === 0) {
SettingsData.set("acLockTimeout", timeout)
} else {
SettingsData.set("batteryLockTimeout", timeout)
}
}
}
}
DankDropdown {
@@ -222,16 +222,16 @@ Item {
}
onValueChanged: value => {
const index = timeoutOptions.indexOf(value)
if (index >= 0) {
const timeout = timeoutValues[index]
if (powerCategory.currentIndex === 0) {
SettingsData.set("acMonitorTimeout", timeout)
} else {
SettingsData.set("batteryMonitorTimeout", timeout)
}
}
}
const index = timeoutOptions.indexOf(value)
if (index >= 0) {
const timeout = timeoutValues[index]
if (powerCategory.currentIndex === 0) {
SettingsData.set("acMonitorTimeout", timeout)
} else {
SettingsData.set("batteryMonitorTimeout", timeout)
}
}
}
}
DankDropdown {
@@ -259,16 +259,16 @@ Item {
}
onValueChanged: value => {
const index = timeoutOptions.indexOf(value)
if (index >= 0) {
const timeout = timeoutValues[index]
if (powerCategory.currentIndex === 0) {
SettingsData.set("acSuspendTimeout", timeout)
} else {
SettingsData.set("batterySuspendTimeout", timeout)
}
}
}
const index = timeoutOptions.indexOf(value)
if (index >= 0) {
const timeout = timeoutValues[index]
if (powerCategory.currentIndex === 0) {
SettingsData.set("acSuspendTimeout", timeout)
} else {
SettingsData.set("batterySuspendTimeout", timeout)
}
}
}
}
Column {
@@ -304,14 +304,14 @@ Item {
}
onSelectionChanged: (index, selected) => {
if (selected) {
if (powerCategory.currentIndex === 0) {
SettingsData.set("acSuspendBehavior", index)
} else {
SettingsData.set("batterySuspendBehavior", index)
}
}
}
if (selected) {
if (powerCategory.currentIndex === 0) {
SettingsData.set("acSuspendBehavior", index)
} else {
SettingsData.set("batterySuspendBehavior", index)
}
}
}
}
}
@@ -325,6 +325,185 @@ Item {
}
}
StyledRect {
width: parent.width
height: powerMenuCustomSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 0
Column {
id: powerMenuCustomSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "tune"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Power Menu Customization")
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
StyledText {
text: I18n.tr("Customize which actions appear in the power menu")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.Wrap
}
DankDropdown {
id: defaultActionDropdown
width: parent.width
addHorizontalPadding: true
text: I18n.tr("Default selected action")
options: ["Reboot", "Log Out", "Power Off", "Lock", "Suspend", "Restart DMS", "Hibernate"]
property var actionValues: ["reboot", "logout", "poweroff", "lock", "suspend", "restart", "hibernate"]
Component.onCompleted: {
const currentAction = SettingsData.powerMenuDefaultAction || "logout"
const index = actionValues.indexOf(currentAction)
currentValue = index >= 0 ? options[index] : "Log Out"
}
onValueChanged: value => {
const index = options.indexOf(value)
if (index >= 0) {
SettingsData.set("powerMenuDefaultAction", actionValues[index])
}
}
}
Column {
width: parent.width
spacing: Theme.spacingS
DankToggle {
width: parent.width
text: I18n.tr("Show Reboot")
checked: SettingsData.powerMenuActions.includes("reboot")
onToggled: checked => {
let actions = [...SettingsData.powerMenuActions]
if (checked && !actions.includes("reboot")) {
actions.push("reboot")
} else if (!checked) {
actions = actions.filter(a => a !== "reboot")
}
SettingsData.set("powerMenuActions", actions)
}
}
DankToggle {
width: parent.width
text: I18n.tr("Show Log Out")
checked: SettingsData.powerMenuActions.includes("logout")
onToggled: checked => {
let actions = [...SettingsData.powerMenuActions]
if (checked && !actions.includes("logout")) {
actions.push("logout")
} else if (!checked) {
actions = actions.filter(a => a !== "logout")
}
SettingsData.set("powerMenuActions", actions)
}
}
DankToggle {
width: parent.width
text: I18n.tr("Show Power Off")
checked: SettingsData.powerMenuActions.includes("poweroff")
onToggled: checked => {
let actions = [...SettingsData.powerMenuActions]
if (checked && !actions.includes("poweroff")) {
actions.push("poweroff")
} else if (!checked) {
actions = actions.filter(a => a !== "poweroff")
}
SettingsData.set("powerMenuActions", actions)
}
}
DankToggle {
width: parent.width
text: I18n.tr("Show Lock")
checked: SettingsData.powerMenuActions.includes("lock")
onToggled: checked => {
let actions = [...SettingsData.powerMenuActions]
if (checked && !actions.includes("lock")) {
actions.push("lock")
} else if (!checked) {
actions = actions.filter(a => a !== "lock")
}
SettingsData.set("powerMenuActions", actions)
}
}
DankToggle {
width: parent.width
text: I18n.tr("Show Suspend")
checked: SettingsData.powerMenuActions.includes("suspend")
onToggled: checked => {
let actions = [...SettingsData.powerMenuActions]
if (checked && !actions.includes("suspend")) {
actions.push("suspend")
} else if (!checked) {
actions = actions.filter(a => a !== "suspend")
}
SettingsData.set("powerMenuActions", actions)
}
}
DankToggle {
width: parent.width
text: I18n.tr("Show Restart DMS")
description: I18n.tr("Restart the DankMaterialShell")
checked: SettingsData.powerMenuActions.includes("restart")
onToggled: checked => {
let actions = [...SettingsData.powerMenuActions]
if (checked && !actions.includes("restart")) {
actions.push("restart")
} else if (!checked) {
actions = actions.filter(a => a !== "restart")
}
SettingsData.set("powerMenuActions", actions)
}
}
DankToggle {
width: parent.width
text: I18n.tr("Show Hibernate")
description: I18n.tr("Only visible if hibernate is supported by your system")
checked: SettingsData.powerMenuActions.includes("hibernate")
visible: SessionService.hibernateSupported
onToggled: checked => {
let actions = [...SettingsData.powerMenuActions]
if (checked && !actions.includes("hibernate")) {
actions.push("hibernate")
} else if (!checked) {
actions = actions.filter(a => a !== "hibernate")
}
SettingsData.set("powerMenuActions", actions)
}
}
}
}
}
StyledRect {
width: parent.width
height: powerCommandConfirmSection.implicitHeight + Theme.spacingL * 2
@@ -425,12 +604,12 @@ Item {
Component.onCompleted: {
if (SettingsData.customPowerActionLock) {
text = SettingsData.customPowerActionLock;
text = SettingsData.customPowerActionLock
}
}
onTextEdited: {
SettingsData.set("customPowerActionLock", text.trim());
SettingsData.set("customPowerActionLock", text.trim())
}
}
}
@@ -457,12 +636,12 @@ Item {
Component.onCompleted: {
if (SettingsData.customPowerActionLogout) {
text = SettingsData.customPowerActionLogout;
text = SettingsData.customPowerActionLogout
}
}
onTextEdited: {
SettingsData.set("customPowerActionLogout", text.trim());
SettingsData.set("customPowerActionLogout", text.trim())
}
}
}
@@ -489,12 +668,12 @@ Item {
Component.onCompleted: {
if (SettingsData.customPowerActionSuspend) {
text = SettingsData.customPowerActionSuspend;
text = SettingsData.customPowerActionSuspend
}
}
onTextEdited: {
SettingsData.set("customPowerActionSuspend", text.trim());
SettingsData.set("customPowerActionSuspend", text.trim())
}
}
}
@@ -521,12 +700,12 @@ Item {
Component.onCompleted: {
if (SettingsData.customPowerActionHibernate) {
text = SettingsData.customPowerActionHibernate;
text = SettingsData.customPowerActionHibernate
}
}
onTextEdited: {
SettingsData.set("customPowerActionHibernate", text.trim());
SettingsData.set("customPowerActionHibernate", text.trim())
}
}
}
@@ -553,12 +732,12 @@ Item {
Component.onCompleted: {
if (SettingsData.customPowerActionReboot) {
text = SettingsData.customPowerActionReboot;
text = SettingsData.customPowerActionReboot
}
}
onTextEdited: {
SettingsData.set("customPowerActionReboot", text.trim());
SettingsData.set("customPowerActionReboot", text.trim())
}
}
}
@@ -585,12 +764,12 @@ Item {
Component.onCompleted: {
if (SettingsData.customPowerActionPowerOff) {
text = SettingsData.customPowerActionPowerOff;
text = SettingsData.customPowerActionPowerOff
}
}
onTextEdited: {
SettingsData.set("customPowerActionPowerOff", text.trim());
SettingsData.set("customPowerActionPowerOff", text.trim())
}
}
}

View File

@@ -2,12 +2,14 @@ import QtQuick
import qs.Common
import qs.Modules.Settings
Item {
FocusScope {
id: root
property int currentIndex: 0
property var parentModal: null
focus: true
Rectangle {
anchors.fill: parent
anchors.leftMargin: 0
@@ -22,6 +24,7 @@ Item {
anchors.fill: parent
active: root.currentIndex === 0
visible: active
focus: active
sourceComponent: Component {
PersonalizationTab {
@@ -30,6 +33,12 @@ Item {
}
onActiveChanged: {
if (active && item) {
Qt.callLater(() => item.forceActiveFocus())
}
}
}
Loader {
@@ -38,10 +47,17 @@ Item {
anchors.fill: parent
active: root.currentIndex === 1
visible: active
focus: active
sourceComponent: TimeWeatherTab {
}
onActiveChanged: {
if (active && item) {
Qt.callLater(() => item.forceActiveFocus())
}
}
}
Loader {
@@ -50,11 +66,18 @@ Item {
anchors.fill: parent
active: root.currentIndex === 2
visible: active
focus: active
sourceComponent: DankBarTab {
parentModal: root.parentModal
}
onActiveChanged: {
if (active && item) {
Qt.callLater(() => item.forceActiveFocus())
}
}
}
Loader {
@@ -63,10 +86,17 @@ Item {
anchors.fill: parent
active: root.currentIndex === 3
visible: active
focus: active
sourceComponent: WidgetTweaksTab {
}
onActiveChanged: {
if (active && item) {
Qt.callLater(() => item.forceActiveFocus())
}
}
}
Loader {
@@ -75,6 +105,7 @@ Item {
anchors.fill: parent
active: root.currentIndex === 4
visible: active
focus: active
sourceComponent: Component {
DockTab {
@@ -82,6 +113,12 @@ Item {
}
onActiveChanged: {
if (active && item) {
Qt.callLater(() => item.forceActiveFocus())
}
}
}
Loader {
@@ -90,10 +127,17 @@ Item {
anchors.fill: parent
active: root.currentIndex === 5
visible: active
focus: active
sourceComponent: DisplaysTab {
}
onActiveChanged: {
if (active && item) {
Qt.callLater(() => item.forceActiveFocus())
}
}
}
Loader {
@@ -102,10 +146,17 @@ Item {
anchors.fill: parent
active: root.currentIndex === 6
visible: active
focus: active
sourceComponent: LauncherTab {
}
onActiveChanged: {
if (active && item) {
Qt.callLater(() => item.forceActiveFocus())
}
}
}
Loader {
@@ -114,10 +165,17 @@ Item {
anchors.fill: parent
active: root.currentIndex === 7
visible: active
focus: active
sourceComponent: ThemeColorsTab {
}
onActiveChanged: {
if (active && item) {
Qt.callLater(() => item.forceActiveFocus())
}
}
}
Loader {
@@ -126,10 +184,17 @@ Item {
anchors.fill: parent
active: root.currentIndex === 8
visible: active
focus: active
sourceComponent: PowerSettings {
}
onActiveChanged: {
if (active && item) {
Qt.callLater(() => item.forceActiveFocus())
}
}
}
Loader {
@@ -138,11 +203,18 @@ Item {
anchors.fill: parent
active: root.currentIndex === 9
visible: active
focus: active
sourceComponent: PluginsTab {
parentModal: root.parentModal
}
onActiveChanged: {
if (active && item) {
Qt.callLater(() => item.forceActiveFocus())
}
}
}
Loader {
@@ -151,10 +223,17 @@ Item {
anchors.fill: parent
active: root.currentIndex === 10
visible: active
focus: active
sourceComponent: AboutTab {
}
onActiveChanged: {
if (active && item) {
Qt.callLater(() => item.forceActiveFocus())
}
}
}
}

View File

@@ -45,7 +45,23 @@ DankModal {
}
content: settingsContent
onOpened: () => {
Qt.callLater(() => modalFocusScope.forceActiveFocus())
Qt.callLater(() => {
modalFocusScope.forceActiveFocus()
if (contentLoader.item) {
contentLoader.item.forceActiveFocus()
}
})
}
onVisibleChanged: {
if (visible && shouldBeVisible) {
Qt.callLater(() => {
modalFocusScope.forceActiveFocus()
if (contentLoader.item) {
contentLoader.item.forceActiveFocus()
}
})
}
}
modalFocusScope.Keys.onPressed: event => {
const tabCount = 11
@@ -113,6 +129,14 @@ DankModal {
}
onDialogClosed: () => {
allowStacking = true;
if (settingsModal.shouldBeVisible) {
Qt.callLater(() => {
settingsModal.modalFocusScope.forceActiveFocus()
if (settingsModal.contentLoader.item) {
settingsModal.contentLoader.item.forceActiveFocus()
}
})
}
}
}
@@ -132,6 +156,14 @@ DankModal {
}
onDialogClosed: () => {
allowStacking = true;
if (settingsModal.shouldBeVisible) {
Qt.callLater(() => {
settingsModal.modalFocusScope.forceActiveFocus()
if (settingsModal.contentLoader.item) {
settingsModal.contentLoader.item.forceActiveFocus()
}
})
}
}
}
@@ -140,6 +172,11 @@ DankModal {
id: rootScope
anchors.fill: parent
Keys.onEscapePressed: event => {
settingsModal.hide()
event.accepted = true
}
Column {
anchors.fill: parent
anchors.leftMargin: Theme.spacingL

View File

@@ -183,6 +183,7 @@ Item {
width: parent.width
spacing: Theme.spacingM
leftPadding: Theme.spacingS
topPadding: Theme.spacingS
DankTextField {
id: searchField

View File

@@ -27,6 +27,7 @@ DankPopout {
property bool editMode: false
property int expandedWidgetIndex: -1
property var expandedWidgetData: null
property bool powerMenuOpen: powerMenuModalLoader?.item?.shouldBeVisible ?? false
signal lockRequested
@@ -115,6 +116,21 @@ DankPopout {
antialiasing: true
smooth: true
Rectangle {
anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.6)
radius: parent.radius
visible: root.powerMenuOpen
z: 5000
Behavior on opacity {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
}
Column {
id: mainColumn
width: parent.width - Theme.spacingL * 2

View File

@@ -24,8 +24,7 @@ Item {
property real totalSize: 0
function updateLayout() {
const containerSize = isVertical ? height : width
if (containerSize <= 0 || !visible) {
if ((isVertical ? height : width) <= 0 || !visible) {
return
}
@@ -34,32 +33,58 @@ Item {
totalSize = 0
let configuredWidgets = 0
let configuredMiddleWidget = null
let configuredLeftWidget = null
let configuredRightWidget = null
for (var i = 0; i < centerRepeater.count; i++) {
const item = centerRepeater.itemAt(i)
if (item && getWidgetVisible(item.widgetId)) {
configuredWidgets++
}
}
const isOddConfigured = configuredWidgets % 2 === 1
const configuredMiddlePos = Math.floor(configuredWidgets / 2)
const configuredLeftPos = isOddConfigured ? -1 : ((configuredWidgets / 2) - 1)
const configuredRightPos = isOddConfigured ? -1 : (configuredWidgets / 2)
let currentConfigIndex = 0
for (var i = 0; i < centerRepeater.count; i++) {
const item = centerRepeater.itemAt(i)
if (item && getWidgetVisible(item.widgetId)) {
if (isOddConfigured && currentConfigIndex === configuredMiddlePos && item.active && item.item) {
configuredMiddleWidget = item.item
}
if (!isOddConfigured && currentConfigIndex === configuredLeftPos && item.active && item.item) {
configuredLeftWidget = item.item
}
if (!isOddConfigured && currentConfigIndex === configuredRightPos && item.active && item.item) {
configuredRightWidget = item.item
}
if (item.active && item.item) {
centerWidgets.push(item.item)
totalWidgets++
totalSize += isVertical ? item.item.height : item.item.width
}
currentConfigIndex++
}
}
if (totalWidgets === 0) {
return
}
if (totalWidgets > 1) {
totalSize += spacing * (totalWidgets - 1)
}
positionWidgets(configuredWidgets)
positionWidgets(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget)
}
function positionWidgets(configuredWidgets) {
if (totalWidgets === 0 || (isVertical ? height : width) <= 0) {
return
}
function positionWidgets(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget) {
const parentCenter = (isVertical ? height : width) / 2
const isOdd = configuredWidgets % 2 === 1
const isOddConfigured = configuredWidgets % 2 === 1
centerWidgets.forEach(widget => {
if (isVertical) {
@@ -69,193 +94,169 @@ Item {
}
})
if (isOdd) {
const middleIndex = Math.floor(configuredWidgets / 2)
let currentActiveIndex = 0
let middleWidget = null
if (isOddConfigured && configuredMiddleWidget) {
const middleWidget = configuredMiddleWidget
const middleIndex = centerWidgets.indexOf(middleWidget)
const middleSize = isVertical ? middleWidget.height : middleWidget.width
for (var i = 0; i < centerRepeater.count; i++) {
const item = centerRepeater.itemAt(i)
if (item && getWidgetVisible(item.widgetId)) {
if (currentActiveIndex === middleIndex && item.active && item.item) {
middleWidget = item.item
break
}
currentActiveIndex++
if (isVertical) {
middleWidget.y = parentCenter - (middleSize / 2)
} else {
middleWidget.x = parentCenter - (middleSize / 2)
}
let currentPos = isVertical ? middleWidget.y : middleWidget.x
for (var i = middleIndex - 1; i >= 0; i--) {
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width
currentPos -= (spacing + size)
if (isVertical) {
centerWidgets[i].y = currentPos
} else {
centerWidgets[i].x = currentPos
}
}
if (middleWidget) {
const middleSize = isVertical ? middleWidget.height : middleWidget.width
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize
for (var i = middleIndex + 1; i < totalWidgets; i++) {
currentPos += spacing
if (isVertical) {
middleWidget.y = parentCenter - (middleSize / 2)
centerWidgets[i].y = currentPos
} else {
middleWidget.x = parentCenter - (middleSize / 2)
}
let leftWidgets = []
let rightWidgets = []
let foundMiddle = false
for (var i = 0; i < centerWidgets.length; i++) {
if (centerWidgets[i] === middleWidget) {
foundMiddle = true
continue
}
if (!foundMiddle) {
leftWidgets.push(centerWidgets[i])
} else {
rightWidgets.push(centerWidgets[i])
}
}
let currentPos = isVertical ? middleWidget.y : middleWidget.x
for (var i = leftWidgets.length - 1; i >= 0; i--) {
const size = isVertical ? leftWidgets[i].height : leftWidgets[i].width
currentPos -= (spacing + size)
if (isVertical) {
leftWidgets[i].y = currentPos
} else {
leftWidgets[i].x = currentPos
}
}
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize
for (var i = 0; i < rightWidgets.length; i++) {
currentPos += spacing
if (isVertical) {
rightWidgets[i].y = currentPos
} else {
rightWidgets[i].x = currentPos
}
currentPos += isVertical ? rightWidgets[i].height : rightWidgets[i].width
centerWidgets[i].x = currentPos
}
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width
}
} else {
let configuredLeftIndex = (configuredWidgets / 2) - 1
let configuredRightIndex = configuredWidgets / 2
const halfSpacing = spacing / 2
if (totalWidgets === 1) {
const widget = centerWidgets[0]
const size = isVertical ? widget.height : widget.width
if (isVertical) {
widget.y = parentCenter - (size / 2)
} else {
widget.x = parentCenter - (size / 2)
}
return
}
let leftWidget = null
let rightWidget = null
let leftWidgets = []
let rightWidgets = []
if (!configuredLeftWidget || !configuredRightWidget) {
if (totalWidgets % 2 === 1) {
const middleIndex = Math.floor(totalWidgets / 2)
const middleWidget = centerWidgets[middleIndex]
let currentConfigIndex = 0
for (var i = 0; i < centerRepeater.count; i++) {
const item = centerRepeater.itemAt(i)
if (item && getWidgetVisible(item.widgetId)) {
if (item.active && item.item) {
if (currentConfigIndex < configuredLeftIndex) {
leftWidgets.push(item.item)
} else if (currentConfigIndex === configuredLeftIndex) {
leftWidget = item.item
} else if (currentConfigIndex === configuredRightIndex) {
rightWidget = item.item
if (!middleWidget) {
return
}
const middleSize = isVertical ? middleWidget.height : middleWidget.width
if (isVertical) {
middleWidget.y = parentCenter - (middleSize / 2)
} else {
middleWidget.x = parentCenter - (middleSize / 2)
}
let currentPos = isVertical ? middleWidget.y : middleWidget.x
for (var i = middleIndex - 1; i >= 0; i--) {
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width
currentPos -= (spacing + size)
if (isVertical) {
centerWidgets[i].y = currentPos
} else {
rightWidgets.push(item.item)
centerWidgets[i].x = currentPos
}
}
currentConfigIndex++
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize
for (var i = middleIndex + 1; i < totalWidgets; i++) {
currentPos += spacing
if (isVertical) {
centerWidgets[i].y = currentPos
} else {
centerWidgets[i].x = currentPos
}
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width
}
} else {
const leftIndex = (totalWidgets / 2) - 1
const rightIndex = totalWidgets / 2
const fallbackLeft = centerWidgets[leftIndex]
const fallbackRight = centerWidgets[rightIndex]
if (!fallbackLeft || !fallbackRight) {
return
}
const halfSpacing = spacing / 2
const leftSize = isVertical ? fallbackLeft.height : fallbackLeft.width
if (isVertical) {
fallbackLeft.y = parentCenter - halfSpacing - leftSize
fallbackRight.y = parentCenter + halfSpacing
} else {
fallbackLeft.x = parentCenter - halfSpacing - leftSize
fallbackRight.x = parentCenter + halfSpacing
}
let currentPos = isVertical ? fallbackLeft.y : fallbackLeft.x
for (var i = leftIndex - 1; i >= 0; i--) {
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width
currentPos -= (spacing + size)
if (isVertical) {
centerWidgets[i].y = currentPos
} else {
centerWidgets[i].x = currentPos
}
}
currentPos = (isVertical ? fallbackRight.y + fallbackRight.height : fallbackRight.x + fallbackRight.width)
for (var i = rightIndex + 1; i < totalWidgets; i++) {
currentPos += spacing
if (isVertical) {
centerWidgets[i].y = currentPos
} else {
centerWidgets[i].x = currentPos
}
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width
}
}
return
}
const leftWidget = configuredLeftWidget
const rightWidget = configuredRightWidget
const leftIndex = centerWidgets.indexOf(leftWidget)
const rightIndex = centerWidgets.indexOf(rightWidget)
const halfSpacing = spacing / 2
const leftSize = isVertical ? leftWidget.height : leftWidget.width
if (isVertical) {
leftWidget.y = parentCenter - halfSpacing - leftSize
rightWidget.y = parentCenter + halfSpacing
} else {
leftWidget.x = parentCenter - halfSpacing - leftSize
rightWidget.x = parentCenter + halfSpacing
}
let currentPos = isVertical ? leftWidget.y : leftWidget.x
for (var i = leftIndex - 1; i >= 0; i--) {
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width
currentPos -= (spacing + size)
if (isVertical) {
centerWidgets[i].y = currentPos
} else {
centerWidgets[i].x = currentPos
}
}
if (leftWidget && rightWidget) {
const leftSize = isVertical ? leftWidget.height : leftWidget.width
currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width)
for (var i = rightIndex + 1; i < totalWidgets; i++) {
currentPos += spacing
if (isVertical) {
leftWidget.y = parentCenter - halfSpacing - leftSize
rightWidget.y = parentCenter + halfSpacing
centerWidgets[i].y = currentPos
} else {
leftWidget.x = parentCenter - halfSpacing - leftSize
rightWidget.x = parentCenter + halfSpacing
}
let currentPos = isVertical ? leftWidget.y : leftWidget.x
for (var i = leftWidgets.length - 1; i >= 0; i--) {
const size = isVertical ? leftWidgets[i].height : leftWidgets[i].width
currentPos -= (spacing + size)
if (isVertical) {
leftWidgets[i].y = currentPos
} else {
leftWidgets[i].x = currentPos
}
}
currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width)
for (var i = 0; i < rightWidgets.length; i++) {
currentPos += spacing
if (isVertical) {
rightWidgets[i].y = currentPos
} else {
rightWidgets[i].x = currentPos
}
currentPos += isVertical ? rightWidgets[i].height : rightWidgets[i].width
}
} else if (leftWidget && !rightWidget) {
const leftSize = isVertical ? leftWidget.height : leftWidget.width
if (isVertical) {
leftWidget.y = parentCenter - halfSpacing - leftSize
} else {
leftWidget.x = parentCenter - halfSpacing - leftSize
}
let currentPos = isVertical ? leftWidget.y : leftWidget.x
for (var i = leftWidgets.length - 1; i >= 0; i--) {
const size = isVertical ? leftWidgets[i].height : leftWidgets[i].width
currentPos -= (spacing + size)
if (isVertical) {
leftWidgets[i].y = currentPos
} else {
leftWidgets[i].x = currentPos
}
}
currentPos = (isVertical ? leftWidget.y + leftWidget.height : leftWidget.x + leftWidget.width) + spacing
for (var i = 0; i < rightWidgets.length; i++) {
currentPos += spacing
if (isVertical) {
rightWidgets[i].y = currentPos
} else {
rightWidgets[i].x = currentPos
}
currentPos += isVertical ? rightWidgets[i].height : rightWidgets[i].width
}
} else if (!leftWidget && rightWidget) {
if (isVertical) {
rightWidget.y = parentCenter + halfSpacing
} else {
rightWidget.x = parentCenter + halfSpacing
}
let currentPos = (isVertical ? rightWidget.y : rightWidget.x) - spacing
for (var i = leftWidgets.length - 1; i >= 0; i--) {
const size = isVertical ? leftWidgets[i].height : leftWidgets[i].width
currentPos -= size
if (isVertical) {
leftWidgets[i].y = currentPos
} else {
leftWidgets[i].x = currentPos
}
currentPos -= spacing
}
currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width)
for (var i = 0; i < rightWidgets.length; i++) {
currentPos += spacing
if (isVertical) {
rightWidgets[i].y = currentPos
} else {
rightWidgets[i].x = currentPos
}
currentPos += isVertical ? rightWidgets[i].height : rightWidgets[i].width
}
} else if (totalWidgets === 1 && centerWidgets[0]) {
const size = isVertical ? centerWidgets[0].height : centerWidgets[0].width
if (isVertical) {
centerWidgets[0].y = parentCenter - (size / 2)
} else {
centerWidgets[0].x = parentCenter - (size / 2)
centerWidgets[i].x = currentPos
}
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width
}
}
}

View File

@@ -25,6 +25,7 @@ Item {
property alias barVariants: barVariants
property var hyprlandOverviewLoader: null
property bool systemTrayMenuOpen: false
function triggerControlCenterOnFocusedScreen() {
let focusedScreenName = ""
@@ -444,7 +445,7 @@ Item {
return item.loader.item[item.prop]
}
return false
})
}) || root.systemTrayMenuOpen
}
Connections {
@@ -470,7 +471,10 @@ Item {
}
onHasActivePopoutChanged: {
if (!hasActivePopout && autoHide && !topBarMouseArea.containsMouse) {
if (hasActivePopout) {
revealSticky = true
revealHold.stop()
} else if (autoHide && !topBarMouseArea.containsMouse) {
revealSticky = true
revealHold.restart()
}

View File

@@ -56,7 +56,7 @@ BasePill {
}
IconImage {
visible: SettingsData.launcherLogoMode === "compositor" && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway)
visible: SettingsData.launcherLogoMode === "compositor" && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isLabwc)
anchors.centerIn: parent
width: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset)
height: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset)
@@ -71,6 +71,8 @@ BasePill {
return "file://" + Theme.shellDir + "/assets/mango.png"
} else if (CompositorService.isSway) {
return "file://" + Theme.shellDir + "/assets/sway.svg"
} else if (CompositorService.isLabwc) {
return "file://" + Theme.shellDir + "/assets/labwc.png"
}
return ""
}

View File

@@ -421,7 +421,11 @@ Item {
tooltipLoader.item.show(delegateItem.tooltipText, screenX + tooltipX, relativeY, root.parentScreen, isLeft, !isLeft)
} else {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height)
const tooltipY = Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS
const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height
const isBottom = root.axis?.edge === "bottom"
const tooltipY = isBottom
? (screenHeight - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS - 35)
: (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS)
tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false)
}
}
@@ -650,7 +654,11 @@ Item {
tooltipLoader.item.show(delegateItem.tooltipText, screenX + tooltipX, relativeY, root.parentScreen, isLeft, !isLeft)
} else {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height)
const tooltipY = Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS
const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height
const isBottom = root.axis?.edge === "bottom"
const tooltipY = isBottom
? (screenHeight - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS - 35)
: (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS)
tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false)
}
}

View File

@@ -22,7 +22,7 @@ Item {
const envValue = Quickshell.env("DMS_HIDE_TRAYIDS") || ""
return envValue ? envValue.split(",").map(id => id.trim().toLowerCase()) : []
}
readonly property var visibleTrayItems: {
readonly property var allTrayItems: {
if (!hiddenTrayIds.length) {
return SystemTray.items.values
}
@@ -31,13 +31,20 @@ Item {
return !hiddenTrayIds.includes(itemId.toLowerCase())
})
}
readonly property int calculatedSize: visibleTrayItems.length > 0 ? visibleTrayItems.length * 24 + horizontalPadding * 2 : 0
readonly property var mainBarItems: allTrayItems.filter(item => !SessionData.isHiddenTrayId(item?.id || ""))
readonly property int calculatedSize: {
if (allTrayItems.length === 0) return 0
const itemCount = mainBarItems.length + 1
return itemCount * 24 + horizontalPadding * 2
}
readonly property real visualWidth: isVertical ? widgetThickness : calculatedSize
readonly property real visualHeight: isVertical ? calculatedSize : widgetThickness
width: isVertical ? barThickness : visualWidth
height: isVertical ? visualHeight : barThickness
visible: visibleTrayItems.length > 0
visible: allTrayItems.length > 0
property bool menuOpen: false
Rectangle {
id: visualBackground
@@ -46,7 +53,7 @@ Item {
anchors.centerIn: parent
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
color: {
if (visibleTrayItems.length === 0) {
if (allTrayItems.length === 0) {
return "transparent";
}
@@ -71,7 +78,7 @@ Item {
spacing: 0
Repeater {
model: root.visibleTrayItems
model: root.mainBarItems
delegate: Item {
id: delegateRoot
@@ -165,6 +172,35 @@ Item {
}
}
}
Item {
width: 24
height: root.barThickness
Rectangle {
id: caretButton
width: 24
height: 24
anchors.centerIn: parent
radius: Theme.cornerRadius
color: caretArea.containsMouse ? Theme.primaryHover : "transparent"
DankIcon {
anchors.centerIn: parent
name: root.menuOpen ? "expand_less" : "expand_more"
size: Theme.barIconSize(root.barThickness)
color: Theme.surfaceText
}
MouseArea {
id: caretArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.menuOpen = !root.menuOpen
}
}
}
}
}
@@ -174,7 +210,7 @@ Item {
spacing: 0
Repeater {
model: root.visibleTrayItems
model: root.mainBarItems
delegate: Item {
id: delegateRoot
@@ -268,6 +304,320 @@ Item {
}
}
}
Item {
width: root.barThickness
height: 24
Rectangle {
id: caretButtonVert
width: 24
height: 24
anchors.centerIn: parent
radius: Theme.cornerRadius
color: caretAreaVert.containsMouse ? Theme.primaryHover : "transparent"
DankIcon {
anchors.centerIn: parent
name: {
const edge = root.axis?.edge
if (edge === "left") {
return root.menuOpen ? "chevron_left" : "chevron_right"
} else {
return root.menuOpen ? "chevron_right" : "chevron_left"
}
}
size: Theme.barIconSize(root.barThickness)
color: Theme.surfaceText
}
MouseArea {
id: caretAreaVert
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.menuOpen = !root.menuOpen
}
}
}
}
}
PanelWindow {
id: overflowMenu
visible: root.menuOpen
screen: root.parentScreen
WlrLayershell.layer: WlrLayershell.Top
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
WlrLayershell.namespace: "dms:tray-overflow-menu"
color: "transparent"
anchors {
top: true
left: true
right: true
bottom: true
}
property point anchorPos: Qt.point(screen.width / 2, screen.height / 2)
onVisibleChanged: {
if (visible) updatePosition()
}
function updatePosition() {
if (!root.parentWindow) {
anchorPos = Qt.point(screen.width / 2, screen.height / 2)
return
}
const globalPos = root.mapToGlobal(0, 0)
const screenX = screen.x || 0
const screenY = screen.y || 0
const relativeX = globalPos.x - screenX
const relativeY = globalPos.y - screenY
const widgetThickness = Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
const effectiveBarThickness = Math.max(widgetThickness + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
if (root.isVertical) {
const edge = root.axis?.edge
let targetX = edge === "left"
? effectiveBarThickness + SettingsData.dankBarSpacing + Theme.popupDistance
: screen.width - (effectiveBarThickness + SettingsData.dankBarSpacing + Theme.popupDistance)
anchorPos = Qt.point(targetX, relativeY + root.height / 2)
} else {
let targetY = root.isAtBottom
? screen.height - (effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap + Theme.popupDistance)
: effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap + Theme.popupDistance
anchorPos = Qt.point(relativeX + root.width / 2, targetY)
}
}
Rectangle {
id: menuContainer
width: 250
height: Math.min(screen.height - 100, menuColumn.implicitHeight + Theme.spacingS * 2)
x: {
if (root.isVertical) {
const edge = root.axis?.edge
if (edge === "left") {
const targetX = overflowMenu.anchorPos.x
return Math.min(overflowMenu.screen.width - width - 10, targetX)
} else {
const targetX = overflowMenu.anchorPos.x - width
return Math.max(10, targetX)
}
} else {
const left = 10
const right = overflowMenu.width - width - 10
const want = overflowMenu.anchorPos.x - width / 2
return Math.max(left, Math.min(right, want))
}
}
y: {
if (root.isVertical) {
const top = 10
const bottom = overflowMenu.height - height - 10
const want = overflowMenu.anchorPos.y - height / 2
return Math.max(top, Math.min(bottom, want))
} else {
if (root.isAtBottom) {
const targetY = overflowMenu.anchorPos.y - height
return Math.max(10, targetY)
} else {
const targetY = overflowMenu.anchorPos.y
return Math.min(overflowMenu.screen.height - height - 10, targetY)
}
}
}
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
opacity: root.menuOpen ? 1 : 0
scale: root.menuOpen ? 1 : 0.85
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on scale {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
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: parent.z - 1
}
DankFlickable {
id: scrollView
anchors.fill: parent
anchors.margins: Theme.spacingS
contentWidth: width
contentHeight: menuColumn.implicitHeight
clip: true
Column {
id: menuColumn
width: parent.width
spacing: 2
Repeater {
model: root.allTrayItems
delegate: Rectangle {
property var trayItem: modelData
property string iconSource: {
let icon = trayItem?.icon
if (typeof icon === 'string' || icon instanceof String) {
if (icon === "") return ""
if (icon.includes("?path=")) {
const split = icon.split("?path=")
if (split.length !== 2) return icon
const name = split[0]
const path = split[1]
let fileName = name.substring(name.lastIndexOf("/") + 1)
if (fileName.startsWith("dropboxstatus")) {
fileName = `hicolor/16x16/status/${fileName}`
}
return `file://${path}/${fileName}`
}
if (icon.startsWith("/") && !icon.startsWith("file://")) {
return `file://${icon}`
}
return icon
}
return ""
}
width: menuColumn.width
height: 32
radius: Theme.cornerRadius
color: itemArea.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.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
IconImage {
id: menuIconImg
width: 20
height: 20
anchors.verticalCenter: parent.verticalCenter
source: parent.parent.iconSource
asynchronous: true
smooth: true
mipmap: true
visible: status === Image.Ready
}
Text {
anchors.verticalCenter: parent.verticalCenter
visible: !menuIconImg.visible
text: {
const itemId = trayItem?.id || ""
if (!itemId) return "?"
return itemId.charAt(0).toUpperCase()
}
font.pixelSize: 10
color: Theme.surfaceText
}
StyledText {
text: trayItem?.tooltip?.title || trayItem?.id || "Unknown"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
width: Math.min(implicitWidth, menuColumn.width - 80)
}
}
Rectangle {
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
width: 24
height: 24
radius: Theme.cornerRadius
color: visibilityArea.containsMouse ? Theme.primaryHover : "transparent"
DankIcon {
anchors.centerIn: parent
name: SessionData.isHiddenTrayId(trayItem?.id || "") ? "visibility_off" : "visibility"
size: 16
color: Theme.surfaceText
}
MouseArea {
id: visibilityArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
const itemId = trayItem?.id || ""
if (!itemId) return
if (SessionData.isHiddenTrayId(itemId)) {
SessionData.showTrayId(itemId)
} else {
SessionData.hideTrayId(itemId)
}
}
}
}
MouseArea {
id: itemArea
anchors.fill: parent
anchors.rightMargin: 32
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton
cursorShape: Qt.PointingHandCursor
onClicked: (mouse) => {
if (!trayItem) return
if (mouse.button === Qt.LeftButton && !trayItem.onlyMenu) {
trayItem.activate()
root.menuOpen = false
return
}
if (trayItem.hasMenu) {
root.menuOpen = false
root.showForTrayItem(trayItem, parent, parentScreen, root.isAtBottom, root.isVertical, root.axis)
}
}
}
}
}
}
}
}
MouseArea {
anchors.fill: parent
z: -1
onClicked: root.menuOpen = false
}
}
@@ -340,9 +690,12 @@ Item {
color: "transparent"
PanelWindow {
WlrLayershell.namespace: "dms:tray-menu-window"
id: menuWindow
visible: menuRoot.showMenu && (menuRoot.trayItem?.hasMenu ?? false)
WlrLayershell.layer: WlrLayershell.Overlay
WlrLayershell.layer: WlrLayershell.Top
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
color: "transparent"
@@ -678,7 +1031,21 @@ Item {
property var currentTrayMenu: null
Connections {
target: currentTrayMenu
enabled: currentTrayMenu !== null
function onShowMenuChanged() {
if (parentWindow && typeof parentWindow.systemTrayMenuOpen !== "undefined") {
parentWindow.systemTrayMenuOpen = currentTrayMenu.showMenu
}
}
}
function showForTrayItem(item, anchor, screen, atBottom, vertical, axisObj) {
if (parentWindow && typeof parentWindow.systemTrayMenuOpen !== "undefined") {
parentWindow.systemTrayMenuOpen = true
}
if (currentTrayMenu) {
currentTrayMenu.destroy()
}

View File

@@ -23,6 +23,8 @@ Item {
return CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName);
}
readonly property bool useExtWorkspace: DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && ExtWorkspaceService.extWorkspaceAvailable)
Connections {
target: DesktopEntries
function onApplicationsChanged() {
@@ -30,18 +32,22 @@ Item {
}
}
property int currentWorkspace: {
if (CompositorService.isNiri) {
property var currentWorkspace: {
if (useExtWorkspace) return getExtWorkspaceActiveWorkspace()
switch (CompositorService.compositor) {
case "niri":
return getNiriActiveWorkspace()
} else if (CompositorService.isHyprland) {
case "hyprland":
return getHyprlandActiveWorkspace()
} else if (CompositorService.isDwl) {
case "dwl":
const activeTags = getDwlActiveTags()
return activeTags.length > 0 ? activeTags[0] : -1
} else if (CompositorService.isSway) {
case "sway":
return getSwayActiveWorkspace()
default:
return 1
}
return 1
}
property var dwlActiveTags: {
if (CompositorService.isDwl) {
@@ -50,24 +56,29 @@ Item {
return []
}
property var workspaceList: {
if (CompositorService.isNiri) {
const baseList = getNiriWorkspaces()
if (useExtWorkspace) {
const baseList = getExtWorkspaceWorkspaces()
return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList
}
if (CompositorService.isHyprland) {
const baseList = getHyprlandWorkspaces()
const filteredList = baseList.filter(ws => ws.id > -1)
return SettingsData.showWorkspacePadding ? padWorkspaces(filteredList) : filteredList
let baseList
switch (CompositorService.compositor) {
case "niri":
baseList = getNiriWorkspaces()
break
case "hyprland":
baseList = getHyprlandWorkspaces()
break
case "dwl":
baseList = getDwlTags()
break
case "sway":
baseList = getSwayWorkspaces()
break
default:
return [1]
}
if (CompositorService.isDwl) {
const baseList = getDwlTags()
return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList
}
if (CompositorService.isSway) {
const baseList = getSwayWorkspaces()
return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList
}
return [1]
return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList
}
function getSwayWorkspaces() {
@@ -92,6 +103,27 @@ Item {
return focusedWs ? focusedWs.num : 1
}
function getHyprlandWorkspaces() {
const workspaces = Hyprland.workspaces?.values || []
if (workspaces.length === 0) return [{id: 1}]
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
return workspaces.slice().sort((a, b) => a.id - b.id)
}
const monitorWorkspaces = workspaces.filter(ws => ws.monitor?.name === root.screenName)
return monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.id - b.id) : [{id: 1}]
}
function getHyprlandActiveWorkspace() {
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
return Hyprland.focusedWorkspace?.id || 1
}
const monitor = Hyprland.monitors?.values?.find(m => m.name === root.screenName)
return monitor?.activeWorkspace?.id || 1
}
function getWorkspaceIcons(ws) {
_desktopEntriesUpdateTrigger
if (!SettingsData.showWorkspaceApps || !ws) {
@@ -192,7 +224,9 @@ Item {
function padWorkspaces(list) {
const padded = list.slice()
let placeholder
if (CompositorService.isHyprland) {
if (useExtWorkspace) {
placeholder = {"id": "", "name": "", "active": false, "hidden": true}
} else if (CompositorService.isHyprland) {
placeholder = {"id": -1, "name": ""}
} else if (CompositorService.isDwl) {
placeholder = {"tag": -1}
@@ -233,51 +267,6 @@ Item {
return activeWs ? activeWs.idx + 1 : 1
}
function getHyprlandWorkspaces() {
const workspaces = Hyprland.workspaces?.values || []
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
// Show all workspaces on all monitors if per-monitor filtering is disabled
const sorted = workspaces.slice().sort((a, b) => a.id - b.id)
return sorted.length > 0 ? sorted : [{
"id": 1,
"name": "1"
}]
}
// Filter workspaces for this specific monitor using lastIpcObject.monitor
// This matches the approach from the original kyle-config
const monitorWorkspaces = workspaces.filter(ws => {
return ws.lastIpcObject && ws.lastIpcObject.monitor === root.screenName
})
if (monitorWorkspaces.length === 0) {
// Fallback if no workspaces exist for this monitor
return [{
"id": 1,
"name": "1"
}]
}
// Return all workspaces for this monitor, sorted by ID
return monitorWorkspaces.sort((a, b) => a.id - b.id)
}
function getHyprlandActiveWorkspace() {
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
return Hyprland.focusedWorkspace ? Hyprland.focusedWorkspace.id : 1
}
const monitors = Hyprland.monitors?.values || []
const currentMonitor = monitors.find(monitor => monitor.name === root.screenName)
if (!currentMonitor) {
return 1
}
return currentMonitor.activeWorkspace?.id ?? 1
}
function getDwlTags() {
if (!DwlService.dwlAvailable) {
return []
@@ -313,25 +302,77 @@ Item {
return activeTags
}
function getExtWorkspaceWorkspaces() {
const groups = ExtWorkspaceService.groups
if (!ExtWorkspaceService.extWorkspaceAvailable || groups.length === 0) {
return [{"id": "1", "name": "1", "active": false}]
}
const group = groups.find(g => g.outputs && g.outputs.includes(root.screenName))
if (!group || !group.workspaces) {
return [{"id": "1", "name": "1", "active": false}]
}
const visible = group.workspaces.filter(ws => !ws.hidden).sort((a, b) => {
const coordsA = a.coordinates || [0, 0]
const coordsB = b.coordinates || [0, 0]
if (coordsA[0] !== coordsB[0]) return coordsA[0] - coordsB[0]
return coordsA[1] - coordsB[1]
}).map(ws => ({
id: ws.id,
name: ws.name,
coordinates: ws.coordinates,
state: ws.state,
active: ws.active,
urgent: ws.urgent,
hidden: ws.hidden,
groupID: group.id
}))
return visible.length > 0 ? visible : [{"id": "1", "name": "1", "active": false}]
}
function getExtWorkspaceActiveWorkspace() {
if (!ExtWorkspaceService.extWorkspaceAvailable) {
return 1
}
const activeWs = ExtWorkspaceService.getActiveWorkspaceForOutput(root.screenName)
return activeWs ? (activeWs.id || activeWs.name || "1") : "1"
}
readonly property real padding: Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
readonly property real visualWidth: isVertical ? widgetHeight : (workspaceRow.implicitWidth + padding * 2)
readonly property real visualHeight: isVertical ? (workspaceRow.implicitHeight + padding * 2) : widgetHeight
function getRealWorkspaces() {
return root.workspaceList.filter(ws => {
if (CompositorService.isHyprland) {
return ws && ws.id !== -1
} else if (CompositorService.isDwl) {
return ws && ws.tag !== -1
} else if (CompositorService.isSway) {
return ws && ws.num !== -1
}
if (useExtWorkspace) return ws && ws.id !== "" && !ws.hidden
if (CompositorService.isHyprland) return ws && ws.id !== -1
if (CompositorService.isDwl) return ws && ws.tag !== -1
if (CompositorService.isSway) return ws && ws.num !== -1
return ws !== -1
})
}
function switchWorkspace(direction) {
if (CompositorService.isNiri) {
if (useExtWorkspace) {
const realWorkspaces = getRealWorkspaces()
if (realWorkspaces.length < 2) {
return
}
const currentIndex = realWorkspaces.findIndex(ws => (ws.id || ws.name) === root.currentWorkspace)
const validIndex = currentIndex === -1 ? 0 : currentIndex
const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0)
if (nextIndex === validIndex) {
return
}
const nextWorkspace = realWorkspaces[nextIndex]
ExtWorkspaceService.activateWorkspace(nextWorkspace.id || nextWorkspace.name, nextWorkspace.groupID || "")
} else if (CompositorService.isNiri) {
const realWorkspaces = getRealWorkspaces()
if (realWorkspaces.length < 2) {
return
@@ -396,7 +437,7 @@ Item {
width: isVertical ? barThickness : visualWidth
height: isVertical ? visualHeight : barThickness
visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway
visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || useExtWorkspace
Rectangle {
id: visualBackground
@@ -443,23 +484,17 @@ Item {
id: delegateRoot
property bool isActive: {
if (CompositorService.isHyprland) {
return modelData && modelData.id === root.currentWorkspace
} else if (CompositorService.isDwl) {
return modelData && root.dwlActiveTags.includes(modelData.tag)
} else if (CompositorService.isSway) {
return modelData && modelData.num === root.currentWorkspace
}
if (root.useExtWorkspace) return (modelData?.id || modelData?.name) === root.currentWorkspace
if (CompositorService.isHyprland) return !!(modelData && modelData.id === root.currentWorkspace)
if (CompositorService.isDwl) return !!(modelData && root.dwlActiveTags.includes(modelData.tag))
if (CompositorService.isSway) return !!(modelData && modelData.num === root.currentWorkspace)
return modelData === root.currentWorkspace
}
property bool isPlaceholder: {
if (CompositorService.isHyprland) {
return modelData && modelData.id === -1
} else if (CompositorService.isDwl) {
return modelData && modelData.tag === -1
} else if (CompositorService.isSway) {
return modelData && modelData.num === -1
}
if (root.useExtWorkspace) return !!(modelData && modelData.hidden)
if (CompositorService.isHyprland) return !!(modelData && modelData.id === -1)
if (CompositorService.isDwl) return !!(modelData && modelData.tag === -1)
if (CompositorService.isSway) return !!(modelData && modelData.num === -1)
return modelData === -1
}
property bool isHovered: mouseArea.containsMouse
@@ -467,15 +502,11 @@ Item {
property var loadedWorkspaceData: null
property bool loadedIsUrgent: false
property bool isUrgent: {
if (CompositorService.isHyprland) {
return modelData?.urgent ?? false
} else if (CompositorService.isNiri) {
return loadedIsUrgent
} else if (CompositorService.isDwl) {
return modelData?.state === 2
} else if (CompositorService.isSway) {
return loadedIsUrgent
}
if (root.useExtWorkspace) return modelData?.urgent ?? false
if (CompositorService.isHyprland) return modelData?.urgent ?? false
if (CompositorService.isNiri) return loadedIsUrgent
if (CompositorService.isDwl) return modelData?.state === 2
if (CompositorService.isSway) return loadedIsUrgent
return false
}
property var loadedIconData: null
@@ -511,13 +542,13 @@ Item {
enabled: !isPlaceholder
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: mouse => {
if (isPlaceholder) {
return
}
if (isPlaceholder) return
const isRightClick = mouse.button === Qt.RightButton
if (CompositorService.isNiri) {
if (root.useExtWorkspace && (modelData?.id || modelData?.name)) {
ExtWorkspaceService.activateWorkspace(modelData.id || modelData.name, modelData.groupID || "")
} else if (CompositorService.isNiri) {
if (isRightClick) {
NiriService.toggleOverview()
} else {
@@ -558,7 +589,9 @@ Item {
}
var wsData = null;
if (CompositorService.isNiri) {
if (root.useExtWorkspace) {
wsData = modelData;
} else if (CompositorService.isNiri) {
wsData = NiriService.allWorkspaces.find(ws => ws.idx + 1 === modelData && ws.output === root.screenName) || null;
} else if (CompositorService.isHyprland) {
wsData = modelData;
@@ -839,7 +872,9 @@ Item {
anchors.centerIn: parent
text: {
let isPlaceholder
if (CompositorService.isHyprland) {
if (root.useExtWorkspace) {
isPlaceholder = modelData?.hidden === true
} else if (CompositorService.isHyprland) {
isPlaceholder = modelData?.id === -1
} else if (CompositorService.isDwl) {
isPlaceholder = modelData?.tag === -1
@@ -849,17 +884,12 @@ Item {
isPlaceholder = modelData === -1
}
if (isPlaceholder) {
return index + 1
}
if (isPlaceholder) return index + 1
if (CompositorService.isHyprland) {
return modelData?.id || ""
} else if (CompositorService.isDwl) {
return (modelData?.tag !== undefined) ? (modelData.tag + 1) : ""
} else if (CompositorService.isSway) {
return modelData?.num || ""
}
if (root.useExtWorkspace) return modelData?.name || modelData?.id || ""
if (CompositorService.isHyprland) return modelData?.id || ""
if (CompositorService.isDwl) return (modelData?.tag !== undefined) ? (modelData.tag + 1) : ""
if (CompositorService.isSway) return modelData?.num || ""
return modelData - 1
}
color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium
@@ -893,12 +923,28 @@ Item {
enabled: CompositorService.isDwl
function onStateChanged() { delegateRoot.updateAllData() }
}
Connections {
target: Hyprland.workspaces
enabled: CompositorService.isHyprland
function onValuesChanged() { delegateRoot.updateAllData() }
}
Connections {
target: I3.workspaces
enabled: CompositorService.isSway
function onValuesChanged() { delegateRoot.updateAllData() }
}
Connections {
target: ExtWorkspaceService
enabled: root.useExtWorkspace
function onStateChanged() { delegateRoot.updateAllData() }
}
}
}
}
Component.onCompleted: {
if (useExtWorkspace && !DMSService.activeSubscriptions.includes("extworkspace")) {
DMSService.addSubscription("extworkspace")
}
}
}

View File

@@ -339,7 +339,7 @@ Variants {
}
}
Rectangle {
Item {
id: dockBackground
objectName: "dockBackground"
anchors {
@@ -360,16 +360,13 @@ Variants {
width: implicitWidth
height: implicitHeight
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, backgroundTransparency)
radius: Theme.cornerRadius
border.width: 1
border.color: Theme.outlineMedium
layer.enabled: true
clip: false
Rectangle {
DankRectangle {
anchors.fill: parent
color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04)
radius: parent.radius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, backgroundTransparency)
overlayColor: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04)
}
}

View File

@@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Wayland
import Quickshell.Hyprland
import Quickshell.Widgets
import qs.Common
import qs.Services
@@ -91,56 +92,11 @@ Item {
}
function getToplevelObject() {
if (!appData) {
return null
}
const sortedToplevels = CompositorService.sortedToplevels
if (!sortedToplevels) {
return null
}
if (appData.type === "window") {
if (appData.uniqueId) {
for (var i = 0; i < sortedToplevels.length; i++) {
const toplevel = sortedToplevels[i]
const checkId = toplevel.title + "|" + (toplevel.appId || "") + "|" + i
if (checkId === appData.uniqueId) {
return toplevel
}
}
}
if (appData.windowId !== undefined && appData.windowId !== null && appData.windowId >= 0) {
if (appData.windowId < sortedToplevels.length) {
return sortedToplevels[appData.windowId]
}
}
} else if (appData.type === "grouped") {
if (appData.windowId !== undefined && appData.windowId !== null && appData.windowId >= 0) {
if (appData.windowId < sortedToplevels.length) {
return sortedToplevels[appData.windowId]
}
}
}
return null
return appData?.toplevel || null
}
function getGroupedToplevels() {
if (!appData || appData.type !== "grouped") {
return []
}
const toplevels = []
const allToplevels = ToplevelManager.toplevels.values
for (let i = 0; i < allToplevels.length; i++) {
const toplevel = allToplevels[i]
if (toplevel.appId === appData.appId) {
toplevels.push(toplevel)
}
}
return toplevels
return appData?.allWindows?.map(w => w.toplevel).filter(t => t !== null) || []
}
onIsHoveredChanged: {
if (mouseArea.pressed) return
@@ -325,17 +281,9 @@ Item {
}
}
} else if (mouse.button === Qt.MiddleButton) {
if (appData && appData.type === "window") {
const sortedToplevels = CompositorService.sortedToplevels
for (var i = 0; i < sortedToplevels.length; i++) {
const toplevel = sortedToplevels[i]
const checkId = toplevel.title + "|" + (toplevel.appId || "") + "|" + i
if (checkId === appData.uniqueId) {
toplevel.close()
break
}
}
} else if (appData && appData.type === "grouped") {
if (appData?.type === "window") {
appData?.toplevel?.close()
} else if (appData?.type === "grouped") {
if (contextMenu) {
contextMenu.showForButton(root, appData, root.height, false, cachedDesktopEntry, parentDockScreen)
}

View File

@@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Wayland
import Quickshell.Hyprland
import qs.Common
import qs.Services
import qs.Widgets
@@ -54,158 +55,149 @@ Item {
Repeater {
id: repeater
model: ListModel {
id: dockModel
Component.onCompleted: updateModel()
property var dockItems: []
function updateModel() {
clear()
model: ScriptModel {
values: repeater.dockItems
objectProp: "uniqueKey"
}
const items = []
const pinnedApps = [...(SessionData.pinnedApps || [])]
const sortedToplevels = CompositorService.sortedToplevels
Component.onCompleted: updateModel()
if (root.groupByApp) {
// Group windows by appId
const appGroups = new Map()
function updateModel() {
const items = []
const pinnedApps = [...(SessionData.pinnedApps || [])]
const sortedToplevels = CompositorService.sortedToplevels
// Add pinned apps first (even if they have no windows)
pinnedApps.forEach(appId => {
if (root.groupByApp) {
const appGroups = new Map()
pinnedApps.forEach(appId => {
appGroups.set(appId, {
appId: appId,
isPinned: true,
windows: []
})
})
sortedToplevels.forEach((toplevel, index) => {
const appId = toplevel.appId || "unknown"
if (!appGroups.has(appId)) {
appGroups.set(appId, {
appId: appId,
isPinned: true,
isPinned: false,
windows: []
})
})
// Group all running windows by appId
sortedToplevels.forEach((toplevel, index) => {
const appId = toplevel.appId || "unknown"
if (!appGroups.has(appId)) {
appGroups.set(appId, {
appId: appId,
isPinned: false,
windows: []
})
}
const title = toplevel.title || "(Unnamed)"
const truncatedTitle = title.length > 50 ? title.substring(0, 47) + "..." : title
const uniqueId = toplevel.title + "|" + (toplevel.appId || "") + "|" + index
appGroups.get(appId).windows.push({
windowId: index,
windowTitle: truncatedTitle,
uniqueId: uniqueId
})
})
// Sort groups: pinned first, then unpinned
const pinnedGroups = []
const unpinnedGroups = []
Array.from(appGroups.entries()).forEach(([appId, group]) => {
// For grouped apps, just show the first window info but track all windows
const firstWindow = group.windows.length > 0 ? group.windows[0] : null
const item = {
"type": "grouped",
"appId": appId,
"windowId": firstWindow ? firstWindow.windowId : -1,
"windowTitle": firstWindow ? firstWindow.windowTitle : "",
"workspaceId": -1,
"isPinned": group.isPinned,
"isRunning": group.windows.length > 0,
"windowCount": group.windows.length,
"uniqueId": firstWindow ? firstWindow.uniqueId : "",
"allWindows": group.windows
}
if (group.isPinned) {
pinnedGroups.push(item)
} else {
unpinnedGroups.push(item)
}
})
// Add items in order
pinnedGroups.forEach(item => items.push(item))
// Add separator if needed
if (pinnedGroups.length > 0 && unpinnedGroups.length > 0) {
items.push({
"type": "separator",
"appId": "__SEPARATOR__",
"windowId": -1,
"windowTitle": "",
"workspaceId": -1,
"isPinned": false,
"isRunning": false
})
}
unpinnedGroups.forEach(item => items.push(item))
root.pinnedAppCount = pinnedGroups.length
} else {
pinnedApps.forEach(appId => {
items.push({
"type": "pinned",
"appId": appId,
"windowId": -1,
"windowTitle": "",
"workspaceId": -1,
"isPinned": true,
"isRunning": false
})
appGroups.get(appId).windows.push({
toplevel: toplevel,
index: index
})
})
root.pinnedAppCount = pinnedApps.length
const pinnedGroups = []
const unpinnedGroups = []
if (pinnedApps.length > 0 && sortedToplevels.length > 0) {
items.push({
"type": "separator",
"appId": "__SEPARATOR__",
"windowId": -1,
"windowTitle": "",
"workspaceId": -1,
"isPinned": false,
"isRunning": false,
"isFocused": false
})
Array.from(appGroups.entries()).forEach(([appId, group]) => {
const firstWindow = group.windows.length > 0 ? group.windows[0] : null
const item = {
uniqueKey: "grouped_" + appId,
type: "grouped",
appId: appId,
toplevel: firstWindow ? firstWindow.toplevel : null,
isPinned: group.isPinned,
isRunning: group.windows.length > 0,
windowCount: group.windows.length,
allWindows: group.windows
}
sortedToplevels.forEach((toplevel, index) => {
const title = toplevel.title || "(Unnamed)"
const truncatedTitle = title.length > 50 ? title.substring(0, 47) + "..." : title
const uniqueId = toplevel.title + "|" + (toplevel.appId || "") + "|" + index
if (group.isPinned) {
pinnedGroups.push(item)
} else {
unpinnedGroups.push(item)
}
})
items.push({
"type": "window",
"appId": toplevel.appId,
"windowId": index,
"windowTitle": truncatedTitle,
"workspaceId": -1,
"isPinned": false,
"isRunning": true,
"uniqueId": uniqueId
})
pinnedGroups.forEach(item => items.push(item))
if (pinnedGroups.length > 0 && unpinnedGroups.length > 0) {
items.push({
uniqueKey: "separator_grouped",
type: "separator",
appId: "__SEPARATOR__",
toplevel: null,
isPinned: false,
isRunning: false
})
}
items.forEach(item => append(item))
unpinnedGroups.forEach(item => items.push(item))
root.pinnedAppCount = pinnedGroups.length
} else {
pinnedApps.forEach(appId => {
items.push({
uniqueKey: "pinned_" + appId,
type: "pinned",
appId: appId,
toplevel: null,
isPinned: true,
isRunning: false
})
})
root.pinnedAppCount = pinnedApps.length
if (pinnedApps.length > 0 && sortedToplevels.length > 0) {
items.push({
uniqueKey: "separator_ungrouped",
type: "separator",
appId: "__SEPARATOR__",
toplevel: null,
isPinned: false,
isRunning: false
})
}
sortedToplevels.forEach((toplevel, index) => {
let uniqueKey = "window_" + index
if (CompositorService.isHyprland && Hyprland.toplevels) {
const hyprlandToplevels = Array.from(Hyprland.toplevels.values)
for (let i = 0; i < hyprlandToplevels.length; i++) {
if (hyprlandToplevels[i].wayland === toplevel) {
uniqueKey = "window_" + hyprlandToplevels[i].address
break
}
}
}
items.push({
uniqueKey: uniqueKey,
type: "window",
appId: toplevel.appId,
toplevel: toplevel,
isPinned: false,
isRunning: true
})
})
}
dockItems = items
}
delegate: Item {
id: delegateItem
property alias dockButton: button
property var itemData: modelData
clip: false
width: model.type === "separator" ? (root.isVertical ? root.iconSize : 8) : (root.isVertical ? root.iconSize : root.iconSize * 1.2)
height: model.type === "separator" ? (root.isVertical ? 8 : root.iconSize) : (root.isVertical ? root.iconSize * 1.2 : root.iconSize)
width: itemData.type === "separator" ? (root.isVertical ? root.iconSize : 8) : (root.isVertical ? root.iconSize : root.iconSize * 1.2)
height: itemData.type === "separator" ? (root.isVertical ? 8 : root.iconSize) : (root.isVertical ? root.iconSize * 1.2 : root.iconSize)
Rectangle {
visible: model.type === "separator"
visible: itemData.type === "separator"
width: root.isVertical ? root.iconSize * 0.5 : 2
height: root.isVertical ? 2 : root.iconSize * 0.5
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
@@ -215,21 +207,24 @@ Item {
DockAppButton {
id: button
visible: model.type !== "separator"
visible: itemData.type !== "separator"
anchors.centerIn: parent
width: delegateItem.width
height: delegateItem.height
actualIconSize: root.iconSize
appData: model
appData: itemData
contextMenu: root.contextMenu
dockApps: root
index: model.index
parentDockScreen: root.dockScreen
showWindowTitle: model.type === "window" || model.type === "grouped"
windowTitle: model.windowTitle || ""
showWindowTitle: itemData?.type === "window" || itemData?.type === "grouped"
windowTitle: {
const title = itemData?.toplevel?.title || "(Unnamed)"
return title.length > 50 ? title.substring(0, 47) + "..." : title
}
}
}
}
@@ -239,18 +234,18 @@ Item {
Connections {
target: CompositorService
function onToplevelsChanged() {
dockModel.updateModel()
repeater.updateModel()
}
}
Connections {
target: SessionData
function onPinnedAppsChanged() {
dockModel.updateModel()
repeater.updateModel()
}
}
onGroupByAppChanged: {
dockModel.updateModel()
repeater.updateModel()
}
}

View File

@@ -1,6 +1,7 @@
import QtQuick
import Quickshell
import Quickshell.Wayland
import Quickshell.Hyprland
import Quickshell.Widgets
import qs.Common
import qs.Services
@@ -9,6 +10,8 @@ import qs.Widgets
PanelWindow {
id: root
WlrLayershell.namespace: "dms:dock-context-menu"
property var appData: null
property var anchorItem: null
property real dockVisibleHeight: 40
@@ -475,24 +478,10 @@ PanelWindow {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
const sortedToplevels = CompositorService.sortedToplevels
if (root.appData && root.appData.type === "window") {
for (var i = 0; i < sortedToplevels.length; i++) {
const toplevel = sortedToplevels[i]
const checkId = toplevel.title + "|" + (toplevel.appId || "") + "|" + i
if (checkId === root.appData.uniqueId) {
toplevel.close()
break
}
}
} else if (root.appData && root.appData.type === "grouped") {
const allToplevels = ToplevelManager.toplevels.values
for (let i = 0; i < allToplevels.length; i++) {
const toplevel = allToplevels[i]
if (toplevel.appId === root.appData.appId) {
toplevel.close()
}
}
if (root.appData?.type === "window") {
root.appData?.toplevel?.close()
} else if (root.appData?.type === "grouped") {
root.appData?.allWindows?.forEach(window => window.toplevel?.close())
}
root.close()
}

View File

@@ -1,4 +1,4 @@
pragma ComponentBehavior
pragma ComponentBehavior: Bound
import QtQuick

View File

@@ -34,7 +34,6 @@ Rectangle {
}
radius: Theme.cornerRadius
Behavior on border.color {
ColorAnimation {
duration: Theme.shortDuration
@@ -266,6 +265,7 @@ Rectangle {
Column {
id: expandedContent
objectName: "expandedContent"
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
@@ -321,6 +321,8 @@ Rectangle {
spacing: 16
Repeater {
id: notificationRepeater
objectName: "notificationRepeater"
model: ScriptModel {
values: notificationGroup?.notifications?.slice(0, 10) || []
}
@@ -348,7 +350,6 @@ Rectangle {
border.color: isSelected ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.4) : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05)
border.width: isSelected ? 1 : 1
Behavior on border.color {
ColorAnimation {
duration: Theme.shortDuration

View File

@@ -28,7 +28,7 @@ QtObject {
const nav = []
const groups = NotificationService.groupedNotifications
for (let i = 0; i < groups.length; i++) {
for (var i = 0; i < groups.length; i++) {
const group = groups[i]
const isExpanded = NotificationService.expandedGroups[group.key] || false
@@ -42,7 +42,8 @@ QtObject {
if (isExpanded) {
const notifications = group.notifications || []
for (let j = 0; j < notifications.length; j++) {
const maxNotifications = Math.min(notifications.length, 10)
for (var j = 0; j < maxNotifications; j++) {
const notifId = String(notifications[j] && notifications[j].notification && notifications[j].notification.id ? notifications[j].notification.id : "")
nav.push({
"type": "notification",
@@ -65,7 +66,7 @@ QtObject {
return
}
for (let i = 0; i < flatNavigation.length; i++) {
for (var i = 0; i < flatNavigation.length; i++) {
const item = flatNavigation[i]
if (selectedItemType === "group" && item.type === "group" && item.groupKey === selectedGroupKey) {
@@ -81,7 +82,7 @@ QtObject {
// If not found, try to find the same group but select the group header instead
if (selectedItemType === "notification") {
for (let j = 0; j < flatNavigation.length; j++) {
for (var j = 0; j < flatNavigation.length; j++) {
const groupItem = flatNavigation[j]
if (groupItem.type === "group" && groupItem.groupKey === selectedGroupKey) {
selectedFlatIndex = j
@@ -195,7 +196,7 @@ QtObject {
// Smart selection after toggle
if (!wasExpanded) {
// Just expanded - move to first notification in the group
for (let i = 0; i < flatNavigation.length; i++) {
for (var i = 0; i < flatNavigation.length; i++) {
if (flatNavigation[i].type === "notification" && flatNavigation[i].groupIndex === groupIndex) {
selectedFlatIndex = i
break
@@ -203,7 +204,7 @@ QtObject {
}
} else {
// Just collapsed - stay on the group header
for (let i = 0; i < flatNavigation.length; i++) {
for (var i = 0; i < flatNavigation.length; i++) {
if (flatNavigation[i].type === "group" && flatNavigation[i].groupIndex === groupIndex) {
selectedFlatIndex = i
break
@@ -319,6 +320,23 @@ QtObject {
}
}
function findRepeater(parent) {
if (!parent || !parent.children) {
return null
}
for (var i = 0; i < parent.children.length; i++) {
const child = parent.children[i]
if (child.objectName === "notificationRepeater") {
return child
}
const found = findRepeater(child)
if (found) {
return found
}
}
return null
}
function ensureVisible() {
if (flatNavigation.length === 0 || selectedFlatIndex >= flatNavigation.length || !listView)
return
@@ -326,17 +344,34 @@ QtObject {
const currentItem = flatNavigation[selectedFlatIndex]
if (keyboardNavigationActive && currentItem && currentItem.groupIndex >= 0) {
// Always center the selected item for better visibility
// This ensures the selected item stays in view even when new notifications arrive
if (currentItem.type === "notification") {
// For individual notifications, center on the group but bias towards the notification
listView.positionViewAtIndex(currentItem.groupIndex, ListView.Center)
const groupDelegate = listView.itemAtIndex(currentItem.groupIndex)
if (groupDelegate && groupDelegate.children && groupDelegate.children.length > 0) {
const notificationCard = groupDelegate.children[0]
const repeater = findRepeater(notificationCard)
if (repeater && currentItem.notificationIndex < repeater.count) {
const notificationItem = repeater.itemAt(currentItem.notificationIndex)
if (notificationItem) {
const itemPos = notificationItem.mapToItem(listView.contentItem, 0, 0)
const itemY = itemPos.y
const itemHeight = notificationItem.height
const viewportTop = listView.contentY
const viewportBottom = listView.contentY + listView.height
if (itemY < viewportTop) {
listView.contentY = itemY - 20
} else if (itemY + itemHeight > viewportBottom) {
listView.contentY = itemY + itemHeight - listView.height + 20
}
}
}
}
} else {
// For group headers, center on the group
listView.positionViewAtIndex(currentItem.groupIndex, ListView.Center)
listView.positionViewAtIndex(currentItem.groupIndex, ListView.Contain)
}
// Force immediate update
listView.forceLayout()
}
}

View File

@@ -1,6 +1,7 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import QtQuick.Shapes
import Quickshell
import Quickshell.Wayland
import Quickshell.Widgets
@@ -63,6 +64,20 @@ PanelWindow {
visible: hasValidData
WlrLayershell.layer: {
const envLayer = Quickshell.env("DMS_NOTIFICATION_LAYER")
if (envLayer) {
switch (envLayer) {
case "bottom":
return WlrLayershell.Bottom
case "overlay":
return WlrLayershell.Overlay
case "background":
return WlrLayershell.Background
case "top":
return WlrLayershell.Top
}
}
if (!notificationData)
return WlrLayershell.Top
@@ -198,65 +213,81 @@ PanelWindow {
return Theme.popupDistance
}
readonly property real dpr: CompositorService.getScreenScale(win.screen)
readonly property real alignedWidth: Theme.px(implicitWidth, dpr)
readonly property real alignedHeight: Theme.px(implicitHeight, dpr)
Item {
id: content
anchors.fill: parent
x: Theme.snap((win.width - alignedWidth) / 2, dpr)
y: Theme.snap((win.height - alignedHeight) / 2, dpr)
width: alignedWidth
height: alignedHeight
visible: win.hasValidData
layer.enabled: true
layer.smooth: true
Rectangle {
property var shadowLayers: [shadowLayer1, shadowLayer2, shadowLayer3]
property real shadowBlurPx: 10
property real shadowSpreadPx: 0
property real shadowBaseAlpha: 0.60
readonly property real popupSurfaceAlpha: SettingsData.popupTransparency
readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha))
Item {
id: bgShadowLayer
anchors.fill: parent
anchors.margins: 4
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
border.color: notificationData && notificationData.urgency === NotificationUrgency.Critical ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: notificationData && notificationData.urgency === NotificationUrgency.Critical ? 2 : 0
clip: true
anchors.margins: Theme.snap(4, win.dpr)
layer.enabled: true
layer.smooth: false
layer.textureSize: Qt.size(Math.round(width * win.dpr), Math.round(height * win.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically
Rectangle {
id: shadowLayer1
anchors.fill: parent
anchors.margins: -3
color: "transparent"
radius: parent.radius + 3
border.color: Qt.rgba(0, 0, 0, 0.05)
border.width: 1
z: -3
layer.effect: MultiEffect {
id: shadowFx
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
property int blurMax: 64
shadowBlur: Math.max(0, Math.min(1, content.shadowBlurPx / blurMax))
shadowScale: 1 + (2 * content.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: Qt.rgba(0, 0, 0, content.effectiveShadowAlpha)
}
Rectangle {
id: shadowLayer2
Shape {
id: backgroundShape
anchors.fill: parent
anchors.margins: -2
color: "transparent"
radius: parent.radius + 2
border.color: Qt.rgba(0, 0, 0, 0.08)
border.width: 1
z: -2
}
preferredRendererType: Shape.CurveRenderer
Rectangle {
id: shadowLayer3
readonly property real radius: Theme.cornerRadius
readonly property color fillColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
readonly property color strokeColor: notificationData && notificationData.urgency === NotificationUrgency.Critical ? Theme.withAlpha(Theme.primary, 0.3) : Theme.withAlpha(Theme.outline, 0.08)
readonly property real strokeWidth: notificationData && notificationData.urgency === NotificationUrgency.Critical ? 2 : 0
anchors.fill: parent
color: "transparent"
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
border.width: 1
radius: parent.radius
z: -1
ShapePath {
fillColor: backgroundShape.fillColor
strokeColor: backgroundShape.strokeColor
strokeWidth: backgroundShape.strokeWidth
startX: backgroundShape.radius
startY: 0
PathLine { x: backgroundShape.width - backgroundShape.radius; y: 0 }
PathQuad { x: backgroundShape.width; y: backgroundShape.radius; controlX: backgroundShape.width; controlY: 0 }
PathLine { x: backgroundShape.width; y: backgroundShape.height - backgroundShape.radius }
PathQuad { x: backgroundShape.width - backgroundShape.radius; y: backgroundShape.height; controlX: backgroundShape.width; controlY: backgroundShape.height }
PathLine { x: backgroundShape.radius; y: backgroundShape.height }
PathQuad { x: 0; y: backgroundShape.height - backgroundShape.radius; controlX: 0; controlY: backgroundShape.height }
PathLine { x: 0; y: backgroundShape.radius }
PathQuad { x: backgroundShape.radius; y: 0; controlX: 0; controlY: 0 }
}
}
Rectangle {
anchors.fill: parent
radius: parent.radius
radius: backgroundShape.radius
visible: notificationData && notificationData.urgency === NotificationUrgency.Critical
opacity: 1
clip: true
gradient: Gradient {
orientation: Gradient.Horizontal
@@ -277,6 +308,13 @@ PanelWindow {
}
}
}
}
Item {
id: backgroundContainer
anchors.fill: parent
anchors.margins: Theme.snap(4, win.dpr)
clip: true
Item {
id: notificationContent

View File

@@ -13,11 +13,13 @@ Item {
property bool isNiri: CompositorService.isNiri
property bool isSway: CompositorService.isSway
property bool isDwl: CompositorService.isDwl
property bool isLabwc: CompositorService.isLabwc
property string compositorName: {
if (isHyprland) return "hyprland"
if (isSway) return "sway"
if (isDwl) return "mangowc"
if (isLabwc) return "labwc"
return "niri"
}
@@ -25,6 +27,7 @@ Item {
if (isHyprland) return "/assets/hyprland.svg"
if (isSway) return "/assets/sway.svg"
if (isDwl) return "/assets/mango.png"
if (isLabwc) return "/assets/labwc.png"
return "/assets/niri.svg"
}
@@ -32,6 +35,7 @@ Item {
if (isHyprland) return "https://hypr.land"
if (isSway) return "https://swaywm.org"
if (isDwl) return "https://github.com/DreamMaoMao/mangowc"
if (isLabwc) return "https://labwc.github.io/"
return "https://github.com/YaLTeR/niri"
}
@@ -39,6 +43,7 @@ Item {
if (isHyprland) return "Hyprland Website"
if (isSway) return "Sway Website"
if (isDwl) return "mangowc GitHub"
if (isLabwc) return "LabWC Website"
return "niri GitHub"
}
@@ -60,9 +65,13 @@ Item {
property string redditUrl: "https://reddit.com/r/niri"
property string redditTooltip: "r/niri Subreddit"
property bool showMatrix: isNiri && !isHyprland && !isSway && !isDwl
property string ircUrl: "https://web.libera.chat/gamja/?channels=#labwc"
property string ircTooltip: "LabWC IRC Channel"
property bool showMatrix: isNiri && !isHyprland && !isSway && !isDwl && !isLabwc
property bool showCompositorDiscord: isHyprland || isDwl
property bool showReddit: isNiri && !isHyprland && !isSway && !isDwl
property bool showReddit: isNiri && !isHyprland && !isSway && !isDwl && !isLabwc
property bool showIrc: isLabwc
DankFlickable {
anchors.fill: parent
@@ -153,6 +162,9 @@ Item {
if (showMatrix) {
baseWidth += matrixButton.width + 4
}
if (showIrc) {
baseWidth += ircButton.width + Theme.spacingM
}
if (showCompositorDiscord) {
baseWidth += compositorDiscordButton.width + Theme.spacingM
}
@@ -232,11 +244,43 @@ Item {
}
}
Item {
id: ircButton
width: 24
height: 24
x: compositorButton.x + compositorButton.width + Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
visible: showIrc
property bool hovered: false
property string tooltipText: ircTooltip
DankIcon {
anchors.centerIn: parent
name: "forum"
size: 20
color: Theme.surfaceText
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onEntered: parent.hovered = true
onExited: parent.hovered = false
onClicked: Qt.openUrlExternally(ircUrl)
}
}
Item {
id: dmsDiscordButton
width: 20
height: 20
x: showMatrix ? matrixButton.x + matrixButton.width + Theme.spacingM : compositorButton.x + compositorButton.width + Theme.spacingM
x: {
if (showMatrix) return matrixButton.x + matrixButton.width + Theme.spacingM
if (showIrc) return ircButton.x + ircButton.width + Theme.spacingM
return compositorButton.x + compositorButton.width + Theme.spacingM
}
anchors.verticalCenter: parent.verticalCenter
property bool hovered: false
@@ -618,6 +662,7 @@ Item {
property var hoveredButton: {
if (compositorButton.hovered) return compositorButton
if (matrixButton.visible && matrixButton.hovered) return matrixButton
if (ircButton.visible && ircButton.hovered) return ircButton
if (dmsDiscordButton.hovered) return dmsDiscordButton
if (compositorDiscordButton.visible && compositorDiscordButton.hovered) return compositorDiscordButton
if (redditButton.visible && redditButton.hovered) return redditButton

View File

@@ -110,6 +110,11 @@ DankModal {
parentModal.shouldHaveFocus = Qt.binding(() => {
return parentModal.shouldBeVisible
})
Qt.callLater(() => {
if (parentModal.modalFocusScope) {
parentModal.modalFocusScope.forceActiveFocus()
}
})
}
}
@@ -117,6 +122,17 @@ DankModal {
refreshPlugins()
}
Connections {
target: contentLoader
function onLoaded() {
Qt.callLater(() => {
if (contentLoader.item && contentLoader.item.searchField) {
contentLoader.item.searchField.forceActiveFocus()
}
})
}
}
onDialogClosed: () => {
allPlugins = []
searchQuery = ""
@@ -138,6 +154,10 @@ DankModal {
anchors.fill: parent
focus: true
Component.onCompleted: {
browserSearchField.forceActiveFocus()
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Escape) {
root.close()

View File

@@ -81,8 +81,9 @@ Item {
text: I18n.tr("Show Workspace Apps")
description: I18n.tr("Display application icons in workspace indicators")
checked: SettingsData.showWorkspaceApps
visible: CompositorService.isNiri || CompositorService.isHyprland
onToggled: checked => {
return SettingsData.set("showWorkspaceApps",
return SettingsData.set("showWorkspaceApps",
checked)
}
}
@@ -355,6 +356,7 @@ Item {
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 0
visible: CompositorService.isNiri || CompositorService.isHyprland
Column {
id: runningAppsSection

View File

@@ -11,6 +11,8 @@ import qs.Widgets
PanelWindow {
id: root
WlrLayershell.namespace: "dms:toast"
property var modelData
property bool shouldBeVisible: false
property real frozenWidth: 0

View File

@@ -100,7 +100,7 @@ Endless customization with the [plugin registry](https://plugins.danklinux.com).
## Supported Compositors
DankMaterialShell works best with **[niri](https://github.com/YaLTeR/niri)**, **[Hyprland](https://hyprland.org/)**, **[sway](https://swaywm.org/)**, and **[dwl/MangoWC](https://github.com/DreamMaoMao/mangowc)** - with full workspace switching, overview integration, and monitor management.
DankMaterialShell works best with **[niri](https://github.com/YaLTeR/niri)**, **[Hyprland](https://hyprland.org/)**, **[sway](https://swaywm.org/)**, and **[dwl/MangoWC](https://github.com/DreamMaoMao/mangowc)**. - with full workspace switching, overview integration, and monitor management.
Other Wayland compositors work too, just with a reduced feature set.

View File

@@ -14,11 +14,13 @@ Singleton {
property bool isNiri: false
property bool isDwl: false
property bool isSway: false
property bool isLabwc: false
property string compositor: "unknown"
readonly property string hyprlandSignature: Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE")
readonly property string niriSocket: Quickshell.env("NIRI_SOCKET")
readonly property string swaySocket: Quickshell.env("SWAYSOCK")
readonly property string labwcPid: Quickshell.env("LABWC_PID")
property bool useNiriSorting: isNiri && NiriService
property var sortedToplevels: []
@@ -29,10 +31,17 @@ Singleton {
function getScreenScale(screen) {
if (!screen) return 1
if (Quickshell.env("QT_WAYLAND_FORCE_DPI")) {
if (Quickshell.env("QT_WAYLAND_FORCE_DPI") || Quickshell.env("QT_SCALE_FACTOR")) {
return screen.devicePixelRatio || 1
}
if (WlrOutputService.wlrOutputAvailable && screen) {
const wlrOutput = WlrOutputService.getOutput(screen.name)
if (wlrOutput?.enabled && wlrOutput.scale !== undefined && wlrOutput.scale > 0) {
return wlrOutput.scale
}
}
if (isNiri && screen) {
const niriScale = NiriService.displayScales[screen.name]
if (niriScale !== undefined) return niriScale
@@ -338,11 +347,13 @@ Singleton {
}
function detectCompositor() {
if (hyprlandSignature && hyprlandSignature.length > 0) {
if (hyprlandSignature && hyprlandSignature.length > 0 &&
!niriSocket && !swaySocket && !labwcPid) {
isHyprland = true
isNiri = false
isDwl = false
isSway = false
isLabwc = false
compositor = "hyprland"
console.info("CompositorService: Detected Hyprland")
return
@@ -355,6 +366,7 @@ Singleton {
isHyprland = false
isDwl = false
isSway = false
isLabwc = false
compositor = "niri"
console.info("CompositorService: Detected Niri with socket:", niriSocket)
NiriService.generateNiriBinds()
@@ -371,13 +383,25 @@ Singleton {
isHyprland = false
isDwl = false
isSway = true
isLabwc = false
compositor = "sway"
console.info("CompositorService: Detected Sway with socket:", swaySocket)
}
}, 0)
return
return
}
if (labwcPid && labwcPid.length > 0) {
isHyprland = false
isNiri = false
isDwl = false
isSway = false
isLabwc = true
compositor = "labwc"
console.info("CompositorService: Detected LabWC with PID:", labwcPid)
return
}
if (DMSService.dmsAvailable) {
Qt.callLater(checkForDwl)
} else {
@@ -385,6 +409,7 @@ Singleton {
isNiri = false
isDwl = false
isSway = false
isLabwc = false
compositor = "unknown"
console.warn("CompositorService: No compositor detected")
}
@@ -393,7 +418,7 @@ Singleton {
Connections {
target: DMSService
function onCapabilitiesReceived() {
if (!isHyprland && !isNiri && !isDwl) {
if (!isHyprland && !isNiri && !isDwl && !isLabwc) {
checkForDwl()
}
}
@@ -404,6 +429,8 @@ Singleton {
isHyprland = false
isNiri = false
isDwl = true
isSway = false
isLabwc = false
compositor = "dwl"
console.info("CompositorService: Detected DWL via DMS capability")
}

View File

@@ -1,6 +1,6 @@
pragma Singleton
pragma ComponentBehavior
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell

View File

@@ -1,6 +1,6 @@
pragma Singleton
pragma ComponentBehavior
pragma ComponentBehavior: Bound
import QtCore
import QtQuick
@@ -20,6 +20,7 @@ Singleton {
property bool isConnected: false
property bool isConnecting: false
property bool subscribeConnected: false
readonly property bool forceExtWorkspace: false
readonly property string socketPath: Quickshell.env("DMS_SOCKET")
@@ -46,8 +47,10 @@ Singleton {
signal dwlStateUpdate(var data)
signal brightnessStateUpdate(var data)
signal brightnessDeviceUpdate(var device)
signal extWorkspaceStateUpdate(var data)
signal wlrOutputStateUpdate(var data)
property var activeSubscriptions: ["network", "network.credentials", "loginctl", "freedesktop", "gamma", "bluetooth", "bluetooth.pairing", "dwl", "brightness"]
property var activeSubscriptions: ["network", "network.credentials", "loginctl", "freedesktop", "gamma", "bluetooth", "bluetooth.pairing", "dwl", "brightness", "wlroutput"]
Component.onCompleted: {
if (socketPath && socketPath.length > 0) {
@@ -263,7 +266,7 @@ Singleton {
function removeSubscription(service) {
if (activeSubscriptions.includes("all")) {
const allServices = ["network", "loginctl", "freedesktop", "gamma", "bluetooth", "dwl", "brightness"]
const allServices = ["network", "loginctl", "freedesktop", "gamma", "bluetooth", "dwl", "brightness", "extworkspace"]
const filtered = allServices.filter(s => s !== service)
subscribe(filtered)
} else {
@@ -285,7 +288,7 @@ Singleton {
excludeServices = [excludeServices]
}
const allServices = ["network", "loginctl", "freedesktop", "gamma", "bluetooth", "cups", "dwl", "brightness"]
const allServices = ["network", "loginctl", "freedesktop", "gamma", "bluetooth", "cups", "dwl", "brightness", "extworkspace"]
const filtered = allServices.filter(s => !excludeServices.includes(s))
subscribe(filtered)
}
@@ -342,6 +345,10 @@ Singleton {
if (data.device) {
brightnessDeviceUpdate(data.device)
}
} else if (service === "extworkspace") {
extWorkspaceStateUpdate(data)
} else if (service === "wlroutput") {
wlrOutputStateUpdate(data)
}
}

View File

@@ -1,6 +1,6 @@
pragma Singleton
pragma ComponentBehavior
pragma ComponentBehavior: Bound
import QtCore
import QtQuick

View File

@@ -0,0 +1,259 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
Singleton {
id: root
property bool extWorkspaceAvailable: false
property var groups: []
property var _cachedWorkspaces: ({})
signal stateChanged()
Connections {
target: DMSService
function onCapabilitiesReceived() {
checkCapabilities()
}
function onConnectionStateChanged() {
if (DMSService.isConnected) {
checkCapabilities()
} else {
extWorkspaceAvailable = false
}
}
function onExtWorkspaceStateUpdate(data) {
if (extWorkspaceAvailable) {
handleStateUpdate(data)
}
}
}
Component.onCompleted: {
if (DMSService.dmsAvailable) {
checkCapabilities()
}
}
function checkCapabilities() {
if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) {
extWorkspaceAvailable = false
return
}
const hasExtWorkspace = DMSService.capabilities.includes("extworkspace")
if (hasExtWorkspace && !extWorkspaceAvailable) {
extWorkspaceAvailable = true
console.info("ExtWorkspaceService: ext-workspace capability detected")
requestState()
} else if (!hasExtWorkspace) {
extWorkspaceAvailable = false
}
}
function requestState() {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return
}
DMSService.sendRequest("extworkspace.getState", null, response => {
if (response.result) {
handleStateUpdate(response.result)
}
})
}
function handleStateUpdate(state) {
groups = state.groups || []
if (groups.length === 0) {
console.warn("ExtWorkspaceService: Received empty workspace groups from backend")
} else {
console.log("ExtWorkspaceService: Updated with", groups.length, "workspace groups")
}
stateChanged()
}
function activateWorkspace(workspaceID, groupID = "") {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return
}
DMSService.sendRequest("extworkspace.activateWorkspace", {
"workspaceID": workspaceID,
"groupID": groupID
}, response => {
if (response.error) {
console.warn("ExtWorkspaceService: activateWorkspace error:", response.error)
}
})
}
function deactivateWorkspace(workspaceID, groupID = "") {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return
}
DMSService.sendRequest("extworkspace.deactivateWorkspace", {
"workspaceID": workspaceID,
"groupID": groupID
}, response => {
if (response.error) {
console.warn("ExtWorkspaceService: deactivateWorkspace error:", response.error)
}
})
}
function removeWorkspace(workspaceID, groupID = "") {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return
}
DMSService.sendRequest("extworkspace.removeWorkspace", {
"workspaceID": workspaceID,
"groupID": groupID
}, response => {
if (response.error) {
console.warn("ExtWorkspaceService: removeWorkspace error:", response.error)
}
})
}
function createWorkspace(groupID, name) {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return
}
DMSService.sendRequest("extworkspace.createWorkspace", {
"groupID": groupID,
"name": name
}, response => {
if (response.error) {
console.warn("ExtWorkspaceService: createWorkspace error:", response.error)
}
})
}
function getGroupForOutput(outputName) {
for (const group of groups) {
if (group.outputs && group.outputs.includes(outputName)) {
return group
}
}
return null
}
function getWorkspacesForOutput(outputName) {
const group = getGroupForOutput(outputName)
return group ? (group.workspaces || []) : []
}
function getActiveWorkspaces() {
const active = []
for (const group of groups) {
if (!group.workspaces) continue
for (const ws of group.workspaces) {
if (ws.active) {
active.push({
workspace: ws,
group: group,
outputs: group.outputs || []
})
}
}
}
return active
}
function getActiveWorkspaceForOutput(outputName) {
const group = getGroupForOutput(outputName)
if (!group || !group.workspaces) return null
for (const ws of group.workspaces) {
if (ws.active) {
return ws
}
}
return null
}
function getVisibleWorkspaces(outputName) {
const workspaces = getWorkspacesForOutput(outputName)
const visible = workspaces.filter(ws => !ws.hidden).sort((a, b) => {
const coordsA = a.coordinates || [0, 0]
const coordsB = b.coordinates || [0, 0]
if (coordsA[0] !== coordsB[0]) return coordsA[0] - coordsB[0]
return coordsA[1] - coordsB[1]
})
const cacheKey = outputName
if (!_cachedWorkspaces[cacheKey]) {
_cachedWorkspaces[cacheKey] = {
workspaces: [],
lastNames: []
}
}
const cache = _cachedWorkspaces[cacheKey]
const currentNames = visible.map(ws => ws.name || ws.id)
const namesChanged = JSON.stringify(cache.lastNames) !== JSON.stringify(currentNames)
if (namesChanged || cache.workspaces.length !== visible.length) {
cache.workspaces = visible.map(ws => ({
id: ws.id,
name: ws.name,
coordinates: ws.coordinates,
state: ws.state,
active: ws.active,
urgent: ws.urgent,
hidden: ws.hidden
}))
cache.lastNames = currentNames
return cache.workspaces
}
for (let i = 0; i < visible.length; i++) {
const src = visible[i]
const dst = cache.workspaces[i]
dst.id = src.id
dst.name = src.name
dst.coordinates = src.coordinates
dst.state = src.state
dst.active = src.active
dst.urgent = src.urgent
dst.hidden = src.hidden
}
return cache.workspaces
}
function getUrgentWorkspaces() {
const urgent = []
for (const group of groups) {
if (!group.workspaces) continue
for (const ws of group.workspaces) {
if (ws.urgent) {
urgent.push({
workspace: ws,
group: group,
outputs: group.outputs || []
})
}
}
}
return urgent
}
function switchToWorkspace(outputName, workspaceName) {
const workspaces = getWorkspacesForOutput(outputName)
for (const ws of workspaces) {
if (ws.name === workspaceName || ws.id === workspaceName) {
activateWorkspace(ws.name || ws.id)
return
}
}
console.warn("ExtWorkspaceService: workspace not found:", workspaceName)
}
}

View File

@@ -1,6 +1,6 @@
pragma Singleton
pragma ComponentBehavior
pragma ComponentBehavior: Bound
import QtCore
import QtQuick

View File

@@ -0,0 +1,275 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
Singleton {
id: root
property bool wlrOutputAvailable: false
property var outputs: []
property int serial: 0
signal stateChanged
signal configurationApplied(bool success, string message)
Connections {
target: DMSService
function onCapabilitiesReceived() {
checkCapabilities()
}
function onConnectionStateChanged() {
if (DMSService.isConnected) {
checkCapabilities()
return
}
wlrOutputAvailable = false
}
function onWlrOutputStateUpdate(data) {
if (!wlrOutputAvailable) {
return
}
handleStateUpdate(data)
}
}
Component.onCompleted: {
if (!DMSService.dmsAvailable) {
return
}
checkCapabilities()
}
function checkCapabilities() {
if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) {
wlrOutputAvailable = false
return
}
const hasWlrOutput = DMSService.capabilities.includes("wlroutput")
if (hasWlrOutput && !wlrOutputAvailable) {
wlrOutputAvailable = true
console.info("WlrOutputService: wlr-output-management capability detected")
requestState()
return
}
if (!hasWlrOutput) {
wlrOutputAvailable = false
}
}
function requestState() {
if (!DMSService.isConnected || !wlrOutputAvailable) {
return
}
DMSService.sendRequest("wlroutput.getState", null, response => {
if (!response.result) {
return
}
handleStateUpdate(response.result)
})
}
function handleStateUpdate(state) {
outputs = state.outputs || []
serial = state.serial || 0
if (outputs.length === 0) {
console.warn("WlrOutputService: Received empty outputs list")
} else {
console.log("WlrOutputService: Updated with", outputs.length, "outputs, serial:", serial)
outputs.forEach((output, index) => {
console.log("WlrOutputService: Output", index, "-", output.name,
"enabled:", output.enabled,
"mode:", output.currentMode ?
output.currentMode.width + "x" + output.currentMode.height + "@" +
(output.currentMode.refresh / 1000) + "Hz" : "none")
})
}
stateChanged()
}
function getOutput(name) {
for (const output of outputs) {
if (output.name === name) {
return output
}
}
return null
}
function getEnabledOutputs() {
return outputs.filter(output => output.enabled)
}
function applyConfiguration(heads, callback) {
if (!DMSService.isConnected || !wlrOutputAvailable) {
if (callback) {
callback(false, "Not connected")
}
return
}
console.log("WlrOutputService: Applying configuration for", heads.length, "outputs")
heads.forEach((head, index) => {
console.log("WlrOutputService: Head", index, "- name:", head.name,
"enabled:", head.enabled,
"modeId:", head.modeId,
"customMode:", JSON.stringify(head.customMode),
"position:", JSON.stringify(head.position),
"scale:", head.scale,
"transform:", head.transform,
"adaptiveSync:", head.adaptiveSync)
})
DMSService.sendRequest("wlroutput.applyConfiguration", {
"heads": heads
}, response => {
const success = !response.error
const message = response.error || response.result?.message || ""
if (response.error) {
console.warn("WlrOutputService: applyConfiguration error:", response.error)
} else {
console.log("WlrOutputService: Configuration applied successfully")
}
configurationApplied(success, message)
if (callback) {
callback(success, message)
}
})
}
function testConfiguration(heads, callback) {
if (!DMSService.isConnected || !wlrOutputAvailable) {
if (callback) {
callback(false, "Not connected")
}
return
}
console.log("WlrOutputService: Testing configuration for", heads.length, "outputs")
DMSService.sendRequest("wlroutput.testConfiguration", {
"heads": heads
}, response => {
const success = !response.error
const message = response.error || response.result?.message || ""
if (response.error) {
console.warn("WlrOutputService: testConfiguration error:", response.error)
} else {
console.log("WlrOutputService: Configuration test passed")
}
if (callback) {
callback(success, message)
}
})
}
function setOutputEnabled(outputName, enabled, callback) {
const output = getOutput(outputName)
if (!output) {
console.warn("WlrOutputService: Output not found:", outputName)
if (callback) {
callback(false, "Output not found")
}
return
}
const heads = [{
"name": outputName,
"enabled": enabled
}]
if (enabled && output.currentMode) {
heads[0].modeId = output.currentMode.id
}
applyConfiguration(heads, callback)
}
function setOutputMode(outputName, modeId, callback) {
const heads = [{
"name": outputName,
"enabled": true,
"modeId": modeId
}]
applyConfiguration(heads, callback)
}
function setOutputCustomMode(outputName, width, height, refresh, callback) {
const heads = [{
"name": outputName,
"enabled": true,
"customMode": {
"width": width,
"height": height,
"refresh": refresh
}
}]
applyConfiguration(heads, callback)
}
function setOutputPosition(outputName, x, y, callback) {
const heads = [{
"name": outputName,
"enabled": true,
"position": {
"x": x,
"y": y
}
}]
applyConfiguration(heads, callback)
}
function setOutputScale(outputName, scale, callback) {
const heads = [{
"name": outputName,
"enabled": true,
"scale": scale
}]
applyConfiguration(heads, callback)
}
function setOutputTransform(outputName, transform, callback) {
const heads = [{
"name": outputName,
"enabled": true,
"transform": transform
}]
applyConfiguration(heads, callback)
}
function setOutputAdaptiveSync(outputName, state, callback) {
const heads = [{
"name": outputName,
"enabled": true,
"adaptiveSync": state
}]
applyConfiguration(heads, callback)
}
function configureOutput(config, callback) {
const heads = [config]
applyConfiguration(heads, callback)
}
function configureMultipleOutputs(configs, callback) {
applyConfiguration(configs, callback)
}
}

View File

@@ -1 +1 @@
v0.4.3
v0.5.0

View File

@@ -29,6 +29,7 @@ Flickable {
property real lastWheelTime: 0
property real momentum: 0
property var velocitySamples: []
property bool sessionUsedMouseWheel: false
function startMomentum() {
flickable.isMomentumActive = true
@@ -49,10 +50,12 @@ Flickable {
const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0
if (isMouseWheel) {
sessionUsedMouseWheel = true
momentumTimer.stop()
flickable.isMomentumActive = false
velocitySamples = []
momentum = 0
flickable.momentumVelocity = 0
const lines = Math.floor(Math.abs(deltaY) / 120)
const scrollAmount = (deltaY > 0 ? -lines : lines) * flickable.mouseWheelSpeed
@@ -65,6 +68,7 @@ Flickable {
flickable.contentY = newY
} else {
sessionUsedMouseWheel = false
momentumTimer.stop()
flickable.isMomentumActive = false
@@ -111,7 +115,7 @@ Flickable {
onActiveChanged: {
if (!active) {
if (Math.abs(flickable.momentumVelocity) >= flickable.minMomentumVelocity) {
if (!sessionUsedMouseWheel && Math.abs(flickable.momentumVelocity) >= flickable.minMomentumVelocity) {
startMomentum()
} else {
velocitySamples = []

View File

@@ -33,6 +33,7 @@ GridView {
property real lastWheelTime: 0
property real momentum: 0
property var velocitySamples: []
property bool sessionUsedMouseWheel: false
function startMomentum() {
isMomentumActive = true
@@ -52,10 +53,12 @@ GridView {
const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0
if (isMouseWheel) {
sessionUsedMouseWheel = true
momentumTimer.stop()
isMomentumActive = false
velocitySamples = []
momentum = 0
momentumVelocity = 0
const lines = Math.floor(Math.abs(deltaY) / 120)
const scrollAmount = (deltaY > 0 ? -lines : lines) * cellHeight * 0.35
@@ -68,6 +71,7 @@ GridView {
contentY = newY
} else {
sessionUsedMouseWheel = false
momentumTimer.stop()
isMomentumActive = false
@@ -108,7 +112,7 @@ GridView {
}
onActiveChanged: {
if (!active) {
if (Math.abs(momentumVelocity) >= minMomentumVelocity) {
if (!sessionUsedMouseWheel && Math.abs(momentumVelocity) >= minMomentumVelocity) {
startMomentum()
} else {
velocitySamples = []

View File

@@ -50,6 +50,7 @@ ListView {
property real lastWheelTime: 0
property real momentum: 0
property var velocitySamples: []
property bool sessionUsedMouseWheel: false
function startMomentum() {
isMomentumActive = true
@@ -71,10 +72,12 @@ ListView {
const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0
if (isMouseWheel) {
sessionUsedMouseWheel = true
momentumTimer.stop()
isMomentumActive = false
velocitySamples = []
momentum = 0
momentumVelocity = 0
const lines = Math.floor(Math.abs(deltaY) / 120)
const scrollAmount = (deltaY > 0 ? -lines : lines) * mouseWheelSpeed
@@ -89,6 +92,7 @@ ListView {
listView.contentY = newY
savedY = newY
} else {
sessionUsedMouseWheel = false
momentumTimer.stop()
isMomentumActive = false
@@ -138,7 +142,7 @@ ListView {
onActiveChanged: {
if (!active) {
isUserScrolling = false
if (Math.abs(momentumVelocity) >= minMomentumVelocity) {
if (!sessionUsedMouseWheel && Math.abs(momentumVelocity) >= minMomentumVelocity) {
startMomentum()
} else {
velocitySamples = []

View File

@@ -4,6 +4,7 @@ import Quickshell
import Quickshell.Wayland
import qs.Common
import qs.Services
import qs.Widgets
PanelWindow {
id: root
@@ -117,14 +118,37 @@ PanelWindow {
scale: shouldBeVisible ? 1 : 0.9
property bool childHovered: false
property real shadowBlurPx: 10
property real shadowSpreadPx: 0
property real shadowBaseAlpha: 0.60
readonly property real popupSurfaceAlpha: SettingsData.popupTransparency
readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha * osdContainer.opacity))
Rectangle {
id: osdBackground
Item {
id: bgShadowLayer
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
visible: osdContainer.popupSurfaceAlpha >= 0.95
layer.enabled: Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
layer.smooth: false
layer.textureSize: Qt.size(Math.round(width * root.dpr), Math.round(height * root.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically
layer.effect: MultiEffect {
id: shadowFx
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
property int blurMax: 64
shadowBlur: Math.max(0, Math.min(1, osdContainer.shadowBlurPx / blurMax))
shadowScale: 1 + (2 * osdContainer.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: Qt.rgba(0, 0, 0, osdContainer.effectiveShadowAlpha)
}
DankRectangle {
anchors.fill: parent
radius: Theme.cornerRadius
}
}
MouseArea {
@@ -162,6 +186,6 @@ PanelWindow {
}
mask: Region {
item: osdBackground
item: bgShadowLayer
}
}

View File

@@ -1,9 +1,11 @@
import QtQuick
import QtQuick.Effects
import Quickshell
import Quickshell.Hyprland
import Quickshell.Wayland
import qs.Common
import qs.Services
import qs.Widgets
PanelWindow {
id: root
@@ -63,7 +65,18 @@ PanelWindow {
}
color: "transparent"
WlrLayershell.layer: WlrLayershell.Top
WlrLayershell.layer: {
switch (Quickshell.env("DMS_DANKBAR_LAYER")) {
case "bottom":
return WlrLayershell.Bottom
case "overlay":
return WlrLayershell.Overlay
case "background":
return WlrLayershell.Background
default:
return WlrLayershell.Top
}
}
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: shouldBeVisible ? keyboardFocusMode : WlrKeyboardFocus.None
@@ -168,23 +181,23 @@ PanelWindow {
}
}
Loader {
id: contentLoader
Item {
id: contentWrapper
anchors.centerIn: parent
width: parent.width
height: parent.height
active: root.visible
asynchronous: false
layer.enabled: Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
layer.smooth: false
layer.textureSize: Qt.size(width * root.dpr, height * root.dpr)
layer.textureMirroring: ShaderEffectSource.NoMirroring
opacity: shouldBeVisible ? 1 : 0
visible: opacity > 0
scale: contentContainer.scaleValue
x: Theme.snap(contentContainer.animX + (parent.width - width) * (1 - contentContainer.scaleValue) * 0.5, root.dpr)
y: Theme.snap(contentContainer.animY + (parent.height - height) * (1 - contentContainer.scaleValue) * 0.5, root.dpr)
property real shadowBlurPx: 10
property real shadowSpreadPx: 0
property real shadowBaseAlpha: 0.60
readonly property real popupSurfaceAlpha: SettingsData.popupTransparency
readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha * contentWrapper.opacity))
Behavior on opacity {
NumberAnimation {
duration: animationDuration
@@ -192,6 +205,47 @@ PanelWindow {
easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve
}
}
Item {
id: bgShadowLayer
anchors.fill: parent
visible: contentWrapper.popupSurfaceAlpha >= 0.95
layer.enabled: Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
layer.smooth: false
layer.textureSize: Qt.size(Math.round(width * root.dpr), Math.round(height * root.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically
layer.effect: MultiEffect {
id: shadowFx
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
property int blurMax: 64
shadowBlur: Math.max(0, Math.min(1, contentWrapper.shadowBlurPx / blurMax))
shadowScale: 1 + (2 * contentWrapper.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: Qt.rgba(0, 0, 0, contentWrapper.effectiveShadowAlpha)
}
DankRectangle {
anchors.fill: parent
radius: Theme.cornerRadius
}
}
Item {
id: contentLoaderWrapper
anchors.fill: parent
x: Theme.snap(x, root.dpr)
y: Theme.snap(y, root.dpr)
Loader {
id: contentLoader
anchors.fill: parent
active: root.visible
asynchronous: false
}
}
}
}

54
Widgets/DankRectangle.qml Normal file
View File

@@ -0,0 +1,54 @@
import QtQuick
import QtQuick.Shapes
import qs.Common
Item {
id: root
property color color: Theme.surfaceContainer
property color borderColor: Theme.outlineMedium
property real borderWidth: 1
property real radius: Theme.cornerRadius
property color overlayColor: "transparent"
Shape {
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
ShapePath {
fillColor: root.color
strokeColor: root.borderColor
strokeWidth: root.borderWidth
startX: root.radius
startY: 0
PathLine { x: root.width - root.radius; y: 0 }
PathQuad { x: root.width; y: root.radius; controlX: root.width; controlY: 0 }
PathLine { x: root.width; y: root.height - root.radius }
PathQuad { x: root.width - root.radius; y: root.height; controlX: root.width; controlY: root.height }
PathLine { x: root.radius; y: root.height }
PathQuad { x: 0; y: root.height - root.radius; controlX: 0; controlY: root.height }
PathLine { x: 0; y: root.radius }
PathQuad { x: root.radius; y: 0; controlX: 0; controlY: 0 }
}
ShapePath {
fillColor: root.overlayColor
strokeColor: "transparent"
strokeWidth: 0
startX: root.radius
startY: 0
PathLine { x: root.width - root.radius; y: 0 }
PathQuad { x: root.width; y: root.radius; controlX: root.width; controlY: 0 }
PathLine { x: root.width; y: root.height - root.radius }
PathQuad { x: root.width - root.radius; y: root.height; controlX: root.width; controlY: root.height }
PathLine { x: root.radius; y: root.height }
PathQuad { x: 0; y: root.height - root.radius; controlX: 0; controlY: root.height }
PathLine { x: 0; y: root.radius }
PathQuad { x: root.radius; y: 0; controlX: 0; controlY: 0 }
}
}
}

View File

@@ -110,22 +110,22 @@ PanelWindow {
}
}
StyledRect {
Item {
id: contentRect
layer.enabled: Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
layer.smooth: false
layer.textureSize: Qt.size(width * root.dpr, height * root.dpr)
layer.textureMirroring: ShaderEffectSource.NoMirroring
anchors.top: parent.top
anchors.bottom: parent.bottom
width: parent.width
x: Theme.snap(slideContainer.slideOffset, root.dpr)
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b,
customTransparency >= 0 ? customTransparency : SettingsData.popupTransparency)
border.color: Theme.outlineMedium
border.width: 1
radius: Theme.cornerRadius
DankRectangle {
anchors.fill: parent
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b,
customTransparency >= 0 ? customTransparency : SettingsData.popupTransparency)
}
Column {
id: headerColumn

View File

@@ -214,7 +214,7 @@ FocusScope {
color: Theme.outlineStrong
}
function updateIndicator(enableAnimation = true) {
function updateIndicator() {
if (tabRepeater.count === 0 || currentIndex < 0 || currentIndex >= tabRepeater.count) {
return
}
@@ -229,25 +229,26 @@ FocusScope {
const indicatorWidth = 60
if (tabPos.x < 10 && currentIndex > 0) {
Qt.callLater(() => updateIndicator(enableAnimation))
Qt.callLater(updateIndicator)
return
}
indicator.animationEnabled = enableAnimation
indicator.width = indicatorWidth
indicator.x = tabCenterX - indicatorWidth / 2
indicator.visible = true
if (!indicator.initialSetupComplete) {
indicator.animationEnabled = false
indicator.width = indicatorWidth
indicator.x = tabCenterX - indicatorWidth / 2
indicator.visible = true
indicator.initialSetupComplete = true
indicator.animationEnabled = true
} else {
indicator.width = indicatorWidth
indicator.x = tabCenterX - indicatorWidth / 2
indicator.visible = true
}
}
onCurrentIndexChanged: {
if (indicator.initialSetupComplete) {
Qt.callLater(() => updateIndicator(true))
} else {
Qt.callLater(() => {
updateIndicator(false)
indicator.initialSetupComplete = true
})
}
Qt.callLater(updateIndicator)
}
onWidthChanged: Qt.callLater(() => updateIndicator(indicator.initialSetupComplete))
onWidthChanged: Qt.callLater(updateIndicator)
}

View File

@@ -6,6 +6,8 @@ import qs.Common
PanelWindow {
id: root
WlrLayershell.namespace: "dms:tooltip"
property string text: ""
property real targetX: 0
property real targetY: 0

BIN
assets/labwc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -9,7 +9,7 @@ Version: %{version}
Release: 0.git%{?dist}
Summary: %{pkg_summary}
License: GPL-3.0-only
License: MIT
URL: https://github.com/AvengeMedia/DankMaterialShell
VCS: {{{ git_repo_vcs }}}
Source0: {{{ git_repo_pack }}}

View File

@@ -10,7 +10,7 @@ Version: %{version}
Release: 1%{?dist}
Summary: %{pkg_summary}
License: GPL-3.0-only
License: MIT
URL: https://github.com/AvengeMedia/DankMaterialShell
VCS: {{{ git_repo_vcs }}}
Source0: {{{ git_repo_pack }}}
@@ -57,7 +57,7 @@ lock screen, and comprehensive plugin system.
%package -n dms-cli
Summary: DankMaterialShell CLI tool
License: GPL-3.0-only
License: MIT
URL: https://github.com/AvengeMedia/danklinux
%description -n dms-cli
@@ -124,6 +124,14 @@ esac
install -Dm755 %{_builddir}/danklinux-master/bin/${DMS_BINARY} %{buildroot}%{_bindir}/dms
# Shell completions
install -d %{buildroot}%{_datadir}/bash-completion/completions
install -d %{buildroot}%{_datadir}/zsh/site-functions
install -d %{buildroot}%{_datadir}/fish/vendor_completions.d
%{_builddir}/danklinux-master/bin/${DMS_BINARY} completion bash > %{buildroot}%{_datadir}/bash-completion/completions/dms || :
%{_builddir}/danklinux-master/bin/${DMS_BINARY} completion zsh > %{buildroot}%{_datadir}/zsh/site-functions/_dms || :
%{_builddir}/danklinux-master/bin/${DMS_BINARY} completion fish > %{buildroot}%{_datadir}/fish/vendor_completions.d/dms.fish || :
# Install dgop binary
install -Dm755 %{_builddir}/dgop %{buildroot}%{_bindir}/dgop
@@ -162,6 +170,9 @@ fi
%files -n dms-cli
%{_bindir}/dms
%{_datadir}/bash-completion/completions/dms
%{_datadir}/zsh/site-functions/_dms
%{_datadir}/fish/vendor_completions.d/dms.fish
%files -n dgop
%{_bindir}/dgop

View File

@@ -8,19 +8,19 @@
{
"term": "(Unnamed)",
"context": "(Unnamed)",
"reference": "Modules/Dock/DockContextMenu.qml:226",
"reference": "Modules/Dock/DockContextMenu.qml:229",
"comment": ""
},
{
"term": "- Stateless System Monitoring",
"context": "- Stateless System Monitoring",
"reference": "Modules/Settings/AboutTab.qml:544",
"reference": "Modules/Settings/AboutTab.qml:588",
"comment": ""
},
{
"term": "- Support Us With a Star ⭐",
"context": "- Support Us With a Star ⭐",
"reference": "Modules/Settings/AboutTab.qml:509",
"reference": "Modules/Settings/AboutTab.qml:553",
"comment": ""
},
{
@@ -44,7 +44,7 @@
{
"term": "3rd party",
"context": "3rd party",
"reference": "Modules/Settings/PluginBrowser.qml:408",
"reference": "Modules/Settings/PluginBrowser.qml:428",
"comment": ""
},
{
@@ -62,7 +62,7 @@
{
"term": "About",
"context": "About",
"reference": "Modals/Settings/SettingsSidebar.qml:44, Modules/Settings/AboutTab.qml:363",
"reference": "Modals/Settings/SettingsSidebar.qml:44, Modules/Settings/AboutTab.qml:407",
"comment": ""
},
{
@@ -140,7 +140,7 @@
{
"term": "Always Show OSD Percentage",
"context": "Always Show OSD Percentage",
"reference": "Modules/Settings/WidgetTweaksTab.qml:675",
"reference": "Modules/Settings/WidgetTweaksTab.qml:677",
"comment": ""
},
{
@@ -212,31 +212,31 @@
{
"term": "Are you sure you want to hibernate the system?",
"context": "Are you sure you want to hibernate the system?",
"reference": "Modals/PowerMenuModal.qml:46",
"reference": "Modals/PowerMenuModal.qml:158",
"comment": ""
},
{
"term": "Are you sure you want to log out?",
"context": "Are you sure you want to log out?",
"reference": "Modals/PowerMenuModal.qml:38",
"reference": "Modals/PowerMenuModal.qml:150",
"comment": ""
},
{
"term": "Are you sure you want to power off the system?",
"context": "Are you sure you want to power off the system?",
"reference": "Modals/PowerMenuModal.qml:54",
"reference": "Modals/PowerMenuModal.qml:166",
"comment": ""
},
{
"term": "Are you sure you want to reboot the system?",
"context": "Are you sure you want to reboot the system?",
"reference": "Modals/PowerMenuModal.qml:50",
"reference": "Modals/PowerMenuModal.qml:162",
"comment": ""
},
{
"term": "Are you sure you want to suspend the system?",
"context": "Are you sure you want to suspend the system?",
"reference": "Modals/PowerMenuModal.qml:42",
"reference": "Modals/PowerMenuModal.qml:154",
"comment": ""
},
{
@@ -428,7 +428,7 @@
{
"term": "Back",
"context": "Back",
"reference": "Modules/DankBar/Widgets/SystemTrayBar.qml:511",
"reference": "Modules/DankBar/Widgets/SystemTrayBar.qml:863",
"comment": ""
},
{
@@ -542,7 +542,7 @@
{
"term": "Browse Plugins",
"context": "Browse Plugins",
"reference": "Modules/Settings/PluginBrowser.qml:177",
"reference": "Modules/Settings/PluginBrowser.qml:197",
"comment": ""
},
{
@@ -590,7 +590,7 @@
{
"term": "Cancel",
"context": "Cancel",
"reference": "Modals/BluetoothPairingModal.qml:251, Modals/PolkitAuthModal.qml:291, Modals/WifiPasswordModal.qml:494, Modals/FileBrowser/FileBrowserOverwriteDialog.qml:83, Modules/Settings/PluginBrowser.qml:630",
"reference": "Modals/BluetoothPairingModal.qml:251, Modals/PolkitAuthModal.qml:291, Modals/WifiPasswordModal.qml:494, Modals/FileBrowser/FileBrowserOverwriteDialog.qml:83, Modules/Settings/PluginBrowser.qml:650",
"comment": ""
},
{
@@ -644,7 +644,7 @@
{
"term": "Choose where notification popups appear on screen",
"context": "Choose where notification popups appear on screen",
"reference": "Modules/Settings/WidgetTweaksTab.qml:602",
"reference": "Modules/Settings/WidgetTweaksTab.qml:604",
"comment": ""
},
{
@@ -692,7 +692,7 @@
{
"term": "Close",
"context": "Close",
"reference": "Modules/SystemUpdatePopout.qml:335, Modals/NetworkWiredInfoModal.qml:131, Modals/NetworkInfoModal.qml:131, Modules/DankBar/Widgets/RunningApps.qml:770",
"reference": "Modules/SystemUpdatePopout.qml:335, Modals/NetworkWiredInfoModal.qml:131, Modals/NetworkInfoModal.qml:131, Modules/DankBar/Widgets/RunningApps.qml:778",
"comment": ""
},
{
@@ -728,37 +728,37 @@
{
"term": "Command or script to run instead of the standard hibernate procedure",
"context": "Command or script to run instead of the standard hibernate procedure",
"reference": "Modals/Settings/PowerSettings.qml:508",
"reference": "Modals/Settings/PowerSettings.qml:687",
"comment": ""
},
{
"term": "Command or script to run instead of the standard lock procedure",
"context": "Command or script to run instead of the standard lock procedure",
"reference": "Modals/Settings/PowerSettings.qml:412",
"reference": "Modals/Settings/PowerSettings.qml:591",
"comment": ""
},
{
"term": "Command or script to run instead of the standard logout procedure",
"context": "Command or script to run instead of the standard logout procedure",
"reference": "Modals/Settings/PowerSettings.qml:444",
"reference": "Modals/Settings/PowerSettings.qml:623",
"comment": ""
},
{
"term": "Command or script to run instead of the standard power off procedure",
"context": "Command or script to run instead of the standard power off procedure",
"reference": "Modals/Settings/PowerSettings.qml:572",
"reference": "Modals/Settings/PowerSettings.qml:751",
"comment": ""
},
{
"term": "Command or script to run instead of the standard reboot procedure",
"context": "Command or script to run instead of the standard reboot procedure",
"reference": "Modals/Settings/PowerSettings.qml:540",
"reference": "Modals/Settings/PowerSettings.qml:719",
"comment": ""
},
{
"term": "Command or script to run instead of the standard suspend procedure",
"context": "Command or script to run instead of the standard suspend procedure",
"reference": "Modals/Settings/PowerSettings.qml:476",
"reference": "Modals/Settings/PowerSettings.qml:655",
"comment": ""
},
{
@@ -788,7 +788,7 @@
{
"term": "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.",
"context": "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.",
"reference": "Modules/Settings/WidgetTweaksTab.qml:438",
"reference": "Modules/Settings/WidgetTweaksTab.qml:440",
"comment": ""
},
{
@@ -890,7 +890,7 @@
{
"term": "Copied!",
"context": "Copied!",
"reference": "Modules/Toast.qml:17",
"reference": "Modules/Toast.qml:19",
"comment": ""
},
{
@@ -974,7 +974,7 @@
{
"term": "Custom Power Actions",
"context": "Custom Power Actions",
"reference": "Modals/Settings/PowerSettings.qml:398",
"reference": "Modals/Settings/PowerSettings.qml:577",
"comment": ""
},
{
@@ -995,6 +995,12 @@
"reference": "Modules/Settings/DankBarTab.qml:151",
"comment": ""
},
{
"term": "Customize which actions appear in the power menu",
"context": "Customize which actions appear in the power menu",
"reference": "Modals/Settings/PowerSettings.qml:363",
"comment": ""
},
{
"term": "DEMO MODE - Click anywhere to exit",
"context": "DEMO MODE - Click anywhere to exit",
@@ -1010,7 +1016,7 @@
{
"term": "DMS out of date",
"context": "DMS out of date",
"reference": "Services/DMSService.qml:298",
"reference": "Services/DMSService.qml:301",
"comment": ""
},
{
@@ -1091,6 +1097,12 @@
"reference": "Modules/Settings/LauncherTab.qml:202",
"comment": ""
},
{
"term": "Default selected action",
"context": "Default selected action",
"reference": "Modals/Settings/PowerSettings.qml:374",
"comment": ""
},
{
"term": "Defaults",
"context": "Defaults",
@@ -1172,7 +1184,7 @@
{
"term": "Dismiss",
"context": "Dismiss",
"reference": "Modules/Notifications/Popup/NotificationPopup.qml:24, Modules/Notifications/Center/NotificationCard.qml:542, Modules/Notifications/Center/NotificationCard.qml:635",
"reference": "Modules/Notifications/Popup/NotificationPopup.qml:25, Modules/Notifications/Center/NotificationCard.qml:543, Modules/Notifications/Center/NotificationCard.qml:636",
"comment": ""
},
{
@@ -1208,7 +1220,7 @@
{
"term": "Display volume and brightness percentage values by default in OSD popups",
"context": "Display volume and brightness percentage values by default in OSD popups",
"reference": "Modules/Settings/WidgetTweaksTab.qml:682",
"reference": "Modules/Settings/WidgetTweaksTab.qml:684",
"comment": ""
},
{
@@ -1262,7 +1274,7 @@
{
"term": "Donate on Ko-fi",
"context": "Donate on Ko-fi",
"reference": "Modules/Settings/AboutTab.qml:598",
"reference": "Modules/Settings/AboutTab.qml:642",
"comment": ""
},
{
@@ -1688,7 +1700,7 @@
{
"term": "Github:",
"context": "Github:",
"reference": "Modules/Settings/AboutTab.qml:482",
"reference": "Modules/Settings/AboutTab.qml:526",
"comment": ""
},
{
@@ -1754,7 +1766,7 @@
{
"term": "Hibernate",
"context": "Hibernate",
"reference": "Modals/PowerMenuModal.qml:45, Modals/PowerMenuModal.qml:313, Modules/Lock/LockPowerMenu.qml:312",
"reference": "Modals/PowerMenuModal.qml:117, Modals/PowerMenuModal.qml:157, Modules/Lock/LockPowerMenu.qml:312",
"comment": ""
},
{
@@ -1796,7 +1808,7 @@
{
"term": "I Understand",
"context": "I Understand",
"reference": "Modules/Settings/PluginBrowser.qml:636",
"reference": "Modules/Settings/PluginBrowser.qml:656",
"comment": ""
},
{
@@ -1880,7 +1892,7 @@
{
"term": "Install plugins from the DMS plugin registry",
"context": "Install plugins from the DMS plugin registry",
"reference": "Modules/Settings/PluginBrowser.qml:231",
"reference": "Modules/Settings/PluginBrowser.qml:251",
"comment": ""
},
{
@@ -1988,7 +2000,7 @@
{
"term": "Launch on dGPU",
"context": "Launch on dGPU",
"reference": "Modals/Spotlight/SpotlightContextMenu.qml:312, Modules/AppDrawer/AppDrawerPopout.qml:806, Modules/Dock/DockContextMenu.qml:417",
"reference": "Modals/Spotlight/SpotlightContextMenu.qml:312, Modules/AppDrawer/AppDrawerPopout.qml:806, Modules/Dock/DockContextMenu.qml:420",
"comment": ""
},
{
@@ -2036,7 +2048,7 @@
{
"term": "Loading plugins...",
"context": "Loading plugins...",
"reference": "Modules/Settings/PluginBrowser.qml:299",
"reference": "Modules/Settings/PluginBrowser.qml:319",
"comment": ""
},
{
@@ -2045,6 +2057,12 @@
"reference": "Modules/Settings/TimeWeatherTab.qml:769",
"comment": ""
},
{
"term": "Lock",
"context": "Lock",
"reference": "Modals/PowerMenuModal.qml:105",
"comment": ""
},
{
"term": "Lock Screen",
"context": "Lock Screen",
@@ -2066,7 +2084,7 @@
{
"term": "Log Out",
"context": "Log Out",
"reference": "Modals/PowerMenuModal.qml:37, Modals/PowerMenuModal.qml:206, Modules/Lock/LockPowerMenu.qml:209, Modules/ControlCenter/PowerMenu.qml:14",
"reference": "Modals/PowerMenuModal.qml:93, Modals/PowerMenuModal.qml:149, Modules/Lock/LockPowerMenu.qml:209, Modules/ControlCenter/PowerMenu.qml:14",
"comment": ""
},
{
@@ -2168,7 +2186,7 @@
{
"term": "Max apps to show",
"context": "Max apps to show",
"reference": "Modules/Settings/WidgetTweaksTab.qml:103",
"reference": "Modules/Settings/WidgetTweaksTab.qml:104",
"comment": ""
},
{
@@ -2210,7 +2228,7 @@
{
"term": "Media Player Settings",
"context": "Media Player Settings",
"reference": "Modules/Settings/WidgetTweaksTab.qml:183",
"reference": "Modules/Settings/WidgetTweaksTab.qml:184",
"comment": ""
},
{
@@ -2306,7 +2324,7 @@
{
"term": "Named Workspace Icons",
"context": "Named Workspace Icons",
"reference": "Modules/Settings/WidgetTweaksTab.qml:428",
"reference": "Modules/Settings/WidgetTweaksTab.qml:430",
"comment": ""
},
{
@@ -2450,7 +2468,7 @@
{
"term": "No plugins found",
"context": "No plugins found",
"reference": "Modules/Settings/PluginBrowser.qml:533",
"reference": "Modules/Settings/PluginBrowser.qml:553",
"comment": ""
},
{
@@ -2516,7 +2534,7 @@
{
"term": "Notification Popups",
"context": "Notification Popups",
"reference": "Modules/Settings/DisplaysTab.qml:24, Modules/Settings/WidgetTweaksTab.qml:585",
"reference": "Modules/Settings/DisplaysTab.qml:24, Modules/Settings/WidgetTweaksTab.qml:587",
"comment": ""
},
{
@@ -2579,6 +2597,12 @@
"reference": "Modules/Settings/DisplaysTab.qml:200",
"comment": ""
},
{
"term": "Only visible if hibernate is supported by your system",
"context": "Only visible if hibernate is supported by your system",
"reference": "Modals/Settings/PowerSettings.qml:490",
"comment": ""
},
{
"term": "Opacity",
"context": "Opacity",
@@ -2702,7 +2726,7 @@
{
"term": "Per-Monitor Workspaces",
"context": "Per-Monitor Workspaces",
"reference": "Modules/Settings/WidgetTweaksTab.qml:134",
"reference": "Modules/Settings/WidgetTweaksTab.qml:135",
"comment": ""
},
{
@@ -2726,7 +2750,7 @@
{
"term": "Pin to Dock",
"context": "Pin to Dock",
"reference": "Modals/Spotlight/SpotlightContextMenu.qml:110, Modals/Spotlight/SpotlightContextMenu.qml:113, Modules/AppDrawer/AppDrawerPopout.qml:609, Modules/Dock/DockContextMenu.qml:370",
"reference": "Modals/Spotlight/SpotlightContextMenu.qml:110, Modals/Spotlight/SpotlightContextMenu.qml:113, Modules/AppDrawer/AppDrawerPopout.qml:609, Modules/Dock/DockContextMenu.qml:373",
"comment": ""
},
{
@@ -2798,13 +2822,13 @@
{
"term": "Plugins:",
"context": "Plugins:",
"reference": "Modules/Settings/AboutTab.qml:459",
"reference": "Modules/Settings/AboutTab.qml:503",
"comment": ""
},
{
"term": "Popup Position",
"context": "Popup Position",
"reference": "Modules/Settings/WidgetTweaksTab.qml:601",
"reference": "Modules/Settings/WidgetTweaksTab.qml:603",
"comment": ""
},
{
@@ -2834,19 +2858,25 @@
{
"term": "Power Action Confirmation",
"context": "Power Action Confirmation",
"reference": "Modals/Settings/PowerSettings.qml:533",
"comment": ""
},
{
"term": "Power Menu Customization",
"context": "Power Menu Customization",
"reference": "Modals/Settings/PowerSettings.qml:354",
"comment": ""
},
{
"term": "Power Off",
"context": "Power Off",
"reference": "Modals/PowerMenuModal.qml:53, Modals/PowerMenuModal.qml:421, Modules/Lock/LockPowerMenu.qml:432, Modules/ControlCenter/PowerMenu.qml:17",
"reference": "Modals/PowerMenuModal.qml:99, Modals/PowerMenuModal.qml:165, Modules/Lock/LockPowerMenu.qml:432, Modules/ControlCenter/PowerMenu.qml:17",
"comment": ""
},
{
"term": "Power Options",
"context": "Power Options",
"reference": "Modals/PowerMenuModal.qml:149, Modules/Lock/LockPowerMenu.qml:154, Modules/ControlCenter/PowerMenu.qml:13",
"reference": "Modules/Lock/LockPowerMenu.qml:154, Modules/ControlCenter/PowerMenu.qml:13",
"comment": ""
},
{
@@ -2972,7 +3002,7 @@
{
"term": "Reboot",
"context": "Reboot",
"reference": "Modals/PowerMenuModal.qml:49, Modals/PowerMenuModal.qml:367, Modules/Lock/LockPowerMenu.qml:372, Modules/ControlCenter/PowerMenu.qml:16",
"reference": "Modals/PowerMenuModal.qml:87, Modals/PowerMenuModal.qml:161, Modules/Lock/LockPowerMenu.qml:372, Modules/ControlCenter/PowerMenu.qml:16",
"comment": ""
},
{
@@ -3014,7 +3044,7 @@
{
"term": "Request confirmation on power off, restart, suspend, hibernate and logout actions",
"context": "Request confirmation on power off, restart, suspend, hibernate and logout actions",
"reference": "Modals/Settings/PowerSettings.qml:365",
"reference": "Modals/Settings/PowerSettings.qml:544",
"comment": ""
},
{
@@ -3026,7 +3056,19 @@
{
"term": "Resources",
"context": "Resources",
"reference": "Modules/Settings/AboutTab.qml:421",
"reference": "Modules/Settings/AboutTab.qml:465",
"comment": ""
},
{
"term": "Restart DMS",
"context": "Restart DMS",
"reference": "Modals/PowerMenuModal.qml:123",
"comment": ""
},
{
"term": "Restart the DankMaterialShell",
"context": "Restart the DankMaterialShell",
"reference": "Modals/Settings/PowerSettings.qml:474",
"comment": ""
},
{
@@ -3074,13 +3116,13 @@
{
"term": "Running Apps Only In Current Workspace",
"context": "Running Apps Only In Current Workspace",
"reference": "Modules/Settings/WidgetTweaksTab.qml:388",
"reference": "Modules/Settings/WidgetTweaksTab.qml:390",
"comment": ""
},
{
"term": "Running Apps Settings",
"context": "Running Apps Settings",
"reference": "Modules/Settings/WidgetTweaksTab.qml:378",
"reference": "Modules/Settings/WidgetTweaksTab.qml:380",
"comment": ""
},
{
@@ -3128,13 +3170,13 @@
{
"term": "Search file contents",
"context": "Search file contents",
"reference": "Modals/Spotlight/SpotlightContent.qml:372",
"reference": "Modals/Spotlight/SpotlightContent.qml:373",
"comment": ""
},
{
"term": "Search filenames",
"context": "Search filenames",
"reference": "Modals/Spotlight/SpotlightContent.qml:330",
"reference": "Modals/Spotlight/SpotlightContent.qml:331",
"comment": ""
},
{
@@ -3146,7 +3188,7 @@
{
"term": "Search plugins...",
"context": "Search plugins...",
"reference": "Modules/Settings/PluginBrowser.qml:255",
"reference": "Modules/Settings/PluginBrowser.qml:275",
"comment": ""
},
{
@@ -3260,7 +3302,7 @@
{
"term": "Settings",
"context": "Settings",
"reference": "Services/AppSearchService.qml:176, Modals/Settings/SettingsModal.qml:168, Modules/DankDash/DankDashPopout.qml:249",
"reference": "Services/AppSearchService.qml:176, Modals/Settings/SettingsModal.qml:205, Modules/DankDash/DankDashPopout.qml:249",
"comment": ""
},
{
@@ -3272,13 +3314,13 @@
{
"term": "Show All Tags",
"context": "Show All Tags",
"reference": "Modules/Settings/WidgetTweaksTab.qml:144",
"reference": "Modules/Settings/WidgetTweaksTab.qml:145",
"comment": ""
},
{
"term": "Show Confirmation on Power Actions",
"context": "Show Confirmation on Power Actions",
"reference": "Modals/Settings/PowerSettings.qml:364",
"reference": "Modals/Settings/PowerSettings.qml:543",
"comment": ""
},
{
@@ -3287,18 +3329,60 @@
"reference": "Modules/Settings/DockTab.qml:128",
"comment": ""
},
{
"term": "Show Hibernate",
"context": "Show Hibernate",
"reference": "Modals/Settings/PowerSettings.qml:489",
"comment": ""
},
{
"term": "Show Line Numbers",
"context": "Show Line Numbers",
"reference": "Modules/Notepad/NotepadSettings.qml:151",
"comment": ""
},
{
"term": "Show Lock",
"context": "Show Lock",
"reference": "Modals/Settings/PowerSettings.qml:443",
"comment": ""
},
{
"term": "Show Log Out",
"context": "Show Log Out",
"reference": "Modals/Settings/PowerSettings.qml:413",
"comment": ""
},
{
"term": "Show Power Actions",
"context": "Show Power Actions",
"reference": "Modals/Settings/PowerSettings.qml:57",
"comment": ""
},
{
"term": "Show Power Off",
"context": "Show Power Off",
"reference": "Modals/Settings/PowerSettings.qml:428",
"comment": ""
},
{
"term": "Show Reboot",
"context": "Show Reboot",
"reference": "Modals/Settings/PowerSettings.qml:398",
"comment": ""
},
{
"term": "Show Restart DMS",
"context": "Show Restart DMS",
"reference": "Modals/Settings/PowerSettings.qml:473",
"comment": ""
},
{
"term": "Show Suspend",
"context": "Show Suspend",
"reference": "Modals/Settings/PowerSettings.qml:458",
"comment": ""
},
{
"term": "Show Workspace Apps",
"context": "Show Workspace Apps",
@@ -3308,7 +3392,7 @@
{
"term": "Show all 9 tags instead of only occupied tags (DWL only)",
"context": "Show all 9 tags instead of only occupied tags (DWL only)",
"reference": "Modules/Settings/WidgetTweaksTab.qml:145",
"reference": "Modules/Settings/WidgetTweaksTab.qml:146",
"comment": ""
},
{
@@ -3344,13 +3428,13 @@
{
"term": "Show only apps running in current workspace",
"context": "Show only apps running in current workspace",
"reference": "Modules/Settings/WidgetTweaksTab.qml:389",
"reference": "Modules/Settings/WidgetTweaksTab.qml:391",
"comment": ""
},
{
"term": "Show only workspaces belonging to each specific monitor.",
"context": "Show only workspaces belonging to each specific monitor.",
"reference": "Modules/Settings/WidgetTweaksTab.qml:135",
"reference": "Modules/Settings/WidgetTweaksTab.qml:136",
"comment": ""
},
{
@@ -3500,7 +3584,7 @@
{
"term": "Support Development",
"context": "Support Development",
"reference": "Modules/Settings/AboutTab.qml:583",
"reference": "Modules/Settings/AboutTab.qml:627",
"comment": ""
},
{
@@ -3512,7 +3596,7 @@
{
"term": "Suspend",
"context": "Suspend",
"reference": "Modals/PowerMenuModal.qml:41, Modals/PowerMenuModal.qml:259, Modules/Lock/LockPowerMenu.qml:260, Modules/ControlCenter/PowerMenu.qml:15",
"reference": "Modals/PowerMenuModal.qml:111, Modals/PowerMenuModal.qml:153, Modules/Lock/LockPowerMenu.qml:260, Modules/ControlCenter/PowerMenu.qml:15",
"comment": ""
},
{
@@ -3578,7 +3662,7 @@
{
"term": "System Monitoring:",
"context": "System Monitoring:",
"reference": "Modules/Settings/AboutTab.qml:517",
"reference": "Modules/Settings/AboutTab.qml:561",
"comment": ""
},
{
@@ -3596,7 +3680,7 @@
{
"term": "System Updater",
"context": "System Updater",
"reference": "Modules/Settings/WidgetTweaksTab.qml:230",
"reference": "Modules/Settings/WidgetTweaksTab.qml:231",
"comment": ""
},
{
@@ -3632,7 +3716,7 @@
{
"term": "System update custom command",
"context": "System update custom command",
"reference": "Modules/Settings/WidgetTweaksTab.qml:266",
"reference": "Modules/Settings/WidgetTweaksTab.qml:267",
"comment": ""
},
{
@@ -3644,7 +3728,7 @@
{
"term": "Terminal custom additional parameters",
"context": "Terminal custom additional parameters",
"reference": "Modules/Settings/WidgetTweaksTab.qml:313",
"reference": "Modules/Settings/WidgetTweaksTab.qml:314",
"comment": ""
},
{
@@ -3686,13 +3770,13 @@
{
"term": "Third-Party Plugin Warning",
"context": "Third-Party Plugin Warning",
"reference": "Modules/Settings/PluginBrowser.qml:581",
"reference": "Modules/Settings/PluginBrowser.qml:601",
"comment": ""
},
{
"term": "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\\n\\nThese plugins may pose security and privacy risks - install at your own risk.",
"context": "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\\n\\nThese plugins may pose security and privacy risks - install at your own risk.",
"reference": "Modules/Settings/PluginBrowser.qml:591",
"reference": "Modules/Settings/PluginBrowser.qml:611",
"comment": ""
},
{
@@ -3728,7 +3812,7 @@
{
"term": "To update, run the following command:",
"context": "To update, run the following command:",
"reference": "Services/DMSService.qml:298",
"reference": "Services/DMSService.qml:301",
"comment": ""
},
{
@@ -3806,7 +3890,7 @@
{
"term": "Unpin from Dock",
"context": "Unpin from Dock",
"reference": "Modals/Spotlight/SpotlightContextMenu.qml:113, Modules/AppDrawer/AppDrawerPopout.qml:609, Modules/Dock/DockContextMenu.qml:370",
"reference": "Modals/Spotlight/SpotlightContextMenu.qml:113, Modules/AppDrawer/AppDrawerPopout.qml:609, Modules/Dock/DockContextMenu.qml:373",
"comment": ""
},
{
@@ -3854,7 +3938,7 @@
{
"term": "Use Custom Command",
"context": "Use Custom Command",
"reference": "Modules/Settings/WidgetTweaksTab.qml:240",
"reference": "Modules/Settings/WidgetTweaksTab.qml:241",
"comment": ""
},
{
@@ -3890,13 +3974,13 @@
{
"term": "Use animated wave progress bars for media playback",
"context": "Use animated wave progress bars for media playback",
"reference": "Modules/Settings/WidgetTweaksTab.qml:194",
"reference": "Modules/Settings/WidgetTweaksTab.qml:195",
"comment": ""
},
{
"term": "Use custom command for update your system",
"context": "Use custom command for update your system",
"reference": "Modules/Settings/WidgetTweaksTab.qml:241",
"reference": "Modules/Settings/WidgetTweaksTab.qml:242",
"comment": ""
},
{
@@ -4034,7 +4118,7 @@
{
"term": "Wave Progress Bars",
"context": "Wave Progress Bars",
"reference": "Modules/Settings/WidgetTweaksTab.qml:193",
"reference": "Modules/Settings/WidgetTweaksTab.qml:194",
"comment": ""
},
{
@@ -4052,7 +4136,7 @@
{
"term": "Website:",
"context": "Website:",
"reference": "Modules/Settings/AboutTab.qml:436",
"reference": "Modules/Settings/AboutTab.qml:480",
"comment": ""
},
{
@@ -4178,7 +4262,7 @@
{
"term": "official",
"context": "official",
"reference": "Modules/Settings/PluginBrowser.qml:388",
"reference": "Modules/Settings/PluginBrowser.qml:408",
"comment": ""
},
{
@@ -4190,7 +4274,7 @@
{
"term": "• Install only from trusted sources",
"context": "• Install only from trusted sources",
"reference": "Modules/Settings/PluginBrowser.qml:614",
"reference": "Modules/Settings/PluginBrowser.qml:634",
"comment": ""
},
{
@@ -4220,13 +4304,13 @@
{
"term": "• Plugins may contain bugs or security issues",
"context": "• Plugins may contain bugs or security issues",
"reference": "Modules/Settings/PluginBrowser.qml:602",
"reference": "Modules/Settings/PluginBrowser.qml:622",
"comment": ""
},
{
"term": "• Review code before installation when possible",
"context": "• Review code before installation when possible",
"reference": "Modules/Settings/PluginBrowser.qml:608",
"reference": "Modules/Settings/PluginBrowser.qml:628",
"comment": ""
},
{

View File

@@ -89,9 +89,6 @@
"Applications": {
"Applications": "Applicazioni"
},
"Apply": {
"Apply": "Applica"
},
"Apply GTK Colors": {
"Apply GTK Colors": "Applica Colori GTK"
},
@@ -167,9 +164,6 @@
"Auto-hide Dock": {
"Auto-hide Dock": "Nascondi automaticamente Dock"
},
"Auto-location": {
"Auto-location": "Localizzazione automatica"
},
"Auto-saving...": {
"Auto-saving...": "Salvataggio automatico..."
},
@@ -230,9 +224,6 @@
"Battery level and power management": {
"Battery level and power management": "Livello batteria e gestione energetica"
},
"Battery not detected - only AC power settings available": {
"Battery not detected - only AC power settings available": "Batteria non rilevata - disponibili solo impostazioni di alimentazione di rete"
},
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": {
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Collega il blocca schermo ai segnali dbus da loginctl.\nDisabilità se stai usando un blocca schermo esterno"
},
@@ -398,9 +389,6 @@
"Compositor": {
"Compositor": "Compositor\n"
},
"Compositor:": {
"Compositor:": "Compositor:"
},
"Configuration activated": {
"Configuration activated": "Configurazione attivata"
},
@@ -434,9 +422,6 @@
"Connecting to Device": {
"Connecting to Device": "Connessione al Dispositivo"
},
"Connection failed. Check password and try again.": {
"Connection failed. Check password and try again.": "Connessione fallita. Controlla la password e riprova"
},
"Contrast": {
"Contrast": "Contrasto"
},
@@ -461,9 +446,6 @@
"Copied!": {
"Copied!": "Copiato!"
},
"Copy": {
"Copy": "Copia"
},
"Copy PID": {
"Copy PID": "Copia PID"
},
@@ -515,6 +497,9 @@
"Customizable empty space": {
"Customizable empty space": "Spazio vuoto personalizzabile"
},
"Customize which actions appear in the power menu": {
"Customize which actions appear in the power menu": ""
},
"DEMO MODE - Click anywhere to exit": {
"DEMO MODE - Click anywhere to exit": "DEMO MODE - Clicca ovunque per uscire"
},
@@ -542,9 +527,6 @@
"Dank Bar Widget Transparency": {
"Dank Bar Widget Transparency": "Trasparenza Widget Dank Bar"
},
"Dank Suite:": {
"Dank Suite:": "Dank Suite:"
},
"DankBar Font Scale": {
"DankBar Font Scale": "Scala Font DankBar"
},
@@ -566,6 +548,9 @@
"Default": {
"Default": "Predefinito"
},
"Default selected action": {
"Default selected action": ""
},
"Defaults": {
"Defaults": "Predefiniti"
},
@@ -842,9 +827,6 @@
"Format Legend": {
"Format Legend": "Legenda Formato"
},
"Framework:": {
"Framework:": "Framework:"
},
"Fun": {
"Fun": "Svago"
},
@@ -866,9 +848,6 @@
"Gamma control not available. Requires DMS API v6+.": {
"Gamma control not available. Requires DMS API v6+.": "Gamma control non disponibile. Richiede API DMS v6+."
},
"Geoclue service not running - cannot auto-detect location": {
"Geoclue service not running - cannot auto-detect location": "Il servizio Geoclue non è in esecuzione - non può determinare la posizione automaticamente"
},
"Github:": {
"Github:": "Github:"
},
@@ -902,15 +881,9 @@
"Hex": {
"Hex": "Hex"
},
"Hex:": {
"Hex:": "Hex:"
},
"Hibernate": {
"Hibernate": "Iberna"
},
"Hibernate system after": {
"Hibernate system after": "Iberna sistema dopo"
},
"Hide the dock when not in use and reveal it when hovering near the dock area": {
"Hide the dock when not in use and reveal it when hovering near the dock area": "Nascondi la dock quando "
},
@@ -1001,9 +974,6 @@
"Kill Process": {
"Kill Process": "Chiusura Processo"
},
"Language:": {
"Language:": "Lingua:"
},
"Last launched %1": {
"Last launched %1": "Ultimo avviato %1"
},
@@ -1058,6 +1028,9 @@
"Location Search": {
"Location Search": "Ricerca Posizione"
},
"Lock": {
"Lock": ""
},
"Lock Screen": {
"Lock Screen": "Blocca Schermo"
},
@@ -1166,9 +1139,6 @@
"Mode: ": {
"Mode: ": ""
},
"Monitor": {
"Monitor": "Monitor"
},
"Monitor Selection:": {
"Monitor Selection:": "Selezione Monitor:"
},
@@ -1328,6 +1298,9 @@
"Only adjust gamma based on time or location rules.": {
"Only adjust gamma based on time or location rules.": "Regolare gamma solo in base alle regole di tempo o di posizione."
},
"Only visible if hibernate is supported by your system": {
"Only visible if hibernate is supported by your system": ""
},
"Opacity": {
"Opacity": "Opacità"
},
@@ -1457,6 +1430,9 @@
"Power Action Confirmation": {
"Power Action Confirmation": "Conferma Azioni Alimentazione"
},
"Power Menu Customization": {
"Power Menu Customization": ""
},
"Power Off": {
"Power Off": "Spegni"
},
@@ -1502,9 +1478,6 @@
"Profile image is too large. Please use a smaller image.": {
"Profile image is too large. Please use a smaller image.": "Immagine profilo troppo grande. Per favore usa un'immagine più piccola"
},
"QML, JavaScript, Go": {
"QML, JavaScript, Go": "\nQML, JavaScript, Go"
},
"Quick access to application launcher": {
"Quick access to application launcher": "Accesso veloce al launcher applicazioni"
},
@@ -1556,6 +1529,15 @@
"Resources": {
"Resources": "Risorse"
},
"Restart": {
"Restart": ""
},
"Restart DMS": {
"Restart DMS": ""
},
"Restart the DankMaterialShell": {
"Restart the DankMaterialShell": ""
},
"Resume": {
"Resume": "Riprendi"
},
@@ -1604,9 +1586,6 @@
"Science": {
"Science": "Scienza"
},
"Scroll through windows, rather than workspaces": {
"Scroll through windows, rather than workspaces": "Scorri tra le finestre, piuttosto che i workspaces"
},
"Search file contents": {
"Search file contents": "Cerca il contenuto dei files"
},
@@ -1688,12 +1667,33 @@
"Show Dock": {
"Show Dock": "Mostra Dock"
},
"Show Hibernate": {
"Show Hibernate": ""
},
"Show Line Numbers": {
"Show Line Numbers": "Mostra Numero Righe"
},
"Show Lock": {
"Show Lock": ""
},
"Show Log Out": {
"Show Log Out": ""
},
"Show Power Actions": {
"Show Power Actions": "Mostra Azioni Alimentazione"
},
"Show Power Off": {
"Show Power Off": ""
},
"Show Reboot": {
"Show Reboot": ""
},
"Show Restart DMS": {
"Show Restart DMS": ""
},
"Show Suspend": {
"Show Suspend": ""
},
"Show Workspace Apps": {
"Show Workspace Apps": "Mostra Apps Workspace"
},
@@ -1865,12 +1865,6 @@
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": {
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: Nav • ←→↑↓: Griglia Nav • Enter/Spazio: Seleziona"
},
"Technical Details": {
"Technical Details": "Dettagli Tecnici"
},
"Temperature": {
"Temperature": "Temperatura"
},
"Terminal custom additional parameters": {
"Terminal custom additional parameters": "Parametri aggiuntivi personalizzati terminale"
},
@@ -1997,9 +1991,6 @@
"Use animated wave progress bars for media playback": {
"Use animated wave progress bars for media playback": "Usa barre ad onde animate per la riproduzione media"
},
"Use automatic location detection (geoclue2)": {
"Use automatic location detection (geoclue2)": "Usa il rilevamento automatico della posizione (geoclue2)"
},
"Use custom command for update your system": {
"Use custom command for update your system": "Usa comando personalizzato per aggiornare il sistema"
},
@@ -2105,9 +2096,6 @@
"Wind": {
"Wind": "Vento"
},
"Window Scrolling": {
"Window Scrolling": "Scorrimento Finestra"
},
"Workspace": {
"Workspace": "Workspace"
},

View File

@@ -89,9 +89,6 @@
"Applications": {
"Applications": "アプリ"
},
"Apply": {
"Apply": "適用"
},
"Apply GTK Colors": {
"Apply GTK Colors": "GTKカラーを適用"
},
@@ -167,9 +164,6 @@
"Auto-hide Dock": {
"Auto-hide Dock": "ドックを自動的に隠す"
},
"Auto-location": {
"Auto-location": "自動位置特定"
},
"Auto-saving...": {
"Auto-saving...": "自動保存中..."
},
@@ -230,9 +224,6 @@
"Battery level and power management": {
"Battery level and power management": "バッテリーレベルおよび電源管理"
},
"Battery not detected - only AC power settings available": {
"Battery not detected - only AC power settings available": "バッテリーが検出されません - AC電源設定のみ利用可能です"
},
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": {
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "ロック画面をloginctlからのdbus信号にバインド。外部ロック画面を使用している場合は無効に"
},
@@ -312,7 +303,7 @@
"Center Section": "センターセクション"
},
"Changes:": {
"Changes:": ""
"Changes:": "変更:"
},
"Check for system updates": {
"Check for system updates": "システムアップデートを検査"
@@ -398,9 +389,6 @@
"Compositor": {
"Compositor": "コンポジター"
},
"Compositor:": {
"Compositor:": "コンポジター:"
},
"Configuration activated": {
"Configuration activated": "設定が適用されました"
},
@@ -414,7 +402,7 @@
"Confirm": "確認"
},
"Confirm Display Changes": {
"Confirm Display Changes": ""
"Confirm Display Changes": "表示変更を確認"
},
"Confirm passkey for ": {
"Confirm passkey for ": "パスキーを確認 "
@@ -434,9 +422,6 @@
"Connecting to Device": {
"Connecting to Device": "デバイスに接続中"
},
"Connection failed. Check password and try again.": {
"Connection failed. Check password and try again.": "接続に失敗しました。パスワードを確認して、もう一度やり直してください。"
},
"Contrast": {
"Contrast": "コントラスト"
},
@@ -461,9 +446,6 @@
"Copied!": {
"Copied!": "コピーしました!"
},
"Copy": {
"Copy": "コピー"
},
"Copy PID": {
"Copy PID": "PIDをコピー"
},
@@ -515,6 +497,9 @@
"Customizable empty space": {
"Customizable empty space": "カスタマイズ可能な空きスペース"
},
"Customize which actions appear in the power menu": {
"Customize which actions appear in the power menu": ""
},
"DEMO MODE - Click anywhere to exit": {
"DEMO MODE - Click anywhere to exit": "デモモード -任意の場所をクリックして 終了"
},
@@ -542,9 +527,6 @@
"Dank Bar Widget Transparency": {
"Dank Bar Widget Transparency": "Dank Barウィジェットの透明度"
},
"Dank Suite:": {
"Dank Suite:": "Dankスイート"
},
"DankBar Font Scale": {
"DankBar Font Scale": "Dank Bar フォントスケール"
},
@@ -566,6 +548,9 @@
"Default": {
"Default": "デフォルト"
},
"Default selected action": {
"Default selected action": ""
},
"Defaults": {
"Defaults": "デフォルト"
},
@@ -591,7 +576,7 @@
"Disable Autoconnect": "自動接続を無効"
},
"Disabled": {
"Disabled": ""
"Disabled": "無効化されました"
},
"Disconnect": {
"Disconnect": "切断"
@@ -621,7 +606,7 @@
"Display currently focused application title": "現在フォーカスされているアプリケーションのタイトルを表示"
},
"Display settings for ": {
"Display settings for ": ""
"Display settings for ": "以下の設定を表示 "
},
"Display volume and brightness percentage values by default in OSD popups": {
"Display volume and brightness percentage values by default in OSD popups": "OSDポップアップに音量と輝度のパーセンテージ値をデフォルトで表示"
@@ -699,7 +684,7 @@
"Enable loginctl lock integration": "ログインロックの統合を有効に"
},
"Enabled": {
"Enabled": ""
"Enabled": "有効化されました"
},
"End": {
"End": "終わり"
@@ -842,9 +827,6 @@
"Format Legend": {
"Format Legend": "フォーマット凡例"
},
"Framework:": {
"Framework:": "フレームワーク:"
},
"Fun": {
"Fun": "娯楽"
},
@@ -866,9 +848,6 @@
"Gamma control not available. Requires DMS API v6+.": {
"Gamma control not available. Requires DMS API v6+.": "ガンマ制御は使用できません。DMS API v6+ が必要です。"
},
"Geoclue service not running - cannot auto-detect location": {
"Geoclue service not running - cannot auto-detect location": "ジオクルー サービスが実行されていない - 位置を自動検出できません"
},
"Github:": {
"Github:": "GitHub:"
},
@@ -902,15 +881,9 @@
"Hex": {
"Hex": "16進数"
},
"Hex:": {
"Hex:": "16進数:"
},
"Hibernate": {
"Hibernate": "休止状態"
},
"Hibernate system after": {
"Hibernate system after": "後にシステムを休止状態"
},
"Hide the dock when not in use and reveal it when hovering near the dock area": {
"Hide the dock when not in use and reveal it when hovering near the dock area": "使用していないときはドックを非表示にし、ドックエリアの近くにホバーすると表示されます"
},
@@ -966,7 +939,7 @@
"Individual Batteries": "バッテリーごと"
},
"Inhibit idle timeout when audio or video is playing": {
"Inhibit idle timeout when audio or video is playing": ""
"Inhibit idle timeout when audio or video is playing": "オーディオまたはビデオの再生中のアイドルタイムアウトを禁止"
},
"Input Devices": {
"Input Devices": "入力デバイス"
@@ -993,7 +966,7 @@
"Jobs: ": "ジョブ: "
},
"Keep Changes": {
"Keep Changes": ""
"Keep Changes": "変更を保持"
},
"Keyboard Layout Name": {
"Keyboard Layout Name": "キーボードレイアウト名"
@@ -1001,9 +974,6 @@
"Kill Process": {
"Kill Process": "プロセスを強制終了"
},
"Language:": {
"Language:": "言語:"
},
"Last launched %1": {
"Last launched %1": "最終起動日 %1"
},
@@ -1058,6 +1028,9 @@
"Location Search": {
"Location Search": "ロケーション検索"
},
"Lock": {
"Lock": "ロック"
},
"Lock Screen": {
"Lock Screen": "ロック画面"
},
@@ -1164,10 +1137,7 @@
"Mode:": "モード:"
},
"Mode: ": {
"Mode: ": ""
},
"Monitor": {
"Monitor": "モニター"
"Mode: ": "モード: "
},
"Monitor Selection:": {
"Monitor Selection:": "モニターの選択:"
@@ -1328,6 +1298,9 @@
"Only adjust gamma based on time or location rules.": {
"Only adjust gamma based on time or location rules.": "ガンマは、時間または場所のルールに基づいてのみ調整します。"
},
"Only visible if hibernate is supported by your system": {
"Only visible if hibernate is supported by your system": ""
},
"Opacity": {
"Opacity": "不透明度"
},
@@ -1449,7 +1422,7 @@
"Position": "位置"
},
"Position: ": {
"Position: ": ""
"Position: ": "位置: "
},
"Power & Security": {
"Power & Security": "電源とセキュリティ"
@@ -1457,6 +1430,9 @@
"Power Action Confirmation": {
"Power Action Confirmation": "電源アクションの確認"
},
"Power Menu Customization": {
"Power Menu Customization": ""
},
"Power Off": {
"Power Off": "電源オフ"
},
@@ -1470,7 +1446,7 @@
"Pressure": "プレッシャー"
},
"Prevent idle for media": {
"Prevent idle for media": ""
"Prevent idle for media": "メディアのアイドル状態を防止"
},
"Prevent screen timeout": {
"Prevent screen timeout": "画面のタイムアウトを防止"
@@ -1502,9 +1478,6 @@
"Profile image is too large. Please use a smaller image.": {
"Profile image is too large. Please use a smaller image.": "プロフィール画像が大きすぎます。より小さい画像を使用してください。"
},
"QML, JavaScript, Go": {
"QML, JavaScript, Go": "QML, JavaScript, Go"
},
"Quick access to application launcher": {
"Quick access to application launcher": "アプリケーションランチャーへのクイックアクセス"
},
@@ -1556,14 +1529,23 @@
"Resources": {
"Resources": "リソース"
},
"Restart": {
"Restart": "再起動"
},
"Restart DMS": {
"Restart DMS": ""
},
"Restart the DankMaterialShell": {
"Restart the DankMaterialShell": ""
},
"Resume": {
"Resume": "レジュメ"
},
"Revert": {
"Revert": ""
"Revert": "戻す"
},
"Reverting in:": {
"Reverting in:": ""
"Reverting in:": "元に戻す:"
},
"Right": {
"Right": "右"
@@ -1604,9 +1586,6 @@
"Science": {
"Science": "科学"
},
"Scroll through windows, rather than workspaces": {
"Scroll through windows, rather than workspaces": "ワークスペースではなくウィンドウをスクロール"
},
"Search file contents": {
"Search file contents": "ファイルの内容を検索"
},
@@ -1688,12 +1667,33 @@
"Show Dock": {
"Show Dock": "ドックを表示"
},
"Show Hibernate": {
"Show Hibernate": ""
},
"Show Line Numbers": {
"Show Line Numbers": "行番号を表示"
},
"Show Lock": {
"Show Lock": ""
},
"Show Log Out": {
"Show Log Out": ""
},
"Show Power Actions": {
"Show Power Actions": "電源アクションを表示"
},
"Show Power Off": {
"Show Power Off": ""
},
"Show Reboot": {
"Show Reboot": ""
},
"Show Restart DMS": {
"Show Restart DMS": ""
},
"Show Suspend": {
"Show Suspend": ""
},
"Show Workspace Apps": {
"Show Workspace Apps": "ワークスペースアプリを表示"
},
@@ -1865,12 +1865,6 @@
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": {
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: ナビゲーション • ←→↑↓: グリッドナビゲーション • Enter/Space: 選択"
},
"Technical Details": {
"Technical Details": "技術的な詳細"
},
"Temperature": {
"Temperature": "温度"
},
"Terminal custom additional parameters": {
"Terminal custom additional parameters": "端末のカスタム追加パラメーター"
},
@@ -1997,9 +1991,6 @@
"Use animated wave progress bars for media playback": {
"Use animated wave progress bars for media playback": "アニメーション化されたウェーブの進行状況バーをメディア再生に使用"
},
"Use automatic location detection (geoclue2)": {
"Use automatic location detection (geoclue2)": "自動位置検出 (geoclue2) を使用"
},
"Use custom command for update your system": {
"Use custom command for update your system": "カスタムコマンドを使用してシステムを更新"
},
@@ -2037,7 +2028,7 @@
"VPN status and quick connect": "VPNステータスとクイック接続"
},
"VRR: ": {
"VRR: ": ""
"VRR: ": "VRR: "
},
"Vibrant palette with playful saturation.": {
"Vibrant palette with playful saturation.": "遊び心のある彩度の鮮やかなパレット。"
@@ -2105,9 +2096,6 @@
"Wind": {
"Wind": "風"
},
"Window Scrolling": {
"Window Scrolling": "ウィンドウスクロール"
},
"Workspace": {
"Workspace": "ワークスペース"
},

View File

@@ -89,9 +89,6 @@
"Applications": {
"Applications": "Aplikacje"
},
"Apply": {
"Apply": "Zastosuj"
},
"Apply GTK Colors": {
"Apply GTK Colors": "Zastosuj kolory GTK"
},
@@ -167,9 +164,6 @@
"Auto-hide Dock": {
"Auto-hide Dock": "Automatyczne ukrywanie doku"
},
"Auto-location": {
"Auto-location": "Automatyczna lokalizacja"
},
"Auto-saving...": {
"Auto-saving...": "Automatyczne zapisywanie..."
},
@@ -230,9 +224,6 @@
"Battery level and power management": {
"Battery level and power management": "Poziom baterii i zarządzanie zasilaniem"
},
"Battery not detected - only AC power settings available": {
"Battery not detected - only AC power settings available": "Nie wykryto baterii - dostępne tylko ustawienia po podłączeniu do zasilacza"
},
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": {
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Powiąż ekran blokady z sygnałami dbus z loginctl. Wyłącz, jeśli używasz zewnętrznego ekranu blokady"
},
@@ -398,9 +389,6 @@
"Compositor": {
"Compositor": "Kompozytor"
},
"Compositor:": {
"Compositor:": "Kompozytor:"
},
"Configuration activated": {
"Configuration activated": "Konfiguracja aktywowana"
},
@@ -434,9 +422,6 @@
"Connecting to Device": {
"Connecting to Device": "Łączenie z urządzeniem"
},
"Connection failed. Check password and try again.": {
"Connection failed. Check password and try again.": "Połączenie nieudane. Sprawdź hasło i spróbuj ponownie."
},
"Contrast": {
"Contrast": "Kontrast"
},
@@ -461,9 +446,6 @@
"Copied!": {
"Copied!": "Skopiowane!"
},
"Copy": {
"Copy": "Kopiuj"
},
"Copy PID": {
"Copy PID": "Kopiuj PID"
},
@@ -515,6 +497,9 @@
"Customizable empty space": {
"Customizable empty space": "Dostosowywalna pusta przestrzeń"
},
"Customize which actions appear in the power menu": {
"Customize which actions appear in the power menu": ""
},
"DEMO MODE - Click anywhere to exit": {
"DEMO MODE - Click anywhere to exit": "TRYB DEMO - Kliknij gdziekolwiek aby wyjść"
},
@@ -542,9 +527,6 @@
"Dank Bar Widget Transparency": {
"Dank Bar Widget Transparency": "Przezroczystość widżetu Dank Bar"
},
"Dank Suite:": {
"Dank Suite:": "Dank Suite:"
},
"DankBar Font Scale": {
"DankBar Font Scale": "Skala czcionki DankBar"
},
@@ -566,6 +548,9 @@
"Default": {
"Default": "Domyślne"
},
"Default selected action": {
"Default selected action": ""
},
"Defaults": {
"Defaults": "Domyślne"
},
@@ -842,9 +827,6 @@
"Format Legend": {
"Format Legend": "Legenda formatowania"
},
"Framework:": {
"Framework:": "Framework:"
},
"Fun": {
"Fun": "Zabawa"
},
@@ -866,9 +848,6 @@
"Gamma control not available. Requires DMS API v6+.": {
"Gamma control not available. Requires DMS API v6+.": "Kontrola gamma niedostępna. Wymaga DMS API w wersji 6+."
},
"Geoclue service not running - cannot auto-detect location": {
"Geoclue service not running - cannot auto-detect location": "Usługa Geoclue nie działa - nie można automatycznie wykryć lokalizacji"
},
"Github:": {
"Github:": "Github:"
},
@@ -902,15 +881,9 @@
"Hex": {
"Hex": ""
},
"Hex:": {
"Hex:": "Hex:"
},
"Hibernate": {
"Hibernate": "Hibernacja"
},
"Hibernate system after": {
"Hibernate system after": "Hibernuj komputer po"
},
"Hide the dock when not in use and reveal it when hovering near the dock area": {
"Hide the dock when not in use and reveal it when hovering near the dock area": "Ukryj dok, gdy nie jest używany, i odkryj go po najechaniu kursorem w jego pobliże"
},
@@ -1001,9 +974,6 @@
"Kill Process": {
"Kill Process": "Zabij proces"
},
"Language:": {
"Language:": "Język:"
},
"Last launched %1": {
"Last launched %1": "Ostatnio uruchomiony %1"
},
@@ -1058,6 +1028,9 @@
"Location Search": {
"Location Search": "Wyszukiwanie lokalizacji"
},
"Lock": {
"Lock": ""
},
"Lock Screen": {
"Lock Screen": "Ekran blokady"
},
@@ -1166,9 +1139,6 @@
"Mode: ": {
"Mode: ": ""
},
"Monitor": {
"Monitor": "Monitor"
},
"Monitor Selection:": {
"Monitor Selection:": "Wybór monitora:"
},
@@ -1328,6 +1298,9 @@
"Only adjust gamma based on time or location rules.": {
"Only adjust gamma based on time or location rules.": "Dostosuj gamma tylko na podstawie reguł czasu lub lokalizacji."
},
"Only visible if hibernate is supported by your system": {
"Only visible if hibernate is supported by your system": ""
},
"Opacity": {
"Opacity": "Przezroczystość"
},
@@ -1457,6 +1430,9 @@
"Power Action Confirmation": {
"Power Action Confirmation": "Potwierdzenie działania zasilania"
},
"Power Menu Customization": {
"Power Menu Customization": ""
},
"Power Off": {
"Power Off": "Wyłącz komputer"
},
@@ -1502,9 +1478,6 @@
"Profile image is too large. Please use a smaller image.": {
"Profile image is too large. Please use a smaller image.": "Zdjęcie profilowe jest za duże. Użyj mniejszego zdjęcia."
},
"QML, JavaScript, Go": {
"QML, JavaScript, Go": "QML, JavaScript, Go"
},
"Quick access to application launcher": {
"Quick access to application launcher": "Szybki dostęp do uruchamiania aplikacji"
},
@@ -1556,6 +1529,15 @@
"Resources": {
"Resources": "Źródła"
},
"Restart": {
"Restart": ""
},
"Restart DMS": {
"Restart DMS": ""
},
"Restart the DankMaterialShell": {
"Restart the DankMaterialShell": ""
},
"Resume": {
"Resume": "Wznów"
},
@@ -1604,9 +1586,6 @@
"Science": {
"Science": "Nauka"
},
"Scroll through windows, rather than workspaces": {
"Scroll through windows, rather than workspaces": "Przewijaj okna zamiast obszarów roboczych"
},
"Search file contents": {
"Search file contents": "Przeszukaj zawartość plików"
},
@@ -1688,12 +1667,33 @@
"Show Dock": {
"Show Dock": "Pokaż dok"
},
"Show Hibernate": {
"Show Hibernate": ""
},
"Show Line Numbers": {
"Show Line Numbers": "Pokaż numery wierszy"
},
"Show Lock": {
"Show Lock": ""
},
"Show Log Out": {
"Show Log Out": ""
},
"Show Power Actions": {
"Show Power Actions": "Pokaż akcje zasilania"
},
"Show Power Off": {
"Show Power Off": ""
},
"Show Reboot": {
"Show Reboot": ""
},
"Show Restart DMS": {
"Show Restart DMS": ""
},
"Show Suspend": {
"Show Suspend": ""
},
"Show Workspace Apps": {
"Show Workspace Apps": "Pokaż aplikacje z obszaru roboczego"
},
@@ -1865,12 +1865,6 @@
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": {
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: Nawigacja • ←→↑↓: Nawigacja po siatce • Enter/Spacja: Wybierz"
},
"Technical Details": {
"Technical Details": "Szczegóły techniczne"
},
"Temperature": {
"Temperature": "Temperatura"
},
"Terminal custom additional parameters": {
"Terminal custom additional parameters": "Niestandardowe dodatkowe parametry terminala"
},
@@ -1997,9 +1991,6 @@
"Use animated wave progress bars for media playback": {
"Use animated wave progress bars for media playback": "Używaj animowanych pasków postępu fali do odtwarzania multimediów"
},
"Use automatic location detection (geoclue2)": {
"Use automatic location detection (geoclue2)": "Użyj automatycznego wykrywania lokalizacji (geoclue2)"
},
"Use custom command for update your system": {
"Use custom command for update your system": "Użyj niestandardowego polecenia do aktualizacji systemu"
},
@@ -2105,9 +2096,6 @@
"Wind": {
"Wind": "Wiatr"
},
"Window Scrolling": {
"Window Scrolling": "Przewijanie okna"
},
"Workspace": {
"Workspace": "Obszar roboczy"
},

View File

@@ -89,9 +89,6 @@
"Applications": {
"Applications": "Aplicativos"
},
"Apply": {
"Apply": "Aplicar"
},
"Apply GTK Colors": {
"Apply GTK Colors": "Aplicar cores no GTK"
},
@@ -167,9 +164,6 @@
"Auto-hide Dock": {
"Auto-hide Dock": "Esconder Automaticamente o Dock"
},
"Auto-location": {
"Auto-location": "Localização-Automática"
},
"Auto-saving...": {
"Auto-saving...": "Salvando automáticamente..."
},
@@ -230,9 +224,6 @@
"Battery level and power management": {
"Battery level and power management": "Nível de bateria e manejamento de energia"
},
"Battery not detected - only AC power settings available": {
"Battery not detected - only AC power settings available": "Bateria não detectada - apenas configurações de tomada disponíveis"
},
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": {
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Vincular o bloqueio de tela aos sinais do DBus do loginctl. Desative se estiver usando um bloqueio de tela externo"
},
@@ -398,9 +389,6 @@
"Compositor": {
"Compositor": "Compositor"
},
"Compositor:": {
"Compositor:": "Compositor:"
},
"Configuration activated": {
"Configuration activated": "Configuração ativada"
},
@@ -434,9 +422,6 @@
"Connecting to Device": {
"Connecting to Device": ""
},
"Connection failed. Check password and try again.": {
"Connection failed. Check password and try again.": "Erro ao conectar. Cheque a senha e tente novamente."
},
"Contrast": {
"Contrast": "Contraste"
},
@@ -461,9 +446,6 @@
"Copied!": {
"Copied!": "Copiado!"
},
"Copy": {
"Copy": "Copiar"
},
"Copy PID": {
"Copy PID": "Copiar PID"
},
@@ -515,6 +497,9 @@
"Customizable empty space": {
"Customizable empty space": "Espaço vazio customizável"
},
"Customize which actions appear in the power menu": {
"Customize which actions appear in the power menu": ""
},
"DEMO MODE - Click anywhere to exit": {
"DEMO MODE - Click anywhere to exit": "MODO DEMONSTRAÇÃO - Clique em qualquer lugar para sair"
},
@@ -542,9 +527,6 @@
"Dank Bar Widget Transparency": {
"Dank Bar Widget Transparency": "Transparência dos Widgets da Dank Bar"
},
"Dank Suite:": {
"Dank Suite:": "Suíte Dank:"
},
"DankBar Font Scale": {
"DankBar Font Scale": "Escala das fontes no Dank Bar"
},
@@ -566,6 +548,9 @@
"Default": {
"Default": "Padrão"
},
"Default selected action": {
"Default selected action": ""
},
"Defaults": {
"Defaults": "Padrões"
},
@@ -842,9 +827,6 @@
"Format Legend": {
"Format Legend": "Formatar Legenda"
},
"Framework:": {
"Framework:": "Estrutura:"
},
"Fun": {
"Fun": "Diversão"
},
@@ -866,9 +848,6 @@
"Gamma control not available. Requires DMS API v6+.": {
"Gamma control not available. Requires DMS API v6+.": "Controle de gama não disponível. Necessário DMS API v6+."
},
"Geoclue service not running - cannot auto-detect location": {
"Geoclue service not running - cannot auto-detect location": "Serviço do Geoclue não está rodando - não foi possível detectar a localização automaticamente"
},
"Github:": {
"Github:": "Github:"
},
@@ -902,15 +881,9 @@
"Hex": {
"Hex": ""
},
"Hex:": {
"Hex:": "Hex:"
},
"Hibernate": {
"Hibernate": "Hibernar"
},
"Hibernate system after": {
"Hibernate system after": "Hibernar sistema após"
},
"Hide the dock when not in use and reveal it when hovering near the dock area": {
"Hide the dock when not in use and reveal it when hovering near the dock area": "Esconder a dock quando não usada e mostrar ao passar o mouse próximo da área"
},
@@ -1001,9 +974,6 @@
"Kill Process": {
"Kill Process": "Matar Processo"
},
"Language:": {
"Language:": "Linguagem:"
},
"Last launched %1": {
"Last launched %1": "Lançado pela última vez em %1"
},
@@ -1058,6 +1028,9 @@
"Location Search": {
"Location Search": "Procurar Localização"
},
"Lock": {
"Lock": ""
},
"Lock Screen": {
"Lock Screen": "Tela de Bloqueio"
},
@@ -1166,9 +1139,6 @@
"Mode: ": {
"Mode: ": ""
},
"Monitor": {
"Monitor": "Monitor"
},
"Monitor Selection:": {
"Monitor Selection:": "Seleção de Monitor:"
},
@@ -1328,6 +1298,9 @@
"Only adjust gamma based on time or location rules.": {
"Only adjust gamma based on time or location rules.": "Apenas ajustar gama baseada em regras de tempo ou localização."
},
"Only visible if hibernate is supported by your system": {
"Only visible if hibernate is supported by your system": ""
},
"Opacity": {
"Opacity": "Opacidade"
},
@@ -1457,6 +1430,9 @@
"Power Action Confirmation": {
"Power Action Confirmation": "Confirmação de Ação de Energia"
},
"Power Menu Customization": {
"Power Menu Customization": ""
},
"Power Off": {
"Power Off": "Desligar"
},
@@ -1502,9 +1478,6 @@
"Profile image is too large. Please use a smaller image.": {
"Profile image is too large. Please use a smaller image.": "A imagem de perfil é muito grande. Por favor use uma imagem menor."
},
"QML, JavaScript, Go": {
"QML, JavaScript, Go": "QML, JavaScript, Go"
},
"Quick access to application launcher": {
"Quick access to application launcher": "Acesso rápido ao lançador de aplicativos"
},
@@ -1556,6 +1529,15 @@
"Resources": {
"Resources": "Recursos"
},
"Restart": {
"Restart": ""
},
"Restart DMS": {
"Restart DMS": ""
},
"Restart the DankMaterialShell": {
"Restart the DankMaterialShell": ""
},
"Resume": {
"Resume": ""
},
@@ -1604,9 +1586,6 @@
"Science": {
"Science": "Ciência"
},
"Scroll through windows, rather than workspaces": {
"Scroll through windows, rather than workspaces": "Role pelas janelas, ao invés de áreas de trabalho"
},
"Search file contents": {
"Search file contents": "Pesquisar conteúdos de arquivos"
},
@@ -1688,12 +1667,33 @@
"Show Dock": {
"Show Dock": "Mostrar Dock"
},
"Show Hibernate": {
"Show Hibernate": ""
},
"Show Line Numbers": {
"Show Line Numbers": "Mostrar Numeração de Linha"
},
"Show Lock": {
"Show Lock": ""
},
"Show Log Out": {
"Show Log Out": ""
},
"Show Power Actions": {
"Show Power Actions": "Mostrar Ações de Energia"
},
"Show Power Off": {
"Show Power Off": ""
},
"Show Reboot": {
"Show Reboot": ""
},
"Show Restart DMS": {
"Show Restart DMS": ""
},
"Show Suspend": {
"Show Suspend": ""
},
"Show Workspace Apps": {
"Show Workspace Apps": "Mostrar Aplicativos da Área de Trabalho Virtual"
},
@@ -1865,12 +1865,6 @@
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": {
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: Navegação • ←→↑↓: Navegação em Grade • Enter/Espaço: Selecionar"
},
"Technical Details": {
"Technical Details": "Detalhes Técnicos"
},
"Temperature": {
"Temperature": "Temperatura"
},
"Terminal custom additional parameters": {
"Terminal custom additional parameters": "Parâmetros adicionais para o terminal"
},
@@ -1997,9 +1991,6 @@
"Use animated wave progress bars for media playback": {
"Use animated wave progress bars for media playback": "Usar barras de progresso de ondas animadas para reprodução de mídia"
},
"Use automatic location detection (geoclue2)": {
"Use automatic location detection (geoclue2)": "Usar detecção automática de localização (geoclue2)"
},
"Use custom command for update your system": {
"Use custom command for update your system": "Usar comando personalizado para atualizar seu sistema"
},
@@ -2105,9 +2096,6 @@
"Wind": {
"Wind": "Vento"
},
"Window Scrolling": {
"Window Scrolling": "Rolagem de Janelas"
},
"Workspace": {
"Workspace": "Área de Trabalho"
},

View File

@@ -89,9 +89,6 @@
"Applications": {
"Applications": "Uygulamalar"
},
"Apply": {
"Apply": "Uygula"
},
"Apply GTK Colors": {
"Apply GTK Colors": "GTK Renklerini Uygula"
},
@@ -167,9 +164,6 @@
"Auto-hide Dock": {
"Auto-hide Dock": "Dock'u Otomatik Gizle"
},
"Auto-location": {
"Auto-location": "Otomatik konum"
},
"Auto-saving...": {
"Auto-saving...": "Otomatik kaydetme..."
},
@@ -230,9 +224,6 @@
"Battery level and power management": {
"Battery level and power management": "Batarya seviyesi ve güç yönetimi"
},
"Battery not detected - only AC power settings available": {
"Battery not detected - only AC power settings available": "Batarya tespit edilmedi - sadece AC güç ayarları kullanılabilir"
},
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": {
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "Kilit ekranını loginctl'den gelen dbus sinyallerine bağlayın. Harici bir kilit ekranı kullanıyorsanız devre dışı bırakın"
},
@@ -312,7 +303,7 @@
"Center Section": "Orta Bölüm"
},
"Changes:": {
"Changes:": ""
"Changes:": "Değişiklikler:"
},
"Check for system updates": {
"Check for system updates": "Sistem güncellemelerini kontrol et"
@@ -398,9 +389,6 @@
"Compositor": {
"Compositor": "Kompozitör"
},
"Compositor:": {
"Compositor:": "Kompozitör:"
},
"Configuration activated": {
"Configuration activated": "Yapılandırma aktifleştirildi"
},
@@ -414,7 +402,7 @@
"Confirm": "Onayla"
},
"Confirm Display Changes": {
"Confirm Display Changes": ""
"Confirm Display Changes": "Ekran Değişikliklerini Onaylayın"
},
"Confirm passkey for ": {
"Confirm passkey for ": "Şunun için şifreyi onayla: "
@@ -434,9 +422,6 @@
"Connecting to Device": {
"Connecting to Device": "Cihaza Bağlanma"
},
"Connection failed. Check password and try again.": {
"Connection failed. Check password and try again.": "Bağlantı başarısız. Parolayı kontrol edin ve tekrar deneyin."
},
"Contrast": {
"Contrast": "Kontrast"
},
@@ -461,9 +446,6 @@
"Copied!": {
"Copied!": "Kopyalandı!"
},
"Copy": {
"Copy": "Kopyala"
},
"Copy PID": {
"Copy PID": "PID'i Kopyala"
},
@@ -515,6 +497,9 @@
"Customizable empty space": {
"Customizable empty space": "Özelleştirilebilir boş alan"
},
"Customize which actions appear in the power menu": {
"Customize which actions appear in the power menu": ""
},
"DEMO MODE - Click anywhere to exit": {
"DEMO MODE - Click anywhere to exit": "DEMO MODU - Çıkmak için herhangi bir yere tıklayın"
},
@@ -542,9 +527,6 @@
"Dank Bar Widget Transparency": {
"Dank Bar Widget Transparency": "Dank Bar Widget Şeffaflığı"
},
"Dank Suite:": {
"Dank Suite:": "Dank Suite:"
},
"DankBar Font Scale": {
"DankBar Font Scale": "DankBar Yazı Tipi Ölçeği"
},
@@ -566,6 +548,9 @@
"Default": {
"Default": "Varsayılan"
},
"Default selected action": {
"Default selected action": ""
},
"Defaults": {
"Defaults": "Varsayılanlar"
},
@@ -591,7 +576,7 @@
"Disable Autoconnect": "Otomatik Bağlanmayı Devre Dışı Bırak"
},
"Disabled": {
"Disabled": ""
"Disabled": "Devre Dışı"
},
"Disconnect": {
"Disconnect": "Bağlantıyı Kes"
@@ -621,7 +606,7 @@
"Display currently focused application title": "Şu anda odaklanmış uygulamanın başlığını göster"
},
"Display settings for ": {
"Display settings for ": ""
"Display settings for ": "Ekran ayarları: "
},
"Display volume and brightness percentage values by default in OSD popups": {
"Display volume and brightness percentage values by default in OSD popups": "OSD açılır pencerelerinde varsayılan olarak ses seviyesi ve parlaklık yüzdelik değerlerini göster"
@@ -699,7 +684,7 @@
"Enable loginctl lock integration": "loginctl kilit entegrasyonunu etkinleştir"
},
"Enabled": {
"Enabled": ""
"Enabled": "Etkin"
},
"End": {
"End": "Son"
@@ -842,9 +827,6 @@
"Format Legend": {
"Format Legend": "Biçim Açıklaması"
},
"Framework:": {
"Framework:": "Framework:"
},
"Fun": {
"Fun": "Eğlence"
},
@@ -866,9 +848,6 @@
"Gamma control not available. Requires DMS API v6+.": {
"Gamma control not available. Requires DMS API v6+.": "Gama kontrolü mevcut değil. DMS API V6+ gerekir."
},
"Geoclue service not running - cannot auto-detect location": {
"Geoclue service not running - cannot auto-detect location": "Geoclue hizmeti çalışmıyor - konum otomatik olarak algılanamıyor"
},
"Github:": {
"Github:": "Github:"
},
@@ -902,15 +881,9 @@
"Hex": {
"Hex": "Hex"
},
"Hex:": {
"Hex:": "Hex:"
},
"Hibernate": {
"Hibernate": "Hazırda Beklet"
},
"Hibernate system after": {
"Hibernate system after": "Şu zaman sonra sistemi hazırda beklet"
},
"Hide the dock when not in use and reveal it when hovering near the dock area": {
"Hide the dock when not in use and reveal it when hovering near the dock area": "Kullanılmadığında dock'u gizle ve dock alanının yakınına geldiğinizde göster"
},
@@ -966,7 +939,7 @@
"Individual Batteries": "Tekil Piller"
},
"Inhibit idle timeout when audio or video is playing": {
"Inhibit idle timeout when audio or video is playing": ""
"Inhibit idle timeout when audio or video is playing": "Ses veya video oynatılırken boşta kalma süresini engelle"
},
"Input Devices": {
"Input Devices": "Giriş Aygıtları"
@@ -993,7 +966,7 @@
"Jobs: ": "İşler:"
},
"Keep Changes": {
"Keep Changes": ""
"Keep Changes": "Değişiklikleri Tut"
},
"Keyboard Layout Name": {
"Keyboard Layout Name": "Klavye Düzeni Adı"
@@ -1001,9 +974,6 @@
"Kill Process": {
"Kill Process": "Süreci Öldür"
},
"Language:": {
"Language:": "Dil:"
},
"Last launched %1": {
"Last launched %1": "Son başlatma %1"
},
@@ -1058,6 +1028,9 @@
"Location Search": {
"Location Search": "Konum Arama"
},
"Lock": {
"Lock": "Kilitle"
},
"Lock Screen": {
"Lock Screen": "Kilit Ekranı"
},
@@ -1164,10 +1137,7 @@
"Mode:": "Mod:"
},
"Mode: ": {
"Mode: ": ""
},
"Monitor": {
"Monitor": "Monitör"
"Mode: ": "Mod: "
},
"Monitor Selection:": {
"Monitor Selection:": "Monitör Seçimi:"
@@ -1328,6 +1298,9 @@
"Only adjust gamma based on time or location rules.": {
"Only adjust gamma based on time or location rules.": "Gamayı yalnızca zaman veya konum kurallarına göre ayarlayın."
},
"Only visible if hibernate is supported by your system": {
"Only visible if hibernate is supported by your system": ""
},
"Opacity": {
"Opacity": "Opaklık"
},
@@ -1449,7 +1422,7 @@
"Position": "Pozisyon"
},
"Position: ": {
"Position: ": ""
"Position: ": "Pozisyon: "
},
"Power & Security": {
"Power & Security": "Güç & Güvenlik"
@@ -1457,6 +1430,9 @@
"Power Action Confirmation": {
"Power Action Confirmation": "Güç Eylemi Onayı"
},
"Power Menu Customization": {
"Power Menu Customization": ""
},
"Power Off": {
"Power Off": "Kapat"
},
@@ -1470,7 +1446,7 @@
"Pressure": "Basınç"
},
"Prevent idle for media": {
"Prevent idle for media": ""
"Prevent idle for media": "Medya için boşta kalmayı önle"
},
"Prevent screen timeout": {
"Prevent screen timeout": "Ekran zaman aşımını önle"
@@ -1502,9 +1478,6 @@
"Profile image is too large. Please use a smaller image.": {
"Profile image is too large. Please use a smaller image.": "Profil resmi çok büyük. Lütfen daha küçük bir resim kullanın."
},
"QML, JavaScript, Go": {
"QML, JavaScript, Go": "QML, Javascript, Go"
},
"Quick access to application launcher": {
"Quick access to application launcher": "Uygulama başlatıcısına hızlı erişim"
},
@@ -1556,14 +1529,23 @@
"Resources": {
"Resources": "Kaynaklar"
},
"Restart": {
"Restart": "Yeniden Başlat"
},
"Restart DMS": {
"Restart DMS": ""
},
"Restart the DankMaterialShell": {
"Restart the DankMaterialShell": ""
},
"Resume": {
"Resume": "Sürdür"
},
"Revert": {
"Revert": ""
"Revert": "Geri Al"
},
"Reverting in:": {
"Reverting in:": ""
"Reverting in:": "Geri dönülüyor:"
},
"Right": {
"Right": "Sağ"
@@ -1604,9 +1586,6 @@
"Science": {
"Science": "Bilim"
},
"Scroll through windows, rather than workspaces": {
"Scroll through windows, rather than workspaces": "Çalışma alanları yerine pencereler arasında gezin"
},
"Search file contents": {
"Search file contents": "Dosya içeriklerini ara"
},
@@ -1688,12 +1667,33 @@
"Show Dock": {
"Show Dock": "Dock'u Göster"
},
"Show Hibernate": {
"Show Hibernate": ""
},
"Show Line Numbers": {
"Show Line Numbers": "Satır Numaralarını Göster"
},
"Show Lock": {
"Show Lock": ""
},
"Show Log Out": {
"Show Log Out": ""
},
"Show Power Actions": {
"Show Power Actions": "Güç Eylemlerini Göster"
},
"Show Power Off": {
"Show Power Off": ""
},
"Show Reboot": {
"Show Reboot": ""
},
"Show Restart DMS": {
"Show Restart DMS": ""
},
"Show Suspend": {
"Show Suspend": ""
},
"Show Workspace Apps": {
"Show Workspace Apps": "Çalışma Alanı Uygulamalarını Göster"
},
@@ -1865,12 +1865,6 @@
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": {
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: Yön • ←→↑↓: Izgara Yönü • Enter/Space: Seç"
},
"Technical Details": {
"Technical Details": "Teknik Detaylar"
},
"Temperature": {
"Temperature": "Sıcaklık"
},
"Terminal custom additional parameters": {
"Terminal custom additional parameters": "Terminal özel ek parametreleri"
},
@@ -1997,9 +1991,6 @@
"Use animated wave progress bars for media playback": {
"Use animated wave progress bars for media playback": "Medya oynatımı için animasyonlu dalga ilerleme çubukları kullanın"
},
"Use automatic location detection (geoclue2)": {
"Use automatic location detection (geoclue2)": "Otomatik konum algılama özelliğini kullan (geoclue2)"
},
"Use custom command for update your system": {
"Use custom command for update your system": "Sistemi güncellemek için özel komut kullan"
},
@@ -2037,7 +2028,7 @@
"VPN status and quick connect": "VPN durumu ve hızlı bağlanma"
},
"VRR: ": {
"VRR: ": ""
"VRR: ": "VRR: "
},
"Vibrant palette with playful saturation.": {
"Vibrant palette with playful saturation.": "Oynak doygunluğa sahip canlı palet"
@@ -2105,9 +2096,6 @@
"Wind": {
"Wind": "Rüzgar"
},
"Window Scrolling": {
"Window Scrolling": "Pencere Kaydırma"
},
"Workspace": {
"Workspace": "Çalışma Alanı"
},

View File

@@ -89,9 +89,6 @@
"Applications": {
"Applications": "应用程序"
},
"Apply": {
"Apply": "应用"
},
"Apply GTK Colors": {
"Apply GTK Colors": "应用 GTK 配色"
},
@@ -167,9 +164,6 @@
"Auto-hide Dock": {
"Auto-hide Dock": "自动隐藏程序坞"
},
"Auto-location": {
"Auto-location": "自动定位"
},
"Auto-saving...": {
"Auto-saving...": "自动保存中..."
},
@@ -230,9 +224,6 @@
"Battery level and power management": {
"Battery level and power management": "电池电量与电源管理"
},
"Battery not detected - only AC power settings available": {
"Battery not detected - only AC power settings available": "未检测到电池,仅电源设置可用"
},
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": {
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "将锁屏绑定到来自 loginctl 的 dbus 信号。如使用外部锁屏程序,请禁用此项"
},
@@ -312,7 +303,7 @@
"Center Section": "中间区域"
},
"Changes:": {
"Changes:": ""
"Changes:": "更改:"
},
"Check for system updates": {
"Check for system updates": "检查系统更新"
@@ -398,9 +389,6 @@
"Compositor": {
"Compositor": "合成器"
},
"Compositor:": {
"Compositor:": "合成器:"
},
"Configuration activated": {
"Configuration activated": "已应用配置"
},
@@ -414,7 +402,7 @@
"Confirm": "确认"
},
"Confirm Display Changes": {
"Confirm Display Changes": ""
"Confirm Display Changes": "确认显示更改"
},
"Confirm passkey for ": {
"Confirm passkey for ": "确认密钥 "
@@ -434,9 +422,6 @@
"Connecting to Device": {
"Connecting to Device": "连接设备中"
},
"Connection failed. Check password and try again.": {
"Connection failed. Check password and try again.": "连接失败,请检查密码后重试。"
},
"Contrast": {
"Contrast": "对比度"
},
@@ -461,9 +446,6 @@
"Copied!": {
"Copied!": "复制成功!"
},
"Copy": {
"Copy": "复制"
},
"Copy PID": {
"Copy PID": "复制进程ID"
},
@@ -515,6 +497,9 @@
"Customizable empty space": {
"Customizable empty space": "可调节留白"
},
"Customize which actions appear in the power menu": {
"Customize which actions appear in the power menu": ""
},
"DEMO MODE - Click anywhere to exit": {
"DEMO MODE - Click anywhere to exit": "演示模式 - 点击任意位置退出"
},
@@ -542,9 +527,6 @@
"Dank Bar Widget Transparency": {
"Dank Bar Widget Transparency": "Dank Bar 小组件透明度"
},
"Dank Suite:": {
"Dank Suite:": "Dank 套件:"
},
"DankBar Font Scale": {
"DankBar Font Scale": "Dank Bar 字体缩放"
},
@@ -566,6 +548,9 @@
"Default": {
"Default": "默认"
},
"Default selected action": {
"Default selected action": ""
},
"Defaults": {
"Defaults": "复位"
},
@@ -591,7 +576,7 @@
"Disable Autoconnect": "禁用自动连接"
},
"Disabled": {
"Disabled": ""
"Disabled": "已关闭"
},
"Disconnect": {
"Disconnect": "断开连接"
@@ -621,7 +606,7 @@
"Display currently focused application title": "显示当前聚焦应用的标题"
},
"Display settings for ": {
"Display settings for ": ""
"Display settings for ": "显示设置 "
},
"Display volume and brightness percentage values by default in OSD popups": {
"Display volume and brightness percentage values by default in OSD popups": "在OSD弹窗中默认显示音量与亮度数值"
@@ -699,7 +684,7 @@
"Enable loginctl lock integration": "启用 loginctl 锁定集成"
},
"Enabled": {
"Enabled": ""
"Enabled": "已开启"
},
"End": {
"End": "结束"
@@ -842,9 +827,6 @@
"Format Legend": {
"Format Legend": "参考格式"
},
"Framework:": {
"Framework:": "框架:"
},
"Fun": {
"Fun": "娱乐"
},
@@ -866,9 +848,6 @@
"Gamma control not available. Requires DMS API v6+.": {
"Gamma control not available. Requires DMS API v6+.": "伽玛控制不可用,需要 DMS API v6+。"
},
"Geoclue service not running - cannot auto-detect location": {
"Geoclue service not running - cannot auto-detect location": "Geoclue 服务未运行 - 无法自动检测位置"
},
"Github:": {
"Github:": "Github:"
},
@@ -902,15 +881,9 @@
"Hex": {
"Hex": "十六进制"
},
"Hex:": {
"Hex:": "十六进制颜色码:"
},
"Hibernate": {
"Hibernate": "休眠"
},
"Hibernate system after": {
"Hibernate system after": "在此时间后休眠系统"
},
"Hide the dock when not in use and reveal it when hovering near the dock area": {
"Hide the dock when not in use and reveal it when hovering near the dock area": "在未使用时隐藏程序坞,鼠标悬停到程序坞区域时显示"
},
@@ -966,7 +939,7 @@
"Individual Batteries": "分别显示电池"
},
"Inhibit idle timeout when audio or video is playing": {
"Inhibit idle timeout when audio or video is playing": ""
"Inhibit idle timeout when audio or video is playing": "在播放音频或视频时,禁止待机超时"
},
"Input Devices": {
"Input Devices": "输入设备"
@@ -993,7 +966,7 @@
"Jobs: ": "任务: "
},
"Keep Changes": {
"Keep Changes": ""
"Keep Changes": "保持更改"
},
"Keyboard Layout Name": {
"Keyboard Layout Name": "键盘布局名称"
@@ -1001,9 +974,6 @@
"Kill Process": {
"Kill Process": "结束进程"
},
"Language:": {
"Language:": "开发语言:"
},
"Last launched %1": {
"Last launched %1": "上次启动于 %1"
},
@@ -1058,6 +1028,9 @@
"Location Search": {
"Location Search": "位置搜索"
},
"Lock": {
"Lock": "锁定"
},
"Lock Screen": {
"Lock Screen": "锁屏"
},
@@ -1164,10 +1137,7 @@
"Mode:": "模式:"
},
"Mode: ": {
"Mode: ": ""
},
"Monitor": {
"Monitor": "显示器"
"Mode: ": "模式: "
},
"Monitor Selection:": {
"Monitor Selection:": "选择显示器:"
@@ -1328,6 +1298,9 @@
"Only adjust gamma based on time or location rules.": {
"Only adjust gamma based on time or location rules.": "根据时间或位置调节伽马值。"
},
"Only visible if hibernate is supported by your system": {
"Only visible if hibernate is supported by your system": ""
},
"Opacity": {
"Opacity": "不透明度"
},
@@ -1449,7 +1422,7 @@
"Position": "位置"
},
"Position: ": {
"Position: ": ""
"Position: ": "位置: "
},
"Power & Security": {
"Power & Security": "电源与安全"
@@ -1457,6 +1430,9 @@
"Power Action Confirmation": {
"Power Action Confirmation": "电源操作确认"
},
"Power Menu Customization": {
"Power Menu Customization": ""
},
"Power Off": {
"Power Off": "关机"
},
@@ -1470,7 +1446,7 @@
"Pressure": "气压"
},
"Prevent idle for media": {
"Prevent idle for media": ""
"Prevent idle for media": "防止媒体播放时进入待机状态"
},
"Prevent screen timeout": {
"Prevent screen timeout": "防止屏幕超时"
@@ -1502,9 +1478,6 @@
"Profile image is too large. Please use a smaller image.": {
"Profile image is too large. Please use a smaller image.": "个人资料图片过大,请选择更小的图片。"
},
"QML, JavaScript, Go": {
"QML, JavaScript, Go": "QML, JavaScript, Go"
},
"Quick access to application launcher": {
"Quick access to application launcher": "快捷访问应用启动器"
},
@@ -1556,14 +1529,23 @@
"Resources": {
"Resources": "资源"
},
"Restart": {
"Restart": "重启"
},
"Restart DMS": {
"Restart DMS": ""
},
"Restart the DankMaterialShell": {
"Restart the DankMaterialShell": ""
},
"Resume": {
"Resume": "恢复"
},
"Revert": {
"Revert": ""
"Revert": "恢复: "
},
"Reverting in:": {
"Reverting in:": ""
"Reverting in:": "恢复于:"
},
"Right": {
"Right": "右侧"
@@ -1604,9 +1586,6 @@
"Science": {
"Science": "科学"
},
"Scroll through windows, rather than workspaces": {
"Scroll through windows, rather than workspaces": "滚动窗口,而非工作区"
},
"Search file contents": {
"Search file contents": "检索文件内容"
},
@@ -1688,12 +1667,33 @@
"Show Dock": {
"Show Dock": "显示程序坞"
},
"Show Hibernate": {
"Show Hibernate": ""
},
"Show Line Numbers": {
"Show Line Numbers": "显示行号"
},
"Show Lock": {
"Show Lock": ""
},
"Show Log Out": {
"Show Log Out": ""
},
"Show Power Actions": {
"Show Power Actions": "显示电源操作"
},
"Show Power Off": {
"Show Power Off": ""
},
"Show Reboot": {
"Show Reboot": ""
},
"Show Restart DMS": {
"Show Restart DMS": ""
},
"Show Suspend": {
"Show Suspend": ""
},
"Show Workspace Apps": {
"Show Workspace Apps": "显示工作区内应用"
},
@@ -1865,12 +1865,6 @@
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": {
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: 导航 • ←→↑↓: 网格导航 • 回车/空格: 选中"
},
"Technical Details": {
"Technical Details": "技术细节"
},
"Temperature": {
"Temperature": "色温"
},
"Terminal custom additional parameters": {
"Terminal custom additional parameters": "终端自定义附加参数"
},
@@ -1997,9 +1991,6 @@
"Use animated wave progress bars for media playback": {
"Use animated wave progress bars for media playback": "进行媒体播放时显示动画波形进度条"
},
"Use automatic location detection (geoclue2)": {
"Use automatic location detection (geoclue2)": "使用自动位置检测 geoclue2"
},
"Use custom command for update your system": {
"Use custom command for update your system": "使用自定义命令来更新系统"
},
@@ -2037,7 +2028,7 @@
"VPN status and quick connect": "VPN 状态与快速连接"
},
"VRR: ": {
"VRR: ": ""
"VRR: ": "可变刷新率: "
},
"Vibrant palette with playful saturation.": {
"Vibrant palette with playful saturation.": "充满活力的调色板,有着俏皮的饱和度。"
@@ -2105,9 +2096,6 @@
"Wind": {
"Wind": "风速"
},
"Window Scrolling": {
"Window Scrolling": "窗口滚动"
},
"Workspace": {
"Workspace": "工作区"
},

View File

@@ -89,9 +89,6 @@
"Applications": {
"Applications": "應用程式"
},
"Apply": {
"Apply": "套用"
},
"Apply GTK Colors": {
"Apply GTK Colors": "套用 GTK 顏色"
},
@@ -167,9 +164,6 @@
"Auto-hide Dock": {
"Auto-hide Dock": "自動隱藏 Dock"
},
"Auto-location": {
"Auto-location": "自動定位"
},
"Auto-saving...": {
"Auto-saving...": "自動保存..."
},
@@ -230,9 +224,6 @@
"Battery level and power management": {
"Battery level and power management": "電量與電源管理"
},
"Battery not detected - only AC power settings available": {
"Battery not detected - only AC power settings available": "未偵測到電池 - 僅提供交流電源設定"
},
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": {
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "將鎖定畫面綁定到 loginctl 的 dbus 訊號。如果使用外部鎖屏,請停用"
},
@@ -398,9 +389,6 @@
"Compositor": {
"Compositor": "合成器"
},
"Compositor:": {
"Compositor:": "合成器:"
},
"Configuration activated": {
"Configuration activated": "配置已啟動"
},
@@ -434,9 +422,6 @@
"Connecting to Device": {
"Connecting to Device": ""
},
"Connection failed. Check password and try again.": {
"Connection failed. Check password and try again.": "連線失敗。請檢查密碼並重試。"
},
"Contrast": {
"Contrast": "對比"
},
@@ -461,9 +446,6 @@
"Copied!": {
"Copied!": "已複製!"
},
"Copy": {
"Copy": "複製"
},
"Copy PID": {
"Copy PID": "複製 PID"
},
@@ -515,6 +497,9 @@
"Customizable empty space": {
"Customizable empty space": "可自訂空白空間"
},
"Customize which actions appear in the power menu": {
"Customize which actions appear in the power menu": ""
},
"DEMO MODE - Click anywhere to exit": {
"DEMO MODE - Click anywhere to exit": "演示模式 - 點擊任意處關閉"
},
@@ -542,9 +527,6 @@
"Dank Bar Widget Transparency": {
"Dank Bar Widget Transparency": "Dank Bar 部件透明度"
},
"Dank Suite:": {
"Dank Suite:": "Dank 套件:"
},
"DankBar Font Scale": {
"DankBar Font Scale": "Dank Bar 字體縮放"
},
@@ -566,6 +548,9 @@
"Default": {
"Default": "預設"
},
"Default selected action": {
"Default selected action": ""
},
"Defaults": {
"Defaults": "預設"
},
@@ -842,9 +827,6 @@
"Format Legend": {
"Format Legend": "格式說明"
},
"Framework:": {
"Framework:": "框架:"
},
"Fun": {
"Fun": "有趣的"
},
@@ -866,9 +848,6 @@
"Gamma control not available. Requires DMS API v6+.": {
"Gamma control not available. Requires DMS API v6+.": "Gamma 控制不可用。需要 DMS API v6+。"
},
"Geoclue service not running - cannot auto-detect location": {
"Geoclue service not running - cannot auto-detect location": "Geoclue 服務未運作 - 無法自動偵測位置"
},
"Github:": {
"Github:": "Github:"
},
@@ -902,15 +881,9 @@
"Hex": {
"Hex": ""
},
"Hex:": {
"Hex:": "色碼:"
},
"Hibernate": {
"Hibernate": "休眠"
},
"Hibernate system after": {
"Hibernate system after": "系統休眠之後"
},
"Hide the dock when not in use and reveal it when hovering near the dock area": {
"Hide the dock when not in use and reveal it when hovering near the dock area": "不使用時隱藏 Dock並在 Dock 區域附近懸停時顯示 Dock"
},
@@ -1001,9 +974,6 @@
"Kill Process": {
"Kill Process": "結束程序"
},
"Language:": {
"Language:": "語言:"
},
"Last launched %1": {
"Last launched %1": "上次啟動於 %1"
},
@@ -1058,6 +1028,9 @@
"Location Search": {
"Location Search": "位置搜尋"
},
"Lock": {
"Lock": ""
},
"Lock Screen": {
"Lock Screen": "鎖定螢幕"
},
@@ -1166,9 +1139,6 @@
"Mode: ": {
"Mode: ": ""
},
"Monitor": {
"Monitor": "螢幕"
},
"Monitor Selection:": {
"Monitor Selection:": "螢幕選擇:"
},
@@ -1328,6 +1298,9 @@
"Only adjust gamma based on time or location rules.": {
"Only adjust gamma based on time or location rules.": "僅根據時間或位置規則調整 gamma。"
},
"Only visible if hibernate is supported by your system": {
"Only visible if hibernate is supported by your system": ""
},
"Opacity": {
"Opacity": "不透明度"
},
@@ -1457,6 +1430,9 @@
"Power Action Confirmation": {
"Power Action Confirmation": "電源操作確認"
},
"Power Menu Customization": {
"Power Menu Customization": ""
},
"Power Off": {
"Power Off": "關機"
},
@@ -1502,9 +1478,6 @@
"Profile image is too large. Please use a smaller image.": {
"Profile image is too large. Please use a smaller image.": "個人資料圖片太大。請使用較小的圖片。"
},
"QML, JavaScript, Go": {
"QML, JavaScript, Go": "QML, JavaScript, Go"
},
"Quick access to application launcher": {
"Quick access to application launcher": "快速存取應用程式啟動器"
},
@@ -1556,6 +1529,15 @@
"Resources": {
"Resources": "資源"
},
"Restart": {
"Restart": ""
},
"Restart DMS": {
"Restart DMS": ""
},
"Restart the DankMaterialShell": {
"Restart the DankMaterialShell": ""
},
"Resume": {
"Resume": ""
},
@@ -1604,9 +1586,6 @@
"Science": {
"Science": "科學"
},
"Scroll through windows, rather than workspaces": {
"Scroll through windows, rather than workspaces": "滾動窗口,而不是工作區"
},
"Search file contents": {
"Search file contents": "搜尋檔案內容"
},
@@ -1688,12 +1667,33 @@
"Show Dock": {
"Show Dock": "顯示 Dock"
},
"Show Hibernate": {
"Show Hibernate": ""
},
"Show Line Numbers": {
"Show Line Numbers": "顯示行數"
},
"Show Lock": {
"Show Lock": ""
},
"Show Log Out": {
"Show Log Out": ""
},
"Show Power Actions": {
"Show Power Actions": "顯示電源選項"
},
"Show Power Off": {
"Show Power Off": ""
},
"Show Reboot": {
"Show Reboot": ""
},
"Show Restart DMS": {
"Show Restart DMS": ""
},
"Show Suspend": {
"Show Suspend": ""
},
"Show Workspace Apps": {
"Show Workspace Apps": "顯示工作區應用程式"
},
@@ -1865,12 +1865,6 @@
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": {
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: 切換焦點 • ←→↑↓: 切換焦點 • Enter/Space: 選擇"
},
"Technical Details": {
"Technical Details": "技術細節"
},
"Temperature": {
"Temperature": "溫度"
},
"Terminal custom additional parameters": {
"Terminal custom additional parameters": "自訂終端附加參數"
},
@@ -1997,9 +1991,6 @@
"Use animated wave progress bars for media playback": {
"Use animated wave progress bars for media playback": "在媒體播放使用動畫波浪進度條"
},
"Use automatic location detection (geoclue2)": {
"Use automatic location detection (geoclue2)": "使用自動位置偵測geoclue2"
},
"Use custom command for update your system": {
"Use custom command for update your system": "使用自訂指令更新您的系統"
},
@@ -2105,9 +2096,6 @@
"Wind": {
"Wind": "風速"
},
"Window Scrolling": {
"Window Scrolling": "視窗滾動"
},
"Workspace": {
"Workspace": "工作區"
},

View File

@@ -1161,6 +1161,13 @@
"reference": "",
"comment": ""
},
{
"term": "Customize which actions appear in the power menu",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "DEMO MODE - Click anywhere to exit",
"translation": "",
@@ -1273,6 +1280,13 @@
"reference": "",
"comment": ""
},
{
"term": "Default selected action",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Defaults",
"translation": "",
@@ -2386,6 +2400,13 @@
"reference": "",
"comment": ""
},
{
"term": "Lock",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Lock Screen",
"translation": "",
@@ -3009,6 +3030,13 @@
"reference": "",
"comment": ""
},
{
"term": "Only visible if hibernate is supported by your system",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Opacity",
"translation": "",
@@ -3310,6 +3338,13 @@
"reference": "",
"comment": ""
},
{
"term": "Power Menu Customization",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Power Off",
"translation": "",
@@ -3534,6 +3569,20 @@
"reference": "",
"comment": ""
},
{
"term": "Restart DMS",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Restart the DankMaterialShell",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Resume",
"translation": "",
@@ -3835,6 +3884,13 @@
"reference": "",
"comment": ""
},
{
"term": "Show Hibernate",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Show Line Numbers",
"translation": "",
@@ -3842,6 +3898,20 @@
"reference": "",
"comment": ""
},
{
"term": "Show Lock",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Show Log Out",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Show Power Actions",
"translation": "",
@@ -3849,6 +3919,34 @@
"reference": "",
"comment": ""
},
{
"term": "Show Power Off",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Show Reboot",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Show Restart DMS",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Show Suspend",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Show Workspace Apps",
"translation": "",