Skip to content

Commit

Permalink
Merge pull request #2390 from andydotxyz/fix/1833
Browse files Browse the repository at this point in the history
Fix/1833
  • Loading branch information
andydotxyz committed Aug 20, 2021
2 parents 21ffbe1 + fc94fa3 commit 12e525e
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 140 deletions.
74 changes: 23 additions & 51 deletions app/app_darwin.go
@@ -1,87 +1,59 @@
// +build !ci

// +build !ios

package app

/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation
#cgo LDFLAGS: -framework Foundation -framework UserNotifications
#include <AppKit/AppKit.h>
#include <stdbool.h>
#include <stdlib.h>
bool isBundled();
bool isDarkMode();
void sendNotification(const char *title, const char *content);
void watchTheme();
void sendNotification(char *title, char *content);
*/
import "C"
import (
"fmt"
"net/url"
"os"
"path/filepath"
"strings"
"unsafe"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/theme"

"golang.org/x/sys/execabs"
)

func defaultVariant() fyne.ThemeVariant {
if C.isDarkMode() {
return theme.VariantDark
}
return theme.VariantLight
}

func rootConfigDir() string {
homeDir, _ := os.UserHomeDir()

desktopConfig := filepath.Join(filepath.Join(homeDir, "Library"), "Preferences")
return filepath.Join(desktopConfig, "fyne")
}

func (a *fyneApp) OpenURL(url *url.URL) error {
cmd := a.exec("open", url.String())
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
return cmd.Run()
}

func (a *fyneApp) SendNotification(n *fyne.Notification) {
if C.isBundled() {
title := C.CString(n.Title)
defer C.free(unsafe.Pointer(title))
content := C.CString(n.Content)
defer C.free(unsafe.Pointer(content))
titleStr := C.CString(n.Title)
defer C.free(unsafe.Pointer(titleStr))
contentStr := C.CString(n.Content)
defer C.free(unsafe.Pointer(contentStr))

C.sendNotification(title, content)
C.sendNotification(titleStr, contentStr)
return
}

title := escapeNotificationString(n.Title)
content := escapeNotificationString(n.Content)
template := `display notification "%s" with title "%s"`
script := fmt.Sprintf(template, content, title)

err := execabs.Command("osascript", "-e", script).Start()
if err != nil {
fyne.LogError("Failed to launch darwin notify script", err)
}
fallbackNotification(n.Title, n.Content)
}

func escapeNotificationString(in string) string {
noSlash := strings.ReplaceAll(in, "\\", "\\\\")
return strings.ReplaceAll(noSlash, "\"", "\\\"")
}

//export themeChanged
func themeChanged() {
fyne.CurrentApp().Settings().(*settings).setupTheme()
//export fallbackSend
func fallbackSend(cTitle, cContent *C.char) {
title := C.GoString(cTitle)
content := C.GoString(cContent)
fallbackNotification(title, content)
}

func watchTheme() {
C.watchTheme()
func fallbackNotification(title, content string) {
template := `display notification "%s" with title "%s"`
script := fmt.Sprintf(template, escapeNotificationString(content), escapeNotificationString(title))

err := execabs.Command("osascript", "-e", script).Start()
if err != nil {
fyne.LogError("Failed to launch darwin notify script", err)
}
}
78 changes: 37 additions & 41 deletions app/app_darwin.m
@@ -1,55 +1,51 @@
// +build !ci
// +build !ios

extern void themeChanged();
#import <UserNotifications/UserNotifications.h>

#import <Foundation/Foundation.h>
static int notifyNum = 0;

@interface FyneUserNotificationCenterDelegate : NSObject<NSUserNotificationCenterDelegate>
extern void fallbackSend(char *cTitle, char *cBody);

- (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center
shouldPresentNotification:(NSUserNotification*)notification;
void doSendNotification(UNUserNotificationCenter *center, NSString *title, NSString *body) {
UNMutableNotificationContent *content = [UNMutableNotificationContent new];
[content autorelease];
content.title = title;
content.body = body;

@end
notifyNum++;
NSString *identifier = [NSString stringWithFormat:@"fyne-notify-%d", notifyNum];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier
content:content trigger:nil];

@implementation FyneUserNotificationCenterDelegate

- (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center
shouldPresentNotification:(NSUserNotification*)notification
{
return YES;
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(@"Could not send notification: %@", error);
}
}];
}

@end

void sendNSUserNotification(const char *, const char *);

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) {
center.delegate = [[FyneUserNotificationCenterDelegate new] autorelease];
}

NSString *uuid = [[NSUUID UUID] UUIDString];
NSUserNotification *notification = [[NSUserNotification new] autorelease];
notification.title = [NSString stringWithUTF8String:title];
notification.informativeText = [NSString stringWithUTF8String:body];
notification.identifier = [NSString stringWithFormat:@"%@-fyne-notify-%@", [[NSBundle mainBundle] bundleIdentifier], uuid];
[center scheduleNotification:notification];
}

void watchTheme() {
[[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"AppleInterfaceThemeChangedNotification" object:nil queue:nil
usingBlock:^(NSNotification *note) {
themeChanged(); // calls back into Go
}];
void sendNotification(char *cTitle, char *cBody) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
NSString *title = [NSString stringWithUTF8String:cTitle];
NSString *body = [NSString stringWithUTF8String:cBody];

UNAuthorizationOptions options = UNAuthorizationOptionAlert;
[center requestAuthorizationWithOptions:options
completionHandler:^(BOOL granted, NSError *_Nullable error) {
if (!granted) {
if (error != NULL) {
NSLog(@"Error asking for permission to send notifications %@", error);
// this happens if our app was not signed, so do it the old way
fallbackSend((char *)[title UTF8String], (char *)[body UTF8String]);
} else {
NSLog(@"Unable to get permission to send notifications");
}
} else {
doSendNotification(center, title, body);
}
}];
}
54 changes: 54 additions & 0 deletions app/app_desktop_darwin.go
@@ -0,0 +1,54 @@
// +build !ci

// +build !ios

package app

/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation
#include <AppKit/AppKit.h>
bool isBundled();
bool isDarkMode();
void watchTheme();
*/
import "C"
import (
"net/url"
"os"
"path/filepath"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/theme"
)

func defaultVariant() fyne.ThemeVariant {
if C.isDarkMode() {
return theme.VariantDark
}
return theme.VariantLight
}

func rootConfigDir() string {
homeDir, _ := os.UserHomeDir()

desktopConfig := filepath.Join(filepath.Join(homeDir, "Library"), "Preferences")
return filepath.Join(desktopConfig, "fyne")
}

func (a *fyneApp) OpenURL(url *url.URL) error {
cmd := a.exec("open", url.String())
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
return cmd.Run()
}

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

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

extern void themeChanged();

#import <Foundation/Foundation.h>

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

void watchTheme() {
[[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"AppleInterfaceThemeChangedNotification" object:nil queue:nil
usingBlock:^(NSNotification *note) {
themeChanged(); // calls back into Go
}];
}
9 changes: 0 additions & 9 deletions app/app_mobile_ios.go
Expand Up @@ -36,15 +36,6 @@ func (a *fyneApp) OpenURL(url *url.URL) error {
return nil
}

func (a *fyneApp) SendNotification(n *fyne.Notification) {
titleStr := C.CString(n.Title)
defer C.free(unsafe.Pointer(titleStr))
contentStr := C.CString(n.Content)
defer C.free(unsafe.Pointer(contentStr))

C.sendNotification(titleStr, contentStr)
}

func defaultVariant() fyne.ThemeVariant {
return systemTheme
}
37 changes: 0 additions & 37 deletions app/app_mobile_ios.m
Expand Up @@ -3,50 +3,13 @@
// +build ios

#import <UIKit/UIKit.h>
#import <UserNotifications/UserNotifications.h>

void openURL(char *urlStr) {
UIApplication *app = [UIApplication sharedApplication];
NSURL *url = [NSURL URLWithString:[NSString stringWithUTF8String:urlStr]];
[app openURL:url options:@{} completionHandler:nil];
}

static int notifyNum = 0;

void doSendNotification(UNUserNotificationCenter *center, NSString *title, NSString *body) {
UNMutableNotificationContent *content = [UNMutableNotificationContent new];
[content autorelease];
content.title = title;
content.body = body;

notifyNum++;
NSString *identifier = [NSString stringWithFormat:@"fyne-notify-%d", notifyNum];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier
content:content trigger:nil];

[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(@"Could not send notification: %@", error);
}
}];
}

void sendNotification(char *cTitle, char *cBody) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
NSString *title = [NSString stringWithUTF8String:cTitle];
NSString *body = [NSString stringWithUTF8String:cBody];

UNAuthorizationOptions options = UNAuthorizationOptionAlert;
[center requestAuthorizationWithOptions:options
completionHandler:^(BOOL granted, NSError *_Nullable error) {
if (!granted) {
NSLog(@"Unable to get permission to send notifications");
} else {
doSendNotification(center, title, body);
}
}];
}

char *documentsPath() {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = paths.firstObject;
Expand Down
13 changes: 11 additions & 2 deletions internal/driver/glfw/menu_darwin.m
Expand Up @@ -5,6 +5,15 @@

const int menuTagMin = 5000;

#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
NSControlStateValue STATE_ON = NSControlStateValueOn;
NSControlStateValue STATE_OFF = NSControlStateValueOff;
#else
NSControlStateValue STATE_ON = NSOnState;
NSControlStateValue STATE_OFF = NSOffState;
#endif


extern void menuCallback(int);
extern BOOL menuEnabled(int);
extern BOOL menuChecked(int);
Expand All @@ -21,9 +30,9 @@ + (void) tapped:(NSMenuItem*) item {
+ (BOOL) validateMenuItem:(NSMenuItem*) item {
BOOL checked = menuChecked([item tag]-menuTagMin);
if (checked) {
[item setState:NSOnState];
[item setState:STATE_ON];
} else {
[item setState:NSOffState];
[item setState:STATE_OFF];
}

return menuEnabled([item tag]-menuTagMin);
Expand Down

0 comments on commit 12e525e

Please sign in to comment.