Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
X
ximperconf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ximper Linux
ximperconf
Commits
49bb8224
Verified
Commit
49bb8224
authored
Feb 07, 2026
by
Kirill Unitsaev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
hyprland/wallpaper: add wallpaper management commands
parent
aa008de8
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
550 additions
and
0 deletions
+550
-0
commands.go
hyprland/commands.go
+2
-0
actions.go
hyprland/wallpaper/actions.go
+195
-0
backend-hyprpaper.go
hyprland/wallpaper/backend-hyprpaper.go
+20
-0
backend.go
hyprland/wallpaper/backend.go
+25
-0
commands.go
hyprland/wallpaper/commands.go
+75
-0
wallpaper.go
hyprland/wallpaper/wallpaper.go
+233
-0
No files found.
hyprland/commands.go
View file @
49bb8224
...
...
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"ximperconf/config"
"ximperconf/hyprland/wallpaper"
"github.com/urfave/cli/v3"
)
...
...
@@ -232,6 +233,7 @@ func CommandList() *cli.Command {
},
},
},
wallpaper
.
CommandList
(),
},
}
}
...
...
hyprland/wallpaper/actions.go
0 → 100644
View file @
49bb8224
package
wallpaper
import
(
"context"
"fmt"
"ximperconf/config"
"ximperconf/ui"
"github.com/fatih/color"
"github.com/urfave/cli/v3"
)
func
WallpaperSetCommand
(
ctx
context
.
Context
,
cmd
*
cli
.
Command
)
error
{
lightPath
:=
cmd
.
String
(
"light"
)
darkPath
:=
cmd
.
String
(
"dark"
)
monitor
:=
cmd
.
String
(
"monitor"
)
if
monitor
==
"default"
{
monitor
=
""
}
if
lightPath
==
""
&&
darkPath
==
""
{
return
fmt
.
Errorf
(
"укажите --light и/или --dark"
)
}
manager
,
err
:=
NewWallpaperManager
()
if
err
!=
nil
{
return
err
}
monitors
:=
[]
string
{
monitor
}
if
monitor
==
"all"
{
monitors
,
err
=
GetHyprlandMonitors
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"не удалось получить список мониторов: %w"
,
err
)
}
}
for
_
,
mon
:=
range
monitors
{
if
err
:=
manager
.
SetWallpaper
(
lightPath
,
darkPath
,
mon
);
err
!=
nil
{
return
err
}
}
if
err
:=
manager
.
Save
();
err
!=
nil
{
return
err
}
color
.
Green
(
"Обои сохранены в конфиг"
)
theme
:=
manager
.
GetCurrentTheme
()
if
theme
==
""
{
if
darkPath
!=
""
{
theme
=
ThemeDark
}
else
{
theme
=
ThemeLight
}
manager
.
SetCurrentTheme
(
theme
)
manager
.
Save
()
}
if
err
:=
manager
.
ApplyAll
(
theme
);
err
!=
nil
{
color
.
Yellow
(
"Не удалось применить обои: %v"
,
err
)
}
else
{
color
.
Green
(
"Обои применены"
)
}
return
nil
}
func
WallpaperGetCommand
(
ctx
context
.
Context
,
cmd
*
cli
.
Command
)
error
{
manager
,
err
:=
NewWallpaperManager
()
if
err
!=
nil
{
return
err
}
monitor
:=
cmd
.
String
(
"monitor"
)
if
monitor
==
"default"
{
monitor
=
""
}
if
cmd
.
Bool
(
"pair"
)
{
light
:=
manager
.
GetWallpaper
(
monitor
,
ThemeLight
)
dark
:=
manager
.
GetWallpaper
(
monitor
,
ThemeDark
)
fmt
.
Printf
(
"[
\"
%s
\"
,
\"
%s
\"
]
\n
"
,
light
,
dark
)
return
nil
}
var
theme
ThemeType
if
cmd
.
Bool
(
"light"
)
{
theme
=
ThemeLight
}
else
if
cmd
.
Bool
(
"dark"
)
{
theme
=
ThemeDark
}
else
{
theme
=
manager
.
GetCurrentTheme
()
if
theme
==
""
{
return
fmt
.
Errorf
(
"укажите --light или --dark, либо установите текущую тему через apply"
)
}
}
path
:=
manager
.
GetWallpaper
(
monitor
,
theme
)
if
config
.
IsJSON
(
cmd
)
{
return
ui
.
PrintJSON
(
map
[
string
]
string
{
"path"
:
path
,
"monitor"
:
monitor
,
"theme"
:
string
(
theme
),
})
}
if
path
==
""
{
return
fmt
.
Errorf
(
"обои не настроены"
)
}
fmt
.
Println
(
path
)
return
nil
}
func
WallpaperApplyCommand
(
ctx
context
.
Context
,
cmd
*
cli
.
Command
)
error
{
themeArg
:=
cmd
.
Args
()
.
Get
(
0
)
manager
,
err
:=
NewWallpaperManager
()
if
err
!=
nil
{
return
err
}
var
targetTheme
ThemeType
if
themeArg
!=
""
{
if
themeArg
!=
"light"
&&
themeArg
!=
"dark"
{
return
fmt
.
Errorf
(
"укажите тему: light или dark"
)
}
targetTheme
=
ThemeType
(
themeArg
)
manager
.
SetCurrentTheme
(
targetTheme
)
if
err
:=
manager
.
Save
();
err
!=
nil
{
return
err
}
}
else
{
targetTheme
=
manager
.
GetCurrentTheme
()
if
targetTheme
==
""
{
return
fmt
.
Errorf
(
"текущая тема не установлена, укажите light или dark"
)
}
}
if
err
:=
manager
.
ApplyAll
(
targetTheme
);
err
!=
nil
{
return
err
}
color
.
Green
(
"Обои применены (тема: %s)"
,
targetTheme
)
return
nil
}
func
WallpaperInfoCommand
(
ctx
context
.
Context
,
cmd
*
cli
.
Command
)
error
{
manager
,
err
:=
NewWallpaperManager
()
if
err
!=
nil
{
return
err
}
monitors
,
err
:=
GetHyprlandMonitors
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"не удалось получить список мониторов: %w"
,
err
)
}
type
monitorEntry
struct
{
Monitor
string
`json:"monitor"`
Light
string
`json:"light"`
Dark
string
`json:"dark"`
}
entries
:=
[]
monitorEntry
{
{
Monitor
:
"default"
,
Light
:
manager
.
Config
.
Default
.
Light
,
Dark
:
manager
.
Config
.
Default
.
Dark
,
},
}
for
_
,
mon
:=
range
monitors
{
entries
=
append
(
entries
,
monitorEntry
{
Monitor
:
mon
,
Light
:
manager
.
GetWallpaper
(
mon
,
ThemeLight
),
Dark
:
manager
.
GetWallpaper
(
mon
,
ThemeDark
),
})
}
if
config
.
IsJSON
(
cmd
)
{
return
ui
.
PrintJSON
(
entries
)
}
for
_
,
e
:=
range
entries
{
fmt
.
Printf
(
"%s:
\n
"
,
e
.
Monitor
)
fmt
.
Printf
(
" light: %s
\n
"
,
e
.
Light
)
fmt
.
Printf
(
" dark: %s
\n
"
,
e
.
Dark
)
}
return
nil
}
hyprland/wallpaper/backend-hyprpaper.go
0 → 100644
View file @
49bb8224
package
wallpaper
import
(
"fmt"
"os/exec"
)
type
HyprpaperBackend
struct
{}
func
(
b
*
HyprpaperBackend
)
Name
()
string
{
return
"hyprpaper"
}
func
(
b
*
HyprpaperBackend
)
SetWallpaper
(
monitor
,
path
string
)
error
{
arg
:=
fmt
.
Sprintf
(
"%s,%s,%s"
,
monitor
,
path
,
"contain"
)
cmd
:=
exec
.
Command
(
"hyprctl"
,
"hyprpaper"
,
"wallpaper"
,
arg
)
out
,
err
:=
cmd
.
CombinedOutput
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"%v: %s"
,
err
,
string
(
out
))
}
return
nil
}
hyprland/wallpaper/backend.go
0 → 100644
View file @
49bb8224
package
wallpaper
import
"fmt"
type
WallpaperBackend
interface
{
Name
()
string
SetWallpaper
(
monitor
,
path
string
)
error
}
var
backends
=
map
[
string
]
WallpaperBackend
{
"hyprpaper"
:
&
HyprpaperBackend
{},
}
const
DefaultBackendName
=
"hyprpaper"
func
ResolveBackend
(
name
string
)
(
WallpaperBackend
,
error
)
{
if
name
==
""
{
name
=
DefaultBackendName
}
b
,
ok
:=
backends
[
name
]
if
!
ok
{
return
nil
,
fmt
.
Errorf
(
"неизвестный бэкенд обоев: %s"
,
name
)
}
return
b
,
nil
}
hyprland/wallpaper/commands.go
0 → 100644
View file @
49bb8224
package
wallpaper
import
(
"ximperconf/config"
"github.com/urfave/cli/v3"
)
func
CommandList
()
*
cli
.
Command
{
return
&
cli
.
Command
{
Name
:
"wallpaper"
,
Usage
:
"Управление обоями"
,
Commands
:
[]
*
cli
.
Command
{
{
Name
:
"set"
,
Usage
:
"установить обои в конфиг"
,
Flags
:
[]
cli
.
Flag
{
&
cli
.
StringFlag
{
Name
:
"light"
,
Usage
:
"путь к обоям для светлой темы"
,
},
&
cli
.
StringFlag
{
Name
:
"dark"
,
Usage
:
"путь к обоям для тёмной темы"
,
},
&
cli
.
StringFlag
{
Name
:
"monitor"
,
Aliases
:
[]
string
{
"m"
},
Usage
:
"имя монитора"
,
},
},
Action
:
WallpaperSetCommand
,
},
{
Name
:
"get"
,
Usage
:
"получить путь к обоям"
,
Flags
:
[]
cli
.
Flag
{
&
cli
.
BoolFlag
{
Name
:
"light"
,
Usage
:
"для светлой темы"
,
},
&
cli
.
BoolFlag
{
Name
:
"dark"
,
Usage
:
"для тёмной темы"
,
},
&
cli
.
BoolFlag
{
Name
:
"pair"
,
Usage
:
"вернуть пару [light, dark]"
,
},
&
cli
.
StringFlag
{
Name
:
"monitor"
,
Aliases
:
[]
string
{
"m"
},
Usage
:
"имя монитора"
,
},
config
.
FormatFlag
,
},
Action
:
WallpaperGetCommand
,
},
{
Name
:
"apply"
,
Usage
:
"применить обои"
,
ArgsUsage
:
"[light|dark]"
,
Action
:
WallpaperApplyCommand
,
},
{
Name
:
"info"
,
Usage
:
"информация о настроенных обоях"
,
Flags
:
[]
cli
.
Flag
{
config
.
FormatFlag
,
},
Action
:
WallpaperInfoCommand
,
},
},
}
}
hyprland/wallpaper/wallpaper.go
0 → 100644
View file @
49bb8224
package
wallpaper
import
(
"encoding/json"
"fmt"
"os"
"os/exec"
"path/filepath"
"ximperconf/utils"
"gopkg.in/yaml.v3"
)
type
ThemeType
string
const
(
ThemeLight
ThemeType
=
"light"
ThemeDark
ThemeType
=
"dark"
)
type
WallpaperEntry
struct
{
Light
string
`yaml:"light,omitempty" json:"light,omitempty"`
Dark
string
`yaml:"dark,omitempty" json:"dark,omitempty"`
}
type
WallpaperConfig
struct
{
Backend
string
`yaml:"backend,omitempty" json:"backend,omitempty"`
CurrentTheme
string
`yaml:"current_theme,omitempty" json:"current_theme,omitempty"`
Monitors
map
[
string
]
WallpaperEntry
`yaml:"monitors,omitempty" json:"monitors,omitempty"`
Default
WallpaperEntry
`yaml:"default,omitempty" json:"default,omitempty"`
}
type
WallpaperManager
struct
{
Config
*
WallpaperConfig
ConfigPath
string
Changed
bool
backend
WallpaperBackend
}
func
NewWallpaperManager
()
(
*
WallpaperManager
,
error
)
{
home
,
err
:=
os
.
UserHomeDir
()
if
err
!=
nil
{
return
nil
,
err
}
configPath
:=
filepath
.
Join
(
home
,
".config"
,
"ximper"
,
"wallpaper.yaml"
)
manager
:=
&
WallpaperManager
{
ConfigPath
:
configPath
,
Config
:
&
WallpaperConfig
{
Monitors
:
make
(
map
[
string
]
WallpaperEntry
),
},
}
if
utils
.
FileExists
(
configPath
)
{
data
,
err
:=
os
.
ReadFile
(
configPath
)
if
err
!=
nil
{
return
nil
,
err
}
if
err
:=
yaml
.
Unmarshal
(
data
,
manager
.
Config
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"ошибка парсинга %s: %w"
,
configPath
,
err
)
}
if
manager
.
Config
.
Monitors
==
nil
{
manager
.
Config
.
Monitors
=
make
(
map
[
string
]
WallpaperEntry
)
}
}
backend
,
err
:=
ResolveBackend
(
manager
.
Config
.
Backend
)
if
err
!=
nil
{
return
nil
,
err
}
manager
.
backend
=
backend
return
manager
,
nil
}
func
(
m
*
WallpaperManager
)
Save
()
error
{
if
!
m
.
Changed
{
return
nil
}
dir
:=
filepath
.
Dir
(
m
.
ConfigPath
)
if
err
:=
os
.
MkdirAll
(
dir
,
0755
);
err
!=
nil
{
return
err
}
data
,
err
:=
yaml
.
Marshal
(
m
.
Config
)
if
err
!=
nil
{
return
err
}
m
.
Changed
=
false
return
os
.
WriteFile
(
m
.
ConfigPath
,
data
,
0644
)
}
func
(
m
*
WallpaperManager
)
SetWallpaper
(
lightPath
,
darkPath
,
monitor
string
)
error
{
if
lightPath
!=
""
{
absPath
,
err
:=
filepath
.
Abs
(
lightPath
)
if
err
!=
nil
{
return
err
}
if
!
utils
.
FileExists
(
absPath
)
{
return
fmt
.
Errorf
(
"файл не найден: %s"
,
absPath
)
}
lightPath
=
absPath
}
if
darkPath
!=
""
{
absPath
,
err
:=
filepath
.
Abs
(
darkPath
)
if
err
!=
nil
{
return
err
}
if
!
utils
.
FileExists
(
absPath
)
{
return
fmt
.
Errorf
(
"файл не найден: %s"
,
absPath
)
}
darkPath
=
absPath
}
if
monitor
==
""
{
if
lightPath
!=
""
{
m
.
Config
.
Default
.
Light
=
lightPath
}
if
darkPath
!=
""
{
m
.
Config
.
Default
.
Dark
=
darkPath
}
}
else
{
entry
:=
m
.
Config
.
Monitors
[
monitor
]
if
lightPath
!=
""
{
entry
.
Light
=
lightPath
}
if
darkPath
!=
""
{
entry
.
Dark
=
darkPath
}
m
.
Config
.
Monitors
[
monitor
]
=
entry
}
m
.
Changed
=
true
return
nil
}
func
(
m
*
WallpaperManager
)
GetWallpaper
(
monitor
string
,
theme
ThemeType
)
string
{
var
entry
WallpaperEntry
var
found
bool
if
monitor
!=
""
{
entry
,
found
=
m
.
Config
.
Monitors
[
monitor
]
}
var
path
string
if
found
{
switch
theme
{
case
ThemeLight
:
path
=
entry
.
Light
case
ThemeDark
:
path
=
entry
.
Dark
}
}
if
path
==
""
{
switch
theme
{
case
ThemeLight
:
path
=
m
.
Config
.
Default
.
Light
case
ThemeDark
:
path
=
m
.
Config
.
Default
.
Dark
}
}
return
path
}
func
(
m
*
WallpaperManager
)
GetCurrentTheme
()
ThemeType
{
return
ThemeType
(
m
.
Config
.
CurrentTheme
)
}
func
(
m
*
WallpaperManager
)
SetCurrentTheme
(
theme
ThemeType
)
{
m
.
Config
.
CurrentTheme
=
string
(
theme
)
m
.
Changed
=
true
}
func
(
m
*
WallpaperManager
)
Apply
(
monitor
string
,
theme
ThemeType
)
error
{
path
:=
m
.
GetWallpaper
(
monitor
,
theme
)
if
path
==
""
{
return
fmt
.
Errorf
(
"обои не настроены для монитора %s, тема %s"
,
monitor
,
theme
)
}
if
!
utils
.
FileExists
(
path
)
{
return
fmt
.
Errorf
(
"файл обоев не найден: %s"
,
path
)
}
if
err
:=
m
.
backend
.
SetWallpaper
(
monitor
,
path
);
err
!=
nil
{
return
fmt
.
Errorf
(
"ошибка установки обоев: %w"
,
err
)
}
return
nil
}
func
(
m
*
WallpaperManager
)
ApplyAll
(
theme
ThemeType
)
error
{
monitors
,
err
:=
GetHyprlandMonitors
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"ошибка получения списка мониторов: %w"
,
err
)
}
for
_
,
mon
:=
range
monitors
{
if
err
:=
m
.
Apply
(
mon
,
theme
);
err
!=
nil
{
return
fmt
.
Errorf
(
"монитор %s: %w"
,
mon
,
err
)
}
}
return
nil
}
func
GetHyprlandMonitors
()
([]
string
,
error
)
{
out
,
err
:=
exec
.
Command
(
"hyprctl"
,
"monitors"
,
"-j"
)
.
Output
()
if
err
!=
nil
{
return
nil
,
err
}
var
monitors
[]
struct
{
Name
string
`json:"name"`
}
if
err
:=
json
.
Unmarshal
(
out
,
&
monitors
);
err
!=
nil
{
return
nil
,
err
}
var
names
[]
string
for
_
,
mon
:=
range
monitors
{
names
=
append
(
names
,
mon
.
Name
)
}
return
names
,
nil
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment