Add Window methods Width(), Height(), Size() + Position()

Fix main thread locking issue
Add Window aliases
This commit is contained in:
Lea Anthony 2022-12-11 19:57:20 +11:00
commit f6a16950f2
No known key found for this signature in database
GPG key ID: 33DAF7BB90A58405
5 changed files with 195 additions and 45 deletions

View file

@ -2,6 +2,7 @@ package main
import (
"log"
"sync"
"time"
"github.com/wailsapp/wails/exp/pkg/application"
@ -63,10 +64,12 @@ func main() {
println(myWindow.ID(), "WindowWillClose")
})
myWindow.On(events.Mac.WindowDidResize, func() {
println(myWindow.ID(), "WindowDidResize")
w, h := myWindow.Size()
println(myWindow.ID(), "WindowDidResize", w, h)
})
myWindow.On(events.Mac.WindowDidMove, func() {
println(myWindow.ID(), "WindowDidMove")
x, y := myWindow.Position()
println(myWindow.ID(), "WindowDidMove", x, y)
})
myWindow.On(events.Mac.WindowDidMiniaturize, func() {
println(myWindow.ID(), "WindowDidMiniaturize")
@ -112,36 +115,28 @@ func main() {
})
var myWindow2 *application.Window
go func() {
time.Sleep(2 * time.Second)
myWindow2 = app.NewWindow(&options.Window{
Title: "#2",
Width: 1024,
Height: 768,
AlwaysOnTop: false,
URL: "https://google.com",
DisableResize: true,
Mac: &options.MacWindow{
Backdrop: options.MacBackdropTranslucent,
},
})
}()
go func() {
for {
time.Sleep(5 * time.Second)
println("window 1 is fullscreen?", myWindow.IsFullscreen())
println("window 2 is fullscreen?", myWindow2.IsFullscreen())
println("window 1 is maximised?", myWindow.IsMaximised())
println("window 2 is maximised?", myWindow2.IsMaximised())
println("window 1 is minimised?", myWindow.IsMinimised())
println("window 2 is minimised?", myWindow2.IsMinimised())
}
}()
var myWindow2Lock sync.RWMutex
myWindow2 = app.NewWindow(&options.Window{
Title: "#2",
Width: 1024,
Height: 768,
AlwaysOnTop: false,
URL: "https://google.com",
Mac: &options.MacWindow{
Backdrop: options.MacBackdropTranslucent,
},
})
//myWindow2.On(events.Mac.WindowDidMove, func() {
// myWindow2Lock.RLock()
// x, y := myWindow2.Position()
// println(myWindow2.ID(), "WindowDidMove: ", x, y)
// myWindow2Lock.RUnlock()
//})
//
go func() {
time.Sleep(5 * time.Second)
myWindow2Lock.RLock()
myWindow.SetTitle("Wooooo")
myWindow.SetAlwaysOnTop(true)
myWindow2.EnableDevTools()
@ -150,6 +145,7 @@ func main() {
myWindow.SetMinSize(600, 600)
myWindow.SetMaxSize(650, 650)
myWindow.Center()
myWindow2Lock.RUnlock()
}()

View file

@ -2,10 +2,16 @@ package application
import (
"log"
"runtime"
"sync"
"github.com/wailsapp/wails/exp/pkg/options"
)
func init() {
runtime.LockOSThread()
}
// Messages sent from javascript get routed here
type windowMessage struct {
windowId uint
@ -22,8 +28,10 @@ type App struct {
options *options.Application
applicationEventListeners map[uint][]func()
windows map[uint]*Window
windowAliases map[string]uint
windows map[uint]*Window
windowsLock sync.Mutex
windowAliases map[string]uint
windowAliasesLock sync.Mutex
// Running
running bool
@ -47,12 +55,17 @@ func (a *App) NewWindow(options *options.Window) *Window {
if a.windows == nil {
a.windows = make(map[uint]*Window)
}
a.windowsLock.Lock()
a.windows[id] = newWindow
a.windowsLock.Unlock()
if options.Alias != "" {
if a.windowAliases == nil {
a.windowAliases = make(map[string]uint)
}
a.windowAliasesLock.Lock()
a.windowAliases[options.Alias] = id
a.windowAliasesLock.Unlock()
}
if a.running {
newWindow.Run()
@ -93,7 +106,9 @@ func (a *App) Run() error {
func (a *App) handleMessage(event *windowMessage) {
// Get window from window map
a.windowsLock.Lock()
window, ok := a.windows[event.windowId]
a.windowsLock.Unlock()
if !ok {
log.Printf("Window #%d not found", event.windowId)
return
@ -104,7 +119,9 @@ func (a *App) handleMessage(event *windowMessage) {
func (a *App) handleWindowEvent(event *WindowEvent) {
// Get window from window map
a.windowsLock.Lock()
window, ok := a.windows[event.WindowID]
a.windowsLock.Unlock()
if !ok {
log.Printf("Window #%d not found", event.WindowID)
return

View file

@ -6,9 +6,13 @@ package application
extern void dispatch(unsigned int id);
*/
import "C"
import "strconv"
import (
"os"
"sync"
)
var mainThreadFuntionStore = make(map[uint]func())
var mainThreadFuntionStoreLock sync.RWMutex
func generateFunctionStoreID() uint {
startID := 0
@ -24,18 +28,23 @@ func generateFunctionStoreID() uint {
}
func Dispatch(fn func()) {
mainThreadFuntionStoreLock.Lock()
id := generateFunctionStoreID()
mainThreadFuntionStore[id] = fn
mainThreadFuntionStoreLock.Unlock()
C.dispatch(C.uint(id))
}
//export dispatchCallback
func dispatchCallback(id C.uint) {
fn := mainThreadFuntionStore[uint(id)]
func dispatchCallback(callbackID C.uint) {
mainThreadFuntionStoreLock.RLock()
id := uint(callbackID)
fn := mainThreadFuntionStore[id]
if fn == nil {
panic("dispatchCallback called with invalid id " + strconv.Itoa(int(id)))
println("***** dispatchCallback called with invalid id: ", id)
os.Exit(1)
}
delete(mainThreadFuntionStore, id)
mainThreadFuntionStoreLock.RUnlock()
fn()
delete(mainThreadFuntionStore, uint(id))
}

View file

@ -27,14 +27,20 @@ type windowImpl interface {
setBackgroundColor(color *options.RGBA)
run()
center()
size() (int, int)
width() int
height() int
position() (int, int)
}
type Window struct {
options *options.Window
impl windowImpl
id uint
options *options.Window
impl windowImpl
implLock sync.RWMutex
id uint
eventListeners map[uint][]func()
eventListeners map[uint][]func()
eventListenersLock sync.RWMutex
}
var windowID uint
@ -48,7 +54,6 @@ func getWindowID() uint {
}
func NewWindow(options *options.Window) *Window {
return &Window{
id: getWindowID(),
options: options,
@ -57,6 +62,8 @@ func NewWindow(options *options.Window) *Window {
}
func (w *Window) SetTitle(title string) {
w.implLock.RLock()
defer w.implLock.RUnlock()
if w.impl == nil {
w.options.Title = title
return
@ -74,7 +81,9 @@ func (w *Window) SetSize(width, height int) {
}
func (w *Window) Run() {
w.implLock.Lock()
w.impl = newWindowImpl(w.id, w.options)
w.implLock.Unlock()
w.impl.run()
}
@ -191,8 +200,18 @@ func (w *Window) IsMaximised() bool {
return w.impl.isMaximised()
}
// Size returns the current size of the window
func (w *Window) Size() (int, int) {
if w.impl == nil {
return 0, 0
}
return w.impl.size()
}
// IsFullscreen returns true if the window is fullscreen
func (w *Window) IsFullscreen() bool {
w.implLock.RLock()
defer w.implLock.RUnlock()
if w.impl == nil {
return false
}
@ -223,15 +242,42 @@ func (w *Window) Center() {
}
func (w *Window) On(eventID uint, callback func()) {
w.eventListenersLock.Lock()
w.eventListeners[eventID] = append(w.eventListeners[eventID], callback)
w.eventListenersLock.Unlock()
}
func (w *Window) handleWindowEvent(id uint) {
w.eventListenersLock.RLock()
for _, callback := range w.eventListeners[id] {
callback()
go callback()
}
w.eventListenersLock.RUnlock()
}
func (w *Window) ID() uint {
return w.id
}
func (w *Window) Width() int {
if w.impl == nil {
return 0
}
return w.impl.width()
}
func (w *Window) Height() int {
if w.impl == nil {
return 0
}
return w.impl.height()
}
func (w *Window) Position() (int, int) {
w.implLock.RLock()
defer w.implLock.RUnlock()
if w.impl == nil {
return 0, 0
}
return w.impl.position()
}

View file

@ -394,8 +394,47 @@ void windowCenter(void* nsWindow) {
});
}
// Get the current size of the window
void windowGetSize(void* nsWindow, int* width, int* height) {
// get main window
NSWindow* window = (NSWindow*)nsWindow;
// get window frame
NSRect frame = [window frame];
// set width and height
*width = frame.size.width;
*height = frame.size.height;
}
// Get window width
int windowGetWidth(void* nsWindow) {
// get main window
NSWindow* window = (NSWindow*)nsWindow;
// get window frame
NSRect frame = [window frame];
// return width
return frame.size.width;
}
// Get window height
int windowGetHeight(void* nsWindow) {
// get main window
NSWindow* window = (NSWindow*)nsWindow;
// get window frame
NSRect frame = [window frame];
// return height
return frame.size.height;
}
// Get window position
void windowGetPosition(void* nsWindow, int* x, int* y) {
// get main window
NSWindow* window = (NSWindow*)nsWindow;
// get window frame
NSRect frame = [window frame];
// set x and y
*x = frame.origin.x;
*y = frame.origin.y;
}
*/
@ -511,6 +550,41 @@ func (w *macosWindow) enableDevTools() {
C.windowEnableDevTools(w.nsWindow)
}
func (w *macosWindow) size() (int, int) {
var width, height C.int
var wg sync.WaitGroup
wg.Add(1)
Dispatch(func() {
C.windowGetSize(w.nsWindow, &width, &height)
wg.Done()
})
wg.Wait()
return int(width), int(height)
}
func (w *macosWindow) width() int {
var width C.int
var wg sync.WaitGroup
wg.Add(1)
Dispatch(func() {
width = C.windowGetWidth(w.nsWindow)
wg.Done()
})
wg.Wait()
return int(width)
}
func (w *macosWindow) height() int {
var height C.int
var wg sync.WaitGroup
wg.Add(1)
Dispatch(func() {
height = C.windowGetHeight(w.nsWindow)
wg.Done()
})
wg.Wait()
return int(height)
}
func (w *macosWindow) run() {
Dispatch(func() {
w.nsWindow = C.windowNew(C.uint(w.id), C.int(w.options.Width), C.int(w.options.Height))
@ -575,6 +649,14 @@ func (w *macosWindow) setBackgroundColor(colour *options.RGBA) {
C.webviewSetBackgroundColor(w.nsWindow, C.int(colour.Red), C.int(colour.Green), C.int(colour.Blue), C.int(colour.Alpha))
}
func (w *macosWindow) Center() {
C.windowCenter(w.nsWindow)
func (w *macosWindow) position() (int, int) {
var x, y C.int
var wg sync.WaitGroup
wg.Add(1)
go Dispatch(func() {
C.windowGetPosition(w.nsWindow, &x, &y)
wg.Done()
})
wg.Wait()
return int(x), int(y)
}