Fix bad merge

This commit is contained in:
Lea Anthony 2023-02-12 13:36:58 +11:00
commit d86e11cef1
No known key found for this signature in database
GPG key ID: 33DAF7BB90A58405
16 changed files with 623 additions and 396 deletions

View file

@ -59,3 +59,14 @@ TBD
Dialogs are now available in JavaScript!
## Drag and Drop
TBD
## Context Menus
Context menus are contextual menus that are shown when the user right clicks on an element. Creating a context menu is the same as creating a standard menu , by using `app.NewMenu()`. To make the context menu available to a window, call `window.RegisterContextMenu(name, menu)`. The name will be the id of the context menu and used by the frontend.
To indicate that an element has a context menu, add the `data-contextmenu` attribute to the element. The value of this attribute should be the name of a context menu previously registered with the window.
It is possible to register a context menu at the application level, making it available to all windows. This can be done using `app.RegisterContextMenu(name, menu)`. If a context menu cannot be found at the window level, the application context menus will be checked. A demo of this can be found in `v3/examples/contextmenus`.

View file

@ -8,13 +8,15 @@
<body>
<h1>Events Demo</h1>
<br/>
The main program emits an event every 10s which will be displayed in the section below.
To send an event from this window, click here: <button onclick="wails.Events.Emit({name:'myevent', data:'hello!'})">Send Event</button>
<div id="results"></div>
</body>
<script>
wails.Events.On("myevent", function(data) {
let currentHTML = document.getElementById("results").innerHTML;
document.getElementById("results").innerHTML = currentHTML + "<br/>" + JSON.stringify(data);;
document.getElementById("results").innerHTML = currentHTML + "<br/>" + JSON.stringify(data);
})
</script>

View file

@ -6,11 +6,8 @@ import (
"log"
"time"
"github.com/wailsapp/wails/v3/pkg/events"
"github.com/wailsapp/wails/v3/pkg/options"
"github.com/wailsapp/wails/v3/pkg/application"
"github.com/wailsapp/wails/v3/pkg/events"
)
//go:embed assets
@ -18,10 +15,10 @@ var assets embed.FS
func main() {
app := application.New(options.Application{
app := application.New(application.Options{
Name: "Events Demo",
Description: "A demo of the Events API",
Mac: options.Mac{
Mac: application.MacOptions{
ApplicationShouldTerminateAfterLastWindowClosed: true,
},
})
@ -41,25 +38,25 @@ func main() {
}
})
app.NewWebviewWindowWithOptions(&options.WebviewWindow{
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
Title: "Events Demo",
Assets: options.Assets{
Assets: application.AssetOptions{
FS: assets,
},
Mac: options.MacWindow{
Backdrop: options.MacBackdropTranslucent,
TitleBar: options.TitleBarHiddenInsetUnified,
Mac: application.MacWindow{
Backdrop: application.MacBackdropTranslucent,
TitleBar: application.MacTitleBarHiddenInsetUnified,
InvisibleTitleBarHeight: 50,
},
})
app.NewWebviewWindowWithOptions(&options.WebviewWindow{
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
Title: "Events Demo",
Assets: options.Assets{
Assets: application.AssetOptions{
FS: assets,
},
Mac: options.MacWindow{
Backdrop: options.MacBackdropTranslucent,
TitleBar: options.TitleBarHiddenInsetUnified,
Mac: application.MacWindow{
Backdrop: application.MacBackdropTranslucent,
TitleBar: application.MacTitleBarHiddenInsetUnified,
InvisibleTitleBarHeight: 50,
},
})

View file

@ -9,7 +9,6 @@ The electron alternative for Go
*/
/* jshint esversion: 9 */
import {dialogCallback, dialogErrorCallback, Error, Info, OpenFile, Question, SaveFile, Warning,} from "./dialogs";
import * as Clipboard from './clipboard';
import * as Application from './application';
@ -17,12 +16,14 @@ import * as Log from './log';
import {newWindow} from "./window";
import {dispatchCustomEvent, Emit, Off, OffAll, On, Once, OnMultiple} from "./events";
import {dialogCallback, dialogErrorCallback, Error, Info, OpenFile, Question, SaveFile, Warning,} from "./dialogs";
import {enableContextMenus} from "./contextmenu";
// Internal wails endpoints
window.wails = {
...newRuntime(-1),
};
// Internal wails endpoints
window._wails = {
dialogCallback,
dialogErrorCallback,
@ -63,3 +64,4 @@ if (DEBUG) {
console.log("Wails v3.0.0 Debug Mode Enabled");
}
enableContextMenus(true);

View file

@ -13,6 +13,7 @@
"happy-dom": "^8.1.5",
"nanoid": "^4.0.0",
"npm-check-updates": "^16.6.3",
"svelte": "^3.55.1",
"vitest": "^0.28.3"
}
},
@ -4408,6 +4409,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/svelte": {
"version": "3.55.1",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.55.1.tgz",
"integrity": "sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/tar": {
"version": "6.1.13",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz",
@ -8185,6 +8195,12 @@
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true
},
"svelte": {
"version": "3.55.1",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.55.1.tgz",
"integrity": "sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ==",
"dev": true
},
"tar": {
"version": "6.1.13",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz",

View file

@ -11,6 +11,7 @@
"happy-dom": "^8.1.5",
"nanoid": "^4.0.0",
"npm-check-updates": "^16.6.3",
"svelte": "^3.55.1",
"vitest": "^0.28.3"
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -9,10 +9,8 @@ import (
"github.com/wailsapp/wails/v3/pkg/logger"
"github.com/wailsapp/wails/v3/pkg/events"
"github.com/wailsapp/wails/v3/pkg/options"
"github.com/wailsapp/wails/v2/pkg/assetserver/webview"
"github.com/wailsapp/wails/v3/pkg/events"
)
var globalApplication *App
@ -21,7 +19,7 @@ func init() {
runtime.LockOSThread()
}
func New(appOptions options.Application) *App {
func New(appOptions Options) *App {
if globalApplication != nil {
return globalApplication
}
@ -33,6 +31,7 @@ func New(appOptions options.Application) *App {
applicationEventListeners: make(map[uint][]func()),
systemTrays: make(map[uint]*SystemTray),
log: logger.New(appOptions.Logger.CustomLoggers...),
contextMenus: make(map[string]*Menu),
}
if !appOptions.Logger.Silent {
@ -44,7 +43,7 @@ func New(appOptions options.Application) *App {
return result
}
func mergeApplicationDefaults(o *options.Application) {
func mergeApplicationDefaults(o *Options) {
if o.Name == "" {
o.Name = "My Wails Application"
}
@ -79,6 +78,13 @@ type windowMessage struct {
var windowMessageBuffer = make(chan *windowMessage)
type dragAndDropMessage struct {
windowId uint
filenames []string
}
var windowDragAndDropBuffer = make(chan *dragAndDropMessage)
type webViewAssetRequest struct {
windowId uint
request webview.Request
@ -87,7 +93,7 @@ type webViewAssetRequest struct {
var webviewRequests = make(chan *webViewAssetRequest)
type App struct {
options options.Application
options Options
applicationEventListeners map[uint][]func()
applicationEventListenersLock sync.RWMutex
@ -117,6 +123,9 @@ type App struct {
clipboard *Clipboard
Events *EventProcessor
log *logger.Logger
contextMenus map[string]*Menu
contextMenusLock sync.Mutex
}
func (a *App) getSystemTrayID() uint {
@ -179,10 +188,10 @@ func (a *App) error(message string, args ...any) {
})
}
func (a *App) NewWebviewWindowWithOptions(windowOptions *options.WebviewWindow) *WebviewWindow {
func (a *App) NewWebviewWindowWithOptions(windowOptions *WebviewWindowOptions) *WebviewWindow {
// Ensure we have sane defaults
if windowOptions == nil {
windowOptions = options.WindowDefaults
windowOptions = WebviewWindowDefaults
}
newWindow := NewWindow(windowOptions)
@ -247,6 +256,12 @@ func (a *App) Run() error {
a.handleWindowMessage(event)
}
}()
go func() {
for {
dragAndDropMessage := <-windowDragAndDropBuffer
a.handleDragAndDropMessage(dragAndDropMessage)
}
}()
go func() {
for {
@ -286,6 +301,19 @@ func (a *App) handleApplicationEvent(event uint) {
}
}
func (a *App) handleDragAndDropMessage(event *dragAndDropMessage) {
// Get window from window map
a.windowsLock.Lock()
window, ok := a.windows[event.windowId]
a.windowsLock.Unlock()
if !ok {
log.Printf("WebviewWindow #%d not found", event.windowId)
return
}
// Get callback from window
window.handleDragAndDropMessage(event)
}
func (a *App) handleWindowMessage(event *windowMessage) {
// Get window from window map
a.windowsLock.Lock()
@ -463,3 +491,17 @@ func (a *App) Show() {
func (a *App) Log(message *logger.Message) {
a.log.Log(message)
}
func (a *App) RegisterContextMenu(name string, menu *Menu) {
a.contextMenusLock.Lock()
defer a.contextMenusLock.Unlock()
a.contextMenus[name] = menu
}
func (a *App) getContextMenu(name string) (*Menu, bool) {
a.contextMenusLock.Lock()
defer a.contextMenusLock.Unlock()
menu, ok := a.contextMenus[name]
return menu, ok
}

View file

@ -67,6 +67,8 @@ func (m *MessageProcessor) HandleRuntimeCall(rw http.ResponseWriter, r *http.Req
m.processApplicationMethod(method, rw, r, targetWindow, params)
case "log":
m.processLogMethod(method, rw, r, targetWindow, params)
case "contextmenu":
m.processContextMenuMethod(method, rw, r, targetWindow, params)
default:
m.httpError(rw, "Unknown runtime call: %s", object)
}

View file

@ -2,11 +2,9 @@ package application
import (
"net/http"
"github.com/wailsapp/wails/v3/pkg/options"
)
func (m *MessageProcessor) processWindowMethod(method string, rw http.ResponseWriter, r *http.Request, window *WebviewWindow, params QueryParams) {
func (m *MessageProcessor) processWindowMethod(method string, rw http.ResponseWriter, _ *http.Request, window *WebviewWindow, params QueryParams) {
args, err := params.Args()
if err != nil {
@ -104,7 +102,7 @@ func (m *MessageProcessor) processWindowMethod(method string, rw http.ResponseWr
m.Error("Invalid SetBackgroundColour Message: 'a' value required")
return
}
window.SetBackgroundColour(&options.RGBA{
window.SetBackgroundColour(&RGBA{
Red: *r,
Green: *g,
Blue: *b,

View file

@ -1,4 +1,4 @@
package options
package application
import (
"io/fs"
@ -14,7 +14,7 @@ const (
WindowStateFullscreen
)
type WebviewWindow struct {
type WebviewWindowOptions struct {
Name string
Title string
Width, Height int
@ -29,7 +29,7 @@ type WebviewWindow struct {
StartState WindowState
Mac MacWindow
BackgroundColour *RGBA
Assets Assets
Assets AssetOptions
HTML string
JS string
CSS string
@ -41,14 +41,14 @@ type WebviewWindow struct {
Zoom float64
}
var WindowDefaults = &WebviewWindow{
var WebviewWindowDefaults = &WebviewWindowOptions{
Title: "",
Width: 800,
Height: 600,
URL: "",
}
type Assets struct {
type AssetOptions struct {
// FS to use for loading assets from
FS fs.FS
// Handler is a custom handler to use for serving assets. If this is set, the `URL` and `FS` fields are ignored.

View file

@ -12,7 +12,6 @@ import (
assetserveroptions "github.com/wailsapp/wails/v2/pkg/options/assetserver"
"github.com/wailsapp/wails/v3/internal/runtime"
"github.com/wailsapp/wails/v3/pkg/events"
"github.com/wailsapp/wails/v3/pkg/options"
)
type (
@ -26,7 +25,7 @@ type (
setMaxSize(width, height int)
execJS(js string)
restore()
setBackgroundColour(color *options.RGBA)
setBackgroundColour(color *RGBA)
run()
center()
size() (int, int)
@ -63,11 +62,12 @@ type (
hide()
getScreen() (*Screen, error)
setFrameless(bool)
openContextMenu(menu *Menu, data *ContextMenuData)
}
)
type WebviewWindow struct {
options *options.WebviewWindow
options *WebviewWindowOptions
impl webviewWindowImpl
implLock sync.RWMutex
id uint
@ -75,8 +75,11 @@ type WebviewWindow struct {
assets *assetserver.AssetServer
messageProcessor *MessageProcessor
eventListeners map[uint][]func()
eventListeners map[uint][]func(ctx *WindowEventContext)
eventListenersLock sync.RWMutex
contextMenus map[string]*Menu
contextMenusLock sync.RWMutex
}
var windowID uint
@ -89,7 +92,7 @@ func getWindowID() uint {
return windowID
}
func NewWindow(options *options.WebviewWindow) *WebviewWindow {
func NewWindow(options *WebviewWindowOptions) *WebviewWindow {
if options.Width == 0 {
options.Width = 800
}
@ -110,7 +113,8 @@ func NewWindow(options *options.WebviewWindow) *WebviewWindow {
result := &WebviewWindow{
id: getWindowID(),
options: options,
eventListeners: make(map[uint][]func()),
eventListeners: make(map[uint][]func(ctx *WindowEventContext)),
contextMenus: make(map[string]*Menu),
assets: srv,
}
@ -313,7 +317,7 @@ func (w *WebviewWindow) ExecJS(js string) {
func (w *WebviewWindow) Fullscreen() *WebviewWindow {
if w.impl == nil {
w.options.StartState = options.WindowStateFullscreen
w.options.StartState = WindowStateFullscreen
return w
}
if !w.IsFullscreen() {
@ -365,7 +369,7 @@ func (w *WebviewWindow) IsFullscreen() bool {
return w.impl.isFullscreen()
}
func (w *WebviewWindow) SetBackgroundColour(colour *options.RGBA) *WebviewWindow {
func (w *WebviewWindow) SetBackgroundColour(colour *RGBA) *WebviewWindow {
w.options.BackgroundColour = colour
if w.impl != nil {
w.impl.setBackgroundColour(colour)
@ -396,7 +400,7 @@ func (w *WebviewWindow) Center() {
w.impl.center()
}
func (w *WebviewWindow) On(eventType events.WindowEventType, callback func()) {
func (w *WebviewWindow) On(eventType events.WindowEventType, callback func(ctx *WindowEventContext)) {
eventID := uint(eventType)
w.eventListenersLock.Lock()
defer w.eventListenersLock.Unlock()
@ -409,7 +413,7 @@ func (w *WebviewWindow) On(eventType events.WindowEventType, callback func()) {
func (w *WebviewWindow) handleWindowEvent(id uint) {
w.eventListenersLock.RLock()
for _, callback := range w.eventListeners[id] {
go callback()
go callback(blankWindowEventContext)
}
w.eventListenersLock.RUnlock()
}
@ -538,7 +542,7 @@ func (w *WebviewWindow) SetPosition(x, y int) *WebviewWindow {
func (w *WebviewWindow) Minimise() *WebviewWindow {
if w.impl == nil {
w.options.StartState = options.WindowStateMinimised
w.options.StartState = WindowStateMinimised
return w
}
if !w.IsMinimised() {
@ -549,7 +553,7 @@ func (w *WebviewWindow) Minimise() *WebviewWindow {
func (w *WebviewWindow) Maximise() *WebviewWindow {
if w.impl == nil {
w.options.StartState = options.WindowStateMaximised
w.options.StartState = WindowStateMaximised
return w
}
if !w.IsMaximised() {
@ -641,3 +645,46 @@ func (w *WebviewWindow) info(message string, args ...any) {
Time: time.Now(),
})
}
func (w *WebviewWindow) error(message string, args ...any) {
globalApplication.Log(&logger.Message{
Level: "ERROR",
Message: message,
Data: args,
Sender: w.Name(),
Time: time.Now(),
})
}
func (w *WebviewWindow) handleDragAndDropMessage(event *dragAndDropMessage) {
println("Drag and drop message received for " + w.Name())
// Print filenames
ctx := newWindowEventContext()
ctx.setDroppedFiles(event.filenames)
for _, listener := range w.eventListeners[uint(events.FilesDropped)] {
listener(ctx)
}
}
func (w *WebviewWindow) openContextMenu(data *ContextMenuData) {
menu, ok := w.contextMenus[data.Id]
if !ok {
// try application level context menu
menu, ok = globalApplication.getContextMenu(data.Id)
if !ok {
w.error("No context menu found for id: %s", data.Id)
return
}
}
menu.setContextData(data)
if w.impl == nil {
return
}
w.impl.openContextMenu(menu, data)
}
func (w *WebviewWindow) RegisterContextMenu(name string, menu *Menu) {
w.contextMenusLock.Lock()
defer w.contextMenusLock.Unlock()
w.contextMenus[name] = menu
}

View file

@ -12,6 +12,8 @@ package application
#include "Cocoa/Cocoa.h"
#import <WebKit/WebKit.h>
#import <AppKit/AppKit.h>
#import "webview_drag.h"
extern void registerListener(unsigned int event);
@ -69,6 +71,12 @@ void* windowNew(unsigned int id, int width, int height, bool fraudulentWebsiteWa
delegate.webView = webView;
delegate.hideOnClose = false;
WebviewDrag* dragView = [[WebviewDrag alloc] initWithFrame:NSMakeRect(0, 0, width-1, height-1)];
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[view addSubview:dragView];
dragView.windowId = id;
return window;
}
@ -748,6 +756,24 @@ static void windowHide(void *window) {
});
}
// windowShowMenu opens an NSMenu at the given coordinates
static void windowShowMenu(void *window, void *menu, int x, int y) {
dispatch_async(dispatch_get_main_queue(), ^{
// get main window
WebviewWindow* nsWindow = (WebviewWindow*)window;
// get menu
NSMenu* nsMenu = (NSMenu*)menu;
// get webview
WebviewWindowDelegate* windowDelegate = (WebviewWindowDelegate*)[nsWindow delegate];
// get webview
WKWebView* webView = (WKWebView*)windowDelegate.webView;
NSPoint point = NSMakePoint(x, y);
[nsMenu popUpMenuPositioningItem:nil atLocation:point inView:webView];
});
}
// Make the given window frameless
static void windowSetFrameless(void *window, bool frameless) {
dispatch_async(dispatch_get_main_queue(), ^{
@ -769,8 +795,6 @@ import (
"unsafe"
"github.com/wailsapp/wails/v3/pkg/events"
"github.com/wailsapp/wails/v3/pkg/options"
)
var showDevTools = func(window unsafe.Pointer) {}
@ -780,6 +804,13 @@ type macosWebviewWindow struct {
parent *WebviewWindow
}
func (w *macosWebviewWindow) openContextMenu(menu *Menu, data *ContextMenuData) {
// Create the menu
thisMenu := newMenuImpl(menu)
thisMenu.update()
C.windowShowMenu(w.nsWindow, thisMenu.nsMenu, C.int(data.X), C.int(data.Y))
}
func (w *macosWebviewWindow) getZoom() float64 {
return float64(C.windowZoomGet(w.nsWindow))
}
@ -1049,10 +1080,10 @@ func (w *macosWebviewWindow) run() {
macOptions := w.parent.options.Mac
switch macOptions.Backdrop {
case options.MacBackdropTransparent:
case MacBackdropTransparent:
C.windowSetTransparent(w.nsWindow)
C.webviewSetTransparent(w.nsWindow)
case options.MacBackdropTranslucent:
case MacBackdropTranslucent:
C.windowSetTranslucent(w.nsWindow)
C.webviewSetTransparent(w.nsWindow)
}
@ -1077,11 +1108,11 @@ func (w *macosWebviewWindow) run() {
}
switch w.parent.options.StartState {
case options.WindowStateMaximised:
case WindowStateMaximised:
w.maximise()
case options.WindowStateMinimised:
case WindowStateMinimised:
w.minimise()
case options.WindowStateFullscreen:
case WindowStateFullscreen:
w.fullscreen()
}
@ -1091,7 +1122,7 @@ func (w *macosWebviewWindow) run() {
w.setURL(w.parent.options.URL)
}
// We need to wait for the HTML to load before we can execute the javascript
w.parent.On(events.Mac.WebViewDidFinishNavigation, func() {
w.parent.On(events.Mac.WebViewDidFinishNavigation, func(_ *WindowEventContext) {
if w.parent.options.JS != "" {
w.execJS(w.parent.options.JS)
}
@ -1108,7 +1139,7 @@ func (w *macosWebviewWindow) run() {
})
}
func (w *macosWebviewWindow) setBackgroundColour(colour *options.RGBA) {
func (w *macosWebviewWindow) setBackgroundColour(colour *RGBA) {
if colour == nil {
return
}

View file

@ -1,15 +0,0 @@
package options
import "github.com/wailsapp/wails/v3/pkg/logger"
type Application struct {
Name string
Description string
Icon []byte
Mac Mac
Bind []interface{}
Logger struct {
Silent bool
CustomLoggers []logger.Output
}
}