mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-15 07:05:50 +01:00
Compare commits
13 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a11655c452 |
||
|
|
11cbfb68f1 |
||
|
|
319d59296e | ||
|
|
368733b7cc | ||
|
|
ee5ca1a84a |
||
|
|
1947a9a17a |
||
|
|
13fb5352d8 |
||
|
|
58b6e4c335 |
||
|
|
ae0933c82a |
||
|
|
c1d4aeb3cd |
||
|
|
1830c64c79 |
||
|
|
ee50170374 |
||
|
|
3f82ceabba |
27 changed files with 1230 additions and 294 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -32,3 +32,4 @@ v2/test/kitchensink/frontend/package.json.md5
|
||||||
!v2/internal/ffenestri/windows/x64/WebView2Loader.dll
|
!v2/internal/ffenestri/windows/x64/WebView2Loader.dll
|
||||||
.idea/
|
.idea/
|
||||||
v2/cmd/wails/internal/commands/initialise/templates/testtemplates/
|
v2/cmd/wails/internal/commands/initialise/templates/testtemplates/
|
||||||
|
v2/internal/frontend/desktop/darwin/test.xcodeproj
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
@property bool startHidden;
|
@property bool startHidden;
|
||||||
@property bool startFullscreen;
|
@property bool startFullscreen;
|
||||||
@property (retain) WailsWindow* mainWindow;
|
@property (retain) WailsWindow* mainWindow;
|
||||||
|
@property int activationPolicy;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
|
#import "message.h"
|
||||||
|
|
||||||
@implementation AppDelegate
|
@implementation AppDelegate
|
||||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
|
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
|
||||||
|
|
@ -25,6 +26,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||||
|
processNotification(0); // Notify Go
|
||||||
|
[NSApp setActivationPolicy:self.activationPolicy];
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
if ( self.startFullscreen ) {
|
if ( self.startFullscreen ) {
|
||||||
NSWindowCollectionBehavior behaviour = [self.mainWindow collectionBehavior];
|
NSWindowCollectionBehavior behaviour = [self.mainWindow collectionBehavior];
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
#define WindowStartsFullscreen 3
|
#define WindowStartsFullscreen 3
|
||||||
|
|
||||||
WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int debug, int windowStartState, int startsHidden, int minWidth, int minHeight, int maxWidth, int maxHeight);
|
WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int debug, int windowStartState, int startsHidden, int minWidth, int minHeight, int maxWidth, int maxHeight);
|
||||||
void Run(void*, const char* url);
|
void Run(void *inctx, const char* url, int activationPolicy);
|
||||||
|
|
||||||
void SetTitle(void* ctx, const char *title);
|
void SetTitle(void* ctx, const char *title);
|
||||||
void Center(void* ctx);
|
void Center(void* ctx);
|
||||||
|
|
@ -57,6 +57,16 @@ void AppendSubmenu(void* parent, void* child);
|
||||||
void AppendRole(void *inctx, void *inMenu, int role);
|
void AppendRole(void *inctx, void *inMenu, int role);
|
||||||
void SetAsApplicationMenu(void *inctx, void *inMenu);
|
void SetAsApplicationMenu(void *inctx, void *inMenu);
|
||||||
void UpdateApplicationMenu(void *inctx);
|
void UpdateApplicationMenu(void *inctx);
|
||||||
|
void SetMenuItemChecked(void* nsMenuItem, int checked);
|
||||||
|
|
||||||
|
/* Tray Menu */
|
||||||
|
void NewNSStatusItem(int id, int length);
|
||||||
|
void SetTrayMenu(void *nsStatusItem, void* nsMenu);
|
||||||
|
void SetTrayMenuLabel(void *nsStatusItem, const char *label);
|
||||||
|
void SetTrayImage(void *nsStatusItem, void *imageData, int imageDataLength, int template, int position);
|
||||||
|
|
||||||
|
/* MenuItems */
|
||||||
|
void SetMenuItemLabel(void *nsStatusItem, const char *label);
|
||||||
|
|
||||||
void SetAbout(void *inctx, const char* title, const char* description, void* imagedata, int datalen);
|
void SetAbout(void *inctx, const char* title, const char* description, void* imagedata, int datalen);
|
||||||
void* AppendMenuItem(void* inctx, void* nsmenu, const char* label, const char* shortcutKey, int modifiers, int disabled, int checked, int menuItemID);
|
void* AppendMenuItem(void* inctx, void* nsmenu, const char* label, const char* shortcutKey, int modifiers, int disabled, int checked, int menuItemID);
|
||||||
|
|
@ -65,4 +75,7 @@ void UpdateMenuItem(void* nsmenuitem, int checked);
|
||||||
|
|
||||||
NSString* safeInit(const char* input);
|
NSString* safeInit(const char* input);
|
||||||
|
|
||||||
|
|
||||||
|
int ScalingFactor(void *ctx);
|
||||||
|
|
||||||
#endif /* Application_h */
|
#endif /* Application_h */
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
#import "WailsMenu.h"
|
#import "WailsMenu.h"
|
||||||
#import "WailsMenuItem.h"
|
#import "WailsMenuItem.h"
|
||||||
|
#import "message.h"
|
||||||
|
|
||||||
WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int debug, int windowStartState, int startsHidden, int minWidth, int minHeight, int maxWidth, int maxHeight) {
|
WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int debug, int windowStartState, int startsHidden, int minWidth, int minHeight, int maxWidth, int maxHeight) {
|
||||||
|
|
||||||
|
|
@ -19,7 +20,7 @@ WailsContext* Create(const char* title, int width, int height, int frameless, in
|
||||||
WailsContext *result = [WailsContext new];
|
WailsContext *result = [WailsContext new];
|
||||||
|
|
||||||
result.debug = debug;
|
result.debug = debug;
|
||||||
|
|
||||||
if ( windowStartState == WindowStartsFullscreen ) {
|
if ( windowStartState == WindowStartsFullscreen ) {
|
||||||
fullscreen = 1;
|
fullscreen = 1;
|
||||||
}
|
}
|
||||||
|
|
@ -27,7 +28,7 @@ WailsContext* Create(const char* title, int width, int height, int frameless, in
|
||||||
[result CreateWindow:width :height :frameless :resizable :fullscreen :fullSizeContent :hideTitleBar :titlebarAppearsTransparent :hideTitle :useToolbar :hideToolbarSeparator :webviewIsTransparent :hideWindowOnClose :safeInit(appearance) :windowIsTranslucent :minWidth :minHeight :maxWidth :maxHeight];
|
[result CreateWindow:width :height :frameless :resizable :fullscreen :fullSizeContent :hideTitleBar :titlebarAppearsTransparent :hideTitle :useToolbar :hideToolbarSeparator :webviewIsTransparent :hideWindowOnClose :safeInit(appearance) :windowIsTranslucent :minWidth :minHeight :maxWidth :maxHeight];
|
||||||
[result SetTitle:safeInit(title)];
|
[result SetTitle:safeInit(title)];
|
||||||
[result Center];
|
[result Center];
|
||||||
|
|
||||||
switch( windowStartState ) {
|
switch( windowStartState ) {
|
||||||
case WindowStartsMaximised:
|
case WindowStartsMaximised:
|
||||||
[result.mainWindow zoom:nil];
|
[result.mainWindow zoom:nil];
|
||||||
|
|
@ -172,6 +173,10 @@ void ToggleMaximise(void* inctx) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetMenuItemChecked(void* nsMenuItem, int checked) {
|
||||||
|
[(NSMenuItem*)nsMenuItem setState:(checked == 0 ? NSOffState : NSOnState)];
|
||||||
|
}
|
||||||
|
|
||||||
const char* GetSize(void *inctx) {
|
const char* GetSize(void *inctx) {
|
||||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
NSRect frame = [ctx.mainWindow frame];
|
NSRect frame = [ctx.mainWindow frame];
|
||||||
|
|
@ -277,6 +282,55 @@ void AppendRole(void *inctx, void *inMenu, int role) {
|
||||||
[menu appendRole :ctx :role];
|
[menu appendRole :ctx :role];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NewNSStatusItem(int id, int length) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
|
||||||
|
NSStatusBar *statusBar = [NSStatusBar systemStatusBar];
|
||||||
|
// Map Go to Cocoa length. 0 = NSVariableStatusItemLength.
|
||||||
|
CGFloat length = NSVariableStatusItemLength;
|
||||||
|
if( length == 1 ) {
|
||||||
|
length = NSSquareStatusItemLength;
|
||||||
|
}
|
||||||
|
NSStatusItem *result = [[statusBar statusItemWithLength:length] retain];
|
||||||
|
objectCreated(id,result);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteStatusItem(void *_nsStatusItem) {
|
||||||
|
NSStatusItem *nsStatusItem = (NSStatusItem*) _nsStatusItem;
|
||||||
|
[nsStatusItem release];
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_main_thread(void (^l)(void)) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), l);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTrayMenuLabel(void *_nsStatusItem, const char *label) {
|
||||||
|
on_main_thread(^{
|
||||||
|
NSStatusItem *nsStatusItem = (NSStatusItem*) _nsStatusItem;
|
||||||
|
nsStatusItem.button.title = safeInit(label);
|
||||||
|
free((void*)label);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTrayMenu(void *nsStatusItem, void* nsMenu) {
|
||||||
|
ON_MAIN_THREAD(
|
||||||
|
[(NSStatusItem*)nsStatusItem setMenu:(NSMenu *)nsMenu];
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**** Menu Item ****/
|
||||||
|
|
||||||
|
void SetMenuItemLabel(void *_nsMenuItem, const char *label) {
|
||||||
|
on_main_thread(^{
|
||||||
|
NSMenuItem *nsMenuItem = (NSMenuItem*) _nsMenuItem;
|
||||||
|
[ nsMenuItem setTitle:safeInit(label) ];
|
||||||
|
free((void*)label);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void* NewMenu(const char *name) {
|
void* NewMenu(const char *name) {
|
||||||
NSString *title = @"";
|
NSString *title = @"";
|
||||||
if (name != nil) {
|
if (name != nil) {
|
||||||
|
|
@ -301,8 +355,8 @@ void SetAsApplicationMenu(void *inctx, void *inMenu) {
|
||||||
void UpdateApplicationMenu(void *inctx) {
|
void UpdateApplicationMenu(void *inctx) {
|
||||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
NSApplication *app = [NSApplication sharedApplication];
|
NSApplication *app = [NSApplication sharedApplication];
|
||||||
[app setMainMenu:ctx.applicationMenu];
|
[app setMainMenu:ctx.applicationMenu];
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -327,7 +381,7 @@ void UpdateMenuItem(void* nsmenuitem, int checked) {
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
WailsMenuItem *menuItem = (__bridge WailsMenuItem*) nsmenuitem;
|
WailsMenuItem *menuItem = (__bridge WailsMenuItem*) nsmenuitem;
|
||||||
[menuItem setState:(checked == 1?NSControlStateValueOn:NSControlStateValueOff)];
|
[menuItem setState:(checked == 1?NSControlStateValueOn:NSControlStateValueOff)];
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -336,12 +390,39 @@ void AppendSeparator(void* inMenu) {
|
||||||
[menu AppendSeparator];
|
[menu AppendSeparator];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetTrayImage(void *nsStatusItem, void *imageData, int imageDataLength, int template, int position) {
|
||||||
|
ON_MAIN_THREAD(
|
||||||
|
NSStatusItem *statusItem = (NSStatusItem*) nsStatusItem;
|
||||||
|
NSData *nsdata = [NSData dataWithBytes:imageData length:imageDataLength];
|
||||||
|
NSImage *image = [[[NSImage alloc] initWithData:nsdata] autorelease];
|
||||||
|
if(template) {
|
||||||
|
image.template = true;
|
||||||
|
}
|
||||||
|
image.size = NSMakeSize(22.0, 22.0);
|
||||||
|
statusItem.button.image = image;
|
||||||
|
|
||||||
|
// Swap NSNoImage and NSImageLeading because we wanted NSImageLeading to be default in Go
|
||||||
|
int actualPosition = position;
|
||||||
|
if( position == 7) {
|
||||||
|
actualPosition = 0;
|
||||||
|
} else if (position == 0) {
|
||||||
|
actualPosition = 7;
|
||||||
|
}
|
||||||
|
[statusItem.button setImagePosition:actualPosition];
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
int ScalingFactor(void *ctx) {
|
||||||
|
CGFloat scale = [((WailsContext*)ctx).mainWindow backingScaleFactor];
|
||||||
|
return (int)scale;
|
||||||
|
}
|
||||||
|
|
||||||
void Run(void *inctx, const char* url) {
|
void Run(void *inctx, const char* url, int activationPolicy) {
|
||||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||||
NSApplication *app = [NSApplication sharedApplication];
|
NSApplication *app = [NSApplication sharedApplication];
|
||||||
AppDelegate* delegate = [AppDelegate new];
|
AppDelegate* delegate = [AppDelegate new];
|
||||||
|
delegate.activationPolicy = activationPolicy;
|
||||||
[app setDelegate:(id)delegate];
|
[app setDelegate:(id)delegate];
|
||||||
ctx.appdelegate = delegate;
|
ctx.appdelegate = delegate;
|
||||||
delegate.mainWindow = ctx.mainWindow;
|
delegate.mainWindow = ctx.mainWindow;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
@property NSSize userMinSize;
|
@property NSSize userMinSize;
|
||||||
@property NSSize userMaxSize;
|
@property NSSize userMaxSize;
|
||||||
|
@property int activationPolicy;
|
||||||
|
|
||||||
- (BOOL) canBecomeKeyWindow;
|
- (BOOL) canBecomeKeyWindow;
|
||||||
- (void) applyWindowConstraints;
|
- (void) applyWindowConstraints;
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,6 @@
|
||||||
|
|
||||||
package darwin
|
package darwin
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo CFLAGS: -x objective-c
|
|
||||||
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import "Application.h"
|
|
||||||
#import "WailsContext.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
@ -31,14 +22,33 @@ import (
|
||||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||||
"github.com/wailsapp/wails/v2/internal/frontend/assetserver"
|
"github.com/wailsapp/wails/v2/internal/frontend/assetserver"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -x objective-c
|
||||||
|
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "Application.h"
|
||||||
|
#import "WailsContext.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
const startURL = "wails://wails/"
|
const startURL = "wails://wails/"
|
||||||
|
|
||||||
|
type NotificationType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
ApplicationDidFinishLaunching NotificationType = 0
|
||||||
|
)
|
||||||
|
|
||||||
var messageBuffer = make(chan string, 100)
|
var messageBuffer = make(chan string, 100)
|
||||||
var requestBuffer = make(chan *request, 100)
|
var requestBuffer = make(chan *request, 100)
|
||||||
var callbackBuffer = make(chan uint, 10)
|
var callbackBuffer = make(chan uint, 10)
|
||||||
|
var notificationBuffer = make(chan NotificationType, 10)
|
||||||
|
|
||||||
type Frontend struct {
|
type Frontend struct {
|
||||||
|
|
||||||
|
|
@ -57,15 +67,22 @@ type Frontend struct {
|
||||||
mainWindow *Window
|
mainWindow *Window
|
||||||
bindings *binding.Bindings
|
bindings *binding.Bindings
|
||||||
dispatcher frontend.Dispatcher
|
dispatcher frontend.Dispatcher
|
||||||
|
trayMenus map[*menu.TrayMenu]*NSTrayMenu
|
||||||
|
|
||||||
|
applicationDidFinishLaunching bool
|
||||||
|
notificationCallbacks map[NotificationType][]func()
|
||||||
|
trayMenusBuffer []*menu.TrayMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) *Frontend {
|
func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) *Frontend {
|
||||||
result := &Frontend{
|
result := &Frontend{
|
||||||
frontendOptions: appoptions,
|
frontendOptions: appoptions,
|
||||||
logger: myLogger,
|
logger: myLogger,
|
||||||
bindings: appBindings,
|
bindings: appBindings,
|
||||||
dispatcher: dispatcher,
|
dispatcher: dispatcher,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
|
trayMenus: make(map[*menu.TrayMenu]*NSTrayMenu),
|
||||||
|
notificationCallbacks: make(map[NotificationType][]func()),
|
||||||
}
|
}
|
||||||
result.startURL, _ = url.Parse(startURL)
|
result.startURL, _ = url.Parse(startURL)
|
||||||
|
|
||||||
|
|
@ -88,10 +105,17 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
|
||||||
|
|
||||||
go result.startMessageProcessor()
|
go result.startMessageProcessor()
|
||||||
go result.startCallbackProcessor()
|
go result.startCallbackProcessor()
|
||||||
|
go result.startNotificationsProcessor()
|
||||||
|
|
||||||
|
result.registerNotificationCallback(ApplicationDidFinishLaunching, result.processTrayMenus)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Frontend) registerNotificationCallback(notificationType NotificationType, callback func()) {
|
||||||
|
f.notificationCallbacks[notificationType] = append(f.notificationCallbacks[notificationType], callback)
|
||||||
|
}
|
||||||
|
|
||||||
func (f *Frontend) startMessageProcessor() {
|
func (f *Frontend) startMessageProcessor() {
|
||||||
for message := range messageBuffer {
|
for message := range messageBuffer {
|
||||||
f.processMessage(message)
|
f.processMessage(message)
|
||||||
|
|
@ -110,6 +134,11 @@ func (f *Frontend) startCallbackProcessor() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func (f *Frontend) startNotificationsProcessor() {
|
||||||
|
for notification := range notificationBuffer {
|
||||||
|
f.handleNotification(notification)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (f *Frontend) WindowReload() {
|
func (f *Frontend) WindowReload() {
|
||||||
f.ExecJS("runtime.WindowReload();")
|
f.ExecJS("runtime.WindowReload();")
|
||||||
|
|
@ -149,7 +178,11 @@ func (f *Frontend) Run(ctx context.Context) error {
|
||||||
f.frontendOptions.OnStartup(f.ctx)
|
f.frontendOptions.OnStartup(f.ctx)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
mainWindow.Run(f.startURL.String())
|
var activationPolicy C.int
|
||||||
|
if f.frontendOptions != nil && f.frontendOptions.Mac != nil {
|
||||||
|
activationPolicy = C.int(f.frontendOptions.Mac.ActivationPolicy)
|
||||||
|
}
|
||||||
|
mainWindow.Run(f.startURL.String(), activationPolicy)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -396,6 +429,11 @@ func processMessage(message *C.char) {
|
||||||
messageBuffer <- goMessage
|
messageBuffer <- goMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//export processNotification
|
||||||
|
func processNotification(notification NotificationType) {
|
||||||
|
notificationBuffer <- notification
|
||||||
|
}
|
||||||
|
|
||||||
//export processURLRequest
|
//export processURLRequest
|
||||||
func processURLRequest(ctx unsafe.Pointer, url *C.char, method *C.char, headers *C.char, body unsafe.Pointer, bodyLen C.int) {
|
func processURLRequest(ctx unsafe.Pointer, url *C.char, method *C.char, headers *C.char, body unsafe.Pointer, bodyLen C.int) {
|
||||||
var goBody []byte
|
var goBody []byte
|
||||||
|
|
@ -416,3 +454,19 @@ func processURLRequest(ctx unsafe.Pointer, url *C.char, method *C.char, headers
|
||||||
func processCallback(callbackID uint) {
|
func processCallback(callbackID uint) {
|
||||||
callbackBuffer <- callbackID
|
callbackBuffer <- callbackID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Frontend) handleNotification(notification NotificationType) {
|
||||||
|
switch notification {
|
||||||
|
case ApplicationDidFinishLaunching:
|
||||||
|
f.applicationDidFinishLaunching = true
|
||||||
|
for _, callback := range f.notificationCallbacks[notification] {
|
||||||
|
go callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Frontend) processTrayMenus() {
|
||||||
|
for _, trayMenu := range f.trayMenusBuffer {
|
||||||
|
f.mainWindow.TrayMenuAdd(trayMenu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,86 @@ package darwin
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
"github.com/wailsapp/wails/v2/pkg/menu/keys"
|
"github.com/wailsapp/wails/v2/pkg/menu/keys"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var createNSObjectMap = make(map[uint32]chan unsafe.Pointer)
|
||||||
|
var createNSObjectMapLock sync.RWMutex
|
||||||
|
|
||||||
|
func waitNSObjectCreate(id uint32, fn func()) unsafe.Pointer {
|
||||||
|
waitchan := make(chan unsafe.Pointer)
|
||||||
|
createNSObjectMapLock.Lock()
|
||||||
|
createNSObjectMap[id] = waitchan
|
||||||
|
createNSObjectMapLock.Unlock()
|
||||||
|
fn()
|
||||||
|
result := <-waitchan
|
||||||
|
createNSObjectMapLock.Lock()
|
||||||
|
createNSObjectMap[id] = nil
|
||||||
|
createNSObjectMapLock.Unlock()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
//export objectCreated
|
||||||
|
func objectCreated(id uint32, pointer unsafe.Pointer) {
|
||||||
|
createNSObjectMapLock.Lock()
|
||||||
|
createNSObjectMap[id] <- pointer
|
||||||
|
createNSObjectMapLock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNSTrayMenu(context unsafe.Pointer, trayMenu *menu.TrayMenu, scalingFactor int) *NSTrayMenu {
|
||||||
|
c := NewCalloc()
|
||||||
|
defer c.Free()
|
||||||
|
|
||||||
|
id := uuid.New().ID()
|
||||||
|
nsStatusItem := waitNSObjectCreate(id, func() {
|
||||||
|
C.NewNSStatusItem(C.int(id), C.int(trayMenu.Sizing))
|
||||||
|
})
|
||||||
|
result := &NSTrayMenu{
|
||||||
|
context: context,
|
||||||
|
nsStatusItem: nsStatusItem,
|
||||||
|
scalingFactor: scalingFactor,
|
||||||
|
}
|
||||||
|
|
||||||
|
result.SetLabel(trayMenu.Label)
|
||||||
|
result.SetMenu(trayMenu.Menu)
|
||||||
|
result.SetImage(trayMenu.Image)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NSTrayMenu) SetImage(image *menu.TrayImage) {
|
||||||
|
if image == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bitmap := image.GetBestBitmap(n.scalingFactor, false)
|
||||||
|
if bitmap == nil {
|
||||||
|
fmt.Printf("[Warning] No TrayMenu Image available for scaling factor %dx\n", n.scalingFactor)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
C.SetTrayImage(n.nsStatusItem,
|
||||||
|
unsafe.Pointer(&bitmap[0]),
|
||||||
|
C.int(len(bitmap)),
|
||||||
|
bool2Cint(image.IsTemplate),
|
||||||
|
C.int(image.Position),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NSTrayMenu) SetMenu(menu *menu.Menu) {
|
||||||
|
if menu == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
theMenu := NewNSMenu(n.context, "")
|
||||||
|
processMenu(theMenu, menu)
|
||||||
|
C.SetTrayMenu(n.nsStatusItem, theMenu.nsmenu)
|
||||||
|
}
|
||||||
|
|
||||||
type NSMenu struct {
|
type NSMenu struct {
|
||||||
context unsafe.Pointer
|
context unsafe.Pointer
|
||||||
nsmenu unsafe.Pointer
|
nsmenu unsafe.Pointer
|
||||||
|
|
@ -53,6 +127,15 @@ type MenuItem struct {
|
||||||
radioGroupMembers []*MenuItem
|
radioGroupMembers []*MenuItem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MenuItem) SetChecked(value bool) {
|
||||||
|
C.SetMenuItemChecked(m.nsmenuitem, bool2Cint(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MenuItem) SetLabel(label string) {
|
||||||
|
cLabel := C.CString(label)
|
||||||
|
C.SetMenuItemLabel(m.nsmenuitem, cLabel)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *NSMenu) AddMenuItem(menuItem *menu.MenuItem) *MenuItem {
|
func (m *NSMenu) AddMenuItem(menuItem *menu.MenuItem) *MenuItem {
|
||||||
c := NewCalloc()
|
c := NewCalloc()
|
||||||
defer c.Free()
|
defer c.Free()
|
||||||
|
|
@ -69,6 +152,7 @@ func (m *NSMenu) AddMenuItem(menuItem *menu.MenuItem) *MenuItem {
|
||||||
|
|
||||||
result.id = createMenuItemID(result)
|
result.id = createMenuItemID(result)
|
||||||
result.nsmenuitem = C.AppendMenuItem(m.context, m.nsmenu, c.String(menuItem.Label), key, modifier, bool2Cint(menuItem.Disabled), bool2Cint(menuItem.Checked), C.int(result.id))
|
result.nsmenuitem = C.AppendMenuItem(m.context, m.nsmenu, c.String(menuItem.Label), key, modifier, bool2Cint(menuItem.Disabled), bool2Cint(menuItem.Checked), C.int(result.id))
|
||||||
|
menuItem.Impl = result
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ void processMessageDialogResponse(int);
|
||||||
void processOpenFileDialogResponse(const char*);
|
void processOpenFileDialogResponse(const char*);
|
||||||
void processSaveFileDialogResponse(const char*);
|
void processSaveFileDialogResponse(const char*);
|
||||||
void processCallback(int);
|
void processCallback(int);
|
||||||
|
void processNotification(int);
|
||||||
|
void objectCreated(int, void*);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
44
v2/internal/frontend/desktop/darwin/traymenu.go
Normal file
44
v2/internal/frontend/desktop/darwin/traymenu.go
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
//go:build darwin
|
||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package darwin
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -x objective-c
|
||||||
|
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "Application.h"
|
||||||
|
#import "WailsContext.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (f *Frontend) TrayMenuAdd(trayMenu *menu.TrayMenu) menu.TrayMenuImpl {
|
||||||
|
nsTrayMenu := f.mainWindow.TrayMenuAdd(trayMenu)
|
||||||
|
f.trayMenus[trayMenu] = nsTrayMenu
|
||||||
|
return nsTrayMenu
|
||||||
|
}
|
||||||
|
|
||||||
|
type NSTrayMenu struct {
|
||||||
|
context unsafe.Pointer
|
||||||
|
nsStatusItem unsafe.Pointer // NSStatusItem
|
||||||
|
scalingFactor int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NSTrayMenu) SetLabel(label string) {
|
||||||
|
if label == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cLabel := C.CString(label)
|
||||||
|
C.SetTrayMenuLabel(n.nsStatusItem, cLabel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Window) TrayMenuAdd(trayMenu *menu.TrayMenu) *NSTrayMenu {
|
||||||
|
return NewNSTrayMenu(w.context, trayMenu, ScalingFactor(w))
|
||||||
|
}
|
||||||
|
|
@ -40,6 +40,10 @@ func bool2Cint(value bool) C.int {
|
||||||
return C.int(0)
|
return C.int(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ScalingFactor(window *Window) int {
|
||||||
|
return int(C.ScalingFactor(window.context))
|
||||||
|
}
|
||||||
|
|
||||||
func NewWindow(frontendOptions *options.App, debugMode bool) *Window {
|
func NewWindow(frontendOptions *options.App, debugMode bool) *Window {
|
||||||
|
|
||||||
c := NewCalloc()
|
c := NewCalloc()
|
||||||
|
|
@ -119,9 +123,9 @@ func (w *Window) Center() {
|
||||||
C.Center(w.context)
|
C.Center(w.context)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Window) Run(url string) {
|
func (w *Window) Run(url string, activationPolicy C.int) {
|
||||||
_url := C.CString(url)
|
_url := C.CString(url)
|
||||||
C.Run(w.context, _url)
|
C.Run(w.context, _url, activationPolicy)
|
||||||
C.free(unsafe.Pointer(_url))
|
C.free(unsafe.Pointer(_url))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
36
v2/internal/frontend/desktop/windows/png.go
Normal file
36
v2/internal/frontend/desktop/windows/png.go
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"golang.org/x/image/draw"
|
||||||
|
"image"
|
||||||
|
"image/png"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ResizePNG(in []byte, size int) ([]byte, error) {
|
||||||
|
imagedata, _, err := image.Decode(bytes.NewReader(in))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Scale image
|
||||||
|
rect := image.Rect(0, 0, size, size)
|
||||||
|
rawdata := image.NewRGBA(rect)
|
||||||
|
scale := draw.CatmullRom
|
||||||
|
scale.Scale(rawdata, rect, imagedata, imagedata.Bounds(), draw.Over, nil)
|
||||||
|
|
||||||
|
// Convert back to PNG
|
||||||
|
icondata := new(bytes.Buffer)
|
||||||
|
writer := bufio.NewWriter(icondata)
|
||||||
|
err = png.Encode(writer, rawdata)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = writer.Flush()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save image data
|
||||||
|
return icondata.Bytes(), nil
|
||||||
|
}
|
||||||
79
v2/internal/frontend/desktop/windows/traymenu.go
Normal file
79
v2/internal/frontend/desktop/windows/traymenu.go
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/win32"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var uids uint32
|
||||||
|
var lock sync.RWMutex
|
||||||
|
|
||||||
|
func newUID() uint32 {
|
||||||
|
lock.Lock()
|
||||||
|
result := uids
|
||||||
|
uids++
|
||||||
|
lock.Unlock()
|
||||||
|
return result
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type Win32TrayMenu struct {
|
||||||
|
hwnd uintptr
|
||||||
|
uid uint32
|
||||||
|
icon uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Win32TrayMenu) SetLabel(label string) {}
|
||||||
|
|
||||||
|
func (w *Win32TrayMenu) SetMenu(menu *menu.Menu) {}
|
||||||
|
|
||||||
|
func (w *Win32TrayMenu) SetImage(image *menu.TrayImage) {
|
||||||
|
data := w.newNotifyIconData()
|
||||||
|
bitmap := image.GetBestBitmap(1, false)
|
||||||
|
icon, err := win32.CreateIconFromResourceEx(uintptr(unsafe.Pointer(&bitmap[0])), uint32(len(bitmap)), true, 0x30000, 0, 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
data.UFlags |= win32.NIF_ICON
|
||||||
|
data.HIcon = icon
|
||||||
|
if _, err := win32.NotifyIcon(win32.NIM_MODIFY, data); err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Frontend) NewWin32TrayMenu(trayMenu *menu.TrayMenu) *Win32TrayMenu {
|
||||||
|
|
||||||
|
result := &Win32TrayMenu{
|
||||||
|
hwnd: f.mainWindow.Handle(),
|
||||||
|
uid: newUID(),
|
||||||
|
}
|
||||||
|
|
||||||
|
data := result.newNotifyIconData()
|
||||||
|
data.UFlags |= win32.NIF_MESSAGE | win32.NIF_ICON
|
||||||
|
data.UCallbackMessage = win32.WM_APP + result.uid
|
||||||
|
if _, err := win32.NotifyIcon(win32.NIM_ADD, data); err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Win32TrayMenu) newNotifyIconData() *win32.NOTIFYICONDATA {
|
||||||
|
var data win32.NOTIFYICONDATA
|
||||||
|
data.CbSize = uint32(unsafe.Sizeof(data))
|
||||||
|
data.UFlags = win32.NIF_GUID
|
||||||
|
data.HWnd = w.hwnd
|
||||||
|
data.UID = w.uid
|
||||||
|
return &data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Frontend) TrayMenuAdd(trayMenu *menu.TrayMenu) menu.TrayMenuImpl {
|
||||||
|
win32TrayMenu := f.NewWin32TrayMenu(trayMenu)
|
||||||
|
return win32TrayMenu
|
||||||
|
}
|
||||||
|
|
@ -12,12 +12,21 @@ type HRESULT int32
|
||||||
type HANDLE uintptr
|
type HANDLE uintptr
|
||||||
|
|
||||||
var (
|
var (
|
||||||
moduser32 = syscall.NewLazyDLL("user32.dll")
|
moduser32 = syscall.NewLazyDLL("user32.dll")
|
||||||
procSystemParametersInfo = moduser32.NewProc("SystemParametersInfoW")
|
procSystemParametersInfo = moduser32.NewProc("SystemParametersInfoW")
|
||||||
procGetWindowLong = moduser32.NewProc("GetWindowLongW")
|
procGetWindowLong = moduser32.NewProc("GetWindowLongW")
|
||||||
procSetClassLong = moduser32.NewProc("SetClassLongW")
|
procSetClassLong = moduser32.NewProc("SetClassLongW")
|
||||||
procSetClassLongPtr = moduser32.NewProc("SetClassLongPtrW")
|
procSetClassLongPtr = moduser32.NewProc("SetClassLongPtrW")
|
||||||
procShowWindow = moduser32.NewProc("ShowWindow")
|
procShowWindow = moduser32.NewProc("ShowWindow")
|
||||||
|
procLookupIconIdFromDirectoryEx = moduser32.NewProc("LookupIconIdFromDirectoryEx")
|
||||||
|
procCreateIconFromResourceEx = moduser32.NewProc("CreateIconFromResourceEx")
|
||||||
|
procCreateIconIndirect = moduser32.NewProc("CreateIconIndirect")
|
||||||
|
procLoadImageW = moduser32.NewProc("LoadImageW")
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
modshell32 = syscall.NewLazyDLL("shell32.dll")
|
||||||
|
procShellNotifyIcon = modshell32.NewProc("Shell_NotifyIconW")
|
||||||
)
|
)
|
||||||
var (
|
var (
|
||||||
moddwmapi = syscall.NewLazyDLL("dwmapi.dll")
|
moddwmapi = syscall.NewLazyDLL("dwmapi.dll")
|
||||||
|
|
@ -36,3 +45,217 @@ func IsWindowsVersionAtLeast(major, minor, buildNumber int) bool {
|
||||||
windowsVersion.Minor >= minor &&
|
windowsVersion.Minor >= minor &&
|
||||||
windowsVersion.Build >= buildNumber
|
windowsVersion.Build >= buildNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931.aspx
|
||||||
|
type GUID struct {
|
||||||
|
Data1 uint32
|
||||||
|
Data2 uint16
|
||||||
|
Data3 uint16
|
||||||
|
Data4 [8]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
WM_APP = 32768
|
||||||
|
WM_ACTIVATE = 6
|
||||||
|
WM_ACTIVATEAPP = 28
|
||||||
|
WM_AFXFIRST = 864
|
||||||
|
WM_AFXLAST = 895
|
||||||
|
WM_ASKCBFORMATNAME = 780
|
||||||
|
WM_CANCELJOURNAL = 75
|
||||||
|
WM_CANCELMODE = 31
|
||||||
|
WM_CAPTURECHANGED = 533
|
||||||
|
WM_CHANGECBCHAIN = 781
|
||||||
|
WM_CHAR = 258
|
||||||
|
WM_CHARTOITEM = 47
|
||||||
|
WM_CHILDACTIVATE = 34
|
||||||
|
WM_CLEAR = 771
|
||||||
|
WM_CLOSE = 16
|
||||||
|
WM_COMMAND = 273
|
||||||
|
WM_COMMNOTIFY = 68 /* OBSOLETE */
|
||||||
|
WM_COMPACTING = 65
|
||||||
|
WM_COMPAREITEM = 57
|
||||||
|
WM_CONTEXTMENU = 123
|
||||||
|
WM_COPY = 769
|
||||||
|
WM_COPYDATA = 74
|
||||||
|
WM_CREATE = 1
|
||||||
|
WM_CTLCOLORBTN = 309
|
||||||
|
WM_CTLCOLORDLG = 310
|
||||||
|
WM_CTLCOLOREDIT = 307
|
||||||
|
WM_CTLCOLORLISTBOX = 308
|
||||||
|
WM_CTLCOLORMSGBOX = 306
|
||||||
|
WM_CTLCOLORSCROLLBAR = 311
|
||||||
|
WM_CTLCOLORSTATIC = 312
|
||||||
|
WM_CUT = 768
|
||||||
|
WM_DEADCHAR = 259
|
||||||
|
WM_DELETEITEM = 45
|
||||||
|
WM_DESTROY = 2
|
||||||
|
WM_DESTROYCLIPBOARD = 775
|
||||||
|
WM_DEVICECHANGE = 537
|
||||||
|
WM_DEVMODECHANGE = 27
|
||||||
|
WM_DISPLAYCHANGE = 126
|
||||||
|
WM_DRAWCLIPBOARD = 776
|
||||||
|
WM_DRAWITEM = 43
|
||||||
|
WM_DROPFILES = 563
|
||||||
|
WM_ENABLE = 10
|
||||||
|
WM_ENDSESSION = 22
|
||||||
|
WM_ENTERIDLE = 289
|
||||||
|
WM_ENTERMENULOOP = 529
|
||||||
|
WM_ENTERSIZEMOVE = 561
|
||||||
|
WM_ERASEBKGND = 20
|
||||||
|
WM_EXITMENULOOP = 530
|
||||||
|
WM_EXITSIZEMOVE = 562
|
||||||
|
WM_FONTCHANGE = 29
|
||||||
|
WM_GETDLGCODE = 135
|
||||||
|
WM_GETFONT = 49
|
||||||
|
WM_GETHOTKEY = 51
|
||||||
|
WM_GETICON = 127
|
||||||
|
WM_GETMINMAXINFO = 36
|
||||||
|
WM_GETTEXT = 13
|
||||||
|
WM_GETTEXTLENGTH = 14
|
||||||
|
WM_HANDHELDFIRST = 856
|
||||||
|
WM_HANDHELDLAST = 863
|
||||||
|
WM_HELP = 83
|
||||||
|
WM_HOTKEY = 786
|
||||||
|
WM_HSCROLL = 276
|
||||||
|
WM_HSCROLLCLIPBOARD = 782
|
||||||
|
WM_ICONERASEBKGND = 39
|
||||||
|
WM_INITDIALOG = 272
|
||||||
|
WM_INITMENU = 278
|
||||||
|
WM_INITMENUPOPUP = 279
|
||||||
|
WM_INPUT = 0x00FF
|
||||||
|
WM_INPUTLANGCHANGE = 81
|
||||||
|
WM_INPUTLANGCHANGEREQUEST = 80
|
||||||
|
WM_KEYDOWN = 256
|
||||||
|
WM_KEYUP = 257
|
||||||
|
WM_KILLFOCUS = 8
|
||||||
|
WM_MDIACTIVATE = 546
|
||||||
|
WM_MDICASCADE = 551
|
||||||
|
WM_MDICREATE = 544
|
||||||
|
WM_MDIDESTROY = 545
|
||||||
|
WM_MDIGETACTIVE = 553
|
||||||
|
WM_MDIICONARRANGE = 552
|
||||||
|
WM_MDIMAXIMIZE = 549
|
||||||
|
WM_MDINEXT = 548
|
||||||
|
WM_MDIREFRESHMENU = 564
|
||||||
|
WM_MDIRESTORE = 547
|
||||||
|
WM_MDISETMENU = 560
|
||||||
|
WM_MDITILE = 550
|
||||||
|
WM_MEASUREITEM = 44
|
||||||
|
WM_GETOBJECT = 0x003D
|
||||||
|
WM_CHANGEUISTATE = 0x0127
|
||||||
|
WM_UPDATEUISTATE = 0x0128
|
||||||
|
WM_QUERYUISTATE = 0x0129
|
||||||
|
WM_UNINITMENUPOPUP = 0x0125
|
||||||
|
WM_MENURBUTTONUP = 290
|
||||||
|
WM_MENUCOMMAND = 0x0126
|
||||||
|
WM_MENUGETOBJECT = 0x0124
|
||||||
|
WM_MENUDRAG = 0x0123
|
||||||
|
WM_APPCOMMAND = 0x0319
|
||||||
|
WM_MENUCHAR = 288
|
||||||
|
WM_MENUSELECT = 287
|
||||||
|
WM_MOVE = 3
|
||||||
|
WM_MOVING = 534
|
||||||
|
WM_NCACTIVATE = 134
|
||||||
|
WM_NCCALCSIZE = 131
|
||||||
|
WM_NCCREATE = 129
|
||||||
|
WM_NCDESTROY = 130
|
||||||
|
WM_NCHITTEST = 132
|
||||||
|
WM_NCLBUTTONDBLCLK = 163
|
||||||
|
WM_NCLBUTTONDOWN = 161
|
||||||
|
WM_NCLBUTTONUP = 162
|
||||||
|
WM_NCMBUTTONDBLCLK = 169
|
||||||
|
WM_NCMBUTTONDOWN = 167
|
||||||
|
WM_NCMBUTTONUP = 168
|
||||||
|
WM_NCXBUTTONDOWN = 171
|
||||||
|
WM_NCXBUTTONUP = 172
|
||||||
|
WM_NCXBUTTONDBLCLK = 173
|
||||||
|
WM_NCMOUSEHOVER = 0x02A0
|
||||||
|
WM_NCMOUSELEAVE = 0x02A2
|
||||||
|
WM_NCMOUSEMOVE = 160
|
||||||
|
WM_NCPAINT = 133
|
||||||
|
WM_NCRBUTTONDBLCLK = 166
|
||||||
|
WM_NCRBUTTONDOWN = 164
|
||||||
|
WM_NCRBUTTONUP = 165
|
||||||
|
WM_NEXTDLGCTL = 40
|
||||||
|
WM_NEXTMENU = 531
|
||||||
|
WM_NOTIFY = 78
|
||||||
|
WM_NOTIFYFORMAT = 85
|
||||||
|
WM_NULL = 0
|
||||||
|
WM_PAINT = 15
|
||||||
|
WM_PAINTCLIPBOARD = 777
|
||||||
|
WM_PAINTICON = 38
|
||||||
|
WM_PALETTECHANGED = 785
|
||||||
|
WM_PALETTEISCHANGING = 784
|
||||||
|
WM_PARENTNOTIFY = 528
|
||||||
|
WM_PASTE = 770
|
||||||
|
WM_PENWINFIRST = 896
|
||||||
|
WM_PENWINLAST = 911
|
||||||
|
WM_POWER = 72
|
||||||
|
WM_PRINT = 791
|
||||||
|
WM_PRINTCLIENT = 792
|
||||||
|
WM_QUERYDRAGICON = 55
|
||||||
|
WM_QUERYENDSESSION = 17
|
||||||
|
WM_QUERYNEWPALETTE = 783
|
||||||
|
WM_QUERYOPEN = 19
|
||||||
|
WM_QUEUESYNC = 35
|
||||||
|
WM_QUIT = 18
|
||||||
|
WM_RENDERALLFORMATS = 774
|
||||||
|
WM_RENDERFORMAT = 773
|
||||||
|
WM_SETCURSOR = 32
|
||||||
|
WM_SETFOCUS = 7
|
||||||
|
WM_SETFONT = 48
|
||||||
|
WM_SETHOTKEY = 50
|
||||||
|
WM_SETICON = 128
|
||||||
|
WM_SETREDRAW = 11
|
||||||
|
WM_SETTEXT = 12
|
||||||
|
WM_SETTINGCHANGE = 26
|
||||||
|
WM_SHOWWINDOW = 24
|
||||||
|
WM_SIZE = 5
|
||||||
|
WM_SIZECLIPBOARD = 779
|
||||||
|
WM_SIZING = 532
|
||||||
|
WM_SPOOLERSTATUS = 42
|
||||||
|
WM_STYLECHANGED = 125
|
||||||
|
WM_STYLECHANGING = 124
|
||||||
|
WM_SYSCHAR = 262
|
||||||
|
WM_SYSCOLORCHANGE = 21
|
||||||
|
WM_SYSCOMMAND = 274
|
||||||
|
WM_SYSDEADCHAR = 263
|
||||||
|
WM_SYSKEYDOWN = 260
|
||||||
|
WM_SYSKEYUP = 261
|
||||||
|
WM_TCARD = 82
|
||||||
|
WM_THEMECHANGED = 794
|
||||||
|
WM_TIMECHANGE = 30
|
||||||
|
WM_TIMER = 275
|
||||||
|
WM_UNDO = 772
|
||||||
|
WM_USER = 1024
|
||||||
|
WM_USERCHANGED = 84
|
||||||
|
WM_VKEYTOITEM = 46
|
||||||
|
WM_VSCROLL = 277
|
||||||
|
WM_VSCROLLCLIPBOARD = 778
|
||||||
|
WM_WINDOWPOSCHANGED = 71
|
||||||
|
WM_WINDOWPOSCHANGING = 70
|
||||||
|
WM_WININICHANGE = 26
|
||||||
|
WM_KEYFIRST = 256
|
||||||
|
WM_KEYLAST = 264
|
||||||
|
WM_SYNCPAINT = 136
|
||||||
|
WM_MOUSEACTIVATE = 33
|
||||||
|
WM_MOUSEMOVE = 512
|
||||||
|
WM_LBUTTONDOWN = 513
|
||||||
|
WM_LBUTTONUP = 514
|
||||||
|
WM_LBUTTONDBLCLK = 515
|
||||||
|
WM_RBUTTONDOWN = 516
|
||||||
|
WM_RBUTTONUP = 517
|
||||||
|
WM_RBUTTONDBLCLK = 518
|
||||||
|
WM_MBUTTONDOWN = 519
|
||||||
|
WM_MBUTTONUP = 520
|
||||||
|
WM_MBUTTONDBLCLK = 521
|
||||||
|
WM_MOUSEWHEEL = 522
|
||||||
|
WM_MOUSEFIRST = 512
|
||||||
|
WM_XBUTTONDOWN = 523
|
||||||
|
WM_XBUTTONUP = 524
|
||||||
|
WM_XBUTTONDBLCLK = 525
|
||||||
|
WM_MOUSELAST = 525
|
||||||
|
WM_MOUSEHOVER = 0x2A1
|
||||||
|
WM_MOUSELEAVE = 0x2A3
|
||||||
|
WM_CLIPBOARDUPDATE = 0x031D
|
||||||
|
)
|
||||||
|
|
|
||||||
130
v2/internal/frontend/desktop/windows/win32/tray.go
Normal file
130
v2/internal/frontend/desktop/windows/win32/tray.go
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
package win32
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
const (
|
||||||
|
NIF_MESSAGE = 0x00000001
|
||||||
|
NIF_ICON = 0x00000002
|
||||||
|
NIF_TIP = 0x00000004
|
||||||
|
NIF_STATE = 0x00000008
|
||||||
|
NIF_INFO = 0x00000010
|
||||||
|
NIF_GUID = 0x00000020
|
||||||
|
NIF_REALTIME = 0x00000040
|
||||||
|
NIF_SHOWTIP = 0x00000080
|
||||||
|
NIM_ADD = 0x00000000
|
||||||
|
NIM_MODIFY = 0x00000001
|
||||||
|
NIM_DELETE = 0x00000002
|
||||||
|
NIM_SETFOCUS = 0x00000003
|
||||||
|
NIM_SETVERSION = 0x00000004
|
||||||
|
NIS_HIDDEN = 0x00000001
|
||||||
|
NIS_SHAREDICON = 0x00000002
|
||||||
|
NIN_BALLOONSHOW = 0x0402
|
||||||
|
NIN_BALLOONTIMEOUT = 0x0404
|
||||||
|
NIN_BALLOONUSERCLICK = 0x0405
|
||||||
|
NIIF_NONE = 0x00000000
|
||||||
|
NIIF_INFO = 0x00000001
|
||||||
|
NIIF_WARNING = 0x00000002
|
||||||
|
NIIF_ERROR = 0x00000003
|
||||||
|
NIIF_USER = 0x00000004
|
||||||
|
NIIF_NOSOUND = 0x00000010
|
||||||
|
NIIF_LARGE_ICON = 0x00000020
|
||||||
|
NIIF_RESPECT_QUIET_TIME = 0x00000080
|
||||||
|
NIIF_ICON_MASK = 0x0000000F
|
||||||
|
)
|
||||||
|
|
||||||
|
type NOTIFYICONDATA struct {
|
||||||
|
CbSize uint32
|
||||||
|
HWnd uintptr
|
||||||
|
UID uint32
|
||||||
|
UFlags uint32
|
||||||
|
UCallbackMessage uint32
|
||||||
|
HIcon uintptr
|
||||||
|
SzTip [128]uint16
|
||||||
|
DwState uint32
|
||||||
|
DwStateMask uint32
|
||||||
|
SzInfo [256]uint16
|
||||||
|
UVersion uint32
|
||||||
|
SzInfoTitle [64]uint16
|
||||||
|
DwInfoFlags uint32
|
||||||
|
GUIDItem GUID
|
||||||
|
HBalloonIcon uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
func NotifyIcon(msg uint32, lpData *NOTIFYICONDATA) (int32, error) {
|
||||||
|
r, _, err := procShellNotifyIcon.Call(
|
||||||
|
uintptr(msg),
|
||||||
|
uintptr(unsafe.Pointer(lpData)))
|
||||||
|
if r == 0 {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int32(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func LookupIconIdFromDirectoryEx(presbits uintptr, isIcon bool, cxDesired int, cyDesired int, flags uint) (int32, error) {
|
||||||
|
var icon uint32 = 0
|
||||||
|
if isIcon {
|
||||||
|
icon = 1
|
||||||
|
}
|
||||||
|
r, _, err := procLookupIconIdFromDirectoryEx.Call(
|
||||||
|
presbits,
|
||||||
|
uintptr(icon),
|
||||||
|
uintptr(cxDesired),
|
||||||
|
uintptr(cyDesired),
|
||||||
|
uintptr(flags),
|
||||||
|
)
|
||||||
|
if r == 0 {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int32(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateIconIndirect(data uintptr) (uintptr, error) {
|
||||||
|
r, _, err := procCreateIconIndirect.Call(
|
||||||
|
data,
|
||||||
|
)
|
||||||
|
|
||||||
|
if r == 0 {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateIconFromResourceEx(presbits uintptr, dwResSize uint32, isIcon bool, version uint32, cxDesired int, cyDesired int, flags uint) (uintptr, error) {
|
||||||
|
icon := 0
|
||||||
|
if isIcon {
|
||||||
|
icon = 1
|
||||||
|
}
|
||||||
|
r, _, err := procCreateIconFromResourceEx.Call(
|
||||||
|
presbits,
|
||||||
|
uintptr(dwResSize),
|
||||||
|
uintptr(icon),
|
||||||
|
uintptr(version),
|
||||||
|
uintptr(cxDesired),
|
||||||
|
uintptr(cyDesired),
|
||||||
|
uintptr(flags),
|
||||||
|
)
|
||||||
|
|
||||||
|
if r == 0 {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadImage(
|
||||||
|
hInst uintptr,
|
||||||
|
name *uint16,
|
||||||
|
type_ uint32,
|
||||||
|
cx, cy int32,
|
||||||
|
fuLoad uint32) (uintptr, error) {
|
||||||
|
r, _, err := procLoadImageW.Call(
|
||||||
|
hInst,
|
||||||
|
uintptr(unsafe.Pointer(name)),
|
||||||
|
uintptr(type_),
|
||||||
|
uintptr(cx),
|
||||||
|
uintptr(cy),
|
||||||
|
uintptr(fuLoad))
|
||||||
|
if r == 0 {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
@ -46,6 +46,10 @@ type DevWebServer struct {
|
||||||
devServerAddr string
|
devServerAddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DevWebServer) TrayMenuAdd(trayMenu *menu.TrayMenu) menu.TrayMenuImpl {
|
||||||
|
return d.desktopFrontend.TrayMenuAdd(trayMenu)
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DevWebServer) WindowSetSystemDefaultTheme() {
|
func (d *DevWebServer) WindowSetSystemDefaultTheme() {
|
||||||
d.desktopFrontend.WindowSetSystemDefaultTheme()
|
d.desktopFrontend.WindowSetSystemDefaultTheme()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,4 +102,7 @@ type Frontend interface {
|
||||||
|
|
||||||
// Browser
|
// Browser
|
||||||
BrowserOpenURL(url string)
|
BrowserOpenURL(url string)
|
||||||
|
|
||||||
|
// Tray Menu
|
||||||
|
TrayMenuAdd(trayMenu *menu.TrayMenu) menu.TrayMenuImpl
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
package menumanager
|
package menumanager
|
||||||
|
|
||||||
import (
|
import "github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//import (
|
||||||
|
// "encoding/json"
|
||||||
|
// "fmt"
|
||||||
|
//
|
||||||
|
// "github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
|
//)
|
||||||
|
//
|
||||||
type ContextMenu struct {
|
type ContextMenu struct {
|
||||||
ID string
|
ID string
|
||||||
ProcessedMenu *WailsMenu
|
ProcessedMenu *WailsMenu
|
||||||
|
|
@ -14,48 +17,49 @@ type ContextMenu struct {
|
||||||
menu *menu.Menu
|
menu *menu.Menu
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ContextMenu) AsJSON() (string, error) {
|
//
|
||||||
data, err := json.Marshal(t)
|
//func (t *ContextMenu) AsJSON() (string, error) {
|
||||||
if err != nil {
|
// data, err := json.Marshal(t)
|
||||||
return "", err
|
// if err != nil {
|
||||||
}
|
// return "", err
|
||||||
return string(data), nil
|
// }
|
||||||
}
|
// return string(data), nil
|
||||||
|
//}
|
||||||
func NewContextMenu(contextMenu *menu.ContextMenu) *ContextMenu {
|
//
|
||||||
|
//func NewContextMenu(contextMenu *menu.ContextMenu) *ContextMenu {
|
||||||
result := &ContextMenu{
|
//
|
||||||
ID: contextMenu.ID,
|
// result := &ContextMenu{
|
||||||
menu: contextMenu.Menu,
|
// ID: contextMenu.ID,
|
||||||
menuItemMap: NewMenuItemMap(),
|
// menu: contextMenu.Menu,
|
||||||
}
|
// menuItemMap: NewMenuItemMap(),
|
||||||
|
// }
|
||||||
result.menuItemMap.AddMenu(contextMenu.Menu)
|
//
|
||||||
result.ProcessedMenu = NewWailsMenu(result.menuItemMap, result.menu)
|
// result.menuItemMap.AddMenu(contextMenu.Menu)
|
||||||
|
// result.ProcessedMenu = NewWailsMenu(result.menuItemMap, result.menu)
|
||||||
return result
|
//
|
||||||
}
|
// return result
|
||||||
|
//}
|
||||||
func (m *Manager) AddContextMenu(contextMenu *menu.ContextMenu) {
|
//
|
||||||
|
//func (m *Manager) AddContextMenu(contextMenu *menu.ContextMenu) {
|
||||||
newContextMenu := NewContextMenu(contextMenu)
|
//
|
||||||
|
// newContextMenu := NewContextMenu(contextMenu)
|
||||||
// Save the references
|
//
|
||||||
m.contextMenus[contextMenu.ID] = newContextMenu
|
// // Save the references
|
||||||
m.contextMenuPointers[contextMenu] = contextMenu.ID
|
// m.contextMenus[contextMenu.ID] = newContextMenu
|
||||||
}
|
// m.contextMenuPointers[contextMenu] = contextMenu.ID
|
||||||
|
//}
|
||||||
func (m *Manager) UpdateContextMenu(contextMenu *menu.ContextMenu) (string, error) {
|
//
|
||||||
contextMenuID, contextMenuKnown := m.contextMenuPointers[contextMenu]
|
//func (m *Manager) UpdateContextMenu(contextMenu *menu.ContextMenu) (string, error) {
|
||||||
if !contextMenuKnown {
|
// contextMenuID, contextMenuKnown := m.contextMenuPointers[contextMenu]
|
||||||
return "", fmt.Errorf("unknown Context Menu '%s'. Please add the context menu using AddContextMenu()", contextMenu.ID)
|
// if !contextMenuKnown {
|
||||||
}
|
// return "", fmt.Errorf("unknown Context Menu '%s'. Please add the context menu using AddContextMenu()", contextMenu.ID)
|
||||||
|
// }
|
||||||
// Create the updated context menu
|
//
|
||||||
updatedContextMenu := NewContextMenu(contextMenu)
|
// // Create the updated context menu
|
||||||
|
// updatedContextMenu := NewContextMenu(contextMenu)
|
||||||
// Save the reference
|
//
|
||||||
m.contextMenus[contextMenuID] = updatedContextMenu
|
// // Save the reference
|
||||||
|
// m.contextMenus[contextMenuID] = updatedContextMenu
|
||||||
return updatedContextMenu.AsJSON()
|
//
|
||||||
}
|
// return updatedContextMenu.AsJSON()
|
||||||
|
//}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package menumanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,11 @@
|
||||||
package menumanager
|
package menumanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/leaanthony/go-ansi-parser"
|
"github.com/leaanthony/go-ansi-parser"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -32,7 +28,7 @@ type TrayMenu struct {
|
||||||
FontName string
|
FontName string
|
||||||
Disabled bool
|
Disabled bool
|
||||||
Tooltip string `json:",omitempty"`
|
Tooltip string `json:",omitempty"`
|
||||||
Image string
|
Image []byte
|
||||||
MacTemplateImage bool
|
MacTemplateImage bool
|
||||||
RGBA string
|
RGBA string
|
||||||
menuItemMap *MenuItemMap
|
menuItemMap *MenuItemMap
|
||||||
|
|
@ -42,181 +38,182 @@ type TrayMenu struct {
|
||||||
StyledLabel []*ansi.StyledText `json:",omitempty"`
|
StyledLabel []*ansi.StyledText `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TrayMenu) AsJSON() (string, error) {
|
//
|
||||||
data, err := json.Marshal(t)
|
//func (t *TrayMenu) AsJSON() (string, error) {
|
||||||
if err != nil {
|
// data, err := json.Marshal(t)
|
||||||
return "", err
|
// if err != nil {
|
||||||
}
|
// return "", err
|
||||||
return string(data), nil
|
// }
|
||||||
}
|
// return string(data), nil
|
||||||
|
//}
|
||||||
func NewTrayMenu(trayMenu *menu.TrayMenu) *TrayMenu {
|
//
|
||||||
|
//func NewTrayMenu(trayMenu *menu.TrayMenu) *TrayMenu {
|
||||||
// Parse ANSI text
|
//
|
||||||
var styledLabel []*ansi.StyledText
|
// // Parse ANSI text
|
||||||
tempLabel := trayMenu.Label
|
// var styledLabel []*ansi.StyledText
|
||||||
if strings.Contains(tempLabel, "\033[") {
|
// tempLabel := trayMenu.Label
|
||||||
parsedLabel, err := ansi.Parse(tempLabel)
|
// if strings.Contains(tempLabel, "\033[") {
|
||||||
if err == nil {
|
// parsedLabel, err := ansi.Parse(tempLabel)
|
||||||
styledLabel = parsedLabel
|
// if err == nil {
|
||||||
}
|
// styledLabel = parsedLabel
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
result := &TrayMenu{
|
//
|
||||||
Label: trayMenu.Label,
|
// result := &TrayMenu{
|
||||||
FontName: trayMenu.FontName,
|
// Label: trayMenu.Label,
|
||||||
FontSize: trayMenu.FontSize,
|
// FontName: trayMenu.FontName,
|
||||||
Disabled: trayMenu.Disabled,
|
// FontSize: trayMenu.FontSize,
|
||||||
Tooltip: trayMenu.Tooltip,
|
// Disabled: trayMenu.Disabled,
|
||||||
Image: trayMenu.Image,
|
// Tooltip: trayMenu.Tooltip,
|
||||||
MacTemplateImage: trayMenu.MacTemplateImage,
|
// Image: trayMenu.Image,
|
||||||
menu: trayMenu.Menu,
|
// MacTemplateImage: trayMenu.MacTemplateImage,
|
||||||
RGBA: trayMenu.RGBA,
|
// menu: trayMenu.Menu,
|
||||||
menuItemMap: NewMenuItemMap(),
|
// RGBA: trayMenu.RGBA,
|
||||||
trayMenu: trayMenu,
|
// menuItemMap: NewMenuItemMap(),
|
||||||
StyledLabel: styledLabel,
|
// trayMenu: trayMenu,
|
||||||
}
|
// StyledLabel: styledLabel,
|
||||||
|
// }
|
||||||
result.menuItemMap.AddMenu(trayMenu.Menu)
|
//
|
||||||
result.ProcessedMenu = NewWailsMenu(result.menuItemMap, result.menu)
|
// result.menuItemMap.AddMenu(trayMenu.Menu)
|
||||||
|
// result.ProcessedMenu = NewWailsMenu(result.menuItemMap, result.menu)
|
||||||
return result
|
//
|
||||||
}
|
// return result
|
||||||
|
//}
|
||||||
func (m *Manager) OnTrayMenuOpen(id string) {
|
//
|
||||||
trayMenu, ok := m.trayMenus[id]
|
//func (m *Manager) OnTrayMenuOpen(id string) {
|
||||||
if !ok {
|
// trayMenu, ok := m.trayMenus[id]
|
||||||
return
|
// if !ok {
|
||||||
}
|
// return
|
||||||
if trayMenu.trayMenu.OnOpen == nil {
|
// }
|
||||||
return
|
// if trayMenu.trayMenu.OnOpen == nil {
|
||||||
}
|
// return
|
||||||
go trayMenu.trayMenu.OnOpen()
|
// }
|
||||||
}
|
// go trayMenu.trayMenu.OnOpen()
|
||||||
|
//}
|
||||||
func (m *Manager) OnTrayMenuClose(id string) {
|
//
|
||||||
trayMenu, ok := m.trayMenus[id]
|
//func (m *Manager) OnTrayMenuClose(id string) {
|
||||||
if !ok {
|
// trayMenu, ok := m.trayMenus[id]
|
||||||
return
|
// if !ok {
|
||||||
}
|
// return
|
||||||
if trayMenu.trayMenu.OnClose == nil {
|
// }
|
||||||
return
|
// if trayMenu.trayMenu.OnClose == nil {
|
||||||
}
|
// return
|
||||||
go trayMenu.trayMenu.OnClose()
|
// }
|
||||||
}
|
// go trayMenu.trayMenu.OnClose()
|
||||||
|
//}
|
||||||
func (m *Manager) AddTrayMenu(trayMenu *menu.TrayMenu) (string, error) {
|
//
|
||||||
newTrayMenu := NewTrayMenu(trayMenu)
|
//func (m *Manager) AddTrayMenu(trayMenu *menu.TrayMenu) (string, error) {
|
||||||
|
// newTrayMenu := NewTrayMenu(trayMenu)
|
||||||
// Hook up a new ID
|
//
|
||||||
trayID := generateTrayID()
|
// // Hook up a new ID
|
||||||
newTrayMenu.ID = trayID
|
// trayID := generateTrayID()
|
||||||
|
// newTrayMenu.ID = trayID
|
||||||
// Save the references
|
//
|
||||||
m.trayMenus[trayID] = newTrayMenu
|
// // Save the references
|
||||||
m.trayMenuPointers[trayMenu] = trayID
|
// m.trayMenus[trayID] = newTrayMenu
|
||||||
|
// m.trayMenuPointers[trayMenu] = trayID
|
||||||
return newTrayMenu.AsJSON()
|
//
|
||||||
}
|
// return newTrayMenu.AsJSON()
|
||||||
|
//}
|
||||||
func (m *Manager) GetTrayID(trayMenu *menu.TrayMenu) (string, error) {
|
//
|
||||||
trayID, exists := m.trayMenuPointers[trayMenu]
|
//func (m *Manager) GetTrayID(trayMenu *menu.TrayMenu) (string, error) {
|
||||||
if !exists {
|
// trayID, exists := m.trayMenuPointers[trayMenu]
|
||||||
return "", fmt.Errorf("Unable to find menu ID for tray menu!")
|
// if !exists {
|
||||||
}
|
// return "", fmt.Errorf("Unable to find menu ID for tray menu!")
|
||||||
return trayID, nil
|
// }
|
||||||
}
|
// return trayID, nil
|
||||||
|
//}
|
||||||
// SetTrayMenu updates or creates a menu
|
//
|
||||||
func (m *Manager) SetTrayMenu(trayMenu *menu.TrayMenu) (string, error) {
|
//// SetTrayMenu updates or creates a menu
|
||||||
trayID, trayMenuKnown := m.trayMenuPointers[trayMenu]
|
//func (m *Manager) SetTrayMenu(trayMenu *menu.TrayMenu) (string, error) {
|
||||||
if !trayMenuKnown {
|
// trayID, trayMenuKnown := m.trayMenuPointers[trayMenu]
|
||||||
return m.AddTrayMenu(trayMenu)
|
// if !trayMenuKnown {
|
||||||
}
|
// return m.AddTrayMenu(trayMenu)
|
||||||
|
// }
|
||||||
// Create the updated tray menu
|
//
|
||||||
updatedTrayMenu := NewTrayMenu(trayMenu)
|
// // Create the updated tray menu
|
||||||
updatedTrayMenu.ID = trayID
|
// updatedTrayMenu := NewTrayMenu(trayMenu)
|
||||||
|
// updatedTrayMenu.ID = trayID
|
||||||
// Save the reference
|
//
|
||||||
m.trayMenus[trayID] = updatedTrayMenu
|
// // Save the reference
|
||||||
|
// m.trayMenus[trayID] = updatedTrayMenu
|
||||||
return updatedTrayMenu.AsJSON()
|
//
|
||||||
}
|
// return updatedTrayMenu.AsJSON()
|
||||||
|
//}
|
||||||
func (m *Manager) GetTrayMenus() ([]string, error) {
|
//
|
||||||
result := []string{}
|
//func (m *Manager) GetTrayMenus() ([]string, error) {
|
||||||
for _, trayMenu := range m.trayMenus {
|
// result := []string{}
|
||||||
JSON, err := trayMenu.AsJSON()
|
// for _, trayMenu := range m.trayMenus {
|
||||||
if err != nil {
|
// JSON, err := trayMenu.AsJSON()
|
||||||
return nil, err
|
// if err != nil {
|
||||||
}
|
// return nil, err
|
||||||
result = append(result, JSON)
|
// }
|
||||||
}
|
// result = append(result, JSON)
|
||||||
|
// }
|
||||||
return result, nil
|
//
|
||||||
}
|
// return result, nil
|
||||||
|
//}
|
||||||
func (m *Manager) UpdateTrayMenuLabel(trayMenu *menu.TrayMenu) (string, error) {
|
//
|
||||||
trayID, trayMenuKnown := m.trayMenuPointers[trayMenu]
|
//func (m *Manager) UpdateTrayMenuLabel(trayMenu *menu.TrayMenu) (string, error) {
|
||||||
if !trayMenuKnown {
|
// trayID, trayMenuKnown := m.trayMenuPointers[trayMenu]
|
||||||
return "", fmt.Errorf("[UpdateTrayMenuLabel] unknown tray id for tray %s", trayMenu.Label)
|
// if !trayMenuKnown {
|
||||||
}
|
// return "", fmt.Errorf("[UpdateTrayMenuLabel] unknown tray id for tray %s", trayMenu.Label)
|
||||||
|
// }
|
||||||
type LabelUpdate struct {
|
//
|
||||||
ID string
|
// type LabelUpdate struct {
|
||||||
Label string `json:",omitempty"`
|
// ID string
|
||||||
FontName string `json:",omitempty"`
|
// Label string `json:",omitempty"`
|
||||||
FontSize int
|
// FontName string `json:",omitempty"`
|
||||||
RGBA string `json:",omitempty"`
|
// FontSize int
|
||||||
Disabled bool
|
// RGBA string `json:",omitempty"`
|
||||||
Tooltip string `json:",omitempty"`
|
// Disabled bool
|
||||||
Image string `json:",omitempty"`
|
// Tooltip string `json:",omitempty"`
|
||||||
MacTemplateImage bool
|
// Image []byte `json:",omitempty"`
|
||||||
StyledLabel []*ansi.StyledText `json:",omitempty"`
|
// MacTemplateImage bool
|
||||||
}
|
// StyledLabel []*ansi.StyledText `json:",omitempty"`
|
||||||
|
// }
|
||||||
// Parse ANSI text
|
//
|
||||||
var styledLabel []*ansi.StyledText
|
// // Parse ANSI text
|
||||||
tempLabel := trayMenu.Label
|
// var styledLabel []*ansi.StyledText
|
||||||
if strings.Contains(tempLabel, "\033[") {
|
// tempLabel := trayMenu.Label
|
||||||
parsedLabel, err := ansi.Parse(tempLabel)
|
// if strings.Contains(tempLabel, "\033[") {
|
||||||
if err == nil {
|
// parsedLabel, err := ansi.Parse(tempLabel)
|
||||||
styledLabel = parsedLabel
|
// if err == nil {
|
||||||
}
|
// styledLabel = parsedLabel
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
update := &LabelUpdate{
|
//
|
||||||
ID: trayID,
|
// update := &LabelUpdate{
|
||||||
Label: trayMenu.Label,
|
// ID: trayID,
|
||||||
FontName: trayMenu.FontName,
|
// Label: trayMenu.Label,
|
||||||
FontSize: trayMenu.FontSize,
|
// FontName: trayMenu.FontName,
|
||||||
Disabled: trayMenu.Disabled,
|
// FontSize: trayMenu.FontSize,
|
||||||
Tooltip: trayMenu.Tooltip,
|
// Disabled: trayMenu.Disabled,
|
||||||
Image: trayMenu.Image,
|
// Tooltip: trayMenu.Tooltip,
|
||||||
MacTemplateImage: trayMenu.MacTemplateImage,
|
// Image: trayMenu.Image,
|
||||||
RGBA: trayMenu.RGBA,
|
// MacTemplateImage: trayMenu.MacTemplateImage,
|
||||||
StyledLabel: styledLabel,
|
// RGBA: trayMenu.RGBA,
|
||||||
}
|
// StyledLabel: styledLabel,
|
||||||
|
// }
|
||||||
data, err := json.Marshal(update)
|
//
|
||||||
if err != nil {
|
// data, err := json.Marshal(update)
|
||||||
return "", errors.Wrap(err, "[UpdateTrayMenuLabel] ")
|
// if err != nil {
|
||||||
}
|
// return "", errors.Wrap(err, "[UpdateTrayMenuLabel] ")
|
||||||
|
// }
|
||||||
return string(data), nil
|
//
|
||||||
|
// return string(data), nil
|
||||||
}
|
//
|
||||||
|
//}
|
||||||
func (m *Manager) GetContextMenus() ([]string, error) {
|
//
|
||||||
result := []string{}
|
//func (m *Manager) GetContextMenus() ([]string, error) {
|
||||||
for _, contextMenu := range m.contextMenus {
|
// result := []string{}
|
||||||
JSON, err := contextMenu.AsJSON()
|
// for _, contextMenu := range m.contextMenus {
|
||||||
if err != nil {
|
// JSON, err := contextMenu.AsJSON()
|
||||||
return nil, err
|
// if err != nil {
|
||||||
}
|
// return nil, err
|
||||||
result = append(result, JSON)
|
// }
|
||||||
}
|
// result = append(result, JSON)
|
||||||
|
// }
|
||||||
return result, nil
|
//
|
||||||
}
|
// return result, nil
|
||||||
|
//}
|
||||||
|
|
|
||||||
3
v2/pkg/events/events.go
Normal file
3
v2/pkg/events/events.go
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
package events
|
||||||
|
|
||||||
|
const ThemeChanged = ":wails:themechanged"
|
||||||
|
|
@ -44,16 +44,23 @@ func (m *Menu) AddRadio(label string, checked bool, accelerator *keys.Accelerato
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSeparator adds a separator to the menu
|
// AddSeparator adds a separator to the menu
|
||||||
func (m *Menu) AddSeparator() {
|
func (m *Menu) AddSeparator() *MenuItem {
|
||||||
item := Separator()
|
item := Separator()
|
||||||
m.Append(item)
|
m.Append(item)
|
||||||
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Menu) AddSubmenu(label string) *Menu {
|
func (m *Menu) AddSubmenu(label string) *MenuItem {
|
||||||
submenu := NewMenu()
|
submenu := NewMenu()
|
||||||
item := SubMenu(label, submenu)
|
item := SubMenu(label, submenu)
|
||||||
m.Append(item)
|
m.Append(item)
|
||||||
return submenu
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Menu) InsertSubmenu(label string, submenu *Menu) *MenuItem {
|
||||||
|
item := SubMenu(label, submenu)
|
||||||
|
m.Append(item)
|
||||||
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Menu) Prepend(item *MenuItem) {
|
func (m *Menu) Prepend(item *MenuItem) {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,11 @@ import (
|
||||||
"github.com/wailsapp/wails/v2/pkg/menu/keys"
|
"github.com/wailsapp/wails/v2/pkg/menu/keys"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type MenuItemImpl interface {
|
||||||
|
SetChecked(bool)
|
||||||
|
SetLabel(string)
|
||||||
|
}
|
||||||
|
|
||||||
// MenuItem represents a menuitem contained in a menu
|
// MenuItem represents a menuitem contained in a menu
|
||||||
type MenuItem struct {
|
type MenuItem struct {
|
||||||
// Label is what appears as the menu text
|
// Label is what appears as the menu text
|
||||||
|
|
@ -53,6 +58,9 @@ type MenuItem struct {
|
||||||
|
|
||||||
// Used for locking when removing elements
|
// Used for locking when removing elements
|
||||||
removeLock sync.Mutex
|
removeLock sync.Mutex
|
||||||
|
|
||||||
|
// Implementation of the runtime methods
|
||||||
|
Impl MenuItemImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parent returns the parent of the menu item.
|
// Parent returns the parent of the menu item.
|
||||||
|
|
@ -216,6 +224,21 @@ func (m *MenuItem) insertItemAtIndex(index int, target *MenuItem) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MenuItem) SetChecked(b bool) {
|
||||||
|
if m.Checked != b {
|
||||||
|
m.Checked = b
|
||||||
|
m.Impl.SetChecked(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MenuItem) SetLabel(name string) {
|
||||||
|
if m.Label == name {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.Label = name
|
||||||
|
m.Impl.SetLabel(name)
|
||||||
|
}
|
||||||
|
|
||||||
// Text is a helper to create basic Text menu items
|
// Text is a helper to create basic Text menu items
|
||||||
func Text(label string, accelerator *keys.Accelerator, click Callback) *MenuItem {
|
func Text(label string, accelerator *keys.Accelerator, click Callback) *MenuItem {
|
||||||
return &MenuItem{
|
return &MenuItem{
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,95 @@
|
||||||
package menu
|
package menu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
goruntime "runtime"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/events"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TrayMenuAdd interface {
|
||||||
|
TrayMenuAdd(menu *TrayMenu) TrayMenuImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
type TrayMenuImpl interface {
|
||||||
|
SetLabel(string)
|
||||||
|
SetImage(*TrayImage)
|
||||||
|
SetMenu(*Menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
type EventsImpl interface {
|
||||||
|
On(eventName string, callback func(...interface{}))
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImagePosition int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ImageLeading ImagePosition = 0
|
||||||
|
ImageOnly ImagePosition = 1
|
||||||
|
ImageLeft ImagePosition = 2
|
||||||
|
ImageRight ImagePosition = 3
|
||||||
|
ImageBelow ImagePosition = 4
|
||||||
|
ImageAbove ImagePosition = 5
|
||||||
|
ImageOverlaps ImagePosition = 6
|
||||||
|
NoImage ImagePosition = 7
|
||||||
|
ImageTrailing ImagePosition = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
type TraySizing int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Variable TraySizing = 0
|
||||||
|
Square TraySizing = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
type TrayImage struct {
|
||||||
|
// Bitmaps hold images for different scaling factors
|
||||||
|
// First = 1x, Second = 2x, etc
|
||||||
|
Bitmaps [][]byte
|
||||||
|
BitmapsDark [][]byte
|
||||||
|
IsTemplate bool
|
||||||
|
Position ImagePosition
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TrayImage) getBestBitmap(scale int, isDarkMode bool) []byte {
|
||||||
|
bitmapsToCheck := t.Bitmaps
|
||||||
|
if isDarkMode {
|
||||||
|
bitmapsToCheck = t.BitmapsDark
|
||||||
|
}
|
||||||
|
if scale < 1 || scale >= len(bitmapsToCheck) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for i := scale; i > 0; i-- {
|
||||||
|
if bitmapsToCheck[i] != nil {
|
||||||
|
return bitmapsToCheck[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBestBitmap will attempt to return the best bitmap for the theme
|
||||||
|
// If dark theme is used and no dark theme bitmap exists, then it will
|
||||||
|
// revert to light theme bitmaps
|
||||||
|
func (t *TrayImage) GetBestBitmap(scale int, isDarkMode bool) []byte {
|
||||||
|
var result []byte
|
||||||
|
if isDarkMode {
|
||||||
|
result = t.getBestBitmap(scale, true)
|
||||||
|
if result != nil {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t.getBestBitmap(scale, false)
|
||||||
|
}
|
||||||
|
|
||||||
// TrayMenu are the options
|
// TrayMenu are the options
|
||||||
type TrayMenu struct {
|
type TrayMenu struct {
|
||||||
|
ctx context.Context
|
||||||
|
|
||||||
// Label is the text we wish to display in the tray
|
// Label is the text we wish to display in the tray
|
||||||
Label string
|
Label string
|
||||||
|
|
||||||
// Image is the name of the tray icon we wish to display.
|
Image *TrayImage
|
||||||
// These are read up during build from <projectdir>/trayicons and
|
|
||||||
// the filenames are used as IDs, minus the extension
|
|
||||||
// EG: <projectdir>/trayicons/main.png can be referenced here with "main"
|
|
||||||
// If the image is not a filename, it will be treated as base64 image data
|
|
||||||
Image string
|
|
||||||
|
|
||||||
// MacTemplateImage indicates that on a Mac, this image is a template image
|
|
||||||
MacTemplateImage bool
|
|
||||||
|
|
||||||
// Text Colour
|
// Text Colour
|
||||||
RGBA string
|
RGBA string
|
||||||
|
|
@ -27,7 +102,7 @@ type TrayMenu struct {
|
||||||
Tooltip string
|
Tooltip string
|
||||||
|
|
||||||
// Callback function when menu clicked
|
// Callback function when menu clicked
|
||||||
//Click Callback `json:"-"`
|
Click Callback
|
||||||
|
|
||||||
// Disabled makes the item unselectable
|
// Disabled makes the item unselectable
|
||||||
Disabled bool
|
Disabled bool
|
||||||
|
|
@ -40,4 +115,67 @@ type TrayMenu struct {
|
||||||
|
|
||||||
// OnClose is called when the Menu is closed
|
// OnClose is called when the Menu is closed
|
||||||
OnClose func()
|
OnClose func()
|
||||||
|
|
||||||
|
/* Mac Options */
|
||||||
|
Sizing TraySizing
|
||||||
|
|
||||||
|
// This is the reference to the OS specific implementation
|
||||||
|
impl TrayMenuImpl
|
||||||
|
|
||||||
|
// Theme change callback
|
||||||
|
themeChangeCallback func(data ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTrayMenu() *TrayMenu {
|
||||||
|
return &TrayMenu{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TrayMenu) Show(ctx context.Context) {
|
||||||
|
if ctx == nil {
|
||||||
|
log.Fatal("TrayMenu.Show() called before Run()")
|
||||||
|
}
|
||||||
|
t.ctx = ctx
|
||||||
|
result := ctx.Value("frontend")
|
||||||
|
if result == nil {
|
||||||
|
pc, _, _, _ := goruntime.Caller(1)
|
||||||
|
funcName := goruntime.FuncForPC(pc).Name()
|
||||||
|
log.Fatalf("invalid context at '%s'", funcName)
|
||||||
|
}
|
||||||
|
t.impl = result.(TrayMenuAdd).TrayMenuAdd(t)
|
||||||
|
|
||||||
|
if t.themeChangeCallback == nil {
|
||||||
|
t.themeChangeCallback = func(data ...interface{}) {
|
||||||
|
println("Update button image")
|
||||||
|
if t.Image != nil {
|
||||||
|
// Update the image
|
||||||
|
t.SetImage(t.Image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result := ctx.Value("events")
|
||||||
|
if result != nil {
|
||||||
|
result.(EventsImpl).On(events.ThemeChanged, t.themeChangeCallback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TrayMenu) SetLabel(label string) {
|
||||||
|
t.Label = label
|
||||||
|
if t.impl != nil {
|
||||||
|
t.impl.SetLabel(label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TrayMenu) SetImage(image *TrayImage) {
|
||||||
|
t.Image = image
|
||||||
|
if t.impl != nil {
|
||||||
|
t.impl.SetImage(image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TrayMenu) SetMenu(menu *Menu) {
|
||||||
|
t.Menu = menu
|
||||||
|
if t.impl != nil {
|
||||||
|
t.impl.SetMenu(menu)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
package mac
|
package mac
|
||||||
|
|
||||||
//type ActivationPolicy int
|
type ActivationPolicy int
|
||||||
//
|
|
||||||
//const (
|
const (
|
||||||
// NSApplicationActivationPolicyRegular ActivationPolicy = 0
|
NSApplicationActivationPolicyRegular ActivationPolicy = 0
|
||||||
// NSApplicationActivationPolicyAccessory ActivationPolicy = 1
|
NSApplicationActivationPolicyAccessory ActivationPolicy = 1
|
||||||
// NSApplicationActivationPolicyProhibited ActivationPolicy = 2
|
NSApplicationActivationPolicyProhibited ActivationPolicy = 2
|
||||||
//)
|
)
|
||||||
|
|
||||||
type AboutInfo struct {
|
type AboutInfo struct {
|
||||||
Title string
|
Title string
|
||||||
|
|
@ -20,7 +20,7 @@ type Options struct {
|
||||||
Appearance AppearanceType
|
Appearance AppearanceType
|
||||||
WebviewIsTransparent bool
|
WebviewIsTransparent bool
|
||||||
WindowIsTranslucent bool
|
WindowIsTranslucent bool
|
||||||
//ActivationPolicy ActivationPolicy
|
About *AboutInfo
|
||||||
About *AboutInfo
|
ActivationPolicy ActivationPolicy
|
||||||
//URLHandlers map[string]func(string)
|
//URLHandlers map[string]func(string)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,19 @@ sidebar_position: 1
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Wails is a project that enables you to write desktop apps using Go and web technologies.
|
Wails is a toolkit that enables you to write beautiful desktop apps using Go.
|
||||||
|
|
||||||
Consider it a lightweight and fast Electron alternative for Go. You can easily build applications with the flexibility
|
Consider it a lightweight and fast Electron alternative for Go. You can easily build applications with the flexibility
|
||||||
and power of Go, combined with a rich, modern frontend.
|
and power of Go, with modern frontend technology.
|
||||||
|
|
||||||
Wails doesn't hold back with the eye candy either! This is [xbar](https://xbarapp.com) - a desktop application for MacOS
|
Wails also offers out-of-the-box integration with the native system libraries, providing native menus, dialogs,
|
||||||
written using Wails. It has menus, supports light and dark desktop themes, and the main window uses translucency that
|
windowing functions, as well as dark and light themes. It also provides a simple way to use native window translucency,
|
||||||
gives it that 'frosty' effect of a native app.
|
allowing you to create modern, beautiful applications.
|
||||||
|
|
||||||
<p class="text--center">
|
<p class="text--center">
|
||||||
<a href="https://xbarapp.com">
|
<a href="https://varly.app">
|
||||||
<img src="/img/xbar-app-preview-2.png" width="75%" />
|
<img src="/img/varly1.png" width="75%"/>
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Quick Start Templates
|
## Quick Start Templates
|
||||||
|
|
|
||||||
BIN
website/static/img/varly1.png
Normal file
BIN
website/static/img/varly1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 220 KiB |
Loading…
Add table
Add a link
Reference in a new issue