mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
Compare commits
32 Commits
wip/bar-ma
...
v0.6.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ddea836a1 | ||
|
|
208d92aa06 | ||
|
|
6ef9ddd4f3 | ||
|
|
1c92d39185 | ||
|
|
c0f072217c | ||
|
|
542562f988 | ||
|
|
4e6f0d5e87 | ||
|
|
10639a5ead | ||
|
|
06d668e710 | ||
|
|
d1472dfcba | ||
|
|
ccb4da3cd8 | ||
|
|
46e96b49f0 | ||
|
|
984cfe7f98 | ||
|
|
d769300137 | ||
|
|
d175d66828 | ||
|
|
c1a314332e | ||
|
|
046ac59d21 | ||
|
|
00c06f07d0 | ||
|
|
3e2ab40c6a | ||
|
|
350ffd0052 | ||
|
|
ecd1a622d2 | ||
|
|
f13968aa61 | ||
|
|
4d1ffde54c | ||
|
|
d69017a706 | ||
|
|
f2deaeccdb | ||
|
|
ea9b0d2a79 | ||
|
|
2e6dbedb8b | ||
|
|
6f359df8f9 | ||
|
|
f6db20cd06 | ||
|
|
6287fae065 | ||
|
|
e441607ce3 | ||
|
|
b5379a95fa |
@@ -19,7 +19,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
DankMaterialShell is a complete desktop shell for [niri](https://github.com/YaLTeR/niri), [Hyprland](https://hyprland.org/), [MangoWC](https://github.com/DreamMaoMao/mangowc), [Sway](https://swaywm.org), and other Wayland compositors. It replaces waybar, swaylock, swayidle, mako, fuzzel, polkit, and everything else you'd normally stitch together to make a desktop.
|
||||
DankMaterialShell is a complete desktop shell for [niri](https://github.com/YaLTeR/niri), [Hyprland](https://hyprland.org/), [MangoWC](https://github.com/DreamMaoMao/mangowc), [Sway](https://swaywm.org), [labwc](https://labwc.github.io/), and other Wayland compositors. It replaces waybar, swaylock, swayidle, mako, fuzzel, polkit, and everything else you'd normally stitch together to make a desktop.
|
||||
|
||||
## Repository Structure
|
||||
|
||||
@@ -105,7 +105,7 @@ Extend functionality with the [plugin registry](https://plugins.danklinux.com).
|
||||
|
||||
## Supported Compositors
|
||||
|
||||
Works best with [niri](https://github.com/YaLTeR/niri), [Hyprland](https://hyprland.org/), [Sway](https://swaywm.org/), and [MangoWC](https://github.com/DreamMaoMao/mangowc) with full workspace switching, overview integration, and monitor management. Other Wayland compositors work with reduced features.
|
||||
Works best with [niri](https://github.com/YaLTeR/niri), [Hyprland](https://hyprland.org/), [Sway](https://swaywm.org/), [MangoWC](https://github.com/DreamMaoMao/mangowc), and [labwc](https://labwc.github.io/) with full workspace switching, overview integration, and monitor management. Other Wayland compositors work with reduced features.
|
||||
|
||||
[Compositor configuration guide](https://danklinux.com/docs/dankmaterialshell/compositors)
|
||||
|
||||
@@ -183,6 +183,10 @@ For documentation contributions, see [DankLinux-Docs](https://github.com/AvengeM
|
||||
- [soramanew](https://github.com/soramanew) - [Caelestia](https://github.com/caelestia-dots/shell) inspiration
|
||||
- [end-4](https://github.com/end-4) - [dots-hyprland](https://github.com/end-4/dots-hyprland) inspiration
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://www.star-history.com/#AvengeMedia/DankMaterialShell&type=date&legend=top-left)
|
||||
|
||||
## License
|
||||
|
||||
MIT License - See [LICENSE](LICENSE) for details.
|
||||
|
||||
@@ -368,6 +368,7 @@ func getCommonCommands() []*cobra.Command {
|
||||
pluginsCmd,
|
||||
dank16Cmd,
|
||||
brightnessCmd,
|
||||
dpmsCmd,
|
||||
keybindsCmd,
|
||||
greeterCmd,
|
||||
setupCmd,
|
||||
|
||||
84
core/cmd/dms/commands_dpms.go
Normal file
84
core/cmd/dms/commands_dpms.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var dpmsCmd = &cobra.Command{
|
||||
Use: "dpms",
|
||||
Short: "Control display power management",
|
||||
}
|
||||
|
||||
var dpmsOnCmd = &cobra.Command{
|
||||
Use: "on [output]",
|
||||
Short: "Turn display(s) on",
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Run: runDPMSOn,
|
||||
}
|
||||
|
||||
var dpmsOffCmd = &cobra.Command{
|
||||
Use: "off [output]",
|
||||
Short: "Turn display(s) off",
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Run: runDPMSOff,
|
||||
}
|
||||
|
||||
var dpmsListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List outputs",
|
||||
Args: cobra.NoArgs,
|
||||
Run: runDPMSList,
|
||||
}
|
||||
|
||||
func init() {
|
||||
dpmsCmd.AddCommand(dpmsOnCmd, dpmsOffCmd, dpmsListCmd)
|
||||
}
|
||||
|
||||
func runDPMSOn(cmd *cobra.Command, args []string) {
|
||||
outputName := ""
|
||||
if len(args) > 0 {
|
||||
outputName = args[0]
|
||||
}
|
||||
|
||||
client, err := newDPMSClient()
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
if err := client.SetDPMS(outputName, true); err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func runDPMSOff(cmd *cobra.Command, args []string) {
|
||||
outputName := ""
|
||||
if len(args) > 0 {
|
||||
outputName = args[0]
|
||||
}
|
||||
|
||||
client, err := newDPMSClient()
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
if err := client.SetDPMS(outputName, false); err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func runDPMSList(cmd *cobra.Command, args []string) {
|
||||
client, err := newDPMSClient()
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
for _, output := range client.ListOutputs() {
|
||||
fmt.Println(output)
|
||||
}
|
||||
}
|
||||
345
core/cmd/dms/dpms_client.go
Normal file
345
core/cmd/dms/dpms_client.go
Normal file
@@ -0,0 +1,345 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_output_power"
|
||||
wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
|
||||
)
|
||||
|
||||
type cmd struct {
|
||||
fn func()
|
||||
done chan error
|
||||
}
|
||||
|
||||
type dpmsClient struct {
|
||||
display *wlclient.Display
|
||||
ctx *wlclient.Context
|
||||
powerMgr *wlr_output_power.ZwlrOutputPowerManagerV1
|
||||
outputs map[string]*outputState
|
||||
mu sync.Mutex
|
||||
syncRound int
|
||||
done bool
|
||||
err error
|
||||
cmdq chan cmd
|
||||
stopChan chan struct{}
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
type outputState struct {
|
||||
wlOutput *wlclient.Output
|
||||
powerCtrl *wlr_output_power.ZwlrOutputPowerV1
|
||||
name string
|
||||
mode uint32
|
||||
failed bool
|
||||
waitCh chan struct{}
|
||||
wantMode *uint32
|
||||
}
|
||||
|
||||
func (c *dpmsClient) post(fn func()) {
|
||||
done := make(chan error, 1)
|
||||
select {
|
||||
case c.cmdq <- cmd{fn: fn, done: done}:
|
||||
<-done
|
||||
case <-c.stopChan:
|
||||
}
|
||||
}
|
||||
|
||||
func (c *dpmsClient) waylandActor() {
|
||||
defer c.wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-c.stopChan:
|
||||
return
|
||||
case cmd := <-c.cmdq:
|
||||
cmd.fn()
|
||||
close(cmd.done)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newDPMSClient() (*dpmsClient, error) {
|
||||
display, err := wlclient.Connect("")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to Wayland: %w", err)
|
||||
}
|
||||
|
||||
c := &dpmsClient{
|
||||
display: display,
|
||||
ctx: display.Context(),
|
||||
outputs: make(map[string]*outputState),
|
||||
cmdq: make(chan cmd, 128),
|
||||
stopChan: make(chan struct{}),
|
||||
}
|
||||
|
||||
c.wg.Add(1)
|
||||
go c.waylandActor()
|
||||
|
||||
registry, err := display.GetRegistry()
|
||||
if err != nil {
|
||||
display.Context().Close()
|
||||
return nil, fmt.Errorf("failed to get registry: %w", err)
|
||||
}
|
||||
|
||||
registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) {
|
||||
switch e.Interface {
|
||||
case wlr_output_power.ZwlrOutputPowerManagerV1InterfaceName:
|
||||
powerMgr := wlr_output_power.NewZwlrOutputPowerManagerV1(c.ctx)
|
||||
version := e.Version
|
||||
if version > 1 {
|
||||
version = 1
|
||||
}
|
||||
if err := registry.Bind(e.Name, e.Interface, version, powerMgr); err == nil {
|
||||
c.powerMgr = powerMgr
|
||||
}
|
||||
|
||||
case "wl_output":
|
||||
output := wlclient.NewOutput(c.ctx)
|
||||
version := e.Version
|
||||
if version > 4 {
|
||||
version = 4
|
||||
}
|
||||
if err := registry.Bind(e.Name, e.Interface, version, output); err == nil {
|
||||
outputID := fmt.Sprintf("output-%d", output.ID())
|
||||
state := &outputState{
|
||||
wlOutput: output,
|
||||
name: outputID,
|
||||
}
|
||||
|
||||
c.mu.Lock()
|
||||
c.outputs[outputID] = state
|
||||
c.mu.Unlock()
|
||||
|
||||
output.SetNameHandler(func(ev wlclient.OutputNameEvent) {
|
||||
c.mu.Lock()
|
||||
delete(c.outputs, state.name)
|
||||
state.name = ev.Name
|
||||
c.outputs[ev.Name] = state
|
||||
c.mu.Unlock()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
syncCallback, err := display.Sync()
|
||||
if err != nil {
|
||||
c.Close()
|
||||
return nil, fmt.Errorf("failed to sync display: %w", err)
|
||||
}
|
||||
syncCallback.SetDoneHandler(func(e wlclient.CallbackDoneEvent) {
|
||||
c.handleSync()
|
||||
})
|
||||
|
||||
for !c.done {
|
||||
if err := c.ctx.Dispatch(); err != nil {
|
||||
c.Close()
|
||||
return nil, fmt.Errorf("dispatch error: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if c.err != nil {
|
||||
c.Close()
|
||||
return nil, c.err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *dpmsClient) handleSync() {
|
||||
c.syncRound++
|
||||
|
||||
switch c.syncRound {
|
||||
case 1:
|
||||
if c.powerMgr == nil {
|
||||
c.err = fmt.Errorf("wlr-output-power-management protocol not supported by compositor")
|
||||
c.done = true
|
||||
return
|
||||
}
|
||||
|
||||
c.mu.Lock()
|
||||
for _, state := range c.outputs {
|
||||
powerCtrl, err := c.powerMgr.GetOutputPower(state.wlOutput)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
state.powerCtrl = powerCtrl
|
||||
|
||||
powerCtrl.SetModeHandler(func(e wlr_output_power.ZwlrOutputPowerV1ModeEvent) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if state.powerCtrl == nil {
|
||||
return
|
||||
}
|
||||
state.mode = e.Mode
|
||||
if state.wantMode != nil && e.Mode == *state.wantMode && state.waitCh != nil {
|
||||
close(state.waitCh)
|
||||
state.wantMode = nil
|
||||
}
|
||||
})
|
||||
|
||||
powerCtrl.SetFailedHandler(func(e wlr_output_power.ZwlrOutputPowerV1FailedEvent) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if state.powerCtrl == nil {
|
||||
return
|
||||
}
|
||||
state.failed = true
|
||||
if state.waitCh != nil {
|
||||
close(state.waitCh)
|
||||
state.wantMode = nil
|
||||
}
|
||||
})
|
||||
}
|
||||
c.mu.Unlock()
|
||||
|
||||
syncCallback, err := c.display.Sync()
|
||||
if err != nil {
|
||||
c.err = fmt.Errorf("failed to sync display: %w", err)
|
||||
c.done = true
|
||||
return
|
||||
}
|
||||
syncCallback.SetDoneHandler(func(e wlclient.CallbackDoneEvent) {
|
||||
c.handleSync()
|
||||
})
|
||||
|
||||
default:
|
||||
c.done = true
|
||||
}
|
||||
}
|
||||
|
||||
func (c *dpmsClient) ListOutputs() []string {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
names := make([]string, 0, len(c.outputs))
|
||||
for name := range c.outputs {
|
||||
names = append(names, name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func (c *dpmsClient) SetDPMS(outputName string, on bool) error {
|
||||
var mode uint32
|
||||
if on {
|
||||
mode = uint32(wlr_output_power.ZwlrOutputPowerV1ModeOn)
|
||||
} else {
|
||||
mode = uint32(wlr_output_power.ZwlrOutputPowerV1ModeOff)
|
||||
}
|
||||
|
||||
var setErr error
|
||||
c.post(func() {
|
||||
c.mu.Lock()
|
||||
var waitStates []*outputState
|
||||
|
||||
if outputName == "" || outputName == "all" {
|
||||
if len(c.outputs) == 0 {
|
||||
c.mu.Unlock()
|
||||
setErr = fmt.Errorf("no outputs found")
|
||||
return
|
||||
}
|
||||
|
||||
for _, state := range c.outputs {
|
||||
if state.powerCtrl == nil {
|
||||
continue
|
||||
}
|
||||
state.wantMode = &mode
|
||||
state.waitCh = make(chan struct{})
|
||||
state.failed = false
|
||||
waitStates = append(waitStates, state)
|
||||
state.powerCtrl.SetMode(mode)
|
||||
}
|
||||
} else {
|
||||
state, ok := c.outputs[outputName]
|
||||
if !ok {
|
||||
c.mu.Unlock()
|
||||
setErr = fmt.Errorf("output not found: %s", outputName)
|
||||
return
|
||||
}
|
||||
if state.powerCtrl == nil {
|
||||
c.mu.Unlock()
|
||||
setErr = fmt.Errorf("output %s has nil powerCtrl", outputName)
|
||||
return
|
||||
}
|
||||
state.wantMode = &mode
|
||||
state.waitCh = make(chan struct{})
|
||||
state.failed = false
|
||||
waitStates = append(waitStates, state)
|
||||
state.powerCtrl.SetMode(mode)
|
||||
}
|
||||
c.mu.Unlock()
|
||||
|
||||
deadline := time.Now().Add(10 * time.Second)
|
||||
|
||||
for _, state := range waitStates {
|
||||
c.mu.Lock()
|
||||
ch := state.waitCh
|
||||
c.mu.Unlock()
|
||||
|
||||
done := false
|
||||
for !done {
|
||||
if err := c.ctx.Dispatch(); err != nil {
|
||||
setErr = fmt.Errorf("dispatch error: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
c.mu.Lock()
|
||||
if state.failed {
|
||||
setErr = fmt.Errorf("compositor reported failed for %s", state.name)
|
||||
c.mu.Unlock()
|
||||
return
|
||||
}
|
||||
c.mu.Unlock()
|
||||
done = true
|
||||
default:
|
||||
if time.Now().After(deadline) {
|
||||
setErr = fmt.Errorf("timeout waiting for mode change on %s", state.name)
|
||||
return
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.mu.Lock()
|
||||
for _, state := range waitStates {
|
||||
if state.powerCtrl != nil {
|
||||
state.powerCtrl.Destroy()
|
||||
state.powerCtrl = nil
|
||||
}
|
||||
}
|
||||
c.mu.Unlock()
|
||||
|
||||
c.display.Roundtrip()
|
||||
})
|
||||
|
||||
return setErr
|
||||
}
|
||||
|
||||
func (c *dpmsClient) Close() {
|
||||
close(c.stopChan)
|
||||
c.wg.Wait()
|
||||
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for _, state := range c.outputs {
|
||||
if state.powerCtrl != nil {
|
||||
state.powerCtrl.Destroy()
|
||||
}
|
||||
}
|
||||
c.outputs = nil
|
||||
|
||||
if c.powerMgr != nil {
|
||||
c.powerMgr.Destroy()
|
||||
c.powerMgr = nil
|
||||
}
|
||||
|
||||
if c.display != nil {
|
||||
c.ctx.Close()
|
||||
c.display = nil
|
||||
}
|
||||
}
|
||||
@@ -157,6 +157,16 @@ type ZdwlIpcOutputV2 struct {
|
||||
appidHandler ZdwlIpcOutputV2AppidHandlerFunc
|
||||
layoutSymbolHandler ZdwlIpcOutputV2LayoutSymbolHandlerFunc
|
||||
frameHandler ZdwlIpcOutputV2FrameHandlerFunc
|
||||
fullscreenHandler ZdwlIpcOutputV2FullscreenHandlerFunc
|
||||
floatingHandler ZdwlIpcOutputV2FloatingHandlerFunc
|
||||
xHandler ZdwlIpcOutputV2XHandlerFunc
|
||||
yHandler ZdwlIpcOutputV2YHandlerFunc
|
||||
widthHandler ZdwlIpcOutputV2WidthHandlerFunc
|
||||
heightHandler ZdwlIpcOutputV2HeightHandlerFunc
|
||||
lastLayerHandler ZdwlIpcOutputV2LastLayerHandlerFunc
|
||||
kbLayoutHandler ZdwlIpcOutputV2KbLayoutHandlerFunc
|
||||
keymodeHandler ZdwlIpcOutputV2KeymodeHandlerFunc
|
||||
scalefactorHandler ZdwlIpcOutputV2ScalefactorHandlerFunc
|
||||
}
|
||||
|
||||
// NewZdwlIpcOutputV2 : control dwl output
|
||||
@@ -251,6 +261,60 @@ func (i *ZdwlIpcOutputV2) SetLayout(index uint32) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Quit : Quit mango
|
||||
// This request allows clients to instruct the compositor to quit mango.
|
||||
func (i *ZdwlIpcOutputV2) Quit() error {
|
||||
const opcode = 4
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
l := 0
|
||||
client.PutUint32(_reqBuf[l:4], i.ID())
|
||||
l += 4
|
||||
client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
|
||||
l += 4
|
||||
err := i.Context().WriteMsg(_reqBuf[:], nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// SendDispatch : Set the active tags of this output
|
||||
//
|
||||
// dispatch: dispatch name.
|
||||
// arg1: arg1.
|
||||
// arg2: arg2.
|
||||
// arg3: arg3.
|
||||
// arg4: arg4.
|
||||
// arg5: arg5.
|
||||
func (i *ZdwlIpcOutputV2) SendDispatch(dispatch, arg1, arg2, arg3, arg4, arg5 string) error {
|
||||
const opcode = 5
|
||||
dispatchLen := client.PaddedLen(len(dispatch) + 1)
|
||||
arg1Len := client.PaddedLen(len(arg1) + 1)
|
||||
arg2Len := client.PaddedLen(len(arg2) + 1)
|
||||
arg3Len := client.PaddedLen(len(arg3) + 1)
|
||||
arg4Len := client.PaddedLen(len(arg4) + 1)
|
||||
arg5Len := client.PaddedLen(len(arg5) + 1)
|
||||
_reqBufLen := 8 + (4 + dispatchLen) + (4 + arg1Len) + (4 + arg2Len) + (4 + arg3Len) + (4 + arg4Len) + (4 + arg5Len)
|
||||
_reqBuf := make([]byte, _reqBufLen)
|
||||
l := 0
|
||||
client.PutUint32(_reqBuf[l:4], i.ID())
|
||||
l += 4
|
||||
client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
|
||||
l += 4
|
||||
client.PutString(_reqBuf[l:l+(4+dispatchLen)], dispatch)
|
||||
l += (4 + dispatchLen)
|
||||
client.PutString(_reqBuf[l:l+(4+arg1Len)], arg1)
|
||||
l += (4 + arg1Len)
|
||||
client.PutString(_reqBuf[l:l+(4+arg2Len)], arg2)
|
||||
l += (4 + arg2Len)
|
||||
client.PutString(_reqBuf[l:l+(4+arg3Len)], arg3)
|
||||
l += (4 + arg3Len)
|
||||
client.PutString(_reqBuf[l:l+(4+arg4Len)], arg4)
|
||||
l += (4 + arg4Len)
|
||||
client.PutString(_reqBuf[l:l+(4+arg5Len)], arg5)
|
||||
l += (4 + arg5Len)
|
||||
err := i.Context().WriteMsg(_reqBuf, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
type ZdwlIpcOutputV2TagState uint32
|
||||
|
||||
// ZdwlIpcOutputV2TagState :
|
||||
@@ -399,6 +463,136 @@ func (i *ZdwlIpcOutputV2) SetFrameHandler(f ZdwlIpcOutputV2FrameHandlerFunc) {
|
||||
i.frameHandler = f
|
||||
}
|
||||
|
||||
// ZdwlIpcOutputV2FullscreenEvent : Update fullscreen status
|
||||
//
|
||||
// Indicates if the selected client on this output is fullscreen.
|
||||
type ZdwlIpcOutputV2FullscreenEvent struct {
|
||||
IsFullscreen uint32
|
||||
}
|
||||
type ZdwlIpcOutputV2FullscreenHandlerFunc func(ZdwlIpcOutputV2FullscreenEvent)
|
||||
|
||||
// SetFullscreenHandler : sets handler for ZdwlIpcOutputV2FullscreenEvent
|
||||
func (i *ZdwlIpcOutputV2) SetFullscreenHandler(f ZdwlIpcOutputV2FullscreenHandlerFunc) {
|
||||
i.fullscreenHandler = f
|
||||
}
|
||||
|
||||
// ZdwlIpcOutputV2FloatingEvent : Update the floating status
|
||||
//
|
||||
// Indicates if the selected client on this output is floating.
|
||||
type ZdwlIpcOutputV2FloatingEvent struct {
|
||||
IsFloating uint32
|
||||
}
|
||||
type ZdwlIpcOutputV2FloatingHandlerFunc func(ZdwlIpcOutputV2FloatingEvent)
|
||||
|
||||
// SetFloatingHandler : sets handler for ZdwlIpcOutputV2FloatingEvent
|
||||
func (i *ZdwlIpcOutputV2) SetFloatingHandler(f ZdwlIpcOutputV2FloatingHandlerFunc) {
|
||||
i.floatingHandler = f
|
||||
}
|
||||
|
||||
// ZdwlIpcOutputV2XEvent : Update the x coordinates
|
||||
//
|
||||
// Indicates if x coordinates of the selected client.
|
||||
type ZdwlIpcOutputV2XEvent struct {
|
||||
X int32
|
||||
}
|
||||
type ZdwlIpcOutputV2XHandlerFunc func(ZdwlIpcOutputV2XEvent)
|
||||
|
||||
// SetXHandler : sets handler for ZdwlIpcOutputV2XEvent
|
||||
func (i *ZdwlIpcOutputV2) SetXHandler(f ZdwlIpcOutputV2XHandlerFunc) {
|
||||
i.xHandler = f
|
||||
}
|
||||
|
||||
// ZdwlIpcOutputV2YEvent : Update the y coordinates
|
||||
//
|
||||
// Indicates if y coordinates of the selected client.
|
||||
type ZdwlIpcOutputV2YEvent struct {
|
||||
Y int32
|
||||
}
|
||||
type ZdwlIpcOutputV2YHandlerFunc func(ZdwlIpcOutputV2YEvent)
|
||||
|
||||
// SetYHandler : sets handler for ZdwlIpcOutputV2YEvent
|
||||
func (i *ZdwlIpcOutputV2) SetYHandler(f ZdwlIpcOutputV2YHandlerFunc) {
|
||||
i.yHandler = f
|
||||
}
|
||||
|
||||
// ZdwlIpcOutputV2WidthEvent : Update the width
|
||||
//
|
||||
// Indicates if width of the selected client.
|
||||
type ZdwlIpcOutputV2WidthEvent struct {
|
||||
Width int32
|
||||
}
|
||||
type ZdwlIpcOutputV2WidthHandlerFunc func(ZdwlIpcOutputV2WidthEvent)
|
||||
|
||||
// SetWidthHandler : sets handler for ZdwlIpcOutputV2WidthEvent
|
||||
func (i *ZdwlIpcOutputV2) SetWidthHandler(f ZdwlIpcOutputV2WidthHandlerFunc) {
|
||||
i.widthHandler = f
|
||||
}
|
||||
|
||||
// ZdwlIpcOutputV2HeightEvent : Update the height
|
||||
//
|
||||
// Indicates if height of the selected client.
|
||||
type ZdwlIpcOutputV2HeightEvent struct {
|
||||
Height int32
|
||||
}
|
||||
type ZdwlIpcOutputV2HeightHandlerFunc func(ZdwlIpcOutputV2HeightEvent)
|
||||
|
||||
// SetHeightHandler : sets handler for ZdwlIpcOutputV2HeightEvent
|
||||
func (i *ZdwlIpcOutputV2) SetHeightHandler(f ZdwlIpcOutputV2HeightHandlerFunc) {
|
||||
i.heightHandler = f
|
||||
}
|
||||
|
||||
// ZdwlIpcOutputV2LastLayerEvent : last map layer.
|
||||
//
|
||||
// last map layer.
|
||||
type ZdwlIpcOutputV2LastLayerEvent struct {
|
||||
LastLayer string
|
||||
}
|
||||
type ZdwlIpcOutputV2LastLayerHandlerFunc func(ZdwlIpcOutputV2LastLayerEvent)
|
||||
|
||||
// SetLastLayerHandler : sets handler for ZdwlIpcOutputV2LastLayerEvent
|
||||
func (i *ZdwlIpcOutputV2) SetLastLayerHandler(f ZdwlIpcOutputV2LastLayerHandlerFunc) {
|
||||
i.lastLayerHandler = f
|
||||
}
|
||||
|
||||
// ZdwlIpcOutputV2KbLayoutEvent : current keyboard layout.
|
||||
//
|
||||
// current keyboard layout.
|
||||
type ZdwlIpcOutputV2KbLayoutEvent struct {
|
||||
KbLayout string
|
||||
}
|
||||
type ZdwlIpcOutputV2KbLayoutHandlerFunc func(ZdwlIpcOutputV2KbLayoutEvent)
|
||||
|
||||
// SetKbLayoutHandler : sets handler for ZdwlIpcOutputV2KbLayoutEvent
|
||||
func (i *ZdwlIpcOutputV2) SetKbLayoutHandler(f ZdwlIpcOutputV2KbLayoutHandlerFunc) {
|
||||
i.kbLayoutHandler = f
|
||||
}
|
||||
|
||||
// ZdwlIpcOutputV2KeymodeEvent : current keybind mode.
|
||||
//
|
||||
// current keybind mode.
|
||||
type ZdwlIpcOutputV2KeymodeEvent struct {
|
||||
Keymode string
|
||||
}
|
||||
type ZdwlIpcOutputV2KeymodeHandlerFunc func(ZdwlIpcOutputV2KeymodeEvent)
|
||||
|
||||
// SetKeymodeHandler : sets handler for ZdwlIpcOutputV2KeymodeEvent
|
||||
func (i *ZdwlIpcOutputV2) SetKeymodeHandler(f ZdwlIpcOutputV2KeymodeHandlerFunc) {
|
||||
i.keymodeHandler = f
|
||||
}
|
||||
|
||||
// ZdwlIpcOutputV2ScalefactorEvent : scale factor of monitor.
|
||||
//
|
||||
// scale factor of monitor.
|
||||
type ZdwlIpcOutputV2ScalefactorEvent struct {
|
||||
Scalefactor uint32
|
||||
}
|
||||
type ZdwlIpcOutputV2ScalefactorHandlerFunc func(ZdwlIpcOutputV2ScalefactorEvent)
|
||||
|
||||
// SetScalefactorHandler : sets handler for ZdwlIpcOutputV2ScalefactorEvent
|
||||
func (i *ZdwlIpcOutputV2) SetScalefactorHandler(f ZdwlIpcOutputV2ScalefactorHandlerFunc) {
|
||||
i.scalefactorHandler = f
|
||||
}
|
||||
|
||||
func (i *ZdwlIpcOutputV2) Dispatch(opcode uint32, fd int, data []byte) {
|
||||
switch opcode {
|
||||
case 0:
|
||||
@@ -487,5 +681,111 @@ func (i *ZdwlIpcOutputV2) Dispatch(opcode uint32, fd int, data []byte) {
|
||||
var e ZdwlIpcOutputV2FrameEvent
|
||||
|
||||
i.frameHandler(e)
|
||||
case 8:
|
||||
if i.fullscreenHandler == nil {
|
||||
return
|
||||
}
|
||||
var e ZdwlIpcOutputV2FullscreenEvent
|
||||
l := 0
|
||||
e.IsFullscreen = client.Uint32(data[l : l+4])
|
||||
l += 4
|
||||
|
||||
i.fullscreenHandler(e)
|
||||
case 9:
|
||||
if i.floatingHandler == nil {
|
||||
return
|
||||
}
|
||||
var e ZdwlIpcOutputV2FloatingEvent
|
||||
l := 0
|
||||
e.IsFloating = client.Uint32(data[l : l+4])
|
||||
l += 4
|
||||
|
||||
i.floatingHandler(e)
|
||||
case 10:
|
||||
if i.xHandler == nil {
|
||||
return
|
||||
}
|
||||
var e ZdwlIpcOutputV2XEvent
|
||||
l := 0
|
||||
e.X = int32(client.Uint32(data[l : l+4]))
|
||||
l += 4
|
||||
|
||||
i.xHandler(e)
|
||||
case 11:
|
||||
if i.yHandler == nil {
|
||||
return
|
||||
}
|
||||
var e ZdwlIpcOutputV2YEvent
|
||||
l := 0
|
||||
e.Y = int32(client.Uint32(data[l : l+4]))
|
||||
l += 4
|
||||
|
||||
i.yHandler(e)
|
||||
case 12:
|
||||
if i.widthHandler == nil {
|
||||
return
|
||||
}
|
||||
var e ZdwlIpcOutputV2WidthEvent
|
||||
l := 0
|
||||
e.Width = int32(client.Uint32(data[l : l+4]))
|
||||
l += 4
|
||||
|
||||
i.widthHandler(e)
|
||||
case 13:
|
||||
if i.heightHandler == nil {
|
||||
return
|
||||
}
|
||||
var e ZdwlIpcOutputV2HeightEvent
|
||||
l := 0
|
||||
e.Height = int32(client.Uint32(data[l : l+4]))
|
||||
l += 4
|
||||
|
||||
i.heightHandler(e)
|
||||
case 14:
|
||||
if i.lastLayerHandler == nil {
|
||||
return
|
||||
}
|
||||
var e ZdwlIpcOutputV2LastLayerEvent
|
||||
l := 0
|
||||
lastLayerLen := client.PaddedLen(int(client.Uint32(data[l : l+4])))
|
||||
l += 4
|
||||
e.LastLayer = client.String(data[l : l+lastLayerLen])
|
||||
l += lastLayerLen
|
||||
|
||||
i.lastLayerHandler(e)
|
||||
case 15:
|
||||
if i.kbLayoutHandler == nil {
|
||||
return
|
||||
}
|
||||
var e ZdwlIpcOutputV2KbLayoutEvent
|
||||
l := 0
|
||||
kbLayoutLen := client.PaddedLen(int(client.Uint32(data[l : l+4])))
|
||||
l += 4
|
||||
e.KbLayout = client.String(data[l : l+kbLayoutLen])
|
||||
l += kbLayoutLen
|
||||
|
||||
i.kbLayoutHandler(e)
|
||||
case 16:
|
||||
if i.keymodeHandler == nil {
|
||||
return
|
||||
}
|
||||
var e ZdwlIpcOutputV2KeymodeEvent
|
||||
l := 0
|
||||
keymodeLen := client.PaddedLen(int(client.Uint32(data[l : l+4])))
|
||||
l += 4
|
||||
e.Keymode = client.String(data[l : l+keymodeLen])
|
||||
l += keymodeLen
|
||||
|
||||
i.keymodeHandler(e)
|
||||
case 17:
|
||||
if i.scalefactorHandler == nil {
|
||||
return
|
||||
}
|
||||
var e ZdwlIpcOutputV2ScalefactorEvent
|
||||
l := 0
|
||||
e.Scalefactor = client.Uint32(data[l : l+4])
|
||||
l += 4
|
||||
|
||||
i.scalefactorHandler(e)
|
||||
}
|
||||
}
|
||||
|
||||
283
core/internal/proto/wlr_output_power/output_power.go
Normal file
283
core/internal/proto/wlr_output_power/output_power.go
Normal file
@@ -0,0 +1,283 @@
|
||||
// Generated by go-wayland-scanner
|
||||
// https://github.com/yaslama/go-wayland/cmd/go-wayland-scanner
|
||||
// XML file : internal/proto/xml/wlr-output-power-management-unstable-v1.xml
|
||||
//
|
||||
// wlr_output_power_management_unstable_v1 Protocol Copyright:
|
||||
//
|
||||
// Copyright © 2019 Purism SPC
|
||||
//
|
||||
// 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 (including the next
|
||||
// paragraph) 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 IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
package wlr_output_power
|
||||
|
||||
import "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
|
||||
|
||||
// ZwlrOutputPowerManagerV1InterfaceName is the name of the interface as it appears in the [client.Registry].
|
||||
// It can be used to match the [client.RegistryGlobalEvent.Interface] in the
|
||||
// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies.
|
||||
const ZwlrOutputPowerManagerV1InterfaceName = "zwlr_output_power_manager_v1"
|
||||
|
||||
// ZwlrOutputPowerManagerV1 : manager to create per-output power management
|
||||
//
|
||||
// This interface is a manager that allows creating per-output power
|
||||
// management mode controls.
|
||||
type ZwlrOutputPowerManagerV1 struct {
|
||||
client.BaseProxy
|
||||
}
|
||||
|
||||
// NewZwlrOutputPowerManagerV1 : manager to create per-output power management
|
||||
//
|
||||
// This interface is a manager that allows creating per-output power
|
||||
// management mode controls.
|
||||
func NewZwlrOutputPowerManagerV1(ctx *client.Context) *ZwlrOutputPowerManagerV1 {
|
||||
zwlrOutputPowerManagerV1 := &ZwlrOutputPowerManagerV1{}
|
||||
ctx.Register(zwlrOutputPowerManagerV1)
|
||||
return zwlrOutputPowerManagerV1
|
||||
}
|
||||
|
||||
// GetOutputPower : get a power management for an output
|
||||
//
|
||||
// Create an output power management mode control that can be used to
|
||||
// adjust the power management mode for a given output.
|
||||
func (i *ZwlrOutputPowerManagerV1) GetOutputPower(output *client.Output) (*ZwlrOutputPowerV1, error) {
|
||||
id := NewZwlrOutputPowerV1(i.Context())
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8 + 4 + 4
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
l := 0
|
||||
client.PutUint32(_reqBuf[l:4], i.ID())
|
||||
l += 4
|
||||
client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
|
||||
l += 4
|
||||
client.PutUint32(_reqBuf[l:l+4], id.ID())
|
||||
l += 4
|
||||
client.PutUint32(_reqBuf[l:l+4], output.ID())
|
||||
l += 4
|
||||
err := i.Context().WriteMsg(_reqBuf[:], nil)
|
||||
return id, err
|
||||
}
|
||||
|
||||
// Destroy : destroy the manager
|
||||
//
|
||||
// All objects created by the manager will still remain valid, until their
|
||||
// appropriate destroy request has been called.
|
||||
func (i *ZwlrOutputPowerManagerV1) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
const opcode = 1
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
l := 0
|
||||
client.PutUint32(_reqBuf[l:4], i.ID())
|
||||
l += 4
|
||||
client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
|
||||
l += 4
|
||||
err := i.Context().WriteMsg(_reqBuf[:], nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// ZwlrOutputPowerV1InterfaceName is the name of the interface as it appears in the [client.Registry].
|
||||
// It can be used to match the [client.RegistryGlobalEvent.Interface] in the
|
||||
// [Registry.SetGlobalHandler] and can be used in [Registry.Bind] if this applies.
|
||||
const ZwlrOutputPowerV1InterfaceName = "zwlr_output_power_v1"
|
||||
|
||||
// ZwlrOutputPowerV1 : adjust power management mode for an output
|
||||
//
|
||||
// This object offers requests to set the power management mode of
|
||||
// an output.
|
||||
type ZwlrOutputPowerV1 struct {
|
||||
client.BaseProxy
|
||||
modeHandler ZwlrOutputPowerV1ModeHandlerFunc
|
||||
failedHandler ZwlrOutputPowerV1FailedHandlerFunc
|
||||
}
|
||||
|
||||
// NewZwlrOutputPowerV1 : adjust power management mode for an output
|
||||
//
|
||||
// This object offers requests to set the power management mode of
|
||||
// an output.
|
||||
func NewZwlrOutputPowerV1(ctx *client.Context) *ZwlrOutputPowerV1 {
|
||||
zwlrOutputPowerV1 := &ZwlrOutputPowerV1{}
|
||||
ctx.Register(zwlrOutputPowerV1)
|
||||
return zwlrOutputPowerV1
|
||||
}
|
||||
|
||||
// SetMode : Set an outputs power save mode
|
||||
//
|
||||
// Set an output's power save mode to the given mode. The mode change
|
||||
// is effective immediately. If the output does not support the given
|
||||
// mode a failed event is sent.
|
||||
//
|
||||
// mode: the power save mode to set
|
||||
func (i *ZwlrOutputPowerV1) SetMode(mode uint32) error {
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8 + 4
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
l := 0
|
||||
client.PutUint32(_reqBuf[l:4], i.ID())
|
||||
l += 4
|
||||
client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
|
||||
l += 4
|
||||
client.PutUint32(_reqBuf[l:l+4], uint32(mode))
|
||||
l += 4
|
||||
err := i.Context().WriteMsg(_reqBuf[:], nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// Destroy : destroy this power management
|
||||
//
|
||||
// Destroys the output power management mode control object.
|
||||
func (i *ZwlrOutputPowerV1) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
const opcode = 1
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
l := 0
|
||||
client.PutUint32(_reqBuf[l:4], i.ID())
|
||||
l += 4
|
||||
client.PutUint32(_reqBuf[l:l+4], uint32(_reqBufLen<<16|opcode&0x0000ffff))
|
||||
l += 4
|
||||
err := i.Context().WriteMsg(_reqBuf[:], nil)
|
||||
return err
|
||||
}
|
||||
|
||||
type ZwlrOutputPowerV1Mode uint32
|
||||
|
||||
// ZwlrOutputPowerV1Mode :
|
||||
const (
|
||||
// ZwlrOutputPowerV1ModeOff : Output is turned off.
|
||||
ZwlrOutputPowerV1ModeOff ZwlrOutputPowerV1Mode = 0
|
||||
// ZwlrOutputPowerV1ModeOn : Output is turned on, no power saving
|
||||
ZwlrOutputPowerV1ModeOn ZwlrOutputPowerV1Mode = 1
|
||||
)
|
||||
|
||||
func (e ZwlrOutputPowerV1Mode) Name() string {
|
||||
switch e {
|
||||
case ZwlrOutputPowerV1ModeOff:
|
||||
return "off"
|
||||
case ZwlrOutputPowerV1ModeOn:
|
||||
return "on"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (e ZwlrOutputPowerV1Mode) Value() string {
|
||||
switch e {
|
||||
case ZwlrOutputPowerV1ModeOff:
|
||||
return "0"
|
||||
case ZwlrOutputPowerV1ModeOn:
|
||||
return "1"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (e ZwlrOutputPowerV1Mode) String() string {
|
||||
return e.Name() + "=" + e.Value()
|
||||
}
|
||||
|
||||
type ZwlrOutputPowerV1Error uint32
|
||||
|
||||
// ZwlrOutputPowerV1Error :
|
||||
const (
|
||||
// ZwlrOutputPowerV1ErrorInvalidMode : nonexistent power save mode
|
||||
ZwlrOutputPowerV1ErrorInvalidMode ZwlrOutputPowerV1Error = 1
|
||||
)
|
||||
|
||||
func (e ZwlrOutputPowerV1Error) Name() string {
|
||||
switch e {
|
||||
case ZwlrOutputPowerV1ErrorInvalidMode:
|
||||
return "invalid_mode"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (e ZwlrOutputPowerV1Error) Value() string {
|
||||
switch e {
|
||||
case ZwlrOutputPowerV1ErrorInvalidMode:
|
||||
return "1"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (e ZwlrOutputPowerV1Error) String() string {
|
||||
return e.Name() + "=" + e.Value()
|
||||
}
|
||||
|
||||
// ZwlrOutputPowerV1ModeEvent : Report a power management mode change
|
||||
//
|
||||
// Report the power management mode change of an output.
|
||||
//
|
||||
// The mode event is sent after an output changed its power
|
||||
// management mode. The reason can be a client using set_mode or the
|
||||
// compositor deciding to change an output's mode.
|
||||
// This event is also sent immediately when the object is created
|
||||
// so the client is informed about the current power management mode.
|
||||
type ZwlrOutputPowerV1ModeEvent struct {
|
||||
Mode uint32
|
||||
}
|
||||
type ZwlrOutputPowerV1ModeHandlerFunc func(ZwlrOutputPowerV1ModeEvent)
|
||||
|
||||
// SetModeHandler : sets handler for ZwlrOutputPowerV1ModeEvent
|
||||
func (i *ZwlrOutputPowerV1) SetModeHandler(f ZwlrOutputPowerV1ModeHandlerFunc) {
|
||||
i.modeHandler = f
|
||||
}
|
||||
|
||||
// ZwlrOutputPowerV1FailedEvent : object no longer valid
|
||||
//
|
||||
// This event indicates that the output power management mode control
|
||||
// is no longer valid. This can happen for a number of reasons,
|
||||
// including:
|
||||
// - The output doesn't support power management
|
||||
// - Another client already has exclusive power management mode control
|
||||
// for this output
|
||||
// - The output disappeared
|
||||
//
|
||||
// Upon receiving this event, the client should destroy this object.
|
||||
type ZwlrOutputPowerV1FailedEvent struct{}
|
||||
type ZwlrOutputPowerV1FailedHandlerFunc func(ZwlrOutputPowerV1FailedEvent)
|
||||
|
||||
// SetFailedHandler : sets handler for ZwlrOutputPowerV1FailedEvent
|
||||
func (i *ZwlrOutputPowerV1) SetFailedHandler(f ZwlrOutputPowerV1FailedHandlerFunc) {
|
||||
i.failedHandler = f
|
||||
}
|
||||
|
||||
func (i *ZwlrOutputPowerV1) Dispatch(opcode uint32, fd int, data []byte) {
|
||||
switch opcode {
|
||||
case 0:
|
||||
if i.modeHandler == nil {
|
||||
return
|
||||
}
|
||||
var e ZwlrOutputPowerV1ModeEvent
|
||||
l := 0
|
||||
e.Mode = client.Uint32(data[l : l+4])
|
||||
l += 4
|
||||
|
||||
i.modeHandler(e)
|
||||
case 1:
|
||||
if i.failedHandler == nil {
|
||||
return
|
||||
}
|
||||
var e ZwlrOutputPowerV1FailedEvent
|
||||
|
||||
i.failedHandler(e)
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ I would probably just submit raphi's patchset but I don't think that would be po
|
||||
reset.
|
||||
</description>
|
||||
|
||||
<interface name="zdwl_ipc_manager_v2" version="1">
|
||||
<interface name="zdwl_ipc_manager_v2" version="2">
|
||||
<description summary="manage dwl state">
|
||||
This interface is exposed as a global in wl_registry.
|
||||
|
||||
@@ -60,7 +60,7 @@ I would probably just submit raphi's patchset but I don't think that would be po
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="zdwl_ipc_output_v2" version="1">
|
||||
<interface name="zdwl_ipc_output_v2" version="2">
|
||||
<description summary="control dwl output">
|
||||
Observe and control a dwl output.
|
||||
|
||||
@@ -162,5 +162,91 @@ I would probably just submit raphi's patchset but I don't think that would be po
|
||||
<description summary="Set the layout of this output"/>
|
||||
<arg name="index" type="uint" summary="index of a layout recieved by dwl_ipc_manager.layout"/>
|
||||
</request>
|
||||
|
||||
<request name="quit" since="2">
|
||||
<description summary="Quit mango">This request allows clients to instruct the compositor to quit mango.</description>
|
||||
</request>
|
||||
|
||||
<request name="dispatch" since="2">
|
||||
<description summary="Set the active tags of this output"/>
|
||||
<arg name="dispatch" type="string" summary="dispatch name."/>
|
||||
<arg name="arg1" type="string" summary="arg1."/>
|
||||
<arg name="arg2" type="string" summary="arg2."/>
|
||||
<arg name="arg3" type="string" summary="arg3."/>
|
||||
<arg name="arg4" type="string" summary="arg4."/>
|
||||
<arg name="arg5" type="string" summary="arg5."/>
|
||||
</request>
|
||||
|
||||
<!-- Version 2 -->
|
||||
<event name="fullscreen" since="2">
|
||||
<description summary="Update fullscreen status">
|
||||
Indicates if the selected client on this output is fullscreen.
|
||||
</description>
|
||||
<arg name="is_fullscreen" type="uint" summary="If the selected client is fullscreen. Nonzero is valid, zero invalid"/>
|
||||
</event>
|
||||
|
||||
<event name="floating" since="2">
|
||||
<description summary="Update the floating status">
|
||||
Indicates if the selected client on this output is floating.
|
||||
</description>
|
||||
<arg name="is_floating" type="uint" summary="If the selected client is floating. Nonzero is valid, zero invalid"/>
|
||||
</event>
|
||||
|
||||
<event name="x" since="2">
|
||||
<description summary="Update the x coordinates">
|
||||
Indicates if x coordinates of the selected client.
|
||||
</description>
|
||||
<arg name="x" type="int" summary="x coordinate of the selected client"/>
|
||||
</event>
|
||||
|
||||
<event name="y" since="2">
|
||||
<description summary="Update the y coordinates">
|
||||
Indicates if y coordinates of the selected client.
|
||||
</description>
|
||||
<arg name="y" type="int" summary="y coordinate of the selected client"/>
|
||||
</event>
|
||||
|
||||
<event name="width" since="2">
|
||||
<description summary="Update the width">
|
||||
Indicates if width of the selected client.
|
||||
</description>
|
||||
<arg name="width" type="int" summary="width of the selected client"/>
|
||||
</event>
|
||||
|
||||
<event name="height" since="2">
|
||||
<description summary="Update the height">
|
||||
Indicates if height of the selected client.
|
||||
</description>
|
||||
<arg name="height" type="int" summary="height of the selected client"/>
|
||||
</event>
|
||||
|
||||
<event name="last_layer" since="2">
|
||||
<description summary="last map layer.">
|
||||
last map layer.
|
||||
</description>
|
||||
<arg name="last_layer" type="string" summary="last map layer."/>
|
||||
</event>
|
||||
|
||||
<event name="kb_layout" since="2">
|
||||
<description summary="current keyboard layout.">
|
||||
current keyboard layout.
|
||||
</description>
|
||||
<arg name="kb_layout" type="string" summary="current keyboard layout."/>
|
||||
</event>
|
||||
|
||||
<event name="keymode" since="2">
|
||||
<description summary="current keybind mode.">
|
||||
current keybind mode.
|
||||
</description>
|
||||
<arg name="keymode" type="string" summary="current keybind mode."/>
|
||||
</event>
|
||||
|
||||
<event name="scalefactor" since="2">
|
||||
<description summary="scale factor of monitor.">
|
||||
scale factor of monitor.
|
||||
</description>
|
||||
<arg name="scalefactor" type="uint" summary="scale factor of monitor."/>
|
||||
</event>
|
||||
|
||||
</interface>
|
||||
</protocol>
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="wlr_output_power_management_unstable_v1">
|
||||
<copyright>
|
||||
Copyright © 2019 Purism SPC
|
||||
|
||||
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 (including the next
|
||||
paragraph) 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 IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<description summary="Control power management modes of outputs">
|
||||
This protocol allows clients to control power management modes
|
||||
of outputs that are currently part of the compositor space. The
|
||||
intent is to allow special clients like desktop shells to power
|
||||
down outputs when the system is idle.
|
||||
|
||||
To modify outputs not currently part of the compositor space see
|
||||
wlr-output-management.
|
||||
|
||||
Warning! The protocol described in this file is experimental and
|
||||
backward incompatible changes may be made. Backward compatible changes
|
||||
may be added together with the corresponding interface version bump.
|
||||
Backward incompatible changes are done by bumping the version number in
|
||||
the protocol and interface names and resetting the interface version.
|
||||
Once the protocol is to be declared stable, the 'z' prefix and the
|
||||
version number in the protocol and interface names are removed and the
|
||||
interface version number is reset.
|
||||
</description>
|
||||
|
||||
<interface name="zwlr_output_power_manager_v1" version="1">
|
||||
<description summary="manager to create per-output power management">
|
||||
This interface is a manager that allows creating per-output power
|
||||
management mode controls.
|
||||
</description>
|
||||
|
||||
<request name="get_output_power">
|
||||
<description summary="get a power management for an output">
|
||||
Create an output power management mode control that can be used to
|
||||
adjust the power management mode for a given output.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zwlr_output_power_v1"/>
|
||||
<arg name="output" type="object" interface="wl_output"/>
|
||||
</request>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the manager">
|
||||
All objects created by the manager will still remain valid, until their
|
||||
appropriate destroy request has been called.
|
||||
</description>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="zwlr_output_power_v1" version="1">
|
||||
<description summary="adjust power management mode for an output">
|
||||
This object offers requests to set the power management mode of
|
||||
an output.
|
||||
</description>
|
||||
|
||||
<enum name="mode">
|
||||
<entry name="off" value="0"
|
||||
summary="Output is turned off."/>
|
||||
<entry name="on" value="1"
|
||||
summary="Output is turned on, no power saving"/>
|
||||
</enum>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="invalid_mode" value="1" summary="nonexistent power save mode"/>
|
||||
</enum>
|
||||
|
||||
<request name="set_mode">
|
||||
<description summary="Set an outputs power save mode">
|
||||
Set an output's power save mode to the given mode. The mode change
|
||||
is effective immediately. If the output does not support the given
|
||||
mode a failed event is sent.
|
||||
</description>
|
||||
<arg name="mode" type="uint" enum="mode" summary="the power save mode to set"/>
|
||||
</request>
|
||||
|
||||
<event name="mode">
|
||||
<description summary="Report a power management mode change">
|
||||
Report the power management mode change of an output.
|
||||
|
||||
The mode event is sent after an output changed its power
|
||||
management mode. The reason can be a client using set_mode or the
|
||||
compositor deciding to change an output's mode.
|
||||
This event is also sent immediately when the object is created
|
||||
so the client is informed about the current power management mode.
|
||||
</description>
|
||||
<arg name="mode" type="uint" enum="mode"
|
||||
summary="the output's new power management mode"/>
|
||||
</event>
|
||||
|
||||
<event name="failed">
|
||||
<description summary="object no longer valid">
|
||||
This event indicates that the output power management mode control
|
||||
is no longer valid. This can happen for a number of reasons,
|
||||
including:
|
||||
- The output doesn't support power management
|
||||
- Another client already has exclusive power management mode control
|
||||
for this output
|
||||
- The output disappeared
|
||||
|
||||
Upon receiving this event, the client should destroy this object.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy this power management">
|
||||
Destroys the output power management mode control object.
|
||||
</description>
|
||||
</request>
|
||||
</interface>
|
||||
</protocol>
|
||||
@@ -165,12 +165,11 @@ func (a *BluezAgent) DisplayPasskey(device dbus.ObjectPath, passkey uint32, ente
|
||||
log.Infof("[BluezAgent] DisplayPasskey: device=%s, passkey=%06d, entered=%d", device, passkey, entered)
|
||||
|
||||
if entered == 0 {
|
||||
pk := passkey
|
||||
_, err := a.promptFor(device, "display-passkey", []string{}, nil)
|
||||
passkeyStr := strconv.FormatUint(uint64(passkey), 10)
|
||||
_, err := a.promptFor(device, "display-passkey", []string{}, &passkeyStr)
|
||||
if err != nil {
|
||||
log.Warnf("[BluezAgent] DisplayPasskey acknowledgment failed: %v", err)
|
||||
}
|
||||
_ = pk
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -179,7 +178,8 @@ func (a *BluezAgent) DisplayPasskey(device dbus.ObjectPath, passkey uint32, ente
|
||||
func (a *BluezAgent) RequestConfirmation(device dbus.ObjectPath, passkey uint32) *dbus.Error {
|
||||
log.Infof("[BluezAgent] RequestConfirmation: device=%s, passkey=%06d", device, passkey)
|
||||
|
||||
secrets, err := a.promptFor(device, "confirm", []string{"decision"}, nil)
|
||||
passkeyStr := strconv.FormatUint(uint64(passkey), 10)
|
||||
secrets, err := a.promptFor(device, "confirm", []string{"decision"}, &passkeyStr)
|
||||
if err != nil {
|
||||
log.Warnf("[BluezAgent] RequestConfirmation failed: %v", err)
|
||||
return a.errorFrom(err)
|
||||
|
||||
@@ -354,21 +354,25 @@ func (m *Manager) handleDevicePropertiesChanged(path dbus.ObjectPath, changed ma
|
||||
_, hasTrusted := changed["Trusted"]
|
||||
|
||||
if hasPaired {
|
||||
if paired, ok := pairedVar.Value().(bool); ok && paired {
|
||||
devicePath := string(path)
|
||||
_, wasPending := m.pendingPairings.LoadAndDelete(devicePath)
|
||||
devicePath := string(path)
|
||||
if paired, ok := pairedVar.Value().(bool); ok {
|
||||
if paired {
|
||||
_, wasPending := m.pendingPairings.LoadAndDelete(devicePath)
|
||||
|
||||
if wasPending {
|
||||
select {
|
||||
case m.eventQueue <- func() {
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
log.Infof("[Bluetooth] Auto-connecting newly paired device: %s", devicePath)
|
||||
if err := m.ConnectDevice(devicePath); err != nil {
|
||||
log.Warnf("[Bluetooth] Auto-connect failed: %v", err)
|
||||
if wasPending {
|
||||
select {
|
||||
case m.eventQueue <- func() {
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
log.Infof("[Bluetooth] Auto-connecting newly paired device: %s", devicePath)
|
||||
if err := m.ConnectDevice(devicePath); err != nil {
|
||||
log.Warnf("[Bluetooth] Auto-connect failed: %v", err)
|
||||
}
|
||||
}:
|
||||
default:
|
||||
}
|
||||
}:
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
m.pendingPairings.Delete(devicePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,8 +100,8 @@ func (m *Manager) setupRegistry() error {
|
||||
log.Infof("DWL: found %s", dwl_ipc.ZdwlIpcManagerV2InterfaceName)
|
||||
manager := dwl_ipc.NewZdwlIpcManagerV2(m.ctx)
|
||||
version := e.Version
|
||||
if version > 1 {
|
||||
version = 1
|
||||
if version > 2 {
|
||||
version = 2
|
||||
}
|
||||
if err := registry.Bind(e.Name, e.Interface, version, manager); err == nil {
|
||||
dwlMgr = manager
|
||||
@@ -282,6 +282,14 @@ func (m *Manager) setupOutput(manager *dwl_ipc.ZdwlIpcManagerV2, output *wlclien
|
||||
outState.layoutSymbol = e.Layout
|
||||
})
|
||||
|
||||
ipcOutput.SetKbLayoutHandler(func(e dwl_ipc.ZdwlIpcOutputV2KbLayoutEvent) {
|
||||
outState.kbLayout = e.KbLayout
|
||||
})
|
||||
|
||||
ipcOutput.SetKeymodeHandler(func(e dwl_ipc.ZdwlIpcOutputV2KeymodeEvent) {
|
||||
outState.keymode = e.Keymode
|
||||
})
|
||||
|
||||
ipcOutput.SetFrameHandler(func(e dwl_ipc.ZdwlIpcOutputV2FrameEvent) {
|
||||
m.updateState()
|
||||
})
|
||||
@@ -310,6 +318,8 @@ func (m *Manager) updateState() {
|
||||
LayoutSymbol: out.layoutSymbol,
|
||||
Title: out.title,
|
||||
AppID: out.appID,
|
||||
KbLayout: out.kbLayout,
|
||||
Keymode: out.keymode,
|
||||
}
|
||||
|
||||
if out.active != 0 {
|
||||
|
||||
@@ -22,6 +22,8 @@ type OutputState struct {
|
||||
LayoutSymbol string `json:"layoutSymbol"`
|
||||
Title string `json:"title"`
|
||||
AppID string `json:"appId"`
|
||||
KbLayout string `json:"kbLayout"`
|
||||
Keymode string `json:"keymode"`
|
||||
}
|
||||
|
||||
type State struct {
|
||||
@@ -73,6 +75,8 @@ type outputState struct {
|
||||
layoutSymbol string
|
||||
title string
|
||||
appID string
|
||||
kbLayout string
|
||||
keymode string
|
||||
}
|
||||
|
||||
func (m *Manager) GetState() State {
|
||||
@@ -147,6 +151,12 @@ func stateChanged(old, new *State) bool {
|
||||
if oldOut.AppID != newOut.AppID {
|
||||
return true
|
||||
}
|
||||
if oldOut.KbLayout != newOut.KbLayout {
|
||||
return true
|
||||
}
|
||||
if oldOut.Keymode != newOut.Keymode {
|
||||
return true
|
||||
}
|
||||
if len(oldOut.Tags) != len(newOut.Tags) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -9,6 +9,35 @@ import (
|
||||
wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
|
||||
)
|
||||
|
||||
func CheckCapability() bool {
|
||||
display, err := wlclient.Connect("")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer display.Destroy()
|
||||
|
||||
registry, err := display.GetRegistry()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer registry.Destroy()
|
||||
|
||||
found := false
|
||||
|
||||
registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) {
|
||||
if e.Interface == ext_workspace.ExtWorkspaceManagerV1InterfaceName {
|
||||
found = true
|
||||
}
|
||||
})
|
||||
|
||||
// Roundtrip to ensure all registry events are processed
|
||||
if err := display.Roundtrip(); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return found
|
||||
}
|
||||
|
||||
func NewManager(display *wlclient.Display) (*Manager, error) {
|
||||
m := &Manager{
|
||||
display: display,
|
||||
@@ -75,6 +104,9 @@ func (m *Manager) setupRegistry() error {
|
||||
output.SetNameHandler(func(ev wlclient.OutputNameEvent) {
|
||||
m.outputNames.Store(outputID, ev.Name)
|
||||
log.Debugf("ExtWorkspace: Output %d (%s) name received", outputID, ev.Name)
|
||||
m.post(func() {
|
||||
m.updateState()
|
||||
})
|
||||
})
|
||||
}
|
||||
return
|
||||
@@ -295,14 +327,8 @@ func (m *Manager) updateState() {
|
||||
|
||||
outputs := make([]string, 0)
|
||||
for outputID := range group.outputIDs {
|
||||
if name, ok := m.outputNames.Load(outputID); ok {
|
||||
if name != "" {
|
||||
outputs = append(outputs, name)
|
||||
} else {
|
||||
outputs = append(outputs, fmt.Sprintf("output-%d", outputID))
|
||||
}
|
||||
} else {
|
||||
outputs = append(outputs, fmt.Sprintf("output-%d", outputID))
|
||||
if name, ok := m.outputNames.Load(outputID); ok && name != "" {
|
||||
outputs = append(outputs, name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -140,8 +140,20 @@ func RouteRequest(conn net.Conn, req models.Request) {
|
||||
|
||||
if strings.HasPrefix(req.Method, "extworkspace.") {
|
||||
if extWorkspaceManager == nil {
|
||||
models.RespondError(conn, req.ID, "extworkspace manager not initialized")
|
||||
return
|
||||
if extWorkspaceAvailable.Load() {
|
||||
extWorkspaceInitMutex.Lock()
|
||||
if extWorkspaceManager == nil {
|
||||
if err := InitializeExtWorkspaceManager(); err != nil {
|
||||
extWorkspaceInitMutex.Unlock()
|
||||
models.RespondError(conn, req.ID, "extworkspace manager not available")
|
||||
return
|
||||
}
|
||||
}
|
||||
extWorkspaceInitMutex.Unlock()
|
||||
} else {
|
||||
models.RespondError(conn, req.ID, "extworkspace manager not initialized")
|
||||
return
|
||||
}
|
||||
}
|
||||
extWorkspaceReq := extworkspace.Request{
|
||||
ID: req.ID,
|
||||
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap"
|
||||
)
|
||||
|
||||
const APIVersion = 18
|
||||
const APIVersion = 19
|
||||
|
||||
type Capabilities struct {
|
||||
Capabilities []string `json:"capabilities"`
|
||||
@@ -63,6 +63,8 @@ var wlContext *wlcontext.SharedContext
|
||||
var capabilitySubscribers syncmap.Map[string, chan ServerInfo]
|
||||
var cupsSubscribers syncmap.Map[string, bool]
|
||||
var cupsSubscriberCount atomic.Int32
|
||||
var extWorkspaceAvailable atomic.Bool
|
||||
var extWorkspaceInitMutex sync.Mutex
|
||||
|
||||
func getSocketDir() string {
|
||||
if runtime := os.Getenv("XDG_RUNTIME_DIR"); runtime != "" {
|
||||
@@ -361,7 +363,7 @@ func getCapabilities() Capabilities {
|
||||
caps = append(caps, "dwl")
|
||||
}
|
||||
|
||||
if extWorkspaceManager != nil {
|
||||
if extWorkspaceAvailable.Load() {
|
||||
caps = append(caps, "extworkspace")
|
||||
}
|
||||
|
||||
@@ -411,7 +413,7 @@ func getServerInfo() ServerInfo {
|
||||
caps = append(caps, "dwl")
|
||||
}
|
||||
|
||||
if extWorkspaceManager != nil {
|
||||
if extWorkspaceAvailable.Load() {
|
||||
caps = append(caps, "extworkspace")
|
||||
}
|
||||
|
||||
@@ -810,12 +812,14 @@ func handleSubscribe(conn net.Conn, req models.Request) {
|
||||
}
|
||||
|
||||
if shouldSubscribe("extworkspace") {
|
||||
if extWorkspaceManager == nil {
|
||||
if err := InitializeExtWorkspaceManager(); err != nil {
|
||||
log.Warnf("Failed to initialize ExtWorkspace manager for subscription: %v", err)
|
||||
} else {
|
||||
notifyCapabilityChange()
|
||||
if extWorkspaceManager == nil && extWorkspaceAvailable.Load() {
|
||||
extWorkspaceInitMutex.Lock()
|
||||
if extWorkspaceManager == nil {
|
||||
if err := InitializeExtWorkspaceManager(); err != nil {
|
||||
log.Warnf("Failed to initialize ExtWorkspace manager for subscription: %v", err)
|
||||
}
|
||||
}
|
||||
extWorkspaceInitMutex.Unlock()
|
||||
}
|
||||
|
||||
if extWorkspaceManager != nil {
|
||||
@@ -1141,11 +1145,18 @@ func Start(printDocs bool) error {
|
||||
log.Info(" cups.cancelJob - Cancel job (params: printerName, jobID)")
|
||||
log.Info(" cups.purgeJobs - Cancel all jobs (params: printerName)")
|
||||
log.Info("DWL:")
|
||||
log.Info(" dwl.getState - Get current dwl state (tags, windows, layouts)")
|
||||
log.Info(" dwl.getState - Get current dwl state (tags, windows, layouts, keyboard)")
|
||||
log.Info(" dwl.setTags - Set active tags (params: output, tagmask, toggleTagset)")
|
||||
log.Info(" dwl.setClientTags - Set focused client tags (params: output, andTags, xorTags)")
|
||||
log.Info(" dwl.setLayout - Set layout (params: output, index)")
|
||||
log.Info(" dwl.subscribe - Subscribe to dwl state changes (streaming)")
|
||||
log.Info(" Output state includes:")
|
||||
log.Info(" - tags : Tag states (active, clients, focused)")
|
||||
log.Info(" - layoutSymbol : Current layout name")
|
||||
log.Info(" - title : Focused window title")
|
||||
log.Info(" - appId : Focused window app ID")
|
||||
log.Info(" - kbLayout : Current keyboard layout")
|
||||
log.Info(" - keymode : Current keybind mode")
|
||||
log.Info("ExtWorkspace:")
|
||||
log.Info(" extworkspace.getState - Get current workspace state (groups, workspaces)")
|
||||
log.Info(" extworkspace.activateWorkspace - Activate workspace (params: groupID, workspaceID)")
|
||||
@@ -1241,6 +1252,14 @@ func Start(printDocs bool) error {
|
||||
log.Debugf("DWL manager unavailable: %v", err)
|
||||
}
|
||||
|
||||
if extworkspace.CheckCapability() {
|
||||
extWorkspaceAvailable.Store(true)
|
||||
log.Info("ExtWorkspace capability detected and will be available on subscription")
|
||||
} else {
|
||||
log.Debug("ExtWorkspace capability not available")
|
||||
extWorkspaceAvailable.Store(false)
|
||||
}
|
||||
|
||||
if err := InitializeWlrOutputManager(); err != nil {
|
||||
log.Debugf("WlrOutput manager unavailable: %v", err)
|
||||
}
|
||||
|
||||
33
distro/nix/common.nix
Normal file
33
distro/nix/common.nix
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
dmsPkgs,
|
||||
...
|
||||
}: let
|
||||
cfg = config.programs.dankMaterialShell;
|
||||
in {
|
||||
qmlPath = "${dmsPkgs.dankMaterialShell}/etc/xdg/quickshell/dms";
|
||||
|
||||
packages =
|
||||
[
|
||||
pkgs.material-symbols
|
||||
pkgs.inter
|
||||
pkgs.fira-code
|
||||
|
||||
pkgs.ddcutil
|
||||
pkgs.libsForQt5.qt5ct
|
||||
pkgs.kdePackages.qt6ct
|
||||
|
||||
dmsPkgs.dmsCli
|
||||
]
|
||||
++ lib.optional cfg.enableSystemMonitoring dmsPkgs.dgop
|
||||
++ lib.optionals cfg.enableClipboard [pkgs.cliphist pkgs.wl-clipboard]
|
||||
++ lib.optionals cfg.enableVPN [pkgs.glib pkgs.networkmanager]
|
||||
++ lib.optional cfg.enableBrightnessControl pkgs.brightnessctl
|
||||
++ lib.optional cfg.enableColorPicker pkgs.hyprpicker
|
||||
++ lib.optional cfg.enableDynamicTheming pkgs.matugen
|
||||
++ lib.optional cfg.enableAudioWavelength pkgs.cava
|
||||
++ lib.optional cfg.enableCalendarEvents pkgs.khal
|
||||
++ lib.optional cfg.enableSystemSound pkgs.kdePackages.qtmultimedia;
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
dmsPkgs,
|
||||
...
|
||||
}: let
|
||||
cfg = config.programs.dankMaterialShell;
|
||||
jsonFormat = pkgs.formats.json { };
|
||||
in {
|
||||
imports = [
|
||||
(lib.mkRemovedOptionModule ["programs" "dankMaterialShell" "enableNightMode"] "Night mode is now always available.")
|
||||
(lib.mkRenamedOptionModule ["programs" "dankMaterialShell" "enableSystemd"] ["programs" "dankMaterialShell" "systemd" "enable"])
|
||||
];
|
||||
options.programs.dankMaterialShell = with lib.types; {
|
||||
enable = lib.mkEnableOption "DankMaterialShell";
|
||||
|
||||
systemd = {
|
||||
enable = lib.mkEnableOption "DankMaterialShell systemd startup";
|
||||
restartIfChanged = lib.mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = "Auto-restart dms.service when dankMaterialShell changes";
|
||||
};
|
||||
};
|
||||
enableSystemMonitoring = lib.mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to use system monitoring widgets";
|
||||
};
|
||||
enableClipboard = lib.mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to use the clipboard widget";
|
||||
};
|
||||
enableVPN = lib.mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to use the VPN widget";
|
||||
};
|
||||
enableBrightnessControl = lib.mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to have brightness/backlight support";
|
||||
};
|
||||
enableColorPicker = lib.mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to have color picking support";
|
||||
};
|
||||
enableDynamicTheming = lib.mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to have dynamic theming support";
|
||||
};
|
||||
enableAudioWavelength = lib.mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to have audio waveleng support";
|
||||
};
|
||||
enableCalendarEvents = lib.mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = "Add calendar events support via khal";
|
||||
};
|
||||
enableSystemSound = lib.mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to have system sound support";
|
||||
};
|
||||
quickshell = {
|
||||
package = lib.mkPackageOption pkgs "quickshell" {};
|
||||
};
|
||||
|
||||
default = {
|
||||
settings = lib.mkOption {
|
||||
type = jsonFormat.type;
|
||||
default = { };
|
||||
description = "The default settings are only read if the settings.json file don't exist";
|
||||
};
|
||||
session = lib.mkOption {
|
||||
type = jsonFormat.type;
|
||||
default = { };
|
||||
description = "The default session are only read if the session.json file don't exist";
|
||||
};
|
||||
};
|
||||
|
||||
plugins = lib.mkOption {
|
||||
type = attrsOf (types.submodule ({ config, ... }: {
|
||||
options = {
|
||||
enable = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Whether to link this plugin";
|
||||
};
|
||||
src = lib.mkOption {
|
||||
type = types.path;
|
||||
description = "Source to link to DMS plugins directory";
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = {};
|
||||
description = "DMS Plugins to install";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable
|
||||
{
|
||||
programs.quickshell = {
|
||||
enable = true;
|
||||
package = cfg.quickshell.package;
|
||||
|
||||
configs.dms = "${dmsPkgs.dankMaterialShell}/etc/xdg/quickshell/dms";
|
||||
};
|
||||
|
||||
systemd.user.services.dms = lib.mkIf cfg.systemd.enable {
|
||||
Unit = {
|
||||
Description = "DankMaterialShell";
|
||||
PartOf = [ config.wayland.systemd.target ];
|
||||
After = [ config.wayland.systemd.target ];
|
||||
X-Restart-Triggers = lib.optional cfg.systemd.restartIfChanged config.programs.quickshell.configs.dms;
|
||||
};
|
||||
|
||||
Service = {
|
||||
ExecStart = lib.getExe dmsPkgs.dmsCli + " run --session";
|
||||
Restart = "on-failure";
|
||||
};
|
||||
|
||||
Install.WantedBy = [ config.wayland.systemd.target ];
|
||||
};
|
||||
|
||||
xdg.stateFile."DankMaterialShell/default-session.json" = lib.mkIf (cfg.default.session != { }) {
|
||||
source = jsonFormat.generate "default-session.json" cfg.default.session;
|
||||
};
|
||||
|
||||
xdg.configFile = lib.mkMerge [
|
||||
(lib.mapAttrs' (name: plugin: {
|
||||
name = "DankMaterialShell/plugins/${name}";
|
||||
value.source = plugin.src;
|
||||
}) (lib.filterAttrs (n: v: v.enable) cfg.plugins))
|
||||
{
|
||||
"DankMaterialShell/default-settings.json" = lib.mkIf (cfg.default.settings != { }) {
|
||||
source = jsonFormat.generate "default-settings.json" cfg.default.settings;
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
home.packages =
|
||||
[
|
||||
pkgs.material-symbols
|
||||
pkgs.inter
|
||||
pkgs.fira-code
|
||||
|
||||
pkgs.ddcutil
|
||||
pkgs.libsForQt5.qt5ct
|
||||
pkgs.kdePackages.qt6ct
|
||||
|
||||
dmsPkgs.dmsCli
|
||||
]
|
||||
++ lib.optional cfg.enableSystemMonitoring dmsPkgs.dgop
|
||||
++ lib.optionals cfg.enableClipboard [pkgs.cliphist pkgs.wl-clipboard]
|
||||
++ lib.optionals cfg.enableVPN [pkgs.glib pkgs.networkmanager]
|
||||
++ lib.optional cfg.enableBrightnessControl pkgs.brightnessctl
|
||||
++ lib.optional cfg.enableColorPicker pkgs.hyprpicker
|
||||
++ lib.optional cfg.enableDynamicTheming pkgs.matugen
|
||||
++ lib.optional cfg.enableAudioWavelength pkgs.cava
|
||||
++ lib.optional cfg.enableCalendarEvents pkgs.khal
|
||||
++ lib.optional cfg.enableSystemSound pkgs.kdePackages.qtmultimedia;
|
||||
};
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
user = config.services.greetd.settings.default_session.user;
|
||||
|
||||
greeterScript = pkgs.writeShellScriptBin "dms-greeter" ''
|
||||
export PATH=$PATH:${lib.makeBinPath [ cfg.quickshell.package config.programs.${cfg.compositor.name}.package ]}
|
||||
export PATH=$PATH:${lib.makeBinPath [cfg.quickshell.package config.programs.${cfg.compositor.name}.package]}
|
||||
${lib.escapeShellArgs ([
|
||||
"sh"
|
||||
"${../../quickshell/Modules/Greetd/assets/dms-greeter}"
|
||||
@@ -28,11 +28,9 @@
|
||||
])} ${lib.optionalString cfg.logs.save "> ${cfg.logs.path} 2>&1"}
|
||||
'';
|
||||
in {
|
||||
imports =
|
||||
let
|
||||
msg = "The option 'programs.dankMaterialShell.greeter.compositor.extraConfig' is deprecated. Please use 'programs.dankMaterialShell.greeter.compositor.customConfig' instead.";
|
||||
in
|
||||
[ (lib.mkRemovedOptionModule [ "programs" "dankMaterialShell" "greeter" "compositor" "extraConfig" ] msg) ];
|
||||
imports = let
|
||||
msg = "The option 'programs.dankMaterialShell.greeter.compositor.extraConfig' is deprecated. Please use 'programs.dankMaterialShell.greeter.compositor.customConfig' instead.";
|
||||
in [(lib.mkRemovedOptionModule ["programs" "dankMaterialShell" "greeter" "compositor" "extraConfig"] msg)];
|
||||
|
||||
options.programs.dankMaterialShell.greeter = {
|
||||
enable = lib.mkEnableOption "DankMaterialShell greeter";
|
||||
@@ -77,7 +75,7 @@ in {
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = (config.users.users.${user} or { }) != { };
|
||||
assertion = (config.users.users.${user} or {}) != {};
|
||||
message = ''
|
||||
dmsgreeter: user set for greetd default_session ${user} does not exist. Please create it before referencing it.
|
||||
'';
|
||||
@@ -95,8 +93,10 @@ in {
|
||||
systemd.tmpfiles.settings."10-dmsgreeter" = {
|
||||
"/var/lib/dmsgreeter".d = {
|
||||
user = user;
|
||||
group = if config.users.users.${user}.group != ""
|
||||
then config.users.users.${user}.group else "greeter";
|
||||
group =
|
||||
if config.users.users.${user}.group != ""
|
||||
then config.users.users.${user}.group
|
||||
else "greeter";
|
||||
mode = "0755";
|
||||
};
|
||||
};
|
||||
@@ -106,7 +106,8 @@ in {
|
||||
if [ -f "${f}" ]; then
|
||||
cp "${f}" .
|
||||
fi
|
||||
'') cfg.configFiles)}
|
||||
'')
|
||||
cfg.configFiles)}
|
||||
|
||||
if [ -f session.json ]; then
|
||||
if cp "$(${lib.getExe pkgs.jq} -r '.wallpaperPath' session.json)" wallpaper.jpg; then
|
||||
|
||||
94
distro/nix/home.nix
Normal file
94
distro/nix/home.nix
Normal file
@@ -0,0 +1,94 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
dmsPkgs,
|
||||
...
|
||||
}: let
|
||||
cfg = config.programs.dankMaterialShell;
|
||||
jsonFormat = pkgs.formats.json {};
|
||||
common = import ./common.nix {inherit config pkgs lib dmsPkgs;};
|
||||
in {
|
||||
imports = [
|
||||
./options.nix
|
||||
(lib.mkRemovedOptionModule ["programs" "dankMaterialShell" "enableNightMode"] "Night mode is now always available.")
|
||||
(lib.mkRenamedOptionModule ["programs" "dankMaterialShell" "enableSystemd"] ["programs" "dankMaterialShell" "systemd" "enable"])
|
||||
];
|
||||
|
||||
options.programs.dankMaterialShell = with lib.types; {
|
||||
default = {
|
||||
settings = lib.mkOption {
|
||||
type = jsonFormat.type;
|
||||
default = {};
|
||||
description = "The default settings are only read if the settings.json file don't exist";
|
||||
};
|
||||
session = lib.mkOption {
|
||||
type = jsonFormat.type;
|
||||
default = {};
|
||||
description = "The default session are only read if the session.json file don't exist";
|
||||
};
|
||||
};
|
||||
|
||||
plugins = lib.mkOption {
|
||||
type = attrsOf (types.submodule ({config, ...}: {
|
||||
options = {
|
||||
enable = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Whether to link this plugin";
|
||||
};
|
||||
src = lib.mkOption {
|
||||
type = types.path;
|
||||
description = "Source to link to DMS plugins directory";
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = {};
|
||||
description = "DMS Plugins to install";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable
|
||||
{
|
||||
programs.quickshell = {
|
||||
enable = true;
|
||||
package = cfg.quickshell.package;
|
||||
|
||||
configs.dms = common.qmlPath;
|
||||
};
|
||||
|
||||
systemd.user.services.dms = lib.mkIf cfg.systemd.enable {
|
||||
Unit = {
|
||||
Description = "DankMaterialShell";
|
||||
PartOf = [config.wayland.systemd.target];
|
||||
After = [config.wayland.systemd.target];
|
||||
X-Restart-Triggers = lib.optional cfg.systemd.restartIfChanged common.qmlPath;
|
||||
};
|
||||
|
||||
Service = {
|
||||
ExecStart = lib.getExe dmsPkgs.dmsCli + " run --session";
|
||||
Restart = "on-failure";
|
||||
};
|
||||
|
||||
Install.WantedBy = [config.wayland.systemd.target];
|
||||
};
|
||||
|
||||
xdg.stateFile."DankMaterialShell/default-session.json" = lib.mkIf (cfg.default.session != {}) {
|
||||
source = jsonFormat.generate "default-session.json" cfg.default.session;
|
||||
};
|
||||
|
||||
xdg.configFile = lib.mkMerge [
|
||||
(lib.mapAttrs' (name: plugin: {
|
||||
name = "DankMaterialShell/plugins/${name}";
|
||||
value.source = plugin.src;
|
||||
}) (lib.filterAttrs (n: v: v.enable) cfg.plugins))
|
||||
{
|
||||
"DankMaterialShell/default-settings.json" = lib.mkIf (cfg.default.settings != {}) {
|
||||
source = jsonFormat.generate "default-settings.json" cfg.default.settings;
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = common.packages;
|
||||
};
|
||||
}
|
||||
36
distro/nix/nixos.nix
Normal file
36
distro/nix/nixos.nix
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
dmsPkgs,
|
||||
...
|
||||
}: let
|
||||
cfg = config.programs.dankMaterialShell;
|
||||
common = import ./common.nix {inherit config pkgs lib dmsPkgs;};
|
||||
in {
|
||||
imports = [
|
||||
./options.nix
|
||||
];
|
||||
|
||||
config = lib.mkIf cfg.enable
|
||||
{
|
||||
environment.etc."xdg/quickshell/dms".source = "${dmsPkgs.dankMaterialShell}/etc/xdg/quickshell/dms";
|
||||
|
||||
systemd.user.services.dms = lib.mkIf cfg.systemd.enable {
|
||||
description = "DankMaterialShell";
|
||||
path = [cfg.quickshell.package];
|
||||
|
||||
partOf = ["graphical-session.target"];
|
||||
after = ["graphical-session.target"];
|
||||
wantedBy = ["graphical-session.target"];
|
||||
restartTriggers = lib.optional cfg.systemd.restartIfChanged common.qmlPath;
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = lib.getExe dmsPkgs.dmsCli + " run --session";
|
||||
Restart = "on-failure";
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = [cfg.quickshell.package] ++ common.packages;
|
||||
};
|
||||
}
|
||||
68
distro/nix/options.nix
Normal file
68
distro/nix/options.nix
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) types;
|
||||
in {
|
||||
options.programs.dankMaterialShell = {
|
||||
enable = lib.mkEnableOption "DankMaterialShell";
|
||||
|
||||
systemd = {
|
||||
enable = lib.mkEnableOption "DankMaterialShell systemd startup";
|
||||
restartIfChanged = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Auto-restart dms.service when dankMaterialShell changes";
|
||||
};
|
||||
};
|
||||
enableSystemMonitoring = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to use system monitoring widgets";
|
||||
};
|
||||
enableClipboard = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to use the clipboard widget";
|
||||
};
|
||||
enableVPN = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to use the VPN widget";
|
||||
};
|
||||
enableBrightnessControl = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to have brightness/backlight support";
|
||||
};
|
||||
enableColorPicker = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to have color picking support";
|
||||
};
|
||||
enableDynamicTheming = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to have dynamic theming support";
|
||||
};
|
||||
enableAudioWavelength = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to have audio wavelength support";
|
||||
};
|
||||
enableCalendarEvents = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Add calendar events support via khal";
|
||||
};
|
||||
enableSystemSound = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Add needed dependencies to have system sound support";
|
||||
};
|
||||
quickshell = {
|
||||
package = lib.mkPackageOption pkgs "quickshell" {};
|
||||
};
|
||||
};
|
||||
}
|
||||
21
flake.nix
21
flake.nix
@@ -24,6 +24,11 @@
|
||||
dgop = dgop.packages.${pkgs.stdenv.hostPlatform.system}.dgop;
|
||||
dankMaterialShell = self.packages.${pkgs.stdenv.hostPlatform.system}.dankMaterialShell;
|
||||
};
|
||||
mkModuleWithDmsPkgs = path: args @ {pkgs, ...}: {
|
||||
imports = [
|
||||
(import path (args // {dmsPkgs = buildDmsPkgs pkgs;}))
|
||||
];
|
||||
};
|
||||
in {
|
||||
formatter = forEachSystem (_: pkgs: pkgs.alejandra);
|
||||
|
||||
@@ -81,20 +86,12 @@
|
||||
}
|
||||
);
|
||||
|
||||
homeModules.dankMaterialShell.default = {pkgs, ...}: let
|
||||
dmsPkgs = buildDmsPkgs pkgs;
|
||||
in {
|
||||
imports = [./distro/nix/default.nix];
|
||||
_module.args.dmsPkgs = dmsPkgs;
|
||||
};
|
||||
homeModules.dankMaterialShell.default = mkModuleWithDmsPkgs ./distro/nix/home.nix;
|
||||
|
||||
homeModules.dankMaterialShell.niri = import ./distro/nix/niri.nix;
|
||||
|
||||
nixosModules.greeter = {pkgs, ...}: let
|
||||
dmsPkgs = buildDmsPkgs pkgs;
|
||||
in {
|
||||
imports = [./distro/nix/greeter.nix];
|
||||
_module.args.dmsPkgs = dmsPkgs;
|
||||
};
|
||||
nixosModules.dankMaterialShell = mkModuleWithDmsPkgs ./distro/nix/nixos.nix;
|
||||
|
||||
nixosModules.greeter = mkModuleWithDmsPkgs ./distro/nix/greeter.nix;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -12,5 +12,9 @@ Singleton {
|
||||
if (!modal.allowStacking) {
|
||||
closeAllModalsExcept(modal)
|
||||
}
|
||||
if (!modal.keepPopoutsOpen) {
|
||||
PopoutManager.closeAllPopouts()
|
||||
}
|
||||
TrayMenuManager.closeAllMenus()
|
||||
}
|
||||
}
|
||||
|
||||
164
quickshell/Common/PopoutManager.qml
Normal file
164
quickshell/Common/PopoutManager.qml
Normal file
@@ -0,0 +1,164 @@
|
||||
pragma Singleton
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property var currentPopoutsByScreen: ({})
|
||||
property var currentPopoutTriggers: ({})
|
||||
|
||||
function showPopout(popout) {
|
||||
if (!popout || !popout.screen) return
|
||||
|
||||
const screenName = popout.screen.name
|
||||
|
||||
for (const otherScreenName in currentPopoutsByScreen) {
|
||||
const otherPopout = currentPopoutsByScreen[otherScreenName]
|
||||
if (!otherPopout || otherPopout === popout) continue
|
||||
|
||||
if (otherPopout.dashVisible !== undefined) {
|
||||
otherPopout.dashVisible = false
|
||||
} else if (otherPopout.notificationHistoryVisible !== undefined) {
|
||||
otherPopout.notificationHistoryVisible = false
|
||||
} else {
|
||||
otherPopout.close()
|
||||
}
|
||||
}
|
||||
|
||||
currentPopoutsByScreen[screenName] = popout
|
||||
ModalManager.closeAllModalsExcept(null)
|
||||
TrayMenuManager.closeAllMenus()
|
||||
}
|
||||
|
||||
function hidePopout(popout) {
|
||||
if (!popout || !popout.screen) return
|
||||
|
||||
const screenName = popout.screen.name
|
||||
if (currentPopoutsByScreen[screenName] === popout) {
|
||||
currentPopoutsByScreen[screenName] = null
|
||||
currentPopoutTriggers[screenName] = null
|
||||
}
|
||||
}
|
||||
|
||||
function closeAllPopouts() {
|
||||
for (const screenName in currentPopoutsByScreen) {
|
||||
const popout = currentPopoutsByScreen[screenName]
|
||||
if (!popout) continue
|
||||
|
||||
if (popout.dashVisible !== undefined) {
|
||||
popout.dashVisible = false
|
||||
} else if (popout.notificationHistoryVisible !== undefined) {
|
||||
popout.notificationHistoryVisible = false
|
||||
} else {
|
||||
popout.close()
|
||||
}
|
||||
}
|
||||
currentPopoutsByScreen = {}
|
||||
}
|
||||
|
||||
function getActivePopout(screen) {
|
||||
if (!screen) return null
|
||||
return currentPopoutsByScreen[screen.name] || null
|
||||
}
|
||||
|
||||
function requestPopout(popout, tabIndex, triggerSource) {
|
||||
if (!popout || !popout.screen) return
|
||||
|
||||
const screenName = popout.screen.name
|
||||
const currentPopout = currentPopoutsByScreen[screenName]
|
||||
const triggerId = triggerSource !== undefined ? triggerSource : tabIndex
|
||||
|
||||
let justClosedSamePopout = false
|
||||
for (const otherScreenName in currentPopoutsByScreen) {
|
||||
if (otherScreenName === screenName) continue
|
||||
const otherPopout = currentPopoutsByScreen[otherScreenName]
|
||||
if (!otherPopout) continue
|
||||
|
||||
if (otherPopout === popout) {
|
||||
justClosedSamePopout = true
|
||||
}
|
||||
|
||||
if (otherPopout.dashVisible !== undefined) {
|
||||
otherPopout.dashVisible = false
|
||||
} else if (otherPopout.notificationHistoryVisible !== undefined) {
|
||||
otherPopout.notificationHistoryVisible = false
|
||||
} else {
|
||||
otherPopout.close()
|
||||
}
|
||||
}
|
||||
|
||||
if (currentPopout && currentPopout !== popout) {
|
||||
if (currentPopout.dashVisible !== undefined) {
|
||||
currentPopout.dashVisible = false
|
||||
} else if (currentPopout.notificationHistoryVisible !== undefined) {
|
||||
currentPopout.notificationHistoryVisible = false
|
||||
} else {
|
||||
currentPopout.close()
|
||||
}
|
||||
}
|
||||
|
||||
if (currentPopout === popout && popout.shouldBeVisible) {
|
||||
if (triggerId !== undefined && currentPopoutTriggers[screenName] === triggerId) {
|
||||
if (popout.dashVisible !== undefined) {
|
||||
popout.dashVisible = false
|
||||
} else if (popout.notificationHistoryVisible !== undefined) {
|
||||
popout.notificationHistoryVisible = false
|
||||
} else {
|
||||
popout.close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (triggerId === undefined) {
|
||||
if (popout.dashVisible !== undefined) {
|
||||
popout.dashVisible = false
|
||||
} else if (popout.notificationHistoryVisible !== undefined) {
|
||||
popout.notificationHistoryVisible = false
|
||||
} else {
|
||||
popout.close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (tabIndex !== undefined && popout.currentTabIndex !== undefined) {
|
||||
popout.currentTabIndex = tabIndex
|
||||
}
|
||||
currentPopoutTriggers[screenName] = triggerId
|
||||
return
|
||||
}
|
||||
|
||||
currentPopoutTriggers[screenName] = triggerId
|
||||
currentPopoutsByScreen[screenName] = popout
|
||||
|
||||
if (tabIndex !== undefined && popout.currentTabIndex !== undefined) {
|
||||
popout.currentTabIndex = tabIndex
|
||||
}
|
||||
|
||||
if (currentPopout !== popout) {
|
||||
ModalManager.closeAllModalsExcept(null)
|
||||
}
|
||||
TrayMenuManager.closeAllMenus()
|
||||
|
||||
if (justClosedSamePopout) {
|
||||
Qt.callLater(() => {
|
||||
if (popout.dashVisible !== undefined) {
|
||||
popout.dashVisible = true
|
||||
} else if (popout.notificationHistoryVisible !== undefined) {
|
||||
popout.notificationHistoryVisible = true
|
||||
} else {
|
||||
popout.open()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if (popout.dashVisible !== undefined) {
|
||||
popout.dashVisible = true
|
||||
} else if (popout.notificationHistoryVisible !== undefined) {
|
||||
popout.notificationHistoryVisible = true
|
||||
} else {
|
||||
popout.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -422,29 +422,59 @@ Singleton {
|
||||
}
|
||||
|
||||
function setMonitorWallpaper(screenName, path) {
|
||||
var newMonitorWallpapers = Object.assign({}, monitorWallpapers)
|
||||
if (path && path !== "") {
|
||||
newMonitorWallpapers[screenName] = path
|
||||
} else {
|
||||
delete newMonitorWallpapers[screenName]
|
||||
var screen = null
|
||||
var screens = Quickshell.screens
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
if (screens[i].name === screenName) {
|
||||
screen = screens[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!screen) {
|
||||
console.warn("SessionData: Screen not found:", screenName)
|
||||
return
|
||||
}
|
||||
|
||||
var identifier = typeof SettingsData !== "undefined" ? SettingsData.getScreenDisplayName(screen) : screen.name
|
||||
|
||||
var newMonitorWallpapers = {}
|
||||
for (var key in monitorWallpapers) {
|
||||
var isThisScreen = key === screen.name || (screen.model && key === screen.model)
|
||||
if (!isThisScreen) {
|
||||
newMonitorWallpapers[key] = monitorWallpapers[key]
|
||||
}
|
||||
}
|
||||
|
||||
if (path && path !== "") {
|
||||
newMonitorWallpapers[identifier] = path
|
||||
}
|
||||
|
||||
monitorWallpapers = newMonitorWallpapers
|
||||
|
||||
if (perModeWallpaper) {
|
||||
if (isLightMode) {
|
||||
var newLight = Object.assign({}, monitorWallpapersLight)
|
||||
var newLight = {}
|
||||
for (var key in monitorWallpapersLight) {
|
||||
var isThisScreen = key === screen.name || (screen.model && key === screen.model)
|
||||
if (!isThisScreen) {
|
||||
newLight[key] = monitorWallpapersLight[key]
|
||||
}
|
||||
}
|
||||
if (path && path !== "") {
|
||||
newLight[screenName] = path
|
||||
} else {
|
||||
delete newLight[screenName]
|
||||
newLight[identifier] = path
|
||||
}
|
||||
monitorWallpapersLight = newLight
|
||||
} else {
|
||||
var newDark = Object.assign({}, monitorWallpapersDark)
|
||||
var newDark = {}
|
||||
for (var key in monitorWallpapersDark) {
|
||||
var isThisScreen = key === screen.name || (screen.model && key === screen.model)
|
||||
if (!isThisScreen) {
|
||||
newDark[key] = monitorWallpapersDark[key]
|
||||
}
|
||||
}
|
||||
if (path && path !== "") {
|
||||
newDark[screenName] = path
|
||||
} else {
|
||||
delete newDark[screenName]
|
||||
newDark[identifier] = path
|
||||
}
|
||||
monitorWallpapersDark = newDark
|
||||
}
|
||||
@@ -489,61 +519,153 @@ Singleton {
|
||||
}
|
||||
|
||||
function setMonitorCyclingEnabled(screenName, enabled) {
|
||||
var newSettings = Object.assign({}, monitorCyclingSettings)
|
||||
if (!newSettings[screenName]) {
|
||||
newSettings[screenName] = {
|
||||
var screen = null
|
||||
var screens = Quickshell.screens
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
if (screens[i].name === screenName) {
|
||||
screen = screens[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!screen) {
|
||||
console.warn("SessionData: Screen not found:", screenName)
|
||||
return
|
||||
}
|
||||
|
||||
var identifier = typeof SettingsData !== "undefined" ? SettingsData.getScreenDisplayName(screen) : screen.name
|
||||
|
||||
var newSettings = {}
|
||||
for (var key in monitorCyclingSettings) {
|
||||
var isThisScreen = key === screen.name || (screen.model && key === screen.model)
|
||||
if (!isThisScreen) {
|
||||
newSettings[key] = monitorCyclingSettings[key]
|
||||
}
|
||||
}
|
||||
|
||||
if (!newSettings[identifier]) {
|
||||
newSettings[identifier] = {
|
||||
"enabled": false,
|
||||
"mode": "interval",
|
||||
"interval": 300,
|
||||
"time": "06:00"
|
||||
}
|
||||
}
|
||||
newSettings[screenName].enabled = enabled
|
||||
newSettings[identifier].enabled = enabled
|
||||
monitorCyclingSettings = newSettings
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setMonitorCyclingMode(screenName, mode) {
|
||||
var newSettings = Object.assign({}, monitorCyclingSettings)
|
||||
if (!newSettings[screenName]) {
|
||||
newSettings[screenName] = {
|
||||
var screen = null
|
||||
var screens = Quickshell.screens
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
if (screens[i].name === screenName) {
|
||||
screen = screens[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!screen) {
|
||||
console.warn("SessionData: Screen not found:", screenName)
|
||||
return
|
||||
}
|
||||
|
||||
var identifier = typeof SettingsData !== "undefined" ? SettingsData.getScreenDisplayName(screen) : screen.name
|
||||
|
||||
var newSettings = {}
|
||||
for (var key in monitorCyclingSettings) {
|
||||
var isThisScreen = key === screen.name || (screen.model && key === screen.model)
|
||||
if (!isThisScreen) {
|
||||
newSettings[key] = monitorCyclingSettings[key]
|
||||
}
|
||||
}
|
||||
|
||||
if (!newSettings[identifier]) {
|
||||
newSettings[identifier] = {
|
||||
"enabled": false,
|
||||
"mode": "interval",
|
||||
"interval": 300,
|
||||
"time": "06:00"
|
||||
}
|
||||
}
|
||||
newSettings[screenName].mode = mode
|
||||
newSettings[identifier].mode = mode
|
||||
monitorCyclingSettings = newSettings
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setMonitorCyclingInterval(screenName, interval) {
|
||||
var newSettings = Object.assign({}, monitorCyclingSettings)
|
||||
if (!newSettings[screenName]) {
|
||||
newSettings[screenName] = {
|
||||
var screen = null
|
||||
var screens = Quickshell.screens
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
if (screens[i].name === screenName) {
|
||||
screen = screens[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!screen) {
|
||||
console.warn("SessionData: Screen not found:", screenName)
|
||||
return
|
||||
}
|
||||
|
||||
var identifier = typeof SettingsData !== "undefined" ? SettingsData.getScreenDisplayName(screen) : screen.name
|
||||
|
||||
var newSettings = {}
|
||||
for (var key in monitorCyclingSettings) {
|
||||
var isThisScreen = key === screen.name || (screen.model && key === screen.model)
|
||||
if (!isThisScreen) {
|
||||
newSettings[key] = monitorCyclingSettings[key]
|
||||
}
|
||||
}
|
||||
|
||||
if (!newSettings[identifier]) {
|
||||
newSettings[identifier] = {
|
||||
"enabled": false,
|
||||
"mode": "interval",
|
||||
"interval": 300,
|
||||
"time": "06:00"
|
||||
}
|
||||
}
|
||||
newSettings[screenName].interval = interval
|
||||
newSettings[identifier].interval = interval
|
||||
monitorCyclingSettings = newSettings
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setMonitorCyclingTime(screenName, time) {
|
||||
var newSettings = Object.assign({}, monitorCyclingSettings)
|
||||
if (!newSettings[screenName]) {
|
||||
newSettings[screenName] = {
|
||||
var screen = null
|
||||
var screens = Quickshell.screens
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
if (screens[i].name === screenName) {
|
||||
screen = screens[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!screen) {
|
||||
console.warn("SessionData: Screen not found:", screenName)
|
||||
return
|
||||
}
|
||||
|
||||
var identifier = typeof SettingsData !== "undefined" ? SettingsData.getScreenDisplayName(screen) : screen.name
|
||||
|
||||
var newSettings = {}
|
||||
for (var key in monitorCyclingSettings) {
|
||||
var isThisScreen = key === screen.name || (screen.model && key === screen.model)
|
||||
if (!isThisScreen) {
|
||||
newSettings[key] = monitorCyclingSettings[key]
|
||||
}
|
||||
}
|
||||
|
||||
if (!newSettings[identifier]) {
|
||||
newSettings[identifier] = {
|
||||
"enabled": false,
|
||||
"mode": "interval",
|
||||
"interval": 300,
|
||||
"time": "06:00"
|
||||
}
|
||||
}
|
||||
newSettings[screenName].time = time
|
||||
newSettings[identifier].time = time
|
||||
monitorCyclingSettings = newSettings
|
||||
saveSettings()
|
||||
}
|
||||
@@ -770,11 +892,57 @@ Singleton {
|
||||
if (!perMonitorWallpaper) {
|
||||
return wallpaperPath
|
||||
}
|
||||
return monitorWallpapers[screenName] || wallpaperPath
|
||||
|
||||
var screen = null
|
||||
var screens = Quickshell.screens
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
if (screens[i].name === screenName) {
|
||||
screen = screens[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!screen) {
|
||||
return monitorWallpapers[screenName] || wallpaperPath
|
||||
}
|
||||
|
||||
if (monitorWallpapers[screen.name]) {
|
||||
return monitorWallpapers[screen.name]
|
||||
}
|
||||
if (screen.model && monitorWallpapers[screen.model]) {
|
||||
return monitorWallpapers[screen.model]
|
||||
}
|
||||
|
||||
return wallpaperPath
|
||||
}
|
||||
|
||||
function getMonitorCyclingSettings(screenName) {
|
||||
return monitorCyclingSettings[screenName] || {
|
||||
var screen = null
|
||||
var screens = Quickshell.screens
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
if (screens[i].name === screenName) {
|
||||
screen = screens[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!screen) {
|
||||
return monitorCyclingSettings[screenName] || {
|
||||
"enabled": false,
|
||||
"mode": "interval",
|
||||
"interval": 300,
|
||||
"time": "06:00"
|
||||
}
|
||||
}
|
||||
|
||||
if (monitorCyclingSettings[screen.name]) {
|
||||
return monitorCyclingSettings[screen.name]
|
||||
}
|
||||
if (screen.model && monitorCyclingSettings[screen.model]) {
|
||||
return monitorCyclingSettings[screen.model]
|
||||
}
|
||||
|
||||
return {
|
||||
"enabled": false,
|
||||
"mode": "interval",
|
||||
"interval": 300,
|
||||
|
||||
@@ -23,7 +23,11 @@ Singleton {
|
||||
Top,
|
||||
Bottom,
|
||||
Left,
|
||||
Right
|
||||
Right,
|
||||
TopCenter,
|
||||
BottomCenter,
|
||||
LeftCenter,
|
||||
RightCenter
|
||||
}
|
||||
|
||||
enum AnimationSpeed {
|
||||
@@ -305,6 +309,7 @@ Singleton {
|
||||
property int notificationPopupPosition: SettingsData.Position.Top
|
||||
|
||||
property bool osdAlwaysShowValue: false
|
||||
property int osdPosition: SettingsData.Position.BottomCenter
|
||||
property bool osdVolumeEnabled: true
|
||||
property bool osdBrightnessEnabled: true
|
||||
property bool osdIdleInhibitorEnabled: true
|
||||
@@ -327,6 +332,7 @@ Singleton {
|
||||
property string updaterCustomCommand: ""
|
||||
property string updaterTerminalAdditionalParams: ""
|
||||
|
||||
property string displayNameMode: "system"
|
||||
property var screenPreferences: ({})
|
||||
property var showOnLastDisplay: ({})
|
||||
|
||||
@@ -590,12 +596,82 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
|
||||
}
|
||||
}
|
||||
|
||||
function getBarBounds(screen, barThickness) {
|
||||
if (!screen) {
|
||||
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
|
||||
}
|
||||
|
||||
const wingRadius = dankBarGothCornerRadiusOverride ? dankBarGothCornerRadiusValue : Theme.cornerRadius
|
||||
const wingSize = dankBarGothCornersEnabled ? Math.max(0, wingRadius) : 0
|
||||
const screenWidth = screen.width
|
||||
const screenHeight = screen.height
|
||||
|
||||
if (dankBarPosition === SettingsData.Position.Top) {
|
||||
return {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": screenWidth,
|
||||
"height": barThickness + dankBarSpacing + wingSize,
|
||||
"wingSize": wingSize
|
||||
}
|
||||
} else if (dankBarPosition === SettingsData.Position.Bottom) {
|
||||
return {
|
||||
"x": 0,
|
||||
"y": screenHeight - barThickness - dankBarSpacing - wingSize,
|
||||
"width": screenWidth,
|
||||
"height": barThickness + dankBarSpacing + wingSize,
|
||||
"wingSize": wingSize
|
||||
}
|
||||
} else if (dankBarPosition === SettingsData.Position.Left) {
|
||||
return {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": barThickness + dankBarSpacing + wingSize,
|
||||
"height": screenHeight,
|
||||
"wingSize": wingSize
|
||||
}
|
||||
} else if (dankBarPosition === SettingsData.Position.Right) {
|
||||
return {
|
||||
"x": screenWidth - barThickness - dankBarSpacing - wingSize,
|
||||
"y": 0,
|
||||
"width": barThickness + dankBarSpacing + wingSize,
|
||||
"height": screenHeight,
|
||||
"wingSize": wingSize
|
||||
}
|
||||
}
|
||||
|
||||
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
|
||||
}
|
||||
|
||||
function getScreenDisplayName(screen) {
|
||||
if (!screen) return ""
|
||||
if (displayNameMode === "model" && screen.model) {
|
||||
return screen.model
|
||||
}
|
||||
return screen.name
|
||||
}
|
||||
|
||||
function isScreenInPreferences(screen, prefs) {
|
||||
if (!screen) return false
|
||||
|
||||
return prefs.some(pref => {
|
||||
if (typeof pref === "string") {
|
||||
return pref === "all" || pref === screen.name || pref === screen.model
|
||||
}
|
||||
|
||||
if (displayNameMode === "model") {
|
||||
return pref.model && screen.model && pref.model === screen.model
|
||||
}
|
||||
return pref.name === screen.name
|
||||
})
|
||||
}
|
||||
|
||||
function getFilteredScreens(componentId) {
|
||||
var prefs = screenPreferences && screenPreferences[componentId] || ["all"]
|
||||
if (prefs.includes("all")) {
|
||||
if (prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")) {
|
||||
return Quickshell.screens
|
||||
}
|
||||
var filtered = Quickshell.screens.filter(screen => prefs.includes(screen.name))
|
||||
var filtered = Quickshell.screens.filter(screen => isScreenInPreferences(screen, prefs))
|
||||
if (filtered.length === 0 && showOnLastDisplay && showOnLastDisplay[componentId] && Quickshell.screens.length === 1) {
|
||||
return Quickshell.screens
|
||||
}
|
||||
|
||||
@@ -421,15 +421,44 @@ Singleton {
|
||||
}
|
||||
return typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12
|
||||
}
|
||||
|
||||
property string fontFamily: {
|
||||
if (typeof SessionData !== "undefined" && SessionData.isGreeterMode && typeof GreetdSettings !== "undefined") {
|
||||
return GreetdSettings.fontFamily
|
||||
}
|
||||
return typeof SettingsData !== "undefined" ? SettingsData.fontFamily : "Inter Variable"
|
||||
}
|
||||
|
||||
property string monoFontFamily: {
|
||||
if (typeof SessionData !== "undefined" && SessionData.isGreeterMode && typeof GreetdSettings !== "undefined") {
|
||||
return GreetdSettings.monoFontFamily
|
||||
}
|
||||
return typeof SettingsData !== "undefined" ? SettingsData.monoFontFamily : "Fira Code"
|
||||
}
|
||||
|
||||
property int fontWeight: {
|
||||
if (typeof SessionData !== "undefined" && SessionData.isGreeterMode && typeof GreetdSettings !== "undefined") {
|
||||
return GreetdSettings.fontWeight
|
||||
}
|
||||
return typeof SettingsData !== "undefined" ? SettingsData.fontWeight : Font.Normal
|
||||
}
|
||||
|
||||
property real fontScale: {
|
||||
if (typeof SessionData !== "undefined" && SessionData.isGreeterMode && typeof GreetdSettings !== "undefined") {
|
||||
return GreetdSettings.fontScale
|
||||
}
|
||||
return typeof SettingsData !== "undefined" ? SettingsData.fontScale : 1.0
|
||||
}
|
||||
|
||||
property real spacingXS: 4
|
||||
property real spacingS: 8
|
||||
property real spacingM: 12
|
||||
property real spacingL: 16
|
||||
property real spacingXL: 24
|
||||
property real fontSizeSmall: (typeof SettingsData !== "undefined" ? SettingsData.fontScale : 1.0) * 12
|
||||
property real fontSizeMedium: (typeof SettingsData !== "undefined" ? SettingsData.fontScale : 1.0) * 14
|
||||
property real fontSizeLarge: (typeof SettingsData !== "undefined" ? SettingsData.fontScale : 1.0) * 16
|
||||
property real fontSizeXLarge: (typeof SettingsData !== "undefined" ? SettingsData.fontScale : 1.0) * 20
|
||||
property real fontSizeSmall: Math.round(fontScale * 12)
|
||||
property real fontSizeMedium: Math.round(fontScale * 14)
|
||||
property real fontSizeLarge: Math.round(fontScale * 16)
|
||||
property real fontSizeXLarge: Math.round(fontScale * 20)
|
||||
property real barHeight: 48
|
||||
property real iconSize: 24
|
||||
property real iconSizeSmall: 16
|
||||
@@ -650,10 +679,10 @@ Singleton {
|
||||
const scale = barThickness / 48
|
||||
const dankBarScale = (typeof SettingsData !== "undefined" ? SettingsData.dankBarFontScale : 1.0)
|
||||
if (scale <= 0.75)
|
||||
return fontSizeSmall * 0.9 * dankBarScale
|
||||
return Math.round(fontSizeSmall * 0.9 * dankBarScale)
|
||||
if (scale >= 1.25)
|
||||
return fontSizeMedium * dankBarScale
|
||||
return fontSizeSmall * dankBarScale
|
||||
return Math.round(fontSizeMedium * dankBarScale)
|
||||
return Math.round(fontSizeSmall * dankBarScale)
|
||||
}
|
||||
|
||||
function getBatteryIcon(level, isCharging, batteryAvailable) {
|
||||
|
||||
32
quickshell/Common/TrayMenuManager.qml
Normal file
32
quickshell/Common/TrayMenuManager.qml
Normal file
@@ -0,0 +1,32 @@
|
||||
pragma Singleton
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property var activeTrayBars: ({})
|
||||
|
||||
function register(screenName, trayBar) {
|
||||
if (!screenName || !trayBar) return
|
||||
activeTrayBars[screenName] = trayBar
|
||||
}
|
||||
|
||||
function unregister(screenName) {
|
||||
if (!screenName) return
|
||||
delete activeTrayBars[screenName]
|
||||
}
|
||||
|
||||
function closeAllMenus() {
|
||||
for (const screenName in activeTrayBars) {
|
||||
const trayBar = activeTrayBars[screenName]
|
||||
if (!trayBar) continue
|
||||
|
||||
trayBar.menuOpen = false
|
||||
if (trayBar.currentTrayMenu) {
|
||||
trayBar.currentTrayMenu.showMenu = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,6 +215,7 @@ var SPEC = {
|
||||
notificationPopupPosition: { def: 0 },
|
||||
|
||||
osdAlwaysShowValue: { def: false },
|
||||
osdPosition: { def: 5 },
|
||||
osdVolumeEnabled: { def: true },
|
||||
osdBrightnessEnabled: { def: true },
|
||||
osdIdleInhibitorEnabled: { def: true },
|
||||
@@ -237,6 +238,7 @@ var SPEC = {
|
||||
updaterCustomCommand: { def: "" },
|
||||
updaterTerminalAdditionalParams: { def: "" },
|
||||
|
||||
displayNameMode: { def: "system" },
|
||||
screenPreferences: { def: {} },
|
||||
showOnLastDisplay: { def: {} }
|
||||
};
|
||||
|
||||
@@ -217,6 +217,14 @@ Item {
|
||||
id: polkitAuthModal
|
||||
}
|
||||
|
||||
BluetoothPairingModal {
|
||||
id: bluetoothPairingModal
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.bluetoothPairingModal = bluetoothPairingModal
|
||||
}
|
||||
}
|
||||
|
||||
property string lastCredentialsToken: ""
|
||||
property var lastCredentialsTime: 0
|
||||
|
||||
@@ -297,48 +305,6 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: powerMenuLoader
|
||||
|
||||
active: false
|
||||
|
||||
PowerMenu {
|
||||
id: powerMenu
|
||||
|
||||
onPowerActionRequested: (action, title, message) => {
|
||||
if (SettingsData.powerActionConfirm) {
|
||||
powerConfirmModalLoader.active = true
|
||||
if (powerConfirmModalLoader.item) {
|
||||
powerConfirmModalLoader.item.confirmButtonColor = action === "poweroff" ? Theme.error : action === "reboot" ? Theme.warning : Theme.primary
|
||||
powerConfirmModalLoader.item.show(title, message, () => actionApply(action), function () {})
|
||||
}
|
||||
} else {
|
||||
actionApply(action)
|
||||
}
|
||||
}
|
||||
|
||||
function actionApply(action) {
|
||||
switch (action) {
|
||||
case "logout":
|
||||
SessionService.logout()
|
||||
break
|
||||
case "suspend":
|
||||
SessionService.suspend()
|
||||
break
|
||||
case "hibernate":
|
||||
SessionService.hibernate()
|
||||
break
|
||||
case "reboot":
|
||||
SessionService.reboot()
|
||||
break
|
||||
case "poweroff":
|
||||
SessionService.poweroff()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: powerConfirmModalLoader
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ DankModal {
|
||||
property string passkeyInput: ""
|
||||
|
||||
function show(pairingData) {
|
||||
console.log("BluetoothPairingModal.show() called:", JSON.stringify(pairingData))
|
||||
token = pairingData.token || ""
|
||||
deviceName = pairingData.deviceName || ""
|
||||
deviceAddress = pairingData.deviceAddr || ""
|
||||
@@ -26,6 +27,7 @@ DankModal {
|
||||
pinInput = ""
|
||||
passkeyInput = ""
|
||||
|
||||
console.log("BluetoothPairingModal: Calling open()")
|
||||
open()
|
||||
Qt.callLater(() => {
|
||||
if (contentLoader.item) {
|
||||
@@ -39,6 +41,8 @@ DankModal {
|
||||
}
|
||||
|
||||
shouldBeVisible: false
|
||||
allowStacking: true
|
||||
keepPopoutsOpen: true
|
||||
width: 420
|
||||
height: contentLoader.item ? contentLoader.item.implicitHeight + Theme.spacingM * 2 : 240
|
||||
|
||||
@@ -62,8 +66,11 @@ DankModal {
|
||||
}
|
||||
|
||||
onBackgroundClicked: () => {
|
||||
DMSService.bluetoothCancelPairing(token)
|
||||
if (token) {
|
||||
DMSService.bluetoothCancelPairing(token)
|
||||
}
|
||||
close()
|
||||
token = ""
|
||||
pinInput = ""
|
||||
passkeyInput = ""
|
||||
}
|
||||
@@ -80,8 +87,11 @@ DankModal {
|
||||
implicitHeight: mainColumn.implicitHeight
|
||||
|
||||
Keys.onEscapePressed: event => {
|
||||
DMSService.bluetoothCancelPairing(token)
|
||||
if (token) {
|
||||
DMSService.bluetoothCancelPairing(token)
|
||||
}
|
||||
close()
|
||||
token = ""
|
||||
pinInput = ""
|
||||
passkeyInput = ""
|
||||
event.accepted = true
|
||||
@@ -110,17 +120,22 @@ DankModal {
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (requestType === "confirm")
|
||||
switch (requestType) {
|
||||
case "confirm":
|
||||
return I18n.tr("Confirm passkey for ") + deviceName
|
||||
if (requestType === "authorize")
|
||||
case "display-passkey":
|
||||
return I18n.tr("Enter this passkey on ") + deviceName
|
||||
case "authorize":
|
||||
return I18n.tr("Authorize pairing with ") + deviceName
|
||||
if (requestType.startsWith("authorize-service"))
|
||||
return I18n.tr("Authorize service for ") + deviceName
|
||||
if (requestType === "pin")
|
||||
case "pin":
|
||||
return I18n.tr("Enter PIN for ") + deviceName
|
||||
if (requestType === "passkey")
|
||||
case "passkey":
|
||||
return I18n.tr("Enter passkey for ") + deviceName
|
||||
return deviceName
|
||||
default:
|
||||
if (requestType.startsWith("authorize-service"))
|
||||
return I18n.tr("Authorize service for ") + deviceName
|
||||
return deviceName
|
||||
}
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceTextMedium
|
||||
@@ -204,7 +219,7 @@ DankModal {
|
||||
height: 56
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency)
|
||||
visible: requestType === "confirm"
|
||||
visible: requestType === "confirm" || requestType === "display-passkey"
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
@@ -261,8 +276,11 @@ DankModal {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: () => {
|
||||
DMSService.bluetoothCancelPairing(token)
|
||||
if (token) {
|
||||
DMSService.bluetoothCancelPairing(token)
|
||||
}
|
||||
close()
|
||||
token = ""
|
||||
pinInput = ""
|
||||
passkeyInput = ""
|
||||
}
|
||||
@@ -288,11 +306,17 @@ DankModal {
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: {
|
||||
if (requestType === "confirm")
|
||||
switch (requestType) {
|
||||
case "confirm":
|
||||
case "display-passkey":
|
||||
return I18n.tr("Confirm")
|
||||
if (requestType === "authorize" || requestType.startsWith("authorize-service"))
|
||||
case "authorize":
|
||||
return I18n.tr("Authorize")
|
||||
return I18n.tr("Pair")
|
||||
default:
|
||||
if (requestType.startsWith("authorize-service"))
|
||||
return I18n.tr("Authorize")
|
||||
return I18n.tr("Pair")
|
||||
}
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.background
|
||||
@@ -331,8 +355,11 @@ DankModal {
|
||||
iconSize: Theme.iconSize - 4
|
||||
iconColor: Theme.surfaceText
|
||||
onClicked: () => {
|
||||
DMSService.bluetoothCancelPairing(token)
|
||||
if (token) {
|
||||
DMSService.bluetoothCancelPairing(token)
|
||||
}
|
||||
close()
|
||||
token = ""
|
||||
pinInput = ""
|
||||
passkeyInput = ""
|
||||
}
|
||||
@@ -343,12 +370,23 @@ DankModal {
|
||||
function submitPairing() {
|
||||
const secrets = {}
|
||||
|
||||
if (requestType === "pin") {
|
||||
switch (requestType) {
|
||||
case "pin":
|
||||
secrets["pin"] = pinInput
|
||||
} else if (requestType === "passkey") {
|
||||
break
|
||||
case "passkey":
|
||||
secrets["passkey"] = passkeyInput
|
||||
} else if (requestType === "confirm" || requestType === "authorize" || requestType.startsWith("authorize-service")) {
|
||||
break
|
||||
case "confirm":
|
||||
case "display-passkey":
|
||||
case "authorize":
|
||||
secrets["decision"] = "yes"
|
||||
break
|
||||
default:
|
||||
if (requestType.startsWith("authorize-service")) {
|
||||
secrets["decision"] = "yes"
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
DMSService.bluetoothSubmitPairing(token, secrets, true, response => {
|
||||
@@ -358,6 +396,7 @@ DankModal {
|
||||
})
|
||||
|
||||
close()
|
||||
token = ""
|
||||
pinInput = ""
|
||||
passkeyInput = ""
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import qs.Widgets
|
||||
DankModal {
|
||||
id: root
|
||||
|
||||
layerNamespace: "dms:confirm-modal"
|
||||
|
||||
property string confirmTitle: ""
|
||||
property string confirmMessage: ""
|
||||
property string confirmButtonText: "Confirm"
|
||||
|
||||
@@ -43,6 +43,7 @@ PanelWindow {
|
||||
property bool allowFocusOverride: false
|
||||
property bool allowStacking: false
|
||||
property bool keepContentLoaded: false
|
||||
property bool keepPopoutsOpen: false
|
||||
|
||||
signal opened
|
||||
signal dialogClosed
|
||||
@@ -88,7 +89,17 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: shouldHaveFocus ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
WlrLayershell.keyboardFocus: {
|
||||
if (!shouldHaveFocus) return WlrKeyboardFocus.None
|
||||
if (CompositorService.isHyprland) return WlrKeyboardFocus.OnDemand
|
||||
return WlrKeyboardFocus.Exclusive
|
||||
}
|
||||
|
||||
HyprlandFocusGrab {
|
||||
windows: [root]
|
||||
active: CompositorService.isHyprland && shouldHaveFocus
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (root.visible) {
|
||||
opened()
|
||||
|
||||
@@ -60,7 +60,7 @@ DankModal {
|
||||
}
|
||||
|
||||
function copyColorToClipboard(colorValue) {
|
||||
Quickshell.execDetached(["sh", "-c", `echo "${colorValue}" | wl-copy`])
|
||||
Quickshell.execDetached(["sh", "-c", `echo -n "${colorValue}" | wl-copy`])
|
||||
ToastService.showInfo(`Color ${colorValue} copied`)
|
||||
SessionData.addRecentColor(currentColor)
|
||||
}
|
||||
@@ -571,7 +571,7 @@ DankModal {
|
||||
} else {
|
||||
rgbString = `rgb(${r}, ${g}, ${b})`
|
||||
}
|
||||
Quickshell.execDetached(["sh", "-c", `echo "${rgbString}" | wl-copy`])
|
||||
Quickshell.execDetached(["sh", "-c", `echo -n "${rgbString}" | wl-copy`])
|
||||
ToastService.showInfo(`${rgbString} copied`)
|
||||
}
|
||||
}
|
||||
@@ -635,7 +635,7 @@ DankModal {
|
||||
} else {
|
||||
hsvString = `${h}, ${s}, ${v}`
|
||||
}
|
||||
Quickshell.execDetached(["sh", "-c", `echo "${hsvString}" | wl-copy`])
|
||||
Quickshell.execDetached(["sh", "-c", `echo -n "${hsvString}" | wl-copy`])
|
||||
ToastService.showInfo(`HSV ${hsvString} copied`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,9 @@ DankModal {
|
||||
parentBounds = bounds
|
||||
parentScreen = targetScreen
|
||||
backgroundOpacity = 0
|
||||
keepPopoutsOpen = true
|
||||
open()
|
||||
keepPopoutsOpen = false
|
||||
}
|
||||
|
||||
function updateVisibleActions() {
|
||||
|
||||
@@ -139,7 +139,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: UserInfoService.hostname || "Linux"
|
||||
text: DgopService.hostname || "DMS"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
elide: Text.ElideRight
|
||||
|
||||
@@ -12,7 +12,9 @@ Rectangle {
|
||||
|
||||
function resetScroll() {
|
||||
resultsList.contentY = 0
|
||||
resultsGrid.contentY = 0
|
||||
if (gridLoader.item) {
|
||||
gridLoader.item.contentY = 0
|
||||
}
|
||||
}
|
||||
|
||||
radius: Theme.cornerRadius
|
||||
@@ -92,88 +94,106 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
DankGridView {
|
||||
id: resultsGrid
|
||||
Loader {
|
||||
id: gridLoader
|
||||
|
||||
property int currentIndex: appLauncher ? appLauncher.selectedIndex : -1
|
||||
property int columns: appLauncher ? appLauncher.gridColumns : 4
|
||||
property bool adaptiveColumns: false
|
||||
property int minCellWidth: 120
|
||||
property int maxCellWidth: 160
|
||||
property int cellPadding: 8
|
||||
property real iconSizeRatio: 0.55
|
||||
property int maxIconSize: 48
|
||||
property int minIconSize: 32
|
||||
property bool hoverUpdatesSelection: false
|
||||
property bool keyboardNavigationActive: appLauncher ? appLauncher.keyboardNavigationActive : false
|
||||
property int baseCellWidth: adaptiveColumns ? Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) : (width - Theme.spacingS * 2) / columns
|
||||
property int baseCellHeight: baseCellWidth + 20
|
||||
property int actualColumns: adaptiveColumns ? Math.floor(width / cellWidth) : columns
|
||||
property int remainingSpace: width - (actualColumns * cellWidth)
|
||||
|
||||
signal keyboardNavigationReset
|
||||
signal itemClicked(int index, var modelData)
|
||||
signal itemRightClicked(int index, var modelData, real mouseX, real mouseY)
|
||||
|
||||
function ensureVisible(index) {
|
||||
if (index < 0 || index >= count)
|
||||
return
|
||||
|
||||
const itemY = Math.floor(index / actualColumns) * cellHeight
|
||||
const itemBottom = itemY + cellHeight
|
||||
if (itemY < contentY)
|
||||
contentY = itemY
|
||||
else if (itemBottom > contentY + height)
|
||||
contentY = itemBottom - height
|
||||
}
|
||||
property real _lastWidth: 0
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
visible: appLauncher && appLauncher.viewMode === "grid"
|
||||
model: appLauncher ? appLauncher.model : null
|
||||
clip: true
|
||||
cellWidth: baseCellWidth
|
||||
cellHeight: baseCellHeight
|
||||
leftMargin: Math.max(Theme.spacingS, remainingSpace / 2)
|
||||
rightMargin: leftMargin
|
||||
focus: true
|
||||
interactive: true
|
||||
cacheBuffer: Math.max(0, Math.min(height * 2, 1000))
|
||||
reuseItems: true
|
||||
onCurrentIndexChanged: {
|
||||
if (keyboardNavigationActive)
|
||||
ensureVisible(currentIndex)
|
||||
}
|
||||
onItemClicked: (index, modelData) => {
|
||||
if (appLauncher)
|
||||
appLauncher.launchApp(modelData)
|
||||
}
|
||||
onItemRightClicked: (index, modelData, mouseX, mouseY) => {
|
||||
if (contextMenu)
|
||||
contextMenu.show(mouseX, mouseY, modelData)
|
||||
}
|
||||
onKeyboardNavigationReset: () => {
|
||||
if (appLauncher)
|
||||
appLauncher.keyboardNavigationActive = false
|
||||
}
|
||||
|
||||
delegate: AppLauncherGridDelegate {
|
||||
gridView: resultsGrid
|
||||
cellWidth: resultsGrid.cellWidth
|
||||
cellHeight: resultsGrid.cellHeight
|
||||
cellPadding: resultsGrid.cellPadding
|
||||
minIconSize: resultsGrid.minIconSize
|
||||
maxIconSize: resultsGrid.maxIconSize
|
||||
iconSizeRatio: resultsGrid.iconSizeRatio
|
||||
hoverUpdatesSelection: resultsGrid.hoverUpdatesSelection
|
||||
keyboardNavigationActive: resultsGrid.keyboardNavigationActive
|
||||
currentIndex: resultsGrid.currentIndex
|
||||
onItemClicked: (idx, modelData) => resultsGrid.itemClicked(idx, modelData)
|
||||
onItemRightClicked: (idx, modelData, mouseX, mouseY) => {
|
||||
const modalPos = resultsContainer.parent.mapFromItem(null, mouseX, mouseY)
|
||||
resultsGrid.itemRightClicked(idx, modelData, modalPos.x, modalPos.y)
|
||||
active: appLauncher && appLauncher.viewMode === "grid"
|
||||
onWidthChanged: {
|
||||
if (visible && Math.abs(width - _lastWidth) > 1) {
|
||||
_lastWidth = width
|
||||
active = false
|
||||
Qt.callLater(() => {
|
||||
active = true
|
||||
})
|
||||
}
|
||||
}
|
||||
sourceComponent: Component {
|
||||
DankGridView {
|
||||
id: resultsGrid
|
||||
|
||||
property int currentIndex: appLauncher ? appLauncher.selectedIndex : -1
|
||||
property int columns: appLauncher ? appLauncher.gridColumns : 4
|
||||
property bool adaptiveColumns: false
|
||||
property int minCellWidth: 120
|
||||
property int maxCellWidth: 160
|
||||
property int cellPadding: 8
|
||||
property real iconSizeRatio: 0.55
|
||||
property int maxIconSize: 48
|
||||
property int minIconSize: 32
|
||||
property bool hoverUpdatesSelection: false
|
||||
property bool keyboardNavigationActive: appLauncher ? appLauncher.keyboardNavigationActive : false
|
||||
property int baseCellWidth: adaptiveColumns ? Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) : (width - Theme.spacingS * 2) / columns
|
||||
property int baseCellHeight: baseCellWidth + 20
|
||||
property int actualColumns: adaptiveColumns ? Math.floor(width / cellWidth) : columns
|
||||
property int remainingSpace: width - (actualColumns * cellWidth)
|
||||
|
||||
signal keyboardNavigationReset
|
||||
signal itemClicked(int index, var modelData)
|
||||
signal itemRightClicked(int index, var modelData, real mouseX, real mouseY)
|
||||
|
||||
function ensureVisible(index) {
|
||||
if (index < 0 || index >= count)
|
||||
return
|
||||
|
||||
const itemY = Math.floor(index / actualColumns) * cellHeight
|
||||
const itemBottom = itemY + cellHeight
|
||||
if (itemY < contentY)
|
||||
contentY = itemY
|
||||
else if (itemBottom > contentY + height)
|
||||
contentY = itemBottom - height
|
||||
}
|
||||
|
||||
model: appLauncher ? appLauncher.model : null
|
||||
clip: true
|
||||
cellWidth: baseCellWidth
|
||||
cellHeight: baseCellHeight
|
||||
leftMargin: Math.max(Theme.spacingS, remainingSpace / 2)
|
||||
rightMargin: leftMargin
|
||||
focus: true
|
||||
interactive: true
|
||||
cacheBuffer: Math.max(0, Math.min(height * 2, 1000))
|
||||
reuseItems: true
|
||||
onCurrentIndexChanged: {
|
||||
if (keyboardNavigationActive)
|
||||
ensureVisible(currentIndex)
|
||||
}
|
||||
onItemClicked: (index, modelData) => {
|
||||
if (appLauncher)
|
||||
appLauncher.launchApp(modelData)
|
||||
}
|
||||
onItemRightClicked: (index, modelData, mouseX, mouseY) => {
|
||||
if (contextMenu)
|
||||
contextMenu.show(mouseX, mouseY, modelData)
|
||||
}
|
||||
onKeyboardNavigationReset: () => {
|
||||
if (appLauncher)
|
||||
appLauncher.keyboardNavigationActive = false
|
||||
}
|
||||
|
||||
delegate: AppLauncherGridDelegate {
|
||||
gridView: resultsGrid
|
||||
cellWidth: resultsGrid.cellWidth
|
||||
cellHeight: resultsGrid.cellHeight
|
||||
cellPadding: resultsGrid.cellPadding
|
||||
minIconSize: resultsGrid.minIconSize
|
||||
maxIconSize: resultsGrid.maxIconSize
|
||||
iconSizeRatio: resultsGrid.iconSizeRatio
|
||||
hoverUpdatesSelection: resultsGrid.hoverUpdatesSelection
|
||||
keyboardNavigationActive: resultsGrid.keyboardNavigationActive
|
||||
currentIndex: resultsGrid.currentIndex
|
||||
onItemClicked: (idx, modelData) => resultsGrid.itemClicked(idx, modelData)
|
||||
onItemRightClicked: (idx, modelData, mouseX, mouseY) => {
|
||||
const modalPos = resultsContainer.parent.mapFromItem(null, mouseX, mouseY)
|
||||
resultsGrid.itemRightClicked(idx, modelData, modalPos.x, modalPos.y)
|
||||
}
|
||||
onKeyboardNavigationReset: resultsGrid.keyboardNavigationReset
|
||||
}
|
||||
}
|
||||
onKeyboardNavigationReset: resultsGrid.keyboardNavigationReset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,6 @@ DankPopout {
|
||||
|
||||
property var triggerScreen: null
|
||||
|
||||
// Setting to Exclusive, so virtual keyboards can send input to app drawer
|
||||
WlrLayershell.keyboardFocus: shouldBeVisible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
|
||||
function show() {
|
||||
open()
|
||||
}
|
||||
@@ -40,6 +37,8 @@ DankPopout {
|
||||
positioning: ""
|
||||
screen: triggerScreen
|
||||
|
||||
onBackgroundClicked: close()
|
||||
|
||||
onShouldBeVisibleChanged: {
|
||||
if (shouldBeVisible) {
|
||||
appLauncher.searchQuery = ""
|
||||
|
||||
@@ -71,7 +71,15 @@ DankPopout {
|
||||
positioning: ""
|
||||
screen: triggerScreen
|
||||
shouldBeVisible: false
|
||||
visible: shouldBeVisible
|
||||
|
||||
WlrLayershell.keyboardFocus: {
|
||||
if (!shouldBeVisible) return WlrKeyboardFocus.None
|
||||
if (powerMenuOpen) return WlrKeyboardFocus.None
|
||||
if (CompositorService.isHyprland) return WlrKeyboardFocus.OnDemand
|
||||
return WlrKeyboardFocus.Exclusive
|
||||
}
|
||||
|
||||
onBackgroundClicked: close()
|
||||
|
||||
onShouldBeVisibleChanged: {
|
||||
if (shouldBeVisible) {
|
||||
|
||||
@@ -29,11 +29,13 @@ Rectangle {
|
||||
if (!device) return
|
||||
|
||||
const deviceAddr = device.address
|
||||
devicesBeingPaired.add(deviceAddr)
|
||||
const pairingSet = devicesBeingPaired
|
||||
|
||||
pairingSet.add(deviceAddr)
|
||||
devicesBeingPairedChanged()
|
||||
|
||||
BluetoothService.pairDevice(device, function(response) {
|
||||
devicesBeingPaired.delete(deviceAddr)
|
||||
pairingSet.delete(deviceAddr)
|
||||
devicesBeingPairedChanged()
|
||||
|
||||
if (response.error) {
|
||||
@@ -625,15 +627,14 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
BluetoothPairingModal {
|
||||
id: bluetoothPairingModal
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: DMSService
|
||||
|
||||
function onBluetoothPairingRequest(data) {
|
||||
bluetoothPairingModal.show(data)
|
||||
const modal = PopoutService.bluetoothPairingModal
|
||||
if (modal && modal.token !== data.token) {
|
||||
modal.show(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,316 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
readonly property string powerOptionsText: I18n.tr("Power Options")
|
||||
readonly property string logOutText: I18n.tr("Log Out")
|
||||
readonly property string suspendText: I18n.tr("Suspend")
|
||||
readonly property string rebootText: I18n.tr("Reboot")
|
||||
readonly property string powerOffText: I18n.tr("Power Off")
|
||||
|
||||
property bool powerMenuVisible: false
|
||||
signal powerActionRequested(string action, string title, string message)
|
||||
|
||||
visible: powerMenuVisible
|
||||
implicitWidth: 400
|
||||
implicitHeight: 320
|
||||
WlrLayershell.layer: WlrLayershell.Overlay
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
color: "transparent"
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
powerMenuVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: Math.min(320, parent.width - Theme.spacingL * 2)
|
||||
height: 320 // Fixed height to prevent cropping
|
||||
x: Math.max(Theme.spacingL, parent.width - width - Theme.spacingL)
|
||||
y: Theme.barHeight + Theme.spacingXS
|
||||
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: 0
|
||||
opacity: powerMenuVisible ? 1 : 0
|
||||
scale: powerMenuVisible ? 1 : 0.85
|
||||
|
||||
MouseArea {
|
||||
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
|
||||
StyledText {
|
||||
text: root.powerOptionsText
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - 150
|
||||
height: 1
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
iconName: "close"
|
||||
iconSize: Theme.iconSize - 4
|
||||
iconColor: Theme.surfaceText
|
||||
onClicked: {
|
||||
powerMenuVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: logoutArea.containsMouse ? Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.08) : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b,
|
||||
0.08)
|
||||
|
||||
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: root.logOutText
|
||||
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: {
|
||||
powerMenuVisible = false
|
||||
root.powerActionRequested(
|
||||
"logout", "Log Out",
|
||||
"Are you sure you want to log out?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: suspendArea.containsMouse ? Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.08) : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b,
|
||||
0.08)
|
||||
|
||||
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: root.suspendText
|
||||
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: {
|
||||
powerMenuVisible = false
|
||||
root.powerActionRequested(
|
||||
"suspend", "Suspend",
|
||||
"Are you sure you want to suspend the system?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: rebootArea.containsMouse ? Qt.rgba(Theme.warning.r,
|
||||
Theme.warning.g,
|
||||
Theme.warning.b,
|
||||
0.08) : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b,
|
||||
0.08)
|
||||
|
||||
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: root.rebootText
|
||||
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: {
|
||||
powerMenuVisible = false
|
||||
root.powerActionRequested(
|
||||
"reboot", "Reboot",
|
||||
"Are you sure you want to reboot the system?")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: powerOffArea.containsMouse ? Qt.rgba(Theme.error.r,
|
||||
Theme.error.g,
|
||||
Theme.error.b,
|
||||
0.08) : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b,
|
||||
0.08)
|
||||
|
||||
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: root.powerOffText
|
||||
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: {
|
||||
powerMenuVisible = false
|
||||
root.powerActionRequested(
|
||||
"poweroff", "Power Off",
|
||||
"Are you sure you want to power off the system?")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property var barWindow
|
||||
required property var axis
|
||||
required property var appDrawerLoader
|
||||
required property var dankDashPopoutLoader
|
||||
required property var processListPopoutLoader
|
||||
required property var notificationCenterLoader
|
||||
required property var batteryPopoutLoader
|
||||
required property var layoutPopoutLoader
|
||||
required property var vpnPopoutLoader
|
||||
required property var controlCenterLoader
|
||||
required property var clipboardHistoryModalPopup
|
||||
required property var systemUpdateLoader
|
||||
required property var notepadInstance
|
||||
|
||||
property alias reveal: core.reveal
|
||||
property alias autoHide: core.autoHide
|
||||
property alias backgroundTransparency: core.backgroundTransparency
|
||||
property alias hasActivePopout: core.hasActivePopout
|
||||
property alias mouseArea: topBarMouseArea
|
||||
|
||||
Item {
|
||||
id: inputMask
|
||||
|
||||
readonly property int barThickness: barWindow.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing)
|
||||
|
||||
readonly property bool showing: SettingsData.dankBarVisible && (core.reveal
|
||||
|| (CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview)
|
||||
|| !core.autoHide)
|
||||
|
||||
readonly property int maskThickness: showing ? barThickness : 1
|
||||
|
||||
x: {
|
||||
if (!axis.isVertical) {
|
||||
return 0
|
||||
} else {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Left: return 0
|
||||
case SettingsData.Position.Right: return parent.width - maskThickness
|
||||
default: return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
y: {
|
||||
if (axis.isVertical) {
|
||||
return 0
|
||||
} else {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Top: return 0
|
||||
case SettingsData.Position.Bottom: return parent.height - maskThickness
|
||||
default: return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
width: axis.isVertical ? maskThickness : parent.width
|
||||
height: axis.isVertical ? parent.height : maskThickness
|
||||
}
|
||||
|
||||
Region {
|
||||
id: mask
|
||||
item: inputMask
|
||||
}
|
||||
|
||||
property alias maskRegion: mask
|
||||
|
||||
QtObject {
|
||||
id: core
|
||||
|
||||
property real backgroundTransparency: SettingsData.dankBarTransparency
|
||||
property bool autoHide: SettingsData.dankBarAutoHide
|
||||
property bool revealSticky: false
|
||||
|
||||
property bool notepadInstanceVisible: notepadInstance?.isVisible ?? false
|
||||
|
||||
readonly property bool hasActivePopout: {
|
||||
const loaders = [{
|
||||
"loader": appDrawerLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": dankDashPopoutLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": processListPopoutLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": notificationCenterLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": batteryPopoutLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": layoutPopoutLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": vpnPopoutLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": controlCenterLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": clipboardHistoryModalPopup,
|
||||
"prop": "visible"
|
||||
}, {
|
||||
"loader": systemUpdateLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}]
|
||||
return notepadInstanceVisible || loaders.some(item => {
|
||||
if (item.loader) {
|
||||
return item.loader?.item?.[item.prop]
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
property bool reveal: {
|
||||
if (CompositorService.isNiri && NiriService.inOverview) {
|
||||
return SettingsData.dankBarOpenOnOverview
|
||||
}
|
||||
return SettingsData.dankBarVisible && (!autoHide || topBarMouseArea.containsMouse || hasActivePopout || revealSticky)
|
||||
}
|
||||
|
||||
onHasActivePopoutChanged: {
|
||||
if (!hasActivePopout && autoHide && !topBarMouseArea.containsMouse) {
|
||||
revealSticky = true
|
||||
revealHold.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: revealHold
|
||||
interval: 250
|
||||
repeat: false
|
||||
onTriggered: core.revealSticky = false
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onDankBarTransparencyChanged() {
|
||||
core.backgroundTransparency = SettingsData.dankBarTransparency
|
||||
}
|
||||
|
||||
target: SettingsData
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: topBarMouseArea
|
||||
function onContainsMouseChanged() {
|
||||
if (topBarMouseArea.containsMouse) {
|
||||
core.revealSticky = true
|
||||
revealHold.stop()
|
||||
} else {
|
||||
if (core.autoHide && !core.hasActivePopout) {
|
||||
revealHold.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: topBarMouseArea
|
||||
y: !barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? parent.height - height : 0) : 0
|
||||
x: barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.width - width : 0) : 0
|
||||
height: !barWindow.isVertical ? barWindow.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing) : undefined
|
||||
width: barWindow.isVertical ? barWindow.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing) : undefined
|
||||
anchors {
|
||||
left: !barWindow.isVertical ? parent.left : (SettingsData.dankBarPosition === SettingsData.Position.Left ? parent.left : undefined)
|
||||
right: !barWindow.isVertical ? parent.right : (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.right : undefined)
|
||||
top: barWindow.isVertical ? parent.top : undefined
|
||||
bottom: barWindow.isVertical ? parent.bottom : undefined
|
||||
}
|
||||
hoverEnabled: SettingsData.dankBarAutoHide && !core.reveal
|
||||
acceptedButtons: Qt.NoButton
|
||||
enabled: SettingsData.dankBarAutoHide && !core.reveal
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,25 @@ Item {
|
||||
debounceTimer.restart()
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
z: -999
|
||||
onClicked: {
|
||||
const activePopout = PopoutManager.getActivePopout(barWindow.screen)
|
||||
if (activePopout) {
|
||||
if (activePopout.dashVisible !== undefined) {
|
||||
activePopout.dashVisible = false
|
||||
} else if (activePopout.notificationHistoryVisible !== undefined) {
|
||||
activePopout.notificationHistoryVisible = false
|
||||
} else {
|
||||
activePopout.close()
|
||||
}
|
||||
}
|
||||
TrayMenuManager.closeAllMenus()
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: debounceTimer
|
||||
interval: 50
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1009
quickshell/Modules/DankBar/DankBarContent.qml
Normal file
1009
quickshell/Modules/DankBar/DankBarContent.qml
Normal file
File diff suppressed because it is too large
Load Diff
539
quickshell/Modules/DankBar/DankBarWindow.qml
Normal file
539
quickshell/Modules/DankBar/DankBarWindow.qml
Normal file
@@ -0,0 +1,539 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Shapes
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.I3
|
||||
import Quickshell.Io
|
||||
import Quickshell.Services.Mpris
|
||||
import Quickshell.Services.Notifications
|
||||
import Quickshell.Services.SystemTray
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Modules
|
||||
import qs.Modules.DankBar.Widgets
|
||||
import qs.Modules.DankBar.Popouts
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
PanelWindow {
|
||||
id: barWindow
|
||||
|
||||
required property var rootWindow
|
||||
property var modelData: item
|
||||
property var hyprlandOverviewLoader: rootWindow ? rootWindow.hyprlandOverviewLoader : null
|
||||
|
||||
property var controlCenterButtonRef: null
|
||||
property var clockButtonRef: null
|
||||
|
||||
function triggerControlCenter() {
|
||||
controlCenterLoader.active = true
|
||||
if (!controlCenterLoader.item) {
|
||||
return
|
||||
}
|
||||
|
||||
if (controlCenterButtonRef && controlCenterLoader.item.setTriggerPosition) {
|
||||
const globalPos = controlCenterButtonRef.mapToGlobal(0, 0)
|
||||
const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, controlCenterButtonRef.width)
|
||||
const section = controlCenterButtonRef.section || "right"
|
||||
controlCenterLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen)
|
||||
} else {
|
||||
controlCenterLoader.item.triggerScreen = barWindow.screen
|
||||
}
|
||||
|
||||
controlCenterLoader.item.toggle()
|
||||
if (controlCenterLoader.item.shouldBeVisible && NetworkService.wifiEnabled) {
|
||||
NetworkService.scanWifi()
|
||||
}
|
||||
}
|
||||
|
||||
function triggerWallpaperBrowser() {
|
||||
dankDashPopoutLoader.active = true
|
||||
if (!dankDashPopoutLoader.item) {
|
||||
return
|
||||
}
|
||||
|
||||
if (clockButtonRef && clockButtonRef.visualContent && dankDashPopoutLoader.item.setTriggerPosition) {
|
||||
const globalPos = clockButtonRef.visualContent.mapToGlobal(0, 0)
|
||||
const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, clockButtonRef.visualWidth)
|
||||
const section = clockButtonRef.section || "center"
|
||||
dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen)
|
||||
} else {
|
||||
dankDashPopoutLoader.item.triggerScreen = barWindow.screen
|
||||
}
|
||||
|
||||
PopoutManager.requestPopout(dankDashPopoutLoader.item, 2)
|
||||
}
|
||||
|
||||
readonly property var dBarLayer: {
|
||||
switch (Quickshell.env("DMS_DANKBAR_LAYER")) {
|
||||
case "bottom":
|
||||
return WlrLayer.Bottom
|
||||
case "overlay":
|
||||
return WlrLayer.Overlay
|
||||
case "background":
|
||||
return WlrLayer.background
|
||||
default:
|
||||
return WlrLayer.Top
|
||||
}
|
||||
}
|
||||
|
||||
WlrLayershell.layer: dBarLayer
|
||||
WlrLayershell.namespace: "dms:bar"
|
||||
|
||||
signal colorPickerRequested
|
||||
|
||||
onColorPickerRequested: rootWindow.colorPickerRequested()
|
||||
|
||||
property alias axis: axis
|
||||
|
||||
AxisContext {
|
||||
id: axis
|
||||
edge: {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return "top"
|
||||
case SettingsData.Position.Bottom:
|
||||
return "bottom"
|
||||
case SettingsData.Position.Left:
|
||||
return "left"
|
||||
case SettingsData.Position.Right:
|
||||
return "right"
|
||||
default:
|
||||
return "top"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readonly property bool isVertical: axis.isVertical
|
||||
|
||||
property bool gothCornersEnabled: SettingsData.dankBarGothCornersEnabled
|
||||
property real wingtipsRadius: SettingsData.dankBarGothCornerRadiusOverride ? SettingsData.dankBarGothCornerRadiusValue : Theme.cornerRadius
|
||||
readonly property real _wingR: Math.max(0, wingtipsRadius)
|
||||
readonly property color _surfaceContainer: Theme.surfaceContainer
|
||||
readonly property real _backgroundAlpha: topBarCore?.backgroundTransparency ?? SettingsData.dankBarTransparency
|
||||
readonly property color _bgColor: Theme.withAlpha(_surfaceContainer, _backgroundAlpha)
|
||||
readonly property real _dpr: CompositorService.getScreenScale(barWindow.screen)
|
||||
|
||||
property string screenName: modelData.name
|
||||
readonly property int notificationCount: NotificationService.notifications.length
|
||||
readonly property real effectiveBarThickness: Math.max(barWindow.widgetThickness + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
|
||||
readonly property real widgetThickness: Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
|
||||
|
||||
screen: modelData
|
||||
implicitHeight: !isVertical ? Theme.px(effectiveBarThickness + SettingsData.dankBarSpacing + (SettingsData.dankBarGothCornersEnabled ? _wingR : 0), _dpr) : 0
|
||||
implicitWidth: isVertical ? Theme.px(effectiveBarThickness + SettingsData.dankBarSpacing + (SettingsData.dankBarGothCornersEnabled ? _wingR : 0), _dpr) : 0
|
||||
color: "transparent"
|
||||
|
||||
property var nativeInhibitor: null
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.forceStatusBarLayoutRefresh) {
|
||||
SettingsData.forceStatusBarLayoutRefresh.connect(() => {
|
||||
Qt.callLater(() => {
|
||||
stackContainer.visible = false
|
||||
Qt.callLater(() => {
|
||||
stackContainer.visible = true
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
updateGpuTempConfig()
|
||||
|
||||
inhibitorInitTimer.start()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: inhibitorInitTimer
|
||||
interval: 300
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
if (SessionService.nativeInhibitorAvailable) {
|
||||
createNativeInhibitor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: PluginService
|
||||
function onPluginLoaded(pluginId) {
|
||||
console.info("DankBar: Plugin loaded:", pluginId)
|
||||
SettingsData.widgetDataChanged()
|
||||
}
|
||||
function onPluginUnloaded(pluginId) {
|
||||
console.info("DankBar: Plugin unloaded:", pluginId)
|
||||
SettingsData.widgetDataChanged()
|
||||
}
|
||||
}
|
||||
|
||||
function updateGpuTempConfig() {
|
||||
const allWidgets = [...(SettingsData.dankBarLeftWidgets || []), ...(SettingsData.dankBarCenterWidgets || []), ...(SettingsData.dankBarRightWidgets || [])]
|
||||
|
||||
const hasGpuTempWidget = allWidgets.some(widget => {
|
||||
const widgetId = typeof widget === "string" ? widget : widget.id
|
||||
const widgetEnabled = typeof widget === "string" ? true : (widget.enabled !== false)
|
||||
return widgetId === "gpuTemp" && widgetEnabled
|
||||
})
|
||||
|
||||
DgopService.gpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled || SessionData.nonNvidiaGpuTempEnabled
|
||||
DgopService.nvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled
|
||||
DgopService.nonNvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nonNvidiaGpuTempEnabled
|
||||
}
|
||||
|
||||
function createNativeInhibitor() {
|
||||
if (!SessionService.nativeInhibitorAvailable) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const qmlString = `
|
||||
import QtQuick
|
||||
import Quickshell.Wayland
|
||||
|
||||
IdleInhibitor {
|
||||
enabled: false
|
||||
}
|
||||
`
|
||||
|
||||
nativeInhibitor = Qt.createQmlObject(qmlString, barWindow, "DankBar.NativeInhibitor")
|
||||
nativeInhibitor.window = barWindow
|
||||
nativeInhibitor.enabled = Qt.binding(() => SessionService.idleInhibited)
|
||||
nativeInhibitor.enabledChanged.connect(function () {
|
||||
console.log("DankBar: Native inhibitor enabled changed to:", nativeInhibitor.enabled)
|
||||
if (SessionService.idleInhibited !== nativeInhibitor.enabled) {
|
||||
SessionService.idleInhibited = nativeInhibitor.enabled
|
||||
SessionService.inhibitorChanged()
|
||||
}
|
||||
})
|
||||
console.log("DankBar: Created native Wayland IdleInhibitor for", barWindow.screenName)
|
||||
} catch (e) {
|
||||
console.warn("DankBar: Failed to create native IdleInhibitor:", e)
|
||||
nativeInhibitor = null
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onDankBarLeftWidgetsChanged() {
|
||||
barWindow.updateGpuTempConfig()
|
||||
}
|
||||
|
||||
function onDankBarCenterWidgetsChanged() {
|
||||
barWindow.updateGpuTempConfig()
|
||||
}
|
||||
|
||||
function onDankBarRightWidgetsChanged() {
|
||||
barWindow.updateGpuTempConfig()
|
||||
}
|
||||
|
||||
target: SettingsData
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onNvidiaGpuTempEnabledChanged() {
|
||||
barWindow.updateGpuTempConfig()
|
||||
}
|
||||
|
||||
function onNonNvidiaGpuTempEnabledChanged() {
|
||||
barWindow.updateGpuTempConfig()
|
||||
}
|
||||
|
||||
target: SessionData
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: barWindow.screen
|
||||
function onGeometryChanged() {
|
||||
Qt.callLater(forceWidgetRefresh)
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: refreshTimer
|
||||
interval: 0
|
||||
running: false
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
forceWidgetRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: axis
|
||||
function onChanged() {
|
||||
Qt.application.active
|
||||
refreshTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
anchors.top: !isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Top) : true
|
||||
anchors.bottom: !isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Bottom) : true
|
||||
anchors.left: !isVertical ? true : (SettingsData.dankBarPosition === SettingsData.Position.Left)
|
||||
anchors.right: !isVertical ? true : (SettingsData.dankBarPosition === SettingsData.Position.Right)
|
||||
|
||||
exclusiveZone: (!SettingsData.dankBarVisible || topBarCore.autoHide) ? -1 : (barWindow.effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap)
|
||||
|
||||
Item {
|
||||
id: inputMask
|
||||
|
||||
readonly property int barThickness: Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr)
|
||||
|
||||
readonly property bool inOverviewWithShow: CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview
|
||||
readonly property bool effectiveVisible: SettingsData.dankBarVisible || inOverviewWithShow
|
||||
readonly property bool showing: effectiveVisible && (topBarCore.reveal || inOverviewWithShow || !topBarCore.autoHide)
|
||||
|
||||
readonly property int maskThickness: showing ? barThickness : 1
|
||||
|
||||
x: {
|
||||
if (!axis.isVertical) {
|
||||
return 0
|
||||
} else {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Left:
|
||||
return 0
|
||||
case SettingsData.Position.Right:
|
||||
return parent.width - maskThickness
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
y: {
|
||||
if (axis.isVertical) {
|
||||
return 0
|
||||
} else {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return 0
|
||||
case SettingsData.Position.Bottom:
|
||||
return parent.height - maskThickness
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
width: axis.isVertical ? maskThickness : parent.width
|
||||
height: axis.isVertical ? parent.height : maskThickness
|
||||
}
|
||||
|
||||
mask: Region {
|
||||
item: inputMask
|
||||
}
|
||||
|
||||
Item {
|
||||
id: topBarCore
|
||||
anchors.fill: parent
|
||||
layer.enabled: true
|
||||
|
||||
property real backgroundTransparency: SettingsData.dankBarTransparency
|
||||
property bool autoHide: SettingsData.dankBarAutoHide
|
||||
property bool revealSticky: false
|
||||
|
||||
Timer {
|
||||
id: revealHold
|
||||
interval: SettingsData.dankBarAutoHideDelay
|
||||
repeat: false
|
||||
onTriggered: topBarCore.revealSticky = false
|
||||
}
|
||||
|
||||
property bool reveal: {
|
||||
if (CompositorService.isNiri && NiriService.inOverview) {
|
||||
return SettingsData.dankBarOpenOnOverview || topBarMouseArea.containsMouse || hasActivePopout || revealSticky
|
||||
}
|
||||
return SettingsData.dankBarVisible && (!autoHide || topBarMouseArea.containsMouse || hasActivePopout || revealSticky)
|
||||
}
|
||||
|
||||
readonly property bool hasActivePopout: {
|
||||
const loaders = [{
|
||||
"loader": appDrawerLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": dankDashPopoutLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": processListPopoutLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": notificationCenterLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": batteryPopoutLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": layoutPopoutLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": vpnPopoutLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": controlCenterLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": clipboardHistoryModalPopup,
|
||||
"prop": "visible"
|
||||
}, {
|
||||
"loader": systemUpdateLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}]
|
||||
return loaders.some(item => {
|
||||
if (item.loader && item.loader.item) {
|
||||
return item.loader.item[item.prop]
|
||||
}
|
||||
return false
|
||||
}) || rootWindow.systemTrayMenuOpen
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onDankBarTransparencyChanged() {
|
||||
topBarCore.backgroundTransparency = SettingsData.dankBarTransparency
|
||||
}
|
||||
|
||||
target: SettingsData
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: topBarMouseArea
|
||||
function onContainsMouseChanged() {
|
||||
if (topBarMouseArea.containsMouse) {
|
||||
topBarCore.revealSticky = true
|
||||
revealHold.stop()
|
||||
} else {
|
||||
if (topBarCore.autoHide && !topBarCore.hasActivePopout) {
|
||||
revealHold.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onHasActivePopoutChanged: {
|
||||
if (hasActivePopout) {
|
||||
revealSticky = true
|
||||
revealHold.stop()
|
||||
} else if (autoHide && !topBarMouseArea.containsMouse) {
|
||||
revealSticky = true
|
||||
revealHold.restart()
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: topBarMouseArea
|
||||
y: !barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? parent.height - height : 0) : 0
|
||||
x: barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.width - width : 0) : 0
|
||||
height: !barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) : undefined
|
||||
width: barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) : undefined
|
||||
anchors {
|
||||
left: !barWindow.isVertical ? parent.left : (SettingsData.dankBarPosition === SettingsData.Position.Left ? parent.left : undefined)
|
||||
right: !barWindow.isVertical ? parent.right : (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.right : undefined)
|
||||
top: barWindow.isVertical ? parent.top : undefined
|
||||
bottom: barWindow.isVertical ? parent.bottom : undefined
|
||||
}
|
||||
readonly property bool inOverview: CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview
|
||||
hoverEnabled: SettingsData.dankBarAutoHide && !topBarCore.reveal && !inOverview
|
||||
acceptedButtons: Qt.NoButton
|
||||
enabled: SettingsData.dankBarAutoHide && !topBarCore.reveal && !inOverview
|
||||
|
||||
Item {
|
||||
id: topBarContainer
|
||||
anchors.fill: parent
|
||||
|
||||
transform: Translate {
|
||||
id: topBarSlide
|
||||
x: barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (SettingsData.dankBarPosition === SettingsData.Position.Right ? barWindow.implicitWidth : -barWindow.implicitWidth), barWindow._dpr) : 0
|
||||
y: !barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? barWindow.implicitHeight : -barWindow.implicitHeight), barWindow._dpr) : 0
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on y {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: barUnitInset
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: !barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.edge === "left" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0)
|
||||
anchors.rightMargin: !barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.edge === "right" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0)
|
||||
anchors.topMargin: barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.outerVisualEdge() === "bottom" ? 0 : Theme.px(SettingsData.dankBarSpacing, barWindow._dpr))
|
||||
anchors.bottomMargin: barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.outerVisualEdge() === "bottom" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0)
|
||||
|
||||
BarCanvas {
|
||||
id: barBackground
|
||||
barWindow: barWindow
|
||||
axis: axis
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: scrollArea
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
propagateComposedEvents: true
|
||||
z: -1
|
||||
|
||||
property real scrollAccumulator: 0
|
||||
property real touchpadThreshold: 500
|
||||
property bool actionInProgress: false
|
||||
|
||||
Timer {
|
||||
id: cooldownTimer
|
||||
interval: 100
|
||||
onTriggered: parent.actionInProgress = false
|
||||
}
|
||||
|
||||
onWheel: wheel => {
|
||||
if (actionInProgress) {
|
||||
wheel.accepted = false
|
||||
return
|
||||
}
|
||||
|
||||
const deltaY = wheel.angleDelta.y
|
||||
const deltaX = wheel.angleDelta.x
|
||||
|
||||
if (CompositorService.isNiri && Math.abs(deltaX) > Math.abs(deltaY)) {
|
||||
topBarContent.switchApp(deltaX)
|
||||
wheel.accepted = false
|
||||
return
|
||||
}
|
||||
|
||||
const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0
|
||||
const direction = deltaY < 0 ? 1 : -1
|
||||
|
||||
if (isMouseWheel) {
|
||||
topBarContent.switchWorkspace(direction)
|
||||
actionInProgress = true
|
||||
cooldownTimer.restart()
|
||||
} else {
|
||||
scrollAccumulator += deltaY
|
||||
|
||||
if (Math.abs(scrollAccumulator) >= touchpadThreshold) {
|
||||
const touchDirection = scrollAccumulator < 0 ? 1 : -1
|
||||
topBarContent.switchWorkspace(touchDirection)
|
||||
scrollAccumulator = 0
|
||||
actionInProgress = true
|
||||
cooldownTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
wheel.accepted = false
|
||||
}
|
||||
}
|
||||
|
||||
DankBarContent {
|
||||
id: topBarContent
|
||||
barWindow: barWindow
|
||||
rootWindow: rootWindow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,8 +50,8 @@ DankPopout {
|
||||
triggerWidth: 70
|
||||
positioning: ""
|
||||
screen: triggerScreen
|
||||
shouldBeVisible: false
|
||||
visible: shouldBeVisible
|
||||
|
||||
onBackgroundClicked: close()
|
||||
|
||||
content: Component {
|
||||
Rectangle {
|
||||
|
||||
@@ -95,7 +95,6 @@ DankPopout {
|
||||
positioning: ""
|
||||
screen: triggerScreen
|
||||
shouldBeVisible: false
|
||||
visible: shouldBeVisible
|
||||
|
||||
content: Component {
|
||||
Rectangle {
|
||||
|
||||
@@ -46,7 +46,8 @@ DankPopout {
|
||||
positioning: ""
|
||||
screen: triggerScreen
|
||||
shouldBeVisible: false
|
||||
visible: shouldBeVisible
|
||||
|
||||
onBackgroundClicked: close()
|
||||
|
||||
content: Component {
|
||||
Rectangle {
|
||||
|
||||
@@ -19,7 +19,7 @@ BasePill {
|
||||
id: clockColumn
|
||||
visible: root.isVerticalOrientation
|
||||
anchors.centerIn: parent
|
||||
spacing: -2
|
||||
spacing: 0
|
||||
|
||||
Row {
|
||||
spacing: 0
|
||||
@@ -37,7 +37,6 @@ BasePill {
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness)
|
||||
color: Theme.surfaceText
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignBottom
|
||||
}
|
||||
@@ -54,7 +53,6 @@ BasePill {
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness)
|
||||
color: Theme.surfaceText
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignBottom
|
||||
}
|
||||
@@ -68,7 +66,6 @@ BasePill {
|
||||
text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(0)
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness)
|
||||
color: Theme.surfaceText
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignBottom
|
||||
}
|
||||
@@ -77,7 +74,6 @@ BasePill {
|
||||
text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(1)
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness)
|
||||
color: Theme.surfaceText
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignBottom
|
||||
}
|
||||
@@ -92,7 +88,6 @@ BasePill {
|
||||
text: String(systemClock?.date?.getSeconds()).padStart(2, '0').charAt(0)
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness)
|
||||
color: Theme.surfaceText
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignBottom
|
||||
}
|
||||
@@ -101,19 +96,18 @@ BasePill {
|
||||
text: String(systemClock?.date?.getSeconds()).padStart(2, '0').charAt(1)
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness)
|
||||
color: Theme.surfaceText
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignBottom
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 12
|
||||
width: parent.width
|
||||
height: Theme.spacingM
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Rectangle {
|
||||
width: 12
|
||||
width: parent.width * 0.6
|
||||
height: 1
|
||||
color: Theme.outlineButton
|
||||
anchors.centerIn: parent
|
||||
@@ -134,7 +128,6 @@ BasePill {
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness)
|
||||
color: Theme.primary
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignBottom
|
||||
}
|
||||
@@ -149,7 +142,6 @@ BasePill {
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness)
|
||||
color: Theme.primary
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignBottom
|
||||
}
|
||||
@@ -169,7 +161,6 @@ BasePill {
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness)
|
||||
color: Theme.primary
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignBottom
|
||||
}
|
||||
@@ -184,7 +175,6 @@ BasePill {
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness)
|
||||
color: Theme.primary
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignBottom
|
||||
}
|
||||
|
||||
@@ -132,8 +132,8 @@ BasePill {
|
||||
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||
}
|
||||
DgopService.setSortBy("cpu");
|
||||
if (root.toggleProcessList) {
|
||||
root.toggleProcessList();
|
||||
if (popoutTarget) {
|
||||
PopoutManager.requestPopout(popoutTarget, undefined, "cpu");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,8 +132,8 @@ BasePill {
|
||||
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||
}
|
||||
DgopService.setSortBy("cpu");
|
||||
if (root.toggleProcessList) {
|
||||
root.toggleProcessList();
|
||||
if (popoutTarget) {
|
||||
PopoutManager.requestPopout(popoutTarget, undefined, "cpu_temp");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,8 +196,8 @@ BasePill {
|
||||
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||
}
|
||||
DgopService.setSortBy("cpu");
|
||||
if (root.toggleProcessList) {
|
||||
root.toggleProcessList();
|
||||
if (popoutTarget) {
|
||||
PopoutManager.requestPopout(popoutTarget, undefined, "gpu_temp");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,14 @@ BasePill {
|
||||
id: root
|
||||
|
||||
property bool compactMode: SettingsData.keyboardLayoutNameCompactMode
|
||||
property string currentLayout: CompositorService.isNiri ? NiriService.getCurrentKeyboardLayoutName() : ""
|
||||
property string currentLayout: {
|
||||
if (CompositorService.isNiri) {
|
||||
return NiriService.getCurrentKeyboardLayoutName()
|
||||
} else if (CompositorService.isDwl) {
|
||||
return DwlService.currentKeyboardLayout
|
||||
}
|
||||
return ""
|
||||
}
|
||||
property string hyprlandKeyboard: ""
|
||||
|
||||
content: Component {
|
||||
@@ -79,6 +86,8 @@ BasePill {
|
||||
root.hyprlandKeyboard,
|
||||
"next"
|
||||
])
|
||||
} else if (CompositorService.isDwl) {
|
||||
Quickshell.execDetached(["mmsg", "-d", "switch_keyboard_layout"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,8 +155,8 @@ BasePill {
|
||||
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||
}
|
||||
DgopService.setSortBy("memory");
|
||||
if (root.toggleProcessList) {
|
||||
root.toggleProcessList();
|
||||
if (popoutTarget) {
|
||||
PopoutManager.requestPopout(popoutTarget, undefined, "memory");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,13 +149,13 @@ Item {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = 0
|
||||
} else {
|
||||
nextIndex = (currentIndex + 1) % windows.length
|
||||
nextIndex = Math.min(currentIndex + 1, windows.length - 1)
|
||||
}
|
||||
} else {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = windows.length - 1
|
||||
} else {
|
||||
nextIndex = (currentIndex - 1 + windows.length) % windows.length
|
||||
nextIndex = Math.max(currentIndex - 1, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,13 +181,13 @@ Item {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = 0
|
||||
} else {
|
||||
nextIndex = (currentIndex + 1) % windows.length
|
||||
nextIndex = Math.min(currentIndex + 1, windows.length - 1)
|
||||
}
|
||||
} else {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = windows.length - 1
|
||||
} else {
|
||||
nextIndex = (currentIndex - 1 + windows.length) % windows.length
|
||||
nextIndex = Math.max(currentIndex - 1, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Services.SystemTray
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
@@ -49,7 +50,17 @@ Item {
|
||||
visible: allTrayItems.length > 0
|
||||
|
||||
property bool menuOpen: false
|
||||
property bool overflowWasOpenBeforeTrayMenu: false
|
||||
property var currentTrayMenu: null
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!parentScreen) return
|
||||
TrayMenuManager.register(parentScreen.name, root)
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
if (!parentScreen) return
|
||||
TrayMenuManager.unregister(parentScreen.name)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: visualBackground
|
||||
@@ -171,7 +182,7 @@ Item {
|
||||
|
||||
if (!delegateRoot.trayItem.hasMenu) return
|
||||
|
||||
root.overflowWasOpenBeforeTrayMenu = root.menuOpen
|
||||
root.menuOpen = false
|
||||
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVertical, root.axis)
|
||||
}
|
||||
}
|
||||
@@ -304,7 +315,7 @@ Item {
|
||||
|
||||
if (!delegateRoot.trayItem.hasMenu) return
|
||||
|
||||
root.overflowWasOpenBeforeTrayMenu = root.menuOpen
|
||||
root.menuOpen = false
|
||||
root.showForTrayItem(delegateRoot.trayItem, visualContent, parentScreen, root.isAtBottom, root.isVertical, root.axis)
|
||||
}
|
||||
}
|
||||
@@ -356,10 +367,19 @@ Item {
|
||||
screen: root.parentScreen
|
||||
WlrLayershell.layer: WlrLayershell.Top
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
WlrLayershell.keyboardFocus: {
|
||||
if (!root.menuOpen) return WlrKeyboardFocus.None
|
||||
if (CompositorService.isHyprland) return WlrKeyboardFocus.OnDemand
|
||||
return WlrKeyboardFocus.Exclusive
|
||||
}
|
||||
WlrLayershell.namespace: "dms:tray-overflow-menu"
|
||||
color: "transparent"
|
||||
|
||||
HyprlandFocusGrab {
|
||||
windows: [overflowMenu]
|
||||
active: CompositorService.isHyprland && root.menuOpen
|
||||
}
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
@@ -372,12 +392,108 @@ Item {
|
||||
: (screen?.devicePixelRatio || 1)
|
||||
property point anchorPos: Qt.point(screen.width / 2, screen.height / 2)
|
||||
|
||||
readonly property var barBounds: {
|
||||
if (!overflowMenu.screen) {
|
||||
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
|
||||
}
|
||||
return SettingsData.getBarBounds(overflowMenu.screen, root.barThickness + SettingsData.dankBarSpacing)
|
||||
}
|
||||
|
||||
readonly property real barX: barBounds.x
|
||||
readonly property real barY: barBounds.y
|
||||
readonly property real barWidth: barBounds.width
|
||||
readonly property real barHeight: barBounds.height
|
||||
|
||||
readonly property real maskX: {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Left:
|
||||
return barWidth > 0 ? barWidth : 0
|
||||
case SettingsData.Position.Right:
|
||||
case SettingsData.Position.Top:
|
||||
case SettingsData.Position.Bottom:
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
readonly property real maskY: {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return barHeight > 0 ? barHeight : 0
|
||||
case SettingsData.Position.Bottom:
|
||||
case SettingsData.Position.Left:
|
||||
case SettingsData.Position.Right:
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
readonly property real maskWidth: {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Left:
|
||||
return barWidth > 0 ? width - barWidth : width
|
||||
case SettingsData.Position.Right:
|
||||
return barWidth > 0 ? width - barWidth : width
|
||||
case SettingsData.Position.Top:
|
||||
case SettingsData.Position.Bottom:
|
||||
default:
|
||||
return width
|
||||
}
|
||||
}
|
||||
|
||||
readonly property real maskHeight: {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return barHeight > 0 ? height - barHeight : height
|
||||
case SettingsData.Position.Bottom:
|
||||
return barHeight > 0 ? height - barHeight : height
|
||||
case SettingsData.Position.Left:
|
||||
case SettingsData.Position.Right:
|
||||
default:
|
||||
return height
|
||||
}
|
||||
}
|
||||
|
||||
mask: Region {
|
||||
item: Rectangle {
|
||||
x: overflowMenu.maskX
|
||||
y: overflowMenu.maskY
|
||||
width: overflowMenu.maskWidth
|
||||
height: overflowMenu.maskHeight
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
if (currentTrayMenu) {
|
||||
currentTrayMenu.showMenu = false
|
||||
}
|
||||
PopoutManager.closeAllPopouts()
|
||||
ModalManager.closeAllModalsExcept(null)
|
||||
updatePosition()
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
x: overflowMenu.maskX
|
||||
y: overflowMenu.maskY
|
||||
width: overflowMenu.maskWidth
|
||||
height: overflowMenu.maskHeight
|
||||
z: -1
|
||||
enabled: root.menuOpen
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
onClicked: mouse => {
|
||||
const clickX = mouse.x + overflowMenu.maskX
|
||||
const clickY = mouse.y + overflowMenu.maskY
|
||||
const outsideContent = clickX < menuContainer.x || clickX > menuContainer.x + menuContainer.width ||
|
||||
clickY < menuContainer.y || clickY > menuContainer.y + menuContainer.height
|
||||
|
||||
if (!outsideContent) return
|
||||
|
||||
root.menuOpen = false
|
||||
}
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
id: overflowFocusScope
|
||||
anchors.fill: parent
|
||||
@@ -389,11 +505,6 @@ Item {
|
||||
}
|
||||
|
||||
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
|
||||
@@ -613,7 +724,6 @@ Item {
|
||||
|
||||
if (!trayItem.hasMenu) return
|
||||
|
||||
root.overflowWasOpenBeforeTrayMenu = true
|
||||
root.menuOpen = false
|
||||
root.showForTrayItem(trayItem, parent, parentScreen, root.isAtBottom, root.isVertical, root.axis)
|
||||
}
|
||||
@@ -622,12 +732,6 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
z: -1
|
||||
onClicked: root.menuOpen = false
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
@@ -674,14 +778,9 @@ Item {
|
||||
|
||||
function close() {
|
||||
showMenu = false
|
||||
if (root.overflowWasOpenBeforeTrayMenu) {
|
||||
root.menuOpen = true
|
||||
}
|
||||
root.overflowWasOpenBeforeTrayMenu = false
|
||||
}
|
||||
|
||||
function closeWithAction() {
|
||||
root.overflowWasOpenBeforeTrayMenu = false
|
||||
close()
|
||||
}
|
||||
|
||||
@@ -715,9 +814,18 @@ Item {
|
||||
visible: menuRoot.showMenu && (menuRoot.trayItem?.hasMenu ?? false)
|
||||
WlrLayershell.layer: WlrLayershell.Top
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
WlrLayershell.keyboardFocus: {
|
||||
if (!menuRoot.showMenu) return WlrKeyboardFocus.None
|
||||
if (CompositorService.isHyprland) return WlrKeyboardFocus.OnDemand
|
||||
return WlrKeyboardFocus.Exclusive
|
||||
}
|
||||
color: "transparent"
|
||||
|
||||
HyprlandFocusGrab {
|
||||
windows: [menuWindow]
|
||||
active: CompositorService.isHyprland && menuRoot.showMenu
|
||||
}
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
@@ -730,12 +838,106 @@ Item {
|
||||
: (screen?.devicePixelRatio || 1)
|
||||
property point anchorPos: Qt.point(screen.width / 2, screen.height / 2)
|
||||
|
||||
readonly property var barBounds: {
|
||||
if (!menuWindow.screen) {
|
||||
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
|
||||
}
|
||||
return SettingsData.getBarBounds(menuWindow.screen, root.barThickness + SettingsData.dankBarSpacing)
|
||||
}
|
||||
|
||||
readonly property real barX: barBounds.x
|
||||
readonly property real barY: barBounds.y
|
||||
readonly property real barWidth: barBounds.width
|
||||
readonly property real barHeight: barBounds.height
|
||||
|
||||
readonly property real maskX: {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Left:
|
||||
return barWidth > 0 ? barWidth : 0
|
||||
case SettingsData.Position.Right:
|
||||
case SettingsData.Position.Top:
|
||||
case SettingsData.Position.Bottom:
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
readonly property real maskY: {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return barHeight > 0 ? barHeight : 0
|
||||
case SettingsData.Position.Bottom:
|
||||
case SettingsData.Position.Left:
|
||||
case SettingsData.Position.Right:
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
readonly property real maskWidth: {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Left:
|
||||
return barWidth > 0 ? width - barWidth : width
|
||||
case SettingsData.Position.Right:
|
||||
return barWidth > 0 ? width - barWidth : width
|
||||
case SettingsData.Position.Top:
|
||||
case SettingsData.Position.Bottom:
|
||||
default:
|
||||
return width
|
||||
}
|
||||
}
|
||||
|
||||
readonly property real maskHeight: {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return barHeight > 0 ? height - barHeight : height
|
||||
case SettingsData.Position.Bottom:
|
||||
return barHeight > 0 ? height - barHeight : height
|
||||
case SettingsData.Position.Left:
|
||||
case SettingsData.Position.Right:
|
||||
default:
|
||||
return height
|
||||
}
|
||||
}
|
||||
|
||||
mask: Region {
|
||||
item: Rectangle {
|
||||
x: menuWindow.maskX
|
||||
y: menuWindow.maskY
|
||||
width: menuWindow.maskWidth
|
||||
height: menuWindow.maskHeight
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
root.menuOpen = false
|
||||
PopoutManager.closeAllPopouts()
|
||||
ModalManager.closeAllModalsExcept(null)
|
||||
updatePosition()
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
x: menuWindow.maskX
|
||||
y: menuWindow.maskY
|
||||
width: menuWindow.maskWidth
|
||||
height: menuWindow.maskHeight
|
||||
z: -1
|
||||
enabled: menuRoot.showMenu
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
onClicked: mouse => {
|
||||
const clickX = mouse.x + menuWindow.maskX
|
||||
const clickY = mouse.y + menuWindow.maskY
|
||||
const outsideContent = clickX < menuContainer.x || clickX > menuContainer.x + menuContainer.width ||
|
||||
clickY < menuContainer.y || clickY > menuContainer.y + menuContainer.height
|
||||
|
||||
if (!outsideContent) return
|
||||
|
||||
menuRoot.close()
|
||||
}
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
id: menuFocusScope
|
||||
anchors.fill: parent
|
||||
@@ -751,12 +953,8 @@ Item {
|
||||
}
|
||||
|
||||
function updatePosition() {
|
||||
if (!root.parentWindow) {
|
||||
anchorPos = Qt.point(screen.width / 2, screen.height / 2)
|
||||
return
|
||||
}
|
||||
|
||||
const globalPos = root.mapToGlobal(0, 0)
|
||||
const targetItem = (typeof menuRoot !== "undefined" && menuRoot.anchorItem) ? menuRoot.anchorItem : root
|
||||
const globalPos = targetItem.mapToGlobal(0, 0)
|
||||
const screenX = screen.x || 0
|
||||
const screenY = screen.y || 0
|
||||
const relativeX = globalPos.x - screenX
|
||||
@@ -770,12 +968,12 @@ Item {
|
||||
let targetX = edge === "left"
|
||||
? effectiveBarThickness + SettingsData.dankBarSpacing + Theme.popupDistance
|
||||
: screen.width - (effectiveBarThickness + SettingsData.dankBarSpacing + Theme.popupDistance)
|
||||
anchorPos = Qt.point(targetX, relativeY + root.height / 2)
|
||||
anchorPos = Qt.point(targetX, relativeY + targetItem.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)
|
||||
anchorPos = Qt.point(relativeX + targetItem.width / 2, targetY)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1128,40 +1326,23 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
z: -1
|
||||
onClicked: menuRoot.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (!screen) return
|
||||
|
||||
if (currentTrayMenu) {
|
||||
currentTrayMenu.showMenu = false
|
||||
currentTrayMenu.destroy()
|
||||
currentTrayMenu = null
|
||||
}
|
||||
|
||||
currentTrayMenu = trayMenuComponent.createObject(null)
|
||||
if (currentTrayMenu) {
|
||||
currentTrayMenu.showForTrayItem(item, anchor, screen, atBottom, vertical ?? false, axisObj)
|
||||
}
|
||||
if (!currentTrayMenu) return
|
||||
|
||||
currentTrayMenu.showForTrayItem(item, anchor, screen, atBottom, vertical ?? false, axisObj)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -316,12 +316,19 @@ Item {
|
||||
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 => ({
|
||||
let visible = group.workspaces.filter(ws => !ws.hidden)
|
||||
|
||||
const hasValidCoordinates = visible.some(ws => ws.coordinates && ws.coordinates.length > 0)
|
||||
if (hasValidCoordinates) {
|
||||
visible = visible.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]
|
||||
})
|
||||
}
|
||||
|
||||
visible = visible.map(ws => ({
|
||||
id: ws.id,
|
||||
name: ws.name,
|
||||
coordinates: ws.coordinates,
|
||||
@@ -350,7 +357,7 @@ Item {
|
||||
|
||||
function getRealWorkspaces() {
|
||||
return root.workspaceList.filter(ws => {
|
||||
if (useExtWorkspace) return ws && ws.id !== "" && !ws.hidden
|
||||
if (useExtWorkspace) return ws && (ws.id !== "" || ws.name !== "") && !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
|
||||
@@ -438,9 +445,13 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
width: isVertical ? barThickness : visualWidth
|
||||
height: isVertical ? visualHeight : barThickness
|
||||
visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || useExtWorkspace
|
||||
readonly property bool hasNativeWorkspaceSupport: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway
|
||||
readonly property bool hasWorkspaces: getRealWorkspaces().length > 0
|
||||
readonly property bool shouldShow: hasNativeWorkspaceSupport || (useExtWorkspace && hasWorkspaces)
|
||||
|
||||
width: shouldShow ? (isVertical ? barThickness : visualWidth) : 0
|
||||
height: shouldShow ? (isVertical ? visualHeight : barThickness) : 0
|
||||
visible: shouldShow
|
||||
|
||||
Rectangle {
|
||||
id: visualBackground
|
||||
@@ -889,7 +900,7 @@ Item {
|
||||
|
||||
if (isPlaceholder) return index + 1
|
||||
|
||||
if (root.useExtWorkspace) return modelData?.name || modelData?.id || ""
|
||||
if (root.useExtWorkspace) return index + 1
|
||||
if (CompositorService.isHyprland) return modelData?.id || ""
|
||||
if (CompositorService.isDwl) return (modelData?.tag !== undefined) ? (modelData.tag + 1) : ""
|
||||
if (CompositorService.isSway) return modelData?.num || ""
|
||||
|
||||
@@ -18,7 +18,6 @@ DankPopout {
|
||||
property var triggerScreen: null
|
||||
property int currentTabIndex: 0
|
||||
|
||||
keyboardFocusMode: WlrKeyboardFocus.Exclusive
|
||||
|
||||
function setTriggerPosition(x, y, width, section, screen) {
|
||||
triggerSection = section
|
||||
@@ -44,8 +43,8 @@ DankPopout {
|
||||
triggerX: Screen.width - 620 - Theme.spacingL
|
||||
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
|
||||
triggerWidth: 80
|
||||
screen: triggerScreen
|
||||
shouldBeVisible: dashVisible
|
||||
visible: shouldBeVisible
|
||||
|
||||
property bool __focusArmed: false
|
||||
property bool __contentReady: false
|
||||
|
||||
@@ -35,7 +35,7 @@ Scope {
|
||||
WlrLayershell.namespace: "dms:workspace-overview"
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||
WlrLayershell.keyboardFocus: overviewScope.overviewOpen ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
|
||||
@@ -11,25 +11,123 @@ Rectangle {
|
||||
property bool isVisible: false
|
||||
property bool showLogout: true
|
||||
property int selectedIndex: 0
|
||||
property int optionCount: {
|
||||
let count = 0
|
||||
if (showLogout) count++
|
||||
count++
|
||||
if (SessionService.hibernateSupported) count++
|
||||
count += 2
|
||||
return count
|
||||
}
|
||||
property int selectedRow: 0
|
||||
property int selectedCol: 0
|
||||
property var visibleActions: []
|
||||
property int gridColumns: 3
|
||||
property int gridRows: 2
|
||||
property bool useGridLayout: false
|
||||
|
||||
signal closed()
|
||||
|
||||
function show() {
|
||||
isVisible = true
|
||||
selectedIndex = 0
|
||||
Qt.callLater(() => {
|
||||
if (powerMenuFocusScope && powerMenuFocusScope.forceActiveFocus) {
|
||||
powerMenuFocusScope.forceActiveFocus()
|
||||
}
|
||||
function updateVisibleActions() {
|
||||
const allActions = (typeof SettingsData !== "undefined" && SettingsData.powerMenuActions)
|
||||
? SettingsData.powerMenuActions
|
||||
: ["logout", "suspend", "hibernate", "reboot", "poweroff"]
|
||||
const hibernateSupported = (typeof SessionService !== "undefined" && SessionService.hibernateSupported) || false
|
||||
let filtered = allActions.filter(action => {
|
||||
if (action === "hibernate" && !hibernateSupported) return false
|
||||
if (action === "lock") return false
|
||||
if (action === "restart") return false
|
||||
if (action === "logout" && !showLogout) return false
|
||||
return true
|
||||
})
|
||||
|
||||
visibleActions = filtered
|
||||
|
||||
useGridLayout = (typeof SettingsData !== "undefined" && SettingsData.powerMenuGridLayout !== undefined)
|
||||
? SettingsData.powerMenuGridLayout
|
||||
: false
|
||||
if (!useGridLayout) return
|
||||
|
||||
const count = visibleActions.length
|
||||
if (count === 0) {
|
||||
gridColumns = 1
|
||||
gridRows = 1
|
||||
return
|
||||
}
|
||||
|
||||
if (count <= 3) {
|
||||
gridColumns = 1
|
||||
gridRows = count
|
||||
return
|
||||
}
|
||||
|
||||
if (count === 4) {
|
||||
gridColumns = 2
|
||||
gridRows = 2
|
||||
return
|
||||
}
|
||||
|
||||
gridColumns = 3
|
||||
gridRows = Math.ceil(count / 3)
|
||||
}
|
||||
|
||||
function getDefaultActionIndex() {
|
||||
const defaultAction = (typeof SettingsData !== "undefined" && SettingsData.powerMenuDefaultAction)
|
||||
? SettingsData.powerMenuDefaultAction
|
||||
: "suspend"
|
||||
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 "suspend":
|
||||
return { "icon": "bedtime", "label": I18n.tr("Suspend"), "key": "S" }
|
||||
case "hibernate":
|
||||
return { "icon": "ac_unit", "label": I18n.tr("Hibernate"), "key": "H" }
|
||||
default:
|
||||
return { "icon": "help", "label": action, "key": "?" }
|
||||
}
|
||||
}
|
||||
|
||||
function selectOption(action) {
|
||||
if (!action) return
|
||||
if (typeof SessionService === "undefined") return
|
||||
hide()
|
||||
switch (action) {
|
||||
case "logout":
|
||||
SessionService.logout()
|
||||
break
|
||||
case "suspend":
|
||||
SessionService.suspend()
|
||||
break
|
||||
case "hibernate":
|
||||
SessionService.hibernate()
|
||||
break
|
||||
case "reboot":
|
||||
SessionService.reboot()
|
||||
break
|
||||
case "poweroff":
|
||||
SessionService.poweroff()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
function show() {
|
||||
updateVisibleActions()
|
||||
const defaultIndex = getDefaultActionIndex()
|
||||
if (useGridLayout) {
|
||||
selectedRow = Math.floor(defaultIndex / gridColumns)
|
||||
selectedCol = defaultIndex % gridColumns
|
||||
selectedIndex = defaultIndex
|
||||
} else {
|
||||
selectedIndex = defaultIndex
|
||||
}
|
||||
isVisible = true
|
||||
Qt.callLater(() => powerMenuFocusScope.forceActiveFocus())
|
||||
}
|
||||
|
||||
function hide() {
|
||||
@@ -37,6 +135,148 @@ Rectangle {
|
||||
closed()
|
||||
}
|
||||
|
||||
function handleListNavigation(event) {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Up:
|
||||
case Qt.Key_Backtab:
|
||||
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length
|
||||
event.accepted = true
|
||||
break
|
||||
case Qt.Key_Down:
|
||||
case Qt.Key_Tab:
|
||||
selectedIndex = (selectedIndex + 1) % visibleActions.length
|
||||
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) {
|
||||
selectedIndex = (selectedIndex + 1) % visibleActions.length
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_P:
|
||||
if (!(event.modifiers & Qt.ControlModifier)) {
|
||||
selectOption("poweroff")
|
||||
event.accepted = true
|
||||
} else {
|
||||
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_J:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedIndex = (selectedIndex + 1) % visibleActions.length
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_K:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length
|
||||
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_S:
|
||||
selectOption("suspend")
|
||||
event.accepted = true
|
||||
break
|
||||
case Qt.Key_H:
|
||||
selectOption("hibernate")
|
||||
event.accepted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
function handleGridNavigation(event) {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Left:
|
||||
selectedCol = (selectedCol - 1 + gridColumns) % gridColumns
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
event.accepted = true
|
||||
break
|
||||
case Qt.Key_Right:
|
||||
selectedCol = (selectedCol + 1) % gridColumns
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
event.accepted = true
|
||||
break
|
||||
case Qt.Key_Up:
|
||||
case Qt.Key_Backtab:
|
||||
selectedRow = (selectedRow - 1 + gridRows) % gridRows
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
event.accepted = true
|
||||
break
|
||||
case Qt.Key_Down:
|
||||
case Qt.Key_Tab:
|
||||
selectedRow = (selectedRow + 1) % gridRows
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
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
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_P:
|
||||
if (!(event.modifiers & Qt.ControlModifier)) {
|
||||
selectOption("poweroff")
|
||||
event.accepted = true
|
||||
} else {
|
||||
selectedCol = (selectedCol - 1 + gridColumns) % gridColumns
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_J:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedRow = (selectedRow + 1) % gridRows
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_K:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedRow = (selectedRow - 1 + gridRows) % gridRows
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
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_S:
|
||||
selectOption("suspend")
|
||||
event.accepted = true
|
||||
break
|
||||
case Qt.Key_H:
|
||||
selectOption("hibernate")
|
||||
event.accepted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(0, 0, 0, 0.5)
|
||||
visible: isVisible
|
||||
@@ -53,102 +293,39 @@ Rectangle {
|
||||
focus: root.isVisible
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
Qt.callLater(() => forceActiveFocus())
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEscapePressed: {
|
||||
root.hide()
|
||||
if (visible) Qt.callLater(() => forceActiveFocus())
|
||||
}
|
||||
|
||||
Keys.onEscapePressed: root.hide()
|
||||
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 = []
|
||||
if (showLogout) actions.push("logout")
|
||||
actions.push("suspend")
|
||||
if (SessionService.hibernateSupported) actions.push("hibernate")
|
||||
actions.push("reboot", "poweroff")
|
||||
if (selectedIndex < actions.length) {
|
||||
const action = actions[selectedIndex]
|
||||
hide()
|
||||
switch (action) {
|
||||
case "logout":
|
||||
SessionService.logout()
|
||||
break
|
||||
case "suspend":
|
||||
SessionService.suspend()
|
||||
break
|
||||
case "hibernate":
|
||||
SessionService.hibernate()
|
||||
break
|
||||
case "reboot":
|
||||
SessionService.reboot()
|
||||
break
|
||||
case "poweroff":
|
||||
SessionService.poweroff()
|
||||
break
|
||||
}
|
||||
}
|
||||
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
|
||||
if (useGridLayout) {
|
||||
handleGridNavigation(event)
|
||||
} else {
|
||||
handleListNavigation(event)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: 320
|
||||
implicitHeight: mainColumn.implicitHeight + Theme.spacingL * 2
|
||||
height: implicitHeight
|
||||
width: useGridLayout
|
||||
? Math.min(550, gridColumns * 180 + Theme.spacingS * (gridColumns - 1) + Theme.spacingL * 2)
|
||||
: 320
|
||||
height: contentItem.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outlineMedium
|
||||
border.width: 1
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
Item {
|
||||
id: contentItem
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
implicitHeight: headerRow.height + Theme.spacingM + (useGridLayout ? buttonGrid.implicitHeight : buttonColumn.implicitHeight)
|
||||
|
||||
Row {
|
||||
id: headerRow
|
||||
width: parent.width
|
||||
height: 30
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Power Options")
|
||||
@@ -171,289 +348,199 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
Grid {
|
||||
id: buttonGrid
|
||||
visible: useGridLayout
|
||||
anchors.top: headerRow.bottom
|
||||
anchors.topMargin: Theme.spacingM
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
columns: root.gridColumns
|
||||
columnSpacing: Theme.spacingS
|
||||
rowSpacing: Theme.spacingS
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
visible: showLogout
|
||||
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 {
|
||||
Repeater {
|
||||
model: root.visibleActions
|
||||
|
||||
Rectangle {
|
||||
required property int index
|
||||
required property string modelData
|
||||
|
||||
readonly property var actionData: root.getActionData(modelData)
|
||||
readonly property bool isSelected: root.selectedIndex === index
|
||||
readonly property bool showWarning: modelData === "reboot" || modelData === "poweroff"
|
||||
|
||||
width: (contentItem.width - 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: selectedIndex === 0 ? Theme.primary : "transparent"
|
||||
border.width: selectedIndex === 0 ? 1 : 0
|
||||
border.color: isSelected ? Theme.primary : "transparent"
|
||||
border.width: isSelected ? 2 : 0
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "logout"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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: {
|
||||
root.hide()
|
||||
SessionService.logout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
const suspendIdx = showLogout ? 1 : 0
|
||||
if (selectedIndex === suspendIdx) {
|
||||
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 === (showLogout ? 1 : 0) ? Theme.primary : "transparent"
|
||||
border.width: selectedIndex === (showLogout ? 1 : 0) ? 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: {
|
||||
root.hide()
|
||||
SessionService.suspend()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
const hibernateIdx = showLogout ? 2 : 1
|
||||
if (selectedIndex === hibernateIdx) {
|
||||
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 === (showLogout ? 2 : 1) ? Theme.primary : "transparent"
|
||||
border.width: selectedIndex === (showLogout ? 2 : 1) ? 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: {
|
||||
root.hide()
|
||||
SessionService.hibernate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
let rebootIdx = showLogout ? 3 : 2
|
||||
if (!SessionService.hibernateSupported) rebootIdx--
|
||||
if (selectedIndex === rebootIdx) {
|
||||
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: {
|
||||
let rebootIdx = showLogout ? 3 : 2
|
||||
if (!SessionService.hibernateSupported) rebootIdx--
|
||||
return selectedIndex === rebootIdx ? Theme.primary : "transparent"
|
||||
}
|
||||
border.width: {
|
||||
let rebootIdx = showLogout ? 3 : 2
|
||||
if (!SessionService.hibernateSupported) rebootIdx--
|
||||
return selectedIndex === rebootIdx ? 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: {
|
||||
root.hide()
|
||||
SessionService.reboot()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
let powerOffIdx = showLogout ? 4 : 3
|
||||
if (!SessionService.hibernateSupported) powerOffIdx--
|
||||
if (selectedIndex === powerOffIdx) {
|
||||
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: {
|
||||
let powerOffIdx = showLogout ? 4 : 3
|
||||
if (!SessionService.hibernateSupported) powerOffIdx--
|
||||
return selectedIndex === powerOffIdx ? Theme.primary : "transparent"
|
||||
}
|
||||
border.width: {
|
||||
let powerOffIdx = showLogout ? 4 : 3
|
||||
if (!SessionService.hibernateSupported) powerOffIdx--
|
||||
return selectedIndex === powerOffIdx ? 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: {
|
||||
root.hide()
|
||||
SessionService.poweroff()
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
height: Theme.spacingS
|
||||
Column {
|
||||
id: buttonColumn
|
||||
visible: !useGridLayout
|
||||
anchors.top: headerRow.bottom
|
||||
anchors.topMargin: Theme.spacingM
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Repeater {
|
||||
model: root.visibleActions
|
||||
|
||||
Rectangle {
|
||||
required property int index
|
||||
required property string modelData
|
||||
|
||||
readonly property var actionData: root.getActionData(modelData)
|
||||
readonly property bool isSelected: root.selectedIndex === index
|
||||
readonly property bool showWarning: modelData === "reboot" || modelData === "poweroff"
|
||||
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (isSelected) return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
if (listMouseArea.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
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: parent.parent.actionData.icon
|
||||
size: Theme.iconSize + 4
|
||||
color: {
|
||||
if (parent.parent.showWarning && listMouseArea.containsMouse) {
|
||||
return parent.parent.modelData === "poweroff" ? Theme.error : Theme.warning
|
||||
}
|
||||
return Theme.surfaceText
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: parent.parent.actionData.label
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: {
|
||||
if (parent.parent.showWarning && listMouseArea.containsMouse) {
|
||||
return parent.parent.modelData === "poweroff" ? Theme.error : Theme.warning
|
||||
}
|
||||
return Theme.surfaceText
|
||||
}
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 28
|
||||
height: 20
|
||||
radius: 4
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.1)
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: parent.parent.actionData.key
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
font.weight: Font.Medium
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: listMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.selectedIndex = index
|
||||
root.selectOption(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: updateVisibleActions()
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ DankListView {
|
||||
|
||||
NotificationEmptyState {
|
||||
visible: listView.count === 0
|
||||
anchors.centerIn: parent
|
||||
y: 20
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
onModelChanged: {
|
||||
|
||||
@@ -42,7 +42,14 @@ DankPopout {
|
||||
positioning: ""
|
||||
screen: triggerScreen
|
||||
shouldBeVisible: notificationHistoryVisible
|
||||
visible: shouldBeVisible
|
||||
|
||||
function toggle() {
|
||||
notificationHistoryVisible = !notificationHistoryVisible
|
||||
}
|
||||
|
||||
onBackgroundClicked: {
|
||||
notificationHistoryVisible = false
|
||||
}
|
||||
|
||||
onNotificationHistoryVisibleChanged: {
|
||||
if (notificationHistoryVisible) {
|
||||
@@ -104,13 +111,20 @@ DankPopout {
|
||||
implicitHeight: {
|
||||
let baseHeight = Theme.spacingL * 2
|
||||
baseHeight += cachedHeaderHeight
|
||||
baseHeight += (notificationSettings.expanded ? notificationSettings.contentHeight : 0)
|
||||
baseHeight += Theme.spacingM * 2
|
||||
|
||||
const settingsHeight = notificationSettings.expanded ? notificationSettings.contentHeight : 0
|
||||
let listHeight = notificationList.listContentHeight
|
||||
if (NotificationService.groupedNotifications.length === 0) {
|
||||
listHeight = 200
|
||||
}
|
||||
baseHeight += Math.min(listHeight, 600)
|
||||
|
||||
const maxContentArea = 600
|
||||
const availableListSpace = Math.max(200, maxContentArea - settingsHeight)
|
||||
|
||||
baseHeight += settingsHeight
|
||||
baseHeight += Math.min(listHeight, availableListSpace)
|
||||
|
||||
const maxHeight = root.screen ? root.screen.height * 0.8 : Screen.height * 0.8
|
||||
return Math.max(300, Math.min(baseHeight, maxHeight))
|
||||
}
|
||||
@@ -191,13 +205,6 @@ DankPopout {
|
||||
showHints: (externalKeyboardController && externalKeyboardController.showKeyboardHints) || false
|
||||
z: 200
|
||||
}
|
||||
|
||||
Behavior on implicitHeight {
|
||||
NumberAnimation {
|
||||
duration: 180
|
||||
easing.type: Easing.OutQuart
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ import qs.Widgets
|
||||
DankOSD {
|
||||
id: root
|
||||
|
||||
osdWidth: Math.min(260, Screen.width - Theme.spacingM * 2)
|
||||
osdHeight: 40 + Theme.spacingS * 2
|
||||
readonly property bool useVertical: isVerticalLayout
|
||||
|
||||
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2)
|
||||
osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
|
||||
autoHideInterval: 3000
|
||||
enableMouseInteraction: true
|
||||
|
||||
@@ -20,8 +22,13 @@ DankOSD {
|
||||
}
|
||||
}
|
||||
|
||||
content: Item {
|
||||
content: Loader {
|
||||
anchors.fill: parent
|
||||
sourceComponent: useVertical ? verticalContent : horizontalContent
|
||||
}
|
||||
|
||||
Component {
|
||||
id: horizontalContent
|
||||
|
||||
Item {
|
||||
property int gap: Theme.spacingS
|
||||
@@ -135,4 +142,175 @@ DankOSD {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: verticalContent
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
property int gap: Theme.spacingS
|
||||
|
||||
Rectangle {
|
||||
width: Theme.iconSize
|
||||
height: Theme.iconSize
|
||||
radius: Theme.iconSize / 2
|
||||
color: "transparent"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: gap
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: {
|
||||
const deviceInfo = DisplayService.getCurrentDeviceInfo()
|
||||
if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") {
|
||||
return "brightness_medium"
|
||||
} else if (deviceInfo.name.includes("kbd")) {
|
||||
return "keyboard"
|
||||
} else {
|
||||
return "lightbulb"
|
||||
}
|
||||
}
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: vertSlider
|
||||
width: 12
|
||||
height: parent.height - Theme.iconSize - gap * 3 - 24
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: gap * 2 + Theme.iconSize
|
||||
|
||||
property bool dragging: false
|
||||
property int value: DisplayService.brightnessAvailable ? DisplayService.brightnessLevel : 0
|
||||
|
||||
readonly property int minimum: {
|
||||
const deviceInfo = DisplayService.getCurrentDeviceInfo()
|
||||
if (!deviceInfo) return 1
|
||||
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id)
|
||||
if (isExponential) return 1
|
||||
return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0
|
||||
}
|
||||
|
||||
readonly property int maximum: {
|
||||
const deviceInfo = DisplayService.getCurrentDeviceInfo()
|
||||
if (!deviceInfo) return 100
|
||||
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id)
|
||||
if (isExponential) return 100
|
||||
return deviceInfo.displayMax || 100
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: vertTrack
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors.centerIn: parent
|
||||
color: Theme.outline
|
||||
radius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: vertFill
|
||||
width: parent.width
|
||||
height: {
|
||||
const ratio = (vertSlider.value - vertSlider.minimum) / (vertSlider.maximum - vertSlider.minimum)
|
||||
return ratio * parent.height
|
||||
}
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: Theme.primary
|
||||
radius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: vertHandle
|
||||
width: 24
|
||||
height: 8
|
||||
radius: Theme.cornerRadius
|
||||
y: {
|
||||
const ratio = (vertSlider.value - vertSlider.minimum) / (vertSlider.maximum - vertSlider.minimum)
|
||||
const travel = parent.height - height
|
||||
return Math.max(0, Math.min(travel, travel * (1 - ratio)))
|
||||
}
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: Theme.primary
|
||||
border.width: 3
|
||||
border.color: Theme.surfaceContainer
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: vertSliderArea
|
||||
anchors.fill: parent
|
||||
anchors.margins: -12
|
||||
enabled: DisplayService.brightnessAvailable
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onContainsMouseChanged: {
|
||||
setChildHovered(containsMouse)
|
||||
}
|
||||
|
||||
onPressed: mouse => {
|
||||
vertSlider.dragging = true
|
||||
updateBrightness(mouse)
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
vertSlider.dragging = false
|
||||
}
|
||||
|
||||
onPositionChanged: mouse => {
|
||||
if (pressed) {
|
||||
updateBrightness(mouse)
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: mouse => {
|
||||
updateBrightness(mouse)
|
||||
}
|
||||
|
||||
function updateBrightness(mouse) {
|
||||
if (DisplayService.brightnessAvailable) {
|
||||
const ratio = 1.0 - (mouse.y / height)
|
||||
const newValue = Math.round(vertSlider.minimum + ratio * (vertSlider.maximum - vertSlider.minimum))
|
||||
DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true)
|
||||
resetHideTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: DisplayService
|
||||
|
||||
function onBrightnessChanged(showOsd) {
|
||||
if (!vertSlider.dragging && vertSlider.value !== DisplayService.brightnessLevel) {
|
||||
vertSlider.value = DisplayService.brightnessLevel
|
||||
}
|
||||
}
|
||||
|
||||
function onDeviceSwitched() {
|
||||
if (!vertSlider.dragging && vertSlider.value !== DisplayService.brightnessLevel) {
|
||||
vertSlider.value = DisplayService.brightnessLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottomMargin: gap
|
||||
text: {
|
||||
const deviceInfo = DisplayService.getCurrentDeviceInfo()
|
||||
const isExponential = deviceInfo ? SessionData.getBrightnessExponential(deviceInfo.id) : false
|
||||
const unit = (deviceInfo && deviceInfo.class === "ddc" && !isExponential) ? "" : "%"
|
||||
return vertSlider.value + unit
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
visible: SettingsData.osdAlwaysShowValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ import qs.Widgets
|
||||
DankOSD {
|
||||
id: root
|
||||
|
||||
osdWidth: Math.min(260, Screen.width - Theme.spacingM * 2)
|
||||
osdHeight: 40 + Theme.spacingS * 2
|
||||
readonly property bool useVertical: isVerticalLayout
|
||||
|
||||
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2)
|
||||
osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
|
||||
autoHideInterval: 3000
|
||||
enableMouseInteraction: true
|
||||
|
||||
@@ -37,8 +39,13 @@ DankOSD {
|
||||
}
|
||||
}
|
||||
|
||||
content: Item {
|
||||
content: Loader {
|
||||
anchors.fill: parent
|
||||
sourceComponent: useVertical ? verticalContent : horizontalContent
|
||||
}
|
||||
|
||||
Component {
|
||||
id: horizontalContent
|
||||
|
||||
Item {
|
||||
property int gap: Theme.spacingS
|
||||
@@ -128,11 +135,161 @@ DankOSD {
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: verticalContent
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
property int gap: Theme.spacingS
|
||||
|
||||
Rectangle {
|
||||
width: Theme.iconSize
|
||||
height: Theme.iconSize
|
||||
radius: Theme.iconSize / 2
|
||||
color: "transparent"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: gap
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.muted ? "volume_off" : "volume_up"
|
||||
size: Theme.iconSize
|
||||
color: muteButtonVert.containsMouse ? Theme.primary : Theme.surfaceText
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: muteButtonVert
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
AudioService.toggleMute()
|
||||
}
|
||||
onContainsMouseChanged: {
|
||||
setChildHovered(containsMouse || vertSliderArea.containsMouse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: vertSlider
|
||||
width: 12
|
||||
height: parent.height - Theme.iconSize - gap * 3 - 24
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: gap * 2 + Theme.iconSize
|
||||
|
||||
property bool dragging: false
|
||||
property int value: AudioService.sink && AudioService.sink.audio ? Math.min(100, Math.round(AudioService.sink.audio.volume * 100)) : 0
|
||||
|
||||
Rectangle {
|
||||
id: vertTrack
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors.centerIn: parent
|
||||
color: Theme.outline
|
||||
radius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: vertFill
|
||||
width: parent.width
|
||||
height: (vertSlider.value / 100) * parent.height
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: Theme.primary
|
||||
radius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: vertHandle
|
||||
width: 24
|
||||
height: 8
|
||||
radius: Theme.cornerRadius
|
||||
y: {
|
||||
const ratio = vertSlider.value / 100
|
||||
const travel = parent.height - height
|
||||
return Math.max(0, Math.min(travel, travel * (1 - ratio)))
|
||||
}
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: Theme.primary
|
||||
border.width: 3
|
||||
border.color: Theme.surfaceContainer
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: vertSliderArea
|
||||
anchors.fill: parent
|
||||
anchors.margins: -12
|
||||
enabled: AudioService.sink && AudioService.sink.audio
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onContainsMouseChanged: {
|
||||
setChildHovered(containsMouse || muteButtonVert.containsMouse)
|
||||
}
|
||||
|
||||
onPressed: mouse => {
|
||||
vertSlider.dragging = true
|
||||
updateVolume(mouse)
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
vertSlider.dragging = false
|
||||
}
|
||||
|
||||
onPositionChanged: mouse => {
|
||||
if (pressed) {
|
||||
updateVolume(mouse)
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: mouse => {
|
||||
updateVolume(mouse)
|
||||
}
|
||||
|
||||
function updateVolume(mouse) {
|
||||
if (AudioService.sink && AudioService.sink.audio) {
|
||||
const ratio = 1.0 - (mouse.y / height)
|
||||
const volume = Math.max(0, Math.min(100, Math.round(ratio * 100)))
|
||||
AudioService.suppressOSD = true
|
||||
AudioService.sink.audio.volume = volume / 100
|
||||
AudioService.suppressOSD = false
|
||||
resetHideTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null
|
||||
|
||||
function onVolumeChanged() {
|
||||
if (!vertSlider.dragging) {
|
||||
vertSlider.value = Math.min(100, Math.round(AudioService.sink.audio.volume * 100))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottomMargin: gap
|
||||
text: vertSlider.value + "%"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
visible: SettingsData.osdAlwaysShowValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onOsdShown: {
|
||||
if (AudioService.sink && AudioService.sink.audio && contentLoader.item) {
|
||||
const slider = contentLoader.item.children[0].children[1]
|
||||
if (slider) {
|
||||
slider.value = Math.min(100, Math.round(AudioService.sink.audio.volume * 100))
|
||||
if (AudioService.sink && AudioService.sink.audio && contentLoader.item && contentLoader.item.item) {
|
||||
if (!useVertical) {
|
||||
const slider = contentLoader.item.item.children[0].children[1]
|
||||
if (slider && slider.value !== undefined) {
|
||||
slider.value = Math.min(100, Math.round(AudioService.sink.audio.volume * 100))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ DankPopout {
|
||||
|
||||
layerNamespace: "dms-plugin:" + layerNamespacePlugin
|
||||
|
||||
WlrLayershell.keyboardFocus: shouldBeVisible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
|
||||
property var triggerScreen: null
|
||||
property Component pluginContent: null
|
||||
property real contentWidth: 400
|
||||
@@ -27,7 +25,8 @@ DankPopout {
|
||||
popupHeight: contentHeight
|
||||
screen: triggerScreen
|
||||
shouldBeVisible: false
|
||||
visible: shouldBeVisible
|
||||
|
||||
onBackgroundClicked: close()
|
||||
|
||||
content: Component {
|
||||
Rectangle {
|
||||
|
||||
@@ -45,9 +45,10 @@ DankPopout {
|
||||
triggerWidth: 55
|
||||
positioning: ""
|
||||
screen: triggerScreen
|
||||
visible: shouldBeVisible
|
||||
shouldBeVisible: false
|
||||
|
||||
onBackgroundClicked: close()
|
||||
|
||||
Ref {
|
||||
service: DgopService
|
||||
}
|
||||
|
||||
@@ -542,11 +542,57 @@ Item {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Available Screens (") + Quickshell.screens.length + ")"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Available Screens (") + Quickshell.screens.length + ")"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 1
|
||||
height: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Display Name Format")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
DankButtonGroup {
|
||||
id: displayModeGroup
|
||||
model: [I18n.tr("Name"), I18n.tr("Model")]
|
||||
currentIndex: SettingsData.displayNameMode === "model" ? 1 : 0
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected) return
|
||||
SettingsData.displayNameMode = index === 1 ? "model" : "system"
|
||||
SettingsData.saveSettings()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onDisplayNameModeChanged() {
|
||||
displayModeGroup.currentIndex = SettingsData.displayNameMode === "model" ? 1 : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
@@ -580,7 +626,7 @@ Item {
|
||||
spacing: Theme.spacingXS / 2
|
||||
|
||||
StyledText {
|
||||
text: modelData.name
|
||||
text: SettingsData.getScreenDisplayName(modelData)
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -602,7 +648,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData.model || "Unknown Model"
|
||||
text: SettingsData.displayNameMode === "system" ? (modelData.model || "Unknown Model") : modelData.name
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
@@ -701,14 +747,17 @@ Item {
|
||||
width: parent.width
|
||||
text: I18n.tr("All displays")
|
||||
description: I18n.tr("Show on all connected displays")
|
||||
checked: displaysTab.getScreenPreferences(parent.componentId).includes("all")
|
||||
checked: {
|
||||
var prefs = displaysTab.getScreenPreferences(parent.componentId)
|
||||
return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")
|
||||
}
|
||||
onToggled: (checked) => {
|
||||
if (checked) {
|
||||
displaysTab.setScreenPreferences(parent.componentId, ["all"]);
|
||||
displaysTab.setScreenPreferences(parent.componentId, ["all"])
|
||||
} else {
|
||||
displaysTab.setScreenPreferences(parent.componentId, []);
|
||||
displaysTab.setScreenPreferences(parent.componentId, [])
|
||||
if (["dankBar", "dock", "notifications", "osd", "toast"].includes(parent.componentId)) {
|
||||
displaysTab.setShowOnLastDisplay(parent.componentId, true);
|
||||
displaysTab.setShowOnLastDisplay(parent.componentId, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -719,9 +768,13 @@ Item {
|
||||
text: I18n.tr("Show on Last Display")
|
||||
description: I18n.tr("Always show when there's only one connected display")
|
||||
checked: displaysTab.getShowOnLastDisplay(parent.componentId)
|
||||
visible: !displaysTab.getScreenPreferences(parent.componentId).includes("all") && ["dankBar", "dock", "notifications", "osd", "toast", "notepad", "systemTray"].includes(parent.componentId)
|
||||
visible: {
|
||||
var prefs = displaysTab.getScreenPreferences(parent.componentId)
|
||||
var isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")
|
||||
return !isAll && ["dankBar", "dock", "notifications", "osd", "toast", "notepad", "systemTray"].includes(parent.componentId)
|
||||
}
|
||||
onToggled: (checked) => {
|
||||
displaysTab.setShowOnLastDisplay(parent.componentId, checked);
|
||||
displaysTab.setShowOnLastDisplay(parent.componentId, checked)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,45 +783,54 @@ Item {
|
||||
height: 1
|
||||
color: Theme.outline
|
||||
opacity: 0.2
|
||||
visible: !displaysTab.getScreenPreferences(parent.componentId).includes("all")
|
||||
visible: {
|
||||
var prefs = displaysTab.getScreenPreferences(parent.componentId)
|
||||
return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all")
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
visible: !displaysTab.getScreenPreferences(parent.componentId).includes("all")
|
||||
visible: {
|
||||
var prefs = displaysTab.getScreenPreferences(parent.componentId)
|
||||
return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all")
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: Quickshell.screens
|
||||
|
||||
delegate: DankToggle {
|
||||
property string screenName: modelData.name
|
||||
property var screenData: modelData
|
||||
property string componentId: parent.parent.componentId
|
||||
|
||||
width: parent.width
|
||||
text: screenName
|
||||
description: modelData.width + "×" + modelData.height + " • " + (modelData.model || "Unknown Model")
|
||||
text: SettingsData.getScreenDisplayName(screenData)
|
||||
description: screenData.width + "×" + screenData.height + " • " + (SettingsData.displayNameMode === "system" ? (screenData.model || "Unknown Model") : screenData.name)
|
||||
checked: {
|
||||
var prefs = displaysTab.getScreenPreferences(componentId);
|
||||
return !prefs.includes("all") && prefs.includes(screenName);
|
||||
var prefs = displaysTab.getScreenPreferences(componentId)
|
||||
if (typeof prefs[0] === "string" && prefs[0] === "all") return false
|
||||
return SettingsData.isScreenInPreferences(screenData, prefs)
|
||||
}
|
||||
onToggled: (checked) => {
|
||||
var currentPrefs = displaysTab.getScreenPreferences(componentId);
|
||||
if (currentPrefs.includes("all"))
|
||||
currentPrefs = [];
|
||||
|
||||
var newPrefs = currentPrefs.slice();
|
||||
if (checked) {
|
||||
if (!newPrefs.includes(screenName))
|
||||
newPrefs.push(screenName);
|
||||
|
||||
} else {
|
||||
var index = newPrefs.indexOf(screenName);
|
||||
if (index > -1)
|
||||
newPrefs.splice(index, 1);
|
||||
|
||||
var currentPrefs = displaysTab.getScreenPreferences(componentId)
|
||||
if (typeof currentPrefs[0] === "string" && currentPrefs[0] === "all") {
|
||||
currentPrefs = []
|
||||
}
|
||||
displaysTab.setScreenPreferences(componentId, newPrefs);
|
||||
|
||||
var newPrefs = currentPrefs.filter(pref => {
|
||||
if (typeof pref === "string") return false
|
||||
return pref.name !== screenData.name || pref.model !== screenData.model
|
||||
})
|
||||
|
||||
if (checked) {
|
||||
newPrefs.push({
|
||||
name: screenData.name,
|
||||
model: screenData.model || ""
|
||||
})
|
||||
}
|
||||
|
||||
displaysTab.setScreenPreferences(componentId, newPrefs)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1007,18 +1007,32 @@ Item {
|
||||
|
||||
text: I18n.tr("Wallpaper Monitor")
|
||||
description: I18n.tr("Select monitor to configure wallpaper")
|
||||
currentValue: selectedMonitorName || "No monitors"
|
||||
currentValue: {
|
||||
var screens = Quickshell.screens
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
if (screens[i].name === selectedMonitorName) {
|
||||
return SettingsData.getScreenDisplayName(screens[i])
|
||||
}
|
||||
}
|
||||
return "No monitors"
|
||||
}
|
||||
options: {
|
||||
var screenNames = []
|
||||
var screens = Quickshell.screens
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
screenNames.push(screens[i].name)
|
||||
screenNames.push(SettingsData.getScreenDisplayName(screens[i]))
|
||||
}
|
||||
return screenNames
|
||||
}
|
||||
onValueChanged: value => {
|
||||
selectedMonitorName = value
|
||||
}
|
||||
var screens = Quickshell.screens
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
if (SettingsData.getScreenDisplayName(screens[i]) === value) {
|
||||
selectedMonitorName = screens[i].name
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
@@ -1027,9 +1041,14 @@ Item {
|
||||
text: I18n.tr("Matugen Target Monitor")
|
||||
description: I18n.tr("Monitor whose wallpaper drives dynamic theming colors")
|
||||
currentValue: {
|
||||
var screens = Quickshell.screens
|
||||
if (!SettingsData.matugenTargetMonitor || SettingsData.matugenTargetMonitor === "") {
|
||||
var screens = Quickshell.screens
|
||||
return screens.length > 0 ? screens[0].name + " (Default)" : "No monitors"
|
||||
return screens.length > 0 ? SettingsData.getScreenDisplayName(screens[0]) + " (Default)" : "No monitors"
|
||||
}
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
if (screens[i].name === SettingsData.matugenTargetMonitor) {
|
||||
return SettingsData.getScreenDisplayName(screens[i])
|
||||
}
|
||||
}
|
||||
return SettingsData.matugenTargetMonitor
|
||||
}
|
||||
@@ -1037,7 +1056,7 @@ Item {
|
||||
var screenNames = []
|
||||
var screens = Quickshell.screens
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
var label = screens[i].name
|
||||
var label = SettingsData.getScreenDisplayName(screens[i])
|
||||
if (i === 0 && (!SettingsData.matugenTargetMonitor || SettingsData.matugenTargetMonitor === "")) {
|
||||
label += " (Default)"
|
||||
}
|
||||
@@ -1046,9 +1065,15 @@ Item {
|
||||
return screenNames
|
||||
}
|
||||
onValueChanged: value => {
|
||||
var cleanValue = value.replace(" (Default)", "")
|
||||
SettingsData.setMatugenTargetMonitor(cleanValue)
|
||||
}
|
||||
var cleanValue = value.replace(" (Default)", "")
|
||||
var screens = Quickshell.screens
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
if (SettingsData.getScreenDisplayName(screens[i]) === cleanValue) {
|
||||
SettingsData.setMatugenTargetMonitor(screens[i].name)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1439,7 +1464,7 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Blur Layer")
|
||||
text: I18n.tr("Duplicate Wallpaper with Blur")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
|
||||
@@ -736,6 +736,70 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
leftPadding: Theme.spacingM
|
||||
rightPadding: Theme.spacingM
|
||||
|
||||
DankDropdown {
|
||||
width: parent.width - parent.leftPadding - parent.rightPadding
|
||||
text: I18n.tr("OSD Position")
|
||||
description: I18n.tr("Choose where on-screen displays appear on screen")
|
||||
currentValue: {
|
||||
switch (SettingsData.osdPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return "Top Right"
|
||||
case SettingsData.Position.Left:
|
||||
return "Top Left"
|
||||
case SettingsData.Position.TopCenter:
|
||||
return "Top Center"
|
||||
case SettingsData.Position.Right:
|
||||
return "Bottom Right"
|
||||
case SettingsData.Position.Bottom:
|
||||
return "Bottom Left"
|
||||
case SettingsData.Position.BottomCenter:
|
||||
return "Bottom Center"
|
||||
case SettingsData.Position.LeftCenter:
|
||||
return "Left Center"
|
||||
case SettingsData.Position.RightCenter:
|
||||
return "Right Center"
|
||||
default:
|
||||
return "Bottom Center"
|
||||
}
|
||||
}
|
||||
options: ["Top Right", "Top Left", "Top Center", "Bottom Right", "Bottom Left", "Bottom Center", "Left Center", "Right Center"]
|
||||
onValueChanged: value => {
|
||||
switch (value) {
|
||||
case "Top Right":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Top)
|
||||
break
|
||||
case "Top Left":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Left)
|
||||
break
|
||||
case "Top Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.TopCenter)
|
||||
break
|
||||
case "Bottom Right":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Right)
|
||||
break
|
||||
case "Bottom Left":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Bottom)
|
||||
break
|
||||
case "Bottom Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.BottomCenter)
|
||||
break
|
||||
case "Left Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.LeftCenter)
|
||||
break
|
||||
case "Right Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.RightCenter)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Volume OSD")
|
||||
|
||||
@@ -35,9 +35,10 @@ DankPopout {
|
||||
triggerWidth: 55
|
||||
positioning: ""
|
||||
screen: triggerScreen
|
||||
visible: shouldBeVisible
|
||||
shouldBeVisible: false
|
||||
|
||||
onBackgroundClicked: close()
|
||||
|
||||
onShouldBeVisibleChanged: {
|
||||
if (shouldBeVisible) {
|
||||
if (SystemUpdateService.updateCount === 0 && !SystemUpdateService.isChecking) {
|
||||
|
||||
@@ -4,7 +4,6 @@ pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import "../Common/fzf.js" as Fzf
|
||||
import qs.Common
|
||||
|
||||
Singleton {
|
||||
@@ -12,7 +11,141 @@ Singleton {
|
||||
|
||||
property var applications: DesktopEntries.applications.values.filter(app => !app.noDisplay && !app.runInTerminal)
|
||||
|
||||
readonly property int maxResults: 10
|
||||
readonly property int frecencySampleSize: 10
|
||||
|
||||
readonly property var timeBuckets: [{
|
||||
"maxDays": 4,
|
||||
"weight": 100
|
||||
}, {
|
||||
"maxDays": 14,
|
||||
"weight": 70
|
||||
}, {
|
||||
"maxDays": 31,
|
||||
"weight": 50
|
||||
}, {
|
||||
"maxDays": 90,
|
||||
"weight": 30
|
||||
}, {
|
||||
"maxDays": 99999,
|
||||
"weight": 10
|
||||
}]
|
||||
|
||||
function tokenize(text) {
|
||||
return text.toLowerCase().trim().split(/[\s\-_]+/).filter(w => w.length > 0)
|
||||
}
|
||||
|
||||
function wordBoundaryMatch(text, query) {
|
||||
const textWords = tokenize(text)
|
||||
const queryWords = tokenize(query)
|
||||
|
||||
if (queryWords.length === 0)
|
||||
return false
|
||||
if (queryWords.length > textWords.length)
|
||||
return false
|
||||
|
||||
for (var i = 0; i <= textWords.length - queryWords.length; i++) {
|
||||
let allMatch = true
|
||||
for (var j = 0; j < queryWords.length; j++) {
|
||||
if (!textWords[i + j].startsWith(queryWords[j])) {
|
||||
allMatch = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if (allMatch)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function levenshteinDistance(s1, s2) {
|
||||
const len1 = s1.length
|
||||
const len2 = s2.length
|
||||
const matrix = []
|
||||
|
||||
for (var i = 0; i <= len1; i++) {
|
||||
matrix[i] = [i]
|
||||
}
|
||||
for (var j = 0; j <= len2; j++) {
|
||||
matrix[0][j] = j
|
||||
}
|
||||
|
||||
for (var i = 1; i <= len1; i++) {
|
||||
for (var j = 1; j <= len2; j++) {
|
||||
const cost = s1[i - 1] === s2[j - 1] ? 0 : 1
|
||||
matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost)
|
||||
}
|
||||
}
|
||||
return matrix[len1][len2]
|
||||
}
|
||||
|
||||
function fuzzyMatchScore(text, query) {
|
||||
const queryLower = query.toLowerCase()
|
||||
const maxDistance = query.length <= 2 ? 0 : query.length === 3 ? 1 : query.length <= 6 ? 2 : 3
|
||||
|
||||
let bestScore = 0
|
||||
|
||||
const distance = levenshteinDistance(text.toLowerCase(), queryLower)
|
||||
if (distance <= maxDistance) {
|
||||
const maxLen = Math.max(text.length, query.length)
|
||||
bestScore = 1 - (distance / maxLen)
|
||||
}
|
||||
|
||||
const words = tokenize(text)
|
||||
for (const word of words) {
|
||||
const wordDistance = levenshteinDistance(word, queryLower)
|
||||
if (wordDistance <= maxDistance) {
|
||||
const maxLen = Math.max(word.length, query.length)
|
||||
const score = 1 - (wordDistance / maxLen)
|
||||
bestScore = Math.max(bestScore, score)
|
||||
}
|
||||
}
|
||||
|
||||
return bestScore
|
||||
}
|
||||
|
||||
function calculateFrecency(app) {
|
||||
const usageRanking = AppUsageHistoryData.appUsageRanking || {}
|
||||
const appId = app.id || (app.execString || app.exec || "")
|
||||
const idVariants = [appId, appId.replace(".desktop", ""), app.id, app.id ? app.id.replace(".desktop", "") : null].filter(id => id)
|
||||
|
||||
let usageData = null
|
||||
for (const variant of idVariants) {
|
||||
if (usageRanking[variant]) {
|
||||
usageData = usageRanking[variant]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!usageData || !usageData.usageCount) {
|
||||
return {
|
||||
"frecency": 0,
|
||||
"daysSinceUsed": 999999
|
||||
}
|
||||
}
|
||||
|
||||
const usageCount = usageData.usageCount || 0
|
||||
const lastUsed = usageData.lastUsed || 0
|
||||
const now = Date.now()
|
||||
const daysSinceUsed = (now - lastUsed) / (1000 * 60 * 60 * 24)
|
||||
|
||||
let timeBucketWeight = 10
|
||||
for (const bucket of timeBuckets) {
|
||||
if (daysSinceUsed <= bucket.maxDays) {
|
||||
timeBucketWeight = bucket.weight
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const contextBonus = 100
|
||||
const sampleSize = Math.min(usageCount, frecencySampleSize)
|
||||
const frecency = (timeBucketWeight * contextBonus * sampleSize) / 100
|
||||
|
||||
return {
|
||||
"frecency": frecency,
|
||||
"daysSinceUsed": daysSinceUsed
|
||||
}
|
||||
}
|
||||
|
||||
function searchApplications(query) {
|
||||
if (!query || query.length === 0) {
|
||||
@@ -23,7 +156,7 @@ Singleton {
|
||||
|
||||
const queryLower = query.toLowerCase().trim()
|
||||
const scoredApps = []
|
||||
const usageRanking = AppUsageHistoryData.appUsageRanking || {}
|
||||
const results = []
|
||||
|
||||
for (const app of applications) {
|
||||
const name = (app.name || "").toLowerCase()
|
||||
@@ -31,123 +164,83 @@ Singleton {
|
||||
const comment = (app.comment || "").toLowerCase()
|
||||
const keywords = app.keywords ? app.keywords.map(k => k.toLowerCase()) : []
|
||||
|
||||
let score = 0
|
||||
let matched = false
|
||||
|
||||
const nameWords = name.trim().split(/\s+/).filter(w => w.length > 0)
|
||||
const containsAsWord = nameWords.includes(queryLower)
|
||||
const startsWithAsWord = nameWords.some(word => word.startsWith(queryLower))
|
||||
let textScore = 0
|
||||
let matchType = "none"
|
||||
|
||||
if (name === queryLower) {
|
||||
score = 10000
|
||||
matched = true
|
||||
} else if (containsAsWord) {
|
||||
score = 9500 + (100 - Math.min(name.length, 100))
|
||||
matched = true
|
||||
textScore = 10000
|
||||
matchType = "exact"
|
||||
} else if (name.startsWith(queryLower)) {
|
||||
score = 9000 + (100 - Math.min(name.length, 100))
|
||||
matched = true
|
||||
} else if (startsWithAsWord) {
|
||||
score = 8500 + (100 - Math.min(name.length, 100))
|
||||
matched = true
|
||||
textScore = 5000
|
||||
matchType = "prefix"
|
||||
} else if (wordBoundaryMatch(name, queryLower)) {
|
||||
textScore = 1000
|
||||
matchType = "word_boundary"
|
||||
} else if (name.includes(queryLower)) {
|
||||
score = 8000 + (100 - Math.min(name.length, 100))
|
||||
matched = true
|
||||
} else if (keywords.length > 0) {
|
||||
textScore = 500
|
||||
matchType = "substring"
|
||||
} else if (genericName && genericName.startsWith(queryLower)) {
|
||||
textScore = 800
|
||||
matchType = "generic_prefix"
|
||||
} else if (genericName && genericName.includes(queryLower)) {
|
||||
textScore = 400
|
||||
matchType = "generic"
|
||||
}
|
||||
|
||||
if (matchType === "none" && keywords.length > 0) {
|
||||
for (const keyword of keywords) {
|
||||
if (keyword === queryLower) {
|
||||
score = 6000
|
||||
matched = true
|
||||
break
|
||||
} else if (keyword.startsWith(queryLower)) {
|
||||
score = 5500
|
||||
matched = true
|
||||
if (keyword.startsWith(queryLower)) {
|
||||
textScore = 300
|
||||
matchType = "keyword_prefix"
|
||||
break
|
||||
} else if (keyword.includes(queryLower)) {
|
||||
score = 5000
|
||||
matched = true
|
||||
textScore = 150
|
||||
matchType = "keyword"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!matched && genericName.includes(queryLower)) {
|
||||
if (genericName === queryLower) {
|
||||
score = 9000
|
||||
} else if (genericName.startsWith(queryLower)) {
|
||||
score = 8500
|
||||
} else {
|
||||
const genericWords = genericName.trim().split(/\s+/).filter(w => w.length > 0)
|
||||
if (genericWords.includes(queryLower)) {
|
||||
score = 8000
|
||||
} else if (genericWords.some(word => word.startsWith(queryLower))) {
|
||||
score = 7500
|
||||
} else {
|
||||
score = 7000
|
||||
}
|
||||
}
|
||||
matched = true
|
||||
} else if (!matched && comment.includes(queryLower)) {
|
||||
score = 3000
|
||||
matched = true
|
||||
} else if (!matched) {
|
||||
const nameFinder = new Fzf.Finder([app], {
|
||||
"selector": a => a.name || "",
|
||||
"casing": "case-insensitive",
|
||||
"fuzzy": "v2"
|
||||
})
|
||||
const fuzzyResults = nameFinder.find(query)
|
||||
if (fuzzyResults.length > 0 && fuzzyResults[0].score > 0) {
|
||||
score = Math.min(fuzzyResults[0].score, 2000)
|
||||
matched = true
|
||||
|
||||
if (matchType === "none" && comment && comment.includes(queryLower)) {
|
||||
textScore = 50
|
||||
matchType = "comment"
|
||||
}
|
||||
|
||||
if (matchType === "none") {
|
||||
const fuzzyScore = fuzzyMatchScore(name, queryLower)
|
||||
if (fuzzyScore > 0) {
|
||||
textScore = fuzzyScore * 100
|
||||
matchType = "fuzzy"
|
||||
}
|
||||
}
|
||||
|
||||
if (matched) {
|
||||
const appId = app.id || (app.execString || app.exec || "")
|
||||
const idVariants = [
|
||||
appId,
|
||||
appId.replace(".desktop", ""),
|
||||
app.id,
|
||||
app.id ? app.id.replace(".desktop", "") : null
|
||||
].filter(id => id)
|
||||
if (matchType !== "none") {
|
||||
const frecencyData = calculateFrecency(app)
|
||||
|
||||
let usageData = null
|
||||
for (const variant of idVariants) {
|
||||
if (usageRanking[variant]) {
|
||||
usageData = usageRanking[variant]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (usageData) {
|
||||
const usageCount = usageData.usageCount || 0
|
||||
const lastUsed = usageData.lastUsed || 0
|
||||
const now = Date.now()
|
||||
const daysSinceUsed = (now - lastUsed) / (1000 * 60 * 60 * 24)
|
||||
|
||||
let usageBonus = 0
|
||||
usageBonus += Math.min(usageCount * 100, 2000)
|
||||
|
||||
if (daysSinceUsed < 1) {
|
||||
usageBonus += 1500
|
||||
} else if (daysSinceUsed < 7) {
|
||||
usageBonus += 1000
|
||||
} else if (daysSinceUsed < 30) {
|
||||
usageBonus += 500
|
||||
}
|
||||
|
||||
score += usageBonus
|
||||
}
|
||||
|
||||
scoredApps.push({
|
||||
"app": app,
|
||||
"score": score
|
||||
})
|
||||
results.push({
|
||||
"app": app,
|
||||
"textScore": textScore,
|
||||
"frecency": frecencyData.frecency,
|
||||
"daysSinceUsed": frecencyData.daysSinceUsed,
|
||||
"matchType": matchType
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for (const result of results) {
|
||||
const frecencyBonus = result.frecency > 0 ? Math.min(result.frecency / 10, 2000) : 0
|
||||
const recencyBonus = result.daysSinceUsed < 1 ? 1500 : result.daysSinceUsed < 7 ? 1000 : result.daysSinceUsed < 30 ? 500 : 0
|
||||
|
||||
const finalScore = result.textScore + frecencyBonus + recencyBonus
|
||||
|
||||
scoredApps.push({
|
||||
"app": result.app,
|
||||
"score": finalScore
|
||||
})
|
||||
}
|
||||
|
||||
scoredApps.sort((a, b) => b.score - a.score)
|
||||
return scoredApps.slice(0, 50).map(item => item.app)
|
||||
return scoredApps.slice(0, maxResults).map(item => item.app)
|
||||
}
|
||||
|
||||
function getCategoriesForApp(app) {
|
||||
@@ -265,7 +358,8 @@ Singleton {
|
||||
}
|
||||
|
||||
function getPluginCategoryIcon(category) {
|
||||
if (typeof PluginService === "undefined") return null
|
||||
if (typeof PluginService === "undefined")
|
||||
return null
|
||||
|
||||
const launchers = PluginService.getLauncherPlugins()
|
||||
for (const pluginId in launchers) {
|
||||
@@ -295,7 +389,8 @@ Singleton {
|
||||
}
|
||||
|
||||
function getPluginItems(category, query) {
|
||||
if (typeof PluginService === "undefined") return []
|
||||
if (typeof PluginService === "undefined")
|
||||
return []
|
||||
|
||||
const launchers = PluginService.getLauncherPlugins()
|
||||
for (const pluginId in launchers) {
|
||||
@@ -313,12 +408,13 @@ Singleton {
|
||||
}
|
||||
|
||||
const component = PluginService.pluginLauncherComponents[pluginId]
|
||||
if (!component) return []
|
||||
if (!component)
|
||||
return []
|
||||
|
||||
try {
|
||||
const instance = component.createObject(root, {
|
||||
"pluginService": PluginService
|
||||
})
|
||||
"pluginService": PluginService
|
||||
})
|
||||
|
||||
if (instance && typeof instance.getItems === "function") {
|
||||
const items = instance.getItems(query || "")
|
||||
@@ -337,15 +433,17 @@ Singleton {
|
||||
}
|
||||
|
||||
function executePluginItem(item, pluginId) {
|
||||
if (typeof PluginService === "undefined") return false
|
||||
if (typeof PluginService === "undefined")
|
||||
return false
|
||||
|
||||
const component = PluginService.pluginLauncherComponents[pluginId]
|
||||
if (!component) return false
|
||||
if (!component)
|
||||
return false
|
||||
|
||||
try {
|
||||
const instance = component.createObject(root, {
|
||||
"pluginService": PluginService
|
||||
})
|
||||
"pluginService": PluginService
|
||||
})
|
||||
|
||||
if (instance && typeof instance.executeItem === "function") {
|
||||
instance.executeItem(item)
|
||||
@@ -364,7 +462,8 @@ Singleton {
|
||||
}
|
||||
|
||||
function searchPluginItems(query) {
|
||||
if (typeof PluginService === "undefined") return []
|
||||
if (typeof PluginService === "undefined")
|
||||
return []
|
||||
|
||||
let allItems = []
|
||||
const launchers = PluginService.getLauncherPlugins()
|
||||
|
||||
@@ -49,20 +49,20 @@ Singleton {
|
||||
return devices.sort((a, b) => {
|
||||
const aName = a.name || a.deviceName || ""
|
||||
const bName = b.name || b.deviceName || ""
|
||||
const aAddr = a.address || ""
|
||||
const bAddr = b.address || ""
|
||||
|
||||
const aHasRealName = aName.includes(" ") && aName.length > 3
|
||||
const bHasRealName = bName.includes(" ") && bName.length > 3
|
||||
|
||||
if (aHasRealName && !bHasRealName) {
|
||||
return -1
|
||||
}
|
||||
if (!aHasRealName && bHasRealName) {
|
||||
return 1
|
||||
if (aHasRealName && !bHasRealName) return -1
|
||||
if (!aHasRealName && bHasRealName) return 1
|
||||
|
||||
if (aHasRealName && bHasRealName) {
|
||||
return aName.localeCompare(bName)
|
||||
}
|
||||
|
||||
const aSignal = (a.signalStrength !== undefined && a.signalStrength > 0) ? a.signalStrength : 0
|
||||
const bSignal = (b.signalStrength !== undefined && b.signalStrength > 0) ? b.signalStrength : 0
|
||||
return bSignal - aSignal
|
||||
return aAddr.localeCompare(bAddr)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ Singleton {
|
||||
if (WlrOutputService.wlrOutputAvailable && screen) {
|
||||
const wlrOutput = WlrOutputService.getOutput(screen.name)
|
||||
if (wlrOutput?.enabled && wlrOutput.scale !== undefined && wlrOutput.scale > 0) {
|
||||
return wlrOutput.scale
|
||||
return Math.round(wlrOutput.scale * 20) / 20
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,6 +441,7 @@ Singleton {
|
||||
if (isHyprland) return Hyprland.dispatch("dpms off")
|
||||
if (isDwl) return _dwlPowerOffMonitors()
|
||||
if (isSway) { try { I3.dispatch("output * dpms off") } catch(_){} return }
|
||||
if (isLabwc) { Quickshell.execDetached(["dms", "dpms", "off"]) }
|
||||
console.warn("CompositorService: Cannot power off monitors, unknown compositor")
|
||||
}
|
||||
|
||||
@@ -449,6 +450,7 @@ Singleton {
|
||||
if (isHyprland) return Hyprland.dispatch("dpms on")
|
||||
if (isDwl) return _dwlPowerOnMonitors()
|
||||
if (isSway) { try { I3.dispatch("output * dpms on") } catch(_){} return }
|
||||
if (isLabwc) { Quickshell.execDetached(["dms", "dpms", "on"]) }
|
||||
console.warn("CompositorService: Cannot power on monitors, unknown compositor")
|
||||
}
|
||||
|
||||
|
||||
@@ -78,10 +78,15 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
const oldValue = deviceBrightness[device.id]
|
||||
const newBrightness = Object.assign({}, deviceBrightness)
|
||||
newBrightness[device.id] = displayValue
|
||||
deviceBrightness = newBrightness
|
||||
brightnessVersion++
|
||||
|
||||
if (oldValue !== undefined && oldValue !== displayValue && brightnessInitialized) {
|
||||
brightnessChanged(true)
|
||||
}
|
||||
}
|
||||
|
||||
function updateFromBrightnessState(state) {
|
||||
@@ -110,9 +115,12 @@ Singleton {
|
||||
deviceMaxCache = newMaxCache
|
||||
|
||||
const newBrightness = {}
|
||||
let anyDeviceBrightnessChanged = false
|
||||
|
||||
for (const device of state.devices) {
|
||||
const isExponential = SessionData.getBrightnessExponential(device.id)
|
||||
const userSetValue = deviceBrightnessUserSet[device.id]
|
||||
const oldValue = deviceBrightness[device.id]
|
||||
|
||||
if (isExponential) {
|
||||
if (userSetValue !== undefined) {
|
||||
@@ -123,6 +131,11 @@ Singleton {
|
||||
} else {
|
||||
newBrightness[device.id] = device.currentPercent
|
||||
}
|
||||
|
||||
const newValue = newBrightness[device.id]
|
||||
if (oldValue !== undefined && oldValue !== newValue) {
|
||||
anyDeviceBrightnessChanged = true
|
||||
}
|
||||
}
|
||||
deviceBrightness = newBrightness
|
||||
brightnessVersion++
|
||||
@@ -142,9 +155,15 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
const shouldShowOsd = brightnessInitialized && anyDeviceBrightnessChanged
|
||||
|
||||
if (!brightnessInitialized) {
|
||||
brightnessInitialized = true
|
||||
}
|
||||
|
||||
if (shouldShowOsd) {
|
||||
brightnessChanged(true)
|
||||
}
|
||||
}
|
||||
|
||||
function setBrightness(percentage, device, suppressOsd) {
|
||||
|
||||
@@ -14,6 +14,11 @@ Singleton {
|
||||
property var layouts: []
|
||||
property string activeOutput: ""
|
||||
property var outputScales: ({})
|
||||
property string currentKeyboardLayout: {
|
||||
if (!outputs || !activeOutput) return ""
|
||||
const output = outputs[activeOutput]
|
||||
return (output && output.kbLayout) || ""
|
||||
}
|
||||
|
||||
signal stateChanged()
|
||||
|
||||
|
||||
@@ -46,8 +46,17 @@ Singleton {
|
||||
|
||||
const hasExtWorkspace = DMSService.capabilities.includes("extworkspace")
|
||||
if (hasExtWorkspace && !extWorkspaceAvailable) {
|
||||
if (typeof CompositorService !== "undefined") {
|
||||
const useExtWorkspace = DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway)
|
||||
if (!useExtWorkspace) {
|
||||
console.info("ExtWorkspaceService: ext-workspace available but compositor has native support")
|
||||
extWorkspaceAvailable = false
|
||||
return
|
||||
}
|
||||
}
|
||||
extWorkspaceAvailable = true
|
||||
console.info("ExtWorkspaceService: ext-workspace capability detected")
|
||||
DMSService.addSubscription("extworkspace")
|
||||
requestState()
|
||||
} else if (!hasExtWorkspace) {
|
||||
extWorkspaceAvailable = false
|
||||
@@ -181,12 +190,17 @@ Singleton {
|
||||
|
||||
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]
|
||||
})
|
||||
let visible = workspaces.filter(ws => !ws.hidden)
|
||||
|
||||
const hasValidCoordinates = visible.some(ws => ws.coordinates && ws.coordinates.length > 0)
|
||||
if (hasValidCoordinates) {
|
||||
visible = visible.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]) {
|
||||
|
||||
@@ -23,6 +23,7 @@ Singleton {
|
||||
property var colorPickerModal: null
|
||||
property var notificationModal: null
|
||||
property var wifiPasswordModal: null
|
||||
property var bluetoothPairingModal: null
|
||||
property var networkInfoModal: null
|
||||
|
||||
property var notepadSlideouts: []
|
||||
|
||||
@@ -137,21 +137,42 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
// * Apps
|
||||
function escapeShellArg(arg) {
|
||||
return "'" + arg.replace(/'/g, "'\\''") + "'"
|
||||
}
|
||||
|
||||
function needsShellExecution(prefix) {
|
||||
if (!prefix || prefix.length === 0) return false
|
||||
return /[;&|<>()$`\\"']/.test(prefix)
|
||||
}
|
||||
|
||||
function launchDesktopEntry(desktopEntry, usePrimeRun) {
|
||||
let cmd = desktopEntry.command
|
||||
if (usePrimeRun && hasPrimeRun) {
|
||||
cmd = ["prime-run"].concat(cmd)
|
||||
}
|
||||
if (SettingsData.launchPrefix && SettingsData.launchPrefix.length > 0) {
|
||||
const launchPrefix = SettingsData.launchPrefix.trim().split(" ")
|
||||
cmd = launchPrefix.concat(cmd)
|
||||
}
|
||||
|
||||
Quickshell.execDetached({
|
||||
command: cmd,
|
||||
workingDirectory: desktopEntry.workingDirectory || Quickshell.env("HOME"),
|
||||
});
|
||||
const prefix = SettingsData.launchPrefix?.trim() || ""
|
||||
|
||||
if (prefix.length > 0 && needsShellExecution(prefix)) {
|
||||
const escapedCmd = cmd.map(arg => escapeShellArg(arg)).join(" ")
|
||||
const shellCmd = `${prefix} ${escapedCmd}`
|
||||
|
||||
Quickshell.execDetached({
|
||||
command: ["sh", "-c", shellCmd],
|
||||
workingDirectory: desktopEntry.workingDirectory || Quickshell.env("HOME"),
|
||||
})
|
||||
} else {
|
||||
if (prefix.length > 0) {
|
||||
const launchPrefix = prefix.split(" ")
|
||||
cmd = launchPrefix.concat(cmd)
|
||||
}
|
||||
|
||||
Quickshell.execDetached({
|
||||
command: cmd,
|
||||
workingDirectory: desktopEntry.workingDirectory || Quickshell.env("HOME"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function launchDesktopAction(desktopEntry, action, usePrimeRun) {
|
||||
@@ -159,15 +180,28 @@ Singleton {
|
||||
if (usePrimeRun && hasPrimeRun) {
|
||||
cmd = ["prime-run"].concat(cmd)
|
||||
}
|
||||
if (SettingsData.launchPrefix && SettingsData.launchPrefix.length > 0) {
|
||||
const launchPrefix = SettingsData.launchPrefix.trim().split(" ")
|
||||
cmd = launchPrefix.concat(cmd)
|
||||
}
|
||||
|
||||
Quickshell.execDetached({
|
||||
command: cmd,
|
||||
workingDirectory: desktopEntry.workingDirectory || Quickshell.env("HOME"),
|
||||
});
|
||||
const prefix = SettingsData.launchPrefix?.trim() || ""
|
||||
|
||||
if (prefix.length > 0 && needsShellExecution(prefix)) {
|
||||
const escapedCmd = cmd.map(arg => escapeShellArg(arg)).join(" ")
|
||||
const shellCmd = `${prefix} ${escapedCmd}`
|
||||
|
||||
Quickshell.execDetached({
|
||||
command: ["sh", "-c", shellCmd],
|
||||
workingDirectory: desktopEntry.workingDirectory || Quickshell.env("HOME"),
|
||||
})
|
||||
} else {
|
||||
if (prefix.length > 0) {
|
||||
const launchPrefix = prefix.split(" ")
|
||||
cmd = launchPrefix.concat(cmd)
|
||||
}
|
||||
|
||||
Quickshell.execDetached({
|
||||
command: cmd,
|
||||
workingDirectory: desktopEntry.workingDirectory || Quickshell.env("HOME"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// * Session management
|
||||
|
||||
@@ -1 +1 @@
|
||||
v0.5.2
|
||||
v0.6.0
|
||||
|
||||
@@ -74,16 +74,83 @@ PanelWindow {
|
||||
readonly property real screenHeight: screen.height
|
||||
readonly property real alignedWidth: Theme.px(osdWidth, dpr)
|
||||
readonly property real alignedHeight: Theme.px(osdHeight, dpr)
|
||||
readonly property real alignedX: Theme.snap((screenWidth - alignedWidth) / 2, dpr)
|
||||
readonly property real barOffsetWhenBottom: {
|
||||
if (SettingsData.dankBarPosition === SettingsData.Position.Bottom && SettingsData.dankBarVisible) {
|
||||
const widgetThickness = Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
|
||||
const effectiveBarThickness = Math.max(widgetThickness + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
|
||||
return effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
|
||||
}
|
||||
return 0
|
||||
|
||||
readonly property bool isVerticalLayout: SettingsData.osdPosition === SettingsData.Position.LeftCenter || SettingsData.osdPosition === SettingsData.Position.RightCenter
|
||||
|
||||
readonly property real barThickness: {
|
||||
if (!SettingsData.dankBarVisible) return 0
|
||||
const widgetThickness = Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
|
||||
return Math.max(widgetThickness + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
|
||||
}
|
||||
|
||||
readonly property real barOffset: {
|
||||
if (!SettingsData.dankBarVisible) return 0
|
||||
return barThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
|
||||
}
|
||||
|
||||
readonly property real dockThickness: {
|
||||
if (!SettingsData.showDock) return 0
|
||||
return SettingsData.dockIconSize + SettingsData.dockSpacing * 2 + 10
|
||||
}
|
||||
|
||||
readonly property real dockOffset: {
|
||||
if (!SettingsData.showDock || SettingsData.dockAutoHide) return 0
|
||||
return dockThickness + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin
|
||||
}
|
||||
|
||||
readonly property real alignedX: {
|
||||
const margin = Theme.spacingM
|
||||
const centerX = (screenWidth - alignedWidth) / 2
|
||||
|
||||
switch (SettingsData.osdPosition) {
|
||||
case SettingsData.Position.Left:
|
||||
case SettingsData.Position.Bottom:
|
||||
const leftBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Left ? barOffset : 0
|
||||
const leftDockOffset = SettingsData.dockPosition === SettingsData.Position.Left ? dockOffset : 0
|
||||
return Theme.snap(margin + Math.max(leftBarOffset, leftDockOffset), dpr)
|
||||
case SettingsData.Position.Top:
|
||||
case SettingsData.Position.Right:
|
||||
const rightBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Right ? barOffset : 0
|
||||
const rightDockOffset = SettingsData.dockPosition === SettingsData.Position.Right ? dockOffset : 0
|
||||
return Theme.snap(screenWidth - alignedWidth - margin - Math.max(rightBarOffset, rightDockOffset), dpr)
|
||||
case SettingsData.Position.LeftCenter:
|
||||
const leftCenterBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Left ? barOffset : 0
|
||||
const leftCenterDockOffset = SettingsData.dockPosition === SettingsData.Position.Left ? dockOffset : 0
|
||||
return Theme.snap(margin + Math.max(leftCenterBarOffset, leftCenterDockOffset), dpr)
|
||||
case SettingsData.Position.RightCenter:
|
||||
const rightCenterBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Right ? barOffset : 0
|
||||
const rightCenterDockOffset = SettingsData.dockPosition === SettingsData.Position.Right ? dockOffset : 0
|
||||
return Theme.snap(screenWidth - alignedWidth - margin - Math.max(rightCenterBarOffset, rightCenterDockOffset), dpr)
|
||||
case SettingsData.Position.TopCenter:
|
||||
case SettingsData.Position.BottomCenter:
|
||||
default:
|
||||
return Theme.snap(centerX, dpr)
|
||||
}
|
||||
}
|
||||
|
||||
readonly property real alignedY: {
|
||||
const margin = Theme.spacingM
|
||||
const centerY = (screenHeight - alignedHeight) / 2
|
||||
|
||||
switch (SettingsData.osdPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
case SettingsData.Position.Left:
|
||||
case SettingsData.Position.TopCenter:
|
||||
const topBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Top ? barOffset : 0
|
||||
const topDockOffset = SettingsData.dockPosition === SettingsData.Position.Top ? dockOffset : 0
|
||||
return Theme.snap(margin + Math.max(topBarOffset, topDockOffset), dpr)
|
||||
case SettingsData.Position.Right:
|
||||
case SettingsData.Position.Bottom:
|
||||
case SettingsData.Position.BottomCenter:
|
||||
const bottomBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Bottom ? barOffset : 0
|
||||
const bottomDockOffset = SettingsData.dockPosition === SettingsData.Position.Bottom ? dockOffset : 0
|
||||
return Theme.snap(screenHeight - alignedHeight - margin - Math.max(bottomBarOffset, bottomDockOffset), dpr)
|
||||
case SettingsData.Position.LeftCenter:
|
||||
case SettingsData.Position.RightCenter:
|
||||
default:
|
||||
return Theme.snap(centerY, dpr)
|
||||
}
|
||||
}
|
||||
readonly property real alignedY: Theme.snap(screenHeight - alignedHeight - Theme.spacingM - barOffsetWhenBottom, dpr)
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
|
||||
@@ -28,7 +28,23 @@ PanelWindow {
|
||||
property list<real> animationEnterCurve: Theme.expressiveCurves.expressiveDefaultSpatial
|
||||
property list<real> animationExitCurve: Theme.expressiveCurves.emphasized
|
||||
property bool shouldBeVisible: false
|
||||
property int keyboardFocusMode: WlrKeyboardFocus.OnDemand
|
||||
|
||||
visible: false
|
||||
|
||||
readonly property real effectiveBarThickness: Math.max(26 + SettingsData.dankBarInnerPadding * 0.6, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing
|
||||
|
||||
readonly property var barBounds: {
|
||||
if (!root.screen) {
|
||||
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
|
||||
}
|
||||
return SettingsData.getBarBounds(root.screen, effectiveBarThickness)
|
||||
}
|
||||
|
||||
readonly property real barX: barBounds.x
|
||||
readonly property real barY: barBounds.y
|
||||
readonly property real barWidth: barBounds.width
|
||||
readonly property real barHeight: barBounds.height
|
||||
readonly property real barWingSize: barBounds.wingSize
|
||||
|
||||
signal opened
|
||||
signal popoutClosed
|
||||
@@ -38,6 +54,7 @@ PanelWindow {
|
||||
closeTimer.stop()
|
||||
shouldBeVisible = true
|
||||
visible = true
|
||||
PopoutManager.showPopout(root)
|
||||
opened()
|
||||
}
|
||||
|
||||
@@ -59,6 +76,7 @@ PanelWindow {
|
||||
onTriggered: {
|
||||
if (!shouldBeVisible) {
|
||||
visible = false
|
||||
PopoutManager.hidePopout(root)
|
||||
popoutClosed()
|
||||
}
|
||||
}
|
||||
@@ -78,7 +96,11 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: shouldBeVisible ? keyboardFocusMode : WlrKeyboardFocus.None
|
||||
WlrLayershell.keyboardFocus: {
|
||||
if (!shouldBeVisible) return WlrKeyboardFocus.None
|
||||
if (CompositorService.isHyprland) return WlrKeyboardFocus.OnDemand
|
||||
return WlrKeyboardFocus.Exclusive
|
||||
}
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
@@ -114,16 +136,82 @@ PanelWindow {
|
||||
}
|
||||
})(), dpr)
|
||||
|
||||
readonly property real maskX: {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Left:
|
||||
return root.barWidth > 0 ? root.barWidth : 0
|
||||
case SettingsData.Position.Right:
|
||||
case SettingsData.Position.Top:
|
||||
case SettingsData.Position.Bottom:
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
readonly property real maskY: {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return root.barHeight > 0 ? root.barHeight : 0
|
||||
case SettingsData.Position.Bottom:
|
||||
case SettingsData.Position.Left:
|
||||
case SettingsData.Position.Right:
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
readonly property real maskWidth: {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Left:
|
||||
return root.barWidth > 0 ? root.width - root.barWidth : root.width
|
||||
case SettingsData.Position.Right:
|
||||
return root.barWidth > 0 ? root.width - root.barWidth : root.width
|
||||
case SettingsData.Position.Top:
|
||||
case SettingsData.Position.Bottom:
|
||||
default:
|
||||
return root.width
|
||||
}
|
||||
}
|
||||
|
||||
readonly property real maskHeight: {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return root.barHeight > 0 ? root.height - root.barHeight : root.height
|
||||
case SettingsData.Position.Bottom:
|
||||
return root.barHeight > 0 ? root.height - root.barHeight : root.height
|
||||
case SettingsData.Position.Left:
|
||||
case SettingsData.Position.Right:
|
||||
default:
|
||||
return root.height
|
||||
}
|
||||
}
|
||||
|
||||
mask: Region {
|
||||
item: Rectangle {
|
||||
x: root.maskX
|
||||
y: root.maskY
|
||||
width: root.maskWidth
|
||||
height: root.maskHeight
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: shouldBeVisible && contentLoader.opacity > 0.1
|
||||
x: maskX
|
||||
y: maskY
|
||||
width: maskWidth
|
||||
height: maskHeight
|
||||
z: -1
|
||||
enabled: shouldBeVisible
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
onClicked: mouse => {
|
||||
if (mouse.x < alignedX || mouse.x > alignedX + alignedWidth ||
|
||||
mouse.y < alignedY || mouse.y > alignedY + alignedHeight) {
|
||||
backgroundClicked()
|
||||
close()
|
||||
}
|
||||
const clickX = mouse.x + maskX
|
||||
const clickY = mouse.y + maskY
|
||||
const outsideContent = clickX < alignedX || clickX > alignedX + alignedWidth ||
|
||||
clickY < alignedY || clickY > alignedY + alignedHeight
|
||||
|
||||
if (!outsideContent) return
|
||||
|
||||
backgroundClicked()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,6 +341,7 @@ PanelWindow {
|
||||
}
|
||||
|
||||
Item {
|
||||
id: focusHelper
|
||||
parent: contentContainer
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
@@ -262,7 +351,5 @@ PanelWindow {
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
Component.onCompleted: forceActiveFocus()
|
||||
onVisibleChanged: if (visible) forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ Text {
|
||||
wrapMode: Text.WordWrap
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
antialiasing: true
|
||||
//renderType: Text.NativeRendering
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -57,7 +57,7 @@
|
||||
"Add a VPN in NetworkManager": "Aggiungi una VPN in NetworkManager"
|
||||
},
|
||||
"Adjust the number of columns in grid view mode.": {
|
||||
"Adjust the number of columns in grid view mode.": ""
|
||||
"Adjust the number of columns in grid view mode.": "Regola il numero di colonne nella modalità di visualizzazione a griglia."
|
||||
},
|
||||
"All": {
|
||||
"All": "Tutto"
|
||||
@@ -275,6 +275,9 @@
|
||||
"Brightness": {
|
||||
"Brightness": "Luminosità"
|
||||
},
|
||||
"Brightness OSD": {
|
||||
"Brightness OSD": ""
|
||||
},
|
||||
"Browse": {
|
||||
"Browse": "Sfoglia"
|
||||
},
|
||||
@@ -303,7 +306,7 @@
|
||||
"CUPS Missing Filter Warning": "Avviso Filtro Mancante CUPS"
|
||||
},
|
||||
"Camera": {
|
||||
"Camera": ""
|
||||
"Camera": "Fotocamera"
|
||||
},
|
||||
"Cancel": {
|
||||
"Cancel": "Annulla"
|
||||
@@ -314,6 +317,9 @@
|
||||
"Caps Lock Indicator": {
|
||||
"Caps Lock Indicator": "Indicatore Maiuscolo"
|
||||
},
|
||||
"Caps Lock OSD": {
|
||||
"Caps Lock OSD": ""
|
||||
},
|
||||
"Center Section": {
|
||||
"Center Section": "Sezione Centrale"
|
||||
},
|
||||
@@ -341,6 +347,9 @@
|
||||
"Choose where notification popups appear on screen": {
|
||||
"Choose where notification popups appear on screen": "Scegli dove i popup delle notifiche appaiono sullo schermo"
|
||||
},
|
||||
"Choose where on-screen displays appear on screen": {
|
||||
"Choose where on-screen displays appear on screen": ""
|
||||
},
|
||||
"Clear": {
|
||||
"Clear": "Pulisci"
|
||||
},
|
||||
@@ -617,6 +626,9 @@
|
||||
"Dismiss": {
|
||||
"Dismiss": "Dismetti"
|
||||
},
|
||||
"Display Name Format": {
|
||||
"Display Name Format": ""
|
||||
},
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": {
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": "Visualizza una dock con applicazioni pinnate ed in esecuzione che possono essere posizionate nell'angolo superiore, inferiore, sinistro o destro dello schermo"
|
||||
},
|
||||
@@ -674,6 +686,9 @@
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": {
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Trascina i widget per riordinarli nelle sezioni. Usa l'icona occhio per nascondere/mostrare i widget (mantenendo la spaziatura), o X per rimuoverli completamente."
|
||||
},
|
||||
"Duplicate Wallpaper with Blur": {
|
||||
"Duplicate Wallpaper with Blur": "Duplica Sfondo con Sfocatura"
|
||||
},
|
||||
"Duration": {
|
||||
"Duration": "Durata"
|
||||
},
|
||||
@@ -749,6 +764,9 @@
|
||||
"Enter password for ": {
|
||||
"Enter password for ": "Inserisci password per"
|
||||
},
|
||||
"Enter this passkey on ": {
|
||||
"Enter this passkey on ": ""
|
||||
},
|
||||
"Error": {
|
||||
"Error": "Errore"
|
||||
},
|
||||
@@ -900,7 +918,7 @@
|
||||
"Grid": "Griglia"
|
||||
},
|
||||
"Grid Columns": {
|
||||
"Grid Columns": ""
|
||||
"Grid Columns": "Colonne Griglia"
|
||||
},
|
||||
"Group by App": {
|
||||
"Group by App": "Raggruppa per App"
|
||||
@@ -959,6 +977,9 @@
|
||||
"Idle Inhibitor": {
|
||||
"Idle Inhibitor": "Inibitore Riposo"
|
||||
},
|
||||
"Idle Inhibitor OSD": {
|
||||
"Idle Inhibitor OSD": ""
|
||||
},
|
||||
"Idle Settings": {
|
||||
"Idle Settings": "Impostazioni Riposo"
|
||||
},
|
||||
@@ -1173,7 +1194,10 @@
|
||||
"Memory usage indicator": "Indicatore uso memoria"
|
||||
},
|
||||
"Microphone": {
|
||||
"Microphone": ""
|
||||
"Microphone": "Microfono"
|
||||
},
|
||||
"Microphone Mute OSD": {
|
||||
"Microphone Mute OSD": ""
|
||||
},
|
||||
"Minimal palette built around a single hue.": {
|
||||
"Minimal palette built around a single hue.": "Tavolozza minima costruita attorno a una singola tonalità."
|
||||
@@ -1187,6 +1211,9 @@
|
||||
"Mode: ": {
|
||||
"Mode: ": "Modalità:"
|
||||
},
|
||||
"Model": {
|
||||
"Model": "Modello"
|
||||
},
|
||||
"Monitor Selection:": {
|
||||
"Monitor Selection:": "Selezione Monitor:"
|
||||
},
|
||||
@@ -1211,6 +1238,9 @@
|
||||
"NM not supported": {
|
||||
"NM not supported": "NM non supportato"
|
||||
},
|
||||
"Name": {
|
||||
"Name": "Nome"
|
||||
},
|
||||
"Named Workspace Icons": {
|
||||
"Named Workspace Icons": "Icone Workspace con Nome"
|
||||
},
|
||||
@@ -1337,6 +1367,9 @@
|
||||
"OS Logo": {
|
||||
"OS Logo": "Logo OS"
|
||||
},
|
||||
"OSD Position": {
|
||||
"OSD Position": ""
|
||||
},
|
||||
"Office": {
|
||||
"Office": "Ufficio"
|
||||
},
|
||||
@@ -1346,6 +1379,9 @@
|
||||
"On-Screen Displays": {
|
||||
"On-Screen Displays": "Visualizzazione A Schermo"
|
||||
},
|
||||
"On-screen Displays": {
|
||||
"On-screen Displays": ""
|
||||
},
|
||||
"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."
|
||||
},
|
||||
@@ -1493,6 +1529,9 @@
|
||||
"Power Profile Degradation": {
|
||||
"Power Profile Degradation": "Degradamento profilo energetico"
|
||||
},
|
||||
"Power Profile OSD": {
|
||||
"Power Profile OSD": ""
|
||||
},
|
||||
"Pressure": {
|
||||
"Pressure": "Pressione"
|
||||
},
|
||||
@@ -1647,7 +1686,7 @@
|
||||
"Science": "Scienza"
|
||||
},
|
||||
"Screen sharing": {
|
||||
"Screen sharing": ""
|
||||
"Screen sharing": "Condivisione schermo"
|
||||
},
|
||||
"Scrolling": {
|
||||
"Scrolling": "Scorrimento"
|
||||
@@ -1781,6 +1820,24 @@
|
||||
"Show on screens:": {
|
||||
"Show on screens:": "Mostra sullo schermo:"
|
||||
},
|
||||
"Show on-screen display when brightness changes": {
|
||||
"Show on-screen display when brightness changes": ""
|
||||
},
|
||||
"Show on-screen display when caps lock state changes": {
|
||||
"Show on-screen display when caps lock state changes": ""
|
||||
},
|
||||
"Show on-screen display when idle inhibitor state changes": {
|
||||
"Show on-screen display when idle inhibitor state changes": ""
|
||||
},
|
||||
"Show on-screen display when microphone is muted/unmuted": {
|
||||
"Show on-screen display when microphone is muted/unmuted": ""
|
||||
},
|
||||
"Show on-screen display when power profile changes": {
|
||||
"Show on-screen display when power profile changes": ""
|
||||
},
|
||||
"Show on-screen display when volume changes": {
|
||||
"Show on-screen display when volume changes": ""
|
||||
},
|
||||
"Show only apps running in current workspace": {
|
||||
"Show only apps running in current workspace": "Mostra solo apps eseguite nel workspace attuale"
|
||||
},
|
||||
@@ -2141,6 +2198,9 @@
|
||||
"Volume Changed": {
|
||||
"Volume Changed": "Volume Cambiato"
|
||||
},
|
||||
"Volume OSD": {
|
||||
"Volume OSD": ""
|
||||
},
|
||||
"Volume, brightness, and other system OSDs": {
|
||||
"Volume, brightness, and other system OSDs": "Volume, luminosità, e altri OSD di sistema"
|
||||
},
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
"Add a VPN in NetworkManager": "NetworkManagerでVPNを追加"
|
||||
},
|
||||
"Adjust the number of columns in grid view mode.": {
|
||||
"Adjust the number of columns in grid view mode.": ""
|
||||
"Adjust the number of columns in grid view mode.": "グリッド表示モードでの列数を調整します。"
|
||||
},
|
||||
"All": {
|
||||
"All": "全て"
|
||||
@@ -75,7 +75,7 @@
|
||||
"Always Show OSD Percentage": "常に OSD パーセンテージを表示"
|
||||
},
|
||||
"Always on icons": {
|
||||
"Always on icons": ""
|
||||
"Always on icons": "常時表示アイコン"
|
||||
},
|
||||
"Always show a minimum of 3 workspaces, even if fewer are available": {
|
||||
"Always show a minimum of 3 workspaces, even if fewer are available": "使用可能なワークスペースが少ない場合でも、常に最低 3 つを表示"
|
||||
@@ -275,6 +275,9 @@
|
||||
"Brightness": {
|
||||
"Brightness": "明るさ"
|
||||
},
|
||||
"Brightness OSD": {
|
||||
"Brightness OSD": "明るさOSD"
|
||||
},
|
||||
"Browse": {
|
||||
"Browse": "ブラウズ"
|
||||
},
|
||||
@@ -303,7 +306,7 @@
|
||||
"CUPS Missing Filter Warning": "CUPS の欠落フィルターの警告"
|
||||
},
|
||||
"Camera": {
|
||||
"Camera": ""
|
||||
"Camera": "カメラ"
|
||||
},
|
||||
"Cancel": {
|
||||
"Cancel": "キャンセル"
|
||||
@@ -314,6 +317,9 @@
|
||||
"Caps Lock Indicator": {
|
||||
"Caps Lock Indicator": "Caps Lock インジケーター"
|
||||
},
|
||||
"Caps Lock OSD": {
|
||||
"Caps Lock OSD": "Caps Lock OSD"
|
||||
},
|
||||
"Center Section": {
|
||||
"Center Section": "センターセクション"
|
||||
},
|
||||
@@ -341,6 +347,9 @@
|
||||
"Choose where notification popups appear on screen": {
|
||||
"Choose where notification popups appear on screen": "通知ポップアップが画面に表示される場所を選ぶ"
|
||||
},
|
||||
"Choose where on-screen displays appear on screen": {
|
||||
"Choose where on-screen displays appear on screen": "OSDの表示する場所を選んでください"
|
||||
},
|
||||
"Clear": {
|
||||
"Clear": "クリア"
|
||||
},
|
||||
@@ -617,6 +626,9 @@
|
||||
"Dismiss": {
|
||||
"Dismiss": "解除"
|
||||
},
|
||||
"Display Name Format": {
|
||||
"Display Name Format": "名称形式を表示"
|
||||
},
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": {
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": "画面の上、下、左、右の端に配置できる、ピン留めされた実行中のアプリケーションを含むドックを表示します"
|
||||
},
|
||||
@@ -674,6 +686,9 @@
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": {
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "ウィジェットをドラッグしてセクション内で順序を変更できます。目のアイコンでウィジェットを表示/非表示に(スペースは維持)、Xで完全に削除できます。"
|
||||
},
|
||||
"Duplicate Wallpaper with Blur": {
|
||||
"Duplicate Wallpaper with Blur": "ぼかしで壁紙を複製"
|
||||
},
|
||||
"Duration": {
|
||||
"Duration": "期間"
|
||||
},
|
||||
@@ -749,6 +764,9 @@
|
||||
"Enter password for ": {
|
||||
"Enter password for ": "パスワードを入力"
|
||||
},
|
||||
"Enter this passkey on ": {
|
||||
"Enter this passkey on ": "ここでパスキーを入力してください "
|
||||
},
|
||||
"Error": {
|
||||
"Error": "エラー"
|
||||
},
|
||||
@@ -900,7 +918,7 @@
|
||||
"Grid": "グリッド"
|
||||
},
|
||||
"Grid Columns": {
|
||||
"Grid Columns": ""
|
||||
"Grid Columns": "グリッド列"
|
||||
},
|
||||
"Group by App": {
|
||||
"Group by App": "アプリ別にグループ化"
|
||||
@@ -924,7 +942,7 @@
|
||||
"Hibernate": "休止状態"
|
||||
},
|
||||
"Hide Delay (ms)": {
|
||||
"Hide Delay (ms)": ""
|
||||
"Hide Delay (ms)": "遅延を隠す (ms)"
|
||||
},
|
||||
"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": "使用していないときはドックを非表示にし、ドックエリアの近くにホバーすると表示されます"
|
||||
@@ -959,6 +977,9 @@
|
||||
"Idle Inhibitor": {
|
||||
"Idle Inhibitor": "アイドルインヒビター"
|
||||
},
|
||||
"Idle Inhibitor OSD": {
|
||||
"Idle Inhibitor OSD": "アイドルインヒビターOSD"
|
||||
},
|
||||
"Idle Settings": {
|
||||
"Idle Settings": "アイドル設定"
|
||||
},
|
||||
@@ -1173,7 +1194,10 @@
|
||||
"Memory usage indicator": "メモリ使用率インジケーター"
|
||||
},
|
||||
"Microphone": {
|
||||
"Microphone": ""
|
||||
"Microphone": "マイク"
|
||||
},
|
||||
"Microphone Mute OSD": {
|
||||
"Microphone Mute OSD": "マイクミュートOSD"
|
||||
},
|
||||
"Minimal palette built around a single hue.": {
|
||||
"Minimal palette built around a single hue.": "単一の色相を中心に構築された最小限のパレット。"
|
||||
@@ -1187,6 +1211,9 @@
|
||||
"Mode: ": {
|
||||
"Mode: ": "モード: "
|
||||
},
|
||||
"Model": {
|
||||
"Model": "モデル"
|
||||
},
|
||||
"Monitor Selection:": {
|
||||
"Monitor Selection:": "モニターの選択:"
|
||||
},
|
||||
@@ -1211,6 +1238,9 @@
|
||||
"NM not supported": {
|
||||
"NM not supported": "NMが利用できません"
|
||||
},
|
||||
"Name": {
|
||||
"Name": "名称"
|
||||
},
|
||||
"Named Workspace Icons": {
|
||||
"Named Workspace Icons": "名前付きワークスペースアイコン"
|
||||
},
|
||||
@@ -1337,6 +1367,9 @@
|
||||
"OS Logo": {
|
||||
"OS Logo": "OSロゴ"
|
||||
},
|
||||
"OSD Position": {
|
||||
"OSD Position": "OSD位置"
|
||||
},
|
||||
"Office": {
|
||||
"Office": "オフィス"
|
||||
},
|
||||
@@ -1346,6 +1379,9 @@
|
||||
"On-Screen Displays": {
|
||||
"On-Screen Displays": "オンスクリーンディスプレイ"
|
||||
},
|
||||
"On-screen Displays": {
|
||||
"On-screen Displays": "オンスクリーンディスプレイ"
|
||||
},
|
||||
"Only adjust gamma based on time or location rules.": {
|
||||
"Only adjust gamma based on time or location rules.": "ガンマは、時間または場所のルールに基づいてのみ調整します。"
|
||||
},
|
||||
@@ -1493,6 +1529,9 @@
|
||||
"Power Profile Degradation": {
|
||||
"Power Profile Degradation": "電源プロファイルの劣化"
|
||||
},
|
||||
"Power Profile OSD": {
|
||||
"Power Profile OSD": "電源プロファイルOSD"
|
||||
},
|
||||
"Pressure": {
|
||||
"Pressure": "プレッシャー"
|
||||
},
|
||||
@@ -1647,7 +1686,7 @@
|
||||
"Science": "科学"
|
||||
},
|
||||
"Screen sharing": {
|
||||
"Screen sharing": ""
|
||||
"Screen sharing": "画面共有"
|
||||
},
|
||||
"Scrolling": {
|
||||
"Scrolling": "スクロール"
|
||||
@@ -1781,6 +1820,24 @@
|
||||
"Show on screens:": {
|
||||
"Show on screens:": "画面に表示:"
|
||||
},
|
||||
"Show on-screen display when brightness changes": {
|
||||
"Show on-screen display when brightness changes": "明るさが変化した時にOSDを表示"
|
||||
},
|
||||
"Show on-screen display when caps lock state changes": {
|
||||
"Show on-screen display when caps lock state changes": "Caps Lock の状態が変化した時にOSDを表示"
|
||||
},
|
||||
"Show on-screen display when idle inhibitor state changes": {
|
||||
"Show on-screen display when idle inhibitor state changes": "アイドルインヒビターの状態が変化した時にOSDを表示"
|
||||
},
|
||||
"Show on-screen display when microphone is muted/unmuted": {
|
||||
"Show on-screen display when microphone is muted/unmuted": "マイクがミュート/ミュート解除された時にOSDを表示"
|
||||
},
|
||||
"Show on-screen display when power profile changes": {
|
||||
"Show on-screen display when power profile changes": "電源プロファイルが変化した時にOSDを表示"
|
||||
},
|
||||
"Show on-screen display when volume changes": {
|
||||
"Show on-screen display when volume changes": "音量が変化したときにOSDを表示"
|
||||
},
|
||||
"Show only apps running in current workspace": {
|
||||
"Show only apps running in current workspace": "現在のワークスペースで実行されているアプリのみを表示"
|
||||
},
|
||||
@@ -2141,6 +2198,9 @@
|
||||
"Volume Changed": {
|
||||
"Volume Changed": "音量変更"
|
||||
},
|
||||
"Volume OSD": {
|
||||
"Volume OSD": "音量OSD"
|
||||
},
|
||||
"Volume, brightness, and other system OSDs": {
|
||||
"Volume, brightness, and other system OSDs": "音量、明るさ、その他のシステム OSD"
|
||||
},
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"A file with this name already exists. Do you want to overwrite it?": "Plik o takiej nazwie już istnieje. Czy chcesz go nadpisać?"
|
||||
},
|
||||
"About": {
|
||||
"About": "O..."
|
||||
"About": "O programie"
|
||||
},
|
||||
"Access clipboard history": {
|
||||
"Access clipboard history": "Dostęp do historii schowka"
|
||||
@@ -57,7 +57,7 @@
|
||||
"Add a VPN in NetworkManager": "Dodaj sieć VPN w NetworkManager"
|
||||
},
|
||||
"Adjust the number of columns in grid view mode.": {
|
||||
"Adjust the number of columns in grid view mode.": ""
|
||||
"Adjust the number of columns in grid view mode.": "Dostosuj liczbę kolumn w widoku siatki."
|
||||
},
|
||||
"All": {
|
||||
"All": "Wszystkie"
|
||||
@@ -66,16 +66,16 @@
|
||||
"All day": "Cały dzień"
|
||||
},
|
||||
"All displays": {
|
||||
"All displays": "Wszystkie wyświetlacze"
|
||||
"All displays": "Wszystkie ekrany"
|
||||
},
|
||||
"Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": {
|
||||
"Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backspace: Wstecz • F1/I: Informacje o pliku • F10: Pomoc • Esc: Zamknij"
|
||||
},
|
||||
"Always Show OSD Percentage": {
|
||||
"Always Show OSD Percentage": "Zawsze pokazuj procent OSD"
|
||||
"Always Show OSD Percentage": "Zawsze pokazuj procent w OSD"
|
||||
},
|
||||
"Always on icons": {
|
||||
"Always on icons": ""
|
||||
"Always on icons": "Ikony zawsze włączone"
|
||||
},
|
||||
"Always show a minimum of 3 workspaces, even if fewer are available": {
|
||||
"Always show a minimum of 3 workspaces, even if fewer are available": "Zawsze pokazuj co najmniej 3 obszary robocze, nawet jeśli jest ich mniej."
|
||||
@@ -87,7 +87,7 @@
|
||||
"Anonymous Identity (optional)": "Tożsamość anonimowa (opcjonalnie)"
|
||||
},
|
||||
"App Launcher": {
|
||||
"App Launcher": "App Launcher"
|
||||
"App Launcher": "Program Uruchamiający"
|
||||
},
|
||||
"Application Dock": {
|
||||
"Application Dock": "Aplikacja Dok"
|
||||
@@ -171,7 +171,7 @@
|
||||
"Auto-hide Dock": "Automatyczne ukrywanie doku"
|
||||
},
|
||||
"Auto-saving...": {
|
||||
"Auto-saving...": "Automatyczne zapisywanie..."
|
||||
"Auto-saving...": "Automatyczny zapis..."
|
||||
},
|
||||
"Autoconnect disabled": {
|
||||
"Autoconnect disabled": "Automatyczne łączenie wyłączone"
|
||||
@@ -183,13 +183,13 @@
|
||||
"Automatic Control": "Automatyczna kontrola"
|
||||
},
|
||||
"Automatic Cycling": {
|
||||
"Automatic Cycling": "Automatyczne przełączanie"
|
||||
"Automatic Cycling": "Automatyczne cykl"
|
||||
},
|
||||
"Automatically calculate popup distance from bar edge.": {
|
||||
"Automatically calculate popup distance from bar edge.": "Automatycznie obliczaj odległość wyskakującego okienka od krawędzi paska."
|
||||
},
|
||||
"Automatically cycle through wallpapers in the same folder": {
|
||||
"Automatically cycle through wallpapers in the same folder": "Automatycznie zmieniaj tapety z tego samego folderu"
|
||||
"Automatically cycle through wallpapers in the same folder": "Automatycznie zmieniaj tapety z tego samego katalogu"
|
||||
},
|
||||
"Automatically detect location based on IP address": {
|
||||
"Automatically detect location based on IP address": "Automatycznie wykrywaj lokalizację na podstawie adresu IP"
|
||||
@@ -198,7 +198,7 @@
|
||||
"Automatically determine your location using your IP address": "Automatycznie określ swoją lokalizację na podstawie adresu IP"
|
||||
},
|
||||
"Automatically extract colors from wallpaper": {
|
||||
"Automatically extract colors from wallpaper": "Automatycznie dopasuj kolory z tapety"
|
||||
"Automatically extract colors from wallpaper": "Automatycznie wyciągnij kolory z tapety"
|
||||
},
|
||||
"Automatically hide the top bar to expand screen real estate": {
|
||||
"Automatically hide the top bar to expand screen real estate": "Automatycznie ukryj górny pasek, aby zwiększyć powierzchnię ekranu"
|
||||
@@ -252,7 +252,7 @@
|
||||
"Blur wallpaper when niri overview is open": "Rozmyj tapetę, gdy podgląd niri jest otwarty"
|
||||
},
|
||||
"Border": {
|
||||
"Border": "Obramowanie"
|
||||
"Border": "Ramka"
|
||||
},
|
||||
"Border Color": {
|
||||
"Border Color": "Kolor obramowania"
|
||||
@@ -275,6 +275,9 @@
|
||||
"Brightness": {
|
||||
"Brightness": "Jasność"
|
||||
},
|
||||
"Brightness OSD": {
|
||||
"Brightness OSD": "OSD Jasności"
|
||||
},
|
||||
"Browse": {
|
||||
"Browse": "Przeglądaj"
|
||||
},
|
||||
@@ -291,7 +294,7 @@
|
||||
"CPU Usage": "Użycie CPU"
|
||||
},
|
||||
"CPU temperature display": {
|
||||
"CPU temperature display": "Temperatura CPU"
|
||||
"CPU temperature display": "Wskaźnik temperatury procesora"
|
||||
},
|
||||
"CPU usage indicator": {
|
||||
"CPU usage indicator": "Wskaźnik użycia procesora"
|
||||
@@ -303,7 +306,7 @@
|
||||
"CUPS Missing Filter Warning": "CUPS: Ostrzeżenie o brakującym filtrze"
|
||||
},
|
||||
"Camera": {
|
||||
"Camera": ""
|
||||
"Camera": "Kamera"
|
||||
},
|
||||
"Cancel": {
|
||||
"Cancel": "Anuluj"
|
||||
@@ -312,7 +315,10 @@
|
||||
"Capacity": "Pojemność"
|
||||
},
|
||||
"Caps Lock Indicator": {
|
||||
"Caps Lock Indicator": ""
|
||||
"Caps Lock Indicator": "Wskaźnik caps locka"
|
||||
},
|
||||
"Caps Lock OSD": {
|
||||
"Caps Lock OSD": "OSD Caps Lock"
|
||||
},
|
||||
"Center Section": {
|
||||
"Center Section": "Sekcja środkowa"
|
||||
@@ -339,7 +345,10 @@
|
||||
"Choose the logo displayed on the launcher button in DankBar": "Wybierz logo wyświetlane na przycisku launchera w DankBar"
|
||||
},
|
||||
"Choose where notification popups appear on screen": {
|
||||
"Choose where notification popups appear on screen": "Wybierz, gdzie na ekranie mają pojawiać się wyskakujące powiadomienia"
|
||||
"Choose where notification popups appear on screen": "Wybierz, gdzie na ekranie mają pojawiać się powiadomienia"
|
||||
},
|
||||
"Choose where on-screen displays appear on screen": {
|
||||
"Choose where on-screen displays appear on screen": "Wybierz miejsce wyświetlania informacji na ekranie"
|
||||
},
|
||||
"Clear": {
|
||||
"Clear": "Wyczyść"
|
||||
@@ -435,7 +444,7 @@
|
||||
"Connect to Wi-Fi": "Połącz z siecią Wi-Fi"
|
||||
},
|
||||
"Connected Displays": {
|
||||
"Connected Displays": "Podłączone wyświetlacze"
|
||||
"Connected Displays": "Podłączone ekrany"
|
||||
},
|
||||
"Connecting to Device": {
|
||||
"Connecting to Device": "Łączenie z urządzeniem"
|
||||
@@ -447,7 +456,7 @@
|
||||
"Control Center": "Centrum sterowania"
|
||||
},
|
||||
"Control currently playing media": {
|
||||
"Control currently playing media": "Steruj aktualnie odtwarzanymi mediami"
|
||||
"Control currently playing media": "Steruj aktualnie odtwarzanymi multimediami"
|
||||
},
|
||||
"Controls opacity of all popouts, modals, and their content layers (DankDash, Settings, App Drawer, Control Center, etc.)": {
|
||||
"Controls opacity of all popouts, modals, and their content layers (DankDash, Settings, App Drawer, Control Center, etc.)": "Kontroluje przezroczystość wszystkich wyskakujących okienek, okien modalnych i ich warstw zawartości (DankDash, Ustawienia, Szuflada aplikacji, Centrum sterowania itp.)"
|
||||
@@ -617,6 +626,9 @@
|
||||
"Dismiss": {
|
||||
"Dismiss": "Odrzuć"
|
||||
},
|
||||
"Display Name Format": {
|
||||
"Display Name Format": "Format nazwy wyświetlanej"
|
||||
},
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": {
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": "Wyświetla dok z przypiętymi i uruchomionymi aplikacjami, który można umieścić na górze, na dole, po lewej lub po prawej stronie ekranu."
|
||||
},
|
||||
@@ -633,7 +645,7 @@
|
||||
"Display currently focused application title": "Wyświetlaj tytuł aktywnej aplikacji"
|
||||
},
|
||||
"Display power menu actions in a grid instead of a list": {
|
||||
"Display power menu actions in a grid instead of a list": ""
|
||||
"Display power menu actions in a grid instead of a list": "Wyświetl elementy menu zasilania w siatce zamiast listy"
|
||||
},
|
||||
"Display settings for ": {
|
||||
"Display settings for ": "Ustawienia wyświetlania dla "
|
||||
@@ -642,7 +654,7 @@
|
||||
"Display volume and brightness percentage values by default in OSD popups": "Domyślnie wyświetlaj wartości procentowe głośności i jasności w wyskakujących okienkach OSD"
|
||||
},
|
||||
"Displays": {
|
||||
"Displays": "Wyświetlacze"
|
||||
"Displays": "Ekrany"
|
||||
},
|
||||
"Displays the active keyboard layout and allows switching": {
|
||||
"Displays the active keyboard layout and allows switching": "Wyświetla aktywny układ klawiatury i umożliwia przełączanie"
|
||||
@@ -674,6 +686,9 @@
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": {
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Przeciągnij widżety, aby zmienić kolejność w sekcjach. Użyj ikony oka, aby ukryć/pokazać widżety (zachowując odstępy), lub X, aby je całkowicie usunąć."
|
||||
},
|
||||
"Duplicate Wallpaper with Blur": {
|
||||
"Duplicate Wallpaper with Blur": "Powiel tapetę z rozmyciem"
|
||||
},
|
||||
"Duration": {
|
||||
"Duration": "Czas trwania"
|
||||
},
|
||||
@@ -749,6 +764,9 @@
|
||||
"Enter password for ": {
|
||||
"Enter password for ": "Wprowadź hasło dla "
|
||||
},
|
||||
"Enter this passkey on ": {
|
||||
"Enter this passkey on ": ""
|
||||
},
|
||||
"Error": {
|
||||
"Error": "Błąd"
|
||||
},
|
||||
@@ -828,13 +846,13 @@
|
||||
"Focused Window": "Aktywne okno"
|
||||
},
|
||||
"Font Family": {
|
||||
"Font Family": "Rodzina czcionek"
|
||||
"Font Family": "Rodzina czcionki"
|
||||
},
|
||||
"Font Scale": {
|
||||
"Font Scale": "Skala czcionki"
|
||||
},
|
||||
"Font Settings": {
|
||||
"Font Settings": "Ustawienia czcionek"
|
||||
"Font Settings": "Ustawienia czcionki"
|
||||
},
|
||||
"Font Size": {
|
||||
"Font Size": "Rozmiar czcionki"
|
||||
@@ -846,7 +864,7 @@
|
||||
"Force Kill Process": "Wymuś zamknięcie procesu"
|
||||
},
|
||||
"Force terminal applications to always use dark color schemes": {
|
||||
"Force terminal applications to always use dark color schemes": ""
|
||||
"Force terminal applications to always use dark color schemes": "Wymuś ciemny motyw na aplikacjach terminala"
|
||||
},
|
||||
"Forget Device": {
|
||||
"Forget Device": "Zapomnij urządzenie"
|
||||
@@ -870,7 +888,7 @@
|
||||
"GPU Temperature": "Temperatura GPU"
|
||||
},
|
||||
"GPU temperature display": {
|
||||
"GPU temperature display": "Wyświetlanie temperatury GPU"
|
||||
"GPU temperature display": "Wskaźnik temperatury GPU"
|
||||
},
|
||||
"Games": {
|
||||
"Games": "Gry"
|
||||
@@ -900,7 +918,7 @@
|
||||
"Grid": "Siatka"
|
||||
},
|
||||
"Grid Columns": {
|
||||
"Grid Columns": ""
|
||||
"Grid Columns": "Kolumny siatki"
|
||||
},
|
||||
"Group by App": {
|
||||
"Group by App": "Grupuj według aplikacji"
|
||||
@@ -924,7 +942,7 @@
|
||||
"Hibernate": "Hibernacja"
|
||||
},
|
||||
"Hide Delay (ms)": {
|
||||
"Hide Delay (ms)": ""
|
||||
"Hide Delay (ms)": "Opóźnienie ukrycia (ms)"
|
||||
},
|
||||
"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"
|
||||
@@ -959,6 +977,9 @@
|
||||
"Idle Inhibitor": {
|
||||
"Idle Inhibitor": "Inhibitor bezczynności"
|
||||
},
|
||||
"Idle Inhibitor OSD": {
|
||||
"Idle Inhibitor OSD": "OSD Inhibitora Bezczynności"
|
||||
},
|
||||
"Idle Settings": {
|
||||
"Idle Settings": "Ustawienia bezczynności"
|
||||
},
|
||||
@@ -1074,7 +1095,7 @@
|
||||
"Location Search": "Wyszukiwanie lokalizacji"
|
||||
},
|
||||
"Lock": {
|
||||
"Lock": "Zamek"
|
||||
"Lock": "Zablokuj"
|
||||
},
|
||||
"Lock Screen": {
|
||||
"Lock Screen": "Ekran blokady"
|
||||
@@ -1173,7 +1194,10 @@
|
||||
"Memory usage indicator": "Wskaźnik zużycia pamięci"
|
||||
},
|
||||
"Microphone": {
|
||||
"Microphone": ""
|
||||
"Microphone": "Mikrofon"
|
||||
},
|
||||
"Microphone Mute OSD": {
|
||||
"Microphone Mute OSD": "OSD Wyciszenia Mikrofonu"
|
||||
},
|
||||
"Minimal palette built around a single hue.": {
|
||||
"Minimal palette built around a single hue.": "Minimalna paleta zbudowana wokół jednego odcienia."
|
||||
@@ -1187,6 +1211,9 @@
|
||||
"Mode: ": {
|
||||
"Mode: ": "Tryb: "
|
||||
},
|
||||
"Model": {
|
||||
"Model": "Model"
|
||||
},
|
||||
"Monitor Selection:": {
|
||||
"Monitor Selection:": "Wybór monitora:"
|
||||
},
|
||||
@@ -1211,6 +1238,9 @@
|
||||
"NM not supported": {
|
||||
"NM not supported": "NM nie jest obsługiwany"
|
||||
},
|
||||
"Name": {
|
||||
"Name": "Nazwa"
|
||||
},
|
||||
"Named Workspace Icons": {
|
||||
"Named Workspace Icons": "Ikony nazwanych obszarów roboczych"
|
||||
},
|
||||
@@ -1337,6 +1367,9 @@
|
||||
"OS Logo": {
|
||||
"OS Logo": "Logo OS"
|
||||
},
|
||||
"OSD Position": {
|
||||
"OSD Position": "Pozycja OSD"
|
||||
},
|
||||
"Office": {
|
||||
"Office": "Biuro"
|
||||
},
|
||||
@@ -1346,6 +1379,9 @@
|
||||
"On-Screen Displays": {
|
||||
"On-Screen Displays": "Wyświetlacze ekranowe"
|
||||
},
|
||||
"On-screen Displays": {
|
||||
"On-screen Displays": "Powiadomienia ekranowe"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
@@ -1493,6 +1529,9 @@
|
||||
"Power Profile Degradation": {
|
||||
"Power Profile Degradation": "Pogorszenie profilu zasilania"
|
||||
},
|
||||
"Power Profile OSD": {
|
||||
"Power Profile OSD": "OSD Profilu Zasilania"
|
||||
},
|
||||
"Pressure": {
|
||||
"Pressure": "Ciśnienie"
|
||||
},
|
||||
@@ -1647,7 +1686,7 @@
|
||||
"Science": "Nauka"
|
||||
},
|
||||
"Screen sharing": {
|
||||
"Screen sharing": ""
|
||||
"Screen sharing": "Udostępnianie ekranu"
|
||||
},
|
||||
"Scrolling": {
|
||||
"Scrolling": "Przewijanie"
|
||||
@@ -1781,6 +1820,24 @@
|
||||
"Show on screens:": {
|
||||
"Show on screens:": "Pokaż na ekranach:"
|
||||
},
|
||||
"Show on-screen display when brightness changes": {
|
||||
"Show on-screen display when brightness changes": "Wyświetlaj powiadomienie ekranowe przy zmianie jasności"
|
||||
},
|
||||
"Show on-screen display when caps lock state changes": {
|
||||
"Show on-screen display when caps lock state changes": "Wyświetlaj powiadomienie ekranowe przy zmianie stanu Caps Lock"
|
||||
},
|
||||
"Show on-screen display when idle inhibitor state changes": {
|
||||
"Show on-screen display when idle inhibitor state changes": "Wyświetlaj powiadomienie ekranowe przy zmianie stanu inhibitora bezczynności"
|
||||
},
|
||||
"Show on-screen display when microphone is muted/unmuted": {
|
||||
"Show on-screen display when microphone is muted/unmuted": "Wyświetlaj powiadomienie ekranowe przy wyciszaniu/włączaniu mikrofonu"
|
||||
},
|
||||
"Show on-screen display when power profile changes": {
|
||||
"Show on-screen display when power profile changes": "Wyświetlaj powiadomienie ekranowe przy zmianie profilu zasilania"
|
||||
},
|
||||
"Show on-screen display when volume changes": {
|
||||
"Show on-screen display when volume changes": "Wyświetlaj powiadomienie ekranowe przy zmianie głośności"
|
||||
},
|
||||
"Show only apps running in current workspace": {
|
||||
"Show only apps running in current workspace": "Pokaż tylko aplikacje uruchomione w bieżącym obszarze roboczym"
|
||||
},
|
||||
@@ -1809,7 +1866,7 @@
|
||||
"Shows current workspace and allows switching": "Pokazuje bieżący obszar roboczy i pozwala na przełączanie"
|
||||
},
|
||||
"Shows when caps lock is active": {
|
||||
"Shows when caps lock is active": ""
|
||||
"Shows when caps lock is active": "Pojawia się gdy 'Caps Lock' jest aktywny"
|
||||
},
|
||||
"Shows when microphone, camera, or screen sharing is active": {
|
||||
"Shows when microphone, camera, or screen sharing is active": "Pokazuje, gdy mikrofon, kamera lub udostępnianie ekranu są aktywne"
|
||||
@@ -1938,7 +1995,7 @@
|
||||
"Terminal custom additional parameters": "Niestandardowe dodatkowe parametry terminala"
|
||||
},
|
||||
"Terminals - Always use Dark Theme": {
|
||||
"Terminals - Always use Dark Theme": ""
|
||||
"Terminals - Always use Dark Theme": "Terminal - Zawsze używaj ciemnego motywu"
|
||||
},
|
||||
"Text": {
|
||||
"Text": "Tekst"
|
||||
@@ -2055,16 +2112,16 @@
|
||||
"Use Fahrenheit instead of Celsius for temperature": "Użyj Fahrenheita zamiast Celsjusza dla temperatury"
|
||||
},
|
||||
"Use Grid Layout": {
|
||||
"Use Grid Layout": ""
|
||||
"Use Grid Layout": "Użyj układu siatki"
|
||||
},
|
||||
"Use IP Location": {
|
||||
"Use IP Location": "Użyj lokalizacji IP"
|
||||
},
|
||||
"Use Imperial Units": {
|
||||
"Use Imperial Units": ""
|
||||
"Use Imperial Units": "Użyj imperialnych jednostek"
|
||||
},
|
||||
"Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": {
|
||||
"Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": ""
|
||||
"Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "Użyj imperialnych jednostek (°F, mph, inHg) zamiast metrycznych (°C, km/h, hPa)"
|
||||
},
|
||||
"Use Monospace Font": {
|
||||
"Use Monospace Font": "Użyj czcionki o stałej szerokości"
|
||||
@@ -2141,6 +2198,9 @@
|
||||
"Volume Changed": {
|
||||
"Volume Changed": "Zmieniony wolumen"
|
||||
},
|
||||
"Volume OSD": {
|
||||
"Volume OSD": "OSD Głośności"
|
||||
},
|
||||
"Volume, brightness, and other system OSDs": {
|
||||
"Volume, brightness, and other system OSDs": "Głośność, jasność i inne systemowe menu ekranowe"
|
||||
},
|
||||
|
||||
@@ -275,6 +275,9 @@
|
||||
"Brightness": {
|
||||
"Brightness": "Brilho"
|
||||
},
|
||||
"Brightness OSD": {
|
||||
"Brightness OSD": ""
|
||||
},
|
||||
"Browse": {
|
||||
"Browse": "Navegar"
|
||||
},
|
||||
@@ -314,6 +317,9 @@
|
||||
"Caps Lock Indicator": {
|
||||
"Caps Lock Indicator": ""
|
||||
},
|
||||
"Caps Lock OSD": {
|
||||
"Caps Lock OSD": ""
|
||||
},
|
||||
"Center Section": {
|
||||
"Center Section": "Seção Central"
|
||||
},
|
||||
@@ -341,6 +347,9 @@
|
||||
"Choose where notification popups appear on screen": {
|
||||
"Choose where notification popups appear on screen": "Escolher onde as notificações irão aparecer na tela"
|
||||
},
|
||||
"Choose where on-screen displays appear on screen": {
|
||||
"Choose where on-screen displays appear on screen": ""
|
||||
},
|
||||
"Clear": {
|
||||
"Clear": "Limpar"
|
||||
},
|
||||
@@ -617,6 +626,9 @@
|
||||
"Dismiss": {
|
||||
"Dismiss": "Descartar"
|
||||
},
|
||||
"Display Name Format": {
|
||||
"Display Name Format": ""
|
||||
},
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": {
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": "Exibir um dock com aplicativos que estão sendo utilizados, e que pode ser posicionada no superior, inferior, esquerda ou direita dos cantos da tela"
|
||||
},
|
||||
@@ -674,6 +686,9 @@
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": {
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Arraste Widgets para reordená-los nas seções. Use o ícone de olho para esconder ou mostrá-los (manter o espaçamento), ou clique no X para removê-los por completo."
|
||||
},
|
||||
"Duplicate Wallpaper with Blur": {
|
||||
"Duplicate Wallpaper with Blur": ""
|
||||
},
|
||||
"Duration": {
|
||||
"Duration": "Duração"
|
||||
},
|
||||
@@ -749,6 +764,9 @@
|
||||
"Enter password for ": {
|
||||
"Enter password for ": "Insira senha para "
|
||||
},
|
||||
"Enter this passkey on ": {
|
||||
"Enter this passkey on ": ""
|
||||
},
|
||||
"Error": {
|
||||
"Error": ""
|
||||
},
|
||||
@@ -959,6 +977,9 @@
|
||||
"Idle Inhibitor": {
|
||||
"Idle Inhibitor": "Inibitor de inatividade"
|
||||
},
|
||||
"Idle Inhibitor OSD": {
|
||||
"Idle Inhibitor OSD": ""
|
||||
},
|
||||
"Idle Settings": {
|
||||
"Idle Settings": "Configurações de inatividade"
|
||||
},
|
||||
@@ -1175,6 +1196,9 @@
|
||||
"Microphone": {
|
||||
"Microphone": ""
|
||||
},
|
||||
"Microphone Mute OSD": {
|
||||
"Microphone Mute OSD": ""
|
||||
},
|
||||
"Minimal palette built around a single hue.": {
|
||||
"Minimal palette built around a single hue.": "Paleta mínima construída ao redor de um único tom."
|
||||
},
|
||||
@@ -1187,6 +1211,9 @@
|
||||
"Mode: ": {
|
||||
"Mode: ": ""
|
||||
},
|
||||
"Model": {
|
||||
"Model": ""
|
||||
},
|
||||
"Monitor Selection:": {
|
||||
"Monitor Selection:": "Seleção de Monitor:"
|
||||
},
|
||||
@@ -1211,6 +1238,9 @@
|
||||
"NM not supported": {
|
||||
"NM not supported": "NM não suportado"
|
||||
},
|
||||
"Name": {
|
||||
"Name": ""
|
||||
},
|
||||
"Named Workspace Icons": {
|
||||
"Named Workspace Icons": "Ícones de Áreas de Trabalho Nomeadas"
|
||||
},
|
||||
@@ -1337,6 +1367,9 @@
|
||||
"OS Logo": {
|
||||
"OS Logo": "Logo do SO"
|
||||
},
|
||||
"OSD Position": {
|
||||
"OSD Position": ""
|
||||
},
|
||||
"Office": {
|
||||
"Office": "Escritório"
|
||||
},
|
||||
@@ -1346,6 +1379,9 @@
|
||||
"On-Screen Displays": {
|
||||
"On-Screen Displays": "Displays na Tela (OSDs)"
|
||||
},
|
||||
"On-screen Displays": {
|
||||
"On-screen Displays": ""
|
||||
},
|
||||
"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."
|
||||
},
|
||||
@@ -1493,6 +1529,9 @@
|
||||
"Power Profile Degradation": {
|
||||
"Power Profile Degradation": "Degradação do Perfil de Energia"
|
||||
},
|
||||
"Power Profile OSD": {
|
||||
"Power Profile OSD": ""
|
||||
},
|
||||
"Pressure": {
|
||||
"Pressure": "Pressão"
|
||||
},
|
||||
@@ -1781,6 +1820,24 @@
|
||||
"Show on screens:": {
|
||||
"Show on screens:": "Mostrar nas telas:"
|
||||
},
|
||||
"Show on-screen display when brightness changes": {
|
||||
"Show on-screen display when brightness changes": ""
|
||||
},
|
||||
"Show on-screen display when caps lock state changes": {
|
||||
"Show on-screen display when caps lock state changes": ""
|
||||
},
|
||||
"Show on-screen display when idle inhibitor state changes": {
|
||||
"Show on-screen display when idle inhibitor state changes": ""
|
||||
},
|
||||
"Show on-screen display when microphone is muted/unmuted": {
|
||||
"Show on-screen display when microphone is muted/unmuted": ""
|
||||
},
|
||||
"Show on-screen display when power profile changes": {
|
||||
"Show on-screen display when power profile changes": ""
|
||||
},
|
||||
"Show on-screen display when volume changes": {
|
||||
"Show on-screen display when volume changes": ""
|
||||
},
|
||||
"Show only apps running in current workspace": {
|
||||
"Show only apps running in current workspace": "Mostrar apenas aplicativos rodando na área de trabalho atual"
|
||||
},
|
||||
@@ -2141,6 +2198,9 @@
|
||||
"Volume Changed": {
|
||||
"Volume Changed": "Volume Alterado"
|
||||
},
|
||||
"Volume OSD": {
|
||||
"Volume OSD": ""
|
||||
},
|
||||
"Volume, brightness, and other system OSDs": {
|
||||
"Volume, brightness, and other system OSDs": "Volume, brilho, e outros OSDs do sistema"
|
||||
},
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
"Add a VPN in NetworkManager": "NetworkManager'da VPN ekle"
|
||||
},
|
||||
"Adjust the number of columns in grid view mode.": {
|
||||
"Adjust the number of columns in grid view mode.": ""
|
||||
"Adjust the number of columns in grid view mode.": "Izgara görünümü modunda sütun sayısını ayarla"
|
||||
},
|
||||
"All": {
|
||||
"All": "Tümü"
|
||||
@@ -75,7 +75,7 @@
|
||||
"Always Show OSD Percentage": "OSD Yüzdesini Her Zaman Göster"
|
||||
},
|
||||
"Always on icons": {
|
||||
"Always on icons": ""
|
||||
"Always on icons": "Her zaman açık simgeler"
|
||||
},
|
||||
"Always show a minimum of 3 workspaces, even if fewer are available": {
|
||||
"Always show a minimum of 3 workspaces, even if fewer are available": "Her zaman en az 3 çalışma alanı göster, daha azı kullanılabilir olsa da"
|
||||
@@ -275,6 +275,9 @@
|
||||
"Brightness": {
|
||||
"Brightness": "Parlaklık"
|
||||
},
|
||||
"Brightness OSD": {
|
||||
"Brightness OSD": "Parlaklık OSD"
|
||||
},
|
||||
"Browse": {
|
||||
"Browse": "Göz at"
|
||||
},
|
||||
@@ -303,7 +306,7 @@
|
||||
"CUPS Missing Filter Warning": "CUPS Eksik Filtre Uyarısı"
|
||||
},
|
||||
"Camera": {
|
||||
"Camera": ""
|
||||
"Camera": "Kamera"
|
||||
},
|
||||
"Cancel": {
|
||||
"Cancel": "İptal"
|
||||
@@ -312,7 +315,10 @@
|
||||
"Capacity": "Kapasite"
|
||||
},
|
||||
"Caps Lock Indicator": {
|
||||
"Caps Lock Indicator": ""
|
||||
"Caps Lock Indicator": "Caps Lock Göstergesi"
|
||||
},
|
||||
"Caps Lock OSD": {
|
||||
"Caps Lock OSD": "Caps Lock OSD"
|
||||
},
|
||||
"Center Section": {
|
||||
"Center Section": "Orta Bölüm"
|
||||
@@ -341,6 +347,9 @@
|
||||
"Choose where notification popups appear on screen": {
|
||||
"Choose where notification popups appear on screen": "Bildirim açılır pencerelerinin ekranda nerede görüneceğini seçin"
|
||||
},
|
||||
"Choose where on-screen displays appear on screen": {
|
||||
"Choose where on-screen displays appear on screen": "Ekran gösterimlerinin ekranda nerede gösterileceğini seç"
|
||||
},
|
||||
"Clear": {
|
||||
"Clear": "Temizle"
|
||||
},
|
||||
@@ -617,6 +626,9 @@
|
||||
"Dismiss": {
|
||||
"Dismiss": "Reddet"
|
||||
},
|
||||
"Display Name Format": {
|
||||
"Display Name Format": "Ekran İsim Formatı"
|
||||
},
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": {
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": "Ekranın üst, alt, sol veya sağ kenarına yerleştirilebilen, sabitlenmiş ve çalışan uygulamaları içeren bir dock görüntüleyin."
|
||||
},
|
||||
@@ -633,7 +645,7 @@
|
||||
"Display currently focused application title": "Şu anda odaklanmış uygulamanın başlığını göster"
|
||||
},
|
||||
"Display power menu actions in a grid instead of a list": {
|
||||
"Display power menu actions in a grid instead of a list": ""
|
||||
"Display power menu actions in a grid instead of a list": "Güç menüsü eylemlerini liste yerine ızgara şeklinde göster"
|
||||
},
|
||||
"Display settings for ": {
|
||||
"Display settings for ": "Ekran ayarları: "
|
||||
@@ -674,6 +686,9 @@
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": {
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "Widget'ları sürükleyerek bölümler içinde yeniden sıralayın. Göz simgesini kullanarak widget'ları gizleyin/gösterin (aralıkları korur) veya X simgesini kullanarak tamamen kaldırın."
|
||||
},
|
||||
"Duplicate Wallpaper with Blur": {
|
||||
"Duplicate Wallpaper with Blur": "Duvar kağıdını bulanıklık ile çoğalt"
|
||||
},
|
||||
"Duration": {
|
||||
"Duration": "Süre"
|
||||
},
|
||||
@@ -749,6 +764,9 @@
|
||||
"Enter password for ": {
|
||||
"Enter password for ": "Parolayı girin "
|
||||
},
|
||||
"Enter this passkey on ": {
|
||||
"Enter this passkey on ": ""
|
||||
},
|
||||
"Error": {
|
||||
"Error": "Hata"
|
||||
},
|
||||
@@ -846,7 +864,7 @@
|
||||
"Force Kill Process": "Süreci Zorla Kapat"
|
||||
},
|
||||
"Force terminal applications to always use dark color schemes": {
|
||||
"Force terminal applications to always use dark color schemes": ""
|
||||
"Force terminal applications to always use dark color schemes": "Terminal uygulamalarının her zaman koyu renk şemalarını kullanmasını zorla"
|
||||
},
|
||||
"Forget Device": {
|
||||
"Forget Device": "Aygıtı Unut"
|
||||
@@ -900,7 +918,7 @@
|
||||
"Grid": "Izgara"
|
||||
},
|
||||
"Grid Columns": {
|
||||
"Grid Columns": ""
|
||||
"Grid Columns": "Izgara Sütunları"
|
||||
},
|
||||
"Group by App": {
|
||||
"Group by App": "Uygulamaya Göre Gruplandır"
|
||||
@@ -924,7 +942,7 @@
|
||||
"Hibernate": "Hazırda Beklet"
|
||||
},
|
||||
"Hide Delay (ms)": {
|
||||
"Hide Delay (ms)": ""
|
||||
"Hide Delay (ms)": "Gizleme Gecikmesi (ms)"
|
||||
},
|
||||
"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"
|
||||
@@ -959,6 +977,9 @@
|
||||
"Idle Inhibitor": {
|
||||
"Idle Inhibitor": "Boşta Kalma Engelleyici"
|
||||
},
|
||||
"Idle Inhibitor OSD": {
|
||||
"Idle Inhibitor OSD": "Boşta Kalma Engelleyici OSD"
|
||||
},
|
||||
"Idle Settings": {
|
||||
"Idle Settings": "Boşta Kalma Ayarları"
|
||||
},
|
||||
@@ -1173,7 +1194,10 @@
|
||||
"Memory usage indicator": "Bellek kullanım göstergesi"
|
||||
},
|
||||
"Microphone": {
|
||||
"Microphone": ""
|
||||
"Microphone": "Mikrofon"
|
||||
},
|
||||
"Microphone Mute OSD": {
|
||||
"Microphone Mute OSD": "Mikrofon Sessiz OSD"
|
||||
},
|
||||
"Minimal palette built around a single hue.": {
|
||||
"Minimal palette built around a single hue.": "Tek bir renk tonu etrafında oluşturulmuş minimal palet."
|
||||
@@ -1187,6 +1211,9 @@
|
||||
"Mode: ": {
|
||||
"Mode: ": "Mod: "
|
||||
},
|
||||
"Model": {
|
||||
"Model": "Model"
|
||||
},
|
||||
"Monitor Selection:": {
|
||||
"Monitor Selection:": "Monitör Seçimi:"
|
||||
},
|
||||
@@ -1211,6 +1238,9 @@
|
||||
"NM not supported": {
|
||||
"NM not supported": "NM desteklenmiyor"
|
||||
},
|
||||
"Name": {
|
||||
"Name": "İsim"
|
||||
},
|
||||
"Named Workspace Icons": {
|
||||
"Named Workspace Icons": "Adlandırılmış Çalışma Alanı Simgeleri"
|
||||
},
|
||||
@@ -1337,6 +1367,9 @@
|
||||
"OS Logo": {
|
||||
"OS Logo": "OS Logo"
|
||||
},
|
||||
"OSD Position": {
|
||||
"OSD Position": "OSD Pozisyonu"
|
||||
},
|
||||
"Office": {
|
||||
"Office": "Ofis"
|
||||
},
|
||||
@@ -1346,6 +1379,9 @@
|
||||
"On-Screen Displays": {
|
||||
"On-Screen Displays": "Ekran Üstü Gösterimler"
|
||||
},
|
||||
"On-screen Displays": {
|
||||
"On-screen Displays": "Ekran Gösterimleri"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
@@ -1493,6 +1529,9 @@
|
||||
"Power Profile Degradation": {
|
||||
"Power Profile Degradation": "Güç Profili Dejenerasyonu"
|
||||
},
|
||||
"Power Profile OSD": {
|
||||
"Power Profile OSD": "Güç Profili OSD"
|
||||
},
|
||||
"Pressure": {
|
||||
"Pressure": "Basınç"
|
||||
},
|
||||
@@ -1647,7 +1686,7 @@
|
||||
"Science": "Bilim"
|
||||
},
|
||||
"Screen sharing": {
|
||||
"Screen sharing": ""
|
||||
"Screen sharing": "Ekran paylaşımı"
|
||||
},
|
||||
"Scrolling": {
|
||||
"Scrolling": "Kaydırma"
|
||||
@@ -1781,6 +1820,24 @@
|
||||
"Show on screens:": {
|
||||
"Show on screens:": "Şu ekranda göster:"
|
||||
},
|
||||
"Show on-screen display when brightness changes": {
|
||||
"Show on-screen display when brightness changes": "Parlaklık değiştiğinde ekran gösterimi göster"
|
||||
},
|
||||
"Show on-screen display when caps lock state changes": {
|
||||
"Show on-screen display when caps lock state changes": "Caps lock durumu değiştiğinde ekran gösterimi göster"
|
||||
},
|
||||
"Show on-screen display when idle inhibitor state changes": {
|
||||
"Show on-screen display when idle inhibitor state changes": "Boşta kalma engelleyici durumu değiştiğinde ekran gösterimi göster"
|
||||
},
|
||||
"Show on-screen display when microphone is muted/unmuted": {
|
||||
"Show on-screen display when microphone is muted/unmuted": "Mikrofon sessize alındığında/sessizden çıkarıldığında ekran gösterimi göster"
|
||||
},
|
||||
"Show on-screen display when power profile changes": {
|
||||
"Show on-screen display when power profile changes": "Güç profili değiştiğinde ekran gösterimi göster"
|
||||
},
|
||||
"Show on-screen display when volume changes": {
|
||||
"Show on-screen display when volume changes": "Ses değiştiğinde ekran gösterimi göster"
|
||||
},
|
||||
"Show only apps running in current workspace": {
|
||||
"Show only apps running in current workspace": "Yalnızca mevcut çalışma alanında çalışan uygulamaları göster"
|
||||
},
|
||||
@@ -1809,7 +1866,7 @@
|
||||
"Shows current workspace and allows switching": "Mevcut çalışma alanı gösterir ve değiştirmeye izin verir"
|
||||
},
|
||||
"Shows when caps lock is active": {
|
||||
"Shows when caps lock is active": ""
|
||||
"Shows when caps lock is active": "Caps Lock tuşunun etkin olduğunu gösterir"
|
||||
},
|
||||
"Shows when microphone, camera, or screen sharing is active": {
|
||||
"Shows when microphone, camera, or screen sharing is active": "Mikrofon, kamera veya ekran paylaşımı aktif olduğunda gösterir"
|
||||
@@ -1938,7 +1995,7 @@
|
||||
"Terminal custom additional parameters": "Terminal özel ek parametreleri"
|
||||
},
|
||||
"Terminals - Always use Dark Theme": {
|
||||
"Terminals - Always use Dark Theme": ""
|
||||
"Terminals - Always use Dark Theme": "Terminaller - Her zaman Karanlı Tema kullan"
|
||||
},
|
||||
"Text": {
|
||||
"Text": "Metin"
|
||||
@@ -2055,16 +2112,16 @@
|
||||
"Use Fahrenheit instead of Celsius for temperature": "Sıcaklık için Celsius yerine Fahrenhayt kullan"
|
||||
},
|
||||
"Use Grid Layout": {
|
||||
"Use Grid Layout": ""
|
||||
"Use Grid Layout": "Izgara Düzeni Kullan"
|
||||
},
|
||||
"Use IP Location": {
|
||||
"Use IP Location": "IP Konumunu Kullan"
|
||||
},
|
||||
"Use Imperial Units": {
|
||||
"Use Imperial Units": ""
|
||||
"Use Imperial Units": "İngiliz Ölçü Birimini Kullan"
|
||||
},
|
||||
"Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": {
|
||||
"Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": ""
|
||||
"Use Imperial units (°F, mph, inHg) instead of Metric (°C, km/h, hPa)": "Metrik birimler (°C, km/h, hPa) yerine İngiliz birimleri (°F, mph, inHg) kullan"
|
||||
},
|
||||
"Use Monospace Font": {
|
||||
"Use Monospace Font": "Sabit Aralıklı Yazı Tipi Kullan"
|
||||
@@ -2141,6 +2198,9 @@
|
||||
"Volume Changed": {
|
||||
"Volume Changed": "Ses Seviyesi Değişti"
|
||||
},
|
||||
"Volume OSD": {
|
||||
"Volume OSD": "Ses OSD"
|
||||
},
|
||||
"Volume, brightness, and other system OSDs": {
|
||||
"Volume, brightness, and other system OSDs": "Ses, parlaklık ve diğer sistem ekran üstü gösterimleri"
|
||||
},
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
"Add a VPN in NetworkManager": "在 NetworkManager 中添加 VPN"
|
||||
},
|
||||
"Adjust the number of columns in grid view mode.": {
|
||||
"Adjust the number of columns in grid view mode.": ""
|
||||
"Adjust the number of columns in grid view mode.": "在网格模式中按需调整列的数量。"
|
||||
},
|
||||
"All": {
|
||||
"All": "全部"
|
||||
@@ -75,7 +75,7 @@
|
||||
"Always Show OSD Percentage": "始终显示 OSD 百分比"
|
||||
},
|
||||
"Always on icons": {
|
||||
"Always on icons": ""
|
||||
"Always on icons": "总显示的图标"
|
||||
},
|
||||
"Always show a minimum of 3 workspaces, even if fewer are available": {
|
||||
"Always show a minimum of 3 workspaces, even if fewer are available": "即使不足也总是显示至少三个工作区"
|
||||
@@ -275,6 +275,9 @@
|
||||
"Brightness": {
|
||||
"Brightness": "亮度"
|
||||
},
|
||||
"Brightness OSD": {
|
||||
"Brightness OSD": "OSD亮度"
|
||||
},
|
||||
"Browse": {
|
||||
"Browse": "浏览"
|
||||
},
|
||||
@@ -303,7 +306,7 @@
|
||||
"CUPS Missing Filter Warning": "CUPS 警告:缺少打印过滤器"
|
||||
},
|
||||
"Camera": {
|
||||
"Camera": ""
|
||||
"Camera": "摄像头"
|
||||
},
|
||||
"Cancel": {
|
||||
"Cancel": "取消"
|
||||
@@ -314,6 +317,9 @@
|
||||
"Caps Lock Indicator": {
|
||||
"Caps Lock Indicator": "大小写指示灯"
|
||||
},
|
||||
"Caps Lock OSD": {
|
||||
"Caps Lock OSD": "OSD大小写"
|
||||
},
|
||||
"Center Section": {
|
||||
"Center Section": "中间区域"
|
||||
},
|
||||
@@ -341,6 +347,9 @@
|
||||
"Choose where notification popups appear on screen": {
|
||||
"Choose where notification popups appear on screen": "设置通知弹窗的出现位置"
|
||||
},
|
||||
"Choose where on-screen displays appear on screen": {
|
||||
"Choose where on-screen displays appear on screen": "选择OSD在屏幕上出现的位置"
|
||||
},
|
||||
"Clear": {
|
||||
"Clear": "清除"
|
||||
},
|
||||
@@ -531,7 +540,7 @@
|
||||
"DMS_SOCKET not available": "DMS_SOCKET 不可用"
|
||||
},
|
||||
"DWL service not available": {
|
||||
"DWL service not available": "DWL服务不可用"
|
||||
"DWL service not available": "DWL 服务不可用"
|
||||
},
|
||||
"Daily at:": {
|
||||
"Daily at:": "在每日:"
|
||||
@@ -617,6 +626,9 @@
|
||||
"Dismiss": {
|
||||
"Dismiss": "忽略"
|
||||
},
|
||||
"Display Name Format": {
|
||||
"Display Name Format": "显示名称格式"
|
||||
},
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": {
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": "显示一个包含固定和运行中应用的程序坞,可放置在屏幕四边任意位置"
|
||||
},
|
||||
@@ -624,7 +636,7 @@
|
||||
"Display all priorities over fullscreen apps": "应用全屏时仍显示所有优先级的通知"
|
||||
},
|
||||
"Display and switch DWL layouts": {
|
||||
"Display and switch DWL layouts": "显示与切换DWL布局"
|
||||
"Display and switch DWL layouts": "显示与切换 DWL 布局"
|
||||
},
|
||||
"Display application icons in workspace indicators": {
|
||||
"Display application icons in workspace indicators": "在工作区指示器中显示应用程序图标"
|
||||
@@ -674,6 +686,9 @@
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": {
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "拖动组件以在各区块内重新排序。点击眼睛图标可隐藏/显示组件(保留间距),点击 X 可彻底移除。"
|
||||
},
|
||||
"Duplicate Wallpaper with Blur": {
|
||||
"Duplicate Wallpaper with Blur": "带模糊效果的壁纸复本"
|
||||
},
|
||||
"Duration": {
|
||||
"Duration": "持续时间"
|
||||
},
|
||||
@@ -749,6 +764,9 @@
|
||||
"Enter password for ": {
|
||||
"Enter password for ": "输入密码"
|
||||
},
|
||||
"Enter this passkey on ": {
|
||||
"Enter this passkey on ": "在该处输入此通行密钥 "
|
||||
},
|
||||
"Error": {
|
||||
"Error": "错误"
|
||||
},
|
||||
@@ -846,7 +864,7 @@
|
||||
"Force Kill Process": "强制结束进程"
|
||||
},
|
||||
"Force terminal applications to always use dark color schemes": {
|
||||
"Force terminal applications to always use dark color schemes": "强制终端应用总使用暗色"
|
||||
"Force terminal applications to always use dark color schemes": "强制终端应用使用暗色"
|
||||
},
|
||||
"Forget Device": {
|
||||
"Forget Device": "取消配对"
|
||||
@@ -900,7 +918,7 @@
|
||||
"Grid": "网格"
|
||||
},
|
||||
"Grid Columns": {
|
||||
"Grid Columns": ""
|
||||
"Grid Columns": "网格列"
|
||||
},
|
||||
"Group by App": {
|
||||
"Group by App": "按应用分组"
|
||||
@@ -924,7 +942,7 @@
|
||||
"Hibernate": "休眠"
|
||||
},
|
||||
"Hide Delay (ms)": {
|
||||
"Hide Delay (ms)": ""
|
||||
"Hide Delay (ms)": "隐藏延迟 (ms)"
|
||||
},
|
||||
"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": "在未使用时隐藏程序坞,鼠标悬停到程序坞区域时显示"
|
||||
@@ -959,6 +977,9 @@
|
||||
"Idle Inhibitor": {
|
||||
"Idle Inhibitor": "待机抑制器"
|
||||
},
|
||||
"Idle Inhibitor OSD": {
|
||||
"Idle Inhibitor OSD": "OSD空闲抑制"
|
||||
},
|
||||
"Idle Settings": {
|
||||
"Idle Settings": "待机设置"
|
||||
},
|
||||
@@ -1020,13 +1041,13 @@
|
||||
"Last launched %1": "上次启动于 %1"
|
||||
},
|
||||
"Last launched %1 day%2 ago": {
|
||||
"Last launched %1 day%2 ago": "上次启动于 %1 天%2 前"
|
||||
"Last launched %1 day%2 ago": "上次启动于 %1 天 前"
|
||||
},
|
||||
"Last launched %1 hour%2 ago": {
|
||||
"Last launched %1 hour%2 ago": "上次启动于 %1 小时%2 前"
|
||||
"Last launched %1 hour%2 ago": "上次启动于 %1 小时 前"
|
||||
},
|
||||
"Last launched %1 minute%2 ago": {
|
||||
"Last launched %1 minute%2 ago": "上次启动于 %1 分钟%2 前"
|
||||
"Last launched %1 minute%2 ago": "上次启动于 %1 分钟 前"
|
||||
},
|
||||
"Last launched just now": {
|
||||
"Last launched just now": "刚刚启动"
|
||||
@@ -1173,7 +1194,10 @@
|
||||
"Memory usage indicator": "内存占用情况"
|
||||
},
|
||||
"Microphone": {
|
||||
"Microphone": ""
|
||||
"Microphone": "麦克风"
|
||||
},
|
||||
"Microphone Mute OSD": {
|
||||
"Microphone Mute OSD": "OSD麦克风静音"
|
||||
},
|
||||
"Minimal palette built around a single hue.": {
|
||||
"Minimal palette built around a single hue.": "围绕单一色调构建的简约配色。"
|
||||
@@ -1187,6 +1211,9 @@
|
||||
"Mode: ": {
|
||||
"Mode: ": "模式: "
|
||||
},
|
||||
"Model": {
|
||||
"Model": "模型"
|
||||
},
|
||||
"Monitor Selection:": {
|
||||
"Monitor Selection:": "选择显示器:"
|
||||
},
|
||||
@@ -1211,6 +1238,9 @@
|
||||
"NM not supported": {
|
||||
"NM not supported": "不支持 NM"
|
||||
},
|
||||
"Name": {
|
||||
"Name": "名称"
|
||||
},
|
||||
"Named Workspace Icons": {
|
||||
"Named Workspace Icons": "已命名工作区图标"
|
||||
},
|
||||
@@ -1337,6 +1367,9 @@
|
||||
"OS Logo": {
|
||||
"OS Logo": "系统 Logo"
|
||||
},
|
||||
"OSD Position": {
|
||||
"OSD Position": "OSD位置"
|
||||
},
|
||||
"Office": {
|
||||
"Office": "办公"
|
||||
},
|
||||
@@ -1346,6 +1379,9 @@
|
||||
"On-Screen Displays": {
|
||||
"On-Screen Displays": "屏幕显示"
|
||||
},
|
||||
"On-screen Displays": {
|
||||
"On-screen Displays": "屏上显示"
|
||||
},
|
||||
"Only adjust gamma based on time or location rules.": {
|
||||
"Only adjust gamma based on time or location rules.": "根据时间或位置调节伽马值。"
|
||||
},
|
||||
@@ -1493,6 +1529,9 @@
|
||||
"Power Profile Degradation": {
|
||||
"Power Profile Degradation": "电源配置性能下降"
|
||||
},
|
||||
"Power Profile OSD": {
|
||||
"Power Profile OSD": "OSD电源配置"
|
||||
},
|
||||
"Pressure": {
|
||||
"Pressure": "气压"
|
||||
},
|
||||
@@ -1575,7 +1614,7 @@
|
||||
"Request confirmation on power off, restart, suspend, hibernate and logout actions": "关机、重启、挂起、休眠和注销前请求确认"
|
||||
},
|
||||
"Requires DWL compositor": {
|
||||
"Requires DWL compositor": "需要DWL合成器"
|
||||
"Requires DWL compositor": "需要 DWL 合成器"
|
||||
},
|
||||
"Reset": {
|
||||
"Reset": "重置"
|
||||
@@ -1587,10 +1626,10 @@
|
||||
"Restart": "重启"
|
||||
},
|
||||
"Restart DMS": {
|
||||
"Restart DMS": "重启DMS"
|
||||
"Restart DMS": "重启 DMS"
|
||||
},
|
||||
"Restart the DankMaterialShell": {
|
||||
"Restart the DankMaterialShell": "重启DankMaterialShell"
|
||||
"Restart the DankMaterialShell": "重启 DankMaterialShell"
|
||||
},
|
||||
"Resume": {
|
||||
"Resume": "恢复"
|
||||
@@ -1611,7 +1650,7 @@
|
||||
"Right Tiling": "右侧平铺"
|
||||
},
|
||||
"Right-click bar widget to cycle": {
|
||||
"Right-click bar widget to cycle": "点击bar上小部件以轮换"
|
||||
"Right-click bar widget to cycle": "点击 bar 上小部件以轮换"
|
||||
},
|
||||
"Run User Templates": {
|
||||
"Run User Templates": "运行用户模板"
|
||||
@@ -1647,7 +1686,7 @@
|
||||
"Science": "科学"
|
||||
},
|
||||
"Screen sharing": {
|
||||
"Screen sharing": ""
|
||||
"Screen sharing": "屏幕分享"
|
||||
},
|
||||
"Scrolling": {
|
||||
"Scrolling": "滚动"
|
||||
@@ -1755,7 +1794,7 @@
|
||||
"Show Reboot": "显示重启"
|
||||
},
|
||||
"Show Restart DMS": {
|
||||
"Show Restart DMS": "显示重启DMS"
|
||||
"Show Restart DMS": "显示重启 DMS"
|
||||
},
|
||||
"Show Suspend": {
|
||||
"Show Suspend": "显示挂起"
|
||||
@@ -1781,6 +1820,24 @@
|
||||
"Show on screens:": {
|
||||
"Show on screens:": "选择显示的屏幕:"
|
||||
},
|
||||
"Show on-screen display when brightness changes": {
|
||||
"Show on-screen display when brightness changes": "当亮度改变时显示OSD"
|
||||
},
|
||||
"Show on-screen display when caps lock state changes": {
|
||||
"Show on-screen display when caps lock state changes": "当大小写状态变化时显示OSD"
|
||||
},
|
||||
"Show on-screen display when idle inhibitor state changes": {
|
||||
"Show on-screen display when idle inhibitor state changes": "当空闲抑制状态改变时显示OSD"
|
||||
},
|
||||
"Show on-screen display when microphone is muted/unmuted": {
|
||||
"Show on-screen display when microphone is muted/unmuted": "当麦克风静音状态切换时显示OSD"
|
||||
},
|
||||
"Show on-screen display when power profile changes": {
|
||||
"Show on-screen display when power profile changes": "当电源配置改变时显示OSD"
|
||||
},
|
||||
"Show on-screen display when volume changes": {
|
||||
"Show on-screen display when volume changes": "当音量变化时显示OSD"
|
||||
},
|
||||
"Show only apps running in current workspace": {
|
||||
"Show only apps running in current workspace": "仅显示当前工作区中的活动应用"
|
||||
},
|
||||
@@ -2115,7 +2172,7 @@
|
||||
"VRR: ": "可变刷新率: "
|
||||
},
|
||||
"Vertical Deck": {
|
||||
"Vertical Deck": "垂直Deck"
|
||||
"Vertical Deck": "垂直 Deck"
|
||||
},
|
||||
"Vertical Grid": {
|
||||
"Vertical Grid": "垂直网格"
|
||||
@@ -2141,6 +2198,9 @@
|
||||
"Volume Changed": {
|
||||
"Volume Changed": "音量变化"
|
||||
},
|
||||
"Volume OSD": {
|
||||
"Volume OSD": "OSD音量"
|
||||
},
|
||||
"Volume, brightness, and other system OSDs": {
|
||||
"Volume, brightness, and other system OSDs": "音量、亮度和其他系统屏幕显示"
|
||||
},
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
"Add a VPN in NetworkManager": "新增VPN至網路管理器"
|
||||
},
|
||||
"Adjust the number of columns in grid view mode.": {
|
||||
"Adjust the number of columns in grid view mode.": ""
|
||||
"Adjust the number of columns in grid view mode.": "調整網格檢視模式中的欄數。"
|
||||
},
|
||||
"All": {
|
||||
"All": "所有"
|
||||
@@ -75,7 +75,7 @@
|
||||
"Always Show OSD Percentage": "OSD 始終顯示百分比"
|
||||
},
|
||||
"Always on icons": {
|
||||
"Always on icons": ""
|
||||
"Always on icons": "始終顯示圖示"
|
||||
},
|
||||
"Always show a minimum of 3 workspaces, even if fewer are available": {
|
||||
"Always show a minimum of 3 workspaces, even if fewer are available": "始終顯示至少 3 個工作區,即使可用的工作區較少"
|
||||
@@ -275,6 +275,9 @@
|
||||
"Brightness": {
|
||||
"Brightness": "亮度"
|
||||
},
|
||||
"Brightness OSD": {
|
||||
"Brightness OSD": "亮度 OSD"
|
||||
},
|
||||
"Browse": {
|
||||
"Browse": "瀏覽"
|
||||
},
|
||||
@@ -303,7 +306,7 @@
|
||||
"CUPS Missing Filter Warning": "CUPS 缺少過濾器警告"
|
||||
},
|
||||
"Camera": {
|
||||
"Camera": ""
|
||||
"Camera": "相機"
|
||||
},
|
||||
"Cancel": {
|
||||
"Cancel": "取消"
|
||||
@@ -312,7 +315,10 @@
|
||||
"Capacity": "容量"
|
||||
},
|
||||
"Caps Lock Indicator": {
|
||||
"Caps Lock Indicator": ""
|
||||
"Caps Lock Indicator": "大小寫鎖定指示器"
|
||||
},
|
||||
"Caps Lock OSD": {
|
||||
"Caps Lock OSD": "大小寫鎖定 OSD"
|
||||
},
|
||||
"Center Section": {
|
||||
"Center Section": "中間區塊"
|
||||
@@ -341,6 +347,9 @@
|
||||
"Choose where notification popups appear on screen": {
|
||||
"Choose where notification popups appear on screen": "選擇通知彈出視窗在螢幕上出現的位置"
|
||||
},
|
||||
"Choose where on-screen displays appear on screen": {
|
||||
"Choose where on-screen displays appear on screen": "選擇螢幕顯示出現在螢幕上的位置"
|
||||
},
|
||||
"Clear": {
|
||||
"Clear": "清除"
|
||||
},
|
||||
@@ -617,6 +626,9 @@
|
||||
"Dismiss": {
|
||||
"Dismiss": "忽略"
|
||||
},
|
||||
"Display Name Format": {
|
||||
"Display Name Format": "顯示名稱格式"
|
||||
},
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": {
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": "顯示一個帶有固定和正在運行的應用程式的 Dock,這些應用程式可以放置在螢幕的頂部、底部、左側或右側邊緣"
|
||||
},
|
||||
@@ -633,7 +645,7 @@
|
||||
"Display currently focused application title": "顯示目前焦點應用程式的標題"
|
||||
},
|
||||
"Display power menu actions in a grid instead of a list": {
|
||||
"Display power menu actions in a grid instead of a list": ""
|
||||
"Display power menu actions in a grid instead of a list": "以網格而非列表顯示電源選單操作"
|
||||
},
|
||||
"Display settings for ": {
|
||||
"Display settings for ": "顯示設定適用於"
|
||||
@@ -674,6 +686,9 @@
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": {
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "拖曳部件即可在版塊內重新排序。使用眼睛圖示隱藏/顯示部件 (會保持間距),或使用 X 將其完全移除。"
|
||||
},
|
||||
"Duplicate Wallpaper with Blur": {
|
||||
"Duplicate Wallpaper with Blur": "模糊化重複桌布"
|
||||
},
|
||||
"Duration": {
|
||||
"Duration": "持續時間"
|
||||
},
|
||||
@@ -749,6 +764,9 @@
|
||||
"Enter password for ": {
|
||||
"Enter password for ": "輸入密碼 "
|
||||
},
|
||||
"Enter this passkey on ": {
|
||||
"Enter this passkey on ": ""
|
||||
},
|
||||
"Error": {
|
||||
"Error": "錯誤"
|
||||
},
|
||||
@@ -900,7 +918,7 @@
|
||||
"Grid": "網格"
|
||||
},
|
||||
"Grid Columns": {
|
||||
"Grid Columns": ""
|
||||
"Grid Columns": "網格欄數"
|
||||
},
|
||||
"Group by App": {
|
||||
"Group by App": "App 分組"
|
||||
@@ -924,7 +942,7 @@
|
||||
"Hibernate": "休眠"
|
||||
},
|
||||
"Hide Delay (ms)": {
|
||||
"Hide Delay (ms)": ""
|
||||
"Hide Delay (ms)": "隱藏延遲 (毫秒)"
|
||||
},
|
||||
"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"
|
||||
@@ -959,6 +977,9 @@
|
||||
"Idle Inhibitor": {
|
||||
"Idle Inhibitor": "空閒抑制器"
|
||||
},
|
||||
"Idle Inhibitor OSD": {
|
||||
"Idle Inhibitor OSD": "閒置抑制器 OSD"
|
||||
},
|
||||
"Idle Settings": {
|
||||
"Idle Settings": "閒置設定"
|
||||
},
|
||||
@@ -1173,7 +1194,10 @@
|
||||
"Memory usage indicator": "記憶體使用率指示器"
|
||||
},
|
||||
"Microphone": {
|
||||
"Microphone": ""
|
||||
"Microphone": "麥克風"
|
||||
},
|
||||
"Microphone Mute OSD": {
|
||||
"Microphone Mute OSD": "麥克風靜音 OSD"
|
||||
},
|
||||
"Minimal palette built around a single hue.": {
|
||||
"Minimal palette built around a single hue.": "圍繞單一色調構建的最小調色板。"
|
||||
@@ -1187,6 +1211,9 @@
|
||||
"Mode: ": {
|
||||
"Mode: ": "模式:"
|
||||
},
|
||||
"Model": {
|
||||
"Model": "型號"
|
||||
},
|
||||
"Monitor Selection:": {
|
||||
"Monitor Selection:": "螢幕選擇:"
|
||||
},
|
||||
@@ -1211,6 +1238,9 @@
|
||||
"NM not supported": {
|
||||
"NM not supported": "NM 不支援"
|
||||
},
|
||||
"Name": {
|
||||
"Name": "名稱"
|
||||
},
|
||||
"Named Workspace Icons": {
|
||||
"Named Workspace Icons": "命名工作區圖示"
|
||||
},
|
||||
@@ -1337,6 +1367,9 @@
|
||||
"OS Logo": {
|
||||
"OS Logo": "發行版 Logo"
|
||||
},
|
||||
"OSD Position": {
|
||||
"OSD Position": "OSD 位置"
|
||||
},
|
||||
"Office": {
|
||||
"Office": "辦公"
|
||||
},
|
||||
@@ -1346,6 +1379,9 @@
|
||||
"On-Screen Displays": {
|
||||
"On-Screen Displays": "螢幕顯示"
|
||||
},
|
||||
"On-screen Displays": {
|
||||
"On-screen Displays": "螢幕顯示"
|
||||
},
|
||||
"Only adjust gamma based on time or location rules.": {
|
||||
"Only adjust gamma based on time or location rules.": "僅根據時間或位置規則調整 gamma。"
|
||||
},
|
||||
@@ -1493,6 +1529,9 @@
|
||||
"Power Profile Degradation": {
|
||||
"Power Profile Degradation": "電源配置降級"
|
||||
},
|
||||
"Power Profile OSD": {
|
||||
"Power Profile OSD": "電源設定檔 OSD"
|
||||
},
|
||||
"Pressure": {
|
||||
"Pressure": "氣壓"
|
||||
},
|
||||
@@ -1647,7 +1686,7 @@
|
||||
"Science": "科學"
|
||||
},
|
||||
"Screen sharing": {
|
||||
"Screen sharing": ""
|
||||
"Screen sharing": "螢幕分享"
|
||||
},
|
||||
"Scrolling": {
|
||||
"Scrolling": "滾動"
|
||||
@@ -1781,6 +1820,24 @@
|
||||
"Show on screens:": {
|
||||
"Show on screens:": "在螢幕上顯示:"
|
||||
},
|
||||
"Show on-screen display when brightness changes": {
|
||||
"Show on-screen display when brightness changes": "亮度改變時顯示螢幕顯示"
|
||||
},
|
||||
"Show on-screen display when caps lock state changes": {
|
||||
"Show on-screen display when caps lock state changes": "大小寫鎖定狀態改變時顯示螢幕顯示"
|
||||
},
|
||||
"Show on-screen display when idle inhibitor state changes": {
|
||||
"Show on-screen display when idle inhibitor state changes": "閒置抑制器狀態改變時顯示螢幕顯示"
|
||||
},
|
||||
"Show on-screen display when microphone is muted/unmuted": {
|
||||
"Show on-screen display when microphone is muted/unmuted": "麥克風靜音/取消靜音時顯示螢幕顯示"
|
||||
},
|
||||
"Show on-screen display when power profile changes": {
|
||||
"Show on-screen display when power profile changes": "電源設定檔改變時顯示螢幕顯示"
|
||||
},
|
||||
"Show on-screen display when volume changes": {
|
||||
"Show on-screen display when volume changes": "音量改變時顯示螢幕顯示"
|
||||
},
|
||||
"Show only apps running in current workspace": {
|
||||
"Show only apps running in current workspace": "僅顯示目前工作區中正在執行的應用程式"
|
||||
},
|
||||
@@ -1809,7 +1866,7 @@
|
||||
"Shows current workspace and allows switching": "顯示目前工作區並允許切換"
|
||||
},
|
||||
"Shows when caps lock is active": {
|
||||
"Shows when caps lock is active": ""
|
||||
"Shows when caps lock is active": "顯示大小寫鎖定啟用時"
|
||||
},
|
||||
"Shows when microphone, camera, or screen sharing is active": {
|
||||
"Shows when microphone, camera, or screen sharing is active": "顯示麥克風、攝影機或螢幕共用處於活動狀態"
|
||||
@@ -2055,7 +2112,7 @@
|
||||
"Use Fahrenheit instead of Celsius for temperature": "使用華氏度代替攝氏度來表示溫度"
|
||||
},
|
||||
"Use Grid Layout": {
|
||||
"Use Grid Layout": ""
|
||||
"Use Grid Layout": "使用網格佈局"
|
||||
},
|
||||
"Use IP Location": {
|
||||
"Use IP Location": "使用 IP 位置"
|
||||
@@ -2141,6 +2198,9 @@
|
||||
"Volume Changed": {
|
||||
"Volume Changed": "音量改變"
|
||||
},
|
||||
"Volume OSD": {
|
||||
"Volume OSD": "音量 OSD"
|
||||
},
|
||||
"Volume, brightness, and other system OSDs": {
|
||||
"Volume, brightness, and other system OSDs": "音量、亮度及其他系統OSD"
|
||||
},
|
||||
|
||||
@@ -566,13 +566,6 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Blur Layer",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Blur on Overview",
|
||||
"translation": "",
|
||||
@@ -643,6 +636,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Brightness OSD",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Browse",
|
||||
"translation": "",
|
||||
@@ -734,6 +734,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Caps Lock OSD",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Center Section",
|
||||
"translation": "",
|
||||
@@ -797,6 +804,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Choose where on-screen displays appear on screen",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Clear",
|
||||
"translation": "",
|
||||
@@ -1441,6 +1455,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Display Name Format",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen",
|
||||
"translation": "",
|
||||
@@ -1574,6 +1595,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Duplicate Wallpaper with Blur",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Duration",
|
||||
"translation": "",
|
||||
@@ -1749,6 +1777,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Enter this passkey on ",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Error",
|
||||
"translation": "",
|
||||
@@ -2232,6 +2267,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Idle Inhibitor OSD",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Idle Settings",
|
||||
"translation": "",
|
||||
@@ -2736,6 +2778,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Microphone Mute OSD",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Minimal palette built around a single hue.",
|
||||
"translation": "",
|
||||
@@ -2764,6 +2813,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Model",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Monitor Selection:",
|
||||
"translation": "",
|
||||
@@ -2820,6 +2876,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Name",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Named Workspace Icons",
|
||||
"translation": "",
|
||||
@@ -3114,6 +3177,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "OSD Position",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Office",
|
||||
"translation": "",
|
||||
@@ -3135,6 +3205,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "On-screen Displays",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Only adjust gamma based on time or location rules.",
|
||||
"translation": "",
|
||||
@@ -3478,6 +3555,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Power Profile OSD",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Pressure",
|
||||
"translation": "",
|
||||
@@ -4143,6 +4227,48 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Show on-screen display when brightness changes",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Show on-screen display when caps lock state changes",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Show on-screen display when idle inhibitor state changes",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Show on-screen display when microphone is muted/unmuted",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Show on-screen display when power profile changes",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Show on-screen display when volume changes",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Show only apps running in current workspace",
|
||||
"translation": "",
|
||||
@@ -4969,6 +5095,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Volume OSD",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Volume, brightness, and other system OSDs",
|
||||
"translation": "",
|
||||
|
||||
Reference in New Issue
Block a user