Files
lazyrun/internal/cursor/cursor.go
T
oxpoe 7f7cb97a65 Ikon otomatis dari internet + cursor mengikuti tema host
- Cari ikon online (Iconify) dari dialog install, plus tombol sync ikon per shortcut
- Auto ikon: file terdekat -> favicon situs (termasuk ikon manifest PWA) -> ikon brand
  yang namanya cocok -> ikon default; sumber ikon disimpan di metadata
- Query dibersihkan (web.whatsapp.com -> whatsapp) dan kata <4 huruf tidak dipakai
  supaya aplikasi tanpa ikon resmi tidak dapat ikon acak
- Unduhan thumbnail dibatasi 4 bersamaan + retry sekali (rate limit Iconify)
- Cursor: XCURSOR_THEME/XCURSOR_SIZE diambil dari config KDE/GTK/~/.icons default,
  dan AppImage tidak lagi membundel libX*/libwayland*/libxkbcommon (dipakai dari host)
- README: bagian ikon + integrasi desktop
2026-10-13 08:00:12 +07:00

90 lines
2.3 KiB
Go

// Package cursor meneruskan cursor theme desktop (KDE/GNOME) ke Fyne/GLFW.
package cursor
import (
"os"
"path/filepath"
"strings"
)
// Apply men-set XCURSOR_THEME dan XCURSOR_SIZE kalau sesi belum men-set-nya.
// Fyne (GLFW) membaca env ini waktu memuat cursor, jadi panggil sebelum app dibuat.
func Apply() {
if os.Getenv("XCURSOR_SIZE") == "" {
if _, size := desktopCursor(); size != "" {
os.Setenv("XCURSOR_SIZE", size)
}
}
if os.Getenv("XCURSOR_THEME") != "" {
return
}
if theme, _ := desktopCursor(); theme != "" {
os.Setenv("XCURSOR_THEME", theme)
}
}
func home() string {
h, _ := os.UserHomeDir()
return h
}
func configHome() string {
if v := os.Getenv("XDG_CONFIG_HOME"); v != "" {
return v
}
return filepath.Join(home(), ".config")
}
// desktopCursor mengambil nama & ukuran cursor dari config KDE, GTK, atau ~/.icons/default.
func desktopCursor() (theme, size string) {
// KDE Plasma: ~/.config/kcminputrc
kde := ini(filepath.Join(configHome(), "kcminputrc"))
if t := kde["mouse"]["cursortheme"]; t != "" {
return t, kde["mouse"]["cursorsize"]
}
for _, gtk := range []string{"gtk-4.0", "gtk-3.0"} {
cfg := ini(filepath.Join(configHome(), gtk, "settings.ini"))
if t := cfg["settings"]["gtk-cursor-theme-name"]; t != "" {
return t, cfg["settings"]["gtk-cursor-theme-size"]
}
}
// fallback: theme default di ~/.icons/default/index.theme (format "Inherits=")
fallback := filepath.Join(home(), ".icons", "default", "index.theme")
if t := ini(fallback)["icon theme"]["inherits"]; t != "" {
return t, ""
}
return "", ""
}
// ini membaca file config berformat INI sederhana; key disimpan huruf kecil.
func ini(path string) map[string]map[string]string {
out := map[string]map[string]string{}
data, err := os.ReadFile(path)
if err != nil {
return out
}
section := ""
for _, line := range strings.Split(string(data), "\n") {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") {
continue
}
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
section = strings.ToLower(strings.Trim(line, "[]"))
continue
}
key, value, ok := strings.Cut(line, "=")
if !ok {
continue
}
if out[section] == nil {
out[section] = map[string]string{}
}
out[section][strings.ToLower(strings.TrimSpace(key))] = strings.TrimSpace(value)
}
return out
}