diff --git a/exp/examples/basic/main.go b/exp/examples/basic/main.go index 38bf8da09..864d536f7 100644 --- a/exp/examples/basic/main.go +++ b/exp/examples/basic/main.go @@ -22,18 +22,25 @@ func main() { println("TERMINATION!!") }) myWindow := app.NewWindow(&options.Window{ - Title: "Basic", - Width: 600, - Height: 400, - AlwaysOnTop: false, - DisableResize: false, - MinWidth: 100, - MinHeight: 100, - MaxWidth: 1000, - MaxHeight: 1000, + Title: "Basic", + Width: 600, + Height: 400, + AlwaysOnTop: false, + DisableResize: false, + //MinWidth: 100, + //MinHeight: 100, + //MaxWidth: 1000, + //MaxHeight: 1000, EnableDevTools: true, + BackgroundColour: &options.RGBA{ + Red: 255, + Green: 255, + Blue: 255, + Alpha: 30, + }, + StartState: options.WindowStateMaximised, Mac: &options.MacWindow{ - Backdrop: options.MacBackdropNormal, + Backdrop: options.MacBackdropTranslucent, }, }) diff --git a/exp/go.mod b/exp/go.mod index 1969eb348..6b99bc397 100644 --- a/exp/go.mod +++ b/exp/go.mod @@ -2,4 +2,7 @@ module github.com/wailsapp/wails/exp go 1.19 -require github.com/leaanthony/clir v1.3.0 +require ( + github.com/gofrs/uuid v4.3.1+incompatible + github.com/leaanthony/clir v1.3.0 +) diff --git a/exp/go.sum b/exp/go.sum index ec90627a4..119fea365 100644 --- a/exp/go.sum +++ b/exp/go.sum @@ -1,2 +1,4 @@ +github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= +github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/leaanthony/clir v1.3.0 h1:L9nPDWrmc/qU9UWZZvRaFajWYuO0np9V5p+5gxyYno0= github.com/leaanthony/clir v1.3.0/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0= diff --git a/exp/pkg/application/application.go b/exp/pkg/application/application.go index 7b03bf82f..39474eeb8 100644 --- a/exp/pkg/application/application.go +++ b/exp/pkg/application/application.go @@ -1,5 +1,6 @@ package application +import "C" import "github.com/wailsapp/wails/exp/pkg/options" type Application interface { @@ -11,6 +12,9 @@ type App struct { systemEventListeners map[string][]func() windows []*Window + + // Running + running bool } func (a *App) On(s string, callback func()) { @@ -20,5 +24,34 @@ func (a *App) On(s string, callback func()) { func (a *App) NewWindow(options *options.Window) *Window { newWindow := NewWindow(options) a.windows = append(a.windows, newWindow) + + if a.running { + err := newWindow.Run() + if err != nil { + panic(err) + } + } + return newWindow } + +func (a *App) Run() error { + + a.running = true + go func() { + for { + event := <-systemEvents + a.handleSystemEvent(event) + } + }() + + // run windows + for _, window := range a.windows { + err := window.Run() + if err != nil { + return err + } + } + + return a.run() +} diff --git a/exp/pkg/application/application.h b/exp/pkg/application/application.h index 93f931fb5..6efc1825a 100644 --- a/exp/pkg/application/application.h +++ b/exp/pkg/application/application.h @@ -1,5 +1,10 @@ //go:build darwin +#ifndef application_h +#define application_h + void Init(void); void Run(void); -void SetActivationPolicy(int policy); \ No newline at end of file +void SetActivationPolicy(int policy); + +#endif \ No newline at end of file diff --git a/exp/pkg/application/application_darwin.go b/exp/pkg/application/application_darwin.go index c30a60864..fdef9c4b2 100644 --- a/exp/pkg/application/application_darwin.go +++ b/exp/pkg/application/application_darwin.go @@ -22,23 +22,7 @@ func New(options *options.Application) *App { } } -func (a *App) Run() error { - - go func() { - for { - event := <-systemEvents - a.handleSystemEvent(event) - } - }() - - // run windows - for _, window := range a.windows { - err := window.Run() - if err != nil { - return err - } - } - +func (a *App) run() error { C.Run() return nil } diff --git a/exp/pkg/application/window.go b/exp/pkg/application/window.go index aa62f07ed..0db8cfbd5 100644 --- a/exp/pkg/application/window.go +++ b/exp/pkg/application/window.go @@ -1,6 +1,10 @@ package application -import "github.com/wailsapp/wails/exp/pkg/options" +import ( + "sync/atomic" + + "github.com/wailsapp/wails/exp/pkg/options" +) type windowImpl interface { setTitle(title string) @@ -13,15 +17,29 @@ type windowImpl interface { setMaxSize(width, height int) enableDevTools() execJS(js string) + setMaximised() + setMinimised() + setFullscreen() + isMinimised() bool + isMaximised() bool + isFullscreen() bool + restore() + setBackgroundColor(color *options.RGBA) } type Window struct { options *options.Window impl windowImpl + id uint64 } +var windowID atomic.Uint64 + func NewWindow(options *options.Window) *Window { + id := windowID.Load() + windowID.Add(1) return &Window{ + id: id, options: options, } } @@ -117,3 +135,62 @@ func (w *Window) ExecJS(js string) { } w.impl.execJS(js) } + +// Set Maximized +func (w *Window) SetMaximized() { + if w.impl == nil { + w.options.StartState = options.WindowStateMaximised + return + } + w.impl.setMaximised() +} + +// Set Minimized +func (w *Window) SetMinimized() { + if w.impl == nil { + w.options.StartState = options.WindowStateMinimised + return + } + w.impl.setMinimised() +} + +// Set Fullscreen +func (w *Window) SetFullscreen() { + if w.impl == nil { + w.options.StartState = options.WindowStateFullscreen + return + } + w.impl.setFullscreen() +} + +// IsMinimised returns true if the window is minimised +func (w *Window) IsMinimised() bool { + if w.impl == nil { + return false + } + return w.impl.isMinimised() +} + +// IsMaximised returns true if the window is maximised +func (w *Window) IsMaximised() bool { + if w.impl == nil { + return false + } + return w.impl.isMaximised() +} + +// IsFullscreen returns true if the window is fullscreen +func (w *Window) IsFullscreen() bool { + if w.impl == nil { + return false + } + return w.impl.isFullscreen() +} + +func (w *Window) SetBackgroundColor(color *options.RGBA) { + if w.impl == nil { + w.options.BackgroundColour = color + return + } + w.impl.setBackgroundColor(color) +} diff --git a/exp/pkg/application/window_darwin.go b/exp/pkg/application/window_darwin.go index 5b9552e04..1241b4024 100644 --- a/exp/pkg/application/window_darwin.go +++ b/exp/pkg/application/window_darwin.go @@ -200,10 +200,94 @@ void webviewSetTransparent(void* nsWindow) { // Get window delegate WindowDelegate* delegate = (WindowDelegate*)[(NSWindow*)nsWindow delegate]; // Set webview background transparent - [delegate.webView setValue:@YES forKey:@"drawsTransparentBackground"]; + [delegate.webView setValue:@NO forKey:@"drawsBackground"]; }); } +// Set webview background color +void webviewSetBackgroundColor(void* nsWindow, int r, int g, int b, int alpha) { + // Set webview background color on main thread + dispatch_async(dispatch_get_main_queue(), ^{ + // Get window delegate + WindowDelegate* delegate = (WindowDelegate*)[(NSWindow*)nsWindow delegate]; + // Set webview background color + [delegate.webView setValue:[NSColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:alpha/255.0] forKey:@"backgroundColor"]; + }); +} + +// Set Window maximised +void windowSetMaximised(void* nsWindow) { + // Set window maximized on main thread + dispatch_async(dispatch_get_main_queue(), ^{ + [(NSWindow*)nsWindow zoom:nil]; + }); +} + +// Set Window fullscreen +void windowSetFullscreen(void* nsWindow) { + // Set window fullscreen on main thread + dispatch_async(dispatch_get_main_queue(), ^{ + [(NSWindow*)nsWindow toggleFullScreen:nil]; + }); +} + +// Set Window Minimised +void windowSetMinimised(void* nsWindow) { + // Set window minimised on main thread + dispatch_async(dispatch_get_main_queue(), ^{ + // Get screen that the window is on + NSScreen* screen = [(NSWindow*)nsWindow screen]; + NSRect screenRect = [screen frame]; + // Set window to top left corner + [(NSWindow*)nsWindow setFrame:NSMakeRect(0, screenRect.size.height, 0, 0) display:YES]; + }); +} + +// restore window to normal size +void windowRestore(void* nsWindow) { + // Set window normal on main thread + dispatch_async(dispatch_get_main_queue(), ^{ + // If window is fullscreen + if([(NSWindow*)nsWindow styleMask] & NSFullScreenWindowMask) { + [(NSWindow*)nsWindow toggleFullScreen:nil]; + } + // If window is maximised + if([(NSWindow*)nsWindow isZoomed]) { + [(NSWindow*)nsWindow zoom:nil]; + } + // If window in minimised + if([(NSWindow*)nsWindow isMiniaturized]) { + [(NSWindow*)nsWindow deminiaturize:nil]; + } + }); +} + +bool windowIsMaximised(void* nsWindow) { + // Get window maximized on main thread + __block bool maximized = false; + dispatch_sync(dispatch_get_main_queue(), ^{ + maximized = [(NSWindow*)nsWindow isZoomed]; + }); + return maximized; +} + +bool windowIsFullscreen(void* nsWindow) { + // Get window fullscreen on main thread + __block bool fullscreen = false; + dispatch_sync(dispatch_get_main_queue(), ^{ + fullscreen = [(NSWindow*)nsWindow styleMask] & NSFullScreenWindowMask; + }); + return fullscreen; +} + +bool windowIsMinimised(void* nsWindow) { + // Get window minimised on main thread + __block bool minimised = false; + dispatch_sync(dispatch_get_main_queue(), ^{ + minimised = [(NSWindow*)nsWindow isMiniaturized]; + }); + return minimised; +} */ @@ -215,10 +299,44 @@ import ( ) type macosWindow struct { + id uint64 nsWindow unsafe.Pointer options *options.Window } +func (w *macosWindow) isMinimised() bool { + return C.windowIsMinimised(w.nsWindow) == C.bool(true) +} + +func (w *macosWindow) isMaximised() bool { + return C.windowIsMaximised(w.nsWindow) == C.bool(true) +} + +func (w *macosWindow) isFullscreen() bool { + return C.windowIsFullscreen(w.nsWindow) == C.bool(true) +} + +func (w *macosWindow) restore() { + //TODO implement me + panic("implement me") +} + +func (w *macosWindow) setMaximised() { + C.windowSetMaximised(w.nsWindow) +} + +func (w *macosWindow) setMinimised() { + C.windowSetMinimised(w.nsWindow) +} + +func (w *macosWindow) setFullscreen() { + C.windowSetFullscreen(w.nsWindow) +} + +func (w *macosWindow) restoreWindow() { + C.windowRestore(w.nsWindow) +} + func (w *macosWindow) execJS(js string) { C.windowExecJS(w.nsWindow, C.CString(js)) } @@ -274,6 +392,7 @@ func (w *macosWindow) run() error { if w.options.EnableDevTools { w.enableDevTools() } + w.setBackgroundColor(w.options.BackgroundColour) if w.options.Mac != nil { switch w.options.Mac.Backdrop { case options.MacBackdropTransparent: @@ -283,7 +402,26 @@ func (w *macosWindow) run() error { C.windowSetTranslucent(w.nsWindow) C.webviewSetTransparent(w.nsWindow) } + + switch w.options.StartState { + case options.WindowStateMaximised: + w.setMaximised() + case options.WindowStateMinimised: + w.setMinimised() + case options.WindowStateFullscreen: + w.setFullscreen() + + } + } C.windowShow(w.nsWindow) + return nil } + +func (w *macosWindow) setBackgroundColor(colour *options.RGBA) { + if colour == nil { + return + } + C.webviewSetBackgroundColor(w.nsWindow, C.int(colour.Red), C.int(colour.Green), C.int(colour.Blue), C.int(colour.Alpha)) +} diff --git a/exp/pkg/options/application.go b/exp/pkg/options/application.go index a06a305d3..c43b9ac42 100644 --- a/exp/pkg/options/application.go +++ b/exp/pkg/options/application.go @@ -21,18 +21,24 @@ type Mac struct { } type Window struct { - Title string - Width, Height int - AlwaysOnTop bool - URL string - DisableResize bool - Resizable bool - MinWidth int - MinHeight int - MaxWidth int - MaxHeight int - EnableDevTools bool - Mac *MacWindow + Title string + Width, Height int + AlwaysOnTop bool + URL string + DisableResize bool + Resizable bool + MinWidth int + MinHeight int + MaxWidth int + MaxHeight int + EnableDevTools bool + StartState WindowState + Mac *MacWindow + BackgroundColour *RGBA +} + +type RGBA struct { + Red, Green, Blue, Alpha uint8 } type MacBackdrop int @@ -43,6 +49,15 @@ const ( MacBackdropTranslucent ) +type WindowState int + +const ( + WindowStateNormal WindowState = iota + WindowStateMinimised + WindowStateMaximised + WindowStateFullscreen +) + // MacWindow contains macOS specific options type MacWindow struct { Backdrop MacBackdrop