Skip to content

Commit

Permalink
Merge pull request fyne-io#1199 from andydotxyz/feature/macOStheme
Browse files Browse the repository at this point in the history
match macOS/Windows system theme
  • Loading branch information
andydotxyz committed Jul 26, 2020
2 parents 002c139 + f585054 commit 65afdd3
Show file tree
Hide file tree
Showing 127 changed files with 18,513 additions and 466 deletions.
17 changes: 15 additions & 2 deletions app/app_darwin.go
Expand Up @@ -11,7 +11,9 @@ package app
#include <AppKit/AppKit.h>
bool isBundled();
bool isDarkMode();
void sendNotification(const char *title, const char *content);
void watchTheme();
*/
import "C"
import (
Expand All @@ -31,8 +33,10 @@ func defaultTheme() fyne.Theme {
if fyne.CurrentDevice().IsMobile() { // this is called in mobile simulate mode
return theme.LightTheme()
}
// TODO read the macOS setting in Mojave onwards
return theme.DarkTheme()
if C.isDarkMode() {
return theme.DarkTheme()
}
return theme.LightTheme()
}

func rootConfigDir() string {
Expand Down Expand Up @@ -74,3 +78,12 @@ func escapeNotificationString(in string) string {
noSlash := strings.ReplaceAll(in, "\\", "\\\\")
return strings.ReplaceAll(noSlash, "\"", "\\\"")
}

//export themeChanged
func themeChanged() {
fyne.CurrentApp().Settings().(*settings).setupTheme()
}

func watchTheme() {
C.watchTheme()
}
14 changes: 14 additions & 0 deletions app/app_darwin.m
@@ -1,6 +1,8 @@
// +build !ci
// +build !ios

extern void themeChanged();

#import <Foundation/Foundation.h>

@interface FyneUserNotificationCenterDelegate : NSObject<NSUserNotificationCenterDelegate>
Expand Down Expand Up @@ -28,6 +30,11 @@ bool isBundled() {
return [[NSBundle mainBundle] bundleIdentifier] != nil;
}

bool isDarkMode() {
NSString *style = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
return [@"Dark" isEqualToString:style];
}

void sendNotification(const char *title, const char *body) {
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
if (center.delegate == nil) {
Expand All @@ -39,3 +46,10 @@ void sendNotification(const char *title, const char *body) {
notification.identifier = [NSString stringWithFormat:@"%@-fyne-notify-%d", [[NSBundle mainBundle] bundleIdentifier], ++notifyNum];
[center scheduleNotification:notification];
}

void watchTheme() {
[[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"AppleInterfaceThemeChangedNotification" object:nil queue:nil
usingBlock:^(NSNotification *note) {
themeChanged(); // calls back into Go
}];
}
4 changes: 4 additions & 0 deletions app/app_other.go
Expand Up @@ -25,3 +25,7 @@ func (app *fyneApp) OpenURL(_ *url.URL) error {
func (app *fyneApp) SendNotification(_ *fyne.Notification) {
fyne.LogError("Refusing to show notification for unknown operating system", nil)
}

func watchTheme() {
// no-op
}
25 changes: 24 additions & 1 deletion app/app_windows.go
Expand Up @@ -14,6 +14,8 @@ import (
"strings"
"syscall"

"golang.org/x/sys/windows/registry"

"fyne.io/fyne"
"fyne.io/fyne/theme"
)
Expand All @@ -32,8 +34,26 @@ $xml.LoadXml($toastXml.OuterXml)
$toast = [Windows.UI.Notifications.ToastNotification]::new($xml)
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("appID").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 defaultTheme() fyne.Theme {
return theme.DarkTheme()
if isDark() {
return theme.DarkTheme()
}
return theme.LightTheme()
}

func rootConfigDir() string {
Expand Down Expand Up @@ -85,3 +105,6 @@ func runScript(name, script string) {
fyne.LogError("Failed to launch windows notify script", err)
}
}
func watchTheme() {
// TODO monitor the Windows theme
}
4 changes: 4 additions & 0 deletions app/app_xdg.go
Expand Up @@ -51,3 +51,7 @@ func rootConfigDir() string {
desktopConfig := filepath.Join(homeDir, ".config")
return filepath.Join(desktopConfig, "fyne")
}

func watchTheme() {
// no-op, not able to read linux theme in a standard way
}
2 changes: 2 additions & 0 deletions app/settings_desktop.go
Expand Up @@ -61,6 +61,8 @@ func watchFile(path string, callback func()) *fsnotify.Watcher {

func (s *settings) watchSettings() {
s.watcher = watchFile(s.schema.StoragePath(), s.fileChanged)

watchTheme()
}

func (s *settings) stopWatching() {
Expand Down
5 changes: 4 additions & 1 deletion app/settings_desktop_test.go
Expand Up @@ -5,6 +5,7 @@ package app
import (
"os"
"path/filepath"
"runtime"
"testing"
"time"

Expand All @@ -15,7 +16,9 @@ import (
)

func TestDefaultTheme(t *testing.T) {
assert.Equal(t, theme.DarkTheme(), defaultTheme())
if runtime.GOOS != "darwin" { // system defines default for macOS
assert.Equal(t, theme.DarkTheme(), defaultTheme())
}
}

func TestEnsureDir(t *testing.T) {
Expand Down
17 changes: 16 additions & 1 deletion cmd/fyne_settings/settings/appearance.go
Expand Up @@ -5,6 +5,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"runtime"

"fyne.io/fyne"
"fyne.io/fyne/app"
Expand All @@ -14,6 +15,10 @@ import (
"fyne.io/fyne/widget"
)

const (
systemThemeName = "system default"
)

// Settings gives access to user interfaces to control Fyne settings
type Settings struct {
fyneSettings app.SettingsSchema
Expand All @@ -40,7 +45,14 @@ func (s *Settings) LoadAppearanceScreen(w fyne.Window) fyne.CanvasObject {
s.preview.FillMode = canvas.ImageFillContain

def := s.fyneSettings.ThemeName
themes := widget.NewSelect([]string{"dark", "light"}, s.chooseTheme)
themeNames := []string{"dark", "light"}
if runtime.GOOS == "darwin" || runtime.GOOS == "windows" {
themeNames = append(themeNames, systemThemeName)
if s.fyneSettings.ThemeName == "" {
def = systemThemeName
}
}
themes := widget.NewSelect(themeNames, s.chooseTheme)
themes.SetSelected(def)

scale := s.makeScaleGroup(w.Canvas().Scale())
Expand All @@ -61,6 +73,9 @@ func (s *Settings) LoadAppearanceScreen(w fyne.Window) fyne.CanvasObject {
}

func (s *Settings) chooseTheme(name string) {
if name == systemThemeName {
name = ""
}
s.fyneSettings.ThemeName = name

switch name {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -23,7 +23,7 @@ require (
golang.org/x/image v0.0.0-20200430140353-33d19683fad8
golang.org/x/mod v0.2.0
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e // indirect
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775 // indirect
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666
golang.org/x/text v0.3.2 // indirect
golang.org/x/tools v0.0.0-20200328031815-3db5fc6bac03
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Expand Up @@ -67,8 +67,8 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775 h1:TC0v2RSO1u2kn1ZugjrFXkRZAEaqMN/RW+OTZkBzmLE=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666 h1:gVCS+QOncANNPlmlO1AhlU3oxs4V9z+gTtPwIk3p2N8=
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
Expand Down
30 changes: 30 additions & 0 deletions vendor/golang.org/x/sys/internal/unsafeheader/unsafeheader.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions vendor/golang.org/x/sys/unix/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions vendor/golang.org/x/sys/unix/mkerrors.sh

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 14 additions & 7 deletions vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions vendor/golang.org/x/sys/unix/syscall_darwin.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 0 additions & 11 deletions vendor/golang.org/x/sys/unix/syscall_darwin_386.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 0 additions & 11 deletions vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 65afdd3

Please sign in to comment.