125 lines
3.8 KiB
Go
125 lines
3.8 KiB
Go
|
//go:build !ci && !js && !android && !ios && !wasm && !test_web_driver
|
||
|
// +build !ci,!js,!android,!ios,!wasm,!test_web_driver
|
||
|
|
||
|
package app
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"net/url"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
"syscall"
|
||
|
|
||
|
"golang.org/x/sys/execabs"
|
||
|
"golang.org/x/sys/windows/registry"
|
||
|
|
||
|
"fyne.io/fyne/v2"
|
||
|
"fyne.io/fyne/v2/theme"
|
||
|
)
|
||
|
|
||
|
const notificationTemplate = `$title = "%s"
|
||
|
$content = "%s"
|
||
|
|
||
|
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null
|
||
|
$template = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02)
|
||
|
$toastXml = [xml] $template.GetXml()
|
||
|
$toastXml.GetElementsByTagName("text")[0].AppendChild($toastXml.CreateTextNode($title)) > $null
|
||
|
$toastXml.GetElementsByTagName("text")[1].AppendChild($toastXml.CreateTextNode($content)) > $null
|
||
|
|
||
|
$xml = New-Object Windows.Data.Xml.Dom.XmlDocument
|
||
|
$xml.LoadXml($toastXml.OuterXml)
|
||
|
$toast = [Windows.UI.Notifications.ToastNotification]::new($xml)
|
||
|
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("%s").Show($toast);`
|
||
|
|
||
|
func isDark() bool {
|
||
|
k, err := registry.OpenKey(registry.CURRENT_USER, `SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize`, registry.QUERY_VALUE)
|
||
|
if err != nil { // older version of Windows will not have this key
|
||
|
return false
|
||
|
}
|
||
|
defer k.Close()
|
||
|
|
||
|
useLight, _, err := k.GetIntegerValue("AppsUseLightTheme")
|
||
|
if err != nil { // older version of Windows will not have this value
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
return useLight == 0
|
||
|
}
|
||
|
|
||
|
func defaultVariant() fyne.ThemeVariant {
|
||
|
if isDark() {
|
||
|
return theme.VariantDark
|
||
|
}
|
||
|
return theme.VariantLight
|
||
|
}
|
||
|
|
||
|
func rootConfigDir() string {
|
||
|
homeDir, _ := os.UserHomeDir()
|
||
|
|
||
|
desktopConfig := filepath.Join(filepath.Join(homeDir, "AppData"), "Roaming")
|
||
|
return filepath.Join(desktopConfig, "fyne")
|
||
|
}
|
||
|
|
||
|
func (a *fyneApp) OpenURL(url *url.URL) error {
|
||
|
cmd := execabs.Command("rundll32", "url.dll,FileProtocolHandler", url.String())
|
||
|
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||
|
return cmd.Run()
|
||
|
}
|
||
|
|
||
|
var scriptNum = 0
|
||
|
|
||
|
func (a *fyneApp) SendNotification(n *fyne.Notification) {
|
||
|
title := escapeNotificationString(n.Title)
|
||
|
content := escapeNotificationString(n.Content)
|
||
|
appID := a.UniqueID()
|
||
|
if appID == "" || strings.Index(appID, "missing-id") == 0 {
|
||
|
appID = a.Metadata().Name
|
||
|
}
|
||
|
|
||
|
script := fmt.Sprintf(notificationTemplate, title, content, appID)
|
||
|
go runScript("notify", script)
|
||
|
}
|
||
|
|
||
|
// SetSystemTrayMenu creates a system tray item and attaches the specified menu.
|
||
|
// By default this will use the application icon.
|
||
|
func (a *fyneApp) SetSystemTrayMenu(menu *fyne.Menu) {
|
||
|
a.Driver().(systrayDriver).SetSystemTrayMenu(menu)
|
||
|
}
|
||
|
|
||
|
// SetSystemTrayIcon sets a custom image for the system tray icon.
|
||
|
// You should have previously called `SetSystemTrayMenu` to initialise the menu icon.
|
||
|
func (a *fyneApp) SetSystemTrayIcon(icon fyne.Resource) {
|
||
|
a.Driver().(systrayDriver).SetSystemTrayIcon(icon)
|
||
|
}
|
||
|
|
||
|
func escapeNotificationString(in string) string {
|
||
|
noSlash := strings.ReplaceAll(in, "`", "``")
|
||
|
return strings.ReplaceAll(noSlash, "\"", "`\"")
|
||
|
}
|
||
|
|
||
|
func runScript(name, script string) {
|
||
|
scriptNum++
|
||
|
appID := fyne.CurrentApp().UniqueID()
|
||
|
fileName := fmt.Sprintf("fyne-%s-%s-%d.ps1", appID, name, scriptNum)
|
||
|
|
||
|
tmpFilePath := filepath.Join(os.TempDir(), fileName)
|
||
|
err := os.WriteFile(tmpFilePath, []byte(script), 0600)
|
||
|
if err != nil {
|
||
|
fyne.LogError("Could not write script to show notification", err)
|
||
|
return
|
||
|
}
|
||
|
defer os.Remove(tmpFilePath)
|
||
|
|
||
|
launch := "(Get-Content -Encoding UTF8 -Path " + tmpFilePath + " -Raw) | Invoke-Expression"
|
||
|
cmd := execabs.Command("PowerShell", "-ExecutionPolicy", "Bypass", launch)
|
||
|
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
||
|
err = cmd.Run()
|
||
|
if err != nil {
|
||
|
fyne.LogError("Failed to launch windows notify script", err)
|
||
|
}
|
||
|
}
|
||
|
func watchTheme() {
|
||
|
// TODO monitor the Windows theme
|
||
|
}
|