mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-05-13 07:42:46 -04:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8fad2826b1 | |||
| 57ee0fb2bd | |||
| 3ef10e73a5 | |||
| dc40492fc7 | |||
| e606a76a86 | |||
| 8838fd67b9 | |||
| c570e20308 | |||
| 0a00ef39e3 | |||
| 9a08b81214 | |||
| c617ae26a2 | |||
| f6a776a692 | |||
| 54b253099d | |||
| f662aca58c | |||
| 76e7755496 | |||
| e05ad81c13 | |||
| cffb16d7f7 | |||
| 18ca571944 | |||
| 3ae1973e21 | |||
| 308c8c3ea7 | |||
| f49b5dd037 | |||
| f245ba82ad | |||
| 60d22d6973 | |||
| d6f48a82d9 | |||
| c0d73dae67 | |||
| 49eb60589d | |||
| 89993b7421 |
@@ -0,0 +1,30 @@
|
||||
name: Check nix flake
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master, main]
|
||||
paths:
|
||||
- "flake.*"
|
||||
- "distro/nix/**"
|
||||
jobs:
|
||||
check-flake:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Create GitHub App token
|
||||
id: app_token
|
||||
uses: actions/create-github-app-token@v1
|
||||
with:
|
||||
app-id: ${{ secrets.APP_ID }}
|
||||
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ steps.app_token.outputs.token }}
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v31
|
||||
|
||||
- name: Update vendorHash in flake.nix
|
||||
run: nix flake check
|
||||
+4
-33
@@ -102,39 +102,6 @@ go.work.sum
|
||||
# .idea/
|
||||
# .vscode/
|
||||
|
||||
# If you prefer the allow list template instead of the deny list, see community template:
|
||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||
#
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Code coverage profiles and other test artifacts
|
||||
*.out
|
||||
coverage.*
|
||||
*.coverprofile
|
||||
profile.cov
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
go.work.sum
|
||||
|
||||
# env file
|
||||
.env
|
||||
|
||||
# Editor/IDE
|
||||
# .idea/
|
||||
# .vscode/
|
||||
|
||||
bin/
|
||||
|
||||
# Extracted source trees in Ubuntu package directories
|
||||
@@ -142,3 +109,7 @@ distro/ubuntu/*/dms-git-repo/
|
||||
distro/ubuntu/*/DankMaterialShell-*/
|
||||
distro/ubuntu/danklinux/*/dsearch-*/
|
||||
distro/ubuntu/danklinux/*/dgop-*/
|
||||
|
||||
# direnv
|
||||
.envrc
|
||||
.direnv/
|
||||
|
||||
@@ -12,6 +12,21 @@ Enable pre-commit hooks to catch CI failures before pushing:
|
||||
git config core.hooksPath .githooks
|
||||
```
|
||||
|
||||
### Nix Development Shell
|
||||
|
||||
If you have Nix installed with flakes enabled, you can use the provided development shell which includes all necessary dependencies:
|
||||
|
||||
```bash
|
||||
nix develop
|
||||
```
|
||||
|
||||
This will provide:
|
||||
- Go 1.24 toolchain (go, gopls, delve, go-tools) and GNU Make
|
||||
- Quickshell and required QML packages
|
||||
- Properly configured QML2_IMPORT_PATH
|
||||
|
||||
The dev shell automatically creates the `.qmlls.ini` file in the `quickshell/` directory.
|
||||
|
||||
## VSCode Setup
|
||||
|
||||
This is a monorepo, the easiest thing to do is to open an editor in either `quickshell`, `core`, or both depending on which part of the project you are working on.
|
||||
|
||||
@@ -21,6 +21,7 @@ linters:
|
||||
# Signal handling
|
||||
- (*os.Process).Signal
|
||||
- (*os.Process).Kill
|
||||
- syscall.Kill
|
||||
# DBus cleanup
|
||||
- (*github.com/godbus/dbus/v5.Conn).RemoveMatchSignal
|
||||
- (*github.com/godbus/dbus/v5.Conn).RemoveSignal
|
||||
|
||||
@@ -454,7 +454,6 @@ func uninstallPluginCLI(idOrName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// getCommonCommands returns the commands available in all builds
|
||||
func getCommonCommands() []*cobra.Command {
|
||||
return []*cobra.Command{
|
||||
versionCmd,
|
||||
@@ -474,5 +473,6 @@ func getCommonCommands() []*cobra.Command {
|
||||
colorCmd,
|
||||
screenshotCmd,
|
||||
notifyActionCmd,
|
||||
matugenCmd,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@ import (
|
||||
)
|
||||
|
||||
var dank16Cmd = &cobra.Command{
|
||||
Use: "dank16 <hex_color>",
|
||||
Use: "dank16 [hex_color]",
|
||||
Short: "Generate Base16 color palettes",
|
||||
Long: "Generate Base16 color palettes from a color with support for various output formats",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Run: runDank16,
|
||||
}
|
||||
|
||||
func init() {
|
||||
dank16Cmd.Flags().Bool("light", false, "Generate light theme variant")
|
||||
dank16Cmd.Flags().Bool("light", false, "Generate light theme variant (sets default to light)")
|
||||
dank16Cmd.Flags().Bool("json", false, "Output in JSON format")
|
||||
dank16Cmd.Flags().Bool("kitty", false, "Output in Kitty terminal format")
|
||||
dank16Cmd.Flags().Bool("foot", false, "Output in Foot terminal format")
|
||||
@@ -27,17 +27,15 @@ func init() {
|
||||
dank16Cmd.Flags().Bool("wezterm", false, "Output in Wezterm terminal format")
|
||||
dank16Cmd.Flags().String("background", "", "Custom background color")
|
||||
dank16Cmd.Flags().String("contrast", "dps", "Contrast algorithm: dps (Delta Phi Star, default) or wcag")
|
||||
dank16Cmd.Flags().Bool("variants", false, "Output all variants (dark/light/default) in JSON")
|
||||
dank16Cmd.Flags().String("primary-dark", "", "Primary color for dark mode (use with --variants)")
|
||||
dank16Cmd.Flags().String("primary-light", "", "Primary color for light mode (use with --variants)")
|
||||
_ = dank16Cmd.RegisterFlagCompletionFunc("contrast", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return []string{"dps", "wcag"}, cobra.ShellCompDirectiveNoFileComp
|
||||
})
|
||||
}
|
||||
|
||||
func runDank16(cmd *cobra.Command, args []string) {
|
||||
primaryColor := args[0]
|
||||
if !strings.HasPrefix(primaryColor, "#") {
|
||||
primaryColor = "#" + primaryColor
|
||||
}
|
||||
|
||||
isLight, _ := cmd.Flags().GetBool("light")
|
||||
isJson, _ := cmd.Flags().GetBool("json")
|
||||
isKitty, _ := cmd.Flags().GetBool("kitty")
|
||||
@@ -47,16 +45,57 @@ func runDank16(cmd *cobra.Command, args []string) {
|
||||
isWezterm, _ := cmd.Flags().GetBool("wezterm")
|
||||
background, _ := cmd.Flags().GetString("background")
|
||||
contrastAlgo, _ := cmd.Flags().GetString("contrast")
|
||||
useVariants, _ := cmd.Flags().GetBool("variants")
|
||||
primaryDark, _ := cmd.Flags().GetString("primary-dark")
|
||||
primaryLight, _ := cmd.Flags().GetString("primary-light")
|
||||
|
||||
if background != "" && !strings.HasPrefix(background, "#") {
|
||||
background = "#" + background
|
||||
}
|
||||
if primaryDark != "" && !strings.HasPrefix(primaryDark, "#") {
|
||||
primaryDark = "#" + primaryDark
|
||||
}
|
||||
if primaryLight != "" && !strings.HasPrefix(primaryLight, "#") {
|
||||
primaryLight = "#" + primaryLight
|
||||
}
|
||||
|
||||
contrastAlgo = strings.ToLower(contrastAlgo)
|
||||
if contrastAlgo != "dps" && contrastAlgo != "wcag" {
|
||||
log.Fatalf("Invalid contrast algorithm: %s (must be 'dps' or 'wcag')", contrastAlgo)
|
||||
}
|
||||
|
||||
if useVariants {
|
||||
if primaryDark == "" || primaryLight == "" {
|
||||
if len(args) == 0 {
|
||||
log.Fatalf("--variants requires either a positional color argument or both --primary-dark and --primary-light")
|
||||
}
|
||||
primaryColor := args[0]
|
||||
if !strings.HasPrefix(primaryColor, "#") {
|
||||
primaryColor = "#" + primaryColor
|
||||
}
|
||||
primaryDark = primaryColor
|
||||
primaryLight = primaryColor
|
||||
}
|
||||
variantOpts := dank16.VariantOptions{
|
||||
PrimaryDark: primaryDark,
|
||||
PrimaryLight: primaryLight,
|
||||
Background: background,
|
||||
UseDPS: contrastAlgo == "dps",
|
||||
IsLightMode: isLight,
|
||||
}
|
||||
variantColors := dank16.GenerateVariantPalette(variantOpts)
|
||||
fmt.Print(dank16.GenerateVariantJSON(variantColors))
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
log.Fatalf("A color argument is required (or use --variants with --primary-dark and --primary-light)")
|
||||
}
|
||||
primaryColor := args[0]
|
||||
if !strings.HasPrefix(primaryColor, "#") {
|
||||
primaryColor = "#" + primaryColor
|
||||
}
|
||||
|
||||
opts := dank16.PaletteOptions{
|
||||
IsLight: isLight,
|
||||
Background: background,
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/matugen"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var matugenCmd = &cobra.Command{
|
||||
Use: "matugen",
|
||||
Short: "Generate Material Design themes",
|
||||
Long: "Generate Material Design themes using matugen with dank16 color integration",
|
||||
}
|
||||
|
||||
var matugenGenerateCmd = &cobra.Command{
|
||||
Use: "generate",
|
||||
Short: "Generate theme synchronously",
|
||||
Run: runMatugenGenerate,
|
||||
}
|
||||
|
||||
var matugenQueueCmd = &cobra.Command{
|
||||
Use: "queue",
|
||||
Short: "Queue theme generation (uses socket if available)",
|
||||
Run: runMatugenQueue,
|
||||
}
|
||||
|
||||
func init() {
|
||||
matugenCmd.AddCommand(matugenGenerateCmd)
|
||||
matugenCmd.AddCommand(matugenQueueCmd)
|
||||
|
||||
for _, cmd := range []*cobra.Command{matugenGenerateCmd, matugenQueueCmd} {
|
||||
cmd.Flags().String("state-dir", "", "State directory for cache files")
|
||||
cmd.Flags().String("shell-dir", "", "DMS shell installation directory")
|
||||
cmd.Flags().String("config-dir", "", "User config directory")
|
||||
cmd.Flags().String("kind", "image", "Source type: image or hex")
|
||||
cmd.Flags().String("value", "", "Wallpaper path or hex color")
|
||||
cmd.Flags().String("mode", "dark", "Color mode: dark or light")
|
||||
cmd.Flags().String("icon-theme", "System Default", "Icon theme name")
|
||||
cmd.Flags().String("matugen-type", "scheme-tonal-spot", "Matugen scheme type")
|
||||
cmd.Flags().Bool("run-user-templates", true, "Run user matugen templates")
|
||||
cmd.Flags().String("stock-colors", "", "Stock theme colors JSON")
|
||||
cmd.Flags().Bool("sync-mode-with-portal", false, "Sync color scheme with GNOME portal")
|
||||
cmd.Flags().Bool("terminals-always-dark", false, "Force terminal themes to dark variant")
|
||||
}
|
||||
|
||||
matugenQueueCmd.Flags().Bool("wait", true, "Wait for completion")
|
||||
matugenQueueCmd.Flags().Duration("timeout", 30*time.Second, "Timeout for waiting")
|
||||
}
|
||||
|
||||
func buildMatugenOptions(cmd *cobra.Command) matugen.Options {
|
||||
stateDir, _ := cmd.Flags().GetString("state-dir")
|
||||
shellDir, _ := cmd.Flags().GetString("shell-dir")
|
||||
configDir, _ := cmd.Flags().GetString("config-dir")
|
||||
kind, _ := cmd.Flags().GetString("kind")
|
||||
value, _ := cmd.Flags().GetString("value")
|
||||
mode, _ := cmd.Flags().GetString("mode")
|
||||
iconTheme, _ := cmd.Flags().GetString("icon-theme")
|
||||
matugenType, _ := cmd.Flags().GetString("matugen-type")
|
||||
runUserTemplates, _ := cmd.Flags().GetBool("run-user-templates")
|
||||
stockColors, _ := cmd.Flags().GetString("stock-colors")
|
||||
syncModeWithPortal, _ := cmd.Flags().GetBool("sync-mode-with-portal")
|
||||
terminalsAlwaysDark, _ := cmd.Flags().GetBool("terminals-always-dark")
|
||||
|
||||
return matugen.Options{
|
||||
StateDir: stateDir,
|
||||
ShellDir: shellDir,
|
||||
ConfigDir: configDir,
|
||||
Kind: kind,
|
||||
Value: value,
|
||||
Mode: mode,
|
||||
IconTheme: iconTheme,
|
||||
MatugenType: matugenType,
|
||||
RunUserTemplates: runUserTemplates,
|
||||
StockColors: stockColors,
|
||||
SyncModeWithPortal: syncModeWithPortal,
|
||||
TerminalsAlwaysDark: terminalsAlwaysDark,
|
||||
}
|
||||
}
|
||||
|
||||
func runMatugenGenerate(cmd *cobra.Command, args []string) {
|
||||
opts := buildMatugenOptions(cmd)
|
||||
if err := matugen.Run(opts); err != nil {
|
||||
log.Fatalf("Theme generation failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func runMatugenQueue(cmd *cobra.Command, args []string) {
|
||||
opts := buildMatugenOptions(cmd)
|
||||
wait, _ := cmd.Flags().GetBool("wait")
|
||||
timeout, _ := cmd.Flags().GetDuration("timeout")
|
||||
|
||||
socketPath := os.Getenv("DMS_SOCKET")
|
||||
if socketPath == "" {
|
||||
var err error
|
||||
socketPath, err = server.FindSocket()
|
||||
if err != nil {
|
||||
log.Info("No socket available, running synchronously")
|
||||
if err := matugen.Run(opts); err != nil {
|
||||
log.Fatalf("Theme generation failed: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
conn, err := net.Dial("unix", socketPath)
|
||||
if err != nil {
|
||||
log.Info("Socket connection failed, running synchronously")
|
||||
if err := matugen.Run(opts); err != nil {
|
||||
log.Fatalf("Theme generation failed: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
request := map[string]any{
|
||||
"id": 1,
|
||||
"method": "matugen.queue",
|
||||
"params": map[string]any{
|
||||
"stateDir": opts.StateDir,
|
||||
"shellDir": opts.ShellDir,
|
||||
"configDir": opts.ConfigDir,
|
||||
"kind": opts.Kind,
|
||||
"value": opts.Value,
|
||||
"mode": opts.Mode,
|
||||
"iconTheme": opts.IconTheme,
|
||||
"matugenType": opts.MatugenType,
|
||||
"runUserTemplates": opts.RunUserTemplates,
|
||||
"stockColors": opts.StockColors,
|
||||
"syncModeWithPortal": opts.SyncModeWithPortal,
|
||||
"terminalsAlwaysDark": opts.TerminalsAlwaysDark,
|
||||
"wait": wait,
|
||||
},
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(conn).Encode(request); err != nil {
|
||||
log.Fatalf("Failed to send request: %v", err)
|
||||
}
|
||||
|
||||
if !wait {
|
||||
fmt.Println("Theme generation queued")
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
resultCh := make(chan error, 1)
|
||||
go func() {
|
||||
var response struct {
|
||||
ID int `json:"id"`
|
||||
Result any `json:"result"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
if err := json.NewDecoder(conn).Decode(&response); err != nil {
|
||||
resultCh <- fmt.Errorf("failed to read response: %w", err)
|
||||
return
|
||||
}
|
||||
if response.Error != "" {
|
||||
resultCh <- fmt.Errorf("server error: %s", response.Error)
|
||||
return
|
||||
}
|
||||
resultCh <- nil
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-resultCh:
|
||||
if err != nil {
|
||||
log.Fatalf("Theme generation failed: %v", err)
|
||||
}
|
||||
fmt.Println("Theme generation completed")
|
||||
case <-ctx.Done():
|
||||
log.Fatalf("Timeout waiting for theme generation")
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ Modes:
|
||||
full - Capture the focused output
|
||||
all - Capture all outputs combined
|
||||
output - Capture a specific output by name
|
||||
window - Capture the focused window (Hyprland only)
|
||||
window - Capture the focused window (Hyprland/DWL)
|
||||
last - Capture the last selected region
|
||||
|
||||
Output format (--format):
|
||||
@@ -91,9 +91,8 @@ If no previous region exists, falls back to interactive selection.`,
|
||||
var ssWindowCmd = &cobra.Command{
|
||||
Use: "window",
|
||||
Short: "Capture the focused window",
|
||||
Long: `Capture the currently focused window.
|
||||
Currently only supported on Hyprland.`,
|
||||
Run: runScreenshotWindow,
|
||||
Long: `Capture the currently focused window. Supported on Hyprland and DWL.`,
|
||||
Run: runScreenshotWindow,
|
||||
}
|
||||
|
||||
var ssListCmd = &cobra.Command{
|
||||
|
||||
+35
-7
@@ -16,7 +16,7 @@ import (
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server"
|
||||
)
|
||||
|
||||
type ipcTargets map[string][]string
|
||||
type ipcTargets map[string]map[string][]string
|
||||
|
||||
var isSessionManaged bool
|
||||
|
||||
@@ -476,28 +476,40 @@ func runShellDaemon(session bool) {
|
||||
}
|
||||
|
||||
func parseTargetsFromIPCShowOutput(output string) ipcTargets {
|
||||
targets := map[string][]string{}
|
||||
targets := make(ipcTargets)
|
||||
var currentTarget string
|
||||
for _, line := range strings.Split(output, "\n") {
|
||||
if strings.HasPrefix(line, "target ") {
|
||||
currentTarget = strings.TrimSpace(strings.TrimPrefix(line, "target "))
|
||||
targets[currentTarget] = make(map[string][]string)
|
||||
}
|
||||
if strings.HasPrefix(line, " function") && currentTarget != "" {
|
||||
argsList := []string{}
|
||||
currentFunc := strings.TrimPrefix(line, " function ")
|
||||
currentFunc = strings.SplitN(currentFunc, "(", 2)[0]
|
||||
targets[currentTarget] = append(targets[currentTarget], currentFunc)
|
||||
funcDef := strings.SplitN(currentFunc, "(", 2)
|
||||
argList := strings.SplitN(funcDef[1], ")", 2)[0]
|
||||
args := strings.Split(argList, ",")
|
||||
if len(args) > 0 && strings.TrimSpace(args[0]) != "" {
|
||||
argsList = append(argsList, funcDef[0])
|
||||
for _, arg := range args {
|
||||
argName := strings.SplitN(strings.TrimSpace(arg), ":", 2)[0]
|
||||
argsList = append(argsList, argName)
|
||||
}
|
||||
targets[currentTarget][funcDef[0]] = argsList
|
||||
} else {
|
||||
targets[currentTarget][funcDef[0]] = make([]string, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
return targets
|
||||
}
|
||||
|
||||
func getShellIPCCompletions(args []string, toComplete string) []string {
|
||||
func getShellIPCCompletions(args []string, _ string) []string {
|
||||
cmdArgs := []string{"-p", configPath, "ipc", "show"}
|
||||
cmd := exec.Command("qs", cmdArgs...)
|
||||
var targets ipcTargets
|
||||
|
||||
if output, err := cmd.Output(); err == nil {
|
||||
log.Debugf("IPC show output: %s", string(output))
|
||||
targets = parseTargetsFromIPCShowOutput(string(output))
|
||||
} else {
|
||||
log.Debugf("Error getting IPC show output for completions: %v", err)
|
||||
@@ -516,8 +528,24 @@ func getShellIPCCompletions(args []string, toComplete string) []string {
|
||||
}
|
||||
return targetNames
|
||||
}
|
||||
if len(args) == 1 {
|
||||
if targetFuncs, ok := targets[args[0]]; ok {
|
||||
funcNames := make([]string, 0)
|
||||
for k := range targetFuncs {
|
||||
funcNames = append(funcNames, k)
|
||||
}
|
||||
return funcNames
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if len(args) <= len(targets[args[0]]) {
|
||||
funcArgs := targets[args[0]][args[1]]
|
||||
if len(funcArgs) >= len(args) {
|
||||
return []string{fmt.Sprintf("[%s]", funcArgs[len(args)-1])}
|
||||
}
|
||||
}
|
||||
|
||||
return targets[args[0]]
|
||||
return nil
|
||||
}
|
||||
|
||||
func runShellIPCCommand(args []string) {
|
||||
|
||||
@@ -2,7 +2,6 @@ package colorpicker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
||||
@@ -116,6 +115,11 @@ func (p *Picker) Run() (*Color, error) {
|
||||
return nil, fmt.Errorf("roundtrip: %w", err)
|
||||
}
|
||||
|
||||
// Extra roundtrip to ensure pointer/keyboard from seat capabilities are registered
|
||||
if err := p.roundtrip(); err != nil {
|
||||
return nil, fmt.Errorf("roundtrip after seat: %w", err)
|
||||
}
|
||||
|
||||
if err := p.createSurfaces(); err != nil {
|
||||
return nil, fmt.Errorf("create surfaces: %w", err)
|
||||
}
|
||||
@@ -405,15 +409,10 @@ func (p *Picker) createLayerSurface(output *Output) (*LayerSurface, error) {
|
||||
|
||||
func (p *Picker) computeSurfaceScale(ls *LayerSurface) int32 {
|
||||
out := ls.output
|
||||
if out == nil || out.fractionalScale <= 0 {
|
||||
if out == nil || out.scale <= 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
scale := int32(math.Ceil(out.fractionalScale))
|
||||
if scale <= 0 {
|
||||
scale = 1
|
||||
}
|
||||
return scale
|
||||
return out.scale
|
||||
}
|
||||
|
||||
func (p *Picker) ensureShortcutsInhibitor(ls *LayerSurface) {
|
||||
@@ -485,6 +484,13 @@ func (p *Picker) captureForSurface(ls *LayerSurface) {
|
||||
|
||||
frame.SetReadyHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1ReadyEvent) {
|
||||
ls.state.OnScreencopyReady()
|
||||
|
||||
logicalW, _ := ls.state.LogicalSize()
|
||||
screenBuf := ls.state.ScreenBuffer()
|
||||
if logicalW > 0 && screenBuf != nil {
|
||||
ls.output.fractionalScale = float64(screenBuf.Width) / float64(logicalW)
|
||||
}
|
||||
|
||||
scale := p.computeSurfaceScale(ls)
|
||||
ls.state.SetScale(scale)
|
||||
frame.Destroy()
|
||||
@@ -545,18 +551,17 @@ func (p *Picker) redrawSurface(ls *LayerSurface) {
|
||||
logicalH = int(ls.output.height)
|
||||
}
|
||||
|
||||
scale := ls.state.Scale()
|
||||
if scale <= 0 {
|
||||
scale = 1
|
||||
}
|
||||
|
||||
if ls.viewport != nil {
|
||||
srcW := float64(renderBuf.Width) / float64(scale)
|
||||
srcH := float64(renderBuf.Height) / float64(scale)
|
||||
_ = ls.viewport.SetSource(0, 0, srcW, srcH)
|
||||
_ = ls.wlSurface.SetBufferScale(1)
|
||||
_ = ls.viewport.SetSource(0, 0, float64(renderBuf.Width), float64(renderBuf.Height))
|
||||
_ = ls.viewport.SetDestination(int32(logicalW), int32(logicalH))
|
||||
} else {
|
||||
bufferScale := ls.output.scale
|
||||
if bufferScale <= 0 {
|
||||
bufferScale = 1
|
||||
}
|
||||
_ = ls.wlSurface.SetBufferScale(bufferScale)
|
||||
}
|
||||
_ = ls.wlSurface.SetBufferScale(scale)
|
||||
_ = ls.wlSurface.Attach(wlBuffer, 0, 0)
|
||||
_ = ls.wlSurface.Damage(0, 0, int32(logicalW), int32(logicalH))
|
||||
_ = ls.wlSurface.Commit()
|
||||
@@ -581,17 +586,19 @@ func (p *Picker) setupInput() {
|
||||
p.seat.SetCapabilitiesHandler(func(e client.SeatCapabilitiesEvent) {
|
||||
if e.Capabilities&uint32(client.SeatCapabilityPointer) != 0 && p.pointer == nil {
|
||||
pointer, err := p.seat.GetPointer()
|
||||
if err == nil {
|
||||
p.pointer = pointer
|
||||
p.setupPointerHandlers()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p.pointer = pointer
|
||||
p.setupPointerHandlers()
|
||||
}
|
||||
if e.Capabilities&uint32(client.SeatCapabilityKeyboard) != 0 && p.keyboard == nil {
|
||||
keyboard, err := p.seat.GetKeyboard()
|
||||
if err == nil {
|
||||
p.keyboard = keyboard
|
||||
p.setupKeyboardHandlers()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p.keyboard = keyboard
|
||||
p.setupKeyboardHandlers()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -269,12 +269,17 @@ func (s *SurfaceState) Redraw() *ShmBuffer {
|
||||
px = clamp(px, 0, dst.Width-1)
|
||||
py = clamp(py, 0, dst.Height-1)
|
||||
|
||||
picked := GetPixelColorWithFormat(s.screenBuf, px, py, s.screenFormat)
|
||||
sampleY := py
|
||||
if s.yInverted {
|
||||
sampleY = s.screenBuf.Height - 1 - py
|
||||
}
|
||||
|
||||
drawMagnifier(
|
||||
picked := GetPixelColorWithFormat(s.screenBuf, px, sampleY, s.screenFormat)
|
||||
|
||||
drawMagnifierWithInversion(
|
||||
dst.Data(), dst.Stride, dst.Width, dst.Height,
|
||||
s.screenBuf.Data(), s.screenBuf.Stride, s.screenBuf.Width, s.screenBuf.Height,
|
||||
px, py, picked,
|
||||
px, py, picked, s.yInverted,
|
||||
)
|
||||
|
||||
drawColorPreview(dst.Data(), dst.Stride, dst.Width, dst.Height, px, py, picked, s.displayFormat, s.lowercase)
|
||||
@@ -379,11 +384,12 @@ func blendColors(bg, fg Color, alpha float64) Color {
|
||||
}
|
||||
}
|
||||
|
||||
func drawMagnifier(
|
||||
func drawMagnifierWithInversion(
|
||||
dst []byte, dstStride, dstW, dstH int,
|
||||
src []byte, srcStride, srcW, srcH int,
|
||||
cx, cy int,
|
||||
borderColor Color,
|
||||
yInverted bool,
|
||||
) {
|
||||
if dstW <= 0 || dstH <= 0 || srcW <= 0 || srcH <= 0 {
|
||||
return
|
||||
@@ -439,10 +445,11 @@ func drawMagnifier(
|
||||
finalColor = blendColors(bgColor, borderColor, alpha)
|
||||
|
||||
case dist > innerRadius:
|
||||
if dist > outerRadiusF-aaWidth {
|
||||
switch {
|
||||
case dist > outerRadiusF-aaWidth:
|
||||
alpha := clampF((outerRadiusF-dist)/aaWidth, 0, 1)
|
||||
finalColor = blendColors(borderColor, borderColor, alpha)
|
||||
} else if dist < innerRadius+aaWidth {
|
||||
case dist < innerRadius+aaWidth:
|
||||
alpha := clampF((dist-innerRadius)/aaWidth, 0, 1)
|
||||
fx := float64(dx) / zoom
|
||||
fy := float64(dy) / zoom
|
||||
@@ -450,6 +457,9 @@ func drawMagnifier(
|
||||
sy := cy + int(math.Round(fy))
|
||||
sx = clamp(sx, 0, srcW-1)
|
||||
sy = clamp(sy, 0, srcH-1)
|
||||
if yInverted {
|
||||
sy = srcH - 1 - sy
|
||||
}
|
||||
srcOff := sy*srcStride + sx*4
|
||||
if srcOff+4 <= len(src) {
|
||||
magColor := Color{B: src[srcOff+0], G: src[srcOff+1], R: src[srcOff+2], A: 255}
|
||||
@@ -457,7 +467,7 @@ func drawMagnifier(
|
||||
} else {
|
||||
finalColor = borderColor
|
||||
}
|
||||
} else {
|
||||
default:
|
||||
finalColor = borderColor
|
||||
}
|
||||
|
||||
@@ -468,6 +478,9 @@ func drawMagnifier(
|
||||
sy := cy + int(math.Round(fy))
|
||||
sx = clamp(sx, 0, srcW-1)
|
||||
sy = clamp(sy, 0, srcH-1)
|
||||
if yInverted {
|
||||
sy = srcH - 1 - sy
|
||||
}
|
||||
srcOff := sy*srcStride + sx*4
|
||||
if srcOff+4 <= len(src) {
|
||||
finalColor = Color{B: src[srcOff+0], G: src[srcOff+1], R: src[srcOff+2], A: 255}
|
||||
|
||||
@@ -435,7 +435,7 @@ func TestHyprlandConfigDeployment(t *testing.T) {
|
||||
content, err := os.ReadFile(result.Path)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, string(content), "# MONITOR CONFIG")
|
||||
assert.Contains(t, string(content), "bind = $mod, T, exec, ghostty")
|
||||
assert.Contains(t, string(content), "bind = $mod, T, exec, $TERMINAL")
|
||||
assert.Contains(t, string(content), "exec-once = ")
|
||||
})
|
||||
|
||||
@@ -471,7 +471,7 @@ general {
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, string(newContent), "monitor = DP-1, 1920x1080@144")
|
||||
assert.Contains(t, string(newContent), "monitor = HDMI-A-1, 3840x2160@60")
|
||||
assert.Contains(t, string(newContent), "bind = $mod, T, exec, kitty")
|
||||
assert.Contains(t, string(newContent), "bind = $mod, T, exec, $TERMINAL")
|
||||
assert.NotContains(t, string(newContent), "monitor = eDP-2")
|
||||
})
|
||||
}
|
||||
@@ -487,16 +487,14 @@ func TestNiriConfigStructure(t *testing.T) {
|
||||
|
||||
func TestHyprlandConfigStructure(t *testing.T) {
|
||||
assert.Contains(t, HyprlandConfig, "# MONITOR CONFIG")
|
||||
assert.Contains(t, HyprlandConfig, "# ENVIRONMENT VARS")
|
||||
assert.Contains(t, HyprlandConfig, "# STARTUP APPS")
|
||||
assert.Contains(t, HyprlandConfig, "# INPUT CONFIG")
|
||||
assert.Contains(t, HyprlandConfig, "# KEYBINDINGS")
|
||||
assert.Contains(t, HyprlandConfig, "{{POLKIT_AGENT_PATH}}")
|
||||
assert.Contains(t, HyprlandConfig, "{{TERMINAL_COMMAND}}")
|
||||
assert.Contains(t, HyprlandConfig, "exec-once = dms run")
|
||||
assert.Contains(t, HyprlandConfig, "bind = $mod, T, exec,")
|
||||
assert.Contains(t, HyprlandConfig, "bind = $mod, T, exec, $TERMINAL")
|
||||
assert.Contains(t, HyprlandConfig, "bind = $mod, space, exec, dms ipc call spotlight toggle")
|
||||
assert.Contains(t, HyprlandConfig, "windowrulev2 = noborder, class:^(com\\.mitchellh\\.ghostty)$")
|
||||
assert.Contains(t, HyprlandConfig, "windowrule {")
|
||||
assert.Contains(t, HyprlandConfig, "match:class = ^(com\\.mitchellh\\.ghostty)$")
|
||||
}
|
||||
|
||||
func TestGhosttyConfigStructure(t *testing.T) {
|
||||
|
||||
@@ -7,20 +7,10 @@
|
||||
# monitor = eDP-2, 2560x1600@239.998993, 2560x0, 1, vrr, 1
|
||||
monitor = , preferred,auto,auto
|
||||
|
||||
# ==================
|
||||
# ENVIRONMENT VARS
|
||||
# ==================
|
||||
env = QT_QPA_PLATFORM,wayland
|
||||
env = ELECTRON_OZONE_PLATFORM_HINT,auto
|
||||
env = QT_QPA_PLATFORMTHEME,gtk3
|
||||
env = QT_QPA_PLATFORMTHEME_QT6,gtk3
|
||||
env = TERMINAL,{{TERMINAL_COMMAND}}
|
||||
|
||||
# ==================
|
||||
# STARTUP APPS
|
||||
# ==================
|
||||
exec-once = bash -c "wl-paste --watch cliphist store &"
|
||||
exec-once = dms run
|
||||
exec-once = {{POLKIT_AGENT_PATH}}
|
||||
|
||||
# ==================
|
||||
@@ -100,36 +90,132 @@ misc {
|
||||
# ==================
|
||||
# WINDOW RULES
|
||||
# ==================
|
||||
windowrulev2 = tile, class:^(org\.wezfurlong\.wezterm)$
|
||||
windowrule {
|
||||
name = windowrule-1
|
||||
tile = on
|
||||
match:class = ^(org\.wezfurlong\.wezterm)$
|
||||
border_size = 0
|
||||
}
|
||||
|
||||
windowrulev2 = rounding 12, class:^(org\.gnome\.)
|
||||
windowrulev2 = noborder, class:^(org\.gnome\.)
|
||||
|
||||
windowrulev2 = tile, class:^(gnome-control-center)$
|
||||
windowrulev2 = tile, class:^(pavucontrol)$
|
||||
windowrulev2 = tile, class:^(nm-connection-editor)$
|
||||
windowrule {
|
||||
name = windowrule-2
|
||||
rounding = 12
|
||||
match:class = ^(org\.gnome\.)
|
||||
border_size = 0
|
||||
}
|
||||
|
||||
windowrulev2 = float, class:^(gnome-calculator)$
|
||||
windowrulev2 = float, class:^(galculator)$
|
||||
windowrulev2 = float, class:^(blueman-manager)$
|
||||
windowrulev2 = float, class:^(org\.gnome\.Nautilus)$
|
||||
windowrulev2 = float, class:^(steam)$
|
||||
windowrulev2 = float, class:^(xdg-desktop-portal)$
|
||||
|
||||
windowrulev2 = noborder, class:^(org\.wezfurlong\.wezterm)$
|
||||
windowrulev2 = noborder, class:^(Alacritty)$
|
||||
windowrulev2 = noborder, class:^(zen)$
|
||||
windowrulev2 = noborder, class:^(com\.mitchellh\.ghostty)$
|
||||
windowrulev2 = noborder, class:^(kitty)$
|
||||
|
||||
windowrulev2 = float, class:^(firefox)$, title:^(Picture-in-Picture)$
|
||||
windowrulev2 = float, class:^(zoom)$
|
||||
windowrule {
|
||||
name = windowrule-3
|
||||
tile = on
|
||||
match:class = ^(gnome-control-center)$
|
||||
}
|
||||
|
||||
# DMS windows floating by default
|
||||
windowrulev2 = float, class:^(org.quickshell)$
|
||||
windowrulev2 = opacity 0.9 0.9, floating:0, focus:0
|
||||
windowrule {
|
||||
name = windowrule-4
|
||||
tile = on
|
||||
match:class = ^(pavucontrol)$
|
||||
}
|
||||
|
||||
layerrule = noanim, ^(quickshell)$
|
||||
windowrule {
|
||||
name = windowrule-5
|
||||
tile = on
|
||||
match:class = ^(nm-connection-editor)$
|
||||
}
|
||||
|
||||
|
||||
windowrule {
|
||||
name = windowrule-6
|
||||
float = on
|
||||
match:class = ^(gnome-calculator)$
|
||||
}
|
||||
|
||||
windowrule {
|
||||
name = windowrule-7
|
||||
float = on
|
||||
match:class = ^(galculator)$
|
||||
}
|
||||
|
||||
windowrule {
|
||||
name = windowrule-8
|
||||
float = on
|
||||
match:class = ^(blueman-manager)$
|
||||
}
|
||||
|
||||
windowrule {
|
||||
name = windowrule-9
|
||||
float = on
|
||||
match:class = ^(org\.gnome\.Nautilus)$
|
||||
}
|
||||
|
||||
windowrule {
|
||||
name = windowrule-10
|
||||
float = on
|
||||
match:class = ^(steam)$
|
||||
}
|
||||
|
||||
windowrule {
|
||||
name = windowrule-11
|
||||
float = on
|
||||
match:class = ^(xdg-desktop-portal)$
|
||||
}
|
||||
|
||||
|
||||
|
||||
windowrule {
|
||||
name = windowrule-12
|
||||
border_size = 0
|
||||
match:class = ^(Alacritty)$
|
||||
}
|
||||
|
||||
windowrule {
|
||||
name = windowrule-13
|
||||
border_size = 0
|
||||
match:class = ^(zen)$
|
||||
}
|
||||
|
||||
windowrule {
|
||||
name = windowrule-14
|
||||
border_size = 0
|
||||
match:class = ^(com\.mitchellh\.ghostty)$
|
||||
}
|
||||
|
||||
windowrule {
|
||||
name = windowrule-15
|
||||
border_size = 0
|
||||
match:class = ^(kitty)$
|
||||
}
|
||||
|
||||
|
||||
windowrule {
|
||||
name = windowrule-16
|
||||
float = on
|
||||
match:class = ^(firefox)$
|
||||
match:title = ^(Picture-in-Picture)$
|
||||
}
|
||||
|
||||
windowrule {
|
||||
name = windowrule-17
|
||||
float = on
|
||||
match:class = ^(zoom)$
|
||||
}
|
||||
|
||||
|
||||
windowrule {
|
||||
name = windowrule-18
|
||||
opacity = 0.9 0.9
|
||||
match:float = 0
|
||||
match:focus = 0
|
||||
}
|
||||
|
||||
|
||||
layerrule {
|
||||
name = layerrule-1
|
||||
no_anim = on
|
||||
match:namespace = ^(quickshell)$
|
||||
}
|
||||
|
||||
# ==================
|
||||
# KEYBINDINGS
|
||||
@@ -137,7 +223,7 @@ layerrule = noanim, ^(quickshell)$
|
||||
$mod = SUPER
|
||||
|
||||
# === Application Launchers ===
|
||||
bind = $mod, T, exec, {{TERMINAL_COMMAND}}
|
||||
bind = $mod, T, exec, $TERMINAL
|
||||
bind = $mod, space, exec, dms ipc call spotlight toggle
|
||||
bind = $mod, V, exec, dms ipc call clipboard toggle
|
||||
bind = $mod, M, exec, dms ipc call processlist focusOrToggle
|
||||
@@ -281,12 +367,9 @@ binde = $mod SHIFT, minus, resizeactive, 0 -10%
|
||||
binde = $mod SHIFT, equal, resizeactive, 0 10%
|
||||
|
||||
# === Screenshots ===
|
||||
bind = , XF86Launch1, exec, grimblast copy area
|
||||
bind = CTRL, XF86Launch1, exec, grimblast copy screen
|
||||
bind = ALT, XF86Launch1, exec, grimblast copy active
|
||||
bind = , Print, exec, grimblast copy area
|
||||
bind = CTRL, Print, exec, grimblast copy screen
|
||||
bind = ALT, Print, exec, grimblast copy active
|
||||
bind = , Print, exec, dms screenshot
|
||||
bind = CTRL, Print, exec, dms screenshot full
|
||||
bind = ALT, Print, exec, dms screenshot window
|
||||
|
||||
# === System Controls ===
|
||||
bind = $mod SHIFT, P, dpms, off
|
||||
|
||||
@@ -116,15 +116,9 @@ overview {
|
||||
// See the binds section below for more spawn examples.
|
||||
// This line starts waybar, a commonly used bar for Wayland compositors.
|
||||
spawn-at-startup "bash" "-c" "wl-paste --watch cliphist store &"
|
||||
spawn-at-startup "dms" "run"
|
||||
spawn-at-startup "{{POLKIT_AGENT_PATH}}"
|
||||
environment {
|
||||
XDG_CURRENT_DESKTOP "niri"
|
||||
QT_QPA_PLATFORM "wayland"
|
||||
ELECTRON_OZONE_PLATFORM_HINT "auto"
|
||||
QT_QPA_PLATFORMTHEME "gtk3"
|
||||
QT_QPA_PLATFORMTHEME_QT6 "gtk3"
|
||||
TERMINAL "{{TERMINAL_COMMAND}}"
|
||||
}
|
||||
hotkey-overlay {
|
||||
skip-at-startup
|
||||
|
||||
@@ -23,6 +23,17 @@ type ColorInfo struct {
|
||||
B int `json:"b"`
|
||||
}
|
||||
|
||||
type VariantColorValue struct {
|
||||
Hex string `json:"hex"`
|
||||
HexStripped string `json:"hex_stripped"`
|
||||
}
|
||||
|
||||
type VariantColorInfo struct {
|
||||
Dark VariantColorValue `json:"dark"`
|
||||
Light VariantColorValue `json:"light"`
|
||||
Default VariantColorValue `json:"default"`
|
||||
}
|
||||
|
||||
type Palette struct {
|
||||
Color0 ColorInfo `json:"color0"`
|
||||
Color1 ColorInfo `json:"color1"`
|
||||
@@ -42,6 +53,25 @@ type Palette struct {
|
||||
Color15 ColorInfo `json:"color15"`
|
||||
}
|
||||
|
||||
type VariantPalette struct {
|
||||
Color0 VariantColorInfo `json:"color0"`
|
||||
Color1 VariantColorInfo `json:"color1"`
|
||||
Color2 VariantColorInfo `json:"color2"`
|
||||
Color3 VariantColorInfo `json:"color3"`
|
||||
Color4 VariantColorInfo `json:"color4"`
|
||||
Color5 VariantColorInfo `json:"color5"`
|
||||
Color6 VariantColorInfo `json:"color6"`
|
||||
Color7 VariantColorInfo `json:"color7"`
|
||||
Color8 VariantColorInfo `json:"color8"`
|
||||
Color9 VariantColorInfo `json:"color9"`
|
||||
Color10 VariantColorInfo `json:"color10"`
|
||||
Color11 VariantColorInfo `json:"color11"`
|
||||
Color12 VariantColorInfo `json:"color12"`
|
||||
Color13 VariantColorInfo `json:"color13"`
|
||||
Color14 VariantColorInfo `json:"color14"`
|
||||
Color15 VariantColorInfo `json:"color15"`
|
||||
}
|
||||
|
||||
func NewColorInfo(hex string) ColorInfo {
|
||||
rgb := HexToRGB(hex)
|
||||
stripped := hex
|
||||
@@ -492,3 +522,54 @@ func GeneratePalette(primaryColor string, opts PaletteOptions) Palette {
|
||||
|
||||
return palette
|
||||
}
|
||||
|
||||
type VariantOptions struct {
|
||||
PrimaryDark string
|
||||
PrimaryLight string
|
||||
Background string
|
||||
UseDPS bool
|
||||
IsLightMode bool
|
||||
}
|
||||
|
||||
func mergeColorInfo(dark, light ColorInfo, isLightMode bool) VariantColorInfo {
|
||||
darkVal := VariantColorValue{Hex: dark.Hex, HexStripped: dark.HexStripped}
|
||||
lightVal := VariantColorValue{Hex: light.Hex, HexStripped: light.HexStripped}
|
||||
|
||||
defaultVal := darkVal
|
||||
if isLightMode {
|
||||
defaultVal = lightVal
|
||||
}
|
||||
|
||||
return VariantColorInfo{
|
||||
Dark: darkVal,
|
||||
Light: lightVal,
|
||||
Default: defaultVal,
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateVariantPalette(opts VariantOptions) VariantPalette {
|
||||
darkOpts := PaletteOptions{IsLight: false, Background: opts.Background, UseDPS: opts.UseDPS}
|
||||
lightOpts := PaletteOptions{IsLight: true, Background: opts.Background, UseDPS: opts.UseDPS}
|
||||
|
||||
dark := GeneratePalette(opts.PrimaryDark, darkOpts)
|
||||
light := GeneratePalette(opts.PrimaryLight, lightOpts)
|
||||
|
||||
return VariantPalette{
|
||||
Color0: mergeColorInfo(dark.Color0, light.Color0, opts.IsLightMode),
|
||||
Color1: mergeColorInfo(dark.Color1, light.Color1, opts.IsLightMode),
|
||||
Color2: mergeColorInfo(dark.Color2, light.Color2, opts.IsLightMode),
|
||||
Color3: mergeColorInfo(dark.Color3, light.Color3, opts.IsLightMode),
|
||||
Color4: mergeColorInfo(dark.Color4, light.Color4, opts.IsLightMode),
|
||||
Color5: mergeColorInfo(dark.Color5, light.Color5, opts.IsLightMode),
|
||||
Color6: mergeColorInfo(dark.Color6, light.Color6, opts.IsLightMode),
|
||||
Color7: mergeColorInfo(dark.Color7, light.Color7, opts.IsLightMode),
|
||||
Color8: mergeColorInfo(dark.Color8, light.Color8, opts.IsLightMode),
|
||||
Color9: mergeColorInfo(dark.Color9, light.Color9, opts.IsLightMode),
|
||||
Color10: mergeColorInfo(dark.Color10, light.Color10, opts.IsLightMode),
|
||||
Color11: mergeColorInfo(dark.Color11, light.Color11, opts.IsLightMode),
|
||||
Color12: mergeColorInfo(dark.Color12, light.Color12, opts.IsLightMode),
|
||||
Color13: mergeColorInfo(dark.Color13, light.Color13, opts.IsLightMode),
|
||||
Color14: mergeColorInfo(dark.Color14, light.Color14, opts.IsLightMode),
|
||||
Color15: mergeColorInfo(dark.Color15, light.Color15, opts.IsLightMode),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,11 @@ func GenerateJSON(p Palette) string {
|
||||
return string(marshalled)
|
||||
}
|
||||
|
||||
func GenerateVariantJSON(p VariantPalette) string {
|
||||
marshalled, _ := json.Marshal(p)
|
||||
return string(marshalled)
|
||||
}
|
||||
|
||||
func GenerateKittyTheme(p Palette) string {
|
||||
var result strings.Builder
|
||||
fmt.Fprintf(&result, "color0 %s\n", p.Color0.Hex)
|
||||
|
||||
@@ -357,6 +357,15 @@ func (a *ArchDistribution) InstallPackages(ctx context.Context, dependencies []d
|
||||
LogOutput: "Starting post-installation configuration...",
|
||||
}
|
||||
|
||||
terminal := a.DetectTerminalFromDeps(dependencies)
|
||||
if err := a.WriteEnvironmentConfig(terminal); err != nil {
|
||||
a.log(fmt.Sprintf("Warning: failed to write environment config: %v", err))
|
||||
}
|
||||
|
||||
if err := a.EnableDMSService(ctx); err != nil {
|
||||
a.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
||||
}
|
||||
|
||||
// Phase 7: Complete
|
||||
progressChan <- InstallProgressMsg{
|
||||
Phase: PhaseComplete,
|
||||
|
||||
@@ -17,8 +17,10 @@ import (
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/version"
|
||||
)
|
||||
|
||||
const forceQuickshellGit = false
|
||||
const forceDMSGit = false
|
||||
const (
|
||||
forceQuickshellGit = false
|
||||
forceDMSGit = false
|
||||
)
|
||||
|
||||
// BaseDistribution provides common functionality for all distributions
|
||||
type BaseDistribution struct {
|
||||
@@ -219,20 +221,6 @@ func (b *BaseDistribution) detectClipboardTools() []deps.Dependency {
|
||||
return dependencies
|
||||
}
|
||||
|
||||
func (b *BaseDistribution) detectHyprpicker() deps.Dependency {
|
||||
status := deps.StatusMissing
|
||||
if b.commandExists("hyprpicker") {
|
||||
status = deps.StatusInstalled
|
||||
}
|
||||
|
||||
return deps.Dependency{
|
||||
Name: "hyprpicker",
|
||||
Status: status,
|
||||
Description: "Color picker for Wayland",
|
||||
Required: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BaseDistribution) detectHyprlandTools() []deps.Dependency {
|
||||
var dependencies []deps.Dependency
|
||||
|
||||
@@ -240,10 +228,7 @@ func (b *BaseDistribution) detectHyprlandTools() []deps.Dependency {
|
||||
name string
|
||||
description string
|
||||
}{
|
||||
{"grim", "Screenshot utility for Wayland"},
|
||||
{"slurp", "Region selection utility for Wayland"},
|
||||
{"hyprctl", "Hyprland control utility"},
|
||||
{"grimblast", "Screenshot script for Hyprland"},
|
||||
{"jq", "JSON processor"},
|
||||
}
|
||||
|
||||
@@ -564,6 +549,68 @@ func (b *BaseDistribution) runWithProgressStepTimeout(cmd *exec.Cmd, progressCha
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BaseDistribution) DetectTerminalFromDeps(dependencies []deps.Dependency) deps.Terminal {
|
||||
for _, dep := range dependencies {
|
||||
switch dep.Name {
|
||||
case "ghostty":
|
||||
return deps.TerminalGhostty
|
||||
case "kitty":
|
||||
return deps.TerminalKitty
|
||||
case "alacritty":
|
||||
return deps.TerminalAlacritty
|
||||
}
|
||||
}
|
||||
return deps.TerminalGhostty
|
||||
}
|
||||
|
||||
func (b *BaseDistribution) WriteEnvironmentConfig(terminal deps.Terminal) error {
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get home directory: %w", err)
|
||||
}
|
||||
|
||||
envDir := filepath.Join(homeDir, ".config", "environment.d")
|
||||
if err := os.MkdirAll(envDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create environment.d directory: %w", err)
|
||||
}
|
||||
|
||||
var terminalCmd string
|
||||
switch terminal {
|
||||
case deps.TerminalGhostty:
|
||||
terminalCmd = "ghostty"
|
||||
case deps.TerminalKitty:
|
||||
terminalCmd = "kitty"
|
||||
case deps.TerminalAlacritty:
|
||||
terminalCmd = "alacritty"
|
||||
default:
|
||||
terminalCmd = "ghostty"
|
||||
}
|
||||
|
||||
content := fmt.Sprintf(`QT_QPA_PLATFORM=wayland
|
||||
ELECTRON_OZONE_PLATFORM_HINT=auto
|
||||
QT_QPA_PLATFORMTHEME=gtk3
|
||||
QT_QPA_PLATFORMTHEME_QT6=gtk3
|
||||
TERMINAL=%s
|
||||
`, terminalCmd)
|
||||
|
||||
envFile := filepath.Join(envDir, "90-dms.conf")
|
||||
if err := os.WriteFile(envFile, []byte(content), 0644); err != nil {
|
||||
return fmt.Errorf("failed to write environment config: %w", err)
|
||||
}
|
||||
|
||||
b.log(fmt.Sprintf("Wrote environment config to %s", envFile))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BaseDistribution) EnableDMSService(ctx context.Context) error {
|
||||
cmd := exec.CommandContext(ctx, "systemctl", "--user", "enable", "--now", "dms")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("failed to enable dms service: %w", err)
|
||||
}
|
||||
b.log("Enabled dms systemd user service")
|
||||
return nil
|
||||
}
|
||||
|
||||
// installDMSBinary installs the DMS binary from GitHub releases
|
||||
func (b *BaseDistribution) installDMSBinary(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
|
||||
b.log("Installing/updating DMS binary...")
|
||||
@@ -602,7 +649,7 @@ func (b *BaseDistribution) installDMSBinary(ctx context.Context, sudoPassword st
|
||||
return fmt.Errorf("failed to get user home directory: %w", err)
|
||||
}
|
||||
tmpDir := filepath.Join(homeDir, ".cache", "dankinstall", "manual-builds")
|
||||
if err := os.MkdirAll(tmpDir, 0755); err != nil {
|
||||
if err := os.MkdirAll(tmpDir, 0o755); err != nil {
|
||||
return fmt.Errorf("failed to create temp directory: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
@@ -333,6 +333,15 @@ func (d *DebianDistribution) InstallPackages(ctx context.Context, dependencies [
|
||||
LogOutput: "Starting post-installation configuration...",
|
||||
}
|
||||
|
||||
terminal := d.DetectTerminalFromDeps(dependencies)
|
||||
if err := d.WriteEnvironmentConfig(terminal); err != nil {
|
||||
d.log(fmt.Sprintf("Warning: failed to write environment config: %v", err))
|
||||
}
|
||||
|
||||
if err := d.EnableDMSService(ctx); err != nil {
|
||||
d.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
||||
}
|
||||
|
||||
progressChan <- InstallProgressMsg{
|
||||
Phase: PhaseComplete,
|
||||
Progress: 1.0,
|
||||
|
||||
@@ -357,6 +357,15 @@ func (f *FedoraDistribution) InstallPackages(ctx context.Context, dependencies [
|
||||
LogOutput: "Starting post-installation configuration...",
|
||||
}
|
||||
|
||||
terminal := f.DetectTerminalFromDeps(dependencies)
|
||||
if err := f.WriteEnvironmentConfig(terminal); err != nil {
|
||||
f.log(fmt.Sprintf("Warning: failed to write environment config: %v", err))
|
||||
}
|
||||
|
||||
if err := f.EnableDMSService(ctx); err != nil {
|
||||
f.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
||||
}
|
||||
|
||||
// Phase 7: Complete
|
||||
progressChan <- InstallProgressMsg{
|
||||
Phase: PhaseComplete,
|
||||
|
||||
@@ -451,6 +451,15 @@ func (g *GentooDistribution) InstallPackages(ctx context.Context, dependencies [
|
||||
LogOutput: "Starting post-installation configuration...",
|
||||
}
|
||||
|
||||
terminal := g.DetectTerminalFromDeps(dependencies)
|
||||
if err := g.WriteEnvironmentConfig(terminal); err != nil {
|
||||
g.log(fmt.Sprintf("Warning: failed to write environment config: %v", err))
|
||||
}
|
||||
|
||||
if err := g.EnableDMSService(ctx); err != nil {
|
||||
g.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
||||
}
|
||||
|
||||
progressChan <- InstallProgressMsg{
|
||||
Phase: PhaseComplete,
|
||||
Progress: 1.0,
|
||||
|
||||
@@ -62,10 +62,6 @@ func (m *ManualPackageInstaller) InstallManualPackages(ctx context.Context, pack
|
||||
if err := m.installDgop(ctx, sudoPassword, progressChan); err != nil {
|
||||
return fmt.Errorf("failed to install dgop: %w", err)
|
||||
}
|
||||
case "grimblast":
|
||||
if err := m.installGrimblast(ctx, sudoPassword, progressChan); err != nil {
|
||||
return fmt.Errorf("failed to install grimblast: %w", err)
|
||||
}
|
||||
case "niri":
|
||||
if err := m.installNiri(ctx, sudoPassword, progressChan); err != nil {
|
||||
return fmt.Errorf("failed to install niri: %w", err)
|
||||
@@ -166,62 +162,6 @@ func (m *ManualPackageInstaller) installDgop(ctx context.Context, sudoPassword s
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ManualPackageInstaller) installGrimblast(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
|
||||
m.log("Installing grimblast script for Hyprland...")
|
||||
|
||||
progressChan <- InstallProgressMsg{
|
||||
Phase: PhaseSystemPackages,
|
||||
Progress: 0.1,
|
||||
Step: "Downloading grimblast script...",
|
||||
IsComplete: false,
|
||||
CommandInfo: "curl grimblast script",
|
||||
}
|
||||
|
||||
grimblastURL := "https://raw.githubusercontent.com/hyprwm/contrib/refs/heads/main/grimblast/grimblast"
|
||||
tmpPath := filepath.Join(os.TempDir(), "grimblast")
|
||||
|
||||
downloadCmd := exec.CommandContext(ctx, "curl", "-L", "-o", tmpPath, grimblastURL)
|
||||
if err := downloadCmd.Run(); err != nil {
|
||||
m.logError("failed to download grimblast", err)
|
||||
return fmt.Errorf("failed to download grimblast: %w", err)
|
||||
}
|
||||
|
||||
progressChan <- InstallProgressMsg{
|
||||
Phase: PhaseSystemPackages,
|
||||
Progress: 0.5,
|
||||
Step: "Making grimblast executable...",
|
||||
IsComplete: false,
|
||||
CommandInfo: "chmod +x grimblast",
|
||||
}
|
||||
|
||||
chmodCmd := exec.CommandContext(ctx, "chmod", "+x", tmpPath)
|
||||
if err := chmodCmd.Run(); err != nil {
|
||||
m.logError("failed to make grimblast executable", err)
|
||||
return fmt.Errorf("failed to make grimblast executable: %w", err)
|
||||
}
|
||||
|
||||
progressChan <- InstallProgressMsg{
|
||||
Phase: PhaseSystemPackages,
|
||||
Progress: 0.8,
|
||||
Step: "Installing grimblast to /usr/local/bin...",
|
||||
IsComplete: false,
|
||||
NeedsSudo: true,
|
||||
CommandInfo: "sudo cp grimblast /usr/local/bin/",
|
||||
}
|
||||
|
||||
installCmd := ExecSudoCommand(ctx, sudoPassword,
|
||||
fmt.Sprintf("cp %s /usr/local/bin/grimblast", tmpPath))
|
||||
if err := installCmd.Run(); err != nil {
|
||||
m.logError("failed to install grimblast", err)
|
||||
return fmt.Errorf("failed to install grimblast: %w", err)
|
||||
}
|
||||
|
||||
os.Remove(tmpPath)
|
||||
|
||||
m.log("grimblast installed successfully to /usr/local/bin")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ManualPackageInstaller) installNiri(ctx context.Context, sudoPassword string, progressChan chan<- InstallProgressMsg) error {
|
||||
m.log("Installing niri from source...")
|
||||
|
||||
|
||||
@@ -372,6 +372,15 @@ func (o *OpenSUSEDistribution) InstallPackages(ctx context.Context, dependencies
|
||||
LogOutput: "Starting post-installation configuration...",
|
||||
}
|
||||
|
||||
terminal := o.DetectTerminalFromDeps(dependencies)
|
||||
if err := o.WriteEnvironmentConfig(terminal); err != nil {
|
||||
o.log(fmt.Sprintf("Warning: failed to write environment config: %v", err))
|
||||
}
|
||||
|
||||
if err := o.EnableDMSService(ctx); err != nil {
|
||||
o.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
||||
}
|
||||
|
||||
// Complete
|
||||
progressChan <- InstallProgressMsg{
|
||||
Phase: PhaseComplete,
|
||||
|
||||
@@ -352,6 +352,15 @@ func (u *UbuntuDistribution) InstallPackages(ctx context.Context, dependencies [
|
||||
LogOutput: "Starting post-installation configuration...",
|
||||
}
|
||||
|
||||
terminal := u.DetectTerminalFromDeps(dependencies)
|
||||
if err := u.WriteEnvironmentConfig(terminal); err != nil {
|
||||
u.log(fmt.Sprintf("Warning: failed to write environment config: %v", err))
|
||||
}
|
||||
|
||||
if err := u.EnableDMSService(ctx); err != nil {
|
||||
u.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
||||
}
|
||||
|
||||
// Phase 7: Complete
|
||||
progressChan <- InstallProgressMsg{
|
||||
Phase: PhaseComplete,
|
||||
|
||||
@@ -514,7 +514,7 @@ func (m Model) categorizeDependencies() map[string][]DependencyInfo {
|
||||
switch dep.Name {
|
||||
case "dms (DankMaterialShell)", "quickshell":
|
||||
categories["Shell"] = append(categories["Shell"], dep)
|
||||
case "hyprland", "grim", "slurp", "hyprctl", "grimblast":
|
||||
case "hyprland", "hyprctl":
|
||||
categories["Hyprland Components"] = append(categories["Hyprland Components"], dep)
|
||||
case "niri":
|
||||
categories["Niri Components"] = append(categories["Niri Components"], dep)
|
||||
|
||||
@@ -371,6 +371,18 @@ func (n *NiriProvider) buildActionNode(action string) *document.Node {
|
||||
|
||||
node.SetName(parts[0])
|
||||
for _, arg := range parts[1:] {
|
||||
if strings.Contains(arg, "=") {
|
||||
kv := strings.SplitN(arg, "=", 2)
|
||||
switch kv[1] {
|
||||
case "true":
|
||||
node.AddProperty(kv[0], true, "")
|
||||
case "false":
|
||||
node.AddProperty(kv[0], false, "")
|
||||
default:
|
||||
node.AddProperty(kv[0], kv[1], "")
|
||||
}
|
||||
continue
|
||||
}
|
||||
node.AddArgument(arg, "")
|
||||
}
|
||||
return node
|
||||
@@ -379,7 +391,7 @@ func (n *NiriProvider) buildActionNode(action string) *document.Node {
|
||||
func (n *NiriProvider) parseActionParts(action string) []string {
|
||||
var parts []string
|
||||
var current strings.Builder
|
||||
var inQuote, escaped bool
|
||||
var inQuote, escaped, wasQuoted bool
|
||||
|
||||
for _, r := range action {
|
||||
switch {
|
||||
@@ -389,17 +401,19 @@ func (n *NiriProvider) parseActionParts(action string) []string {
|
||||
case r == '\\':
|
||||
escaped = true
|
||||
case r == '"':
|
||||
wasQuoted = true
|
||||
inQuote = !inQuote
|
||||
case r == ' ' && !inQuote:
|
||||
if current.Len() > 0 {
|
||||
if current.Len() > 0 || wasQuoted {
|
||||
parts = append(parts, current.String())
|
||||
current.Reset()
|
||||
wasQuoted = false
|
||||
}
|
||||
default:
|
||||
current.WriteRune(r)
|
||||
}
|
||||
}
|
||||
if current.Len() > 0 {
|
||||
if current.Len() > 0 || wasQuoted {
|
||||
parts = append(parts, current.String())
|
||||
}
|
||||
return parts
|
||||
@@ -508,6 +522,10 @@ func (n *NiriProvider) writeBindNode(sb *strings.Builder, bind *overrideBind, in
|
||||
sb.WriteString(" ")
|
||||
n.writeArg(sb, arg.ValueString(), forceQuote)
|
||||
}
|
||||
if child.Properties.Exist() {
|
||||
sb.WriteString(" ")
|
||||
sb.WriteString(strings.TrimLeft(child.Properties.String(), " "))
|
||||
}
|
||||
}
|
||||
sb.WriteString("; }\n")
|
||||
}
|
||||
|
||||
@@ -265,6 +265,11 @@ func (p *NiriParser) parseKeybindNode(node *document.Node, _ string) *NiriKeyBin
|
||||
for _, arg := range actionNode.Arguments {
|
||||
args = append(args, arg.ValueString())
|
||||
}
|
||||
if actionNode.Properties != nil {
|
||||
if val, ok := actionNode.Properties.Get("focus"); ok {
|
||||
args = append(args, "focus="+val.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var description string
|
||||
|
||||
@@ -602,8 +602,24 @@ func TestNiriParseActionWithProperties(t *testing.T) {
|
||||
for _, kb := range result.Section.Keybinds {
|
||||
switch kb.Action {
|
||||
case "move-column-to-workspace":
|
||||
if len(kb.Args) != 1 {
|
||||
t.Errorf("move-column-to-workspace should have 1 arg, got %d", len(kb.Args))
|
||||
if len(kb.Args) != 2 {
|
||||
t.Errorf("move-column-to-workspace should have 2 args (index + focus), got %d", len(kb.Args))
|
||||
}
|
||||
hasIndex := false
|
||||
hasFocus := false
|
||||
for _, arg := range kb.Args {
|
||||
if arg == "1" || arg == "2" {
|
||||
hasIndex = true
|
||||
}
|
||||
if arg == "focus=false" {
|
||||
hasFocus = true
|
||||
}
|
||||
}
|
||||
if !hasIndex {
|
||||
t.Errorf("move-column-to-workspace missing index arg")
|
||||
}
|
||||
if !hasFocus {
|
||||
t.Errorf("move-column-to-workspace missing focus=false arg")
|
||||
}
|
||||
case "next-window":
|
||||
if kb.Key != "Tab" {
|
||||
|
||||
@@ -0,0 +1,587 @@
|
||||
package matugen
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/dank16"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
||||
)
|
||||
|
||||
var (
|
||||
matugenVersionOnce sync.Once
|
||||
matugenSupportsCOE bool
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
StateDir string
|
||||
ShellDir string
|
||||
ConfigDir string
|
||||
Kind string
|
||||
Value string
|
||||
Mode string
|
||||
IconTheme string
|
||||
MatugenType string
|
||||
RunUserTemplates bool
|
||||
StockColors string
|
||||
SyncModeWithPortal bool
|
||||
TerminalsAlwaysDark bool
|
||||
}
|
||||
|
||||
type ColorsOutput struct {
|
||||
Colors struct {
|
||||
Dark map[string]string `json:"dark"`
|
||||
Light map[string]string `json:"light"`
|
||||
} `json:"colors"`
|
||||
}
|
||||
|
||||
func (o *Options) ColorsOutput() string {
|
||||
return filepath.Join(o.StateDir, "dms-colors.json")
|
||||
}
|
||||
|
||||
func Run(opts Options) error {
|
||||
if opts.StateDir == "" {
|
||||
return fmt.Errorf("state-dir is required")
|
||||
}
|
||||
if opts.ShellDir == "" {
|
||||
return fmt.Errorf("shell-dir is required")
|
||||
}
|
||||
if opts.ConfigDir == "" {
|
||||
return fmt.Errorf("config-dir is required")
|
||||
}
|
||||
if opts.Kind == "" {
|
||||
return fmt.Errorf("kind is required")
|
||||
}
|
||||
if opts.Value == "" {
|
||||
return fmt.Errorf("value is required")
|
||||
}
|
||||
if opts.Mode == "" {
|
||||
opts.Mode = "dark"
|
||||
}
|
||||
if opts.MatugenType == "" {
|
||||
opts.MatugenType = "scheme-tonal-spot"
|
||||
}
|
||||
if opts.IconTheme == "" {
|
||||
opts.IconTheme = "System Default"
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(opts.StateDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create state dir: %w", err)
|
||||
}
|
||||
|
||||
log.Infof("Building theme: %s %s (%s)", opts.Kind, opts.Value, opts.Mode)
|
||||
|
||||
if err := buildOnce(&opts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.SyncModeWithPortal {
|
||||
syncColorScheme(opts.Mode)
|
||||
}
|
||||
|
||||
log.Info("Done")
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildOnce(opts *Options) error {
|
||||
cfgFile, err := os.CreateTemp("", "matugen-config-*.toml")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create temp config: %w", err)
|
||||
}
|
||||
defer os.Remove(cfgFile.Name())
|
||||
defer cfgFile.Close()
|
||||
|
||||
tmpDir, err := os.MkdirTemp("", "matugen-templates-*")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create temp dir: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
if err := buildMergedConfig(opts, cfgFile, tmpDir); err != nil {
|
||||
return fmt.Errorf("failed to build config: %w", err)
|
||||
}
|
||||
cfgFile.Close()
|
||||
|
||||
var primaryDark, primaryLight, surface string
|
||||
var dank16JSON string
|
||||
var importArgs []string
|
||||
|
||||
if opts.StockColors != "" {
|
||||
log.Info("Using stock/custom theme colors with matugen base")
|
||||
primaryDark = extractNestedColor(opts.StockColors, "primary", "dark")
|
||||
primaryLight = extractNestedColor(opts.StockColors, "primary", "light")
|
||||
surface = extractNestedColor(opts.StockColors, "surface", "dark")
|
||||
|
||||
if primaryDark == "" {
|
||||
return fmt.Errorf("failed to extract primary dark from stock colors")
|
||||
}
|
||||
if primaryLight == "" {
|
||||
primaryLight = primaryDark
|
||||
}
|
||||
|
||||
dank16JSON = generateDank16Variants(primaryDark, primaryLight, surface, opts.Mode)
|
||||
importData := fmt.Sprintf(`{"colors": %s, "dank16": %s}`, opts.StockColors, dank16JSON)
|
||||
importArgs = []string{"--import-json-string", importData}
|
||||
|
||||
log.Info("Running matugen color hex with stock color overrides")
|
||||
args := []string{"color", "hex", primaryDark, "-m", opts.Mode, "-t", opts.MatugenType, "-c", cfgFile.Name()}
|
||||
args = append(args, importArgs...)
|
||||
if err := runMatugen(args); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Infof("Using dynamic theme from %s: %s", opts.Kind, opts.Value)
|
||||
|
||||
matJSON, err := runMatugenDryRun(opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("matugen dry-run failed: %w", err)
|
||||
}
|
||||
|
||||
primaryDark = extractMatugenColor(matJSON, "primary", "dark")
|
||||
primaryLight = extractMatugenColor(matJSON, "primary", "light")
|
||||
surface = extractMatugenColor(matJSON, "surface", "dark")
|
||||
|
||||
if primaryDark == "" {
|
||||
return fmt.Errorf("failed to extract primary color")
|
||||
}
|
||||
if primaryLight == "" {
|
||||
primaryLight = primaryDark
|
||||
}
|
||||
|
||||
dank16JSON = generateDank16Variants(primaryDark, primaryLight, surface, opts.Mode)
|
||||
importData := fmt.Sprintf(`{"dank16": %s}`, dank16JSON)
|
||||
importArgs = []string{"--import-json-string", importData}
|
||||
|
||||
log.Infof("Running matugen %s with dank16 injection", opts.Kind)
|
||||
var args []string
|
||||
switch opts.Kind {
|
||||
case "hex":
|
||||
args = []string{"color", "hex", opts.Value}
|
||||
default:
|
||||
args = []string{opts.Kind, opts.Value}
|
||||
}
|
||||
args = append(args, "-m", opts.Mode, "-t", opts.MatugenType, "-c", cfgFile.Name())
|
||||
args = append(args, importArgs...)
|
||||
if err := runMatugen(args); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
refreshGTK(opts.ConfigDir, opts.Mode)
|
||||
signalTerminals()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildMergedConfig(opts *Options, cfgFile *os.File, tmpDir string) error {
|
||||
userConfigPath := filepath.Join(opts.ConfigDir, "matugen", "config.toml")
|
||||
|
||||
wroteConfig := false
|
||||
if opts.RunUserTemplates {
|
||||
if data, err := os.ReadFile(userConfigPath); err == nil {
|
||||
configSection := extractTOMLSection(string(data), "[config]", "[templates]")
|
||||
if configSection != "" {
|
||||
cfgFile.WriteString(configSection)
|
||||
cfgFile.WriteString("\n")
|
||||
wroteConfig = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !wroteConfig {
|
||||
cfgFile.WriteString("[config]\n\n")
|
||||
}
|
||||
|
||||
baseConfigPath := filepath.Join(opts.ShellDir, "matugen", "configs", "base.toml")
|
||||
if data, err := os.ReadFile(baseConfigPath); err == nil {
|
||||
content := string(data)
|
||||
lines := strings.Split(content, "\n")
|
||||
for _, line := range lines {
|
||||
if strings.TrimSpace(line) == "[config]" {
|
||||
continue
|
||||
}
|
||||
cfgFile.WriteString(substituteShellDir(line, opts.ShellDir) + "\n")
|
||||
}
|
||||
cfgFile.WriteString("\n")
|
||||
}
|
||||
|
||||
fmt.Fprintf(cfgFile, `[templates.dank]
|
||||
input_path = '%s/matugen/templates/dank.json'
|
||||
output_path = '%s'
|
||||
|
||||
`, opts.ShellDir, opts.ColorsOutput())
|
||||
|
||||
switch opts.Mode {
|
||||
case "light":
|
||||
appendConfig(opts, cfgFile, "skip", "gtk3-light.toml")
|
||||
default:
|
||||
appendConfig(opts, cfgFile, "skip", "gtk3-dark.toml")
|
||||
}
|
||||
|
||||
appendConfig(opts, cfgFile, "niri", "niri.toml")
|
||||
appendConfig(opts, cfgFile, "qt5ct", "qt5ct.toml")
|
||||
appendConfig(opts, cfgFile, "qt6ct", "qt6ct.toml")
|
||||
appendConfig(opts, cfgFile, "firefox", "firefox.toml")
|
||||
appendConfig(opts, cfgFile, "pywalfox", "pywalfox.toml")
|
||||
appendConfig(opts, cfgFile, "vesktop", "vesktop.toml")
|
||||
|
||||
appendTerminalConfig(opts, cfgFile, tmpDir, "ghostty", "ghostty.toml")
|
||||
appendTerminalConfig(opts, cfgFile, tmpDir, "kitty", "kitty.toml")
|
||||
appendTerminalConfig(opts, cfgFile, tmpDir, "foot", "foot.toml")
|
||||
appendTerminalConfig(opts, cfgFile, tmpDir, "alacritty", "alacritty.toml")
|
||||
appendTerminalConfig(opts, cfgFile, tmpDir, "wezterm", "wezterm.toml")
|
||||
|
||||
appendConfig(opts, cfgFile, "dgop", "dgop.toml")
|
||||
|
||||
homeDir, _ := os.UserHomeDir()
|
||||
appendVSCodeConfig(cfgFile, "vscode", filepath.Join(homeDir, ".vscode/extensions/local.dynamic-base16-dankshell-0.0.1"), opts.ShellDir)
|
||||
appendVSCodeConfig(cfgFile, "codium", filepath.Join(homeDir, ".vscode-oss/extensions/local.dynamic-base16-dankshell-0.0.1"), opts.ShellDir)
|
||||
appendVSCodeConfig(cfgFile, "codeoss", filepath.Join(homeDir, ".config/Code - OSS/extensions/local.dynamic-base16-dankshell-0.0.1"), opts.ShellDir)
|
||||
appendVSCodeConfig(cfgFile, "cursor", filepath.Join(homeDir, ".cursor/extensions/local.dynamic-base16-dankshell-0.0.1"), opts.ShellDir)
|
||||
appendVSCodeConfig(cfgFile, "windsurf", filepath.Join(homeDir, ".windsurf/extensions/local.dynamic-base16-dankshell-0.0.1"), opts.ShellDir)
|
||||
|
||||
if opts.RunUserTemplates {
|
||||
if data, err := os.ReadFile(userConfigPath); err == nil {
|
||||
templatesSection := extractTOMLSection(string(data), "[templates]", "")
|
||||
if templatesSection != "" {
|
||||
cfgFile.WriteString(templatesSection)
|
||||
cfgFile.WriteString("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
userPluginConfigDir := filepath.Join(opts.ConfigDir, "matugen", "dms", "configs")
|
||||
if entries, err := os.ReadDir(userPluginConfigDir); err == nil {
|
||||
for _, entry := range entries {
|
||||
if !strings.HasSuffix(entry.Name(), ".toml") {
|
||||
continue
|
||||
}
|
||||
if data, err := os.ReadFile(filepath.Join(userPluginConfigDir, entry.Name())); err == nil {
|
||||
cfgFile.WriteString(string(data))
|
||||
cfgFile.WriteString("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func appendConfig(opts *Options, cfgFile *os.File, checkCmd, fileName string) {
|
||||
configPath := filepath.Join(opts.ShellDir, "matugen", "configs", fileName)
|
||||
if _, err := os.Stat(configPath); err != nil {
|
||||
return
|
||||
}
|
||||
if checkCmd != "skip" && !commandExists(checkCmd) {
|
||||
return
|
||||
}
|
||||
data, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cfgFile.WriteString(substituteShellDir(string(data), opts.ShellDir))
|
||||
cfgFile.WriteString("\n")
|
||||
}
|
||||
|
||||
func appendTerminalConfig(opts *Options, cfgFile *os.File, tmpDir, checkCmd, fileName string) {
|
||||
configPath := filepath.Join(opts.ShellDir, "matugen", "configs", fileName)
|
||||
if _, err := os.Stat(configPath); err != nil {
|
||||
return
|
||||
}
|
||||
if checkCmd != "skip" && !commandExists(checkCmd) {
|
||||
return
|
||||
}
|
||||
data, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content := string(data)
|
||||
|
||||
if !opts.TerminalsAlwaysDark {
|
||||
cfgFile.WriteString(substituteShellDir(content, opts.ShellDir))
|
||||
cfgFile.WriteString("\n")
|
||||
return
|
||||
}
|
||||
|
||||
lines := strings.Split(content, "\n")
|
||||
for _, line := range lines {
|
||||
if !strings.Contains(line, "input_path") || !strings.Contains(line, "SHELL_DIR/matugen/templates/") {
|
||||
continue
|
||||
}
|
||||
|
||||
start := strings.Index(line, "'SHELL_DIR/matugen/templates/")
|
||||
if start == -1 {
|
||||
continue
|
||||
}
|
||||
end := strings.Index(line[start+1:], "'")
|
||||
if end == -1 {
|
||||
continue
|
||||
}
|
||||
templateName := line[start+len("'SHELL_DIR/matugen/templates/") : start+1+end]
|
||||
origPath := filepath.Join(opts.ShellDir, "matugen", "templates", templateName)
|
||||
|
||||
origData, err := os.ReadFile(origPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
modified := strings.ReplaceAll(string(origData), ".default.", ".dark.")
|
||||
tmpPath := filepath.Join(tmpDir, templateName)
|
||||
if err := os.WriteFile(tmpPath, []byte(modified), 0644); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
content = strings.ReplaceAll(content,
|
||||
fmt.Sprintf("'SHELL_DIR/matugen/templates/%s'", templateName),
|
||||
fmt.Sprintf("'%s'", tmpPath))
|
||||
}
|
||||
|
||||
cfgFile.WriteString(substituteShellDir(content, opts.ShellDir))
|
||||
cfgFile.WriteString("\n")
|
||||
}
|
||||
|
||||
func appendVSCodeConfig(cfgFile *os.File, name, extDir, shellDir string) {
|
||||
if _, err := os.Stat(extDir); err != nil {
|
||||
return
|
||||
}
|
||||
templateDir := filepath.Join(shellDir, "matugen", "templates")
|
||||
fmt.Fprintf(cfgFile, `[templates.dms%sdefault]
|
||||
input_path = '%s/vscode-color-theme-default.json'
|
||||
output_path = '%s/themes/dankshell-default.json'
|
||||
|
||||
[templates.dms%sdark]
|
||||
input_path = '%s/vscode-color-theme-dark.json'
|
||||
output_path = '%s/themes/dankshell-dark.json'
|
||||
|
||||
[templates.dms%slight]
|
||||
input_path = '%s/vscode-color-theme-light.json'
|
||||
output_path = '%s/themes/dankshell-light.json'
|
||||
|
||||
`, name, templateDir, extDir,
|
||||
name, templateDir, extDir,
|
||||
name, templateDir, extDir)
|
||||
log.Infof("Added %s theme config (extension found at %s)", name, extDir)
|
||||
}
|
||||
|
||||
func substituteShellDir(content, shellDir string) string {
|
||||
return strings.ReplaceAll(content, "'SHELL_DIR/", "'"+shellDir+"/")
|
||||
}
|
||||
|
||||
func extractTOMLSection(content, startMarker, endMarker string) string {
|
||||
startIdx := strings.Index(content, startMarker)
|
||||
if startIdx == -1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
if endMarker == "" {
|
||||
return content[startIdx:]
|
||||
}
|
||||
|
||||
endIdx := strings.Index(content[startIdx:], endMarker)
|
||||
if endIdx == -1 {
|
||||
return content[startIdx:]
|
||||
}
|
||||
return content[startIdx : startIdx+endIdx]
|
||||
}
|
||||
|
||||
func commandExists(name string) bool {
|
||||
_, err := exec.LookPath(name)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func checkMatugenVersion() {
|
||||
matugenVersionOnce.Do(func() {
|
||||
cmd := exec.Command("matugen", "--version")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
versionStr := strings.TrimSpace(string(output))
|
||||
versionStr = strings.TrimPrefix(versionStr, "matugen ")
|
||||
|
||||
parts := strings.Split(versionStr, ".")
|
||||
if len(parts) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
major, err := strconv.Atoi(parts[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
minor, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
matugenSupportsCOE = major > 3 || (major == 3 && minor >= 1)
|
||||
if matugenSupportsCOE {
|
||||
log.Infof("Matugen %s supports --continue-on-error", versionStr)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func runMatugen(args []string) error {
|
||||
checkMatugenVersion()
|
||||
|
||||
if matugenSupportsCOE {
|
||||
args = append([]string{"--continue-on-error"}, args...)
|
||||
}
|
||||
|
||||
cmd := exec.Command("matugen", args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func runMatugenDryRun(opts *Options) (string, error) {
|
||||
var args []string
|
||||
switch opts.Kind {
|
||||
case "hex":
|
||||
args = []string{"color", "hex", opts.Value}
|
||||
default:
|
||||
args = []string{opts.Kind, opts.Value}
|
||||
}
|
||||
args = append(args, "-m", "dark", "-t", opts.MatugenType, "--json", "hex", "--dry-run")
|
||||
|
||||
cmd := exec.Command("matugen", args...)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.ReplaceAll(string(output), "\n", ""), nil
|
||||
}
|
||||
|
||||
func extractMatugenColor(jsonStr, colorName, variant string) string {
|
||||
var data map[string]any
|
||||
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
colors, ok := data["colors"].(map[string]any)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
colorData, ok := colors[colorName].(map[string]any)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
variantData, ok := colorData[variant].(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
return variantData
|
||||
}
|
||||
|
||||
func extractNestedColor(jsonStr, colorName, variant string) string {
|
||||
var data map[string]any
|
||||
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
colorData, ok := data[colorName].(map[string]any)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
variantData, ok := colorData[variant].(map[string]any)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
color, ok := variantData["color"].(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
return color
|
||||
}
|
||||
|
||||
func generateDank16Variants(primaryDark, primaryLight, surface, mode string) string {
|
||||
variantOpts := dank16.VariantOptions{
|
||||
PrimaryDark: primaryDark,
|
||||
PrimaryLight: primaryLight,
|
||||
Background: surface,
|
||||
UseDPS: true,
|
||||
IsLightMode: mode == "light",
|
||||
}
|
||||
variantColors := dank16.GenerateVariantPalette(variantOpts)
|
||||
return dank16.GenerateVariantJSON(variantColors)
|
||||
}
|
||||
|
||||
func refreshGTK(configDir, mode string) {
|
||||
gtkCSS := filepath.Join(configDir, "gtk-3.0", "gtk.css")
|
||||
|
||||
info, err := os.Lstat(gtkCSS)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
shouldRun := false
|
||||
if info.Mode()&os.ModeSymlink != 0 {
|
||||
target, err := os.Readlink(gtkCSS)
|
||||
if err == nil && strings.Contains(target, "dank-colors.css") {
|
||||
shouldRun = true
|
||||
}
|
||||
} else {
|
||||
data, err := os.ReadFile(gtkCSS)
|
||||
if err == nil && strings.Contains(string(data), "dank-colors.css") {
|
||||
shouldRun = true
|
||||
}
|
||||
}
|
||||
|
||||
if !shouldRun {
|
||||
return
|
||||
}
|
||||
|
||||
exec.Command("gsettings", "set", "org.gnome.desktop.interface", "gtk-theme", "").Run()
|
||||
exec.Command("gsettings", "set", "org.gnome.desktop.interface", "gtk-theme", "adw-gtk3-"+mode).Run()
|
||||
}
|
||||
|
||||
func signalTerminals() {
|
||||
signalByName("kitty", syscall.SIGUSR1)
|
||||
signalByName("ghostty", syscall.SIGUSR2)
|
||||
signalByName(".kitty-wrapped", syscall.SIGUSR1)
|
||||
signalByName(".ghostty-wrappe", syscall.SIGUSR2)
|
||||
}
|
||||
|
||||
func signalByName(name string, sig syscall.Signal) {
|
||||
entries, err := os.ReadDir("/proc")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, entry := range entries {
|
||||
pid, err := strconv.Atoi(entry.Name())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
comm, err := os.ReadFile(filepath.Join("/proc", entry.Name(), "comm"))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if strings.TrimSpace(string(comm)) == name {
|
||||
syscall.Kill(pid, sig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func syncColorScheme(mode string) {
|
||||
scheme := "prefer-dark"
|
||||
if mode == "light" {
|
||||
scheme = "default"
|
||||
}
|
||||
|
||||
if err := exec.Command("gsettings", "set", "org.gnome.desktop.interface", "color-scheme", scheme).Run(); err != nil {
|
||||
exec.Command("dconf", "write", "/org/gnome/desktop/interface/color-scheme", "'"+scheme+"'").Run()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package matugen
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
||||
)
|
||||
|
||||
type Result struct {
|
||||
Success bool
|
||||
Error error
|
||||
}
|
||||
|
||||
type QueuedJob struct {
|
||||
Options Options
|
||||
Done chan Result
|
||||
Ctx context.Context
|
||||
Cancel context.CancelFunc
|
||||
}
|
||||
|
||||
type Queue struct {
|
||||
mu sync.Mutex
|
||||
current *QueuedJob
|
||||
pending *QueuedJob
|
||||
jobDone chan struct{}
|
||||
}
|
||||
|
||||
var globalQueue *Queue
|
||||
var queueOnce sync.Once
|
||||
|
||||
func GetQueue() *Queue {
|
||||
queueOnce.Do(func() {
|
||||
globalQueue = &Queue{
|
||||
jobDone: make(chan struct{}, 1),
|
||||
}
|
||||
})
|
||||
return globalQueue
|
||||
}
|
||||
|
||||
func (q *Queue) Submit(opts Options) <-chan Result {
|
||||
result := make(chan Result, 1)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
job := &QueuedJob{
|
||||
Options: opts,
|
||||
Done: result,
|
||||
Ctx: ctx,
|
||||
Cancel: cancel,
|
||||
}
|
||||
|
||||
q.mu.Lock()
|
||||
|
||||
if q.pending != nil {
|
||||
log.Info("Cancelling pending theme request")
|
||||
q.pending.Cancel()
|
||||
q.pending.Done <- Result{Success: false, Error: context.Canceled}
|
||||
close(q.pending.Done)
|
||||
}
|
||||
|
||||
if q.current != nil {
|
||||
q.pending = job
|
||||
q.mu.Unlock()
|
||||
log.Info("Theme request queued (worker running)")
|
||||
return result
|
||||
}
|
||||
|
||||
q.current = job
|
||||
q.mu.Unlock()
|
||||
|
||||
go q.runWorker()
|
||||
return result
|
||||
}
|
||||
|
||||
func (q *Queue) runWorker() {
|
||||
for {
|
||||
q.mu.Lock()
|
||||
job := q.current
|
||||
if job == nil {
|
||||
q.mu.Unlock()
|
||||
return
|
||||
}
|
||||
q.mu.Unlock()
|
||||
|
||||
select {
|
||||
case <-job.Ctx.Done():
|
||||
q.finishJob(Result{Success: false, Error: context.Canceled})
|
||||
continue
|
||||
default:
|
||||
}
|
||||
|
||||
log.Infof("Processing theme: %s %s (%s)", job.Options.Kind, job.Options.Value, job.Options.Mode)
|
||||
err := Run(job.Options)
|
||||
|
||||
var result Result
|
||||
if err != nil {
|
||||
result = Result{Success: false, Error: err}
|
||||
} else {
|
||||
result = Result{Success: true}
|
||||
}
|
||||
|
||||
q.finishJob(result)
|
||||
}
|
||||
}
|
||||
|
||||
func (q *Queue) finishJob(result Result) {
|
||||
q.mu.Lock()
|
||||
defer q.mu.Unlock()
|
||||
|
||||
if q.current != nil {
|
||||
select {
|
||||
case q.current.Done <- result:
|
||||
default:
|
||||
}
|
||||
close(q.current.Done)
|
||||
}
|
||||
|
||||
q.current = q.pending
|
||||
q.pending = nil
|
||||
|
||||
if q.current == nil {
|
||||
select {
|
||||
case q.jobDone <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (q *Queue) IsRunning() bool {
|
||||
q.mu.Lock()
|
||||
defer q.mu.Unlock()
|
||||
return q.current != nil
|
||||
}
|
||||
|
||||
func (q *Queue) HasPending() bool {
|
||||
q.mu.Lock()
|
||||
defer q.mu.Unlock()
|
||||
return q.pending != nil
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func NewZdwlIpcManagerV2(ctx *client.Context) *ZdwlIpcManagerV2 {
|
||||
// Indicates that the client will not the dwl_ipc_manager object anymore.
|
||||
// Objects created through this instance are not affected.
|
||||
func (i *ZdwlIpcManagerV2) Release() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -188,7 +188,7 @@ func NewZdwlIpcOutputV2(ctx *client.Context) *ZdwlIpcOutputV2 {
|
||||
//
|
||||
// Indicates to that the client no longer needs this dwl_ipc_output.
|
||||
func (i *ZdwlIpcOutputV2) Release() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
|
||||
@@ -174,7 +174,7 @@ func (i *ExtWorkspaceManagerV1) Stop() error {
|
||||
}
|
||||
|
||||
func (i *ExtWorkspaceManagerV1) Destroy() error {
|
||||
i.Context().Unregister(i)
|
||||
i.MarkZombie()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -385,7 +385,7 @@ func (i *ExtWorkspaceGroupHandleV1) CreateWorkspace(workspace string) error {
|
||||
// use the workspace group object any more or after the removed event to finalize
|
||||
// the destruction of the object.
|
||||
func (i *ExtWorkspaceGroupHandleV1) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 1
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -655,7 +655,7 @@ func NewExtWorkspaceHandleV1(ctx *client.Context) *ExtWorkspaceHandleV1 {
|
||||
// use the workspace object any more or after the remove event to finalize
|
||||
// the destruction of the object.
|
||||
func (i *ExtWorkspaceHandleV1) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
|
||||
@@ -54,7 +54,7 @@ func NewZwpKeyboardShortcutsInhibitManagerV1(ctx *client.Context) *ZwpKeyboardSh
|
||||
//
|
||||
// Destroy the keyboard shortcuts inhibitor manager.
|
||||
func (i *ZwpKeyboardShortcutsInhibitManagerV1) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -218,7 +218,7 @@ func NewZwpKeyboardShortcutsInhibitorV1(ctx *client.Context) *ZwpKeyboardShortcu
|
||||
//
|
||||
// Remove the keyboard shortcuts inhibitor from the associated wl_surface.
|
||||
func (i *ZwpKeyboardShortcutsInhibitorV1) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
|
||||
@@ -85,7 +85,7 @@ func (i *ZwlrGammaControlManagerV1) GetGammaControl(output *client.Output) (*Zwl
|
||||
// All objects created by the manager will still remain valid, until their
|
||||
// appropriate destroy request has been called.
|
||||
func (i *ZwlrGammaControlManagerV1) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 1
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -169,7 +169,7 @@ func (i *ZwlrGammaControlV1) SetGamma(fd int) error {
|
||||
// Destroys the gamma control object. If the object is still valid, this
|
||||
// restores the original gamma tables.
|
||||
func (i *ZwlrGammaControlV1) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 1
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
|
||||
@@ -129,7 +129,7 @@ func (i *ZwlrLayerShellV1) GetLayerSurface(surface *client.Surface, output *clie
|
||||
// object any more. Objects that have been created through this instance
|
||||
// are not affected.
|
||||
func (i *ZwlrLayerShellV1) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 1
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -509,7 +509,7 @@ func (i *ZwlrLayerSurfaceV1) AckConfigure(serial uint32) error {
|
||||
//
|
||||
// This request destroys the layer surface.
|
||||
func (i *ZwlrLayerSurfaceV1) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 7
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
|
||||
@@ -172,7 +172,7 @@ func (i *ZwlrOutputManagerV1) Stop() error {
|
||||
}
|
||||
|
||||
func (i *ZwlrOutputManagerV1) Destroy() error {
|
||||
i.Context().Unregister(i)
|
||||
i.MarkZombie()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ func NewZwlrOutputHeadV1(ctx *client.Context) *ZwlrOutputHeadV1 {
|
||||
// This request indicates that the client will no longer use this head
|
||||
// object.
|
||||
func (i *ZwlrOutputHeadV1) Release() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -879,7 +879,7 @@ func NewZwlrOutputModeV1(ctx *client.Context) *ZwlrOutputModeV1 {
|
||||
// This request indicates that the client will no longer use this mode
|
||||
// object.
|
||||
func (i *ZwlrOutputModeV1) Release() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -1132,7 +1132,7 @@ func (i *ZwlrOutputConfigurationV1) Test() error {
|
||||
// This request also destroys wlr_output_configuration_head objects created
|
||||
// via this object.
|
||||
func (i *ZwlrOutputConfigurationV1) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 4
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -1415,7 +1415,7 @@ func (i *ZwlrOutputConfigurationHeadV1) SetAdaptiveSync(state uint32) error {
|
||||
}
|
||||
|
||||
func (i *ZwlrOutputConfigurationHeadV1) Destroy() error {
|
||||
i.Context().Unregister(i)
|
||||
i.MarkZombie()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ func (i *ZwlrOutputPowerManagerV1) GetOutputPower(output *client.Output) (*ZwlrO
|
||||
// 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)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 1
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -143,7 +143,7 @@ func (i *ZwlrOutputPowerV1) SetMode(mode uint32) error {
|
||||
//
|
||||
// Destroys the output power management mode control object.
|
||||
func (i *ZwlrOutputPowerV1) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 1
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
|
||||
@@ -120,7 +120,7 @@ func (i *ZwlrScreencopyManagerV1) CaptureOutputRegion(overlayCursor int32, outpu
|
||||
// All objects created by the manager will still remain valid, until their
|
||||
// appropriate destroy request has been called.
|
||||
func (i *ZwlrScreencopyManagerV1) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 2
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -219,7 +219,7 @@ func (i *ZwlrScreencopyFrameV1) Copy(buffer *client.Buffer) error {
|
||||
//
|
||||
// Destroys the frame. This request can be sent at any time by the client.
|
||||
func (i *ZwlrScreencopyFrameV1) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 1
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
|
||||
@@ -66,7 +66,7 @@ func NewWpViewporter(ctx *client.Context) *WpViewporter {
|
||||
// protocol object anymore. This does not affect any other objects,
|
||||
// wp_viewport objects included.
|
||||
func (i *WpViewporter) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -267,7 +267,7 @@ func NewWpViewport(ctx *client.Context) *WpViewport {
|
||||
// The associated wl_surface's crop and scale state is removed.
|
||||
// The change is applied on the next wl_surface.commit.
|
||||
func (i *WpViewport) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
|
||||
@@ -5,6 +5,10 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/proto/dwl_ipc"
|
||||
wlhelpers "github.com/AvengeMedia/DankMaterialShell/core/internal/wayland/client"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
|
||||
)
|
||||
|
||||
type Compositor int
|
||||
@@ -12,13 +16,76 @@ type Compositor int
|
||||
const (
|
||||
CompositorUnknown Compositor = iota
|
||||
CompositorHyprland
|
||||
CompositorSway
|
||||
CompositorNiri
|
||||
CompositorDWL
|
||||
)
|
||||
|
||||
var detectedCompositor Compositor = -1
|
||||
|
||||
func DetectCompositor() Compositor {
|
||||
if os.Getenv("HYPRLAND_INSTANCE_SIGNATURE") != "" {
|
||||
return CompositorHyprland
|
||||
if detectedCompositor >= 0 {
|
||||
return detectedCompositor
|
||||
}
|
||||
return CompositorUnknown
|
||||
|
||||
hyprlandSig := os.Getenv("HYPRLAND_INSTANCE_SIGNATURE")
|
||||
niriSocket := os.Getenv("NIRI_SOCKET")
|
||||
swaySocket := os.Getenv("SWAYSOCK")
|
||||
|
||||
switch {
|
||||
case niriSocket != "":
|
||||
if _, err := os.Stat(niriSocket); err == nil {
|
||||
detectedCompositor = CompositorNiri
|
||||
return detectedCompositor
|
||||
}
|
||||
case swaySocket != "":
|
||||
if _, err := os.Stat(swaySocket); err == nil {
|
||||
detectedCompositor = CompositorSway
|
||||
return detectedCompositor
|
||||
}
|
||||
case hyprlandSig != "":
|
||||
detectedCompositor = CompositorHyprland
|
||||
return detectedCompositor
|
||||
}
|
||||
|
||||
if detectDWLProtocol() {
|
||||
detectedCompositor = CompositorDWL
|
||||
return detectedCompositor
|
||||
}
|
||||
|
||||
detectedCompositor = CompositorUnknown
|
||||
return detectedCompositor
|
||||
}
|
||||
|
||||
func detectDWLProtocol() bool {
|
||||
display, err := client.Connect("")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
ctx := display.Context()
|
||||
defer ctx.Close()
|
||||
|
||||
registry, err := display.GetRegistry()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
found := false
|
||||
registry.SetGlobalHandler(func(e client.RegistryGlobalEvent) {
|
||||
if e.Interface == dwl_ipc.ZdwlIpcManagerV2InterfaceName {
|
||||
found = true
|
||||
}
|
||||
})
|
||||
|
||||
if err := wlhelpers.Roundtrip(display, ctx); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return found
|
||||
}
|
||||
|
||||
func SetCompositorDWL() {
|
||||
detectedCompositor = CompositorDWL
|
||||
}
|
||||
|
||||
type WindowGeometry struct {
|
||||
@@ -26,16 +93,18 @@ type WindowGeometry struct {
|
||||
Y int32
|
||||
Width int32
|
||||
Height int32
|
||||
Output string
|
||||
Scale float64
|
||||
}
|
||||
|
||||
func GetActiveWindow() (*WindowGeometry, error) {
|
||||
compositor := DetectCompositor()
|
||||
|
||||
switch compositor {
|
||||
switch DetectCompositor() {
|
||||
case CompositorHyprland:
|
||||
return getHyprlandActiveWindow()
|
||||
case CompositorDWL:
|
||||
return getDWLActiveWindow()
|
||||
default:
|
||||
return nil, fmt.Errorf("window capture requires Hyprland (other compositors not yet supported)")
|
||||
return nil, fmt.Errorf("window capture requires Hyprland or DWL")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +114,7 @@ type hyprlandWindow struct {
|
||||
}
|
||||
|
||||
func getHyprlandActiveWindow() (*WindowGeometry, error) {
|
||||
cmd := exec.Command("hyprctl", "-j", "activewindow")
|
||||
output, err := cmd.Output()
|
||||
output, err := exec.Command("hyprctl", "-j", "activewindow").Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("hyprctl activewindow: %w", err)
|
||||
}
|
||||
@@ -67,3 +135,389 @@ func getHyprlandActiveWindow() (*WindowGeometry, error) {
|
||||
Height: win.Size[1],
|
||||
}, nil
|
||||
}
|
||||
|
||||
type hyprlandMonitor struct {
|
||||
Name string `json:"name"`
|
||||
X int32 `json:"x"`
|
||||
Y int32 `json:"y"`
|
||||
Width int32 `json:"width"`
|
||||
Height int32 `json:"height"`
|
||||
Scale float64 `json:"scale"`
|
||||
Focused bool `json:"focused"`
|
||||
}
|
||||
|
||||
func GetHyprlandMonitorScale(name string) float64 {
|
||||
output, err := exec.Command("hyprctl", "-j", "monitors").Output()
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
var monitors []hyprlandMonitor
|
||||
if err := json.Unmarshal(output, &monitors); err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
for _, m := range monitors {
|
||||
if m.Name == name {
|
||||
return m.Scale
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func getHyprlandFocusedMonitor() string {
|
||||
output, err := exec.Command("hyprctl", "-j", "monitors").Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var monitors []hyprlandMonitor
|
||||
if err := json.Unmarshal(output, &monitors); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
for _, m := range monitors {
|
||||
if m.Focused {
|
||||
return m.Name
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func GetHyprlandMonitorGeometry(name string) (x, y, w, h int32, ok bool) {
|
||||
output, err := exec.Command("hyprctl", "-j", "monitors").Output()
|
||||
if err != nil {
|
||||
return 0, 0, 0, 0, false
|
||||
}
|
||||
|
||||
var monitors []hyprlandMonitor
|
||||
if err := json.Unmarshal(output, &monitors); err != nil {
|
||||
return 0, 0, 0, 0, false
|
||||
}
|
||||
|
||||
for _, m := range monitors {
|
||||
if m.Name == name {
|
||||
logicalW := int32(float64(m.Width) / m.Scale)
|
||||
logicalH := int32(float64(m.Height) / m.Scale)
|
||||
return m.X, m.Y, logicalW, logicalH, true
|
||||
}
|
||||
}
|
||||
return 0, 0, 0, 0, false
|
||||
}
|
||||
|
||||
type swayWorkspace struct {
|
||||
Output string `json:"output"`
|
||||
Focused bool `json:"focused"`
|
||||
}
|
||||
|
||||
func getSwayFocusedMonitor() string {
|
||||
output, err := exec.Command("swaymsg", "-t", "get_workspaces").Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var workspaces []swayWorkspace
|
||||
if err := json.Unmarshal(output, &workspaces); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
for _, ws := range workspaces {
|
||||
if ws.Focused {
|
||||
return ws.Output
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type niriWorkspace struct {
|
||||
Output string `json:"output"`
|
||||
IsFocused bool `json:"is_focused"`
|
||||
}
|
||||
|
||||
func getNiriFocusedMonitor() string {
|
||||
output, err := exec.Command("niri", "msg", "-j", "workspaces").Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var workspaces []niriWorkspace
|
||||
if err := json.Unmarshal(output, &workspaces); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
for _, ws := range workspaces {
|
||||
if ws.IsFocused {
|
||||
return ws.Output
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var dwlActiveOutput string
|
||||
|
||||
func SetDWLActiveOutput(name string) {
|
||||
dwlActiveOutput = name
|
||||
}
|
||||
|
||||
func getDWLFocusedMonitor() string {
|
||||
if dwlActiveOutput != "" {
|
||||
return dwlActiveOutput
|
||||
}
|
||||
return queryDWLActiveOutput()
|
||||
}
|
||||
|
||||
func queryDWLActiveOutput() string {
|
||||
display, err := client.Connect("")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
ctx := display.Context()
|
||||
defer ctx.Close()
|
||||
|
||||
registry, err := display.GetRegistry()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var dwlManager *dwl_ipc.ZdwlIpcManagerV2
|
||||
outputs := make(map[uint32]*client.Output)
|
||||
|
||||
registry.SetGlobalHandler(func(e client.RegistryGlobalEvent) {
|
||||
switch e.Interface {
|
||||
case dwl_ipc.ZdwlIpcManagerV2InterfaceName:
|
||||
mgr := dwl_ipc.NewZdwlIpcManagerV2(ctx)
|
||||
if err := registry.Bind(e.Name, e.Interface, e.Version, mgr); err == nil {
|
||||
dwlManager = mgr
|
||||
}
|
||||
case client.OutputInterfaceName:
|
||||
out := client.NewOutput(ctx)
|
||||
version := e.Version
|
||||
if version > 4 {
|
||||
version = 4
|
||||
}
|
||||
if err := registry.Bind(e.Name, e.Interface, version, out); err == nil {
|
||||
outputs[e.Name] = out
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if err := wlhelpers.Roundtrip(display, ctx); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if dwlManager == nil || len(outputs) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
outputNames := make(map[uint32]string)
|
||||
for name, out := range outputs {
|
||||
n := name
|
||||
out.SetNameHandler(func(e client.OutputNameEvent) {
|
||||
outputNames[n] = e.Name
|
||||
})
|
||||
}
|
||||
|
||||
if err := wlhelpers.Roundtrip(display, ctx); err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
type outputState struct {
|
||||
name string
|
||||
active bool
|
||||
gotFrame bool
|
||||
}
|
||||
states := make(map[uint32]*outputState)
|
||||
|
||||
for name, out := range outputs {
|
||||
dwlOut, err := dwlManager.GetOutput(out)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
state := &outputState{name: outputNames[name]}
|
||||
states[name] = state
|
||||
|
||||
dwlOut.SetActiveHandler(func(e dwl_ipc.ZdwlIpcOutputV2ActiveEvent) {
|
||||
state.active = e.Active != 0
|
||||
})
|
||||
dwlOut.SetFrameHandler(func(e dwl_ipc.ZdwlIpcOutputV2FrameEvent) {
|
||||
state.gotFrame = true
|
||||
})
|
||||
}
|
||||
|
||||
allFramesReceived := func() bool {
|
||||
for _, s := range states {
|
||||
if !s.gotFrame {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
for !allFramesReceived() {
|
||||
if err := ctx.Dispatch(); err != nil {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
for _, state := range states {
|
||||
if state.active {
|
||||
return state.name
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func GetFocusedMonitor() string {
|
||||
switch DetectCompositor() {
|
||||
case CompositorHyprland:
|
||||
return getHyprlandFocusedMonitor()
|
||||
case CompositorSway:
|
||||
return getSwayFocusedMonitor()
|
||||
case CompositorNiri:
|
||||
return getNiriFocusedMonitor()
|
||||
case CompositorDWL:
|
||||
return getDWLFocusedMonitor()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getDWLActiveWindow() (*WindowGeometry, error) {
|
||||
display, err := client.Connect("")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("connect: %w", err)
|
||||
}
|
||||
ctx := display.Context()
|
||||
defer ctx.Close()
|
||||
|
||||
registry, err := display.GetRegistry()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get registry: %w", err)
|
||||
}
|
||||
|
||||
var dwlManager *dwl_ipc.ZdwlIpcManagerV2
|
||||
outputs := make(map[uint32]*client.Output)
|
||||
|
||||
registry.SetGlobalHandler(func(e client.RegistryGlobalEvent) {
|
||||
switch e.Interface {
|
||||
case dwl_ipc.ZdwlIpcManagerV2InterfaceName:
|
||||
mgr := dwl_ipc.NewZdwlIpcManagerV2(ctx)
|
||||
if err := registry.Bind(e.Name, e.Interface, e.Version, mgr); err == nil {
|
||||
dwlManager = mgr
|
||||
}
|
||||
case client.OutputInterfaceName:
|
||||
out := client.NewOutput(ctx)
|
||||
version := e.Version
|
||||
if version > 4 {
|
||||
version = 4
|
||||
}
|
||||
if err := registry.Bind(e.Name, e.Interface, version, out); err == nil {
|
||||
outputs[e.Name] = out
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if err := wlhelpers.Roundtrip(display, ctx); err != nil {
|
||||
return nil, fmt.Errorf("roundtrip: %w", err)
|
||||
}
|
||||
|
||||
if dwlManager == nil {
|
||||
return nil, fmt.Errorf("dwl_ipc_manager not available")
|
||||
}
|
||||
|
||||
if len(outputs) == 0 {
|
||||
return nil, fmt.Errorf("no outputs found")
|
||||
}
|
||||
|
||||
outputNames := make(map[uint32]string)
|
||||
for name, out := range outputs {
|
||||
n := name
|
||||
out.SetNameHandler(func(e client.OutputNameEvent) {
|
||||
outputNames[n] = e.Name
|
||||
})
|
||||
}
|
||||
|
||||
if err := wlhelpers.Roundtrip(display, ctx); err != nil {
|
||||
return nil, fmt.Errorf("roundtrip: %w", err)
|
||||
}
|
||||
|
||||
type dwlOutputState struct {
|
||||
output *dwl_ipc.ZdwlIpcOutputV2
|
||||
name string
|
||||
active bool
|
||||
x, y int32
|
||||
w, h int32
|
||||
scalefactor uint32
|
||||
gotFrame bool
|
||||
}
|
||||
|
||||
dwlOutputs := make(map[uint32]*dwlOutputState)
|
||||
for name, out := range outputs {
|
||||
dwlOut, err := dwlManager.GetOutput(out)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
state := &dwlOutputState{output: dwlOut, name: outputNames[name]}
|
||||
dwlOutputs[name] = state
|
||||
|
||||
dwlOut.SetActiveHandler(func(e dwl_ipc.ZdwlIpcOutputV2ActiveEvent) {
|
||||
state.active = e.Active != 0
|
||||
})
|
||||
dwlOut.SetXHandler(func(e dwl_ipc.ZdwlIpcOutputV2XEvent) {
|
||||
state.x = e.X
|
||||
})
|
||||
dwlOut.SetYHandler(func(e dwl_ipc.ZdwlIpcOutputV2YEvent) {
|
||||
state.y = e.Y
|
||||
})
|
||||
dwlOut.SetWidthHandler(func(e dwl_ipc.ZdwlIpcOutputV2WidthEvent) {
|
||||
state.w = e.Width
|
||||
})
|
||||
dwlOut.SetHeightHandler(func(e dwl_ipc.ZdwlIpcOutputV2HeightEvent) {
|
||||
state.h = e.Height
|
||||
})
|
||||
dwlOut.SetScalefactorHandler(func(e dwl_ipc.ZdwlIpcOutputV2ScalefactorEvent) {
|
||||
state.scalefactor = e.Scalefactor
|
||||
})
|
||||
dwlOut.SetFrameHandler(func(e dwl_ipc.ZdwlIpcOutputV2FrameEvent) {
|
||||
state.gotFrame = true
|
||||
})
|
||||
}
|
||||
|
||||
allFramesReceived := func() bool {
|
||||
for _, s := range dwlOutputs {
|
||||
if !s.gotFrame {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
for !allFramesReceived() {
|
||||
if err := ctx.Dispatch(); err != nil {
|
||||
return nil, fmt.Errorf("dispatch: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, state := range dwlOutputs {
|
||||
if !state.active {
|
||||
continue
|
||||
}
|
||||
if state.w <= 0 || state.h <= 0 {
|
||||
return nil, fmt.Errorf("no active window")
|
||||
}
|
||||
scale := float64(state.scalefactor) / 100.0
|
||||
if scale <= 0 {
|
||||
scale = 1.0
|
||||
}
|
||||
return &WindowGeometry{
|
||||
X: state.x,
|
||||
Y: state.y,
|
||||
Width: state.w,
|
||||
Height: state.h,
|
||||
Output: state.name,
|
||||
Scale: scale,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no active output found")
|
||||
}
|
||||
|
||||
@@ -251,9 +251,10 @@ func (r *RegionSelector) handleGlobal(e client.RegistryGlobalEvent) {
|
||||
if err := r.registry.Bind(e.Name, e.Interface, version, output); err == nil {
|
||||
r.outputsMu.Lock()
|
||||
r.outputs[e.Name] = &WaylandOutput{
|
||||
wlOutput: output,
|
||||
globalName: e.Name,
|
||||
scale: 1,
|
||||
wlOutput: output,
|
||||
globalName: e.Name,
|
||||
scale: 1,
|
||||
fractionalScale: 1.0,
|
||||
}
|
||||
r.outputsMu.Unlock()
|
||||
r.setupOutputHandlers(e.Name, output)
|
||||
@@ -320,6 +321,7 @@ func (r *RegionSelector) setupOutputHandlers(name uint32, output *client.Output)
|
||||
r.outputsMu.Lock()
|
||||
if o, ok := r.outputs[name]; ok {
|
||||
o.scale = e.Factor
|
||||
o.fractionalScale = float64(e.Factor)
|
||||
}
|
||||
r.outputsMu.Unlock()
|
||||
})
|
||||
@@ -607,6 +609,10 @@ func (r *RegionSelector) captureForSurface(os *OutputSurface) {
|
||||
os.screenFormat = pc.format
|
||||
os.yInverted = pc.yInverted
|
||||
|
||||
if os.logicalW > 0 && os.screenBuf != nil {
|
||||
os.output.fractionalScale = float64(os.screenBuf.Width) / float64(os.logicalW)
|
||||
}
|
||||
|
||||
r.initRenderBuffer(os)
|
||||
r.applyPreSelection(os)
|
||||
r.redrawSurface(os)
|
||||
@@ -713,19 +719,17 @@ func (r *RegionSelector) redrawSurface(os *OutputSurface) {
|
||||
// Draw overlay (dimming + selection) into this slot
|
||||
r.drawOverlay(os, slot.shm)
|
||||
|
||||
// Attach and commit (viewport only needs to be set once, but it's cheap)
|
||||
scale := os.output.scale
|
||||
if scale <= 0 {
|
||||
scale = 1
|
||||
}
|
||||
|
||||
if os.viewport != nil {
|
||||
srcW := float64(slot.shm.Width) / float64(scale)
|
||||
srcH := float64(slot.shm.Height) / float64(scale)
|
||||
_ = os.viewport.SetSource(0, 0, srcW, srcH)
|
||||
_ = os.wlSurface.SetBufferScale(1)
|
||||
_ = os.viewport.SetSource(0, 0, float64(slot.shm.Width), float64(slot.shm.Height))
|
||||
_ = os.viewport.SetDestination(int32(os.logicalW), int32(os.logicalH))
|
||||
} else {
|
||||
bufferScale := os.output.scale
|
||||
if bufferScale <= 0 {
|
||||
bufferScale = 1
|
||||
}
|
||||
_ = os.wlSurface.SetBufferScale(bufferScale)
|
||||
}
|
||||
_ = os.wlSurface.SetBufferScale(scale)
|
||||
|
||||
_ = os.wlSurface.Attach(slot.wlBuf, 0, 0)
|
||||
_ = os.wlSurface.Damage(0, 0, int32(os.logicalW), int32(os.logicalH))
|
||||
|
||||
@@ -223,16 +223,23 @@ func (r *RegionSelector) finishSelection() {
|
||||
dstData := cropped.Data()
|
||||
for y := 0; y < h; y++ {
|
||||
srcY := by1 + y
|
||||
if srcY >= srcBuf.Height {
|
||||
break
|
||||
if os.yInverted {
|
||||
srcY = srcBuf.Height - 1 - (by1 + y)
|
||||
}
|
||||
if srcY < 0 || srcY >= srcBuf.Height {
|
||||
continue
|
||||
}
|
||||
dstY := y
|
||||
if os.yInverted {
|
||||
dstY = h - 1 - y
|
||||
}
|
||||
for x := 0; x < w; x++ {
|
||||
srcX := bx1 + x
|
||||
if srcX >= srcBuf.Width {
|
||||
break
|
||||
if srcX < 0 || srcX >= srcBuf.Width {
|
||||
continue
|
||||
}
|
||||
si := srcY*srcBuf.Stride + srcX*4
|
||||
di := y*cropped.Stride + x*4
|
||||
di := dstY*cropped.Stride + x*4
|
||||
if si+3 < len(srcData) && di+3 < len(dstData) {
|
||||
dstData[di+0] = srcData[si+0]
|
||||
dstData[di+1] = srcData[si+1]
|
||||
|
||||
@@ -11,14 +11,15 @@ import (
|
||||
)
|
||||
|
||||
type WaylandOutput struct {
|
||||
wlOutput *client.Output
|
||||
globalName uint32
|
||||
name string
|
||||
x, y int32
|
||||
width int32
|
||||
height int32
|
||||
scale int32
|
||||
transform int32
|
||||
wlOutput *client.Output
|
||||
globalName uint32
|
||||
name string
|
||||
x, y int32
|
||||
width int32
|
||||
height int32
|
||||
scale int32
|
||||
fractionalScale float64
|
||||
transform int32
|
||||
}
|
||||
|
||||
type CaptureResult struct {
|
||||
@@ -134,12 +135,138 @@ func (s *Screenshoter) captureWindow() (*CaptureResult, error) {
|
||||
Height: geom.Height,
|
||||
}
|
||||
|
||||
output := s.findOutputForRegion(region)
|
||||
var output *WaylandOutput
|
||||
if geom.Output != "" {
|
||||
output = s.findOutputByName(geom.Output)
|
||||
}
|
||||
if output == nil {
|
||||
output = s.findOutputForRegion(region)
|
||||
}
|
||||
if output == nil {
|
||||
return nil, fmt.Errorf("could not find output for window")
|
||||
}
|
||||
|
||||
return s.captureRegionOnOutput(output, region)
|
||||
switch DetectCompositor() {
|
||||
case CompositorHyprland:
|
||||
return s.captureAndCrop(output, region)
|
||||
case CompositorDWL:
|
||||
return s.captureDWLWindow(output, region, geom.Scale)
|
||||
default:
|
||||
return s.captureRegionOnOutput(output, region)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Screenshoter) captureDWLWindow(output *WaylandOutput, region Region, dwlScale float64) (*CaptureResult, error) {
|
||||
result, err := s.captureWholeOutput(output)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
scale := dwlScale
|
||||
if scale <= 0 {
|
||||
scale = float64(result.Buffer.Width) / float64(output.width)
|
||||
}
|
||||
if scale <= 0 {
|
||||
scale = 1.0
|
||||
}
|
||||
|
||||
localX := int(float64(region.X) * scale)
|
||||
localY := int(float64(region.Y) * scale)
|
||||
if localX >= result.Buffer.Width {
|
||||
localX = localX % result.Buffer.Width
|
||||
}
|
||||
if localY >= result.Buffer.Height {
|
||||
localY = localY % result.Buffer.Height
|
||||
}
|
||||
|
||||
w := int(float64(region.Width) * scale)
|
||||
h := int(float64(region.Height) * scale)
|
||||
|
||||
if localY+h > result.Buffer.Height && h <= result.Buffer.Height {
|
||||
localY = result.Buffer.Height - h
|
||||
if localY < 0 {
|
||||
localY = 0
|
||||
}
|
||||
}
|
||||
if localX+w > result.Buffer.Width && w <= result.Buffer.Width {
|
||||
localX = result.Buffer.Width - w
|
||||
if localX < 0 {
|
||||
localX = 0
|
||||
}
|
||||
}
|
||||
|
||||
if localX < 0 {
|
||||
w += localX
|
||||
localX = 0
|
||||
}
|
||||
if localY < 0 {
|
||||
h += localY
|
||||
localY = 0
|
||||
}
|
||||
if localX+w > result.Buffer.Width {
|
||||
w = result.Buffer.Width - localX
|
||||
}
|
||||
if localY+h > result.Buffer.Height {
|
||||
h = result.Buffer.Height - localY
|
||||
}
|
||||
|
||||
if w <= 0 || h <= 0 {
|
||||
result.Buffer.Close()
|
||||
return nil, fmt.Errorf("window not visible on output")
|
||||
}
|
||||
|
||||
cropped, err := CreateShmBuffer(w, h, w*4)
|
||||
if err != nil {
|
||||
result.Buffer.Close()
|
||||
return nil, fmt.Errorf("create crop buffer: %w", err)
|
||||
}
|
||||
|
||||
srcData := result.Buffer.Data()
|
||||
dstData := cropped.Data()
|
||||
|
||||
for y := 0; y < h; y++ {
|
||||
srcY := localY + y
|
||||
if result.YInverted {
|
||||
srcY = result.Buffer.Height - 1 - (localY + y)
|
||||
}
|
||||
if srcY < 0 || srcY >= result.Buffer.Height {
|
||||
continue
|
||||
}
|
||||
|
||||
dstY := y
|
||||
if result.YInverted {
|
||||
dstY = h - 1 - y
|
||||
}
|
||||
|
||||
for x := 0; x < w; x++ {
|
||||
srcX := localX + x
|
||||
if srcX < 0 || srcX >= result.Buffer.Width {
|
||||
continue
|
||||
}
|
||||
|
||||
si := srcY*result.Buffer.Stride + srcX*4
|
||||
di := dstY*cropped.Stride + x*4
|
||||
|
||||
if si+3 >= len(srcData) || di+3 >= len(dstData) {
|
||||
continue
|
||||
}
|
||||
|
||||
dstData[di+0] = srcData[si+0]
|
||||
dstData[di+1] = srcData[si+1]
|
||||
dstData[di+2] = srcData[si+2]
|
||||
dstData[di+3] = srcData[si+3]
|
||||
}
|
||||
}
|
||||
|
||||
result.Buffer.Close()
|
||||
cropped.Format = PixelFormat(result.Format)
|
||||
|
||||
return &CaptureResult{
|
||||
Buffer: cropped,
|
||||
Region: region,
|
||||
YInverted: false,
|
||||
Format: result.Format,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Screenshoter) captureFullScreen() (*CaptureResult, error) {
|
||||
@@ -181,33 +308,8 @@ func (s *Screenshoter) captureOutput(name string) (*CaptureResult, error) {
|
||||
func (s *Screenshoter) captureAllScreens() (*CaptureResult, error) {
|
||||
s.outputsMu.Lock()
|
||||
outputs := make([]*WaylandOutput, 0, len(s.outputs))
|
||||
var minX, minY, maxX, maxY int32
|
||||
first := true
|
||||
|
||||
for _, o := range s.outputs {
|
||||
outputs = append(outputs, o)
|
||||
right := o.x + o.width
|
||||
bottom := o.y + o.height
|
||||
|
||||
if first {
|
||||
minX, minY = o.x, o.y
|
||||
maxX, maxY = right, bottom
|
||||
first = false
|
||||
continue
|
||||
}
|
||||
|
||||
if o.x < minX {
|
||||
minX = o.x
|
||||
}
|
||||
if o.y < minY {
|
||||
minY = o.y
|
||||
}
|
||||
if right > maxX {
|
||||
maxX = right
|
||||
}
|
||||
if bottom > maxY {
|
||||
maxY = bottom
|
||||
}
|
||||
}
|
||||
s.outputsMu.Unlock()
|
||||
|
||||
@@ -219,18 +321,18 @@ func (s *Screenshoter) captureAllScreens() (*CaptureResult, error) {
|
||||
return s.captureWholeOutput(outputs[0])
|
||||
}
|
||||
|
||||
totalW := maxX - minX
|
||||
totalH := maxY - minY
|
||||
|
||||
compositeStride := int(totalW) * 4
|
||||
composite, err := CreateShmBuffer(int(totalW), int(totalH), compositeStride)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create composite buffer: %w", err)
|
||||
// Capture all outputs first to get actual buffer sizes
|
||||
type capturedOutput struct {
|
||||
output *WaylandOutput
|
||||
result *CaptureResult
|
||||
physX int
|
||||
physY int
|
||||
}
|
||||
captured := make([]capturedOutput, 0, len(outputs))
|
||||
|
||||
composite.Clear()
|
||||
var minX, minY, maxX, maxY int
|
||||
first := true
|
||||
|
||||
var format uint32
|
||||
for _, output := range outputs {
|
||||
result, err := s.captureWholeOutput(output)
|
||||
if err != nil {
|
||||
@@ -238,16 +340,88 @@ func (s *Screenshoter) captureAllScreens() (*CaptureResult, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
if format == 0 {
|
||||
format = result.Format
|
||||
outX, outY := output.x, output.y
|
||||
scale := float64(output.scale)
|
||||
if DetectCompositor() == CompositorHyprland {
|
||||
if hx, hy, _, _, ok := GetHyprlandMonitorGeometry(output.name); ok {
|
||||
outX, outY = hx, hy
|
||||
}
|
||||
if s := GetHyprlandMonitorScale(output.name); s > 0 {
|
||||
scale = s
|
||||
}
|
||||
}
|
||||
s.blitBuffer(composite, result.Buffer, int(output.x-minX), int(output.y-minY), result.YInverted)
|
||||
result.Buffer.Close()
|
||||
if scale <= 0 {
|
||||
scale = 1.0
|
||||
}
|
||||
|
||||
physX := int(float64(outX) * scale)
|
||||
physY := int(float64(outY) * scale)
|
||||
|
||||
captured = append(captured, capturedOutput{
|
||||
output: output,
|
||||
result: result,
|
||||
physX: physX,
|
||||
physY: physY,
|
||||
})
|
||||
|
||||
right := physX + result.Buffer.Width
|
||||
bottom := physY + result.Buffer.Height
|
||||
|
||||
if first {
|
||||
minX, minY = physX, physY
|
||||
maxX, maxY = right, bottom
|
||||
first = false
|
||||
continue
|
||||
}
|
||||
|
||||
if physX < minX {
|
||||
minX = physX
|
||||
}
|
||||
if physY < minY {
|
||||
minY = physY
|
||||
}
|
||||
if right > maxX {
|
||||
maxX = right
|
||||
}
|
||||
if bottom > maxY {
|
||||
maxY = bottom
|
||||
}
|
||||
}
|
||||
|
||||
if len(captured) == 0 {
|
||||
return nil, fmt.Errorf("failed to capture any outputs")
|
||||
}
|
||||
|
||||
if len(captured) == 1 {
|
||||
return captured[0].result, nil
|
||||
}
|
||||
|
||||
totalW := maxX - minX
|
||||
totalH := maxY - minY
|
||||
|
||||
compositeStride := totalW * 4
|
||||
composite, err := CreateShmBuffer(totalW, totalH, compositeStride)
|
||||
if err != nil {
|
||||
for _, c := range captured {
|
||||
c.result.Buffer.Close()
|
||||
}
|
||||
return nil, fmt.Errorf("create composite buffer: %w", err)
|
||||
}
|
||||
|
||||
composite.Clear()
|
||||
|
||||
var format uint32
|
||||
for _, c := range captured {
|
||||
if format == 0 {
|
||||
format = c.result.Format
|
||||
}
|
||||
s.blitBuffer(composite, c.result.Buffer, c.physX-minX, c.physY-minY, c.result.YInverted)
|
||||
c.result.Buffer.Close()
|
||||
}
|
||||
|
||||
return &CaptureResult{
|
||||
Buffer: composite,
|
||||
Region: Region{X: minX, Y: minY, Width: totalW, Height: totalH},
|
||||
Region: Region{X: int32(minX), Y: int32(minY), Width: int32(totalW), Height: int32(totalH)},
|
||||
Format: format,
|
||||
}, nil
|
||||
}
|
||||
@@ -311,21 +485,131 @@ func (s *Screenshoter) captureWholeOutput(output *WaylandOutput) (*CaptureResult
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Screenshoter) captureAndCrop(output *WaylandOutput, region Region) (*CaptureResult, error) {
|
||||
result, err := s.captureWholeOutput(output)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
outX, outY := output.x, output.y
|
||||
scale := float64(output.scale)
|
||||
if hx, hy, _, _, ok := GetHyprlandMonitorGeometry(output.name); ok {
|
||||
outX, outY = hx, hy
|
||||
}
|
||||
if s := GetHyprlandMonitorScale(output.name); s > 0 {
|
||||
scale = s
|
||||
}
|
||||
if scale <= 0 {
|
||||
scale = 1.0
|
||||
}
|
||||
|
||||
localX := int(float64(region.X-outX) * scale)
|
||||
localY := int(float64(region.Y-outY) * scale)
|
||||
w := int(float64(region.Width) * scale)
|
||||
h := int(float64(region.Height) * scale)
|
||||
|
||||
cropped, err := CreateShmBuffer(w, h, w*4)
|
||||
if err != nil {
|
||||
result.Buffer.Close()
|
||||
return nil, fmt.Errorf("create crop buffer: %w", err)
|
||||
}
|
||||
|
||||
srcData := result.Buffer.Data()
|
||||
dstData := cropped.Data()
|
||||
|
||||
for y := 0; y < h; y++ {
|
||||
srcY := localY + y
|
||||
if result.YInverted {
|
||||
srcY = result.Buffer.Height - 1 - (localY + y)
|
||||
}
|
||||
if srcY < 0 || srcY >= result.Buffer.Height {
|
||||
continue
|
||||
}
|
||||
|
||||
dstY := y
|
||||
if result.YInverted {
|
||||
dstY = h - 1 - y
|
||||
}
|
||||
|
||||
for x := 0; x < w; x++ {
|
||||
srcX := localX + x
|
||||
if srcX < 0 || srcX >= result.Buffer.Width {
|
||||
continue
|
||||
}
|
||||
|
||||
si := srcY*result.Buffer.Stride + srcX*4
|
||||
di := dstY*cropped.Stride + x*4
|
||||
|
||||
if si+3 >= len(srcData) || di+3 >= len(dstData) {
|
||||
continue
|
||||
}
|
||||
|
||||
dstData[di+0] = srcData[si+0]
|
||||
dstData[di+1] = srcData[si+1]
|
||||
dstData[di+2] = srcData[si+2]
|
||||
dstData[di+3] = srcData[si+3]
|
||||
}
|
||||
}
|
||||
|
||||
result.Buffer.Close()
|
||||
cropped.Format = PixelFormat(result.Format)
|
||||
|
||||
return &CaptureResult{
|
||||
Buffer: cropped,
|
||||
Region: region,
|
||||
YInverted: false,
|
||||
Format: result.Format,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Screenshoter) captureRegionOnOutput(output *WaylandOutput, region Region) (*CaptureResult, error) {
|
||||
localX := region.X - output.x
|
||||
localY := region.Y - output.y
|
||||
scale := output.fractionalScale
|
||||
if scale <= 0 && DetectCompositor() == CompositorHyprland {
|
||||
scale = GetHyprlandMonitorScale(output.name)
|
||||
}
|
||||
if scale <= 0 {
|
||||
scale = float64(output.scale)
|
||||
}
|
||||
if scale <= 0 {
|
||||
scale = 1.0
|
||||
}
|
||||
|
||||
localX := int32(float64(region.X-output.x) * scale)
|
||||
localY := int32(float64(region.Y-output.y) * scale)
|
||||
w := int32(float64(region.Width) * scale)
|
||||
h := int32(float64(region.Height) * scale)
|
||||
|
||||
if DetectCompositor() == CompositorDWL {
|
||||
scaledOutW := int32(float64(output.width) * scale)
|
||||
scaledOutH := int32(float64(output.height) * scale)
|
||||
if localX >= scaledOutW {
|
||||
localX = localX % scaledOutW
|
||||
}
|
||||
if localY >= scaledOutH {
|
||||
localY = localY % scaledOutH
|
||||
}
|
||||
if localX+w > scaledOutW {
|
||||
w = scaledOutW - localX
|
||||
}
|
||||
if localY+h > scaledOutH {
|
||||
h = scaledOutH - localY
|
||||
}
|
||||
if localX < 0 {
|
||||
w += localX
|
||||
localX = 0
|
||||
}
|
||||
if localY < 0 {
|
||||
h += localY
|
||||
localY = 0
|
||||
}
|
||||
}
|
||||
|
||||
cursor := int32(0)
|
||||
if s.config.IncludeCursor {
|
||||
cursor = 1
|
||||
}
|
||||
|
||||
frame, err := s.screencopy.CaptureOutputRegion(
|
||||
cursor,
|
||||
output.wlOutput,
|
||||
localX, localY,
|
||||
region.Width, region.Height,
|
||||
)
|
||||
frame, err := s.screencopy.CaptureOutputRegion(cursor, output.wlOutput, localX, localY, w, h)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("capture region: %w", err)
|
||||
}
|
||||
@@ -335,6 +619,8 @@ func (s *Screenshoter) captureRegionOnOutput(output *WaylandOutput, region Regio
|
||||
|
||||
func (s *Screenshoter) processFrame(frame *wlr_screencopy.ZwlrScreencopyFrameV1, region Region) (*CaptureResult, error) {
|
||||
var buf *ShmBuffer
|
||||
var pool *client.ShmPool
|
||||
var wlBuf *client.Buffer
|
||||
var format PixelFormat
|
||||
var yInverted bool
|
||||
ready := false
|
||||
@@ -360,15 +646,17 @@ func (s *Screenshoter) processFrame(frame *wlr_screencopy.ZwlrScreencopyFrameV1,
|
||||
return
|
||||
}
|
||||
|
||||
pool, err := s.shm.CreatePool(buf.Fd(), int32(buf.Size()))
|
||||
var err error
|
||||
pool, err = s.shm.CreatePool(buf.Fd(), int32(buf.Size()))
|
||||
if err != nil {
|
||||
log.Error("failed to create pool", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
wlBuf, err := pool.CreateBuffer(0, int32(buf.Width), int32(buf.Height), int32(buf.Stride), uint32(format))
|
||||
wlBuf, err = pool.CreateBuffer(0, int32(buf.Width), int32(buf.Height), int32(buf.Stride), uint32(format))
|
||||
if err != nil {
|
||||
pool.Destroy()
|
||||
pool = nil
|
||||
log.Error("failed to create wl_buffer", "err", err)
|
||||
return
|
||||
}
|
||||
@@ -376,8 +664,6 @@ func (s *Screenshoter) processFrame(frame *wlr_screencopy.ZwlrScreencopyFrameV1,
|
||||
if err := frame.Copy(wlBuf); err != nil {
|
||||
log.Error("failed to copy frame", "err", err)
|
||||
}
|
||||
|
||||
pool.Destroy()
|
||||
})
|
||||
|
||||
frame.SetReadyHandler(func(e wlr_screencopy.ZwlrScreencopyFrameV1ReadyEvent) {
|
||||
@@ -396,6 +682,12 @@ func (s *Screenshoter) processFrame(frame *wlr_screencopy.ZwlrScreencopyFrameV1,
|
||||
}
|
||||
|
||||
frame.Destroy()
|
||||
if wlBuf != nil {
|
||||
wlBuf.Destroy()
|
||||
}
|
||||
if pool != nil {
|
||||
pool.Destroy()
|
||||
}
|
||||
|
||||
if failed {
|
||||
if buf != nil {
|
||||
@@ -412,6 +704,17 @@ func (s *Screenshoter) processFrame(frame *wlr_screencopy.ZwlrScreencopyFrameV1,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Screenshoter) findOutputByName(name string) *WaylandOutput {
|
||||
s.outputsMu.Lock()
|
||||
defer s.outputsMu.Unlock()
|
||||
for _, o := range s.outputs {
|
||||
if o.name == name {
|
||||
return o
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Screenshoter) findOutputForRegion(region Region) *WaylandOutput {
|
||||
s.outputsMu.Lock()
|
||||
defer s.outputsMu.Unlock()
|
||||
@@ -420,14 +723,26 @@ func (s *Screenshoter) findOutputForRegion(region Region) *WaylandOutput {
|
||||
cy := region.Y + region.Height/2
|
||||
|
||||
for _, o := range s.outputs {
|
||||
if cx >= o.x && cx < o.x+o.width && cy >= o.y && cy < o.y+o.height {
|
||||
x, y, w, h := o.x, o.y, o.width, o.height
|
||||
if DetectCompositor() == CompositorHyprland {
|
||||
if hx, hy, hw, hh, ok := GetHyprlandMonitorGeometry(o.name); ok {
|
||||
x, y, w, h = hx, hy, hw, hh
|
||||
}
|
||||
}
|
||||
if cx >= x && cx < x+w && cy >= y && cy < y+h {
|
||||
return o
|
||||
}
|
||||
}
|
||||
|
||||
for _, o := range s.outputs {
|
||||
if region.X >= o.x && region.X < o.x+o.width &&
|
||||
region.Y >= o.y && region.Y < o.y+o.height {
|
||||
x, y, w, h := o.x, o.y, o.width, o.height
|
||||
if DetectCompositor() == CompositorHyprland {
|
||||
if hx, hy, hw, hh, ok := GetHyprlandMonitorGeometry(o.name); ok {
|
||||
x, y, w, h = hx, hy, hw, hh
|
||||
}
|
||||
}
|
||||
if region.X >= x && region.X < x+w &&
|
||||
region.Y >= y && region.Y < y+h {
|
||||
return o
|
||||
}
|
||||
}
|
||||
@@ -436,6 +751,15 @@ func (s *Screenshoter) findOutputForRegion(region Region) *WaylandOutput {
|
||||
}
|
||||
|
||||
func (s *Screenshoter) findFocusedOutput() *WaylandOutput {
|
||||
if mon := GetFocusedMonitor(); mon != "" {
|
||||
s.outputsMu.Lock()
|
||||
defer s.outputsMu.Unlock()
|
||||
for _, o := range s.outputs {
|
||||
if o.name == mon {
|
||||
return o
|
||||
}
|
||||
}
|
||||
}
|
||||
s.outputsMu.Lock()
|
||||
defer s.outputsMu.Unlock()
|
||||
for _, o := range s.outputs {
|
||||
@@ -501,9 +825,10 @@ func (s *Screenshoter) handleGlobal(e client.RegistryGlobalEvent) {
|
||||
if err := s.registry.Bind(e.Name, e.Interface, version, output); err == nil {
|
||||
s.outputsMu.Lock()
|
||||
s.outputs[e.Name] = &WaylandOutput{
|
||||
wlOutput: output,
|
||||
globalName: e.Name,
|
||||
scale: 1,
|
||||
wlOutput: output,
|
||||
globalName: e.Name,
|
||||
scale: 1,
|
||||
fractionalScale: 1.0,
|
||||
}
|
||||
s.outputsMu.Unlock()
|
||||
s.setupOutputHandlers(e.Name, output)
|
||||
@@ -546,6 +871,7 @@ func (s *Screenshoter) setupOutputHandlers(name uint32, output *client.Output) {
|
||||
s.outputsMu.Lock()
|
||||
if o, ok := s.outputs[name]; ok {
|
||||
o.scale = e.Factor
|
||||
o.fractionalScale = float64(e.Factor)
|
||||
}
|
||||
s.outputsMu.Unlock()
|
||||
})
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/matugen"
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
|
||||
)
|
||||
|
||||
type MatugenQueueResult struct {
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
func handleMatugenQueue(conn net.Conn, req models.Request) {
|
||||
getString := func(key string) string {
|
||||
if v, ok := req.Params[key].(string); ok {
|
||||
return v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
getBool := func(key string, def bool) bool {
|
||||
if v, ok := req.Params[key].(bool); ok {
|
||||
return v
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
opts := matugen.Options{
|
||||
StateDir: getString("stateDir"),
|
||||
ShellDir: getString("shellDir"),
|
||||
ConfigDir: getString("configDir"),
|
||||
Kind: getString("kind"),
|
||||
Value: getString("value"),
|
||||
Mode: getString("mode"),
|
||||
IconTheme: getString("iconTheme"),
|
||||
MatugenType: getString("matugenType"),
|
||||
RunUserTemplates: getBool("runUserTemplates", true),
|
||||
StockColors: getString("stockColors"),
|
||||
SyncModeWithPortal: getBool("syncModeWithPortal", false),
|
||||
TerminalsAlwaysDark: getBool("terminalsAlwaysDark", false),
|
||||
}
|
||||
|
||||
wait := getBool("wait", true)
|
||||
|
||||
queue := matugen.GetQueue()
|
||||
resultCh := queue.Submit(opts)
|
||||
|
||||
if !wait {
|
||||
models.Respond(conn, req.ID, MatugenQueueResult{
|
||||
Success: true,
|
||||
Message: "queued",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
|
||||
select {
|
||||
case result := <-resultCh:
|
||||
if result.Error != nil {
|
||||
if result.Error == context.Canceled {
|
||||
models.Respond(conn, req.ID, MatugenQueueResult{
|
||||
Success: false,
|
||||
Message: "cancelled",
|
||||
})
|
||||
return
|
||||
}
|
||||
models.RespondError(conn, req.ID, result.Error.Error())
|
||||
return
|
||||
}
|
||||
models.Respond(conn, req.ID, MatugenQueueResult{
|
||||
Success: true,
|
||||
Message: "completed",
|
||||
})
|
||||
case <-ctx.Done():
|
||||
models.RespondError(conn, req.ID, "timeout waiting for theme generation")
|
||||
}
|
||||
}
|
||||
|
||||
func handleMatugenStatus(conn net.Conn, req models.Request) {
|
||||
queue := matugen.GetQueue()
|
||||
models.Respond(conn, req.ID, map[string]bool{
|
||||
"running": queue.IsRunning(),
|
||||
"pending": queue.HasPending(),
|
||||
})
|
||||
}
|
||||
@@ -215,6 +215,10 @@ func RouteRequest(conn net.Conn, req models.Request) {
|
||||
models.Respond(conn, req.ID, info)
|
||||
case "subscribe":
|
||||
handleSubscribe(conn, req)
|
||||
case "matugen.queue":
|
||||
handleMatugenQueue(conn, req)
|
||||
case "matugen.status":
|
||||
handleMatugenStatus(conn, req)
|
||||
default:
|
||||
models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method))
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ func (i *Display) GetRegistry() (*Registry, error) {
|
||||
}
|
||||
|
||||
func (i *Display) Destroy() error {
|
||||
i.Context().Unregister(i)
|
||||
i.MarkZombie()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -224,15 +224,16 @@ func (i *Display) Dispatch(opcode uint32, fd int, data []byte) {
|
||||
|
||||
i.errorHandler(e)
|
||||
case 1:
|
||||
if i.deleteIdHandler == nil {
|
||||
return
|
||||
}
|
||||
var e DisplayDeleteIdEvent
|
||||
l := 0
|
||||
e.Id = Uint32(data[l : l+4])
|
||||
l += 4
|
||||
|
||||
i.deleteIdHandler(e)
|
||||
i.Context().DeleteID(e.Id)
|
||||
|
||||
if i.deleteIdHandler != nil {
|
||||
i.deleteIdHandler(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,7 +327,7 @@ func (i *Registry) Bind(name uint32, iface string, version uint32, id Proxy) err
|
||||
}
|
||||
|
||||
func (i *Registry) Destroy() error {
|
||||
i.Context().Unregister(i)
|
||||
i.MarkZombie()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -433,7 +434,7 @@ func NewCallback(ctx *Context) *Callback {
|
||||
}
|
||||
|
||||
func (i *Callback) Destroy() error {
|
||||
i.Context().Unregister(i)
|
||||
i.MarkZombie()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -529,7 +530,7 @@ func (i *Compositor) CreateRegion() (*Region, error) {
|
||||
}
|
||||
|
||||
func (i *Compositor) Destroy() error {
|
||||
i.Context().Unregister(i)
|
||||
i.MarkZombie()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -619,7 +620,7 @@ func (i *ShmPool) CreateBuffer(offset, width, height, stride int32, format uint3
|
||||
// buffers that have been created from this pool
|
||||
// are gone.
|
||||
func (i *ShmPool) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 1
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -735,7 +736,7 @@ func (i *Shm) CreatePool(fd int, size int32) (*ShmPool, error) {
|
||||
//
|
||||
// Objects created via this interface remain unaffected.
|
||||
func (i *Shm) Release() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 1
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -1642,7 +1643,7 @@ func NewBuffer(ctx *Context) *Buffer {
|
||||
//
|
||||
// For possible side-effects to a surface, see wl_surface.attach.
|
||||
func (i *Buffer) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -1803,7 +1804,7 @@ func (i *DataOffer) Receive(mimeType string, fd int) error {
|
||||
//
|
||||
// Destroy the data offer.
|
||||
func (i *DataOffer) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 2
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -2120,7 +2121,7 @@ func (i *DataSource) Offer(mimeType string) error {
|
||||
//
|
||||
// Destroy the data source.
|
||||
func (i *DataSource) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 1
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -2540,7 +2541,7 @@ func (i *DataDevice) SetSelection(source *DataSource, serial uint32) error {
|
||||
//
|
||||
// This request destroys the data device.
|
||||
func (i *DataDevice) Release() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 2
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -2859,7 +2860,7 @@ func (i *DataDeviceManager) GetDataDevice(seat *Seat) (*DataDevice, error) {
|
||||
}
|
||||
|
||||
func (i *DataDeviceManager) Destroy() error {
|
||||
i.Context().Unregister(i)
|
||||
i.MarkZombie()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3000,7 +3001,7 @@ func (i *Shell) GetShellSurface(surface *Surface) (*ShellSurface, error) {
|
||||
}
|
||||
|
||||
func (i *Shell) Destroy() error {
|
||||
i.Context().Unregister(i)
|
||||
i.MarkZombie()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3421,7 +3422,7 @@ func (i *ShellSurface) SetClass(class string) error {
|
||||
}
|
||||
|
||||
func (i *ShellSurface) Destroy() error {
|
||||
i.Context().Unregister(i)
|
||||
i.MarkZombie()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3798,7 +3799,7 @@ func NewSurface(ctx *Context) *Surface {
|
||||
//
|
||||
// Deletes the surface and invalidates its object ID.
|
||||
func (i *Surface) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -4618,7 +4619,7 @@ func (i *Seat) GetTouch() (*Touch, error) {
|
||||
// Using this request a client can tell the server that it is not going to
|
||||
// use the seat object anymore.
|
||||
func (i *Seat) Release() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 3
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -4920,7 +4921,7 @@ func (i *Pointer) SetCursor(serial uint32, surface *Surface, hotspotX, hotspotY
|
||||
// This request destroys the pointer proxy object, so clients must not call
|
||||
// wl_pointer_destroy() after using this request.
|
||||
func (i *Pointer) Release() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 1
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -5685,7 +5686,7 @@ func NewKeyboard(ctx *Context) *Keyboard {
|
||||
|
||||
// Release : release the keyboard object
|
||||
func (i *Keyboard) Release() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -6091,7 +6092,7 @@ func NewTouch(ctx *Context) *Touch {
|
||||
|
||||
// Release : release the touch object
|
||||
func (i *Touch) Release() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -6406,7 +6407,7 @@ func NewOutput(ctx *Context) *Output {
|
||||
// Using this request a client can tell the server that it is not going to
|
||||
// use the output object anymore.
|
||||
func (i *Output) Release() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -6923,7 +6924,7 @@ func NewRegion(ctx *Context) *Region {
|
||||
//
|
||||
// Destroy the region. This will invalidate the object ID.
|
||||
func (i *Region) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -7057,7 +7058,7 @@ func NewSubcompositor(ctx *Context) *Subcompositor {
|
||||
// protocol object anymore. This does not affect any other
|
||||
// objects, wl_subsurface objects included.
|
||||
func (i *Subcompositor) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -7280,7 +7281,7 @@ func NewSubsurface(ctx *Context) *Subsurface {
|
||||
// wl_subcompositor.get_subsurface request. The wl_surface's association
|
||||
// to the parent is deleted. The wl_surface is unmapped immediately.
|
||||
func (i *Subsurface) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
@@ -7499,7 +7500,7 @@ func NewFixes(ctx *Context) *Fixes {
|
||||
|
||||
// Destroy : destroys this object
|
||||
func (i *Fixes) Destroy() error {
|
||||
defer i.Context().Unregister(i)
|
||||
defer i.MarkZombie()
|
||||
const opcode = 0
|
||||
const _reqBufLen = 8
|
||||
var _reqBuf [_reqBufLen]byte
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package client
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
type Dispatcher interface {
|
||||
Dispatch(opcode uint32, fd int, data []byte)
|
||||
}
|
||||
@@ -9,11 +11,14 @@ type Proxy interface {
|
||||
SetContext(ctx *Context)
|
||||
ID() uint32
|
||||
SetID(id uint32)
|
||||
IsZombie() bool
|
||||
MarkZombie()
|
||||
}
|
||||
|
||||
type BaseProxy struct {
|
||||
ctx *Context
|
||||
id uint32
|
||||
ctx *Context
|
||||
id uint32
|
||||
zombie atomic.Bool
|
||||
}
|
||||
|
||||
func (p *BaseProxy) ID() uint32 {
|
||||
@@ -31,3 +36,11 @@ func (p *BaseProxy) Context() *Context {
|
||||
func (p *BaseProxy) SetContext(ctx *Context) {
|
||||
p.ctx = ctx
|
||||
}
|
||||
|
||||
func (p *BaseProxy) IsZombie() bool {
|
||||
return p.zombie.Load()
|
||||
}
|
||||
|
||||
func (p *BaseProxy) MarkZombie() {
|
||||
p.zombie.Store(true)
|
||||
}
|
||||
|
||||
@@ -32,6 +32,10 @@ func (ctx *Context) Unregister(p Proxy) {
|
||||
ctx.objects.Delete(p.ID())
|
||||
}
|
||||
|
||||
func (ctx *Context) DeleteID(id uint32) {
|
||||
ctx.objects.Delete(id)
|
||||
}
|
||||
|
||||
func (ctx *Context) GetProxy(id uint32) Proxy {
|
||||
if val, ok := ctx.objects.Load(id); ok {
|
||||
return val
|
||||
@@ -72,7 +76,11 @@ func (ctx *Context) GetDispatch() func() error {
|
||||
return func() error {
|
||||
proxy, ok := ctx.objects.Load(senderID)
|
||||
if !ok {
|
||||
return fmt.Errorf("%w (senderID=%d)", ErrDispatchSenderNotFound, senderID)
|
||||
return nil // Proxy already deleted via delete_id, silently ignore
|
||||
}
|
||||
|
||||
if proxy.IsZombie() {
|
||||
return nil // Zombie proxy, discard late events
|
||||
}
|
||||
|
||||
sender, ok := proxy.(Dispatcher)
|
||||
|
||||
@@ -61,7 +61,9 @@ in {
|
||||
'';
|
||||
};
|
||||
quickshell = {
|
||||
package = lib.mkPackageOption pkgs "quickshell" {};
|
||||
package = lib.mkPackageOption dmsPkgs "quickshell" {
|
||||
extraDescription = "The quickshell package to use (defaults to be built from source, in the commit 26531f due to unreleased features used by DMS).";
|
||||
};
|
||||
};
|
||||
logs.save = lib.mkEnableOption "saving logs from DMS greeter to file";
|
||||
logs.path = lib.mkOption {
|
||||
|
||||
+2
-2
@@ -4,13 +4,13 @@
|
||||
lib,
|
||||
dmsPkgs,
|
||||
...
|
||||
}: let
|
||||
} @ args: let
|
||||
cfg = config.programs.dankMaterialShell;
|
||||
jsonFormat = pkgs.formats.json {};
|
||||
common = import ./common.nix {inherit config pkgs lib dmsPkgs;};
|
||||
in {
|
||||
imports = [
|
||||
./options.nix
|
||||
(import ./options.nix args)
|
||||
(lib.mkRemovedOptionModule ["programs" "dankMaterialShell" "enableNightMode"] "Night mode is now always available.")
|
||||
(lib.mkRenamedOptionModule ["programs" "dankMaterialShell" "enableSystemd"] ["programs" "dankMaterialShell" "systemd" "enable"])
|
||||
];
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
lib,
|
||||
dmsPkgs,
|
||||
...
|
||||
}: let
|
||||
} @ args: let
|
||||
cfg = config.programs.dankMaterialShell;
|
||||
common = import ./common.nix {inherit config pkgs lib dmsPkgs;};
|
||||
in {
|
||||
imports = [
|
||||
./options.nix
|
||||
(import ./options.nix args)
|
||||
];
|
||||
|
||||
config = lib.mkIf cfg.enable
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
dmsPkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) types;
|
||||
@@ -62,7 +62,9 @@ in {
|
||||
description = "Add needed dependencies to have system sound support";
|
||||
};
|
||||
quickshell = {
|
||||
package = lib.mkPackageOption pkgs "quickshell" {};
|
||||
package = lib.mkPackageOption dmsPkgs "quickshell" {
|
||||
extraDescription = "The quickshell package to use (defaults to be built from source, in the commit 26531f due to unreleased features used by DMS).";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Generated
+29
-7
@@ -7,11 +7,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1762435535,
|
||||
"narHash": "sha256-QhzRn7pYN35IFpKjjxJAj3GPJECuC+VLhoGem3ezycc=",
|
||||
"lastModified": 1762835999,
|
||||
"narHash": "sha256-UykYGrGFOFTmDpKTLNxj1wvd1gbDG4TkqLNSbV0TYwk=",
|
||||
"owner": "AvengeMedia",
|
||||
"repo": "dgop",
|
||||
"rev": "6cf638dde818f9f8a2e26d0243179c43cb3458d7",
|
||||
"rev": "799301991cd5dcea9b64245f9d500dcc76615653",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -22,11 +22,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1762363567,
|
||||
"narHash": "sha256-YRqMDEtSMbitIMj+JLpheSz0pwEr0Rmy5mC7myl17xs=",
|
||||
"lastModified": 1764950072,
|
||||
"narHash": "sha256-BmPWzogsG2GsXZtlT+MTcAWeDK5hkbGRZTeZNW42fwA=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ae814fd3904b621d8ab97418f1d0f2eb0d3716f4",
|
||||
"rev": "f61125a668a320878494449750330ca58b78c557",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -36,10 +36,32 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"quickshell": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1764663772,
|
||||
"narHash": "sha256-sHqLmm0wAt3PC4vczJeBozI1/f4rv9yp3IjkClHDXDs=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "26531fc46ef17e9365b03770edd3fb9206fcb460",
|
||||
"revCount": 713,
|
||||
"type": "git",
|
||||
"url": "https://git.outfoxxed.me/quickshell/quickshell"
|
||||
},
|
||||
"original": {
|
||||
"rev": "26531fc46ef17e9365b03770edd3fb9206fcb460",
|
||||
"type": "git",
|
||||
"url": "https://git.outfoxxed.me/quickshell/quickshell"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"dgop": "dgop",
|
||||
"nixpkgs": "nixpkgs"
|
||||
"nixpkgs": "nixpkgs",
|
||||
"quickshell": "quickshell"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -7,12 +7,17 @@
|
||||
url = "github:AvengeMedia/dgop";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
quickshell = {
|
||||
url = "git+https://git.outfoxxed.me/quickshell/quickshell?rev=26531fc46ef17e9365b03770edd3fb9206fcb460";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs,
|
||||
dgop,
|
||||
quickshell,
|
||||
...
|
||||
}: let
|
||||
forEachSystem = fn:
|
||||
@@ -22,6 +27,7 @@
|
||||
buildDmsPkgs = pkgs: {
|
||||
dms-shell = self.packages.${pkgs.stdenv.hostPlatform.system}.default;
|
||||
dgop = dgop.packages.${pkgs.stdenv.hostPlatform.system}.dgop;
|
||||
quickshell = quickshell.packages.${pkgs.stdenv.hostPlatform.system}.default;
|
||||
};
|
||||
mkModuleWithDmsPkgs = path: args @ {pkgs, ...}: {
|
||||
imports = [
|
||||
@@ -46,67 +52,69 @@
|
||||
+ "_"
|
||||
+ (self.shortRev or "dirty");
|
||||
in {
|
||||
dms-shell = pkgs.buildGoModule (let
|
||||
rootSrc = ./.;
|
||||
in {
|
||||
inherit version;
|
||||
pname = "dms-shell";
|
||||
src = ./core;
|
||||
vendorHash = "sha256-2PCqiW4frxME8IlmwWH5ktznhd/G1bah5Ae4dp0HPTQ=";
|
||||
dms-shell = pkgs.buildGoModule (
|
||||
let
|
||||
rootSrc = ./.;
|
||||
in {
|
||||
inherit version;
|
||||
pname = "dms-shell";
|
||||
src = ./core;
|
||||
vendorHash = "sha256-2PCqiW4frxME8IlmwWH5ktznhd/G1bah5Ae4dp0HPTQ=";
|
||||
|
||||
subPackages = ["cmd/dms"];
|
||||
subPackages = ["cmd/dms"];
|
||||
|
||||
ldflags = [
|
||||
"-s"
|
||||
"-w"
|
||||
"-X main.Version=${version}"
|
||||
];
|
||||
ldflags = [
|
||||
"-s"
|
||||
"-w"
|
||||
"-X main.Version=${version}"
|
||||
];
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkgs.installShellFiles
|
||||
pkgs.makeWrapper
|
||||
];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
installShellFiles
|
||||
makeWrapper
|
||||
];
|
||||
|
||||
postInstall = ''
|
||||
mkdir -p $out/share/quickshell/dms
|
||||
cp -r ${rootSrc}/quickshell/. $out/share/quickshell/dms/
|
||||
postInstall = ''
|
||||
mkdir -p $out/share/quickshell/dms
|
||||
cp -r ${rootSrc}/quickshell/. $out/share/quickshell/dms/
|
||||
|
||||
chmod u+w $out/share/quickshell/dms/VERSION
|
||||
echo "${version}" > $out/share/quickshell/dms/VERSION
|
||||
chmod u+w $out/share/quickshell/dms/VERSION
|
||||
echo "${version}" > $out/share/quickshell/dms/VERSION
|
||||
|
||||
# Install desktop file and icon
|
||||
install -D ${rootSrc}/assets/dms-open.desktop \
|
||||
$out/share/applications/dms-open.desktop
|
||||
install -D ${rootSrc}/core/assets/danklogo.svg \
|
||||
$out/share/hicolor/scalable/apps/danklogo.svg
|
||||
# Install desktop file and icon
|
||||
install -D ${rootSrc}/assets/dms-open.desktop \
|
||||
$out/share/applications/dms-open.desktop
|
||||
install -D ${rootSrc}/core/assets/danklogo.svg \
|
||||
$out/share/hicolor/scalable/apps/danklogo.svg
|
||||
|
||||
wrapProgram $out/bin/dms --add-flags "-c $out/share/quickshell/dms"
|
||||
wrapProgram $out/bin/dms --add-flags "-c $out/share/quickshell/dms"
|
||||
|
||||
install -Dm644 ${rootSrc}/assets/systemd/dms.service \
|
||||
$out/lib/systemd/user/dms.service
|
||||
install -Dm644 ${rootSrc}/assets/systemd/dms.service \
|
||||
$out/lib/systemd/user/dms.service
|
||||
|
||||
substituteInPlace $out/lib/systemd/user/dms.service \
|
||||
--replace-fail /usr/bin/dms $out/bin/dms \
|
||||
--replace-fail /usr/bin/pkill ${pkgs.procps}/bin/pkill
|
||||
substituteInPlace $out/lib/systemd/user/dms.service \
|
||||
--replace-fail /usr/bin/dms $out/bin/dms \
|
||||
--replace-fail /usr/bin/pkill ${pkgs.procps}/bin/pkill
|
||||
|
||||
substituteInPlace $out/share/quickshell/dms/Modules/Greetd/assets/dms-greeter \
|
||||
--replace-fail /bin/bash ${pkgs.bashInteractive}/bin/bash
|
||||
substituteInPlace $out/share/quickshell/dms/Modules/Greetd/assets/dms-greeter \
|
||||
--replace-fail /bin/bash ${pkgs.bashInteractive}/bin/bash
|
||||
|
||||
installShellCompletion --cmd dms \
|
||||
--bash <($out/bin/dms completion bash) \
|
||||
--fish <($out/bin/dms completion fish) \
|
||||
--zsh <($out/bin/dms completion zsh)
|
||||
'';
|
||||
installShellCompletion --cmd dms \
|
||||
--bash <($out/bin/dms completion bash) \
|
||||
--fish <($out/bin/dms completion fish) \
|
||||
--zsh <($out/bin/dms completion zsh)
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "Desktop shell for wayland compositors built with Quickshell & GO";
|
||||
homepage = "https://danklinux.com";
|
||||
changelog = "https://github.com/AvengeMedia/DankMaterialShell/releases/tag/v${version}";
|
||||
license = pkgs.lib.licenses.mit;
|
||||
mainProgram = "dms";
|
||||
platforms = pkgs.lib.platforms.linux;
|
||||
};
|
||||
});
|
||||
meta = {
|
||||
description = "Desktop shell for wayland compositors built with Quickshell & GO";
|
||||
homepage = "https://danklinux.com";
|
||||
changelog = "https://github.com/AvengeMedia/DankMaterialShell/releases/tag/v${version}";
|
||||
license = pkgs.lib.licenses.mit;
|
||||
mainProgram = "dms";
|
||||
platforms = pkgs.lib.platforms.linux;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
default = self.packages.${system}.dms-shell;
|
||||
}
|
||||
@@ -119,5 +127,38 @@
|
||||
nixosModules.dankMaterialShell = mkModuleWithDmsPkgs ./distro/nix/nixos.nix;
|
||||
|
||||
nixosModules.greeter = mkModuleWithDmsPkgs ./distro/nix/greeter.nix;
|
||||
|
||||
devShells = forEachSystem (
|
||||
system: pkgs: let
|
||||
qmlPkgs =
|
||||
[
|
||||
quickshell.packages.${system}.default
|
||||
]
|
||||
++ (with pkgs.kdePackages; [
|
||||
qtdeclarative
|
||||
kirigami.unwrapped
|
||||
sonnet
|
||||
qtmultimedia
|
||||
]);
|
||||
in {
|
||||
default = pkgs.mkShell {
|
||||
buildInputs = with pkgs;
|
||||
[
|
||||
go_1_24
|
||||
gopls
|
||||
delve
|
||||
go-tools
|
||||
gnumake
|
||||
]
|
||||
++ qmlPkgs;
|
||||
|
||||
shellHook = ''
|
||||
touch quickshell/.qmlls.ini 2>/dev/null
|
||||
'';
|
||||
|
||||
QML2_IMPORT_PATH = pkgs.lib.concatStringsSep ":" (map (o: "${o}/lib/qt-6/qml") qmlPkgs);
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -197,14 +197,26 @@ const ACTION_ARGS = {
|
||||
{ name: "focus", type: "bool", label: "Follow focus", default: false }
|
||||
]
|
||||
},
|
||||
"move-column-to-workspace-down": {
|
||||
args: [{ name: "focus", type: "bool", label: "Follow focus", default: false }]
|
||||
},
|
||||
"move-column-to-workspace-up": {
|
||||
args: [{ name: "focus", type: "bool", label: "Follow focus", default: false }]
|
||||
},
|
||||
"screenshot": {
|
||||
args: [{ name: "opts", type: "screenshot", label: "Options" }]
|
||||
args: [{ name: "show-pointer", type: "bool", label: "Show pointer" }]
|
||||
},
|
||||
"screenshot-screen": {
|
||||
args: [{ name: "opts", type: "screenshot", label: "Options" }]
|
||||
args: [
|
||||
{ name: "show-pointer", type: "bool", label: "Show pointer" },
|
||||
{ name: "write-to-disk", type: "bool", label: "Save to disk" }
|
||||
]
|
||||
},
|
||||
"screenshot-window": {
|
||||
args: [{ name: "opts", type: "screenshot", label: "Options" }]
|
||||
args: [
|
||||
{ name: "show-pointer", type: "bool", label: "Show pointer" },
|
||||
{ name: "write-to-disk", type: "bool", label: "Save to disk" }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
@@ -288,11 +300,12 @@ function getActionLabel(action) {
|
||||
if (!action)
|
||||
return "";
|
||||
|
||||
const dmsAct = findDmsAction(action);
|
||||
var dmsAct = findDmsAction(action);
|
||||
if (dmsAct)
|
||||
return dmsAct.label;
|
||||
|
||||
const compAct = findCompositorAction(action);
|
||||
var base = action.split(" ")[0];
|
||||
var compAct = findCompositorAction(base);
|
||||
if (compAct)
|
||||
return compAct.label;
|
||||
|
||||
@@ -337,7 +350,8 @@ function isValidAction(action) {
|
||||
function isKnownCompositorAction(action) {
|
||||
if (!action)
|
||||
return false;
|
||||
return findCompositorAction(action) !== null;
|
||||
var base = action.split(" ")[0];
|
||||
return findCompositorAction(base) !== null;
|
||||
}
|
||||
|
||||
function buildSpawnAction(command, args) {
|
||||
@@ -404,10 +418,10 @@ function parseCompositorActionArgs(action) {
|
||||
if (!ACTION_ARGS[base])
|
||||
return { base: action, args: {} };
|
||||
|
||||
var argConfig = ACTION_ARGS[base];
|
||||
var argParts = parts.slice(1);
|
||||
|
||||
if (base === "move-column-to-workspace") {
|
||||
switch (base) {
|
||||
case "move-column-to-workspace":
|
||||
for (var i = 0; i < argParts.length; i++) {
|
||||
if (argParts[i] === "focus=true" || argParts[i] === "focus=false") {
|
||||
args.focus = argParts[i] === "focus=true";
|
||||
@@ -415,14 +429,24 @@ function parseCompositorActionArgs(action) {
|
||||
args.index = argParts[i];
|
||||
}
|
||||
}
|
||||
} else if (base.startsWith("screenshot")) {
|
||||
args.opts = {};
|
||||
for (var j = 0; j < argParts.length; j += 2) {
|
||||
if (j + 1 < argParts.length)
|
||||
args.opts[argParts[j]] = argParts[j + 1];
|
||||
break;
|
||||
case "move-column-to-workspace-down":
|
||||
case "move-column-to-workspace-up":
|
||||
for (var k = 0; k < argParts.length; k++) {
|
||||
if (argParts[k] === "focus=true" || argParts[k] === "focus=false")
|
||||
args.focus = argParts[k] === "focus=true";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (base.startsWith("screenshot")) {
|
||||
for (var j = 0; j < argParts.length; j++) {
|
||||
var kv = argParts[j].split("=");
|
||||
if (kv.length === 2)
|
||||
args[kv[0]] = kv[1] === "true";
|
||||
}
|
||||
} else if (argParts.length > 0) {
|
||||
args.value = argParts.join(" ");
|
||||
}
|
||||
} else if (argParts.length > 0) {
|
||||
args.value = argParts.join(" ");
|
||||
}
|
||||
|
||||
return { base: base, args: args };
|
||||
@@ -437,24 +461,29 @@ function buildCompositorAction(base, args) {
|
||||
if (!args || Object.keys(args).length === 0)
|
||||
return base;
|
||||
|
||||
if (base === "move-column-to-workspace") {
|
||||
switch (base) {
|
||||
case "move-column-to-workspace":
|
||||
if (args.index)
|
||||
parts.push(args.index);
|
||||
if (args.focus === true)
|
||||
parts.push("focus=true");
|
||||
else if (args.focus === false)
|
||||
if (args.focus === false)
|
||||
parts.push("focus=false");
|
||||
} else if (base.startsWith("screenshot") && args.opts) {
|
||||
for (var key in args.opts) {
|
||||
if (args.opts[key] !== undefined && args.opts[key] !== "") {
|
||||
parts.push(key);
|
||||
parts.push(args.opts[key]);
|
||||
}
|
||||
break;
|
||||
case "move-column-to-workspace-down":
|
||||
case "move-column-to-workspace-up":
|
||||
if (args.focus === false)
|
||||
parts.push("focus=false");
|
||||
break;
|
||||
default:
|
||||
if (base.startsWith("screenshot")) {
|
||||
if (args["show-pointer"] === true)
|
||||
parts.push("show-pointer=true");
|
||||
if (args["write-to-disk"] === true)
|
||||
parts.push("write-to-disk=true");
|
||||
} else if (args.value) {
|
||||
parts.push(args.value);
|
||||
} else if (args.index) {
|
||||
parts.push(args.index);
|
||||
}
|
||||
} else if (args.value) {
|
||||
parts.push(args.value);
|
||||
} else if (args.index) {
|
||||
parts.push(args.index);
|
||||
}
|
||||
|
||||
return parts.join(" ");
|
||||
|
||||
@@ -295,7 +295,7 @@ Singleton {
|
||||
|
||||
property bool lockScreenShowPowerActions: true
|
||||
property bool enableFprint: false
|
||||
property int maxFprintTries: 3
|
||||
property int maxFprintTries: 15
|
||||
property bool fprintdAvailable: false
|
||||
property string lockScreenActiveMonitor: "all"
|
||||
property string lockScreenInactiveColor: "#000000"
|
||||
|
||||
+27
-10
@@ -820,18 +820,35 @@ Singleton {
|
||||
"runUserTemplates": (typeof SettingsData !== "undefined") ? SettingsData.runUserMatugenTemplates : true
|
||||
};
|
||||
|
||||
if (stockColors) {
|
||||
desired.stockColors = JSON.stringify(stockColors);
|
||||
}
|
||||
|
||||
const json = JSON.stringify(desired);
|
||||
const desiredPath = stateDir + "/matugen.desired.json";
|
||||
const syncModeWithPortal = (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal) ? "true" : "false";
|
||||
const terminalsAlwaysDark = (typeof SettingsData !== "undefined" && SettingsData.terminalsAlwaysDark) ? "true" : "false";
|
||||
|
||||
console.log("Theme: Starting matugen worker");
|
||||
workerRunning = true;
|
||||
systemThemeGenerator.command = ["sh", "-c", `mkdir -p '${stateDir}' && cat > '${desiredPath}' << 'EOF'\n${json}\nEOF\nexec '${shellDir}/scripts/matugen-worker.sh' '${stateDir}' '${shellDir}' '${configDir}' '${syncModeWithPortal}' '${terminalsAlwaysDark}' --run`];
|
||||
|
||||
const args = [
|
||||
"dms", "matugen", "queue",
|
||||
"--state-dir", stateDir,
|
||||
"--shell-dir", shellDir,
|
||||
"--config-dir", configDir,
|
||||
"--kind", desired.kind,
|
||||
"--value", desired.value,
|
||||
"--mode", desired.mode,
|
||||
"--icon-theme", desired.iconTheme,
|
||||
"--matugen-type", desired.matugenType,
|
||||
];
|
||||
|
||||
if (!desired.runUserTemplates) {
|
||||
args.push("--run-user-templates=false");
|
||||
}
|
||||
if (stockColors) {
|
||||
args.push("--stock-colors", JSON.stringify(stockColors));
|
||||
}
|
||||
if (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal) {
|
||||
args.push("--sync-mode-with-portal");
|
||||
}
|
||||
if (typeof SettingsData !== "undefined" && SettingsData.terminalsAlwaysDark) {
|
||||
args.push("--terminals-always-dark");
|
||||
}
|
||||
|
||||
systemThemeGenerator.command = args;
|
||||
systemThemeGenerator.running = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ var SPEC = {
|
||||
|
||||
lockScreenShowPowerActions: { def: true },
|
||||
enableFprint: { def: false },
|
||||
maxFprintTries: { def: 3 },
|
||||
maxFprintTries: { def: 15 },
|
||||
fprintdAvailable: { def: false, persist: false },
|
||||
lockScreenActiveMonitor: { def: "all" },
|
||||
lockScreenInactiveColor: { def: "#000000" },
|
||||
|
||||
@@ -56,6 +56,8 @@ Row {
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
id: volumeSlider
|
||||
|
||||
readonly property real actualVolumePercent: defaultSink ? Math.round(defaultSink.audio.volume * 100) : 0
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -63,7 +65,6 @@ Row {
|
||||
enabled: defaultSink !== null
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
value: defaultSink ? Math.min(100, Math.round(defaultSink.audio.volume * 100)) : 0
|
||||
showValue: true
|
||||
unit: "%"
|
||||
valueOverride: actualVolumePercent
|
||||
@@ -81,4 +82,11 @@ Row {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: volumeSlider
|
||||
property: "value"
|
||||
value: defaultSink ? Math.min(100, Math.round(defaultSink.audio.volume * 100)) : 0
|
||||
when: !volumeSlider.isDragging
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ Loader {
|
||||
property bool isRightBarEdge: false
|
||||
property bool isTopBarEdge: false
|
||||
property bool isBottomBarEdge: false
|
||||
property string _registeredScreenName: ""
|
||||
|
||||
asynchronous: false
|
||||
|
||||
@@ -198,13 +199,16 @@ Loader {
|
||||
if (!hasPopout)
|
||||
return;
|
||||
|
||||
BarWidgetService.registerWidget(widgetId, parentScreen.name, item);
|
||||
_registeredScreenName = parentScreen.name;
|
||||
BarWidgetService.registerWidget(widgetId, _registeredScreenName, item);
|
||||
}
|
||||
|
||||
function unregisterWidget() {
|
||||
if (!widgetId || !parentScreen?.name)
|
||||
if (!widgetId || !_registeredScreenName)
|
||||
return;
|
||||
BarWidgetService.unregisterWidget(widgetId, parentScreen.name);
|
||||
|
||||
BarWidgetService.unregisterWidget(widgetId, _registeredScreenName);
|
||||
_registeredScreenName = "";
|
||||
}
|
||||
|
||||
function getWidgetComponent(widgetId, components) {
|
||||
|
||||
@@ -17,7 +17,7 @@ BasePill {
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "content_paste"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: Theme.widgetIconColor
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ BasePill {
|
||||
|
||||
DankIcon {
|
||||
name: root.getNetworkIconName()
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: root.getNetworkIconColor()
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: root.showNetworkIcon && NetworkService.networkAvailable
|
||||
@@ -181,7 +181,7 @@ BasePill {
|
||||
|
||||
DankIcon {
|
||||
name: "vpn_lock"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: NetworkService.vpnConnected ? Theme.primary : Theme.outlineButton
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: root.showVpnIcon && NetworkService.vpnAvailable && NetworkService.vpnConnected
|
||||
@@ -189,7 +189,7 @@ BasePill {
|
||||
|
||||
DankIcon {
|
||||
name: "bluetooth"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: BluetoothService.connected ? Theme.primary : Theme.outlineButton
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: root.showBluetoothIcon && BluetoothService.available && BluetoothService.enabled
|
||||
@@ -205,7 +205,7 @@ BasePill {
|
||||
DankIcon {
|
||||
id: audioIconV
|
||||
name: root.getVolumeIconName()
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: Theme.widgetIconColor
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
@@ -230,7 +230,7 @@ BasePill {
|
||||
DankIcon {
|
||||
id: micIconV
|
||||
name: root.getMicIconName()
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: root.getMicIconColor()
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
@@ -255,7 +255,7 @@ BasePill {
|
||||
DankIcon {
|
||||
id: brightnessIconV
|
||||
name: root.getBrightnessIconName()
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: Theme.widgetIconColor
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
@@ -272,7 +272,7 @@ BasePill {
|
||||
|
||||
DankIcon {
|
||||
name: Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable)
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: root.getBatteryIconColor()
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: root.showBatteryIcon && BatteryService.batteryAvailable
|
||||
@@ -280,7 +280,7 @@ BasePill {
|
||||
|
||||
DankIcon {
|
||||
name: "print"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: Theme.primary
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: root.showPrinterIcon && CupsService.cupsAvailable && root.hasPrintJobs()
|
||||
@@ -288,7 +288,7 @@ BasePill {
|
||||
|
||||
DankIcon {
|
||||
name: "settings"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: root.isActive ? Theme.primary : Theme.widgetIconColor
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: root.hasNoVisibleIcons()
|
||||
@@ -304,7 +304,7 @@ BasePill {
|
||||
DankIcon {
|
||||
id: networkIcon
|
||||
name: root.getNetworkIconName()
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: root.getNetworkIconColor()
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: root.showNetworkIcon && NetworkService.networkAvailable
|
||||
@@ -313,7 +313,7 @@ BasePill {
|
||||
DankIcon {
|
||||
id: vpnIcon
|
||||
name: "vpn_lock"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: NetworkService.vpnConnected ? Theme.primary : Theme.outlineButton
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: root.showVpnIcon && NetworkService.vpnAvailable && NetworkService.vpnConnected
|
||||
@@ -322,7 +322,7 @@ BasePill {
|
||||
DankIcon {
|
||||
id: bluetoothIcon
|
||||
name: "bluetooth"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: BluetoothService.connected ? Theme.primary : Theme.outlineButton
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: root.showBluetoothIcon && BluetoothService.available && BluetoothService.enabled
|
||||
@@ -338,7 +338,7 @@ BasePill {
|
||||
DankIcon {
|
||||
id: audioIcon
|
||||
name: root.getVolumeIconName()
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: Theme.widgetIconColor
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
@@ -364,7 +364,7 @@ BasePill {
|
||||
DankIcon {
|
||||
id: micIcon
|
||||
name: root.getMicIconName()
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: root.getMicIconColor()
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
@@ -390,7 +390,7 @@ BasePill {
|
||||
DankIcon {
|
||||
id: brightnessIcon
|
||||
name: root.getBrightnessIconName()
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: Theme.widgetIconColor
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
@@ -409,7 +409,7 @@ BasePill {
|
||||
DankIcon {
|
||||
id: batteryIcon
|
||||
name: Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable)
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: root.getBatteryIconColor()
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: root.showBatteryIcon && BatteryService.batteryAvailable
|
||||
@@ -418,7 +418,7 @@ BasePill {
|
||||
DankIcon {
|
||||
id: printerIcon
|
||||
name: "print"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: root.showPrinterIcon && CupsService.cupsAvailable && root.hasPrintJobs()
|
||||
@@ -426,7 +426,7 @@ BasePill {
|
||||
|
||||
DankIcon {
|
||||
name: "settings"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
size: Theme.barIconSize(root.barThickness, -4)
|
||||
color: root.isActive ? Theme.primary : Theme.widgetIconColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: root.hasNoVisibleIcons()
|
||||
|
||||
@@ -541,6 +541,34 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
function getWorkspaceIndex(modelData) {
|
||||
let isPlaceholder;
|
||||
if (root.useExtWorkspace) {
|
||||
isPlaceholder = modelData?.hidden === true;
|
||||
} else if (CompositorService.isHyprland) {
|
||||
isPlaceholder = modelData?.id === -1;
|
||||
} else if (CompositorService.isDwl) {
|
||||
isPlaceholder = modelData?.tag === -1;
|
||||
} else if (CompositorService.isSway) {
|
||||
isPlaceholder = modelData?.num === -1;
|
||||
} else {
|
||||
isPlaceholder = modelData === -1;
|
||||
}
|
||||
|
||||
if (isPlaceholder)
|
||||
return index + 1;
|
||||
|
||||
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 || "";
|
||||
return modelData - 1;
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -862,7 +890,18 @@ Item {
|
||||
id: rowLayout
|
||||
Row {
|
||||
spacing: 4
|
||||
visible: loadedIcons.length > 0
|
||||
visible: loadedIcons.length > 0 || SettingsData.showWorkspaceIndex
|
||||
StyledText {
|
||||
topPadding: 2
|
||||
rightPadding: isActive ? 4 : 0
|
||||
visible: SettingsData.showWorkspaceIndex
|
||||
text: {
|
||||
return root.getWorkspaceIndex(modelData);
|
||||
}
|
||||
color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium
|
||||
font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale)
|
||||
font.weight: (isActive && !isPlaceholder) ? Font.DemiBold : Font.Normal
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: ScriptModel {
|
||||
@@ -1045,31 +1084,7 @@ Item {
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: {
|
||||
let isPlaceholder;
|
||||
if (root.useExtWorkspace) {
|
||||
isPlaceholder = modelData?.hidden === true;
|
||||
} else if (CompositorService.isHyprland) {
|
||||
isPlaceholder = modelData?.id === -1;
|
||||
} else if (CompositorService.isDwl) {
|
||||
isPlaceholder = modelData?.tag === -1;
|
||||
} else if (CompositorService.isSway) {
|
||||
isPlaceholder = modelData?.num === -1;
|
||||
} else {
|
||||
isPlaceholder = modelData === -1;
|
||||
}
|
||||
|
||||
if (isPlaceholder)
|
||||
return index + 1;
|
||||
|
||||
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 || "";
|
||||
return modelData - 1;
|
||||
return root.getWorkspaceIndex(modelData);
|
||||
}
|
||||
color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium
|
||||
font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale)
|
||||
|
||||
@@ -51,17 +51,9 @@ Item {
|
||||
readonly property bool usePlayerVolume: activePlayer && activePlayer.volumeSupported && !__isChromeBrowser
|
||||
readonly property real currentVolume: usePlayerVolume ? activePlayer.volume : (AudioService.sink?.audio?.volume ?? 0)
|
||||
|
||||
// Palette that stays stable across track switches until new colors are ready
|
||||
property color dom: Qt.rgba(Theme.surface.r, Theme.surface.g, Theme.surface.b, 1.0)
|
||||
property color acc: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.25)
|
||||
property color _nextDom: dom
|
||||
property color _nextAcc: acc
|
||||
|
||||
// Track-switch hold (prevents banner flicker only during switches)
|
||||
property bool isSwitching: false
|
||||
property bool paletteReady: false
|
||||
property string _lastArtUrl: ""
|
||||
property url _cqSource: ""
|
||||
property string _bgArtSource: ""
|
||||
|
||||
// Derived "no players" state: always correct, no timers.
|
||||
readonly property int _playerCount: allPlayers ? allPlayers.length : 0
|
||||
@@ -69,7 +61,6 @@ Item {
|
||||
readonly property bool _trulyIdle: activePlayer && activePlayer.playbackState === MprisPlaybackState.Stopped && !activePlayer.trackTitle && !activePlayer.trackArtist
|
||||
readonly property bool showNoPlayerNow: (!_switchHold) && (_noneAvailable || _trulyIdle)
|
||||
|
||||
// Short hold only during track switches (not when players disappear)
|
||||
property bool _switchHold: false
|
||||
Timer {
|
||||
id: _switchHoldTimer
|
||||
@@ -86,11 +77,9 @@ Item {
|
||||
}
|
||||
isSwitching = true;
|
||||
_switchHold = true;
|
||||
paletteReady = false;
|
||||
_switchHoldTimer.restart();
|
||||
if (activePlayer.trackArtUrl) {
|
||||
if (activePlayer.trackArtUrl)
|
||||
loadArtwork(activePlayer.trackArtUrl);
|
||||
}
|
||||
}
|
||||
|
||||
property string activeTrackArtFile: ""
|
||||
@@ -108,13 +97,13 @@ Item {
|
||||
imageDownloader.command = ["curl", "-L", "-s", "--user-agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36", "-o", filename, url];
|
||||
imageDownloader.targetFile = filename;
|
||||
imageDownloader.running = true;
|
||||
} else {
|
||||
_preloadImage.source = url;
|
||||
return;
|
||||
}
|
||||
_bgArtSource = url;
|
||||
}
|
||||
|
||||
function maybeFinishSwitch() {
|
||||
if (activePlayer && activePlayer.trackTitle !== "" && paletteReady) {
|
||||
if (activePlayer && activePlayer.trackTitle !== "") {
|
||||
isSwitching = false;
|
||||
_switchHold = false;
|
||||
}
|
||||
@@ -219,9 +208,8 @@ Item {
|
||||
property string targetFile: ""
|
||||
|
||||
onExited: exitCode => {
|
||||
if (exitCode === 0 && targetFile) {
|
||||
_preloadImage.source = "file://" + targetFile;
|
||||
}
|
||||
if (exitCode === 0 && targetFile)
|
||||
_bgArtSource = "file://" + targetFile;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,121 +218,70 @@ Item {
|
||||
running: false
|
||||
}
|
||||
|
||||
Image {
|
||||
id: _preloadImage
|
||||
source: ""
|
||||
asynchronous: true
|
||||
cache: true
|
||||
visible: false
|
||||
onStatusChanged: {
|
||||
if (status === Image.Ready) {
|
||||
_cqSource = source;
|
||||
colorQuantizer.source = _cqSource;
|
||||
} else if (status === Image.Error) {
|
||||
_cqSource = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColorQuantizer {
|
||||
id: colorQuantizer
|
||||
source: _cqSource !== "" ? _cqSource : undefined
|
||||
depth: 8
|
||||
rescaleSize: 32
|
||||
onColorsChanged: {
|
||||
if (!colors || colors.length === 0)
|
||||
return;
|
||||
function enhanceColor(color) {
|
||||
const satBoost = 1.4;
|
||||
const valueBoost = 1.2;
|
||||
return Qt.hsva(color.hsvHue, Math.min(1, color.hsvSaturation * satBoost), Math.min(1, color.hsvValue * valueBoost), color.a);
|
||||
}
|
||||
|
||||
function getExtremeColor(startIdx, direction = 1) {
|
||||
let bestColor = colors[startIdx];
|
||||
let bestScore = 0;
|
||||
|
||||
for (let i = startIdx; i >= 0 && i < colors.length; i += direction) {
|
||||
const c = colors[i];
|
||||
const saturation = c.hsvSaturation;
|
||||
const brightness = c.hsvValue;
|
||||
const contrast = Math.abs(brightness - 0.5) * 2;
|
||||
const score = saturation * 0.7 + contrast * 0.3;
|
||||
|
||||
if (score > bestScore) {
|
||||
bestScore = score;
|
||||
bestColor = c;
|
||||
}
|
||||
}
|
||||
|
||||
return enhanceColor(bestColor);
|
||||
}
|
||||
|
||||
_pendingDom = getExtremeColor(Math.floor(colors.length * 0.2), 1);
|
||||
_pendingAcc = getExtremeColor(Math.floor(colors.length * 0.8), -1);
|
||||
paletteApplyDelay.restart();
|
||||
}
|
||||
}
|
||||
|
||||
property color _pendingDom: dom
|
||||
property color _pendingAcc: acc
|
||||
Timer {
|
||||
id: paletteApplyDelay
|
||||
interval: 90
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
const dist = (c1, c2) => {
|
||||
const dr = c1.r - c2.r, dg = c1.g - c2.g, db = c1.b - c2.b;
|
||||
return Math.sqrt(dr * dr + dg * dg + db * db);
|
||||
};
|
||||
const domChanged = dist(_pendingDom, dom) > 0.02;
|
||||
const accChanged = dist(_pendingAcc, acc) > 0.02;
|
||||
if (domChanged || accChanged) {
|
||||
dom = _pendingDom;
|
||||
acc = _pendingAcc;
|
||||
}
|
||||
paletteReady = true;
|
||||
maybeFinishSwitch();
|
||||
}
|
||||
}
|
||||
|
||||
property bool isSeeking: false
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
id: bgContainer
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
opacity: 1.0
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0.0
|
||||
color: Qt.rgba(dom.r, dom.g, dom.b, paletteReady ? 0.38 : 0.06)
|
||||
}
|
||||
GradientStop {
|
||||
position: 0.3
|
||||
color: Qt.rgba(acc.r, acc.g, acc.b, paletteReady ? 0.28 : 0.05)
|
||||
}
|
||||
GradientStop {
|
||||
position: 1.0
|
||||
color: Qt.rgba(Theme.surface.r, Theme.surface.g, Theme.surface.b, paletteReady ? 0.92 : 0.985)
|
||||
}
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 160
|
||||
}
|
||||
}
|
||||
}
|
||||
visible: _bgArtSource !== ""
|
||||
|
||||
Behavior on dom {
|
||||
ColorAnimation {
|
||||
duration: 220
|
||||
easing.type: Easing.InOutQuad
|
||||
Image {
|
||||
id: bgImage
|
||||
anchors.centerIn: parent
|
||||
width: Math.max(parent.width, parent.height) * 1.1
|
||||
height: width
|
||||
source: _bgArtSource
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
cache: true
|
||||
visible: false
|
||||
onStatusChanged: {
|
||||
if (status === Image.Ready)
|
||||
maybeFinishSwitch();
|
||||
}
|
||||
}
|
||||
}
|
||||
Behavior on acc {
|
||||
ColorAnimation {
|
||||
duration: 220
|
||||
easing.type: Easing.InOutQuad
|
||||
|
||||
Item {
|
||||
id: blurredBg
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
|
||||
MultiEffect {
|
||||
anchors.centerIn: parent
|
||||
width: bgImage.width
|
||||
height: bgImage.height
|
||||
source: bgImage
|
||||
blurEnabled: true
|
||||
blurMax: 64
|
||||
blur: 0.8
|
||||
saturation: -0.2
|
||||
brightness: -0.25
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: bgMask
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
visible: false
|
||||
layer.enabled: true
|
||||
}
|
||||
|
||||
MultiEffect {
|
||||
anchors.fill: parent
|
||||
source: blurredBg
|
||||
maskEnabled: true
|
||||
maskSource: bgMask
|
||||
maskThresholdMin: 0.5
|
||||
maskSpreadAtMin: 1.0
|
||||
opacity: 0.7
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surface
|
||||
opacity: 0.3
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1086,14 +1086,33 @@ Item {
|
||||
Row {
|
||||
spacing: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: NetworkService.networkStatus !== "disconnected" || (BluetoothService.available && BluetoothService.enabled) || (AudioService.sink && AudioService.sink.audio)
|
||||
visible: NetworkService.networkAvailable || (BluetoothService.available && BluetoothService.enabled) || (AudioService.sink && AudioService.sink.audio)
|
||||
|
||||
DankIcon {
|
||||
name: NetworkService.networkStatus === "ethernet" ? "lan" : NetworkService.wifiSignalIcon
|
||||
name: {
|
||||
if (NetworkService.wifiToggling)
|
||||
return "sync";
|
||||
switch (NetworkService.networkStatus) {
|
||||
case "ethernet":
|
||||
return "lan";
|
||||
case "vpn":
|
||||
return NetworkService.ethernetConnected ? "lan" : NetworkService.wifiSignalIcon;
|
||||
default:
|
||||
return NetworkService.wifiSignalIcon;
|
||||
}
|
||||
}
|
||||
size: Theme.iconSize - 2
|
||||
color: NetworkService.networkStatus !== "disconnected" ? "white" : Qt.rgba(255, 255, 255, 0.5)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: NetworkService.networkStatus !== "disconnected"
|
||||
visible: NetworkService.networkAvailable
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
name: "vpn_lock"
|
||||
size: Theme.iconSize - 2
|
||||
color: NetworkService.vpnConnected ? Theme.primary : Qt.rgba(255, 255, 255, 0.5)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: NetworkService.vpnAvailable && NetworkService.vpnConnected
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
|
||||
@@ -59,12 +59,6 @@ Item {
|
||||
"description": I18n.tr("Quick note-taking slideout panel"),
|
||||
"icon": "sticky_note_2"
|
||||
},
|
||||
{
|
||||
"id": "systemTray",
|
||||
"name": I18n.tr("System Tray"),
|
||||
"description": I18n.tr("System tray icons"),
|
||||
"icon": "notifications"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -199,8 +193,8 @@ Item {
|
||||
|
||||
DankDropdown {
|
||||
width: parent.width - parent.leftPadding - parent.rightPadding
|
||||
text: I18n.tr("Night Temperature")
|
||||
description: I18n.tr("Color temperature for night mode")
|
||||
text: SessionData.nightModeAutoEnabled ? I18n.tr("Night Temperature") : I18n.tr("Color Temperature")
|
||||
description: SessionData.nightModeAutoEnabled ? I18n.tr("Color temperature for night mode") : I18n.tr("Warm color temperature to apply")
|
||||
currentValue: SessionData.nightModeTemperature + "K"
|
||||
options: {
|
||||
var temps = [];
|
||||
@@ -223,6 +217,7 @@ Item {
|
||||
text: I18n.tr("Day Temperature")
|
||||
description: I18n.tr("Color temperature for day time")
|
||||
currentValue: SessionData.nightModeHighTemperature + "K"
|
||||
visible: SessionData.nightModeAutoEnabled
|
||||
options: {
|
||||
var temps = [];
|
||||
var minTemp = SessionData.nightModeTemperature;
|
||||
@@ -821,7 +816,7 @@ Item {
|
||||
const prefs = displaysTab.getScreenPreferences(parent.componentId);
|
||||
const isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all");
|
||||
const cid = parent.componentId;
|
||||
const isRelevantComponent = ["dankBar", "dock", "notifications", "osd", "toast", "notepad", "systemTray"].includes(cid) || cid.startsWith("bar:");
|
||||
const isRelevantComponent = ["dankBar", "dock", "notifications", "osd", "toast", "notepad"].includes(cid) || cid.startsWith("bar:");
|
||||
return !isAll && isRelevantComponent;
|
||||
}
|
||||
onToggled: checked => {
|
||||
@@ -905,4 +900,4 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,7 +597,7 @@ Item {
|
||||
onSaveBind: (originalKey, newData) => {
|
||||
KeybindsService.saveBind(originalKey, newData);
|
||||
keybindsTab._editingKey = newData.key;
|
||||
keybindsTab.expandedKey = modelData.action;
|
||||
keybindsTab.expandedKey = newData.action;
|
||||
}
|
||||
onRemoveBind: key => {
|
||||
const remainingKey = bindItem.keys.find(k => k.key !== key)?.key ?? "";
|
||||
|
||||
@@ -506,7 +506,7 @@ Singleton {
|
||||
|
||||
DMSService.sendRequest("wayland.gamma.setTemperature", {
|
||||
"low": temperature,
|
||||
"high": 6500
|
||||
"high": temperature
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.error("DisplayService: Failed to set temperature:", response.error);
|
||||
|
||||
@@ -650,9 +650,10 @@ Item {
|
||||
}
|
||||
|
||||
onWheel: wheel => {
|
||||
if (!root.recording)
|
||||
if (!root.recording) {
|
||||
wheel.accepted = false;
|
||||
return;
|
||||
|
||||
}
|
||||
wheel.accepted = true;
|
||||
|
||||
const mods = [];
|
||||
@@ -959,12 +960,12 @@ Item {
|
||||
Layout.preferredWidth: 120
|
||||
compactMode: true
|
||||
currentValue: {
|
||||
const action = root.editAction;
|
||||
const base = root.editAction.split(" ")[0];
|
||||
const cats = KeybindsService.getCompositorCategories();
|
||||
for (const cat of cats) {
|
||||
const actions = KeybindsService.getCompositorActions(cat);
|
||||
for (const act of actions) {
|
||||
if (act.id === action)
|
||||
if (act.id === base)
|
||||
return cat;
|
||||
}
|
||||
}
|
||||
@@ -1024,12 +1025,13 @@ Item {
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: optionsRow
|
||||
Layout.fillWidth: true
|
||||
spacing: Theme.spacingM
|
||||
visible: root._actionType === "compositor" && !root.useCustomCompositor && Actions.getActionArgConfig(root.editAction)
|
||||
|
||||
property var argConfig: Actions.getActionArgConfig(root.editAction)
|
||||
property var parsedArgs: Actions.parseCompositorActionArgs(root.editAction)
|
||||
readonly property var argConfig: Actions.getActionArgConfig(root.editAction)
|
||||
readonly property var parsedArgs: Actions.parseCompositorActionArgs(root.editAction)
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Options")
|
||||
@@ -1048,56 +1050,75 @@ Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 40
|
||||
visible: {
|
||||
const cfg = parent.parent.argConfig;
|
||||
if (!cfg || !cfg.config || !cfg.config.args)
|
||||
const cfg = optionsRow.argConfig;
|
||||
if (!cfg?.config?.args)
|
||||
return false;
|
||||
const firstArg = cfg.config.args[0];
|
||||
return firstArg && (firstArg.type === "text" || firstArg.type === "number");
|
||||
}
|
||||
placeholderText: {
|
||||
const cfg = parent.parent.argConfig;
|
||||
if (!cfg || !cfg.config || !cfg.config.args)
|
||||
return "";
|
||||
return cfg.config.args[0]?.placeholder || "";
|
||||
placeholderText: optionsRow.argConfig?.config?.args?.[0]?.placeholder || ""
|
||||
|
||||
Connections {
|
||||
target: optionsRow
|
||||
function onParsedArgsChanged() {
|
||||
const newText = optionsRow.parsedArgs?.args?.value || optionsRow.parsedArgs?.args?.index || "";
|
||||
if (argValueField.text !== newText)
|
||||
argValueField.text = newText;
|
||||
}
|
||||
}
|
||||
text: parent.parent.parsedArgs?.args?.value || parent.parent.parsedArgs?.args?.index || ""
|
||||
onTextChanged: {
|
||||
const cfg = parent.parent.argConfig;
|
||||
|
||||
Component.onCompleted: {
|
||||
text = optionsRow.parsedArgs?.args?.value || optionsRow.parsedArgs?.args?.index || "";
|
||||
}
|
||||
|
||||
onEditingFinished: {
|
||||
const cfg = optionsRow.argConfig;
|
||||
if (!cfg)
|
||||
return;
|
||||
const base = parent.parent.parsedArgs?.base || root.editAction.split(" ")[0];
|
||||
const args = cfg.config.args[0]?.type === "number" ? {
|
||||
index: text
|
||||
} : {
|
||||
value: text
|
||||
};
|
||||
const parsed = optionsRow.parsedArgs;
|
||||
const args = {};
|
||||
if (cfg.config.args[0]?.type === "number")
|
||||
args.index = text;
|
||||
else
|
||||
args.value = text;
|
||||
if (parsed?.args?.focus === false)
|
||||
args.focus = false;
|
||||
root.updateEdit({
|
||||
action: Actions.buildCompositorAction(base, args)
|
||||
action: Actions.buildCompositorAction(parsed?.base || cfg.base, args)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
visible: {
|
||||
const cfg = parent.parent.argConfig;
|
||||
return cfg && cfg.base === "move-column-to-workspace";
|
||||
const cfg = optionsRow.argConfig;
|
||||
if (!cfg)
|
||||
return false;
|
||||
switch (cfg.base) {
|
||||
case "move-column-to-workspace":
|
||||
case "move-column-to-workspace-down":
|
||||
case "move-column-to-workspace-up":
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankToggle {
|
||||
id: focusToggle
|
||||
checked: parent.parent.parent.parsedArgs?.args?.focus === true
|
||||
onCheckedChanged: {
|
||||
const cfg = parent.parent.parent.argConfig;
|
||||
checked: optionsRow.parsedArgs?.args?.focus !== false
|
||||
onToggled: newChecked => {
|
||||
const cfg = optionsRow.argConfig;
|
||||
if (!cfg)
|
||||
return;
|
||||
const parsed = parent.parent.parent.parsedArgs;
|
||||
const args = {
|
||||
index: parsed?.args?.index || "",
|
||||
focus: checked
|
||||
};
|
||||
const parsed = optionsRow.parsedArgs;
|
||||
const args = {};
|
||||
if (cfg.base === "move-column-to-workspace")
|
||||
args.index = parsed?.args?.index || "";
|
||||
if (!newChecked)
|
||||
args.focus = false;
|
||||
root.updateEdit({
|
||||
action: Actions.buildCompositorAction("move-column-to-workspace", args)
|
||||
action: Actions.buildCompositorAction(cfg.base, args)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1110,53 +1131,22 @@ Item {
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
visible: {
|
||||
const cfg = parent.parent.argConfig;
|
||||
return cfg && cfg.base && cfg.base.startsWith("screenshot");
|
||||
}
|
||||
visible: optionsRow.argConfig?.base?.startsWith("screenshot") ?? false
|
||||
spacing: Theme.spacingM
|
||||
|
||||
RowLayout {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankToggle {
|
||||
id: writeToDiskToggle
|
||||
checked: parent.parent.parent.parent.parsedArgs?.args?.opts?.["write-to-disk"] === "true"
|
||||
onCheckedChanged: {
|
||||
const parsed = parent.parent.parent.parent.parsedArgs;
|
||||
const base = parsed?.base || "screenshot";
|
||||
const opts = parsed?.args?.opts || {};
|
||||
opts["write-to-disk"] = checked ? "true" : "";
|
||||
root.updateEdit({
|
||||
action: Actions.buildCompositorAction(base, {
|
||||
opts: opts
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Save")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankToggle {
|
||||
id: showPointerToggle
|
||||
checked: parent.parent.parent.parent.parsedArgs?.args?.opts?.["show-pointer"] === "true"
|
||||
onCheckedChanged: {
|
||||
const parsed = parent.parent.parent.parent.parsedArgs;
|
||||
checked: optionsRow.parsedArgs?.args?.["show-pointer"] === true
|
||||
onToggled: newChecked => {
|
||||
const parsed = optionsRow.parsedArgs;
|
||||
const base = parsed?.base || "screenshot";
|
||||
const opts = parsed?.args?.opts || {};
|
||||
opts["show-pointer"] = checked ? "true" : "";
|
||||
const args = Object.assign({}, parsed?.args || {});
|
||||
args["show-pointer"] = newChecked;
|
||||
root.updateEdit({
|
||||
action: Actions.buildCompositorAction(base, {
|
||||
opts: opts
|
||||
})
|
||||
action: Actions.buildCompositorAction(base, args)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1167,6 +1157,31 @@ Item {
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
visible: optionsRow.argConfig?.base !== "screenshot"
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankToggle {
|
||||
id: writeToDiskToggle
|
||||
checked: optionsRow.parsedArgs?.args?.["write-to-disk"] === true
|
||||
onToggled: newChecked => {
|
||||
const parsed = optionsRow.parsedArgs;
|
||||
const base = parsed?.base || "screenshot-screen";
|
||||
const args = Object.assign({}, parsed?.args || {});
|
||||
args["write-to-disk"] = newChecked;
|
||||
root.updateEdit({
|
||||
action: Actions.buildCompositorAction(base, args)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Save")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,19 @@ Item {
|
||||
property color playheadColor: Theme.primary
|
||||
|
||||
property real dpr: (root.window ? root.window.devicePixelRatio : 1)
|
||||
function snap(v) { return Math.round(v * dpr) / dpr }
|
||||
function snap(v) {
|
||||
return Math.round(v * dpr) / dpr;
|
||||
}
|
||||
|
||||
readonly property real playX: snap(root.width * root.value)
|
||||
readonly property real midY: snap(height / 2)
|
||||
|
||||
Behavior on currentAmp { NumberAnimation { duration: 300; easing.type: Easing.OutCubic } }
|
||||
Behavior on currentAmp {
|
||||
NumberAnimation {
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
onIsPlayingChanged: currentAmp = isPlaying ? amp : 0
|
||||
|
||||
Shape {
|
||||
@@ -38,8 +45,16 @@ Item {
|
||||
capStyle: ShapePath.RoundCap
|
||||
joinStyle: ShapePath.RoundJoin
|
||||
fillColor: "transparent"
|
||||
PathMove { id: flatStart; x: 0; y: root.midY }
|
||||
PathLine { id: flatEnd; x: root.width; y: root.midY }
|
||||
PathMove {
|
||||
id: flatStart
|
||||
x: Math.min(root.width, snap(root.playX + playhead.width / 2))
|
||||
y: root.midY
|
||||
}
|
||||
PathLine {
|
||||
id: flatEnd
|
||||
x: root.width
|
||||
y: root.midY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +63,7 @@ Item {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
|
||||
readonly property real startX: snap(root.lineWidth/2)
|
||||
readonly property real startX: snap(root.lineWidth / 2)
|
||||
readonly property real aaBias: (0.25 / root.dpr)
|
||||
readonly property real endX: Math.max(startX, Math.min(root.playX - startX - aaBias, width))
|
||||
|
||||
@@ -77,7 +92,10 @@ Item {
|
||||
capStyle: ShapePath.RoundCap
|
||||
joinStyle: ShapePath.RoundJoin
|
||||
fillColor: "transparent"
|
||||
PathSvg { id: waveSvg; path: "" }
|
||||
PathSvg {
|
||||
id: waveSvg
|
||||
path: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,8 +106,8 @@ Item {
|
||||
height: snap(root.lineWidth)
|
||||
radius: width / 2
|
||||
color: root.fillColor
|
||||
x: waveClip.startX - width/2
|
||||
y: root.midY - height/2 + root.currentAmp * Math.sin((waveClip.startX / root.wavelength) * 2 * Math.PI + root.phase)
|
||||
x: waveClip.startX - width / 2
|
||||
y: root.midY - height / 2 + root.currentAmp * Math.sin((waveClip.startX / root.wavelength) * 2 * Math.PI + root.phase)
|
||||
visible: waveClip.endX > waveClip.startX
|
||||
z: 2
|
||||
}
|
||||
@@ -100,8 +118,8 @@ Item {
|
||||
height: snap(root.lineWidth)
|
||||
radius: width / 2
|
||||
color: root.fillColor
|
||||
x: waveClip.endX - width/2
|
||||
y: root.midY - height/2 + root.currentAmp * Math.sin((waveClip.endX / root.wavelength) * 2 * Math.PI + root.phase)
|
||||
x: waveClip.endX - width / 2
|
||||
y: root.midY - height / 2 + root.currentAmp * Math.sin((waveClip.endX / root.wavelength) * 2 * Math.PI + root.phase)
|
||||
visible: waveClip.endX > waveClip.startX
|
||||
z: 2
|
||||
}
|
||||
@@ -119,48 +137,68 @@ Item {
|
||||
}
|
||||
|
||||
property real k: (2 * Math.PI) / Math.max(1e-6, wavelength)
|
||||
function wrapMod(a, m) { let r = a % m; return r < 0 ? r + m : r }
|
||||
function wrapMod(a, m) {
|
||||
let r = a % m;
|
||||
return r < 0 ? r + m : r;
|
||||
}
|
||||
readonly property real waveOffsetX: -wrapMod(phase / k, wavelength)
|
||||
|
||||
FrameAnimation {
|
||||
running: root.visible && (root.isPlaying || root.currentAmp > 0)
|
||||
onTriggered: {
|
||||
if (root.isPlaying) root.phase += 0.03 * frameTime * 60
|
||||
startCap.y = root.midY - startCap.height/2 + root.currentAmp * Math.sin((waveClip.startX / root.wavelength) * 2 * Math.PI + root.phase)
|
||||
endCap.y = root.midY - endCap.height/2 + root.currentAmp * Math.sin((waveClip.endX / root.wavelength) * 2 * Math.PI + root.phase)
|
||||
if (root.isPlaying)
|
||||
root.phase += 0.03 * frameTime * 60;
|
||||
startCap.y = root.midY - startCap.height / 2 + root.currentAmp * Math.sin((waveClip.startX / root.wavelength) * 2 * Math.PI + root.phase);
|
||||
endCap.y = root.midY - endCap.height / 2 + root.currentAmp * Math.sin((waveClip.endX / root.wavelength) * 2 * Math.PI + root.phase);
|
||||
}
|
||||
}
|
||||
|
||||
function buildStaticWave() {
|
||||
const start = waveClip.startX - 2 * root.wavelength
|
||||
const end = width + 2 * root.wavelength
|
||||
if (end <= start) { waveSvg.path = ""; return }
|
||||
|
||||
const kLocal = k
|
||||
const halfPeriod = root.wavelength / 2
|
||||
function y0(x) { return root.midY + root.currentAmp * Math.sin(kLocal * x) }
|
||||
function dy0(x) { return root.currentAmp * Math.cos(kLocal * x) * kLocal }
|
||||
|
||||
let x0 = start
|
||||
let d = `M ${x0} ${y0(x0)}`
|
||||
while (x0 < end) {
|
||||
const x1 = Math.min(x0 + halfPeriod, end)
|
||||
const dx = x1 - x0
|
||||
const yA = y0(x0), yB = y0(x1)
|
||||
const dyA = dy0(x0), dyB = dy0(x1)
|
||||
const c1x = x0 + dx/3
|
||||
const c1y = yA + (dyA * dx)/3
|
||||
const c2x = x1 - dx/3
|
||||
const c2y = yB - (dyB * dx)/3
|
||||
d += ` C ${c1x} ${c1y} ${c2x} ${c2y} ${x1} ${yB}`
|
||||
x0 = x1
|
||||
const start = waveClip.startX - 2 * root.wavelength;
|
||||
const end = width + 2 * root.wavelength;
|
||||
if (end <= start) {
|
||||
waveSvg.path = "";
|
||||
return;
|
||||
}
|
||||
waveSvg.path = d
|
||||
|
||||
const kLocal = k;
|
||||
const halfPeriod = root.wavelength / 2;
|
||||
function y0(x) {
|
||||
return root.midY + root.currentAmp * Math.sin(kLocal * x);
|
||||
}
|
||||
function dy0(x) {
|
||||
return root.currentAmp * Math.cos(kLocal * x) * kLocal;
|
||||
}
|
||||
|
||||
let x0 = start;
|
||||
let d = `M ${x0} ${y0(x0)}`;
|
||||
while (x0 < end) {
|
||||
const x1 = Math.min(x0 + halfPeriod, end);
|
||||
const dx = x1 - x0;
|
||||
const yA = y0(x0), yB = y0(x1);
|
||||
const dyA = dy0(x0), dyB = dy0(x1);
|
||||
const c1x = x0 + dx / 3;
|
||||
const c1y = yA + (dyA * dx) / 3;
|
||||
const c2x = x1 - dx / 3;
|
||||
const c2y = yB - (dyB * dx) / 3;
|
||||
d += ` C ${c1x} ${c1y} ${c2x} ${c2y} ${x1} ${yB}`;
|
||||
x0 = x1;
|
||||
}
|
||||
waveSvg.path = d;
|
||||
}
|
||||
|
||||
Component.onCompleted: { currentAmp = isPlaying ? amp : 0; buildStaticWave() }
|
||||
onWidthChanged: { flatStart.x = 0; flatEnd.x = width; buildStaticWave() }
|
||||
Component.onCompleted: {
|
||||
currentAmp = isPlaying ? amp : 0;
|
||||
buildStaticWave();
|
||||
}
|
||||
onWidthChanged: {
|
||||
flatEnd.x = width;
|
||||
buildStaticWave();
|
||||
}
|
||||
onHeightChanged: buildStaticWave()
|
||||
onCurrentAmpChanged: buildStaticWave()
|
||||
onWavelengthChanged: { k = (2 * Math.PI) / Math.max(1e-6, wavelength); buildStaticWave() }
|
||||
onWavelengthChanged: {
|
||||
k = (2 * Math.PI) / Math.max(1e-6, wavelength);
|
||||
buildStaticWave();
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -11,21 +11,21 @@ text = '{{colors.background.default.hex}}'
|
||||
cursor = '{{colors.primary.default.hex}}'
|
||||
|
||||
[colors.normal]
|
||||
black = '{{dank16.color0.hex}}'
|
||||
red = '{{dank16.color1.hex}}'
|
||||
green = '{{dank16.color2.hex}}'
|
||||
yellow = '{{dank16.color3.hex}}'
|
||||
blue = '{{dank16.color4.hex}}'
|
||||
magenta = '{{dank16.color5.hex}}'
|
||||
cyan = '{{dank16.color6.hex}}'
|
||||
white = '{{dank16.color7.hex}}'
|
||||
black = '{{dank16.color0.default.hex}}'
|
||||
red = '{{dank16.color1.default.hex}}'
|
||||
green = '{{dank16.color2.default.hex}}'
|
||||
yellow = '{{dank16.color3.default.hex}}'
|
||||
blue = '{{dank16.color4.default.hex}}'
|
||||
magenta = '{{dank16.color5.default.hex}}'
|
||||
cyan = '{{dank16.color6.default.hex}}'
|
||||
white = '{{dank16.color7.default.hex}}'
|
||||
|
||||
[colors.bright]
|
||||
black = '{{dank16.color8.hex}}'
|
||||
red = '{{dank16.color9.hex}}'
|
||||
green = '{{dank16.color10.hex}}'
|
||||
yellow = '{{dank16.color11.hex}}'
|
||||
blue = '{{dank16.color12.hex}}'
|
||||
magenta = '{{dank16.color13.hex}}'
|
||||
cyan = '{{dank16.color14.hex}}'
|
||||
white = '{{dank16.color15.hex}}'
|
||||
black = '{{dank16.color8.default.hex}}'
|
||||
red = '{{dank16.color9.default.hex}}'
|
||||
green = '{{dank16.color10.default.hex}}'
|
||||
yellow = '{{dank16.color11.default.hex}}'
|
||||
blue = '{{dank16.color12.default.hex}}'
|
||||
magenta = '{{dank16.color13.default.hex}}'
|
||||
cyan = '{{dank16.color14.default.hex}}'
|
||||
white = '{{dank16.color15.default.hex}}'
|
||||
|
||||
@@ -4,19 +4,19 @@ background={{colors.background.default.hex_stripped}}
|
||||
selection-foreground={{colors.on_surface.default.hex_stripped}}
|
||||
selection-background={{colors.primary_container.default.hex_stripped}}
|
||||
|
||||
regular0={{dank16.color0.hex_stripped}}
|
||||
regular1={{dank16.color1.hex_stripped}}
|
||||
regular2={{dank16.color2.hex_stripped}}
|
||||
regular3={{dank16.color3.hex_stripped}}
|
||||
regular4={{dank16.color4.hex_stripped}}
|
||||
regular5={{dank16.color5.hex_stripped}}
|
||||
regular6={{dank16.color6.hex_stripped}}
|
||||
regular7={{dank16.color7.hex_stripped}}
|
||||
bright0={{dank16.color8.hex_stripped}}
|
||||
bright1={{dank16.color9.hex_stripped}}
|
||||
bright2={{dank16.color10.hex_stripped}}
|
||||
bright3={{dank16.color11.hex_stripped}}
|
||||
bright4={{dank16.color12.hex_stripped}}
|
||||
bright5={{dank16.color13.hex_stripped}}
|
||||
bright6={{dank16.color14.hex_stripped}}
|
||||
bright7={{dank16.color15.hex_stripped}}
|
||||
regular0={{dank16.color0.default.hex_stripped}}
|
||||
regular1={{dank16.color1.default.hex_stripped}}
|
||||
regular2={{dank16.color2.default.hex_stripped}}
|
||||
regular3={{dank16.color3.default.hex_stripped}}
|
||||
regular4={{dank16.color4.default.hex_stripped}}
|
||||
regular5={{dank16.color5.default.hex_stripped}}
|
||||
regular6={{dank16.color6.default.hex_stripped}}
|
||||
regular7={{dank16.color7.default.hex_stripped}}
|
||||
bright0={{dank16.color8.default.hex_stripped}}
|
||||
bright1={{dank16.color9.default.hex_stripped}}
|
||||
bright2={{dank16.color10.default.hex_stripped}}
|
||||
bright3={{dank16.color11.default.hex_stripped}}
|
||||
bright4={{dank16.color12.default.hex_stripped}}
|
||||
bright5={{dank16.color13.default.hex_stripped}}
|
||||
bright6={{dank16.color14.default.hex_stripped}}
|
||||
bright7={{dank16.color15.default.hex_stripped}}
|
||||
|
||||
@@ -4,19 +4,19 @@ cursor-color = {{colors.primary.default.hex}}
|
||||
selection-background = {{colors.primary_container.default.hex}}
|
||||
selection-foreground = {{colors.on_surface.default.hex}}
|
||||
|
||||
palette = 0={{dank16.color0.hex}}
|
||||
palette = 1={{dank16.color1.hex}}
|
||||
palette = 2={{dank16.color2.hex}}
|
||||
palette = 3={{dank16.color3.hex}}
|
||||
palette = 4={{dank16.color4.hex}}
|
||||
palette = 5={{dank16.color5.hex}}
|
||||
palette = 6={{dank16.color6.hex}}
|
||||
palette = 7={{dank16.color7.hex}}
|
||||
palette = 8={{dank16.color8.hex}}
|
||||
palette = 9={{dank16.color9.hex}}
|
||||
palette = 10={{dank16.color10.hex}}
|
||||
palette = 11={{dank16.color11.hex}}
|
||||
palette = 12={{dank16.color12.hex}}
|
||||
palette = 13={{dank16.color13.hex}}
|
||||
palette = 14={{dank16.color14.hex}}
|
||||
palette = 15={{dank16.color15.hex}}
|
||||
palette = 0={{dank16.color0.default.hex}}
|
||||
palette = 1={{dank16.color1.default.hex}}
|
||||
palette = 2={{dank16.color2.default.hex}}
|
||||
palette = 3={{dank16.color3.default.hex}}
|
||||
palette = 4={{dank16.color4.default.hex}}
|
||||
palette = 5={{dank16.color5.default.hex}}
|
||||
palette = 6={{dank16.color6.default.hex}}
|
||||
palette = 7={{dank16.color7.default.hex}}
|
||||
palette = 8={{dank16.color8.default.hex}}
|
||||
palette = 9={{dank16.color9.default.hex}}
|
||||
palette = 10={{dank16.color10.default.hex}}
|
||||
palette = 11={{dank16.color11.default.hex}}
|
||||
palette = 12={{dank16.color12.default.hex}}
|
||||
palette = 13={{dank16.color13.default.hex}}
|
||||
palette = 14={{dank16.color14.default.hex}}
|
||||
palette = 15={{dank16.color15.default.hex}}
|
||||
|
||||
@@ -7,19 +7,19 @@ selection_foreground {{colors.on_secondary.default.hex}}
|
||||
selection_background {{colors.secondary_fixed_dim.default.hex}}
|
||||
url_color {{colors.primary.default.hex}}
|
||||
|
||||
color0 {{dank16.color0.hex}}
|
||||
color1 {{dank16.color1.hex}}
|
||||
color2 {{dank16.color2.hex}}
|
||||
color3 {{dank16.color3.hex}}
|
||||
color4 {{dank16.color4.hex}}
|
||||
color5 {{dank16.color5.hex}}
|
||||
color6 {{dank16.color6.hex}}
|
||||
color7 {{dank16.color7.hex}}
|
||||
color8 {{dank16.color8.hex}}
|
||||
color9 {{dank16.color9.hex}}
|
||||
color10 {{dank16.color10.hex}}
|
||||
color11 {{dank16.color11.hex}}
|
||||
color12 {{dank16.color12.hex}}
|
||||
color13 {{dank16.color13.hex}}
|
||||
color14 {{dank16.color14.hex}}
|
||||
color15 {{dank16.color15.hex}}
|
||||
color0 {{dank16.color0.default.hex}}
|
||||
color1 {{dank16.color1.default.hex}}
|
||||
color2 {{dank16.color2.default.hex}}
|
||||
color3 {{dank16.color3.default.hex}}
|
||||
color4 {{dank16.color4.default.hex}}
|
||||
color5 {{dank16.color5.default.hex}}
|
||||
color6 {{dank16.color6.default.hex}}
|
||||
color7 {{dank16.color7.default.hex}}
|
||||
color8 {{dank16.color8.default.hex}}
|
||||
color9 {{dank16.color9.default.hex}}
|
||||
color10 {{dank16.color10.default.hex}}
|
||||
color11 {{dank16.color11.default.hex}}
|
||||
color12 {{dank16.color12.default.hex}}
|
||||
color13 {{dank16.color13.default.hex}}
|
||||
color14 {{dank16.color14.default.hex}}
|
||||
color15 {{dank16.color15.default.hex}}
|
||||
|
||||
@@ -1,431 +1,299 @@
|
||||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "Dynamic Base16 DankShell",
|
||||
"name": "Dynamic Base16 DankShell Dark",
|
||||
"semanticHighlighting": true,
|
||||
"colors": {
|
||||
//
|
||||
// Core foreground + background hierarchy
|
||||
//
|
||||
"foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"editor.background": "{{colors.background.dark.hex}}",
|
||||
"editor.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"editorLineNumber.foreground": "{{colors.outline.dark.hex}}",
|
||||
"editorLineNumber.activeForeground": "{{colors.on_surface.dark.hex}}",
|
||||
"editorCursor.foreground": "{{colors.primary.dark.hex}}",
|
||||
"editor.selectionBackground": "{{colors.primary_container.dark.hex}}",
|
||||
"editor.inactiveSelectionBackground": "{{colors.background.dark.hex}}",
|
||||
"editor.lineHighlightBackground": "{{colors.background.dark.hex}}",
|
||||
"editorIndentGuide.background": "{{colors.background.dark.hex}}",
|
||||
"editorIndentGuide.activeBackground": "{{colors.outline.dark.hex}}",
|
||||
"editorWhitespace.foreground": "{{colors.outline_variant.dark.hex}}",
|
||||
"editorBracketMatch.background": "{{colors.background.dark.hex}}",
|
||||
"editorBracketMatch.border": "{{colors.primary.dark.hex}}",
|
||||
|
||||
"errorForeground": "{{colors.error.dark.hex}}",
|
||||
//
|
||||
// Borders + dividers
|
||||
//
|
||||
"panel.border": "{{colors.outline_variant.dark.hex}}",
|
||||
"panelTitle.activeBorder": "{{colors.primary.dark.hex}}",
|
||||
"sideBar.border": "{{colors.outline_variant.dark.hex}}",
|
||||
"editorGroup.border": "{{colors.outline_variant.dark.hex}}",
|
||||
"tab.border": "{{colors.outline_variant.dark.hex}}",
|
||||
"titleBar.border": "{{colors.outline_variant.dark.hex}}",
|
||||
//
|
||||
// Focus + active indicators
|
||||
//
|
||||
"focusBorder": "{{colors.primary.dark.hex}}",
|
||||
"selection.background": "{{colors.primary_container.dark.hex}}66",
|
||||
//
|
||||
// Title bar, activity bar, sidebar
|
||||
//
|
||||
"titleBar.activeBackground": "{{colors.background.dark.hex}}",
|
||||
"titleBar.activeForeground": "{{colors.on_surface.dark.hex}}",
|
||||
"titleBar.inactiveForeground": "{{colors.outline.dark.hex}}",
|
||||
"activityBar.background": "{{colors.background.dark.hex}}",
|
||||
"activityBar.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"activityBar.inactiveForeground": "{{colors.outline.dark.hex}}",
|
||||
"activityBar.activeBorder": "{{colors.primary.dark.hex}}",
|
||||
"activityBar.activeBackground": "{{colors.background.dark.hex}}",
|
||||
"activityBarBadge.background": "{{colors.primary.dark.hex}}",
|
||||
"activityBarBadge.foreground": "{{colors.on_primary.dark.hex}}",
|
||||
|
||||
"sideBar.background": "{{colors.background.dark.hex}}",
|
||||
"sideBar.background": "{{colors.surface_container_low.dark.hex}}",
|
||||
"sideBar.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"sideBar.border": "{{colors.background.dark.hex}}",
|
||||
"statusBarItem.hoverBackground": "{{colors.surface_container_low.dark.hex}}",
|
||||
"statusBarItem.activeBackground": "{{colors.surface_container.dark.hex}}",
|
||||
"sideBarTitle.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"sideBarSectionHeader.background": "{{colors.background.dark.hex}}",
|
||||
"panel.background": "{{colors.surface_container_low.dark.hex}}",
|
||||
"panelTitle.activeForeground": "{{colors.on_surface.dark.hex}}",
|
||||
"panelTitle.inactiveForeground": "{{colors.outline.dark.hex}}",
|
||||
"sideBarSectionHeader.background": "{{colors.surface_container.dark.hex}}",
|
||||
"sideBarSectionHeader.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
|
||||
"list.activeSelectionBackground": "{{colors.primary_container.dark.hex}}",
|
||||
"list.activeSelectionForeground": "{{colors.on_primary_container.dark.hex}}",
|
||||
"list.inactiveSelectionBackground": "{{colors.surface_container.dark.hex}}",
|
||||
"list.inactiveSelectionForeground": "{{colors.on_surface.dark.hex}}",
|
||||
"list.hoverBackground": "{{colors.surface_container.dark.hex}}",
|
||||
"list.hoverForeground": "{{colors.on_surface.dark.hex}}",
|
||||
"list.focusBackground": "{{colors.surface_container_high.dark.hex}}",
|
||||
"list.focusForeground": "{{colors.on_surface.dark.hex}}",
|
||||
"list.highlightForeground": "{{colors.primary.dark.hex}}",
|
||||
|
||||
"statusBar.background": "{{colors.background.dark.hex}}",
|
||||
"statusBar.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"statusBar.border": "{{colors.background.dark.hex}}",
|
||||
"statusBar.noFolderBackground": "{{colors.background.dark.hex}}",
|
||||
"statusBar.debuggingBackground": "{{colors.error.dark.hex}}",
|
||||
"statusBar.debuggingForeground": "{{colors.on_error.dark.hex}}",
|
||||
|
||||
"tab.activeBackground": "{{colors.background.dark.hex}}",
|
||||
//
|
||||
// Tabs + editor groups
|
||||
//
|
||||
"editorGroupHeader.tabsBackground": "{{colors.background.dark.hex}}",
|
||||
"tab.activeBackground": "{{colors.surface_container_low.dark.hex}}",
|
||||
"tab.inactiveBackground": "{{colors.background.dark.hex}}",
|
||||
"tab.activeForeground": "{{colors.on_surface.dark.hex}}",
|
||||
"tab.inactiveForeground": "{{colors.outline.dark.hex}}",
|
||||
"tab.border": "{{colors.background.dark.hex}}",
|
||||
"tab.activeBorder": "{{colors.primary.dark.hex}}",
|
||||
"tab.unfocusedActiveBorder": "{{colors.outline.dark.hex}}",
|
||||
|
||||
"editorGroupHeader.tabsBackground": "{{colors.background.dark.hex}}",
|
||||
"editorGroupHeader.noTabsBackground": "{{colors.background.dark.hex}}",
|
||||
|
||||
"titleBar.activeBackground": "{{colors.background.dark.hex}}",
|
||||
"titleBar.activeForeground": "{{colors.on_surface.dark.hex}}",
|
||||
"titleBar.inactiveBackground": "{{colors.background.dark.hex}}",
|
||||
"titleBar.inactiveForeground": "{{colors.outline.dark.hex}}",
|
||||
"titleBar.border": "{{colors.background.dark.hex}}",
|
||||
|
||||
"input.background": "{{colors.background.dark.hex}}",
|
||||
"tab.activeBorderTop": "{{colors.primary.dark.hex}}",
|
||||
//
|
||||
// Lists (files, search results, etc.)
|
||||
//
|
||||
"list.activeSelectionBackground": "{{colors.primary_container.dark.hex}}",
|
||||
"list.activeSelectionForeground": "{{colors.on_primary_container.dark.hex}}",
|
||||
"list.inactiveSelectionBackground": "{{colors.surface_container.dark.hex}}",
|
||||
"list.hoverBackground": "{{colors.surface_container.dark.hex}}",
|
||||
"list.hoverForeground": "{{colors.on_surface.dark.hex}}",
|
||||
"list.focusForeground": "{{colors.on_surface.dark.hex}}",
|
||||
"list.focusOutline": "{{colors.primary.dark.hex}}",
|
||||
"list.focusBackground": "{{colors.surface_container_high.dark.hex}}",
|
||||
"list.highlightForeground": "{{colors.primary.dark.hex}}",
|
||||
"list.errorForeground": "{{colors.error.dark.hex}}",
|
||||
"list.warningForeground": "{{colors.secondary.dark.hex}}",
|
||||
//
|
||||
// Inputs + dropdowns
|
||||
//
|
||||
"input.background": "{{colors.surface_container_low.dark.hex}}",
|
||||
"input.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"input.border": "{{colors.outline.dark.hex}}",
|
||||
"input.border": "{{colors.outline_variant.dark.hex}}",
|
||||
"input.placeholderForeground": "{{colors.outline.dark.hex}}",
|
||||
"inputOption.activeBorder": "{{colors.primary.dark.hex}}",
|
||||
"inputValidation.errorBackground": "{{colors.error.dark.hex}}",
|
||||
"inputValidation.errorBorder": "{{colors.error.dark.hex}}",
|
||||
|
||||
"dropdown.background": "{{colors.background.dark.hex}}",
|
||||
"dropdown.background": "{{colors.surface_container_low.dark.hex}}",
|
||||
"dropdown.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"dropdown.border": "{{colors.outline.dark.hex}}",
|
||||
|
||||
"quickInput.background": "{{colors.background.dark.hex}}",
|
||||
"dropdown.border": "{{colors.outline_variant.dark.hex}}",
|
||||
"quickInput.background": "{{colors.surface_container_low.dark.hex}}",
|
||||
"quickInput.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"quickInputList.focusBackground": "{{colors.surface_container_high.dark.hex}}",
|
||||
"quickInputList.focusForeground": "{{colors.on_surface.dark.hex}}",
|
||||
|
||||
"widget.shadow": "{{colors.background.dark.hex}}80",
|
||||
//
|
||||
// Buttons
|
||||
//
|
||||
"button.background": "{{colors.primary.dark.hex}}",
|
||||
"button.foreground": "{{colors.on_primary.dark.hex}}",
|
||||
"button.hoverBackground": "{{colors.primary_container.dark.hex}}",
|
||||
|
||||
"focusBorder": "{{colors.primary.dark.hex}}",
|
||||
"badge.background": "{{colors.secondary.dark.hex}}",
|
||||
"badge.foreground": "{{colors.on_secondary.dark.hex}}",
|
||||
|
||||
"panel.background": "{{colors.background.dark.hex}}",
|
||||
"panel.border": "{{colors.primary.dark.hex}}",
|
||||
"panelTitle.activeBorder": "{{colors.primary.dark.hex}}",
|
||||
"panelTitle.activeForeground": "{{colors.on_surface.dark.hex}}",
|
||||
"panelTitle.inactiveForeground": "{{colors.outline.dark.hex}}",
|
||||
|
||||
"terminal.background": "{{colors.background.dark.hex}}",
|
||||
"terminal.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"terminal.ansiBlack": "{{dank16.color0.hex}}",
|
||||
"terminal.ansiRed": "{{dank16.color1.hex}}",
|
||||
"terminal.ansiGreen": "{{dank16.color2.hex}}",
|
||||
"terminal.ansiYellow": "{{dank16.color3.hex}}",
|
||||
"terminal.ansiBlue": "{{dank16.color4.hex}}",
|
||||
"terminal.ansiMagenta": "{{dank16.color5.hex}}",
|
||||
"terminal.ansiCyan": "{{dank16.color6.hex}}",
|
||||
"terminal.ansiWhite": "{{dank16.color7.hex}}",
|
||||
"terminal.ansiBrightBlack": "{{dank16.color8.hex}}",
|
||||
"terminal.ansiBrightRed": "{{dank16.color9.hex}}",
|
||||
"terminal.ansiBrightGreen": "{{dank16.color10.hex}}",
|
||||
"terminal.ansiBrightYellow": "{{dank16.color11.hex}}",
|
||||
"terminal.ansiBrightBlue": "{{dank16.color12.hex}}",
|
||||
"terminal.ansiBrightMagenta": "{{dank16.color13.hex}}",
|
||||
"terminal.ansiBrightCyan": "{{dank16.color14.hex}}",
|
||||
"terminal.ansiBrightWhite": "{{dank16.color15.hex}}",
|
||||
|
||||
"gitDecoration.modifiedResourceForeground": "{{colors.primary.dark.hex}}",
|
||||
"gitDecoration.addedResourceForeground": "{{colors.primary.dark.hex}}",
|
||||
"gitDecoration.stageModifiedResourceForeground": "{{colors.primary.dark.hex}}",
|
||||
"gitDecoration.stageDeletedResourceForeground": "{{colors.error.dark.hex}}",
|
||||
"gitDecoration.deletedResourceForeground": "{{colors.error.dark.hex}}",
|
||||
"gitDecoration.untrackedResourceForeground": "{{colors.secondary.dark.hex}}",
|
||||
"gitDecoration.ignoredResourceForeground": "{{colors.outline.dark.hex}}",
|
||||
"gitDecoration.conflictingResourceForeground": "{{colors.error_container.dark.hex}}",
|
||||
"gitDecoration.submoduleResourceForeground": "{{colors.primary.dark.hex}}",
|
||||
|
||||
"editorWidget.background": "{{colors.background.dark.hex}}",
|
||||
"editorWidget.border": "{{colors.outline.dark.hex}}",
|
||||
"editorSuggestWidget.background": "{{colors.background.dark.hex}}",
|
||||
"editorSuggestWidget.border": "{{colors.outline.dark.hex}}",
|
||||
"editorSuggestWidget.selectedBackground": "{{colors.surface_container_high.dark.hex}}",
|
||||
"editorSuggestWidget.highlightForeground": "{{colors.primary.dark.hex}}",
|
||||
|
||||
"peekView.border": "{{colors.primary.dark.hex}}",
|
||||
"peekViewEditor.background": "{{colors.background.dark.hex}}",
|
||||
"peekViewResult.background": "{{colors.background.dark.hex}}",
|
||||
"peekViewTitle.background": "{{colors.background.dark.hex}}",
|
||||
|
||||
"notificationCenter.border": "{{colors.outline.dark.hex}}",
|
||||
"notifications.background": "{{colors.background.dark.hex}}",
|
||||
"notifications.border": "{{colors.outline.dark.hex}}",
|
||||
|
||||
//
|
||||
// Status bar
|
||||
//
|
||||
"statusBar.background": "{{colors.background.dark.hex}}",
|
||||
"statusBar.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"statusBar.border": "{{colors.outline_variant.dark.hex}}",
|
||||
"statusBar.noFolderBackground": "{{colors.background.dark.hex}}",
|
||||
"statusBar.noFolderForeground": "{{colors.on_surface.dark.hex}}",
|
||||
"statusBar.debuggingBackground": "{{colors.error.dark.hex}}",
|
||||
"statusBar.debuggingForeground": "{{colors.on_error.dark.hex}}",
|
||||
//
|
||||
// Notifications
|
||||
//
|
||||
"notificationCenterHeader.background": "{{colors.surface_container_low.dark.hex}}",
|
||||
"notificationCenterHeader.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"notificationCenter.border": "{{colors.outline_variant.dark.hex}}",
|
||||
"notifications.background": "{{colors.surface_container_low.dark.hex}}",
|
||||
"notifications.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"notifications.border": "{{colors.outline_variant.dark.hex}}",
|
||||
"notificationsErrorIcon.foreground": "{{colors.error.dark.hex}}",
|
||||
"notificationsWarningIcon.foreground": "{{colors.secondary.dark.hex}}",
|
||||
"notificationsInfoIcon.foreground": "{{colors.primary.dark.hex}}",
|
||||
//
|
||||
// Breadcrumbs
|
||||
//
|
||||
"breadcrumb.background": "{{colors.surface_container.dark.hex}}",
|
||||
"breadcrumb.foreground": "{{colors.outline.dark.hex}}",
|
||||
"breadcrumb.focusForeground": "{{colors.on_surface.dark.hex}}",
|
||||
"breadcrumb.activeSelectionForeground": "{{colors.primary.dark.hex}}",
|
||||
|
||||
//
|
||||
// Editor highlights + guides
|
||||
//
|
||||
"editorLineNumber.foreground": "{{colors.outline.dark.hex}}",
|
||||
"editorLineNumber.activeForeground": "{{colors.primary.dark.hex}}",
|
||||
"editorCursor.foreground": "{{colors.primary.dark.hex}}",
|
||||
"editor.lineHighlightBackground": "{{colors.surface_container.dark.hex}}66",
|
||||
"editor.wordHighlightBackground": "{{colors.secondary.dark.hex}}22",
|
||||
"editor.wordHighlightStrongBackground": "{{colors.tertiary.dark.hex}}22",
|
||||
"editor.selectionBackground": "{{colors.primary_container.dark.hex}}66",
|
||||
"editor.inactiveSelectionBackground": "{{colors.primary_container.dark.hex}}33",
|
||||
"editorWhitespace.foreground": "{{colors.outline.dark.hex}}66",
|
||||
"editorIndentGuide.background1": "{{colors.outline.dark.hex}}33",
|
||||
"editorIndentGuide.activeBackground1": "{{colors.primary.dark.hex}}99",
|
||||
"editorOverviewRuler.border": "{{colors.outline_variant.dark.hex}}",
|
||||
"editorOverviewRuler.errorForeground": "{{colors.error.dark.hex}}88",
|
||||
"editorOverviewRuler.warningForeground": "{{colors.tertiary.dark.hex}}88",
|
||||
"editorOverviewRuler.infoForeground": "{{colors.primary.dark.hex}}88",
|
||||
"editorStickyScroll.background": "{{colors.background.dark.hex}}",
|
||||
"editorStickyScrollHover.background": "{{colors.surface_container_low.dark.hex}}",
|
||||
"editorBracketHighlight.unexpectedBracket.foreground": "{{colors.outline.dark.hex}}",
|
||||
//
|
||||
// Diff editor
|
||||
//
|
||||
"diffEditor.insertedTextBackground": "{{colors.secondary.dark.hex}}20",
|
||||
"diffEditor.removedTextBackground": "{{colors.error.dark.hex}}20",
|
||||
//
|
||||
// Git
|
||||
//
|
||||
"gitDecoration.modifiedResourceForeground": "{{colors.primary.dark.hex}}",
|
||||
"gitDecoration.addedResourceForeground": "{{colors.secondary.dark.hex}}",
|
||||
"gitDecoration.deletedResourceForeground": "{{colors.error.dark.hex}}",
|
||||
"gitDecoration.ignoredResourceForeground": "{{colors.outline.dark.hex}}",
|
||||
//
|
||||
// Peek, Hover, Widgets
|
||||
//
|
||||
"editorHoverWidget.background": "{{colors.surface_container_high.dark.hex}}",
|
||||
"editorHoverWidget.border": "{{colors.outline.dark.hex}}",
|
||||
"editorSuggestWidget.background": "{{colors.surface_container.dark.hex}}",
|
||||
"editorSuggestWidget.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"editorSuggestWidget.selectedBackground": "{{colors.surface_container_high.dark.hex}}",
|
||||
"editorSuggestWidget.highlightForeground": "{{colors.primary.dark.hex}}",
|
||||
//
|
||||
// Scrollbar
|
||||
//
|
||||
"scrollbarSlider.background": "{{colors.outline.dark.hex}}40",
|
||||
"scrollbarSlider.hoverBackground": "{{colors.outline.dark.hex}}60",
|
||||
"scrollbarSlider.activeBackground": "{{colors.outline.dark.hex}}80",
|
||||
|
||||
"editorError.foreground": "{{colors.error.dark.hex}}",
|
||||
"editorWarning.foreground": "{{colors.tertiary.dark.hex}}",
|
||||
"editorInfo.foreground": "{{colors.primary.dark.hex}}",
|
||||
|
||||
"editorGutter.addedBackground": "{{colors.secondary.dark.hex}}",
|
||||
"editorGutter.modifiedBackground": "{{colors.tertiary.dark.hex}}",
|
||||
"editorGutter.deletedBackground": "{{colors.error.dark.hex}}",
|
||||
|
||||
"diffEditor.insertedTextBackground": "{{colors.secondary.dark.hex}}20",
|
||||
"diffEditor.removedTextBackground": "{{colors.error.dark.hex}}20",
|
||||
|
||||
"merge.currentHeaderBackground": "{{colors.primary.dark.hex}}40",
|
||||
"merge.incomingHeaderBackground": "{{colors.secondary.dark.hex}}40",
|
||||
|
||||
"menubar.selectionBackground": "{{colors.surface_container.dark.hex}}",
|
||||
"menu.background": "{{colors.background.dark.hex}}",
|
||||
"menu.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"menu.selectionBackground": "{{colors.surface_container_high.dark.hex}}",
|
||||
"menu.selectionForeground": "{{colors.on_surface.dark.hex}}",
|
||||
|
||||
"debugToolBar.background": "{{colors.background.dark.hex}}",
|
||||
"debugExceptionWidget.background": "{{colors.background.dark.hex}}",
|
||||
"debugExceptionWidget.border": "{{colors.error.dark.hex}}"
|
||||
//
|
||||
// Terminal (Dank16)
|
||||
//
|
||||
"terminal.background": "{{colors.background.dark.hex}}",
|
||||
"terminal.foreground": "{{colors.on_surface.dark.hex}}",
|
||||
"terminal.ansiBlack": "{{dank16.color0.dark.hex}}",
|
||||
"terminal.ansiRed": "{{dank16.color1.dark.hex}}",
|
||||
"terminal.ansiGreen": "{{dank16.color2.dark.hex}}",
|
||||
"terminal.ansiYellow": "{{dank16.color3.dark.hex}}",
|
||||
"terminal.ansiBlue": "{{dank16.color4.dark.hex}}",
|
||||
"terminal.ansiMagenta": "{{dank16.color5.dark.hex}}",
|
||||
"terminal.ansiCyan": "{{dank16.color6.dark.hex}}",
|
||||
"terminal.ansiWhite": "{{dank16.color7.dark.hex}}",
|
||||
"terminal.ansiBrightBlack": "{{dank16.color8.dark.hex}}",
|
||||
"terminal.ansiBrightRed": "{{dank16.color9.dark.hex}}",
|
||||
"terminal.ansiBrightGreen": "{{dank16.color10.dark.hex}}",
|
||||
"terminal.ansiBrightYellow": "{{dank16.color11.dark.hex}}",
|
||||
"terminal.ansiBrightBlue": "{{dank16.color12.dark.hex}}",
|
||||
"terminal.ansiBrightMagenta": "{{dank16.color13.dark.hex}}",
|
||||
"terminal.ansiBrightCyan": "{{dank16.color14.dark.hex}}",
|
||||
"terminal.ansiBrightWhite": "{{dank16.color15.dark.hex}}"
|
||||
},
|
||||
|
||||
//
|
||||
// Token colors
|
||||
//
|
||||
"tokenColors": [
|
||||
{
|
||||
"scope": ["variable", "meta.object-literal.key"],
|
||||
"scope": [
|
||||
"comment"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.on_surface.dark.hex}}"
|
||||
"foreground": "{{dank16.color8.dark.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["string", "constant.other.symbol"],
|
||||
"scope": [
|
||||
"keyword"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.dark.hex}}"
|
||||
"foreground": "{{dank16.color5.dark.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["constant.numeric", "constant.language", "constant.character"],
|
||||
"scope": [
|
||||
"string"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.tertiary.dark.hex}}"
|
||||
"foreground": "{{dank16.color3.dark.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.type", "support.type", "entity.name.class"],
|
||||
"scope": [
|
||||
"constant",
|
||||
"number"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.tertiary.dark.hex}}"
|
||||
"foreground": "{{dank16.color12.dark.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.function", "support.function"],
|
||||
"scope": [
|
||||
"variable"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.primary.dark.hex}}"
|
||||
"foreground": "{{dank16.color15.dark.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["support.class", "support.variable", "variable.language"],
|
||||
"scope": [
|
||||
"entity.name.function"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.dark.hex}}"
|
||||
"foreground": "{{dank16.color2.dark.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["invalid"],
|
||||
"scope": [
|
||||
"entity.name.class",
|
||||
"support.type"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.dark.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"invalid"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.error.dark.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["invalid.deprecated"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.outline.dark.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.heading"],
|
||||
"scope": [
|
||||
"markup.heading"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.primary.dark.hex}}",
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.bold"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.tertiary.dark.hex}}",
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.italic"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.primary.dark.hex}}",
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.underline"],
|
||||
"settings": {
|
||||
"fontStyle": "underline"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.quote"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.dark.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.list"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.on_surface.dark.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.raw", "markup.inline.raw"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.dark.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["comment", "punctuation.definition.comment"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color8.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color5.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage.type",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color13.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage.modifier",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color5.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "variable",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "variable.parameter",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color7.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["meta.object-literal.key", "meta.property.object", "variable.other.property"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color4.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.other.symbol",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["constant.numeric", "constant.language"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.character",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color3.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.type", "entity.name.class"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "support.type",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color13.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.function", "support.function"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color2.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["support.class", "support.variable"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "variable.language",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "entity.name.tag.yaml",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["string.unquoted.plain.out.yaml", "string.unquoted.yaml"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color3.hex}}"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
"semanticHighlighting": true,
|
||||
//
|
||||
// Semantic tokens
|
||||
//
|
||||
"semanticTokenColors": {
|
||||
"variable": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
},
|
||||
"variable.readonly": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"property": {
|
||||
"foreground": "{{dank16.color4.hex}}"
|
||||
},
|
||||
"function": {
|
||||
"foreground": "{{dank16.color2.hex}}"
|
||||
},
|
||||
"method": {
|
||||
"foreground": "{{dank16.color2.hex}}"
|
||||
},
|
||||
"type": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"class": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"typeParameter": {
|
||||
"foreground": "{{dank16.color13.hex}}"
|
||||
},
|
||||
"enumMember": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"string": {
|
||||
"foreground": "{{dank16.color3.hex}}"
|
||||
},
|
||||
"number": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"comment": {
|
||||
"foreground": "{{dank16.color8.hex}}"
|
||||
},
|
||||
"keyword": {
|
||||
"foreground": "{{dank16.color5.hex}}"
|
||||
},
|
||||
"operator": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
"foreground": "{{dank16.color15.dark.hex}}"
|
||||
},
|
||||
"parameter": {
|
||||
"foreground": "{{dank16.color7.hex}}"
|
||||
"foreground": "{{dank16.color7.dark.hex}}"
|
||||
},
|
||||
"namespace": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
"property": {
|
||||
"foreground": "{{dank16.color4.dark.hex}}"
|
||||
},
|
||||
"function": {
|
||||
"foreground": "{{dank16.color2.dark.hex}}"
|
||||
},
|
||||
"string": {
|
||||
"foreground": "{{dank16.color3.dark.hex}}"
|
||||
},
|
||||
"number": {
|
||||
"foreground": "{{dank16.color12.dark.hex}}"
|
||||
},
|
||||
"keyword": {
|
||||
"foreground": "{{dank16.color5.dark.hex}}"
|
||||
},
|
||||
"comment": {
|
||||
"foreground": "{{dank16.color8.dark.hex}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,431 +1,251 @@
|
||||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "Dynamic Base16 DankShell",
|
||||
"semanticHighlighting": true,
|
||||
"colors": {
|
||||
"foreground": "{{colors.on_surface.default.hex}}",
|
||||
"editor.background": "{{colors.background.default.hex}}",
|
||||
"editor.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"editorLineNumber.foreground": "{{colors.outline.default.hex}}",
|
||||
"editorLineNumber.activeForeground": "{{colors.on_surface.default.hex}}",
|
||||
"editorCursor.foreground": "{{colors.primary.default.hex}}",
|
||||
"editor.selectionBackground": "{{colors.primary_container.default.hex}}",
|
||||
"editor.inactiveSelectionBackground": "{{colors.background.default.hex}}",
|
||||
"editor.lineHighlightBackground": "{{colors.background.default.hex}}",
|
||||
"editorIndentGuide.background": "{{colors.background.default.hex}}",
|
||||
"editorIndentGuide.activeBackground": "{{colors.outline.default.hex}}",
|
||||
"editorWhitespace.foreground": "{{colors.outline_variant.default.hex}}",
|
||||
"editorBracketMatch.background": "{{colors.background.default.hex}}",
|
||||
"editorBracketMatch.border": "{{colors.primary.default.hex}}",
|
||||
|
||||
"errorForeground": "{{colors.error.default.hex}}",
|
||||
"panel.border": "{{colors.outline_variant.default.hex}}",
|
||||
"panelTitle.activeBorder": "{{colors.primary.default.hex}}",
|
||||
"sideBar.border": "{{colors.outline_variant.default.hex}}",
|
||||
"editorGroup.border": "{{colors.outline_variant.default.hex}}",
|
||||
"tab.border": "{{colors.outline_variant.default.hex}}",
|
||||
"titleBar.border": "{{colors.outline_variant.default.hex}}",
|
||||
"focusBorder": "{{colors.primary.default.hex}}",
|
||||
"selection.background": "{{colors.primary_container.default.hex}}66",
|
||||
"titleBar.activeBackground": "{{colors.background.default.hex}}",
|
||||
"titleBar.activeForeground": "{{colors.on_surface.default.hex}}",
|
||||
"titleBar.inactiveForeground": "{{colors.outline.default.hex}}",
|
||||
"activityBar.background": "{{colors.background.default.hex}}",
|
||||
"activityBar.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"activityBar.inactiveForeground": "{{colors.outline.default.hex}}",
|
||||
"activityBar.activeBorder": "{{colors.primary.default.hex}}",
|
||||
"activityBar.activeBackground": "{{colors.background.default.hex}}",
|
||||
"activityBarBadge.background": "{{colors.primary.default.hex}}",
|
||||
"activityBarBadge.foreground": "{{colors.on_primary.default.hex}}",
|
||||
|
||||
"sideBar.background": "{{colors.background.default.hex}}",
|
||||
"sideBar.background": "{{colors.surface_container_low.default.hex}}",
|
||||
"sideBar.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"sideBar.border": "{{colors.background.default.hex}}",
|
||||
"statusBarItem.hoverBackground": "{{colors.surface_container_low.default.hex}}",
|
||||
"statusBarItem.activeBackground": "{{colors.surface_container.default.hex}}",
|
||||
"sideBarTitle.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"sideBarSectionHeader.background": "{{colors.background.default.hex}}",
|
||||
"panel.background": "{{colors.surface_container_low.default.hex}}",
|
||||
"panelTitle.activeForeground": "{{colors.on_surface.default.hex}}",
|
||||
"panelTitle.inactiveForeground": "{{colors.outline.default.hex}}",
|
||||
"sideBarSectionHeader.background": "{{colors.surface_container.default.hex}}",
|
||||
"sideBarSectionHeader.foreground": "{{colors.on_surface.default.hex}}",
|
||||
|
||||
"list.activeSelectionBackground": "{{colors.primary_container.default.hex}}",
|
||||
"list.activeSelectionForeground": "{{colors.on_primary_container.default.hex}}",
|
||||
"list.inactiveSelectionBackground": "{{colors.surface_container.default.hex}}",
|
||||
"list.inactiveSelectionForeground": "{{colors.on_surface.default.hex}}",
|
||||
"list.hoverBackground": "{{colors.surface_container.default.hex}}",
|
||||
"list.hoverForeground": "{{colors.on_surface.default.hex}}",
|
||||
"list.focusBackground": "{{colors.surface_container_high.default.hex}}",
|
||||
"list.focusForeground": "{{colors.on_surface.default.hex}}",
|
||||
"list.highlightForeground": "{{colors.primary.default.hex}}",
|
||||
|
||||
"statusBar.background": "{{colors.background.default.hex}}",
|
||||
"statusBar.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"statusBar.border": "{{colors.background.default.hex}}",
|
||||
"statusBar.noFolderBackground": "{{colors.background.default.hex}}",
|
||||
"statusBar.debuggingBackground": "{{colors.error.default.hex}}",
|
||||
"statusBar.debuggingForeground": "{{colors.on_error.default.hex}}",
|
||||
|
||||
"tab.activeBackground": "{{colors.background.default.hex}}",
|
||||
"editorGroupHeader.tabsBackground": "{{colors.background.default.hex}}",
|
||||
"tab.activeBackground": "{{colors.surface_container_low.default.hex}}",
|
||||
"tab.inactiveBackground": "{{colors.background.default.hex}}",
|
||||
"tab.activeForeground": "{{colors.on_surface.default.hex}}",
|
||||
"tab.inactiveForeground": "{{colors.outline.default.hex}}",
|
||||
"tab.border": "{{colors.background.default.hex}}",
|
||||
"tab.activeBorder": "{{colors.primary.default.hex}}",
|
||||
"tab.unfocusedActiveBorder": "{{colors.outline.default.hex}}",
|
||||
|
||||
"editorGroupHeader.tabsBackground": "{{colors.background.default.hex}}",
|
||||
"editorGroupHeader.noTabsBackground": "{{colors.background.default.hex}}",
|
||||
|
||||
"titleBar.activeBackground": "{{colors.background.default.hex}}",
|
||||
"titleBar.activeForeground": "{{colors.on_surface.default.hex}}",
|
||||
"titleBar.inactiveBackground": "{{colors.background.default.hex}}",
|
||||
"titleBar.inactiveForeground": "{{colors.outline.default.hex}}",
|
||||
"titleBar.border": "{{colors.background.default.hex}}",
|
||||
|
||||
"input.background": "{{colors.background.default.hex}}",
|
||||
"tab.activeBorderTop": "{{colors.primary.default.hex}}",
|
||||
"list.activeSelectionBackground": "{{colors.primary_container.default.hex}}",
|
||||
"list.activeSelectionForeground": "{{colors.on_primary_container.default.hex}}",
|
||||
"list.inactiveSelectionBackground": "{{colors.surface_container.default.hex}}",
|
||||
"list.hoverBackground": "{{colors.surface_container.default.hex}}",
|
||||
"list.hoverForeground": "{{colors.on_surface.default.hex}}",
|
||||
"list.focusForeground": "{{colors.on_surface.default.hex}}",
|
||||
"list.focusOutline": "{{colors.primary.default.hex}}",
|
||||
"list.focusBackground": "{{colors.surface_container_high.default.hex}}",
|
||||
"list.highlightForeground": "{{colors.primary.default.hex}}",
|
||||
"list.errorForeground": "{{colors.error.default.hex}}",
|
||||
"list.warningForeground": "{{colors.secondary.default.hex}}",
|
||||
"input.background": "{{colors.surface_container_low.default.hex}}",
|
||||
"input.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"input.border": "{{colors.outline.default.hex}}",
|
||||
"input.border": "{{colors.outline_variant.default.hex}}",
|
||||
"input.placeholderForeground": "{{colors.outline.default.hex}}",
|
||||
"inputOption.activeBorder": "{{colors.primary.default.hex}}",
|
||||
"inputValidation.errorBackground": "{{colors.error.default.hex}}",
|
||||
"inputValidation.errorBorder": "{{colors.error.default.hex}}",
|
||||
|
||||
"dropdown.background": "{{colors.background.default.hex}}",
|
||||
"dropdown.background": "{{colors.surface_container_low.default.hex}}",
|
||||
"dropdown.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"dropdown.border": "{{colors.outline.default.hex}}",
|
||||
|
||||
"quickInput.background": "{{colors.background.default.hex}}",
|
||||
"dropdown.border": "{{colors.outline_variant.default.hex}}",
|
||||
"quickInput.background": "{{colors.surface_container_low.default.hex}}",
|
||||
"quickInput.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"quickInputList.focusBackground": "{{colors.surface_container_high.default.hex}}",
|
||||
"quickInputList.focusForeground": "{{colors.on_surface.default.hex}}",
|
||||
|
||||
"widget.shadow": "{{colors.background.default.hex}}80",
|
||||
"button.background": "{{colors.primary.default.hex}}",
|
||||
"button.foreground": "{{colors.on_primary.default.hex}}",
|
||||
"button.hoverBackground": "{{colors.primary_container.default.hex}}",
|
||||
|
||||
"focusBorder": "{{colors.primary.default.hex}}",
|
||||
"badge.background": "{{colors.secondary.default.hex}}",
|
||||
"badge.foreground": "{{colors.on_secondary.default.hex}}",
|
||||
|
||||
"panel.background": "{{colors.background.default.hex}}",
|
||||
"panel.border": "{{colors.primary.default.hex}}",
|
||||
"panelTitle.activeBorder": "{{colors.primary.default.hex}}",
|
||||
"panelTitle.activeForeground": "{{colors.on_surface.default.hex}}",
|
||||
"panelTitle.inactiveForeground": "{{colors.outline.default.hex}}",
|
||||
|
||||
"terminal.background": "{{colors.background.default.hex}}",
|
||||
"terminal.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"terminal.ansiBlack": "{{dank16.color0.hex}}",
|
||||
"terminal.ansiRed": "{{dank16.color1.hex}}",
|
||||
"terminal.ansiGreen": "{{dank16.color2.hex}}",
|
||||
"terminal.ansiYellow": "{{dank16.color3.hex}}",
|
||||
"terminal.ansiBlue": "{{dank16.color4.hex}}",
|
||||
"terminal.ansiMagenta": "{{dank16.color5.hex}}",
|
||||
"terminal.ansiCyan": "{{dank16.color6.hex}}",
|
||||
"terminal.ansiWhite": "{{dank16.color7.hex}}",
|
||||
"terminal.ansiBrightBlack": "{{dank16.color8.hex}}",
|
||||
"terminal.ansiBrightRed": "{{dank16.color9.hex}}",
|
||||
"terminal.ansiBrightGreen": "{{dank16.color10.hex}}",
|
||||
"terminal.ansiBrightYellow": "{{dank16.color11.hex}}",
|
||||
"terminal.ansiBrightBlue": "{{dank16.color12.hex}}",
|
||||
"terminal.ansiBrightMagenta": "{{dank16.color13.hex}}",
|
||||
"terminal.ansiBrightCyan": "{{dank16.color14.hex}}",
|
||||
"terminal.ansiBrightWhite": "{{dank16.color15.hex}}",
|
||||
|
||||
"gitDecoration.modifiedResourceForeground": "{{colors.primary.default.hex}}",
|
||||
"gitDecoration.addedResourceForeground": "{{colors.primary.default.hex}}",
|
||||
"gitDecoration.stageModifiedResourceForeground": "{{colors.primary.default.hex}}",
|
||||
"gitDecoration.stageDeletedResourceForeground": "{{colors.error.default.hex}}",
|
||||
"gitDecoration.deletedResourceForeground": "{{colors.error.default.hex}}",
|
||||
"gitDecoration.untrackedResourceForeground": "{{colors.secondary.default.hex}}",
|
||||
"gitDecoration.ignoredResourceForeground": "{{colors.outline.default.hex}}",
|
||||
"gitDecoration.conflictingResourceForeground": "{{colors.error_container.default.hex}}",
|
||||
"gitDecoration.submoduleResourceForeground": "{{colors.primary.default.hex}}",
|
||||
|
||||
"editorWidget.background": "{{colors.background.default.hex}}",
|
||||
"editorWidget.border": "{{colors.outline.default.hex}}",
|
||||
"editorSuggestWidget.background": "{{colors.background.default.hex}}",
|
||||
"editorSuggestWidget.border": "{{colors.outline.default.hex}}",
|
||||
"editorSuggestWidget.selectedBackground": "{{colors.surface_container_high.default.hex}}",
|
||||
"editorSuggestWidget.highlightForeground": "{{colors.primary.default.hex}}",
|
||||
|
||||
"peekView.border": "{{colors.primary.default.hex}}",
|
||||
"peekViewEditor.background": "{{colors.background.default.hex}}",
|
||||
"peekViewResult.background": "{{colors.background.default.hex}}",
|
||||
"peekViewTitle.background": "{{colors.background.default.hex}}",
|
||||
|
||||
"notificationCenter.border": "{{colors.outline.default.hex}}",
|
||||
"notifications.background": "{{colors.background.default.hex}}",
|
||||
"notifications.border": "{{colors.outline.default.hex}}",
|
||||
|
||||
"statusBar.background": "{{colors.background.default.hex}}",
|
||||
"statusBar.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"statusBar.border": "{{colors.outline_variant.default.hex}}",
|
||||
"statusBar.noFolderBackground": "{{colors.background.default.hex}}",
|
||||
"statusBar.noFolderForeground": "{{colors.on_surface.default.hex}}",
|
||||
"statusBar.debuggingBackground": "{{colors.error.default.hex}}",
|
||||
"statusBar.debuggingForeground": "{{colors.on_error.default.hex}}",
|
||||
"notificationCenterHeader.background": "{{colors.surface_container_low.default.hex}}",
|
||||
"notificationCenterHeader.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"notificationCenter.border": "{{colors.outline_variant.default.hex}}",
|
||||
"notifications.background": "{{colors.surface_container_low.default.hex}}",
|
||||
"notifications.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"notifications.border": "{{colors.outline_variant.default.hex}}",
|
||||
"notificationsErrorIcon.foreground": "{{colors.error.default.hex}}",
|
||||
"notificationsWarningIcon.foreground": "{{colors.secondary.default.hex}}",
|
||||
"notificationsInfoIcon.foreground": "{{colors.primary.default.hex}}",
|
||||
"breadcrumb.background": "{{colors.surface_container.default.hex}}",
|
||||
"breadcrumb.foreground": "{{colors.outline.default.hex}}",
|
||||
"breadcrumb.focusForeground": "{{colors.on_surface.default.hex}}",
|
||||
"breadcrumb.activeSelectionForeground": "{{colors.primary.default.hex}}",
|
||||
|
||||
"editorLineNumber.foreground": "{{colors.outline.default.hex}}",
|
||||
"editorLineNumber.activeForeground": "{{colors.primary.default.hex}}",
|
||||
"editorCursor.foreground": "{{colors.primary.default.hex}}",
|
||||
"editor.lineHighlightBackground": "{{colors.surface_container.default.hex}}66",
|
||||
"editor.wordHighlightBackground": "{{colors.secondary.default.hex}}22",
|
||||
"editor.wordHighlightStrongBackground": "{{colors.tertiary.default.hex}}22",
|
||||
"editor.selectionBackground": "{{colors.primary_container.default.hex}}66",
|
||||
"editor.inactiveSelectionBackground": "{{colors.primary_container.default.hex}}33",
|
||||
"editorWhitespace.foreground": "{{colors.outline.default.hex}}66",
|
||||
"editorIndentGuide.background1": "{{colors.outline.default.hex}}33",
|
||||
"editorIndentGuide.activeBackground1": "{{colors.primary.default.hex}}99",
|
||||
"editorOverviewRuler.border": "{{colors.outline_variant.default.hex}}",
|
||||
"editorOverviewRuler.errorForeground": "{{colors.error.default.hex}}88",
|
||||
"editorOverviewRuler.warningForeground": "{{colors.tertiary.default.hex}}88",
|
||||
"editorOverviewRuler.infoForeground": "{{colors.primary.default.hex}}88",
|
||||
"editorStickyScroll.background": "{{colors.background.default.hex}}",
|
||||
"editorStickyScrollHover.background": "{{colors.surface_container_low.default.hex}}",
|
||||
"editorBracketHighlight.unexpectedBracket.foreground": "{{colors.outline.default.hex}}",
|
||||
"diffEditor.insertedTextBackground": "{{colors.secondary.default.hex}}20",
|
||||
"diffEditor.removedTextBackground": "{{colors.error.default.hex}}20",
|
||||
"gitDecoration.modifiedResourceForeground": "{{colors.primary.default.hex}}",
|
||||
"gitDecoration.addedResourceForeground": "{{colors.secondary.default.hex}}",
|
||||
"gitDecoration.deletedResourceForeground": "{{colors.error.default.hex}}",
|
||||
"gitDecoration.ignoredResourceForeground": "{{colors.outline.default.hex}}",
|
||||
"editorHoverWidget.background": "{{colors.surface_container_high.default.hex}}",
|
||||
"editorHoverWidget.border": "{{colors.outline.default.hex}}",
|
||||
"editorSuggestWidget.background": "{{colors.surface_container.default.hex}}",
|
||||
"editorSuggestWidget.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"editorSuggestWidget.selectedBackground": "{{colors.surface_container_high.default.hex}}",
|
||||
"editorSuggestWidget.highlightForeground": "{{colors.primary.default.hex}}",
|
||||
"scrollbarSlider.background": "{{colors.outline.default.hex}}40",
|
||||
"scrollbarSlider.hoverBackground": "{{colors.outline.default.hex}}60",
|
||||
"scrollbarSlider.activeBackground": "{{colors.outline.default.hex}}80",
|
||||
|
||||
"editorError.foreground": "{{colors.error.default.hex}}",
|
||||
"editorWarning.foreground": "{{colors.tertiary.default.hex}}",
|
||||
"editorInfo.foreground": "{{colors.primary.default.hex}}",
|
||||
|
||||
"editorGutter.addedBackground": "{{colors.secondary.default.hex}}",
|
||||
"editorGutter.modifiedBackground": "{{colors.tertiary.default.hex}}",
|
||||
"editorGutter.deletedBackground": "{{colors.error.default.hex}}",
|
||||
|
||||
"diffEditor.insertedTextBackground": "{{colors.secondary.default.hex}}20",
|
||||
"diffEditor.removedTextBackground": "{{colors.error.default.hex}}20",
|
||||
|
||||
"merge.currentHeaderBackground": "{{colors.primary.default.hex}}40",
|
||||
"merge.incomingHeaderBackground": "{{colors.secondary.default.hex}}40",
|
||||
|
||||
"menubar.selectionBackground": "{{colors.surface_container.default.hex}}",
|
||||
"menu.background": "{{colors.background.default.hex}}",
|
||||
"menu.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"menu.selectionBackground": "{{colors.surface_container_high.default.hex}}",
|
||||
"menu.selectionForeground": "{{colors.on_surface.default.hex}}",
|
||||
|
||||
"debugToolBar.background": "{{colors.background.default.hex}}",
|
||||
"debugExceptionWidget.background": "{{colors.background.default.hex}}",
|
||||
"debugExceptionWidget.border": "{{colors.error.default.hex}}"
|
||||
"terminal.background": "{{colors.background.default.hex}}",
|
||||
"terminal.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"terminal.ansiBlack": "{{dank16.color0.default.hex}}",
|
||||
"terminal.ansiRed": "{{dank16.color1.default.hex}}",
|
||||
"terminal.ansiGreen": "{{dank16.color2.default.hex}}",
|
||||
"terminal.ansiYellow": "{{dank16.color3.default.hex}}",
|
||||
"terminal.ansiBlue": "{{dank16.color4.default.hex}}",
|
||||
"terminal.ansiMagenta": "{{dank16.color5.default.hex}}",
|
||||
"terminal.ansiCyan": "{{dank16.color6.default.hex}}",
|
||||
"terminal.ansiWhite": "{{dank16.color7.default.hex}}",
|
||||
"terminal.ansiBrightBlack": "{{dank16.color8.default.hex}}",
|
||||
"terminal.ansiBrightRed": "{{dank16.color9.default.hex}}",
|
||||
"terminal.ansiBrightGreen": "{{dank16.color10.default.hex}}",
|
||||
"terminal.ansiBrightYellow": "{{dank16.color11.default.hex}}",
|
||||
"terminal.ansiBrightBlue": "{{dank16.color12.default.hex}}",
|
||||
"terminal.ansiBrightMagenta": "{{dank16.color13.default.hex}}",
|
||||
"terminal.ansiBrightCyan": "{{dank16.color14.default.hex}}",
|
||||
"terminal.ansiBrightWhite": "{{dank16.color15.default.hex}}"
|
||||
},
|
||||
|
||||
"tokenColors": [
|
||||
{
|
||||
"scope": ["variable", "meta.object-literal.key"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.on_surface.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["string", "constant.other.symbol"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["constant.numeric", "constant.language", "constant.character"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.tertiary.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.type", "support.type", "entity.name.class"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.tertiary.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.function", "support.function"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.primary.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["support.class", "support.variable", "variable.language"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["invalid"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.error.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["invalid.deprecated"],
|
||||
"scope": [
|
||||
"comment"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.outline.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.heading"],
|
||||
"scope": [
|
||||
"keyword"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.primary.default.hex}}",
|
||||
"fontStyle": "bold"
|
||||
"foreground": "{{dank16.color5.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.bold"],
|
||||
"scope": [
|
||||
"string"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.tertiary.default.hex}}",
|
||||
"fontStyle": "bold"
|
||||
"foreground": "{{dank16.color2.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.italic"],
|
||||
"scope": [
|
||||
"constant",
|
||||
"number"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.primary.default.hex}}",
|
||||
"fontStyle": "italic"
|
||||
"foreground": "{{dank16.color12.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.underline"],
|
||||
"settings": {
|
||||
"fontStyle": "underline"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.quote"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.list"],
|
||||
"scope": [
|
||||
"variable"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.on_surface.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.raw", "markup.inline.raw"],
|
||||
"scope": [
|
||||
"entity.name.function"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color4.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": [
|
||||
"entity.name.class",
|
||||
"support.type"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["comment", "punctuation.definition.comment"],
|
||||
"scope": [
|
||||
"invalid"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color8.hex}}"
|
||||
"foreground": "{{colors.error.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword",
|
||||
"scope": [
|
||||
"markup.heading"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color5.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage.type",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color13.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage.modifier",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color5.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "variable",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "variable.parameter",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color7.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["meta.object-literal.key", "meta.property.object", "variable.other.property"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color4.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.other.symbol",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["constant.numeric", "constant.language"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.character",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color3.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.type", "entity.name.class"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "support.type",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color13.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.function", "support.function"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color2.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["support.class", "support.variable"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "variable.language",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "entity.name.tag.yaml",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["string.unquoted.plain.out.yaml", "string.unquoted.yaml"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color3.hex}}"
|
||||
"foreground": "{{colors.primary.default.hex}}",
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
"semanticHighlighting": true,
|
||||
"semanticTokenColors": {
|
||||
"variable": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
},
|
||||
"variable.readonly": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"property": {
|
||||
"foreground": "{{dank16.color4.hex}}"
|
||||
},
|
||||
"function": {
|
||||
"foreground": "{{dank16.color2.hex}}"
|
||||
},
|
||||
"method": {
|
||||
"foreground": "{{dank16.color2.hex}}"
|
||||
},
|
||||
"type": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"class": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"typeParameter": {
|
||||
"foreground": "{{dank16.color13.hex}}"
|
||||
},
|
||||
"enumMember": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"string": {
|
||||
"foreground": "{{dank16.color3.hex}}"
|
||||
},
|
||||
"number": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"comment": {
|
||||
"foreground": "{{dank16.color8.hex}}"
|
||||
},
|
||||
"keyword": {
|
||||
"foreground": "{{dank16.color5.hex}}"
|
||||
},
|
||||
"operator": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
"foreground": "{{colors.on_surface.default.hex}}"
|
||||
},
|
||||
"parameter": {
|
||||
"foreground": "{{dank16.color7.hex}}"
|
||||
"foreground": "{{colors.on_surface.default.hex}}"
|
||||
},
|
||||
"namespace": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
"property": {
|
||||
"foreground": "{{dank16.color4.default.hex}}"
|
||||
},
|
||||
"function": {
|
||||
"foreground": "{{dank16.color4.default.hex}}"
|
||||
},
|
||||
"method": {
|
||||
"foreground": "{{dank16.color4.default.hex}}"
|
||||
},
|
||||
"type": {
|
||||
"foreground": "{{colors.secondary.default.hex}}"
|
||||
},
|
||||
"class": {
|
||||
"foreground": "{{colors.secondary.default.hex}}"
|
||||
},
|
||||
"string": {
|
||||
"foreground": "{{dank16.color2.default.hex}}"
|
||||
},
|
||||
"number": {
|
||||
"foreground": "{{dank16.color12.default.hex}}"
|
||||
},
|
||||
"keyword": {
|
||||
"foreground": "{{dank16.color5.default.hex}}"
|
||||
},
|
||||
"comment": {
|
||||
"foreground": "{{colors.outline.default.hex}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,74 @@
|
||||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "Dynamic Base16 DankShell",
|
||||
"name": "Dynamic Base16 DankShell Light",
|
||||
"semanticHighlighting": true,
|
||||
"colors": {
|
||||
"foreground": "{{colors.on_surface.light.hex}}",
|
||||
"selection.background": "{{colors.primary_container.light.hex}}66",
|
||||
"errorForeground": "{{colors.error.light.hex}}",
|
||||
"focusBorder": "{{colors.primary.light.hex}}",
|
||||
"editor.background": "{{colors.background.light.hex}}",
|
||||
"editor.foreground": "{{colors.on_surface.light.hex}}",
|
||||
"editorLineNumber.foreground": "{{colors.outline.light.hex}}",
|
||||
"editorLineNumber.activeForeground": "{{colors.on_surface.light.hex}}",
|
||||
"editorLineNumber.activeForeground": "{{colors.primary.light.hex}}",
|
||||
"editorCursor.foreground": "{{colors.primary.light.hex}}",
|
||||
"editor.selectionBackground": "{{colors.primary_container.light.hex}}",
|
||||
"editor.inactiveSelectionBackground": "{{colors.background.light.hex}}",
|
||||
"editor.lineHighlightBackground": "{{colors.background.light.hex}}",
|
||||
"editorIndentGuide.background": "{{colors.background.light.hex}}",
|
||||
"editorIndentGuide.activeBackground": "{{colors.outline.light.hex}}",
|
||||
"editorWhitespace.foreground": "{{colors.outline_variant.light.hex}}",
|
||||
"editorBracketMatch.background": "{{colors.background.light.hex}}",
|
||||
"editor.selectionBackground": "{{colors.primary_container.light.hex}}B3",
|
||||
"editor.inactiveSelectionBackground": "{{colors.primary_container.light.hex}}33",
|
||||
"editor.lineHighlightBackground": "{{colors.surface_container.light.hex}}66",
|
||||
"editor.lineHighlightBorder": "{{colors.outline_variant.light.hex}}18",
|
||||
"editor.wordHighlightBackground": "{{colors.secondary.light.hex}}22",
|
||||
"editor.wordHighlightStrongBackground": "{{colors.tertiary.light.hex}}22",
|
||||
"editor.findMatchBackground": "{{colors.secondary.light.hex}}33",
|
||||
"editor.findMatchHighlightBackground": "{{colors.secondary.light.hex}}22",
|
||||
"editor.findRangeHighlightBackground": "{{colors.surface_container.light.hex}}33",
|
||||
"editorWhitespace.foreground": "{{colors.outline.light.hex}}66",
|
||||
"editorIndentGuide.background1": "{{colors.outline.light.hex}}99",
|
||||
"editorIndentGuide.activeBackground1": "{{colors.primary.light.hex}}CC",
|
||||
"editorBracketMatch.background": "{{colors.primary_container.light.hex}}33",
|
||||
"editorBracketMatch.border": "{{colors.primary.light.hex}}",
|
||||
|
||||
"editorGutter.addedBackground": "{{colors.secondary.light.hex}}AA",
|
||||
"editorGutter.modifiedBackground": "{{colors.tertiary.light.hex}}AA",
|
||||
"editorGutter.deletedBackground": "{{colors.error.light.hex}}AA",
|
||||
"editorError.foreground": "{{colors.error.light.hex}}",
|
||||
"editorWarning.foreground": "{{colors.tertiary.light.hex}}",
|
||||
"editorInfo.foreground": "{{colors.primary.light.hex}}",
|
||||
"editorOverviewRuler.border": "{{colors.outline_variant.light.hex}}",
|
||||
"editorOverviewRuler.errorForeground": "{{colors.error.light.hex}}88",
|
||||
"editorOverviewRuler.warningForeground": "{{colors.tertiary.light.hex}}88",
|
||||
"editorOverviewRuler.infoForeground": "{{colors.primary.light.hex}}88",
|
||||
"editorWidget.background": "{{colors.surface_container.light.hex}}",
|
||||
"editorWidget.border": "{{colors.outline_variant.light.hex}}",
|
||||
"editorHoverWidget.background": "{{colors.surface_container_high.light.hex}}",
|
||||
"editorHoverWidget.border": "{{colors.outline.light.hex}}",
|
||||
"editorSuggestWidget.background": "{{colors.surface_container.light.hex}}",
|
||||
"editorSuggestWidget.foreground": "{{colors.on_surface.light.hex}}",
|
||||
"editorSuggestWidget.border": "{{colors.outline_variant.light.hex}}",
|
||||
"editorSuggestWidget.selectedBackground": "{{colors.surface_container_high.light.hex}}",
|
||||
"editorSuggestWidget.highlightForeground": "{{colors.primary.light.hex}}",
|
||||
"editorGroup.border": "{{colors.outline_variant.light.hex}}",
|
||||
"editorGroup.dropBackground": "{{colors.primary_container.light.hex}}33",
|
||||
"editorGroupHeader.tabsBackground": "{{colors.background.light.hex}}",
|
||||
"editorGroupHeader.noTabsBackground": "{{colors.background.light.hex}}",
|
||||
"tab.border": "{{colors.outline_variant.light.hex}}",
|
||||
"tab.activeBackground": "{{colors.surface_container_high.light.hex}}",
|
||||
"tab.inactiveBackground": "{{colors.surface_container.light.hex}}",
|
||||
"tab.activeForeground": "{{colors.on_surface.light.hex}}",
|
||||
"tab.inactiveForeground": "{{colors.outline.light.hex}}",
|
||||
"tab.activeBorder": "{{colors.primary.light.hex}}",
|
||||
"tab.unfocusedActiveBorder": "{{colors.outline.light.hex}}",
|
||||
"activityBar.background": "{{colors.background.light.hex}}",
|
||||
"activityBar.foreground": "{{colors.on_surface.light.hex}}",
|
||||
"activityBar.inactiveForeground": "{{colors.outline.light.hex}}",
|
||||
"activityBar.activeBorder": "{{colors.primary.light.hex}}",
|
||||
"activityBar.activeBackground": "{{colors.background.light.hex}}",
|
||||
"activityBarBadge.background": "{{colors.primary.light.hex}}",
|
||||
"activityBarBadge.foreground": "{{colors.on_primary.light.hex}}",
|
||||
|
||||
"sideBar.background": "{{colors.background.light.hex}}",
|
||||
"sideBar.background": "{{colors.surface_container.light.hex}}",
|
||||
"sideBar.foreground": "{{colors.on_surface.light.hex}}",
|
||||
"sideBar.border": "{{colors.background.light.hex}}",
|
||||
"sideBar.border": "{{colors.outline_variant.light.hex}}",
|
||||
"sideBarTitle.foreground": "{{colors.on_surface.light.hex}}",
|
||||
"sideBarSectionHeader.background": "{{colors.background.light.hex}}",
|
||||
"sideBarSectionHeader.background": "{{colors.surface_container_low.light.hex}}",
|
||||
"sideBarSectionHeader.foreground": "{{colors.on_surface.light.hex}}",
|
||||
|
||||
"list.activeSelectionBackground": "{{colors.primary_container.light.hex}}",
|
||||
"list.activeSelectionForeground": "{{colors.on_primary_container.light.hex}}",
|
||||
"list.inactiveSelectionBackground": "{{colors.surface_container.light.hex}}",
|
||||
@@ -39,83 +78,64 @@
|
||||
"list.focusBackground": "{{colors.surface_container_high.light.hex}}",
|
||||
"list.focusForeground": "{{colors.on_surface.light.hex}}",
|
||||
"list.highlightForeground": "{{colors.primary.light.hex}}",
|
||||
|
||||
"statusBar.background": "{{colors.background.light.hex}}",
|
||||
"list.errorForeground": "{{colors.error.light.hex}}",
|
||||
"list.warningForeground": "{{colors.tertiary.light.hex}}",
|
||||
"statusBar.background": "{{colors.surface_container.light.hex}}",
|
||||
"statusBar.foreground": "{{colors.on_surface.light.hex}}",
|
||||
"statusBar.border": "{{colors.background.light.hex}}",
|
||||
"statusBar.noFolderBackground": "{{colors.background.light.hex}}",
|
||||
"statusBar.border": "{{colors.outline_variant.light.hex}}",
|
||||
"statusBar.noFolderBackground": "{{colors.surface_container.light.hex}}",
|
||||
"statusBar.noFolderForeground": "{{colors.on_surface.light.hex}}",
|
||||
"statusBar.debuggingBackground": "{{colors.error.light.hex}}",
|
||||
"statusBar.debuggingForeground": "{{colors.on_error.light.hex}}",
|
||||
|
||||
"tab.activeBackground": "{{colors.background.light.hex}}",
|
||||
"tab.inactiveBackground": "{{colors.background.light.hex}}",
|
||||
"tab.activeForeground": "{{colors.on_surface.light.hex}}",
|
||||
"tab.inactiveForeground": "{{colors.outline.light.hex}}",
|
||||
"tab.border": "{{colors.background.light.hex}}",
|
||||
"tab.activeBorder": "{{colors.primary.light.hex}}",
|
||||
"tab.unfocusedActiveBorder": "{{colors.outline.light.hex}}",
|
||||
|
||||
"editorGroupHeader.tabsBackground": "{{colors.background.light.hex}}",
|
||||
"editorGroupHeader.noTabsBackground": "{{colors.background.light.hex}}",
|
||||
|
||||
"titleBar.activeBackground": "{{colors.background.light.hex}}",
|
||||
"titleBar.activeForeground": "{{colors.on_surface.light.hex}}",
|
||||
"titleBar.inactiveBackground": "{{colors.background.light.hex}}",
|
||||
"titleBar.inactiveForeground": "{{colors.outline.light.hex}}",
|
||||
"titleBar.border": "{{colors.background.light.hex}}",
|
||||
|
||||
"input.background": "{{colors.background.light.hex}}",
|
||||
"titleBar.border": "{{colors.outline_variant.light.hex}}",
|
||||
"input.background": "{{colors.surface_container_low.light.hex}}",
|
||||
"input.foreground": "{{colors.on_surface.light.hex}}",
|
||||
"input.border": "{{colors.outline.light.hex}}",
|
||||
"input.border": "{{colors.outline_variant.light.hex}}",
|
||||
"input.placeholderForeground": "{{colors.outline.light.hex}}",
|
||||
"inputOption.activeBorder": "{{colors.primary.light.hex}}",
|
||||
"inputValidation.errorBackground": "{{colors.error.light.hex}}",
|
||||
"inputValidation.errorBackground": "{{colors.error_container.light.hex}}",
|
||||
"inputValidation.errorBorder": "{{colors.error.light.hex}}",
|
||||
|
||||
"dropdown.background": "{{colors.background.light.hex}}",
|
||||
"dropdown.background": "{{colors.surface_container_low.light.hex}}",
|
||||
"dropdown.foreground": "{{colors.on_surface.light.hex}}",
|
||||
"dropdown.border": "{{colors.outline.light.hex}}",
|
||||
|
||||
"quickInput.background": "{{colors.background.light.hex}}",
|
||||
"dropdown.border": "{{colors.outline_variant.light.hex}}",
|
||||
"quickInput.background": "{{colors.surface_container.light.hex}}",
|
||||
"quickInput.foreground": "{{colors.on_surface.light.hex}}",
|
||||
"quickInputList.focusBackground": "{{colors.surface_container_high.light.hex}}",
|
||||
"quickInputList.focusForeground": "{{colors.on_surface.light.hex}}",
|
||||
|
||||
"button.background": "{{colors.primary.light.hex}}",
|
||||
"button.foreground": "{{colors.on_primary.light.hex}}",
|
||||
"button.hoverBackground": "{{colors.primary_container.light.hex}}",
|
||||
|
||||
"focusBorder": "{{colors.primary.light.hex}}",
|
||||
"badge.background": "{{colors.secondary.light.hex}}",
|
||||
"badge.foreground": "{{colors.on_secondary.light.hex}}",
|
||||
|
||||
"panel.background": "{{colors.background.light.hex}}",
|
||||
"panel.border": "{{colors.primary.light.hex}}",
|
||||
"panel.background": "{{colors.surface_container.light.hex}}",
|
||||
"panel.border": "{{colors.outline_variant.light.hex}}",
|
||||
"panelTitle.activeBorder": "{{colors.primary.light.hex}}",
|
||||
"panelTitle.activeForeground": "{{colors.on_surface.light.hex}}",
|
||||
"panelTitle.inactiveForeground": "{{colors.outline.light.hex}}",
|
||||
|
||||
"terminal.background": "{{colors.background.light.hex}}",
|
||||
"terminal.foreground": "{{colors.on_surface.light.hex}}",
|
||||
"terminal.ansiBlack": "{{dank16.color0.hex}}",
|
||||
"terminal.ansiRed": "{{dank16.color1.hex}}",
|
||||
"terminal.ansiGreen": "{{dank16.color2.hex}}",
|
||||
"terminal.ansiYellow": "{{dank16.color3.hex}}",
|
||||
"terminal.ansiBlue": "{{dank16.color4.hex}}",
|
||||
"terminal.ansiMagenta": "{{dank16.color5.hex}}",
|
||||
"terminal.ansiCyan": "{{dank16.color6.hex}}",
|
||||
"terminal.ansiWhite": "{{dank16.color7.hex}}",
|
||||
"terminal.ansiBrightBlack": "{{dank16.color8.hex}}",
|
||||
"terminal.ansiBrightRed": "{{dank16.color9.hex}}",
|
||||
"terminal.ansiBrightGreen": "{{dank16.color10.hex}}",
|
||||
"terminal.ansiBrightYellow": "{{dank16.color11.hex}}",
|
||||
"terminal.ansiBrightBlue": "{{dank16.color12.hex}}",
|
||||
"terminal.ansiBrightMagenta": "{{dank16.color13.hex}}",
|
||||
"terminal.ansiBrightCyan": "{{dank16.color14.hex}}",
|
||||
"terminal.ansiBrightWhite": "{{dank16.color15.hex}}",
|
||||
|
||||
"terminal.ansiBlack": "{{dank16.color0.light.hex}}",
|
||||
"terminal.ansiRed": "{{dank16.color1.light.hex}}",
|
||||
"terminal.ansiGreen": "{{dank16.color2.light.hex}}",
|
||||
"terminal.ansiYellow": "{{dank16.color3.light.hex}}",
|
||||
"terminal.ansiBlue": "{{dank16.color4.light.hex}}",
|
||||
"terminal.ansiMagenta": "{{dank16.color5.light.hex}}",
|
||||
"terminal.ansiCyan": "{{dank16.color6.light.hex}}",
|
||||
"terminal.ansiWhite": "{{dank16.color7.light.hex}}",
|
||||
"terminal.ansiBrightBlack": "{{dank16.color8.light.hex}}",
|
||||
"terminal.ansiBrightRed": "{{dank16.color9.light.hex}}",
|
||||
"terminal.ansiBrightGreen": "{{dank16.color10.light.hex}}",
|
||||
"terminal.ansiBrightYellow": "{{dank16.color11.light.hex}}",
|
||||
"terminal.ansiBrightBlue": "{{dank16.color12.light.hex}}",
|
||||
"terminal.ansiBrightMagenta": "{{dank16.color13.light.hex}}",
|
||||
"terminal.ansiBrightCyan": "{{dank16.color14.light.hex}}",
|
||||
"terminal.ansiBrightWhite": "{{dank16.color15.light.hex}}",
|
||||
"gitDecoration.modifiedResourceForeground": "{{colors.primary.light.hex}}",
|
||||
"gitDecoration.addedResourceForeground": "{{colors.primary.light.hex}}",
|
||||
"gitDecoration.addedResourceForeground": "{{colors.secondary.light.hex}}",
|
||||
"gitDecoration.stageModifiedResourceForeground": "{{colors.primary.light.hex}}",
|
||||
"gitDecoration.stageDeletedResourceForeground": "{{colors.error.light.hex}}",
|
||||
"gitDecoration.deletedResourceForeground": "{{colors.error.light.hex}}",
|
||||
@@ -123,309 +143,276 @@
|
||||
"gitDecoration.ignoredResourceForeground": "{{colors.outline.light.hex}}",
|
||||
"gitDecoration.conflictingResourceForeground": "{{colors.error_container.light.hex}}",
|
||||
"gitDecoration.submoduleResourceForeground": "{{colors.primary.light.hex}}",
|
||||
|
||||
"editorWidget.background": "{{colors.background.light.hex}}",
|
||||
"editorWidget.border": "{{colors.outline.light.hex}}",
|
||||
"editorSuggestWidget.background": "{{colors.background.light.hex}}",
|
||||
"editorSuggestWidget.border": "{{colors.outline.light.hex}}",
|
||||
"editorSuggestWidget.selectedBackground": "{{colors.surface_container_high.light.hex}}",
|
||||
"editorSuggestWidget.highlightForeground": "{{colors.primary.light.hex}}",
|
||||
|
||||
"peekView.border": "{{colors.primary.light.hex}}",
|
||||
"peekViewEditor.background": "{{colors.background.light.hex}}",
|
||||
"peekViewResult.background": "{{colors.background.light.hex}}",
|
||||
"peekViewTitle.background": "{{colors.background.light.hex}}",
|
||||
|
||||
"notificationCenter.border": "{{colors.outline.light.hex}}",
|
||||
"notifications.background": "{{colors.background.light.hex}}",
|
||||
"notifications.border": "{{colors.outline.light.hex}}",
|
||||
|
||||
"peekViewEditor.background": "{{colors.surface_container_high.light.hex}}",
|
||||
"peekViewResult.background": "{{colors.surface_container.light.hex}}",
|
||||
"peekViewTitle.background": "{{colors.surface_container_low.light.hex}}",
|
||||
"notificationCenter.border": "{{colors.outline_variant.light.hex}}",
|
||||
"notifications.background": "{{colors.surface_container.light.hex}}",
|
||||
"notifications.border": "{{colors.outline_variant.light.hex}}",
|
||||
"breadcrumb.background": "{{colors.surface_container_high.light.hex}}",
|
||||
"breadcrumb.foreground": "{{colors.outline.light.hex}}",
|
||||
"breadcrumb.focusForeground": "{{colors.on_surface.light.hex}}",
|
||||
"breadcrumb.activeSelectionForeground": "{{colors.primary.light.hex}}",
|
||||
|
||||
"scrollbarSlider.background": "{{colors.outline.light.hex}}40",
|
||||
"scrollbarSlider.hoverBackground": "{{colors.outline.light.hex}}60",
|
||||
"scrollbarSlider.activeBackground": "{{colors.outline.light.hex}}80",
|
||||
|
||||
"editorError.foreground": "{{colors.error.light.hex}}",
|
||||
"editorWarning.foreground": "{{colors.tertiary.light.hex}}",
|
||||
"editorInfo.foreground": "{{colors.primary.light.hex}}",
|
||||
|
||||
"editorGutter.addedBackground": "{{colors.secondary.light.hex}}",
|
||||
"editorGutter.modifiedBackground": "{{colors.tertiary.light.hex}}",
|
||||
"editorGutter.deletedBackground": "{{colors.error.light.hex}}",
|
||||
|
||||
"diffEditor.insertedTextBackground": "{{colors.secondary.light.hex}}20",
|
||||
"diffEditor.removedTextBackground": "{{colors.error.light.hex}}20",
|
||||
|
||||
"merge.currentHeaderBackground": "{{colors.primary.light.hex}}40",
|
||||
"merge.incomingHeaderBackground": "{{colors.secondary.light.hex}}40",
|
||||
|
||||
"menubar.selectionBackground": "{{colors.surface_container.light.hex}}",
|
||||
"menu.background": "{{colors.background.light.hex}}",
|
||||
"menubar.selectionBackground": "{{colors.primary_container.light.hex}}",
|
||||
"menubar.selectionForeground": "{{colors.on_primary_container.light.hex}}",
|
||||
"menu.background": "{{colors.surface_container.light.hex}}",
|
||||
"menu.foreground": "{{colors.on_surface.light.hex}}",
|
||||
"menu.selectionBackground": "{{colors.surface_container_high.light.hex}}",
|
||||
"menu.selectionForeground": "{{colors.on_surface.light.hex}}",
|
||||
|
||||
"debugToolBar.background": "{{colors.background.light.hex}}",
|
||||
"debugExceptionWidget.background": "{{colors.background.light.hex}}",
|
||||
"menu.selectionBackground": "{{colors.primary_container.light.hex}}",
|
||||
"menu.selectionForeground": "{{colors.on_primary_container.light.hex}}",
|
||||
"debugToolBar.background": "{{colors.surface_container.light.hex}}",
|
||||
"debugExceptionWidget.background": "{{colors.surface_container.light.hex}}",
|
||||
"debugExceptionWidget.border": "{{colors.error.light.hex}}"
|
||||
},
|
||||
|
||||
"tokenColors": [
|
||||
{
|
||||
"scope": ["variable", "meta.object-literal.key"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.on_surface.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["string", "constant.other.symbol"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["constant.numeric", "constant.language", "constant.character"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.tertiary.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.type", "support.type", "entity.name.class"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.tertiary.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.function", "support.function"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.primary.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["support.class", "support.variable", "variable.language"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["invalid"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.error.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["invalid.deprecated"],
|
||||
"name": "Comments",
|
||||
"scope": [
|
||||
"comment",
|
||||
"punctuation.definition.comment",
|
||||
"string.comment"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.outline.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.heading"],
|
||||
"name": "Keywords and storage",
|
||||
"scope": [
|
||||
"keyword",
|
||||
"punctuation.definition.keyword",
|
||||
"storage",
|
||||
"storage.type"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color5.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Strings",
|
||||
"scope": [
|
||||
"string",
|
||||
"string punctuation.section.embedded source"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color2.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Constants and numbers",
|
||||
"scope": [
|
||||
"constant.numeric",
|
||||
"constant.language",
|
||||
"constant.other",
|
||||
"constant.character"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color0.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Variables (plain)",
|
||||
"scope": [
|
||||
"variable",
|
||||
"variable.other"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.on_surface.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Parameters",
|
||||
"scope": [
|
||||
"variable.parameter",
|
||||
"variable.parameter.function"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.on_surface.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Object properties and keys",
|
||||
"scope": [
|
||||
"meta.object-literal.key",
|
||||
"meta.property.object",
|
||||
"variable.other.property",
|
||||
"entity.name.tag.yaml"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color4.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Functions",
|
||||
"scope": [
|
||||
"entity.name.function",
|
||||
"support.function"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color4.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Types and classes",
|
||||
"scope": [
|
||||
"entity.name.type",
|
||||
"entity.name.class",
|
||||
"support.type"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Language builtins and special variables",
|
||||
"scope": [
|
||||
"support.class",
|
||||
"support.variable",
|
||||
"variable.language",
|
||||
"support.constant"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color4.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Invalid",
|
||||
"scope": [
|
||||
"invalid"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.error.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Invalid deprecated",
|
||||
"scope": [
|
||||
"invalid.deprecated"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.outline.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Headings",
|
||||
"scope": [
|
||||
"markup.heading",
|
||||
"markup.heading entity.name"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.primary.light.hex}}",
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.bold"],
|
||||
"name": "Bold",
|
||||
"scope": [
|
||||
"markup.bold"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.tertiary.light.hex}}",
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.italic"],
|
||||
"name": "Italic",
|
||||
"scope": [
|
||||
"markup.italic"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.primary.light.hex}}",
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.underline"],
|
||||
"name": "Underline",
|
||||
"scope": [
|
||||
"markup.underline"
|
||||
],
|
||||
"settings": {
|
||||
"fontStyle": "underline"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.quote"],
|
||||
"name": "Quotes",
|
||||
"scope": [
|
||||
"markup.quote"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.light.hex}}"
|
||||
"foreground": "{{colors.outline.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.list"],
|
||||
"name": "Lists",
|
||||
"scope": [
|
||||
"markup.list"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.on_surface.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.raw", "markup.inline.raw"],
|
||||
"name": "Inline code in prose",
|
||||
"scope": [
|
||||
"markup.raw",
|
||||
"markup.inline.raw"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.light.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["comment", "punctuation.definition.comment"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color8.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "keyword",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color5.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage.type",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color13.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "storage.modifier",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color5.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "variable",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "variable.parameter",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color7.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["meta.object-literal.key", "meta.property.object", "variable.other.property"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color4.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.other.symbol",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["constant.numeric", "constant.language"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "constant.character",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color3.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.type", "entity.name.class"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "support.type",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color13.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.function", "support.function"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color2.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["support.class", "support.variable"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "variable.language",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "entity.name.tag.yaml",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["string.unquoted.plain.out.yaml", "string.unquoted.yaml"],
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "string",
|
||||
"settings": {
|
||||
"foreground": "{{dank16.color3.hex}}"
|
||||
"foreground": "{{dank16.color4.light.hex}}"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
"semanticHighlighting": true,
|
||||
"semanticTokenColors": {
|
||||
"variable": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
"foreground": "{{colors.on_surface.light.hex}}"
|
||||
},
|
||||
"variable.readonly": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"property": {
|
||||
"foreground": "{{dank16.color4.hex}}"
|
||||
},
|
||||
"function": {
|
||||
"foreground": "{{dank16.color2.hex}}"
|
||||
},
|
||||
"method": {
|
||||
"foreground": "{{dank16.color2.hex}}"
|
||||
},
|
||||
"type": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"class": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"typeParameter": {
|
||||
"foreground": "{{dank16.color13.hex}}"
|
||||
},
|
||||
"enumMember": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"string": {
|
||||
"foreground": "{{dank16.color3.hex}}"
|
||||
},
|
||||
"number": {
|
||||
"foreground": "{{dank16.color12.hex}}"
|
||||
},
|
||||
"comment": {
|
||||
"foreground": "{{dank16.color8.hex}}"
|
||||
},
|
||||
"keyword": {
|
||||
"foreground": "{{dank16.color5.hex}}"
|
||||
},
|
||||
"operator": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
"foreground": "{{dank16.color1.light.hex}}"
|
||||
},
|
||||
"parameter": {
|
||||
"foreground": "{{dank16.color7.hex}}"
|
||||
"foreground": "{{colors.on_surface.light.hex}}"
|
||||
},
|
||||
"property": {
|
||||
"foreground": "{{dank16.color4.light.hex}}"
|
||||
},
|
||||
"function": {
|
||||
"foreground": "{{dank16.color4.light.hex}}"
|
||||
},
|
||||
"method": {
|
||||
"foreground": "{{dank16.color4.light.hex}}"
|
||||
},
|
||||
"type": {
|
||||
"foreground": "{{colors.secondary.light.hex}}"
|
||||
},
|
||||
"class": {
|
||||
"foreground": "{{colors.secondary.light.hex}}"
|
||||
},
|
||||
"typeParameter": {
|
||||
"foreground": "{{colors.tertiary.light.hex}}"
|
||||
},
|
||||
"enumMember": {
|
||||
"foreground": "{{dank16.color1.light.hex}}"
|
||||
},
|
||||
"string": {
|
||||
"foreground": "{{dank16.color2.light.hex}}"
|
||||
},
|
||||
"number": {
|
||||
"foreground": "{{dank16.color1.light.hex}}"
|
||||
},
|
||||
"comment": {
|
||||
"foreground": "{{colors.outline.light.hex}}"
|
||||
},
|
||||
"keyword": {
|
||||
"foreground": "{{dank16.color5.light.hex}}"
|
||||
},
|
||||
"operator": {
|
||||
"foreground": "{{colors.on_surface.light.hex}}"
|
||||
},
|
||||
"namespace": {
|
||||
"foreground": "{{dank16.color15.hex}}"
|
||||
"foreground": "{{colors.on_surface.light.hex}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,315 +0,0 @@
|
||||
{
|
||||
"$schema": "vscode://schemas/color-theme",
|
||||
"name": "Dynamic Base16 DankShell",
|
||||
"colors": {
|
||||
"editor.background": "{{colors.background.default.hex}}",
|
||||
"editor.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"editorLineNumber.foreground": "{{colors.outline.default.hex}}",
|
||||
"editorLineNumber.activeForeground": "{{colors.on_surface.default.hex}}",
|
||||
"editorCursor.foreground": "{{colors.primary.default.hex}}",
|
||||
"editor.selectionBackground": "{{colors.primary_container.default.hex}}",
|
||||
"editor.inactiveSelectionBackground": "{{colors.background.default.hex}}",
|
||||
"editor.lineHighlightBackground": "{{colors.background.default.hex}}",
|
||||
"editorIndentGuide.background": "{{colors.background.default.hex}}",
|
||||
"editorIndentGuide.activeBackground": "{{colors.outline.default.hex}}",
|
||||
"editorWhitespace.foreground": "{{colors.outline_variant.default.hex}}",
|
||||
"editorBracketMatch.background": "{{colors.background.default.hex}}",
|
||||
"editorBracketMatch.border": "{{colors.primary.default.hex}}",
|
||||
|
||||
"activityBar.background": "{{colors.background.default.hex}}",
|
||||
"activityBar.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"activityBar.activeBorder": "{{colors.primary.default.hex}}",
|
||||
"activityBar.activeBackground": "{{colors.background.default.hex}}",
|
||||
"activityBarBadge.background": "{{colors.primary.default.hex}}",
|
||||
"activityBarBadge.foreground": "{{colors.on_primary.default.hex}}",
|
||||
|
||||
"sideBar.background": "{{colors.background.default.hex}}",
|
||||
"sideBar.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"sideBar.border": "{{colors.background.default.hex}}",
|
||||
"sideBarTitle.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"sideBarSectionHeader.background": "{{colors.background.default.hex}}",
|
||||
"sideBarSectionHeader.foreground": "{{colors.on_surface.default.hex}}",
|
||||
|
||||
"list.activeSelectionBackground": "{{colors.primary_container.default.hex}}",
|
||||
"list.activeSelectionForeground": "{{colors.on_primary_container.default.hex}}",
|
||||
"list.inactiveSelectionBackground": "{{colors.surface_container.default.hex}}",
|
||||
"list.inactiveSelectionForeground": "{{colors.on_surface.default.hex}}",
|
||||
"list.hoverBackground": "{{colors.surface_container.default.hex}}",
|
||||
"list.hoverForeground": "{{colors.on_surface.default.hex}}",
|
||||
"list.focusBackground": "{{colors.surface_container_high.default.hex}}",
|
||||
"list.focusForeground": "{{colors.on_surface.default.hex}}",
|
||||
"list.highlightForeground": "{{colors.primary.default.hex}}",
|
||||
|
||||
"statusBar.background": "{{colors.background.default.hex}}",
|
||||
"statusBar.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"statusBar.border": "{{colors.background.default.hex}}",
|
||||
"statusBar.noFolderBackground": "{{colors.background.default.hex}}",
|
||||
"statusBar.debuggingBackground": "{{colors.error.default.hex}}",
|
||||
"statusBar.debuggingForeground": "{{colors.on_error.default.hex}}",
|
||||
|
||||
"tab.activeBackground": "{{colors.background.default.hex}}",
|
||||
"tab.inactiveBackground": "{{colors.background.default.hex}}",
|
||||
"tab.activeForeground": "{{colors.on_surface.default.hex}}",
|
||||
"tab.inactiveForeground": "{{colors.outline.default.hex}}",
|
||||
"tab.border": "{{colors.background.default.hex}}",
|
||||
"tab.activeBorder": "{{colors.primary.default.hex}}",
|
||||
"tab.unfocusedActiveBorder": "{{colors.outline.default.hex}}",
|
||||
|
||||
"editorGroupHeader.tabsBackground": "{{colors.background.default.hex}}",
|
||||
"editorGroupHeader.noTabsBackground": "{{colors.background.default.hex}}",
|
||||
|
||||
"titleBar.activeBackground": "{{colors.background.default.hex}}",
|
||||
"titleBar.activeForeground": "{{colors.on_surface.default.hex}}",
|
||||
"titleBar.inactiveBackground": "{{colors.background.default.hex}}",
|
||||
"titleBar.inactiveForeground": "{{colors.outline.default.hex}}",
|
||||
"titleBar.border": "{{colors.background.default.hex}}",
|
||||
|
||||
"input.background": "{{colors.background.default.hex}}",
|
||||
"input.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"input.border": "{{colors.outline.default.hex}}",
|
||||
"input.placeholderForeground": "{{colors.outline.default.hex}}",
|
||||
"inputOption.activeBorder": "{{colors.primary.default.hex}}",
|
||||
"inputValidation.errorBackground": "{{colors.error.default.hex}}",
|
||||
"inputValidation.errorBorder": "{{colors.error.default.hex}}",
|
||||
|
||||
"dropdown.background": "{{colors.background.default.hex}}",
|
||||
"dropdown.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"dropdown.border": "{{colors.outline.default.hex}}",
|
||||
|
||||
"quickInput.background": "{{colors.background.default.hex}}",
|
||||
"quickInput.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"quickInputList.focusBackground": "{{colors.surface_container_high.default.hex}}",
|
||||
"quickInputList.focusForeground": "{{colors.on_surface.default.hex}}",
|
||||
|
||||
"button.background": "{{colors.primary.default.hex}}",
|
||||
"button.foreground": "{{colors.on_primary.default.hex}}",
|
||||
"button.hoverBackground": "{{colors.primary_container.default.hex}}",
|
||||
|
||||
"focusBorder": "{{colors.primary.default.hex}}",
|
||||
"badge.background": "{{colors.secondary.default.hex}}",
|
||||
"badge.foreground": "{{colors.on_secondary.default.hex}}",
|
||||
|
||||
"panel.background": "{{colors.background.default.hex}}",
|
||||
"panel.border": "{{colors.primary.default.hex}}",
|
||||
"panelTitle.activeBorder": "{{colors.primary.default.hex}}",
|
||||
"panelTitle.activeForeground": "{{colors.on_surface.default.hex}}",
|
||||
"panelTitle.inactiveForeground": "{{colors.outline.default.hex}}",
|
||||
|
||||
"terminal.background": "{{colors.background.default.hex}}",
|
||||
"terminal.foreground": "{{colors.on_surface.default.hex}}",
|
||||
|
||||
"gitDecoration.modifiedResourceForeground": "{{colors.primary.default.hex}}",
|
||||
"gitDecoration.addedResourceForeground": "{{colors.primary.default.hex}}",
|
||||
"gitDecoration.stageModifiedResourceForeground": "{{colors.primary.default.hex}}",
|
||||
"gitDecoration.stageDeletedResourceForeground": "{{colors.error.default.hex}}",
|
||||
"gitDecoration.deletedResourceForeground": "{{colors.error.default.hex}}",
|
||||
"gitDecoration.untrackedResourceForeground": "{{colors.secondary.default.hex}}",
|
||||
"gitDecoration.ignoredResourceForeground": "{{colors.outline.default.hex}}",
|
||||
"gitDecoration.conflictingResourceForeground": "{{colors.error_container.default.hex}}",
|
||||
"gitDecoration.submoduleResourceForeground": "{{colors.primary.default.hex}}",
|
||||
|
||||
"editorWidget.background": "{{colors.background.default.hex}}",
|
||||
"editorWidget.border": "{{colors.outline.default.hex}}",
|
||||
"editorSuggestWidget.background": "{{colors.background.default.hex}}",
|
||||
"editorSuggestWidget.border": "{{colors.outline.default.hex}}",
|
||||
"editorSuggestWidget.selectedBackground": "{{colors.surface_container_high.default.hex}}",
|
||||
"editorSuggestWidget.highlightForeground": "{{colors.primary.default.hex}}",
|
||||
|
||||
"peekView.border": "{{colors.primary.default.hex}}",
|
||||
"peekViewEditor.background": "{{colors.background.default.hex}}",
|
||||
"peekViewResult.background": "{{colors.background.default.hex}}",
|
||||
"peekViewTitle.background": "{{colors.background.default.hex}}",
|
||||
|
||||
"notificationCenter.border": "{{colors.outline.default.hex}}",
|
||||
"notifications.background": "{{colors.background.default.hex}}",
|
||||
"notifications.border": "{{colors.outline.default.hex}}",
|
||||
|
||||
"breadcrumb.foreground": "{{colors.outline.default.hex}}",
|
||||
"breadcrumb.focusForeground": "{{colors.on_surface.default.hex}}",
|
||||
"breadcrumb.activeSelectionForeground": "{{colors.primary.default.hex}}",
|
||||
|
||||
"scrollbarSlider.background": "{{colors.outline.default.hex}}40",
|
||||
"scrollbarSlider.hoverBackground": "{{colors.outline.default.hex}}60",
|
||||
"scrollbarSlider.activeBackground": "{{colors.outline.default.hex}}80",
|
||||
|
||||
"editorError.foreground": "{{colors.error.default.hex}}",
|
||||
"editorWarning.foreground": "{{colors.tertiary.default.hex}}",
|
||||
"editorInfo.foreground": "{{colors.primary.default.hex}}",
|
||||
|
||||
"editorGutter.addedBackground": "{{colors.secondary.default.hex}}",
|
||||
"editorGutter.modifiedBackground": "{{colors.tertiary.default.hex}}",
|
||||
"editorGutter.deletedBackground": "{{colors.error.default.hex}}",
|
||||
|
||||
"diffEditor.insertedTextBackground": "{{colors.secondary.default.hex}}20",
|
||||
"diffEditor.removedTextBackground": "{{colors.error.default.hex}}20",
|
||||
|
||||
"merge.currentHeaderBackground": "{{colors.primary.default.hex}}40",
|
||||
"merge.incomingHeaderBackground": "{{colors.secondary.default.hex}}40",
|
||||
|
||||
"menubar.selectionBackground": "{{colors.surface_container.default.hex}}",
|
||||
"menu.background": "{{colors.background.default.hex}}",
|
||||
"menu.foreground": "{{colors.on_surface.default.hex}}",
|
||||
"menu.selectionBackground": "{{colors.surface_container_high.default.hex}}",
|
||||
"menu.selectionForeground": "{{colors.on_surface.default.hex}}",
|
||||
|
||||
"debugToolBar.background": "{{colors.background.default.hex}}",
|
||||
"debugExceptionWidget.background": "{{colors.background.default.hex}}",
|
||||
"debugExceptionWidget.border": "{{colors.error.default.hex}}"
|
||||
},
|
||||
|
||||
"tokenColors": [
|
||||
{
|
||||
"scope": ["comment", "punctuation.definition.comment"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.outline.default.hex}}",
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["keyword", "storage.type", "storage.modifier"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.primary.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["variable", "meta.object-literal.key"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.on_surface.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["string", "constant.other.symbol"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["constant.numeric", "constant.language", "constant.character"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.tertiary.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.type", "support.type", "entity.name.class"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.tertiary.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["entity.name.function", "support.function"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.primary.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["support.class", "support.variable", "variable.language"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["invalid"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.error.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["invalid.deprecated"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.outline.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.heading"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.primary.default.hex}}",
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.bold"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.tertiary.default.hex}}",
|
||||
"fontStyle": "bold"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.italic"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.primary.default.hex}}",
|
||||
"fontStyle": "italic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.underline"],
|
||||
"settings": {
|
||||
"fontStyle": "underline"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.quote"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.list"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.on_surface.default.hex}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": ["markup.raw", "markup.inline.raw"],
|
||||
"settings": {
|
||||
"foreground": "{{colors.secondary.default.hex}}"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
"semanticHighlighting": true,
|
||||
"semanticTokenColors": {
|
||||
"variable.readonly": {
|
||||
"foreground": "{{colors.tertiary.default.hex}}"
|
||||
},
|
||||
"property": {
|
||||
"foreground": "{{colors.on_surface.default.hex}}"
|
||||
},
|
||||
"function": {
|
||||
"foreground": "{{colors.primary.default.hex}}"
|
||||
},
|
||||
"method": {
|
||||
"foreground": "{{colors.primary.default.hex}}"
|
||||
},
|
||||
"type": {
|
||||
"foreground": "{{colors.tertiary.default.hex}}"
|
||||
},
|
||||
"class": {
|
||||
"foreground": "{{colors.tertiary.default.hex}}"
|
||||
},
|
||||
"enumMember": {
|
||||
"foreground": "{{colors.tertiary.default.hex}}"
|
||||
},
|
||||
"string": {
|
||||
"foreground": "{{colors.secondary.default.hex}}"
|
||||
},
|
||||
"number": {
|
||||
"foreground": "{{colors.tertiary.default.hex}}"
|
||||
},
|
||||
"comment": {
|
||||
"foreground": "{{colors.outline.default.hex}}",
|
||||
"fontStyle": "italic"
|
||||
},
|
||||
"keyword": {
|
||||
"foreground": "{{colors.primary.default.hex}}"
|
||||
},
|
||||
"operator": {
|
||||
"foreground": "{{colors.on_surface.default.hex}}"
|
||||
},
|
||||
"parameter": {
|
||||
"foreground": "{{colors.on_surface.default.hex}}"
|
||||
},
|
||||
"namespace": {
|
||||
"foreground": "{{colors.secondary.default.hex}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,5 +9,5 @@ cursor_border = '{{colors.primary.default.hex}}'
|
||||
selection_bg = '{{colors.primary_container.default.hex}}'
|
||||
selection_fg = '{{colors.on_surface.default.hex}}'
|
||||
|
||||
ansi = ['{{dank16.color0.hex}}', '{{dank16.color1.hex}}', '{{dank16.color2.hex}}', '{{dank16.color3.hex}}', '{{dank16.color4.hex}}', '{{dank16.color5.hex}}', '{{dank16.color6.hex}}', '{{dank16.color7.hex}}']
|
||||
brights = ['{{dank16.color8.hex}}', '{{dank16.color9.hex}}', '{{dank16.color10.hex}}', '{{dank16.color11.hex}}', '{{dank16.color12.hex}}', '{{dank16.color13.hex}}', '{{dank16.color14.hex}}', '{{dank16.color15.hex}}']
|
||||
ansi = ['{{dank16.color0.default.hex}}', '{{dank16.color1.default.hex}}', '{{dank16.color2.default.hex}}', '{{dank16.color3.default.hex}}', '{{dank16.color4.default.hex}}', '{{dank16.color5.default.hex}}', '{{dank16.color6.default.hex}}', '{{dank16.color7.default.hex}}']
|
||||
brights = ['{{dank16.color8.default.hex}}', '{{dank16.color9.default.hex}}', '{{dank16.color10.default.hex}}', '{{dank16.color11.default.hex}}', '{{dank16.color12.default.hex}}', '{{dank16.color13.default.hex}}', '{{dank16.color14.default.hex}}', '{{dank16.color15.default.hex}}']
|
||||
|
||||
@@ -1,298 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -uo pipefail
|
||||
|
||||
log() { echo "[matugen-worker] $*" >&2; }
|
||||
err() { echo "[matugen-worker] ERROR: $*" >&2; }
|
||||
|
||||
[[ $# -lt 6 ]] && { echo "Usage: $0 STATE_DIR SHELL_DIR CONFIG_DIR SYNC_MODE_WITH_PORTAL TERMINALS_ALWAYS_DARK --run" >&2; exit 1; }
|
||||
|
||||
STATE_DIR="$1"
|
||||
SHELL_DIR="$2"
|
||||
CONFIG_DIR="$3"
|
||||
SYNC_MODE_WITH_PORTAL="$4"
|
||||
TERMINALS_ALWAYS_DARK="$5"
|
||||
shift 5
|
||||
[[ "${1:-}" != "--run" ]] && { echo "Usage: $0 ... --run" >&2; exit 1; }
|
||||
|
||||
[[ ! -d "$STATE_DIR" ]] && { err "STATE_DIR '$STATE_DIR' does not exist"; exit 1; }
|
||||
[[ ! -d "$SHELL_DIR" ]] && { err "SHELL_DIR '$SHELL_DIR' does not exist"; exit 1; }
|
||||
[[ ! -d "$CONFIG_DIR" ]] && { err "CONFIG_DIR '$CONFIG_DIR' does not exist"; exit 1; }
|
||||
|
||||
DESIRED_JSON="$STATE_DIR/matugen.desired.json"
|
||||
BUILT_KEY="$STATE_DIR/matugen.key"
|
||||
LOCK="$STATE_DIR/matugen-worker.lock"
|
||||
COLORS_OUTPUT="$STATE_DIR/dms-colors.json"
|
||||
|
||||
exec 9>"$LOCK"
|
||||
flock 9
|
||||
rm -f "$BUILT_KEY"
|
||||
|
||||
read_json_field() {
|
||||
local json="$1" field="$2"
|
||||
echo "$json" | sed -n "s/.*\"$field\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" | head -1
|
||||
}
|
||||
|
||||
read_json_escaped_field() {
|
||||
local json="$1" field="$2"
|
||||
local after="${json#*\"$field\":\"}"
|
||||
[[ "$after" == "$json" ]] && return
|
||||
local result=""
|
||||
while [[ -n "$after" ]]; do
|
||||
local char="${after:0:1}"
|
||||
after="${after:1}"
|
||||
[[ "$char" == '"' ]] && break
|
||||
[[ "$char" == '\' ]] && { result+="${after:0:1}"; after="${after:1}"; continue; }
|
||||
result+="$char"
|
||||
done
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
read_json_bool() {
|
||||
local json="$1" field="$2"
|
||||
echo "$json" | sed -n "s/.*\"$field\"[[:space:]]*:[[:space:]]*\([^,}]*\).*/\1/p" | head -1 | tr -d ' '
|
||||
}
|
||||
|
||||
compute_key() {
|
||||
local json="$1"
|
||||
local kind=$(read_json_field "$json" "kind")
|
||||
local value=$(read_json_field "$json" "value")
|
||||
local mode=$(read_json_field "$json" "mode")
|
||||
local icon=$(read_json_field "$json" "iconTheme")
|
||||
local mtype=$(read_json_field "$json" "matugenType")
|
||||
local run_user=$(read_json_bool "$json" "runUserTemplates")
|
||||
local stock_colors=$(read_json_escaped_field "$json" "stockColors")
|
||||
echo "${kind}|${value}|${mode}|${icon:-default}|${mtype:-scheme-tonal-spot}|${run_user:-true}|${stock_colors:-}" | sha256sum | cut -d' ' -f1
|
||||
}
|
||||
|
||||
append_config() {
|
||||
local check_cmd="$1" file_name="$2" cfg_file="$3"
|
||||
local target="$SHELL_DIR/matugen/configs/$file_name"
|
||||
[[ ! -f "$target" ]] && return
|
||||
[[ "$check_cmd" != "skip" ]] && ! command -v "$check_cmd" >/dev/null 2>&1 && return
|
||||
sed "s|'SHELL_DIR/|'$SHELL_DIR/|g" "$target" >> "$cfg_file"
|
||||
echo "" >> "$cfg_file"
|
||||
}
|
||||
|
||||
append_vscode_config() {
|
||||
local name="$1" ext_dir="$2" cfg_file="$3"
|
||||
[[ ! -d "$ext_dir" ]] && return
|
||||
local template_dir="$SHELL_DIR/matugen/templates"
|
||||
cat >> "$cfg_file" << EOF
|
||||
[templates.dms${name}default]
|
||||
input_path = '$template_dir/vscode-color-theme-default.json'
|
||||
output_path = '$ext_dir/themes/dankshell-default.json'
|
||||
|
||||
[templates.dms${name}dark]
|
||||
input_path = '$template_dir/vscode-color-theme-dark.json'
|
||||
output_path = '$ext_dir/themes/dankshell-dark.json'
|
||||
|
||||
[templates.dms${name}light]
|
||||
input_path = '$template_dir/vscode-color-theme-light.json'
|
||||
output_path = '$ext_dir/themes/dankshell-light.json'
|
||||
|
||||
EOF
|
||||
log "Added $name theme config (extension found at $ext_dir)"
|
||||
}
|
||||
|
||||
build_merged_config() {
|
||||
local mode="$1" run_user="$2" cfg_file="$3"
|
||||
|
||||
if [[ "$run_user" == "true" && -f "$CONFIG_DIR/matugen/config.toml" ]]; then
|
||||
awk '/^\[config\]/{p=1} /^\[templates\]/{p=0} p' "$CONFIG_DIR/matugen/config.toml" >> "$cfg_file"
|
||||
else
|
||||
echo "[config]" >> "$cfg_file"
|
||||
fi
|
||||
echo "" >> "$cfg_file"
|
||||
|
||||
grep -v '^\[config\]' "$SHELL_DIR/matugen/configs/base.toml" | sed "s|'SHELL_DIR/|'$SHELL_DIR/|g" >> "$cfg_file"
|
||||
echo "" >> "$cfg_file"
|
||||
|
||||
cat >> "$cfg_file" << EOF
|
||||
[templates.dank]
|
||||
input_path = '$SHELL_DIR/matugen/templates/dank.json'
|
||||
output_path = '$COLORS_OUTPUT'
|
||||
|
||||
EOF
|
||||
|
||||
[[ "$mode" == "light" ]] && append_config "skip" "gtk3-light.toml" "$cfg_file" || append_config "skip" "gtk3-dark.toml" "$cfg_file"
|
||||
|
||||
append_config "niri" "niri.toml" "$cfg_file"
|
||||
append_config "qt5ct" "qt5ct.toml" "$cfg_file"
|
||||
append_config "qt6ct" "qt6ct.toml" "$cfg_file"
|
||||
append_config "firefox" "firefox.toml" "$cfg_file"
|
||||
append_config "pywalfox" "pywalfox.toml" "$cfg_file"
|
||||
append_config "vesktop" "vesktop.toml" "$cfg_file"
|
||||
append_config "ghostty" "ghostty.toml" "$cfg_file"
|
||||
append_config "kitty" "kitty.toml" "$cfg_file"
|
||||
append_config "foot" "foot.toml" "$cfg_file"
|
||||
append_config "alacritty" "alacritty.toml" "$cfg_file"
|
||||
append_config "wezterm" "wezterm.toml" "$cfg_file"
|
||||
append_config "dgop" "dgop.toml" "$cfg_file"
|
||||
|
||||
append_vscode_config "vscode" "$HOME/.vscode/extensions/local.dynamic-base16-dankshell-0.0.1" "$cfg_file"
|
||||
append_vscode_config "codium" "$HOME/.vscode-oss/extensions/local.dynamic-base16-dankshell-0.0.1" "$cfg_file"
|
||||
append_vscode_config "codeoss" "$HOME/.config/Code - OSS/extensions/local.dynamic-base16-dankshell-0.0.1" "$cfg_file"
|
||||
append_vscode_config "cursor" "$HOME/.cursor/extensions/local.dynamic-base16-dankshell-0.0.1" "$cfg_file"
|
||||
append_vscode_config "windsurf" "$HOME/.windsurf/extensions/local.dynamic-base16-dankshell-0.0.1" "$cfg_file"
|
||||
|
||||
if [[ "$run_user" == "true" && -f "$CONFIG_DIR/matugen/config.toml" ]]; then
|
||||
awk '/^\[templates\]/{p=1} p' "$CONFIG_DIR/matugen/config.toml" >> "$cfg_file"
|
||||
echo "" >> "$cfg_file"
|
||||
fi
|
||||
|
||||
if [[ -d "$CONFIG_DIR/matugen/dms/configs" ]]; then
|
||||
for config in "$CONFIG_DIR/matugen/dms/configs"/*.toml; do
|
||||
[[ -f "$config" ]] || continue
|
||||
cat "$config" >> "$cfg_file"
|
||||
echo "" >> "$cfg_file"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
generate_dank16() {
|
||||
local primary="$1" surface="$2" light_flag="$3"
|
||||
local args=("$primary" --json)
|
||||
[[ -n "$light_flag" ]] && args+=("$light_flag")
|
||||
[[ -n "$surface" ]] && args+=(--background "$surface")
|
||||
dms dank16 "${args[@]}" 2>/dev/null || echo '{}'
|
||||
}
|
||||
|
||||
set_system_color_scheme() {
|
||||
[[ "$SYNC_MODE_WITH_PORTAL" != "true" ]] && return
|
||||
local mode="$1"
|
||||
local scheme="prefer-dark"
|
||||
[[ "$mode" == "light" ]] && scheme="default"
|
||||
gsettings set org.gnome.desktop.interface color-scheme "$scheme" 2>/dev/null || \
|
||||
dconf write /org/gnome/desktop/interface/color-scheme "'$scheme'" 2>/dev/null || true
|
||||
}
|
||||
|
||||
sync_color_scheme_on_exit() {
|
||||
[[ "$SYNC_MODE_WITH_PORTAL" != "true" ]] && return
|
||||
[[ ! -f "$DESIRED_JSON" ]] && return
|
||||
local json mode
|
||||
json=$(cat "$DESIRED_JSON" 2>/dev/null) || return
|
||||
mode=$(read_json_field "$json" "mode")
|
||||
[[ -n "$mode" ]] && set_system_color_scheme "$mode"
|
||||
}
|
||||
|
||||
trap sync_color_scheme_on_exit EXIT
|
||||
|
||||
refresh_gtk() {
|
||||
local mode="$1"
|
||||
local gtk_css="$CONFIG_DIR/gtk-3.0/gtk.css"
|
||||
[[ ! -e "$gtk_css" ]] && return
|
||||
local should_run=false
|
||||
if [[ -L "$gtk_css" ]]; then
|
||||
[[ "$(readlink "$gtk_css")" == *"dank-colors.css"* ]] && should_run=true
|
||||
elif grep -q "dank-colors.css" "$gtk_css" 2>/dev/null; then
|
||||
should_run=true
|
||||
fi
|
||||
[[ "$should_run" != "true" ]] && return
|
||||
gsettings set org.gnome.desktop.interface gtk-theme "" 2>/dev/null || true
|
||||
gsettings set org.gnome.desktop.interface gtk-theme "adw-gtk3-${mode}" 2>/dev/null || true
|
||||
}
|
||||
|
||||
signal_terminals() {
|
||||
pgrep -x kitty >/dev/null 2>&1 && pkill -USR1 kitty
|
||||
pgrep -x ghostty >/dev/null 2>&1 && pkill -USR2 ghostty
|
||||
}
|
||||
|
||||
build_once() {
|
||||
local json="$1"
|
||||
local kind=$(read_json_field "$json" "kind")
|
||||
local value=$(read_json_field "$json" "value")
|
||||
local mode=$(read_json_field "$json" "mode")
|
||||
local mtype=$(read_json_field "$json" "matugenType")
|
||||
local run_user=$(read_json_bool "$json" "runUserTemplates")
|
||||
local stock_colors=$(read_json_escaped_field "$json" "stockColors")
|
||||
|
||||
[[ -z "$mtype" ]] && mtype="scheme-tonal-spot"
|
||||
[[ -z "$run_user" ]] && run_user="true"
|
||||
|
||||
local TMP_CFG=$(mktemp)
|
||||
trap "rm -f '$TMP_CFG'" RETURN
|
||||
|
||||
build_merged_config "$mode" "$run_user" "$TMP_CFG"
|
||||
|
||||
local light_flag=""
|
||||
[[ "$mode" == "light" ]] && light_flag="--light"
|
||||
|
||||
local primary surface dank16_dark dank16_light import_args=()
|
||||
|
||||
if [[ -n "$stock_colors" ]]; then
|
||||
log "Using stock/custom theme colors with matugen base"
|
||||
primary=$(echo "$stock_colors" | sed -n 's/.*"primary"[^{]*{[^}]*"dark"[^{]*{[^}]*"color"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
|
||||
surface=$(echo "$stock_colors" | sed -n 's/.*"surface"[^{]*{[^}]*"dark"[^{]*{[^}]*"color"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
|
||||
|
||||
[[ -z "$primary" ]] && { err "Failed to extract primary from stock colors"; return 1; }
|
||||
|
||||
dank16_dark=$(generate_dank16 "$primary" "$surface" "")
|
||||
dank16_light=$(generate_dank16 "$primary" "$surface" "--light")
|
||||
|
||||
local dank16_current
|
||||
[[ "$mode" == "light" ]] && dank16_current="$dank16_light" || dank16_current="$dank16_dark"
|
||||
[[ "$TERMINALS_ALWAYS_DARK" == "true" && "$mode" == "light" ]] && dank16_current="$dank16_dark"
|
||||
|
||||
import_args+=(--import-json-string "{\"colors\": $stock_colors, \"dank16\": $dank16_current}")
|
||||
|
||||
log "Running matugen color hex with stock color overrides"
|
||||
if ! matugen color hex "$primary" -m "$mode" -t "${mtype:-scheme-tonal-spot}" -c "$TMP_CFG" "${import_args[@]}"; then
|
||||
err "matugen failed"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log "Using dynamic theme from $kind: $value"
|
||||
|
||||
local matugen_cmd=("matugen")
|
||||
[[ "$kind" == "hex" ]] && matugen_cmd+=("color" "hex") || matugen_cmd+=("$kind")
|
||||
matugen_cmd+=("$value")
|
||||
|
||||
local mat_json
|
||||
mat_json=$("${matugen_cmd[@]}" -m dark -t "$mtype" --json hex --dry-run 2>/dev/null | tr -d '\n')
|
||||
[[ -z "$mat_json" ]] && { err "matugen dry-run failed"; return 1; }
|
||||
|
||||
primary=$(echo "$mat_json" | sed -n 's/.*"primary"[[:space:]]*:[[:space:]]*{[^}]*"dark"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
|
||||
surface=$(echo "$mat_json" | sed -n 's/.*"surface"[[:space:]]*:[[:space:]]*{[^}]*"dark"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
|
||||
|
||||
[[ -z "$primary" ]] && { err "Failed to extract primary color"; return 1; }
|
||||
|
||||
dank16_dark=$(generate_dank16 "$primary" "$surface" "")
|
||||
dank16_light=$(generate_dank16 "$primary" "$surface" "--light")
|
||||
|
||||
local dank16_current
|
||||
[[ "$mode" == "light" ]] && dank16_current="$dank16_light" || dank16_current="$dank16_dark"
|
||||
[[ "$TERMINALS_ALWAYS_DARK" == "true" && "$mode" == "light" ]] && dank16_current="$dank16_dark"
|
||||
|
||||
import_args+=(--import-json-string "{\"dank16\": $dank16_current}")
|
||||
|
||||
log "Running matugen $kind with dank16 injection"
|
||||
if ! "${matugen_cmd[@]}" -m "$mode" -t "$mtype" -c "$TMP_CFG" "${import_args[@]}"; then
|
||||
err "matugen failed"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
refresh_gtk "$mode"
|
||||
signal_terminals
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
[[ ! -f "$DESIRED_JSON" ]] && { log "No desired state file"; exit 0; }
|
||||
|
||||
DESIRED=$(cat "$DESIRED_JSON")
|
||||
WANT_KEY=$(compute_key "$DESIRED")
|
||||
HAVE_KEY=""
|
||||
[[ -f "$BUILT_KEY" ]] && HAVE_KEY=$(cat "$BUILT_KEY" 2>/dev/null || true)
|
||||
|
||||
[[ "$WANT_KEY" == "$HAVE_KEY" ]] && { log "Already up to date"; exit 0; }
|
||||
|
||||
log "Building theme (key: ${WANT_KEY:0:12}...)"
|
||||
if build_once "$DESIRED"; then
|
||||
echo "$WANT_KEY" > "$BUILT_KEY"
|
||||
log "Done"
|
||||
exit 0
|
||||
else
|
||||
err "Build failed"
|
||||
exit 2
|
||||
fi
|
||||
Reference in New Issue
Block a user