From 7cdab16ba91cf43cabfb8524bca5e39e2c2211e0 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sun, 24 Sep 2023 08:57:22 +1000 Subject: [PATCH] Add API docs. Do small refactors --- mkdocs-website/docs/API/application.md | 184 +++++++++++++++++++ mkdocs-website/docs/API/mainthread.md | 38 ++++ mkdocs-website/docs/API/menu.md | 57 ++++++ mkdocs-website/docs/API/systray.md | 99 ++++++++++ mkdocs-website/docs/API/window.md | 115 ++++++++++++ mkdocs-website/docs/favicon.ico | Bin 111538 -> 15086 bytes mkdocs-website/mkdocs.yml | 6 + v3/examples/systray/main.go | 2 - v3/pkg/application/application.go | 53 +----- v3/pkg/application/application_darwin.go | 2 +- v3/pkg/application/application_linux.go | 2 +- v3/pkg/application/application_windows.go | 10 +- v3/pkg/application/dialogs.go | 8 +- v3/pkg/application/events.go | 4 +- v3/pkg/application/mainthread.go | 54 ++++++ v3/pkg/application/menu_windows.go | 2 +- v3/pkg/application/menuitem_linux.go | 10 +- v3/pkg/application/options_application.go | 4 +- v3/pkg/application/screen_linux.go | 2 +- v3/pkg/application/systemtray.go | 20 +- v3/pkg/application/systemtray_linux.go | 6 +- v3/pkg/application/webview_window.go | 126 ++++++------- v3/pkg/application/webview_window_darwin.go | 4 +- v3/pkg/application/webview_window_windows.go | 2 +- 24 files changed, 657 insertions(+), 153 deletions(-) create mode 100644 mkdocs-website/docs/API/application.md create mode 100644 mkdocs-website/docs/API/mainthread.md create mode 100644 mkdocs-website/docs/API/menu.md create mode 100644 mkdocs-website/docs/API/systray.md create mode 100644 mkdocs-website/docs/API/window.md diff --git a/mkdocs-website/docs/API/application.md b/mkdocs-website/docs/API/application.md new file mode 100644 index 00000000..eae421e0 --- /dev/null +++ b/mkdocs-website/docs/API/application.md @@ -0,0 +1,184 @@ +# Application + +The application API assists in creating an application using the Wails framework. + +### New + +API: `New(appOptions Options) *App` + +`New(appOptions Options)` creates a new application using the given application options . It applies default values for unspecified options, merges them with the provided ones, initializes and returns an instance of the application. + +In case of an error during initialization, the application is stopped with the error message provided. + +It should be noted that if a global application instance already exists, that instance will be returned instead of creating a new one. + +### Get + +`Get()` returns the global application instance. It's useful when you need to access the application from different parts of your code. + +### Capabilities + +API: `Capabilities() capabilities.Capabilities` + +`Capabilities()` retrieves a map of capabilities that the application currently has. Capabilities can be about different features the operating system provides, like webview features. + +### GetPID + +API: `GetPID() int` + +`GetPID()` returns the Process ID of the application. + +### Run + +API: `Run() error` + +`Run()` starts the execution of the application and its components. + + +### Quit + +API: `Quit()` + +`Quit()` quits the application by destroying windows and potentially other components. + +### IsDarkMode + +API: `IsDarkMode() bool` + +`IsDarkMode()` checks if the application is running in dark mode. It returns a boolean indicating whether dark mode is enabled. + +### Hide + +API: `Hide()` + +`Hide()` hides the application window. + +### Show + +API: `Show()` + +`Show()` shows the application window. + +### NewWebviewWindow + +API: `NewWebviewWindow() *WebviewWindow` + +`NewWebviewWindow()` creates a new Webview window with default options, and returns it. + +### NewWebviewWindowWithOptions + +API: `NewWebviewWindowWithOptions(windowOptions WebviewWindowOptions) *WebviewWindow` + +`NewWebviewWindowWithOptions()` creates a new webview window with custom options. The newly created window is added to a map of windows managed by the application. + +### OnWindowCreation + +API: `OnWindowCreation(callback func(window *WebviewWindow))` + +`OnWindowCreation()` registers a callback function to be called when a window is created. + +### GetWindowByName + +API: `GetWindowByName(name string) *WebviewWindow` + +`GetWindowByName()` fetches and returns a window with a specific name. + +### CurrentWindow + +API: `CurrentWindow() *WebviewWindow` + +`CurrentWindow()` fetches and returns a pointer to the currently active window in the application. If there is no window, it returns nil. + + +### NewSystemTray + +API: `NewSystemTray() *SystemTray` + +`NewSystemTray()` creates and returns a new system tray instance. + + + +### NewMenu + +API: `NewMenu() *Menu` + +This method, belonging to App struct and not Menu struct, also initialises and returns a new `Menu`. + + + +### RegisterContextMenu + +API: `RegisterContextMenu(name string, menu *Menu)` + +`RegisterContextMenu()` registers a context menu with a given name. This menu can be used later in the application. + +### SetMenu + +API: `SetMenu(menu *Menu)` + +`SetMenu()` sets the menu for the application. + +### ShowAboutDialog + +API: `ShowAboutDialog()` + +`ShowAboutDialog()` shows an "About" dialog box. It can show the application's name, description and icon. + +### Info + +`InfoDialog()` creates and returns a new instance of `MessageDialog` with an `InfoDialogType`. This dialog is typically used to display informational messages to the user. + +### Question + +`QuestionDialog()` creates and returns a new instance of `MessageDialog` with a `QuestionDialogType`. This dialog is often used to ask a question to the user and expect a response. + +### Warning + +`WarningDialog()` creates and returns a new instance of `MessageDialog` with a `WarningDialogType`. As the name suggests, this dialog is primarily used to display warning messages to the user. + +### Error + +`ErrorDialog()` creates and returns a new instance of `MessageDialog` with an `ErrorDialogType`. This dialog is designed to be used when you need to display an error message to the user. + +### OpenFile + +`OpenFileDialog()` creates and returns a new `OpenFileDialogStruct`. This dialog prompts the user to select one or more files from their file system. + +### SaveFile + +`SaveFileDialog()` creates and returns a new `SaveFileDialogStruct`. This dialog prompts the user to choose a location on their file system where a file should be saved. + +### OpenDirectory + +`OpenDirectoryDialog()` creates and returns a new instance of `MessageDialog` with an `OpenDirectoryDialogType`. This dialog enables the user to choose a directory from their file system. + + +### On + +API: `On(eventType events.ApplicationEventType, callback func(event *Event)) func()` + +`On()` registers an event listener for specific application events. The callback function provided will be triggered when the corresponding event occurs. The function returns a function that can be called to remove the listener. + +### RegisterHook + +API: `RegisterHook(eventType events.ApplicationEventType, callback func(event *Event)) func()` + +`RegisterHook()` registers a callback to be run as a hook during specific events. These hooks are run before listeners attached with `On()`. The function returns a function that can be called to remove the hook. + +### GetPrimaryScreen + +API: `GetPrimaryScreen() (*Screen, error)` + +`GetPrimaryScreen()` returns the primary screen of the system. + +### GetScreens + +API: `GetScreens() ([]*Screen, error)` + +`GetScreens()` returns information about all screens attached to the system. + +This is a brief summary of the exported methods in the provided `App` struct. Do note that for more detailed functionality or considerations, refer to the actual Go code or further internal documentation. + +## Options + +--8<-- "../../../v3/pkg/application/options_application.go" diff --git a/mkdocs-website/docs/API/mainthread.md b/mkdocs-website/docs/API/mainthread.md new file mode 100644 index 00000000..d62f0c42 --- /dev/null +++ b/mkdocs-website/docs/API/mainthread.md @@ -0,0 +1,38 @@ +# Main Thread Functions + +These methods are utility functions to run code on the main thread. This is required when you want to run +custom code on the UI thread. + +### InvokeSync + +API: `InvokeSync(fn func())` + +This function runs the passed function (`fn`) synchronously. It uses a WaitGroup (`wg`) to ensure that the main thread waits for the `fn` function to finish before it continues. If a panic occurs inside `fn`, it will be passed to the handler function `PanicHandler`, defined in the application options. + +### InvokeSyncWithResult + +API: `InvokeSyncWithResult[T any](fn func() T) (res T)` + +This function works similarly to `InvokeSync(fn func())`, however, it yields a result. Use this for calling any function with a single return. + +### InvokeSyncWithError + +API: `InvokeSyncWithError(fn func() error) (err error)` + +This function runs `fn` synchronously and returns any error that `fn` produces. Note that this function will recover from a panic if one occurs during `fn`'s execution. + +### InvokeSyncWithResultAndError + +API: `InvokeSyncWithResultAndError[T any](fn func() (T, error)) (res T, err error)` + +This function runs `fn` synchronously and returns both a result of type `T` and an error. + +### InvokeAsync + +API: `InvokeAsync(fn func())` + +This function runs `fn` asynchronously. It runs the given function on the main thread. If a panic occurs inside `fn`, it will be passed to the handler function `PanicHandler`, defined in the application options. + +--- + +_Note_: These functions will block execution until `fn` has finished. It's critical to ensure that `fn` doesn't block. If you need to run a function that blocks, use `InvokeAsync` instead. \ No newline at end of file diff --git a/mkdocs-website/docs/API/menu.md b/mkdocs-website/docs/API/menu.md new file mode 100644 index 00000000..905ce6d3 --- /dev/null +++ b/mkdocs-website/docs/API/menu.md @@ -0,0 +1,57 @@ +# Menu + +### `type Menu struct` + +The `Menu` struct holds information about a menu, including which items it contains and its label. + +### `func NewMenu() *Menu` + +This function initializes a new Menu. + +### Add + +API: `Add(label string) *MenuItem` + +This method takes a `label` of type `string` as an input and adds a new `MenuItem` with the given label to the menu. It returns the `MenuItem` added. + +### AddSeparator + +API: `AddSeparator()` + +This method adds a new separator `MenuItem` to the menu. + +### AddCheckbox + +API: `AddCheckbox(label string, enabled bool) *MenuItem` + +This method takes a `label` of type `string` and `enabled` of type `bool` as inputs and adds a new checkbox `MenuItem` with the given label and enabled state to the menu. It returns the `MenuItem` added. + +### AddRadio + +API: `AddRadio(label string, enabled bool) *MenuItem` + +This method takes a `label` of type `string` and `enabled` of type `bool` as inputs and adds a new radio `MenuItem` with the given label and enabled state to the menu. It returns the `MenuItem` added. + +### Update + +API: `Update()` + +This method processes any radio groups and updates the menu if a menu implementation is not initialized. + +### AddSubmenu + +API: `AddSubmenu(s string) *Menu` + +This method takes a `s` of type `string` as input and adds a new submenu `MenuItem` with the given label to the menu. It returns the submenu added. + +### AddRole + +API: `AddRole(role Role) *Menu` + +This method takes `role` of type `Role` as input, adds it to the menu if it is not `nil` and returns the `Menu`. + +### SetLabel + +API: `SetLabel(label string)` + +This method sets the `label` of the `Menu`. diff --git a/mkdocs-website/docs/API/systray.md b/mkdocs-website/docs/API/systray.md new file mode 100644 index 00000000..6e62aaba --- /dev/null +++ b/mkdocs-website/docs/API/systray.md @@ -0,0 +1,99 @@ +# System Tray + +The system tray houses notification area on a desktop environment, which can contain both icons of currently-running applications and specific system notifications. + +### NewSystemTray + +API: `NewSystemTray(id uint) *SystemTray` + +The `NewSystemTray` function constructs an instance of the `SystemTray` struct. This function takes a unique identifier of type `uint`. It returns a pointer to a `SystemTray` instance. + +### SetLabel + +API: `SetLabel(label string)` + +The `SetLabel` method sets the tray's label. + +### Label + +API: `Label() string` + +The `Label` method retrieves the tray's label. + +### PositionWindow + +API: `PositionWindow(*WebviewWindow, offset int) error` + +The `PositionWindow` method calls both `AttachWindow` and `WindowOffset` methods. + +### SetIcon + +API: `SetIcon(icon []byte) *SystemTray` + +The `SetIcon` method sets the system tray's icon. + +### SetDarkModeIcon + +API: `SetDarkModeIcon(icon []byte) *SystemTray` + +The `SetDarkModeIcon` method sets the system tray's icon when in dark mode. + +### SetMenu + +API: `SetMenu(menu *Menu) *SystemTray` + +The `SetMenu` method sets the system tray's menu. + +### Destroy + +API: `Destroy()` + +The `Destroy` method destroys the system tray instance. + +### OnClick + +API: `OnClick(handler func()) *SystemTray` + +The `OnClick` method sets the function to execute when the tray icon is clicked. + +### OnRightClick + +API: `OnRightClick(handler func()) *SystemTray` + +The `OnRightClick` method sets the function to execute when right-clicking the tray icon. + +### OnDoubleClick + +API: `OnDoubleClick(handler func()) *SystemTray` + +The `OnDoubleClick` method sets the function to execute when double-clicking the tray icon. + +### OnRightDoubleClick + +API: `OnRightDoubleClick(handler func()) *SystemTray` + +The `OnRightDoubleClick` method sets the function to execute when right double-clicking the tray icon. + +### AttachWindow + +API: `AttachWindow(window *WebviewWindow) *SystemTray` + +The `AttachWindow` method attaches a window to the system tray. The window will be shown when the system tray icon is clicked. + +### WindowOffset + +API: `WindowOffset(offset int) *SystemTray` + +The `WindowOffset` method sets the gap in pixels between the system tray and the window. + +### WindowDebounce + +API: `WindowDebounce(debounce time.Duration) *SystemTray` + +The `WindowDebounce` method sets a debounce time. In the context of Windows, this is used to specify how long to wait before responding to a mouse up event on the notification icon. + +### OpenMenu + +API: `OpenMenu()` + +The `OpenMenu` method opens the menu associated with the system tray. diff --git a/mkdocs-website/docs/API/window.md b/mkdocs-website/docs/API/window.md new file mode 100644 index 00000000..99b7180a --- /dev/null +++ b/mkdocs-website/docs/API/window.md @@ -0,0 +1,115 @@ +# Window + +To create a window, use [Application.NewWebviewWindow](application.md#newwebviewwindow) or [Application.NewWebviewWindowWithOptions](application.md#newwebviewwindowwithoptions). The former creates a window with default options, while the latter allows you to specify custom options. + +These methods are callable on the returned WebviewWindow object: + +### SetTitle + +API: `SetTitle(title string) *WebviewWindow` + +This method updates the window title to the provided string. It returns the WebviewWindow object, allowing for method chaining. + + +### Name + +API: `Name() string` + +This function returns the name of the WebviewWindow. + + +### SetSize + +API: `SetSize(width, height int) *WebviewWindow` + +This method sets the size of the WebviewWindow to the provided width and height parameters. If the dimensions provided exceed the constraints, they are adjusted appropriately. + + +### SetAlwaysOnTop + +API: `SetAlwaysOnTop(b bool) *WebviewWindow` + +This function sets the window to stay on top based on the boolean flag provided. + + +### Show + +API: `Show() *WebviewWindow` + +`Show` method is used to make the window visible. If the window is not running, it first invokes the `run` method to start the window and then makes it visible. + + +### Hide + +API: `Hide() *WebviewWindow` + +`Hide` method is used to hide the window. It sets the hidden status of the window to true and emits the window hide event. + + +### SetURL + +API: `SetURL(s string) *WebviewWindow` + +`SetURL` method is used to set the URL of the window to the given URL string. + + +### SetZoom + +API: `SetZoom(magnification float64) *WebviewWindow` + +`SetZoom` method sets the zoom level of the window content to the provided magnification level. + + +### GetZoom + +API: `GetZoom() float64` + +`GetZoom` function returns the current zoom level of the window content. + + +### GetScreen + +API: `GetScreen() (*Screen, error)` + +`GetScreen` method returns the screen on which the window is displayed. + +#### SetFrameless + +API: `SetFrameless(frameless bool) *WebviewWindow` + +This function is used to remove the window frame and title bar. It toggles the framelessness of the window according to the boolean value provided (true for frameless, false for framed). + + +#### RegisterContextMenu + +API: `RegisterContextMenu(name string, menu *Menu)` + +This function is used to register a context menu and assigns it the given name. + + +#### NativeWindowHandle + +API: `NativeWindowHandle() (uintptr, error)` + +This function is used to fetch the platform native window handle for the window. + + +#### Focus + +API: `Focus()` + +This function is used to focus the window. + + +#### SetEnabled + +API: `SetEnabled(enabled bool)` + +This function is used to enable/disable the window based on the provided boolean value. + + +#### SetAbsolutePosition + +API: `SetAbsolutePosition(x int, y int)` + +This function sets the absolute position of the window in the screen. diff --git a/mkdocs-website/docs/favicon.ico b/mkdocs-website/docs/favicon.ico index fb362effe518e4ee18b4526a6b2c83096f965e2e..256f9ec199284c8df351101efc71819df284ff14 100644 GIT binary patch literal 15086 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 U8U8UdF#KVLi2nzbQ~wzl08GN_GXMYp literal 111538 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 0 { result = selection[0] @@ -289,7 +289,7 @@ func (d *OpenFileDialogStruct) PromptForMultipleSelection() ([]string, error) { if d.impl == nil { d.impl = newOpenFileDialogImpl(d) } - return invokeSyncWithResultAndError(d.impl.show) + return InvokeSyncWithResultAndError(d.impl.show) } func (d *OpenFileDialogStruct) SetMessage(message string) *OpenFileDialogStruct { @@ -448,7 +448,7 @@ func (d *SaveFileDialogStruct) PromptForSingleSelection() (string, error) { if d.impl == nil { d.impl = newSaveFileDialogImpl(d) } - return invokeSyncWithResultAndError(d.impl.show) + return InvokeSyncWithResultAndError(d.impl.show) } func (d *SaveFileDialogStruct) SetButtonText(text string) *SaveFileDialogStruct { diff --git a/v3/pkg/application/events.go b/v3/pkg/application/events.go index dbf6bc9f..3e815510 100644 --- a/v3/pkg/application/events.go +++ b/v3/pkg/application/events.go @@ -17,7 +17,7 @@ func (w *Event) Context() *ApplicationEventContext { return w.ctx } -func NewApplicationEvent(id int) *Event { +func newApplicationEvent(id int) *Event { return &Event{ Id: uint(id), ctx: newApplicationEventContext(), @@ -50,7 +50,7 @@ func (e *WailsEvent) Cancel() { e.Cancelled = true } -func (e WailsEvent) ToJSON() string { +func (e WailsEvent) toJSON() string { marshal, err := json.Marshal(&e) if err != nil { // TODO: Fatal error? log? diff --git a/v3/pkg/application/mainthread.go b/v3/pkg/application/mainthread.go index f0ae2803..d7b0af37 100644 --- a/v3/pkg/application/mainthread.go +++ b/v3/pkg/application/mainthread.go @@ -19,3 +19,57 @@ func generateFunctionStoreID() uint { } } } + +func InvokeSync(fn func()) { + var wg sync.WaitGroup + wg.Add(1) + globalApplication.dispatchOnMainThread(func() { + defer processPanicHandlerRecover() + fn() + wg.Done() + }) + wg.Wait() +} + +func InvokeSyncWithResult[T any](fn func() T) (res T) { + var wg sync.WaitGroup + wg.Add(1) + globalApplication.dispatchOnMainThread(func() { + defer processPanicHandlerRecover() + res = fn() + wg.Done() + }) + wg.Wait() + return res +} + +func InvokeSyncWithError(fn func() error) (err error) { + var wg sync.WaitGroup + wg.Add(1) + globalApplication.dispatchOnMainThread(func() { + defer processPanicHandlerRecover() + err = fn() + wg.Done() + }) + wg.Wait() + return +} + +func InvokeSyncWithResultAndError[T any](fn func() (T, error)) (res T, err error) { + var wg sync.WaitGroup + wg.Add(1) + globalApplication.dispatchOnMainThread(func() { + defer processPanicHandlerRecover() + res, err = fn() + wg.Done() + }) + wg.Wait() + return res, err +} + +func InvokeAsync(fn func()) { + globalApplication.dispatchOnMainThread(func() { + defer processPanicHandlerRecover() + fn() + }) +} diff --git a/v3/pkg/application/menu_windows.go b/v3/pkg/application/menu_windows.go index efa1bd0e..a7278d72 100644 --- a/v3/pkg/application/menu_windows.go +++ b/v3/pkg/application/menu_windows.go @@ -82,7 +82,7 @@ func (w *windowsMenu) processMenu(parentMenu w32.HMENU, inputMenu *Menu) { } func (w *windowsMenu) ShowAtCursor() { - invokeSync(func() { + InvokeSync(func() { x, y, ok := w32.GetCursorPos() if !ok { return diff --git a/v3/pkg/application/menuitem_linux.go b/v3/pkg/application/menuitem_linux.go index 575c4b59..cce9414b 100644 --- a/v3/pkg/application/menuitem_linux.go +++ b/v3/pkg/application/menuitem_linux.go @@ -14,7 +14,7 @@ type linuxMenuItem struct { } func (l linuxMenuItem) setTooltip(tooltip string) { - invokeSync(func(){ + InvokeSync(func() { l.blockSignal() defer l.unBlockSignal() menuItemSetToolTip(l.native, tooltip) @@ -34,7 +34,7 @@ func (l linuxMenuItem) unBlockSignal() { } func (l linuxMenuItem) setLabel(s string) { - invokeSync(func() { + InvokeSync(func() { l.blockSignal() defer l.unBlockSignal() menuItemSetLabel(l.native, s) @@ -46,7 +46,7 @@ func (l linuxMenuItem) isChecked() bool { } func (l linuxMenuItem) setDisabled(disabled bool) { - invokeSync(func() { + InvokeSync(func() { l.blockSignal() defer l.unBlockSignal() menuItemSetDisabled(l.native, disabled) @@ -54,7 +54,7 @@ func (l linuxMenuItem) setDisabled(disabled bool) { } func (l linuxMenuItem) setChecked(checked bool) { - invokeSync(func() { + InvokeSync(func() { l.blockSignal() defer l.unBlockSignal() menuItemSetChecked(l.native, checked) @@ -62,7 +62,7 @@ func (l linuxMenuItem) setChecked(checked bool) { } func (l linuxMenuItem) setHidden(hidden bool) { - invokeSync(func() { + InvokeSync(func() { l.blockSignal() defer l.unBlockSignal() widgetSetVisible(l.native, hidden) diff --git a/v3/pkg/application/options_application.go b/v3/pkg/application/options_application.go index 4cc3036a..4d606c5c 100644 --- a/v3/pkg/application/options_application.go +++ b/v3/pkg/application/options_application.go @@ -70,7 +70,7 @@ type AssetOptions struct { // Other request: `http.StatusMethodNotAllowed` Handler http.Handler - // Middleware is a HTTP Middleware which allows to hook into the AssetServer request chain. It allows to skip the default + // Middleware is HTTP Middleware which allows to hook into the AssetServer request chain. It allows to skip the default // request handler dynamically, e.g. implement specialized Routing etc. // The Middleware is called to build a new `http.Handler` used by the AssetSever and it also receives the default // handler used by the AssetServer as an argument. @@ -86,7 +86,7 @@ type AssetOptions struct { ExternalURL string } -// Middleware defines a HTTP middleware that can be applied to the AssetServer. +// Middleware defines HTTP middleware that can be applied to the AssetServer. // The handler passed as next is the next handler in the chain. One can decide to call the next handler // or implement a specialized handling. type Middleware func(next http.Handler) http.Handler diff --git a/v3/pkg/application/screen_linux.go b/v3/pkg/application/screen_linux.go index 07b02107..36411045 100644 --- a/v3/pkg/application/screen_linux.go +++ b/v3/pkg/application/screen_linux.go @@ -16,7 +16,7 @@ func (m *linuxApp) getScreens() ([]*Screen, error) { var screens []*Screen var err error wg.Add(1) - invokeSync(func() { + InvokeSync(func() { screens, err = getScreens(m.application) wg.Done() }) diff --git a/v3/pkg/application/systemtray.go b/v3/pkg/application/systemtray.go index 01cfd844..0dc81836 100644 --- a/v3/pkg/application/systemtray.go +++ b/v3/pkg/application/systemtray.go @@ -65,7 +65,7 @@ type SystemTray struct { attachedWindow WindowAttachConfig } -func NewSystemTray(id uint) *SystemTray { +func newSystemTray(id uint) *SystemTray { result := &SystemTray{ id: id, label: "", @@ -85,7 +85,7 @@ func (s *SystemTray) SetLabel(label string) { s.label = label return } - invokeSync(func() { + InvokeSync(func() { s.impl.setLabel(label) }) } @@ -116,14 +116,14 @@ func (s *SystemTray) run() { }) } - invokeSync(s.impl.run) + InvokeSync(s.impl.run) } func (s *SystemTray) PositionWindow(window *WebviewWindow, offset int) error { if s.impl == nil { return fmt.Errorf("system tray not running") } - return invokeSyncWithError(func() error { + return InvokeSyncWithError(func() error { return s.impl.positionWindow(window, offset) }) } @@ -132,7 +132,7 @@ func (s *SystemTray) SetIcon(icon []byte) *SystemTray { if s.impl == nil { s.icon = icon } else { - invokeSync(func() { + InvokeSync(func() { s.impl.setIcon(icon) }) } @@ -143,7 +143,7 @@ func (s *SystemTray) SetDarkModeIcon(icon []byte) *SystemTray { if s.impl == nil { s.darkModeIcon = icon } else { - invokeSync(func() { + InvokeSync(func() { s.impl.setDarkModeIcon(icon) }) } @@ -154,7 +154,7 @@ func (s *SystemTray) SetMenu(menu *Menu) *SystemTray { if s.impl == nil { s.menu = menu } else { - invokeSync(func() { + InvokeSync(func() { s.impl.setMenu(menu) }) } @@ -165,7 +165,7 @@ func (s *SystemTray) SetIconPosition(iconPosition int) *SystemTray { if s.impl == nil { s.iconPosition = iconPosition } else { - invokeSync(func() { + InvokeSync(func() { s.impl.setIconPosition(iconPosition) }) } @@ -177,7 +177,7 @@ func (s *SystemTray) SetTemplateIcon(icon []byte) *SystemTray { s.icon = icon s.isTemplateIcon = true } else { - invokeSync(func() { + InvokeSync(func() { s.impl.setTemplateIcon(icon) }) } @@ -294,5 +294,5 @@ func (s *SystemTray) OpenMenu() { if s.impl == nil { return } - invokeSync(s.impl.openMenu) + InvokeSync(s.impl.openMenu) } diff --git a/v3/pkg/application/systemtray_linux.go b/v3/pkg/application/systemtray_linux.go index 2f496868..79149e1d 100644 --- a/v3/pkg/application/systemtray_linux.go +++ b/v3/pkg/application/systemtray_linux.go @@ -36,7 +36,7 @@ func (s *linuxSystemTray) bounds() (*Rect, error) { } func (s *linuxSystemTray) run() { - invokeSync(func() { + InvokeSync(func() { // if s.nsStatusItem != nil { // Fatal("System tray '%d' already running", s.id) // } @@ -60,7 +60,7 @@ func (s *linuxSystemTray) run() { func (s *linuxSystemTray) setIcon(icon []byte) { s.icon = icon - invokeSync(func() { + InvokeSync(func() { // s.nsImage = unsafe.Pointer(C.imageFromBytes((*C.uchar)(&icon[0]), C.int(len(icon)))) // C.systemTraySetIcon(s.nsStatusItem, s.nsImage, C.int(s.iconPosition), C.bool(s.isTemplateIcon)) }) @@ -68,7 +68,7 @@ func (s *linuxSystemTray) setIcon(icon []byte) { func (s *linuxSystemTray) setDarkModeIcon(icon []byte) { s.icon = icon - invokeSync(func() { + InvokeSync(func() { // s.nsImage = unsafe.Pointer(C.imageFromBytes((*C.uchar)(&icon[0]), C.int(len(icon)))) // C.systemTraySetIcon(s.nsStatusItem, s.nsImage, C.int(s.iconPosition), C.bool(s.isTemplateIcon)) }) diff --git a/v3/pkg/application/webview_window.go b/v3/pkg/application/webview_window.go index 0ba7e268..7af9e322 100644 --- a/v3/pkg/application/webview_window.go +++ b/v3/pkg/application/webview_window.go @@ -156,8 +156,8 @@ func (w *WebviewWindow) setupEventMapping() { } } -// NewWindow creates a new window with the given options -func NewWindow(options WebviewWindowOptions) *WebviewWindow { +// newWindow creates a new window with the given options +func newWindow(options WebviewWindowOptions) *WebviewWindow { if options.Width == 0 { options.Width = 800 } @@ -186,7 +186,7 @@ func NewWindow(options WebviewWindowOptions) *WebviewWindow { } if shouldClose { globalApplication.deleteWindowByID(result.id) - invokeSync(result.impl.close) + InvokeSync(result.impl.close) } }) @@ -223,7 +223,7 @@ func (w *WebviewWindow) addCancellationFunction(canceller func()) { func (w *WebviewWindow) SetTitle(title string) *WebviewWindow { w.options.Title = title if w.impl != nil { - invokeSync(func() { + InvokeSync(func() { w.impl.setTitle(title) }) } @@ -271,7 +271,7 @@ func (w *WebviewWindow) SetSize(width, height int) *WebviewWindow { } if w.impl != nil { - invokeSync(func() { + InvokeSync(func() { w.impl.setSize(width, height) }) } @@ -283,14 +283,14 @@ func (w *WebviewWindow) run() { return } w.impl = newWindowImpl(w) - invokeSync(w.impl.run) + InvokeSync(w.impl.run) } // SetAlwaysOnTop sets the window to be always on top. func (w *WebviewWindow) SetAlwaysOnTop(b bool) *WebviewWindow { w.options.AlwaysOnTop = b if w.impl != nil { - invokeSync(func() { + InvokeSync(func() { w.impl.setAlwaysOnTop(b) }) } @@ -303,10 +303,10 @@ func (w *WebviewWindow) Show() *WebviewWindow { return w } if w.impl == nil { - invokeSync(w.run) + InvokeSync(w.run) return w } - invokeSync(w.impl.show) + InvokeSync(w.impl.show) w.emit(events.Common.WindowShow) return w } @@ -315,7 +315,7 @@ func (w *WebviewWindow) Show() *WebviewWindow { func (w *WebviewWindow) Hide() *WebviewWindow { w.options.Hidden = true if w.impl != nil { - invokeSync(w.impl.hide) + InvokeSync(w.impl.hide) w.emit(events.Common.WindowHide) } return w @@ -324,7 +324,7 @@ func (w *WebviewWindow) Hide() *WebviewWindow { func (w *WebviewWindow) SetURL(s string) *WebviewWindow { w.options.URL = s if w.impl != nil { - invokeSync(func() { + InvokeSync(func() { w.impl.setURL(s) }) } @@ -335,7 +335,7 @@ func (w *WebviewWindow) SetURL(s string) *WebviewWindow { func (w *WebviewWindow) SetZoom(magnification float64) *WebviewWindow { w.options.Zoom = magnification if w.impl != nil { - invokeSync(func() { + InvokeSync(func() { w.impl.setZoom(magnification) }) } @@ -345,7 +345,7 @@ func (w *WebviewWindow) SetZoom(magnification float64) *WebviewWindow { // GetZoom returns the current zoom level of the window. func (w *WebviewWindow) GetZoom() float64 { if w.impl != nil { - return invokeSyncWithResult(w.impl.getZoom) + return InvokeSyncWithResult(w.impl.getZoom) } return 1 } @@ -354,7 +354,7 @@ func (w *WebviewWindow) GetZoom() float64 { func (w *WebviewWindow) SetResizable(b bool) *WebviewWindow { w.options.DisableResize = !b if w.impl != nil { - invokeSync(func() { + InvokeSync(func() { w.impl.setResizable(b) }) } @@ -387,11 +387,11 @@ func (w *WebviewWindow) SetMinSize(minWidth, minHeight int) *WebviewWindow { } if w.impl != nil { if newSize { - invokeSync(func() { + InvokeSync(func() { w.impl.setSize(newWidth, newHeight) }) } - invokeSync(func() { + InvokeSync(func() { w.impl.setMinSize(minWidth, minHeight) }) } @@ -419,11 +419,11 @@ func (w *WebviewWindow) SetMaxSize(maxWidth, maxHeight int) *WebviewWindow { } if w.impl != nil { if newSize { - invokeSync(func() { + InvokeSync(func() { w.impl.setSize(newWidth, newHeight) }) } - invokeSync(func() { + InvokeSync(func() { w.impl.setMaxSize(maxWidth, maxHeight) }) } @@ -446,7 +446,7 @@ func (w *WebviewWindow) Fullscreen() *WebviewWindow { } if !w.IsFullscreen() { w.disableSizeConstraints() - invokeSync(w.impl.fullscreen) + InvokeSync(w.impl.fullscreen) } return w } @@ -454,7 +454,7 @@ func (w *WebviewWindow) Fullscreen() *WebviewWindow { func (w *WebviewWindow) SetFullscreenButtonEnabled(enabled bool) *WebviewWindow { w.options.FullscreenButtonEnabled = enabled if w.impl != nil { - invokeSync(func() { + InvokeSync(func() { w.impl.setFullscreenButtonEnabled(enabled) }) } @@ -466,7 +466,7 @@ func (w *WebviewWindow) Flash(enabled bool) { if w.impl == nil { return } - invokeSync(func() { + InvokeSync(func() { w.impl.flash(enabled) }) } @@ -476,7 +476,7 @@ func (w *WebviewWindow) IsMinimised() bool { if w.impl == nil { return false } - return invokeSyncWithResult(w.impl.isMinimised) + return InvokeSyncWithResult(w.impl.isMinimised) } // IsVisible returns true if the window is visible @@ -484,7 +484,7 @@ func (w *WebviewWindow) IsVisible() bool { if w.impl == nil { return false } - return invokeSyncWithResult(w.impl.isVisible) + return InvokeSyncWithResult(w.impl.isVisible) } // IsMaximised returns true if the window is maximised @@ -492,7 +492,7 @@ func (w *WebviewWindow) IsMaximised() bool { if w.impl == nil { return false } - return invokeSyncWithResult(w.impl.isMaximised) + return InvokeSyncWithResult(w.impl.isMaximised) } // Size returns the size of the window @@ -501,7 +501,7 @@ func (w *WebviewWindow) Size() (int, int) { return 0, 0 } var width, height int - invokeSync(func() { + InvokeSync(func() { width, height = w.impl.size() }) return width, height @@ -512,7 +512,7 @@ func (w *WebviewWindow) IsFocused() bool { if w.impl == nil { return false } - return invokeSyncWithResult(w.impl.isFocused) + return InvokeSyncWithResult(w.impl.isFocused) } // IsFullscreen returns true if the window is fullscreen @@ -520,14 +520,14 @@ func (w *WebviewWindow) IsFullscreen() bool { if w.impl == nil { return false } - return invokeSyncWithResult(w.impl.isFullscreen) + return InvokeSyncWithResult(w.impl.isFullscreen) } // SetBackgroundColour sets the background colour of the window func (w *WebviewWindow) SetBackgroundColour(colour RGBA) *WebviewWindow { w.options.BackgroundColour = colour if w.impl != nil { - invokeSync(func() { + InvokeSync(func() { w.impl.setBackgroundColour(colour) }) } @@ -538,7 +538,7 @@ func (w *WebviewWindow) handleMessage(message string) { // Check for special messages if message == "drag" { if !w.IsFullscreen() { - invokeSync(func() { + InvokeSync(func() { err := w.startDrag() if err != nil { w.error("Failed to start drag: %s", err) @@ -571,7 +571,7 @@ func (w *WebviewWindow) startResize(border string) error { if w.impl == nil { return nil } - return invokeSyncWithResult(func() error { + return InvokeSyncWithResult(func() error { return w.impl.startResize(border) }) } @@ -582,7 +582,7 @@ func (w *WebviewWindow) Center() { w.options.Centered = true return } - invokeSync(w.impl.center) + InvokeSync(w.impl.center) } // On registers a callback for the given window event @@ -652,7 +652,7 @@ func (w *WebviewWindow) Width() int { if w.impl == nil { return 0 } - return invokeSyncWithResult(w.impl.width) + return InvokeSyncWithResult(w.impl.width) } // Height returns the height of the window @@ -660,7 +660,7 @@ func (w *WebviewWindow) Height() int { if w.impl == nil { return 0 } - return invokeSyncWithResult(w.impl.height) + return InvokeSyncWithResult(w.impl.height) } // RelativePosition returns the relative position of the window to the screen @@ -669,7 +669,7 @@ func (w *WebviewWindow) RelativePosition() (int, int) { return 0, 0 } var x, y int - invokeSync(func() { + InvokeSync(func() { x, y = w.impl.relativePosition() }) return x, y @@ -681,7 +681,7 @@ func (w *WebviewWindow) AbsolutePosition() (int, int) { return 0, 0 } var x, y int - invokeSync(func() { + InvokeSync(func() { x, y = w.impl.absolutePosition() }) return x, y @@ -697,7 +697,7 @@ func (w *WebviewWindow) Destroy() { cancelFunc() } - invokeSync(w.impl.destroy) + InvokeSync(w.impl.destroy) } // Reload reloads the page assets @@ -705,7 +705,7 @@ func (w *WebviewWindow) Reload() { if w.impl == nil { return } - invokeSync(w.impl.reload) + InvokeSync(w.impl.reload) } // ForceReload forces the window to reload the page assets @@ -713,7 +713,7 @@ func (w *WebviewWindow) ForceReload() { if w.impl == nil { return } - invokeSync(w.impl.forceReload) + InvokeSync(w.impl.forceReload) } // ToggleFullscreen toggles the window between fullscreen and normal @@ -721,7 +721,7 @@ func (w *WebviewWindow) ToggleFullscreen() { if w.impl == nil { return } - invokeSync(func() { + InvokeSync(func() { if w.IsFullscreen() { w.UnFullscreen() } else { @@ -734,13 +734,13 @@ func (w *WebviewWindow) ToggleDevTools() { if w.impl == nil { return } - invokeSync(w.impl.toggleDevTools) + InvokeSync(w.impl.toggleDevTools) } // ZoomReset resets the zoom level of the webview content to 100% func (w *WebviewWindow) ZoomReset() *WebviewWindow { if w.impl != nil { - invokeSync(w.impl.zoomReset) + InvokeSync(w.impl.zoomReset) w.emit(events.Common.WindowZoomReset) } return w @@ -752,7 +752,7 @@ func (w *WebviewWindow) ZoomIn() { if w.impl == nil { return } - invokeSync(w.impl.zoomIn) + InvokeSync(w.impl.zoomIn) w.emit(events.Common.WindowZoomIn) } @@ -762,7 +762,7 @@ func (w *WebviewWindow) ZoomOut() { if w.impl == nil { return } - invokeSync(w.impl.zoomOut) + InvokeSync(w.impl.zoomOut) w.emit(events.Common.WindowZoomOut) } @@ -778,7 +778,7 @@ func (w *WebviewWindow) Zoom() { if w.impl == nil { return } - invokeSync(w.impl.zoom) + InvokeSync(w.impl.zoom) w.emit(events.Common.WindowZoom) } @@ -786,7 +786,7 @@ func (w *WebviewWindow) Zoom() { func (w *WebviewWindow) SetHTML(html string) *WebviewWindow { w.options.HTML = html if w.impl != nil { - invokeSync(func() { + InvokeSync(func() { w.impl.setHTML(html) }) } @@ -798,7 +798,7 @@ func (w *WebviewWindow) SetRelativePosition(x, y int) *WebviewWindow { w.options.X = x w.options.Y = y if w.impl != nil { - invokeSync(func() { + InvokeSync(func() { w.impl.setRelativePosition(x, y) }) } @@ -812,7 +812,7 @@ func (w *WebviewWindow) Minimise() *WebviewWindow { return w } if !w.IsMinimised() { - invokeSync(w.impl.minimise) + InvokeSync(w.impl.minimise) w.emit(events.Common.WindowMinimise) } return w @@ -826,7 +826,7 @@ func (w *WebviewWindow) Maximise() *WebviewWindow { } if !w.IsMaximised() { w.disableSizeConstraints() - invokeSync(w.impl.maximise) + InvokeSync(w.impl.maximise) w.emit(events.Common.WindowMaximise) } return w @@ -838,7 +838,7 @@ func (w *WebviewWindow) UnMinimise() { return } if w.IsMinimised() { - invokeSync(w.impl.unminimise) + InvokeSync(w.impl.unminimise) w.emit(events.Common.WindowUnMinimise) } } @@ -850,7 +850,7 @@ func (w *WebviewWindow) UnMaximise() { } if w.IsMaximised() { w.enableSizeConstraints() - invokeSync(w.impl.unmaximise) + InvokeSync(w.impl.unmaximise) w.emit(events.Common.WindowUnMaximise) } } @@ -862,7 +862,7 @@ func (w *WebviewWindow) UnFullscreen() { } if w.IsFullscreen() { w.enableSizeConstraints() - invokeSync(w.impl.unfullscreen) + InvokeSync(w.impl.unfullscreen) w.emit(events.Common.WindowUnFullscreen) } } @@ -872,7 +872,7 @@ func (w *WebviewWindow) Restore() { if w.impl == nil { return } - invokeSync(func() { + InvokeSync(func() { if w.IsMinimised() { w.UnMinimise() } else if w.IsMaximised() { @@ -888,7 +888,7 @@ func (w *WebviewWindow) disableSizeConstraints() { if w.impl == nil { return } - invokeSync(func() { + InvokeSync(func() { if w.options.MinWidth > 0 && w.options.MinHeight > 0 { w.impl.setMinSize(0, 0) } @@ -902,7 +902,7 @@ func (w *WebviewWindow) enableSizeConstraints() { if w.impl == nil { return } - invokeSync(func() { + InvokeSync(func() { if w.options.MinWidth > 0 && w.options.MinHeight > 0 { w.SetMinSize(w.options.MinWidth, w.options.MinHeight) } @@ -917,14 +917,14 @@ func (w *WebviewWindow) GetScreen() (*Screen, error) { if w.impl == nil { return nil, nil } - return invokeSyncWithResultAndError(w.impl.getScreen) + return InvokeSyncWithResultAndError(w.impl.getScreen) } // SetFrameless removes the window frame and title bar func (w *WebviewWindow) SetFrameless(frameless bool) *WebviewWindow { w.options.Frameless = frameless if w.impl != nil { - invokeSync(func() { + InvokeSync(func() { w.impl.setFrameless(frameless) }) } @@ -932,7 +932,7 @@ func (w *WebviewWindow) SetFrameless(frameless bool) *WebviewWindow { } func (w *WebviewWindow) dispatchWailsEvent(event *WailsEvent) { - msg := fmt.Sprintf("_wails.dispatchWailsEvent(%s);", event.ToJSON()) + msg := fmt.Sprintf("_wails.dispatchWailsEvent(%s);", event.toJSON()) w.ExecJS(msg) } @@ -1006,7 +1006,7 @@ func (w *WebviewWindow) Focus() { w.options.Focused = true return } - invokeSync(w.impl.focus) + InvokeSync(w.impl.focus) w.emit(events.Common.WindowFocus) } @@ -1021,21 +1021,21 @@ func (w *WebviewWindow) startDrag() error { if w.impl == nil { return nil } - return invokeSyncWithError(w.impl.startDrag) + return InvokeSyncWithError(w.impl.startDrag) } func (w *WebviewWindow) Print() error { if w.impl == nil { return nil } - return invokeSyncWithError(w.impl.print) + return InvokeSyncWithError(w.impl.print) } func (w *WebviewWindow) SetEnabled(enabled bool) { if w.impl == nil { return } - invokeSync(func() { + InvokeSync(func() { w.impl.setEnabled(enabled) }) } @@ -1045,7 +1045,7 @@ func (w *WebviewWindow) SetAbsolutePosition(x int, y int) { if w.impl == nil { return } - invokeSync(func() { + InvokeSync(func() { w.impl.setAbsolutePosition(x, y) }) } @@ -1071,7 +1071,7 @@ func (w *WebviewWindow) handleKeyEvent(acceleratorString string) { if w.impl == nil { return } - invokeSync(func() { + InvokeSync(func() { w.impl.handleKeyEvent(acceleratorString) }) } diff --git a/v3/pkg/application/webview_window_darwin.go b/v3/pkg/application/webview_window_darwin.go index 7d481281..39657b75 100644 --- a/v3/pkg/application/webview_window_darwin.go +++ b/v3/pkg/application/webview_window_darwin.go @@ -1146,7 +1146,7 @@ func (w *macosWebviewWindow) setBackgroundColour(colour RGBA) { func (w *macosWebviewWindow) relativePosition() (int, int) { var x, y C.int - invokeSync(func() { + InvokeSync(func() { C.windowGetRelativePosition(w.nsWindow, &x, &y) }) @@ -1155,7 +1155,7 @@ func (w *macosWebviewWindow) relativePosition() (int, int) { func (w *macosWebviewWindow) absolutePosition() (int, int) { var x, y C.int - invokeSync(func() { + InvokeSync(func() { C.windowGetAbsolutePosition(w.nsWindow, &x, &y) }) diff --git a/v3/pkg/application/webview_window_windows.go b/v3/pkg/application/webview_window_windows.go index a24eab69..1c6c4351 100644 --- a/v3/pkg/application/webview_window_windows.go +++ b/v3/pkg/application/webview_window_windows.go @@ -967,7 +967,7 @@ func (w *windowsWebviewWindow) WndProc(msg uint32, wparam, lparam uintptr) uintp // depends on the content in the WebView, see https://github.com/wailsapp/wails/issues/1319 } else if w.resizeDebouncer != nil { w.resizeDebouncer(func() { - invokeSync(func() { + InvokeSync(func() { w.chromium.Resize() }) })