mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-06 22:42:09 +08:00

This commit adds a robust teardown process for windows on application shutdown. It introduces a field to track the destruction state of each window and checks such before performing window operations. Also, it enhances the destroy functions within application for thorough clean up. Finally, redundant event handlers related to application termination were removed while fixing file generating challenge in go tasks.
377 lines
12 KiB
Go
377 lines
12 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
var eventsGo = `package events
|
|
|
|
type ApplicationEventType uint
|
|
type WindowEventType uint
|
|
|
|
var Common = newCommonEvents()
|
|
|
|
type commonEvents struct {
|
|
$$COMMONEVENTSDECL}
|
|
|
|
func newCommonEvents() commonEvents {
|
|
return commonEvents{
|
|
$$COMMONEVENTSVALUES }
|
|
}
|
|
|
|
var Linux = newLinuxEvents()
|
|
|
|
type linuxEvents struct {
|
|
$$LINUXEVENTSDECL}
|
|
|
|
func newLinuxEvents() linuxEvents {
|
|
return linuxEvents{
|
|
$$LINUXEVENTSVALUES }
|
|
}
|
|
|
|
var Mac = newMacEvents()
|
|
|
|
type macEvents struct {
|
|
$$MACEVENTSDECL}
|
|
|
|
func newMacEvents() macEvents {
|
|
return macEvents{
|
|
$$MACEVENTSVALUES }
|
|
}
|
|
|
|
var Windows = newWindowsEvents()
|
|
|
|
type windowsEvents struct {
|
|
$$WINDOWSEVENTSDECL}
|
|
|
|
func newWindowsEvents() windowsEvents {
|
|
return windowsEvents{
|
|
$$WINDOWSEVENTSVALUES }
|
|
}
|
|
|
|
func JSEvent(event uint) string {
|
|
return eventToJS[event]
|
|
}
|
|
|
|
var eventToJS = map[uint]string{
|
|
$$EVENTTOJS}
|
|
|
|
`
|
|
|
|
var eventsH = `//go:build darwin
|
|
|
|
#ifndef _events_h
|
|
#define _events_h
|
|
|
|
extern void processApplicationEvent(unsigned int, void* data);
|
|
extern void processWindowEvent(unsigned int, unsigned int);
|
|
|
|
$$CHEADEREVENTS
|
|
|
|
#endif`
|
|
|
|
var eventsJS = `
|
|
export const EventTypes = {
|
|
Windows: {
|
|
$$WINDOWSJSEVENTS },
|
|
Mac: {
|
|
$$MACJSEVENTS },
|
|
Linux: {
|
|
$$LINUXJSEVENTS },
|
|
Common: {
|
|
$$COMMONJSEVENTS },
|
|
};
|
|
`
|
|
|
|
var eventsTS = `
|
|
export declare const EventTypes: {
|
|
Windows: {
|
|
$$WINDOWSTSEVENTS },
|
|
Mac: {
|
|
$$MACTSEVENTS },
|
|
Linux: {
|
|
$$LINUXTSEVENTS },
|
|
Common: {
|
|
$$COMMONTSEVENTS },
|
|
};
|
|
`
|
|
|
|
func main() {
|
|
|
|
eventNames, err := os.ReadFile("../../pkg/events/events.txt")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
linuxEventsDecl := bytes.NewBufferString("")
|
|
linuxEventsValues := bytes.NewBufferString("")
|
|
|
|
macEventsDecl := bytes.NewBufferString("")
|
|
macEventsValues := bytes.NewBufferString("")
|
|
cHeaderEvents := bytes.NewBufferString("")
|
|
windowDelegateEvents := bytes.NewBufferString("")
|
|
applicationDelegateEvents := bytes.NewBufferString("")
|
|
webviewDelegateEvents := bytes.NewBufferString("")
|
|
|
|
windowsEventsDecl := bytes.NewBufferString("")
|
|
windowsEventsValues := bytes.NewBufferString("")
|
|
|
|
commonEventsDecl := bytes.NewBufferString("")
|
|
commonEventsValues := bytes.NewBufferString("")
|
|
|
|
linuxJSEvents := bytes.NewBufferString("")
|
|
macJSEvents := bytes.NewBufferString("")
|
|
windowsJSEvents := bytes.NewBufferString("")
|
|
commonJSEvents := bytes.NewBufferString("")
|
|
|
|
linuxTSEvents := bytes.NewBufferString("")
|
|
macTSEvents := bytes.NewBufferString("")
|
|
windowsTSEvents := bytes.NewBufferString("")
|
|
commonTSEvents := bytes.NewBufferString("")
|
|
|
|
eventToJS := bytes.NewBufferString("")
|
|
|
|
var id int
|
|
// var maxLinuxEvents int
|
|
var maxMacEvents int
|
|
var line []byte
|
|
// Loop over each line in the file
|
|
for id, line = range bytes.Split(eventNames, []byte{'\n'}) {
|
|
|
|
// First 1024 is reserved
|
|
id = id + 1024
|
|
|
|
// Skip empty lines
|
|
if len(line) == 0 {
|
|
continue
|
|
}
|
|
|
|
// split on the colon
|
|
split := bytes.Split(line, []byte{':'})
|
|
platform := strings.TrimSpace(string(split[0]))
|
|
event := strings.TrimSpace(string(split[1]))
|
|
var ignoreEvent bool
|
|
if strings.HasSuffix(event, "!") {
|
|
event = event[:len(event)-1]
|
|
ignoreEvent = true
|
|
}
|
|
|
|
// Title case the event name
|
|
eventTitle := string(bytes.ToUpper([]byte{event[0]})) + event[1:]
|
|
// delegate function name has a lowercase first character
|
|
delegateEventFunction := string(bytes.ToLower([]byte{event[0]})) + event[1:]
|
|
|
|
// Add to buffer
|
|
switch platform {
|
|
case "linux":
|
|
eventType := "ApplicationEventType"
|
|
if strings.HasPrefix(event, "Window") {
|
|
eventType = "WindowEventType"
|
|
}
|
|
if strings.HasPrefix(event, "WebView") {
|
|
eventType = "WindowEventType"
|
|
}
|
|
linuxEventsDecl.WriteString("\t" + eventTitle + " " + eventType + "\n")
|
|
linuxEventsValues.WriteString("\t\t" + event + ": " + strconv.Itoa(id) + ",\n")
|
|
linuxJSEvents.WriteString("\t\t" + event + ": \"" + strings.TrimSpace(string(line)) + "\",\n")
|
|
linuxTSEvents.WriteString("\t\t" + event + ": string,\n")
|
|
eventToJS.WriteString("\t" + strconv.Itoa(id) + ": \"" + strings.TrimSpace(string(line)) + "\",\n")
|
|
//maxLinuxEvents = id
|
|
case "mac":
|
|
eventType := "ApplicationEventType"
|
|
if strings.HasPrefix(event, "Window") {
|
|
eventType = "WindowEventType"
|
|
}
|
|
if strings.HasPrefix(event, "WebView") {
|
|
eventType = "WindowEventType"
|
|
}
|
|
macEventsDecl.WriteString("\t" + eventTitle + " " + eventType + "\n")
|
|
macEventsValues.WriteString("\t\t" + event + ": " + strconv.Itoa(id) + ",\n")
|
|
macJSEvents.WriteString("\t\t" + event + ": \"" + strings.TrimSpace(string(line)) + "\",\n")
|
|
macTSEvents.WriteString("\t\t" + event + ": string,\n")
|
|
cHeaderEvents.WriteString("#define Event" + eventTitle + " " + strconv.Itoa(id) + "\n")
|
|
eventToJS.WriteString("\t" + strconv.Itoa(id) + ": \"" + strings.TrimSpace(string(line)) + "\",\n")
|
|
maxMacEvents = id
|
|
if ignoreEvent {
|
|
continue
|
|
}
|
|
// Check if this is a window event
|
|
if strings.HasPrefix(event, "Window") {
|
|
windowDelegateEvents.WriteString(`- (void)` + delegateEventFunction + `:(NSNotification *)notification {
|
|
if( hasListeners(Event` + eventTitle + `) ) {
|
|
processWindowEvent(self.windowId, Event` + eventTitle + `);
|
|
}
|
|
}
|
|
|
|
`)
|
|
}
|
|
// Check if this is a webview event
|
|
if strings.HasPrefix(event, "WebView") {
|
|
webViewFunction := strings.TrimPrefix(event, "WebView")
|
|
webViewFunction = string(bytes.ToLower([]byte{webViewFunction[0]})) + webViewFunction[1:]
|
|
webviewDelegateEvents.WriteString(`- (void)webView:(WKWebView *)webview ` + webViewFunction + `:(WKNavigation *)navigation {
|
|
if( hasListeners(Event` + eventTitle + `) ) {
|
|
processWindowEvent(self.windowId, Event` + eventTitle + `);
|
|
}
|
|
}
|
|
|
|
`)
|
|
}
|
|
if strings.HasPrefix(event, "Application") {
|
|
applicationDelegateEvents.WriteString(`- (void)` + delegateEventFunction + `:(NSNotification *)notification {
|
|
if( hasListeners(Event` + eventTitle + `) ) {
|
|
processApplicationEvent(Event` + eventTitle + `, NULL);
|
|
}
|
|
}
|
|
|
|
`)
|
|
}
|
|
case "common":
|
|
eventType := "ApplicationEventType"
|
|
if strings.HasPrefix(event, "Window") {
|
|
eventType = "WindowEventType"
|
|
}
|
|
if strings.HasPrefix(event, "WebView") {
|
|
eventType = "WindowEventType"
|
|
}
|
|
commonEventsDecl.WriteString("\t" + eventTitle + " " + eventType + "\n")
|
|
commonEventsValues.WriteString("\t\t" + event + ": " + strconv.Itoa(id) + ",\n")
|
|
commonJSEvents.WriteString("\t\t" + event + ": \"" + strings.TrimSpace(string(line)) + "\",\n")
|
|
commonTSEvents.WriteString("\t\t" + event + ": string,\n")
|
|
eventToJS.WriteString("\t" + strconv.Itoa(id) + ": \"" + strings.TrimSpace(string(line)) + "\",\n")
|
|
case "windows":
|
|
eventType := "ApplicationEventType"
|
|
if strings.HasPrefix(event, "Window") {
|
|
eventType = "WindowEventType"
|
|
}
|
|
if strings.HasPrefix(event, "WebView") {
|
|
eventType = "WindowEventType"
|
|
}
|
|
windowsEventsDecl.WriteString("\t" + eventTitle + " " + eventType + "\n")
|
|
windowsEventsValues.WriteString("\t\t" + event + ": " + strconv.Itoa(id) + ",\n")
|
|
windowsJSEvents.WriteString("\t\t" + event + ": \"" + strings.TrimSpace(string(line)) + "\",\n")
|
|
windowsTSEvents.WriteString("\t\t" + event + ": string,\n")
|
|
eventToJS.WriteString("\t" + strconv.Itoa(id) + ": \"" + strings.TrimSpace(string(line)) + "\",\n")
|
|
}
|
|
}
|
|
|
|
cHeaderEvents.WriteString("\n#define MAX_EVENTS " + strconv.Itoa(maxMacEvents+1) + "\n")
|
|
|
|
// Save the eventsGo template substituting the values and decls
|
|
templateToWrite := strings.ReplaceAll(eventsGo, "$$LINUXEVENTSDECL", linuxEventsDecl.String())
|
|
templateToWrite = strings.ReplaceAll(templateToWrite, "$$LINUXEVENTSVALUES", linuxEventsValues.String())
|
|
templateToWrite = strings.ReplaceAll(templateToWrite, "$$MACEVENTSDECL", macEventsDecl.String())
|
|
templateToWrite = strings.ReplaceAll(templateToWrite, "$$MACEVENTSVALUES", macEventsValues.String())
|
|
|
|
templateToWrite = strings.ReplaceAll(templateToWrite, "$$WINDOWSEVENTSDECL", windowsEventsDecl.String())
|
|
templateToWrite = strings.ReplaceAll(templateToWrite, "$$WINDOWSEVENTSVALUES", windowsEventsValues.String())
|
|
templateToWrite = strings.ReplaceAll(templateToWrite, "$$COMMONEVENTSDECL", commonEventsDecl.String())
|
|
templateToWrite = strings.ReplaceAll(templateToWrite, "$$COMMONEVENTSVALUES", commonEventsValues.String())
|
|
templateToWrite = strings.ReplaceAll(templateToWrite, "$$EVENTTOJS", eventToJS.String())
|
|
err = os.WriteFile("../../pkg/events/events.go", []byte(templateToWrite), 0644)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Save the eventsJS template substituting the values and decls
|
|
templateToWrite = strings.ReplaceAll(eventsJS, "$$MACJSEVENTS", macJSEvents.String())
|
|
templateToWrite = strings.ReplaceAll(templateToWrite, "$$WINDOWSJSEVENTS", windowsJSEvents.String())
|
|
templateToWrite = strings.ReplaceAll(templateToWrite, "$$LINUXJSEVENTS", linuxJSEvents.String())
|
|
templateToWrite = strings.ReplaceAll(templateToWrite, "$$COMMONJSEVENTS", commonJSEvents.String())
|
|
err = os.WriteFile("../../internal/runtime/desktop/@wailsio/runtime/src/event_types.js", []byte(templateToWrite), 0644)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Save the eventsTS template substituting the values and decls
|
|
templateToWrite = strings.ReplaceAll(eventsTS, "$$MACTSEVENTS", macTSEvents.String())
|
|
templateToWrite = strings.ReplaceAll(templateToWrite, "$$WINDOWSTSEVENTS", windowsTSEvents.String())
|
|
templateToWrite = strings.ReplaceAll(templateToWrite, "$$LINUXTSEVENTS", linuxTSEvents.String())
|
|
templateToWrite = strings.ReplaceAll(templateToWrite, "$$COMMONTSEVENTS", commonTSEvents.String())
|
|
err = os.WriteFile("../../internal/runtime/desktop/@wailsio/runtime/types/event_types.d.ts", []byte(templateToWrite), 0644)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Save the eventsH template substituting the values and decls
|
|
templateToWrite = strings.ReplaceAll(eventsH, "$$CHEADEREVENTS", cHeaderEvents.String())
|
|
err = os.WriteFile("../../pkg/events/events_darwin.h", []byte(templateToWrite), 0644)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Load the window_delegate.m file
|
|
windowDelegate, err := os.ReadFile("../../pkg/application/webview_window_darwin.m")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
// iterate over the lines until we reach a line that says "// GENERATED EVENTS START"
|
|
// then we insert the events
|
|
// then we iterate until we reach a line that says "// GENERATED EVENTS END"
|
|
// then we write the file
|
|
var buffer bytes.Buffer
|
|
var inGeneratedEvents bool
|
|
for _, line := range bytes.Split(windowDelegate, []byte{'\n'}) {
|
|
if bytes.Contains(line, []byte("// GENERATED EVENTS START")) {
|
|
inGeneratedEvents = true
|
|
buffer.WriteString("// GENERATED EVENTS START\n")
|
|
buffer.WriteString(windowDelegateEvents.String())
|
|
buffer.WriteString(webviewDelegateEvents.String())
|
|
continue
|
|
}
|
|
if bytes.Contains(line, []byte("// GENERATED EVENTS END")) {
|
|
inGeneratedEvents = false
|
|
buffer.WriteString("// GENERATED EVENTS END\n")
|
|
continue
|
|
}
|
|
if !inGeneratedEvents {
|
|
if len(line) > 0 {
|
|
buffer.Write(line)
|
|
buffer.WriteString("\n")
|
|
}
|
|
}
|
|
}
|
|
err = os.WriteFile("../../pkg/application/webview_window_darwin.m", buffer.Bytes(), 0755)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Load the app_delegate.m file
|
|
appDelegate, err := os.ReadFile("../../pkg/application/application_darwin_delegate.m")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
// iterate over the lines until we reach a line that says "// GENERATED EVENTS START"
|
|
// then we insert the events
|
|
// then we iterate until we reach a line that says "// GENERATED EVENTS END"
|
|
// then we write the file
|
|
buffer.Reset()
|
|
for _, line := range bytes.Split(appDelegate, []byte{'\n'}) {
|
|
if bytes.Contains(line, []byte("// GENERATED EVENTS START")) {
|
|
inGeneratedEvents = true
|
|
buffer.WriteString("// GENERATED EVENTS START\n")
|
|
buffer.WriteString(applicationDelegateEvents.String())
|
|
continue
|
|
}
|
|
if bytes.Contains(line, []byte("// GENERATED EVENTS END")) {
|
|
inGeneratedEvents = false
|
|
buffer.WriteString("// GENERATED EVENTS END\n")
|
|
continue
|
|
}
|
|
if !inGeneratedEvents {
|
|
if len(line) > 0 {
|
|
buffer.Write(line)
|
|
buffer.WriteString("\n")
|
|
}
|
|
}
|
|
}
|
|
err = os.WriteFile("../../pkg/application/application_darwin_delegate.m", buffer.Bytes(), 0755)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
}
|