mirror of
https://github.com/taigrr/wails.git
synced 2026-04-03 13:48:55 -07:00
Compare commits
25 Commits
v2-alpha2
...
feature/v2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4138779c5e | ||
|
|
ae04b4fcc0 | ||
|
|
5eb91dd3fa | ||
|
|
3ad537fdbb | ||
|
|
2c570bb4f6 | ||
|
|
461f3aec0a | ||
|
|
fd47122e39 | ||
|
|
8de013f192 | ||
|
|
1dd3a602d7 | ||
|
|
a84a49a13f | ||
|
|
64a6a69bbd | ||
|
|
d75b9f26f1 | ||
|
|
10cb7f830f | ||
|
|
dd3e6de9b2 | ||
|
|
d42b84abc1 | ||
|
|
b6c649041b | ||
|
|
93ec65be6a | ||
|
|
bfa8929c47 | ||
|
|
360713c803 | ||
|
|
26ce682824 | ||
|
|
65b546c0f9 | ||
|
|
31494bba22 | ||
|
|
f25abb0b26 | ||
|
|
e831bc75c6 | ||
|
|
852bbd148c |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -16,4 +16,9 @@ examples/**/example*
|
||||
cmd/wails/wails
|
||||
.DS_Store
|
||||
tmp
|
||||
node_modules/
|
||||
node_modules/
|
||||
package.json.md5
|
||||
v2/test/**/frontend/dist
|
||||
v2/test/**/build/
|
||||
v2/test/frameless/icon.png
|
||||
v2/test/hidden/icon.png
|
||||
|
||||
7
v2/.vscode/settings.json
vendored
Normal file
7
v2/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"ios": "c",
|
||||
"typeinfo": "c",
|
||||
"sstream": "c"
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,6 @@ package app
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/features"
|
||||
)
|
||||
|
||||
// App defines a Wails application structure
|
||||
@@ -22,8 +20,6 @@ type App struct {
|
||||
|
||||
// Indicates if the app is running in debug mode
|
||||
debug bool
|
||||
|
||||
Features *features.Features
|
||||
}
|
||||
|
||||
// CreateApp returns a null application
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/features"
|
||||
"github.com/wailsapp/wails/v2/internal/ffenestri"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||
@@ -35,9 +34,6 @@ type App struct {
|
||||
|
||||
// This is our binding DB
|
||||
bindings *binding.Bindings
|
||||
|
||||
// Feature flags
|
||||
Features *features.Features
|
||||
}
|
||||
|
||||
// Create App
|
||||
@@ -73,7 +69,6 @@ func CreateApp(options *Options) *App {
|
||||
servicebus: servicebus.New(myLogger),
|
||||
logger: myLogger,
|
||||
bindings: binding.NewBindings(myLogger),
|
||||
Features: features.New(),
|
||||
}
|
||||
|
||||
// Initialise the app
|
||||
@@ -152,7 +147,7 @@ func (a *App) Run() error {
|
||||
return err
|
||||
}
|
||||
|
||||
result := a.window.Run(dispatcher, bindingDump, a.Features)
|
||||
result := a.window.Run(dispatcher, bindingDump)
|
||||
a.logger.Trace("Ffenestri.Run() exited")
|
||||
a.servicebus.Stop()
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/features"
|
||||
"github.com/wailsapp/wails/v2/internal/ffenestri"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||
@@ -44,9 +43,6 @@ type App struct {
|
||||
servicebus *servicebus.ServiceBus
|
||||
|
||||
debug bool
|
||||
|
||||
// Feature flags
|
||||
Features *features.Features
|
||||
}
|
||||
|
||||
// Create App
|
||||
@@ -191,7 +187,7 @@ func (a *App) Run() error {
|
||||
}
|
||||
}()
|
||||
|
||||
result := a.window.Run(dispatcher, bindingDump, a.Features)
|
||||
result := a.window.Run(dispatcher, bindingDump)
|
||||
a.servicebus.Stop()
|
||||
|
||||
return result
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package features
|
||||
|
||||
// Features holds generic and platform specific feature flags
|
||||
type Features struct {
|
||||
Linux *Linux
|
||||
}
|
||||
|
||||
// New creates a new Features object
|
||||
func New() *Features {
|
||||
return &Features{
|
||||
Linux: &Linux{},
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package features
|
||||
|
||||
// Linux holds linux specific feature flags
|
||||
type Linux struct {
|
||||
}
|
||||
62
v2/internal/ffenestri/README.md
Normal file
62
v2/internal/ffenestri/README.md
Normal file
File diff suppressed because one or more lines are too long
@@ -1,23 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
package ffenestri
|
||||
|
||||
/*
|
||||
|
||||
#cgo linux CFLAGS: -DFFENESTRI_LINUX=1
|
||||
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "ffenestri.h"
|
||||
|
||||
|
||||
*/
|
||||
import "C"
|
||||
import "github.com/wailsapp/wails/v2/internal/features"
|
||||
|
||||
func (a *Application) processOSFeatureFlags(features *features.Features) {
|
||||
|
||||
// Process Linux features
|
||||
// linux := features.Linux
|
||||
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/features"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||
)
|
||||
@@ -15,6 +14,9 @@ import (
|
||||
#cgo linux CFLAGS: -DFFENESTRI_LINUX=1
|
||||
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0
|
||||
|
||||
#cgo darwin CFLAGS: -DFFENESTRI_DARWIN=1
|
||||
#cgo darwin LDFLAGS: -framework WebKit -lobjc
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "ffenestri.h"
|
||||
|
||||
@@ -124,7 +126,7 @@ type DispatchClient interface {
|
||||
}
|
||||
|
||||
// Run the application
|
||||
func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, features *features.Features) error {
|
||||
func (a *Application) Run(incomingDispatcher Dispatcher, bindings string) error {
|
||||
title := a.string2CString(a.config.Title)
|
||||
width := C.int(a.config.Width)
|
||||
height := C.int(a.config.Height)
|
||||
@@ -161,9 +163,6 @@ func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, featur
|
||||
// Set bindings
|
||||
C.SetBindings(app, a.string2CString(bindings))
|
||||
|
||||
// Process feature flags
|
||||
a.processFeatureFlags(features)
|
||||
|
||||
// save the dispatcher in a package variable so that the C callbacks
|
||||
// can access it
|
||||
dispatcher = incomingDispatcher.RegisterClient(newClient(a))
|
||||
@@ -189,11 +188,3 @@ func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, featur
|
||||
func messageFromWindowCallback(data *C.char) {
|
||||
dispatcher.DispatchMessage(C.GoString(data))
|
||||
}
|
||||
|
||||
func (a *Application) processFeatureFlags(features *features.Features) {
|
||||
|
||||
// Process generic features
|
||||
|
||||
// Process OS Specific flags
|
||||
a.processOSFeatureFlags(features)
|
||||
}
|
||||
|
||||
@@ -16,14 +16,17 @@ extern void Show(void *app);
|
||||
extern void Center(void *app);
|
||||
extern void Maximise(void *app);
|
||||
extern void Unmaximise(void *app);
|
||||
extern void ToggleMaximise(void *app);
|
||||
extern void Minimise(void *app);
|
||||
extern void Unminimise(void *app);
|
||||
extern void ToggleMinimise(void *app);
|
||||
extern void SetSize(void *app, int width, int height);
|
||||
extern void SetPosition(void *app, int x, int y);
|
||||
extern void Quit(void *app);
|
||||
extern void SetTitle(void *app, const char *title);
|
||||
extern void Fullscreen(void *app);
|
||||
extern void UnFullscreen(void *app);
|
||||
extern void ToggleFullscreen(void *app);
|
||||
extern int SetColour(void *app, const char *colourString);
|
||||
extern void DisableFrame(void *app);
|
||||
extern char *SaveFileDialog(void *appPointer, char *title, char *filter);
|
||||
|
||||
803
v2/internal/ffenestri/ffenestri_darwin.c
Normal file
803
v2/internal/ffenestri/ffenestri_darwin.c
Normal file
@@ -0,0 +1,803 @@
|
||||
|
||||
#ifdef FFENESTRI_DARWIN
|
||||
|
||||
#define OBJC_OLD_DISPATCH_PROTOTYPES 1
|
||||
#include <objc/objc-runtime.h>
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
// Macros to make it slightly more sane
|
||||
#define msg objc_msgSend
|
||||
#define msg_stret objc_msgSend_stret
|
||||
|
||||
#define c(str) (id)objc_getClass(str)
|
||||
#define s(str) sel_registerName(str)
|
||||
#define u(str) sel_getUid(str)
|
||||
#define str(input) msg(c("NSString"), s("stringWithUTF8String:"), input)
|
||||
|
||||
#define ON_MAIN_THREAD(str) dispatch( ^{ str; } );
|
||||
#define MAIN_WINDOW_CALL(str) msg(app->mainWindow, s((str)));
|
||||
|
||||
#define NSBackingStoreBuffered 2
|
||||
|
||||
#define NSWindowStyleMaskBorderless 0
|
||||
#define NSWindowStyleMaskTitled 1
|
||||
#define NSWindowStyleMaskClosable 2
|
||||
#define NSWindowStyleMaskMiniaturizable 4
|
||||
#define NSWindowStyleMaskResizable 8
|
||||
#define NSWindowStyleMaskFullscreen 1 << 14
|
||||
|
||||
#define NSWindowTitleHidden 1
|
||||
#define NSWindowStyleMaskFullSizeContentView 1 << 15
|
||||
|
||||
// References to assets
|
||||
extern const unsigned char *assets[];
|
||||
extern const unsigned char runtime;
|
||||
extern const char *icon[];
|
||||
|
||||
// MAIN DEBUG FLAG
|
||||
int debug;
|
||||
|
||||
// Dispatch Method
|
||||
typedef void (^dispatchMethod)(void);
|
||||
|
||||
// dispatch will execute the given `func` pointer
|
||||
void dispatch(dispatchMethod func) {
|
||||
dispatch_async(dispatch_get_main_queue(), func);
|
||||
}
|
||||
|
||||
// App Delegate
|
||||
typedef struct AppDel {
|
||||
Class isa;
|
||||
id window;
|
||||
} AppDelegate;
|
||||
|
||||
// Credit: https://stackoverflow.com/a/8465083
|
||||
char* concat(const char *string1, const char *string2)
|
||||
{
|
||||
const size_t len1 = strlen(string1);
|
||||
const size_t len2 = strlen(string2);
|
||||
char *result = malloc(len1 + len2 + 1);
|
||||
memcpy(result, string1, len1);
|
||||
memcpy(result + len1, string2, len2 + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
// yes command simply returns YES!
|
||||
BOOL yes(id self, SEL cmd)
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Debug works like sprintf but mutes if the global debug flag is true
|
||||
// Credit: https://stackoverflow.com/a/20639708
|
||||
void Debug(char *message, ... ) {
|
||||
if ( debug ) {
|
||||
char *temp = concat("TRACE | Ffenestri (C) | ", message);
|
||||
message = concat(temp, "\n");
|
||||
free(temp);
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
vprintf(message, args);
|
||||
free(message);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
extern void messageFromWindowCallback(const char *);
|
||||
typedef void (*ffenestriCallback)(const char *);
|
||||
|
||||
struct Application {
|
||||
|
||||
// Cocoa data
|
||||
id application;
|
||||
id mainWindow;
|
||||
id wkwebview;
|
||||
id manager;
|
||||
id config;
|
||||
|
||||
// Window Data
|
||||
const char *title;
|
||||
int width;
|
||||
int height;
|
||||
int minWidth;
|
||||
int minHeight;
|
||||
int maxWidth;
|
||||
int maxHeight;
|
||||
int resizable;
|
||||
int devtools;
|
||||
int fullscreen;
|
||||
|
||||
// Features
|
||||
int frame;
|
||||
int maximised;
|
||||
int minimised;
|
||||
|
||||
// User Data
|
||||
char *HTML;
|
||||
|
||||
// Callback
|
||||
ffenestriCallback sendMessageToBackend;
|
||||
|
||||
// Bindings
|
||||
const char *bindings;
|
||||
|
||||
// Lock - used for sync operations (Should we be using g_mutex?)
|
||||
int lock;
|
||||
|
||||
};
|
||||
|
||||
void Hide(void *appPointer) {
|
||||
struct Application *app = (struct Application*) appPointer;
|
||||
ON_MAIN_THREAD(
|
||||
msg(app->application, s("hide:"))
|
||||
)
|
||||
}
|
||||
|
||||
void Show(void *appPointer) {
|
||||
struct Application *app = (struct Application*) appPointer;
|
||||
ON_MAIN_THREAD(
|
||||
msg(app->mainWindow, s("makeKeyAndOrderFront:"), NULL);
|
||||
msg(app->application, s("activateIgnoringOtherApps:"), YES);
|
||||
)
|
||||
}
|
||||
|
||||
// Sends messages to the backend
|
||||
void messageHandler(id self, SEL cmd, id contentController, id message) {
|
||||
struct Application *app = (struct Application *)objc_getAssociatedObject(
|
||||
self, "application");
|
||||
const char *name = (const char *)msg(msg(message, s("name")), s("UTF8String"));
|
||||
if( strcmp(name, "completed") == 0) {
|
||||
// Delete handler
|
||||
msg(app->manager, s("removeScriptMessageHandlerForName:"), str("completed"));
|
||||
// Show window after a short delay so rendering can catch up
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10000000), dispatch_get_main_queue(), ^{
|
||||
Show(app);
|
||||
msg(app->config, s("setValue:forKey:"), msg(c("NSNumber"), s("numberWithBool:"), 0), str("suppressesIncrementalRendering"));
|
||||
});
|
||||
|
||||
} else {
|
||||
const char *m = (const char *)msg(msg(message, s("body")), s("UTF8String"));
|
||||
app->sendMessageToBackend(m);
|
||||
}
|
||||
}
|
||||
|
||||
// closeWindow is called when the close button is pressed
|
||||
void closeWindow(id self, SEL cmd, id sender) {
|
||||
struct Application *app = (struct Application *) objc_getAssociatedObject(self, "application");
|
||||
app->sendMessageToBackend("WC");
|
||||
}
|
||||
|
||||
void* NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen) {
|
||||
// Setup main application struct
|
||||
struct Application *result = malloc(sizeof(struct Application));
|
||||
result->title = title;
|
||||
result->width = width;
|
||||
result->height = height;
|
||||
result->minWidth = 0;
|
||||
result->minHeight = 0;
|
||||
result->maxWidth = 0;
|
||||
result->maxHeight = 0;
|
||||
result->resizable = resizable;
|
||||
result->devtools = devtools;
|
||||
result->fullscreen = fullscreen;
|
||||
result->lock = 0;
|
||||
result->maximised = 0;
|
||||
result->minimised = 0;
|
||||
|
||||
// Features
|
||||
result->frame = 1;
|
||||
|
||||
result->sendMessageToBackend = (ffenestriCallback) messageFromWindowCallback;
|
||||
|
||||
return (void*) result;
|
||||
}
|
||||
|
||||
void DestroyApplication(void *appPointer) {
|
||||
Debug("Destroying Application");
|
||||
struct Application *app = (struct Application*) appPointer;
|
||||
|
||||
// Free the bindings
|
||||
if (app->bindings != NULL) {
|
||||
free((void*)app->bindings);
|
||||
app->bindings = NULL;
|
||||
} else {
|
||||
Debug("Almost a double free for app->bindings");
|
||||
}
|
||||
|
||||
msg(app->manager, s("removeScriptMessageHandlerForName:"), str("external"));
|
||||
msg(app->mainWindow, s("close"));
|
||||
msg(c("NSApp"), s("terminate:"), NULL);
|
||||
Debug("Finished Destroying Application");
|
||||
}
|
||||
|
||||
// Quit will stop the gtk application and free up all the memory
|
||||
// used by the application
|
||||
void Quit(void *appPointer) {
|
||||
Debug("Quit Called");
|
||||
DestroyApplication(appPointer);
|
||||
}
|
||||
|
||||
// SetTitle sets the main window title to the given string
|
||||
void SetTitle(struct Application *app, const char *title) {
|
||||
Debug("SetTitle Called");
|
||||
ON_MAIN_THREAD(
|
||||
msg(app->mainWindow, s("setTitle:"), str(title));
|
||||
)
|
||||
}
|
||||
|
||||
void ToggleFullscreen(struct Application *app) {
|
||||
ON_MAIN_THREAD(
|
||||
app->fullscreen = !app->fullscreen;
|
||||
MAIN_WINDOW_CALL("toggleFullScreen:")
|
||||
)
|
||||
}
|
||||
|
||||
// Fullscreen sets the main window to be fullscreen
|
||||
void Fullscreen(struct Application *app) {
|
||||
Debug("Fullscreen Called");
|
||||
if( app->fullscreen == 0) {
|
||||
ToggleFullscreen(app);
|
||||
}
|
||||
}
|
||||
|
||||
// UnFullscreen resets the main window after a fullscreen
|
||||
void UnFullscreen(struct Application *app) {
|
||||
Debug("UnFullscreen Called");
|
||||
if( app->fullscreen == 1) {
|
||||
ToggleFullscreen(app);
|
||||
}
|
||||
}
|
||||
|
||||
void Center(struct Application *app) {
|
||||
Debug("Center Called");
|
||||
ON_MAIN_THREAD(
|
||||
MAIN_WINDOW_CALL("center")
|
||||
)
|
||||
}
|
||||
|
||||
void SetMaximumSize(void *appPointer, int width, int height) {
|
||||
Debug("SetMaximumSize Called");
|
||||
// struct Application *app = (struct Application*) appPointer;
|
||||
// GdkGeometry size;
|
||||
// size.max_height = (height == 0 ? INT_MAX: height);
|
||||
// size.max_width = (width == 0 ? INT_MAX: width);
|
||||
// gtk_window_set_geometry_hints(app->mainWindow, NULL, &size, GDK_HINT_MAX_SIZE);
|
||||
}
|
||||
|
||||
void SetMinimumSize(void *appPointer, int width, int height) {
|
||||
Debug("SetMinimumSize Called");
|
||||
// struct Application *app = (struct Application*) appPointer;
|
||||
// GdkGeometry size;
|
||||
// size.max_height = height;
|
||||
// size.max_width = width;
|
||||
// gtk_window_set_geometry_hints(app->mainWindow, NULL, &size, GDK_HINT_MIN_SIZE);
|
||||
}
|
||||
|
||||
void ToggleMaximise(struct Application *app) {
|
||||
ON_MAIN_THREAD(
|
||||
app->maximised = !app->maximised;
|
||||
MAIN_WINDOW_CALL("zoom:")
|
||||
)
|
||||
}
|
||||
|
||||
void Maximise(struct Application *app) {
|
||||
if( app->maximised == 0) {
|
||||
ToggleMaximise(app);
|
||||
}
|
||||
}
|
||||
|
||||
void Unmaximise(struct Application *app) {
|
||||
if( app->maximised == 1) {
|
||||
ToggleMaximise(app);
|
||||
}
|
||||
}
|
||||
|
||||
void ToggleMinimise(struct Application *app) {
|
||||
ON_MAIN_THREAD(
|
||||
MAIN_WINDOW_CALL(app->minimised ? "deminiaturize:" : "miniaturize:" );
|
||||
app->minimised = !app->minimised;
|
||||
)
|
||||
}
|
||||
|
||||
void Minimise(struct Application *app) {
|
||||
if( app->minimised == 0) {
|
||||
ToggleMinimise(app);
|
||||
}
|
||||
}
|
||||
void Unminimise(struct Application *app) {
|
||||
if( app->minimised == 1) {
|
||||
ToggleMinimise(app);
|
||||
}
|
||||
}
|
||||
|
||||
void SetSize(struct Application *app, int width, int height) {
|
||||
ON_MAIN_THREAD(
|
||||
id screen = NULL;
|
||||
screen = msg(app->mainWindow, s("screen"));
|
||||
if( screen == NULL ) {
|
||||
screen = msg(c("NSScreen"), u("mainScreen"));
|
||||
}
|
||||
|
||||
// Get the rect for the mainWindow
|
||||
CGRect* frame = (CGRect*) msg(app->mainWindow, s("valueForKey:"), str("frame"));
|
||||
|
||||
// Get the rect for the current screen
|
||||
CGRect *visibleFrame = (CGRect*) msg(screen, s("valueForKey:"), str("visibleFrame"));
|
||||
|
||||
// Credit: https://github.com/patr0nus/DeskGap/blob/73c0ac9f2c73f55b6e81f64f6673a7962b5719cd/lib/src/platform/mac/util/NSScreen%2BGeometry.m
|
||||
Debug("visibleFrame->origin.x %4.1f", visibleFrame->origin.x);
|
||||
Debug("visibleFrame->origin.y %4.1f", visibleFrame->origin.y);
|
||||
Debug("visibleFrame->size.width %4.1f", visibleFrame->size.width);
|
||||
Debug("visibleFrame->size.height %4.1f", visibleFrame->size.height);
|
||||
Debug("frame->origin.x %4.1f", frame->origin.x);
|
||||
Debug("frame->origin.y %4.1f", frame->origin.y);
|
||||
Debug("frame->size.width %4.1f", frame->size.width);
|
||||
Debug("frame->size.height %4.1f", frame->size.height);
|
||||
|
||||
frame->size.width = width;
|
||||
frame->size.height = height;
|
||||
msg(app->mainWindow, s("setFrame:display:"), *frame, true);
|
||||
|
||||
// Move the window
|
||||
// msg(app->mainWindow, s("setFrame:display:animate:"), *frame, 1, 0);
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
void SetPosition(struct Application *app, int x, int y) {
|
||||
msg(app->mainWindow, s("cascadeTopLeftFromPoint:"), CGPointMake(x, y));
|
||||
}
|
||||
|
||||
// OpenFileDialog opens a dialog to select a file
|
||||
// NOTE: The result is a string that will need to be freed!
|
||||
char* OpenFileDialog(void *appPointer, char *title) {
|
||||
Debug("OpenFileDialog Called");
|
||||
|
||||
// struct Application *app = (struct Application*) appPointer;
|
||||
// GtkFileChooserNative *native;
|
||||
// GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
|
||||
// gint res;
|
||||
char *filename = "BogusFilename";
|
||||
|
||||
// native = gtk_file_chooser_native_new (title,
|
||||
// app->mainWindow,
|
||||
// action,
|
||||
// "_Open",
|
||||
// "_Cancel");
|
||||
|
||||
// res = gtk_native_dialog_run (GTK_NATIVE_DIALOG (native));
|
||||
// if (res == GTK_RESPONSE_ACCEPT)
|
||||
// {
|
||||
// GtkFileChooser *chooser = GTK_FILE_CHOOSER (native);
|
||||
// filename = gtk_file_chooser_get_filename (chooser);
|
||||
// }
|
||||
|
||||
// g_object_unref (native);
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
// SaveFileDialog opens a dialog to select a file
|
||||
// NOTE: The result is a string that will need to be freed!
|
||||
char* SaveFileDialog(void *appPointer, char *title) {
|
||||
Debug("SaveFileDialog Called");
|
||||
char *filename = "BogusSaveFilename";
|
||||
/* struct Application *app = (struct Application*) appPointer;
|
||||
GtkFileChooserNative *native;
|
||||
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
|
||||
gint res;
|
||||
|
||||
native = gtk_file_chooser_native_new (title,
|
||||
app->mainWindow,
|
||||
action,
|
||||
"_Save",
|
||||
"_Cancel");
|
||||
|
||||
res = gtk_native_dialog_run (GTK_NATIVE_DIALOG (native));
|
||||
if (res == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
GtkFileChooser *chooser = GTK_FILE_CHOOSER (native);
|
||||
filename = gtk_file_chooser_get_filename (chooser);
|
||||
}
|
||||
|
||||
g_object_unref (native);
|
||||
*/
|
||||
return filename;
|
||||
}
|
||||
|
||||
// OpenDirectoryDialog opens a dialog to select a directory
|
||||
// NOTE: The result is a string that will need to be freed!
|
||||
char* OpenDirectoryDialog(void *appPointer, char *title) {
|
||||
Debug("OpenDirectoryDialog Called");
|
||||
char *foldername = "BogusDirectory";
|
||||
/*
|
||||
struct Application *app = (struct Application*) appPointer;
|
||||
GtkFileChooserNative *native;
|
||||
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
||||
gint res;
|
||||
|
||||
native = gtk_file_chooser_native_new (title,
|
||||
app->mainWindow,
|
||||
action,
|
||||
"_Open",
|
||||
"_Cancel");
|
||||
|
||||
res = gtk_native_dialog_run (GTK_NATIVE_DIALOG (native));
|
||||
if (res == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
GtkFileChooser *chooser = GTK_FILE_CHOOSER (native);
|
||||
foldername = gtk_file_chooser_get_filename (chooser);
|
||||
}
|
||||
|
||||
g_object_unref (native);
|
||||
*/
|
||||
return foldername;
|
||||
}
|
||||
|
||||
// SetColour sets the colour of the webview to the given colour string
|
||||
int SetColour(void *appPointer, const char *colourString) {
|
||||
Debug("SetColour Called with: %s", colourString);
|
||||
|
||||
// struct Application *app = (struct Application*) appPointer;
|
||||
// GdkRGBA rgba;
|
||||
// gboolean result = gdk_rgba_parse(&rgba, colourString);
|
||||
// if (result == FALSE) {
|
||||
// return 0;
|
||||
// }
|
||||
// Debug("Setting webview colour to: %s", colourString);
|
||||
// webkit_web_view_get_background_color((WebKitWebView*)(app->webView), &rgba);
|
||||
// int c = NS_RGBA(1, 0, 0, 0.5);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *invoke = "window.external={invoke:function(x){window.webkit.messageHandlers.external.postMessage(x);}};";
|
||||
|
||||
// DisableFrame disables the window frame
|
||||
void DisableFrame(struct Application *app)
|
||||
{
|
||||
app->frame = 0;
|
||||
}
|
||||
|
||||
void SetMinWindowSize(struct Application *app, int minWidth, int minHeight)
|
||||
{
|
||||
app->minWidth = minWidth;
|
||||
app->minHeight = minHeight;
|
||||
}
|
||||
|
||||
void SetMaxWindowSize(struct Application *app, int maxWidth, int maxHeight)
|
||||
{
|
||||
app->maxWidth = maxWidth;
|
||||
app->maxHeight = maxHeight;
|
||||
}
|
||||
|
||||
void ExecJS(struct Application *app, const char *js) {
|
||||
ON_MAIN_THREAD(
|
||||
msg(app->wkwebview,
|
||||
s("evaluateJavaScript:completionHandler:"),
|
||||
str(js),
|
||||
NULL);
|
||||
)
|
||||
}
|
||||
|
||||
// typedef char* (*dialogMethod)(void *app, void *);
|
||||
|
||||
// struct dialogCall {
|
||||
// struct Application *app;
|
||||
// dialogMethod method;
|
||||
// void *args;
|
||||
// char *result;
|
||||
// int done;
|
||||
// };
|
||||
|
||||
|
||||
// gboolean executeMethodWithReturn(gpointer data) {
|
||||
// struct dialogCall *d = (struct dialogCall *)data;
|
||||
// struct Application *app = (struct Application *)(d->app);
|
||||
// Debug("Webview %p\n", app->webView);
|
||||
// Debug("Args %s\n", d->args);
|
||||
// Debug("Method %p\n", (d->method));
|
||||
// d->result = (d->method)(app, d->args);
|
||||
// d->done = 1;
|
||||
// // Debug("Method Execute Complete. Freeing memory");
|
||||
// return FALSE;
|
||||
// }
|
||||
|
||||
|
||||
char* OpenFileDialogOnMainThread(void *app, char *title) {
|
||||
Debug("OpenFileDialogOnMainThread Called");
|
||||
|
||||
// struct dialogCall *data =
|
||||
// (struct dialogCall *)g_new(struct dialogCall, 1);
|
||||
// data->result = NULL;
|
||||
// data->done = 0;
|
||||
// data->method = (dialogMethod)OpenFileDialog;
|
||||
// data->args = title;
|
||||
// data->app = app;
|
||||
|
||||
// gdk_threads_add_idle(executeMethodWithReturn, data);
|
||||
|
||||
// while( data->done == 0 ) {
|
||||
// // Debug("Waiting for dialog");
|
||||
// usleep(100000);
|
||||
// }
|
||||
// Debug("Dialog done");
|
||||
// Debug("Result = %s\n", data->result);
|
||||
// g_free(data);
|
||||
// // Fingers crossed this wasn't freed by g_free above
|
||||
// return data->result;
|
||||
return "OpenFileDialogOnMainThread result";
|
||||
}
|
||||
|
||||
char* SaveFileDialogOnMainThread(void *app, char *title) {
|
||||
Debug("SaveFileDialogOnMainThread Called");
|
||||
return "SaveFileDialogOnMainThread result";
|
||||
}
|
||||
|
||||
char* OpenDirectoryDialogOnMainThread(void *app, char *title) {
|
||||
Debug("OpenDirectoryDialogOnMainThread Called");
|
||||
return "OpenDirectoryDialogOnMainThread result";
|
||||
}
|
||||
|
||||
// // Sets the icon to the XPM stored in icon
|
||||
// void setIcon( struct Application *app) {
|
||||
// GdkPixbuf *appIcon = gdk_pixbuf_new_from_xpm_data ((const char**)icon);
|
||||
// gtk_window_set_icon (app->mainWindow, appIcon);
|
||||
// }
|
||||
|
||||
|
||||
void SetDebug(void *applicationPointer, int flag) {
|
||||
struct Application *app = (struct Application*) applicationPointer;
|
||||
debug = flag;
|
||||
}
|
||||
|
||||
void SetBindings(void* applicationPointer, const char *bindings) {
|
||||
struct Application *app = (struct Application*) applicationPointer;
|
||||
|
||||
const char* temp = concat("window.wailsbindings = \"", bindings);
|
||||
const char* jscall = concat(temp, "\";");
|
||||
free((void*)temp);
|
||||
app->bindings = jscall;
|
||||
}
|
||||
|
||||
// This is called when the close button on the window is pressed
|
||||
// void close_button_pressed () {
|
||||
// struct Application *app = (struct Application*) user_data;
|
||||
// app->sendMessageToBackend("WC"); // Window Close
|
||||
// return TRUE;
|
||||
// }
|
||||
|
||||
// static void setupWindow(void *applicationPointer) {
|
||||
|
||||
// struct Application *app = (struct Application*) applicationPointer;
|
||||
|
||||
// // Create the window
|
||||
// GtkWidget *mainWindow = gtk_application_window_new (app->application);
|
||||
// // Save reference
|
||||
// app->mainWindow = GTK_WINDOW(mainWindow);
|
||||
|
||||
// // Setup borderless
|
||||
// if (app->borderless) {
|
||||
// gtk_window_set_decorated((GtkWindow*)mainWindow, FALSE);
|
||||
// }
|
||||
|
||||
// // Setup title
|
||||
// printf("Setting title to: %s\n", app->title);
|
||||
// gtk_window_set_title(GTK_WINDOW(mainWindow), app->title);
|
||||
|
||||
// // Setup script handler
|
||||
// WebKitUserContentManager *contentManager = webkit_user_content_manager_new();
|
||||
// webkit_user_content_manager_register_script_message_handler(contentManager, "external");
|
||||
// g_signal_connect(contentManager, "script-message-received::external", G_CALLBACK(sendMessageToBackend), app);
|
||||
// GtkWidget *webView = webkit_web_view_new_with_user_content_manager(contentManager);
|
||||
// // Save reference
|
||||
// app->webView = webView;
|
||||
|
||||
// // Add the webview to the window
|
||||
// gtk_container_add(GTK_CONTAINER(mainWindow), webView);
|
||||
|
||||
// // Load default HTML
|
||||
// g_signal_connect(G_OBJECT(webView), "load-changed", G_CALLBACK(load_finished_cb), app);
|
||||
|
||||
// // Load the user's HTML
|
||||
// webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webView), &userhtml);
|
||||
|
||||
// // Check if we want to enable the dev tools
|
||||
// if( app->devtools ) {
|
||||
// WebKitSettings *settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webView));
|
||||
// // webkit_settings_set_enable_write_console_messages_to_stdout(settings, true);
|
||||
// webkit_settings_set_enable_developer_extras(settings, true);
|
||||
// } else {
|
||||
// g_signal_connect(G_OBJECT(webView), "context-menu", G_CALLBACK(disable_context_menu_cb), app);
|
||||
// }
|
||||
|
||||
// // Listen for close button signal
|
||||
// g_signal_connect (GTK_WIDGET(mainWindow), "delete-event", G_CALLBACK (close_button_pressed), app);
|
||||
|
||||
// }
|
||||
|
||||
void enableBoolConfig(id config, const char *setting) {
|
||||
msg(msg(config, s("preferences")), s("setValue:forKey:"), msg(c("NSNumber"), s("numberWithBool:"), 1), str(setting));
|
||||
}
|
||||
|
||||
void disableBoolConfig(id config, const char *setting) {
|
||||
msg(msg(config, s("preferences")), s("setValue:forKey:"), msg(c("NSNumber"), s("numberWithBool:"), 0), str(setting));
|
||||
}
|
||||
|
||||
void Run(void *applicationPointer, int argc, char **argv) {
|
||||
struct Application *app = (struct Application*) applicationPointer;
|
||||
|
||||
int decorations;
|
||||
|
||||
if (app->frame == 1 ) {
|
||||
decorations = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
|
||||
}
|
||||
|
||||
if (app->resizable) {
|
||||
decorations |= NSWindowStyleMaskResizable;
|
||||
}
|
||||
|
||||
if (app->fullscreen) {
|
||||
decorations |= NSWindowStyleMaskFullscreen;
|
||||
}
|
||||
|
||||
if( app->frame == 0) {
|
||||
decorations |= NSWindowStyleMaskFullSizeContentView;
|
||||
}
|
||||
|
||||
id application = msg(c("NSApplication"), s("sharedApplication"));
|
||||
app->application = application;
|
||||
msg(application, s("setActivationPolicy:"), 0);
|
||||
|
||||
// Define delegate
|
||||
Class delegateClass = objc_allocateClassPair((Class) c("NSResponder"), "AppDelegate", 0);
|
||||
class_addProtocol(delegateClass, objc_getProtocol("NSTouchBarProvider"));
|
||||
class_addMethod(delegateClass, s("applicationShouldTerminateAfterLastWindowClosed:"), (IMP) yes, "c@:@");
|
||||
// TODO: add userContentController:didReceiveScriptMessage
|
||||
class_addMethod(delegateClass, s("userContentController:didReceiveScriptMessage:"), (IMP) messageHandler,
|
||||
"v@:@@");
|
||||
objc_registerClassPair(delegateClass);
|
||||
|
||||
// Create delegate
|
||||
id delegate = msg((id)delegateClass, s("new"));
|
||||
objc_setAssociatedObject(delegate, "application", (id)app, OBJC_ASSOCIATION_ASSIGN);
|
||||
msg(application, s("setDelegate:"), delegate);
|
||||
|
||||
// Create main window
|
||||
id mainWindow = msg(c("NSWindow"),s("alloc"));
|
||||
mainWindow = msg(mainWindow, s("initWithContentRect:styleMask:backing:defer:"),
|
||||
CGRectMake(0, 0, app->width, app->height), decorations, NSBackingStoreBuffered, 0);
|
||||
msg(mainWindow, s("autorelease"));
|
||||
|
||||
app->mainWindow = mainWindow;
|
||||
|
||||
// Set the main window title
|
||||
SetTitle(app, app->title);
|
||||
|
||||
// Center Window
|
||||
Center(app);
|
||||
// msg(app->mainWindow, s("cascadeTopLeftFromPoint:"), CGPointMake(100, 100));
|
||||
|
||||
// Set Style Mask
|
||||
msg(mainWindow, s("setStyleMask:"), decorations);
|
||||
|
||||
|
||||
// Setup webview
|
||||
id config = msg(c("WKWebViewConfiguration"), s("new"));
|
||||
app->config = config;
|
||||
id manager = msg(config, s("userContentController"));
|
||||
app->manager = manager;
|
||||
id wkwebview = msg(c("WKWebView"), s("alloc"));
|
||||
app->wkwebview = wkwebview;
|
||||
|
||||
// Only show content when fully rendered
|
||||
msg(config, s("setValue:forKey:"), msg(c("NSNumber"), s("numberWithBool:"), 1), str("suppressesIncrementalRendering"));
|
||||
|
||||
// TODO: Fix "NSWindow warning: adding an unknown subview: <WKInspectorWKWebView: 0x465ed90>. Break on NSLog to debug." error
|
||||
if (app->devtools) {
|
||||
Debug("Enabling devtools");
|
||||
enableBoolConfig(config, "developerExtrasEnabled");
|
||||
}
|
||||
// TODO: Understand why this shouldn't be CGRectMake(0, 0, app->width, app->height)
|
||||
msg(wkwebview, s("initWithFrame:configuration:"), CGRectMake(0, 0, 0, 0), config);
|
||||
|
||||
|
||||
msg(manager, s("addScriptMessageHandler:name:"), delegate, str("external"));
|
||||
msg(manager, s("addScriptMessageHandler:name:"), delegate, str("completed"));
|
||||
msg(mainWindow, s("setContentView:"), wkwebview);
|
||||
|
||||
if( app->frame == 0) {
|
||||
msg(mainWindow, s("setTitlebarAppearsTransparent:"), YES);
|
||||
msg(mainWindow, s("setTitleVisibility:"), NSWindowTitleHidden);
|
||||
// msg( msg( mainWindow, ("standardWindowButton"), str("NSWindowZoomButton")), s("setHidden"), YES);
|
||||
// [[window standardWindowButton:NSWindowZoomButton] setHidden:YES];
|
||||
// [[window standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
|
||||
// [[window standardWindowButton:NSWindowCloseButton] setHidden:YES];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// msg(mainWindow, s("setFrame:display:animate:"), CGRectMake(0, 0, 0, 0), YES, YES);
|
||||
// // Set the icon
|
||||
// setIcon(app);
|
||||
|
||||
// // Setup resize
|
||||
// gtk_window_resize(GTK_WINDOW (app->mainWindow), app->width, app->height);
|
||||
|
||||
// if( app->resizable ) {
|
||||
// gtk_window_set_default_size(GTK_WINDOW (app->mainWindow), app->width, app->height);
|
||||
// } else {
|
||||
// gtk_widget_set_size_request(GTK_WIDGET (app->mainWindow), app->width, app->height);
|
||||
// SetMaximumSize(app, app->width, app->height);
|
||||
// SetMinimumSize(app, app->width, app->height);
|
||||
// gtk_window_resize(GTK_WINDOW (app->mainWindow), app->width, app->height);
|
||||
// }
|
||||
// gtk_window_set_resizable(GTK_WINDOW(app->mainWindow), app->resizable ? TRUE : FALSE );
|
||||
|
||||
|
||||
// Load HTML
|
||||
id html = msg(c("NSURL"), s("URLWithString:"), str(assets[0]));
|
||||
// Debug("HTML: %p", html);
|
||||
msg(wkwebview, s("loadRequest:"), msg(c("NSURLRequest"), s("requestWithURL:"), html));
|
||||
|
||||
// Load assets
|
||||
|
||||
Debug("Loading Internal Code");
|
||||
// We want to evaluate the internal code plus runtime before the assets
|
||||
const char *temp = concat(invoke, app->bindings);
|
||||
const char *internalCode = concat(temp, (const char*)&runtime);
|
||||
// Debug("Internal code: %s", internalCode);
|
||||
free((void*)temp);
|
||||
|
||||
// Loop over assets and build up one giant Mother Of All Evals
|
||||
int index = 1;
|
||||
while(1) {
|
||||
// Get next asset pointer
|
||||
const unsigned char *asset = assets[index];
|
||||
|
||||
// If we have no more assets, break
|
||||
if (asset == 0x00) {
|
||||
break;
|
||||
}
|
||||
|
||||
temp = concat(internalCode, (const char *)asset);
|
||||
free((void*)internalCode);
|
||||
internalCode = temp;
|
||||
index++;
|
||||
};
|
||||
|
||||
class_addMethod(delegateClass, s("closeWindow"), (IMP) closeWindow, "v@:@");
|
||||
// TODO: Check if we can split out the User JS/CSS from the MOAE
|
||||
|
||||
// Debug("MOAE: %s", internalCode);
|
||||
|
||||
// Include callback after evaluation
|
||||
temp = concat(internalCode, "webkit.messageHandlers.completed.postMessage(true);");
|
||||
free((void*)internalCode);
|
||||
internalCode = temp;
|
||||
|
||||
// const char *viewportScriptString = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); meta.setAttribute('initial-scale', '1.0'); meta.setAttribute('maximum-scale', '1.0'); meta.setAttribute('minimum-scale', '1.0'); meta.setAttribute('user-scalable', 'no'); document.getElementsByTagName('head')[0].appendChild(meta);";
|
||||
// ExecJS(app, viewportScriptString);
|
||||
|
||||
|
||||
// This evaluates the MOAE once the Dom has finished loading
|
||||
msg(manager,
|
||||
s("addUserScript:"),
|
||||
msg(msg(c("WKUserScript"), s("alloc")),
|
||||
s("initWithSource:injectionTime:forMainFrameOnly:"),
|
||||
str(internalCode),
|
||||
1,
|
||||
1));
|
||||
|
||||
// Finally call run
|
||||
Debug("Run called");
|
||||
msg(application, s("activateIgnoringOtherApps:"), true);
|
||||
msg(application, s("run"));
|
||||
|
||||
free((void*)internalCode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
5
v2/internal/ffenestri/runtime.c
Normal file
5
v2/internal/ffenestri/runtime.c
Normal file
File diff suppressed because one or more lines are too long
@@ -63,6 +63,10 @@ func (a *Asset) AsCHexData() string {
|
||||
result = strings.ReplaceAll(result, "\n", "")
|
||||
result = strings.ReplaceAll(result, "\r\n", "")
|
||||
result = strings.ReplaceAll(result, "\n", "")
|
||||
|
||||
// Inject wailsloader code
|
||||
result = strings.Replace(result, `</body>`, `<script id='wailsloader'>window.wailsloader = { html: true, runtime: false, userjs: false, usercss: false };var self=document.querySelector('#wailsloader');self.parentNode.removeChild(self);</script></body>`, 1)
|
||||
|
||||
url := url.URL{Path: result}
|
||||
urlString := strings.ReplaceAll(url.String(), "/", "%2f")
|
||||
|
||||
@@ -103,6 +107,7 @@ func (a *Asset) AsCHexData() string {
|
||||
return cdata.String()
|
||||
}
|
||||
|
||||
// Dump will output the asset to the terminal
|
||||
func (a *Asset) Dump() {
|
||||
fmt.Printf("{ Type: %s, Path: %s, Data: %+v }\n", a.Type, a.Path, a.Data[:10])
|
||||
}
|
||||
|
||||
@@ -153,6 +153,10 @@ func (a *AssetBundle) WriteToCFile(targetDir string) (string, error) {
|
||||
assetVariables := slicer.String()
|
||||
var variableName string
|
||||
for index, asset := range a.assets {
|
||||
// For desktop we ignore the favicon
|
||||
if asset.Type == AssetTypes.FAVICON {
|
||||
continue
|
||||
}
|
||||
variableName = fmt.Sprintf("%s%d", asset.Type, index)
|
||||
assetCdata := fmt.Sprintf("const unsigned char %s[]={ %s0x00 };\n", variableName, asset.AsCHexData())
|
||||
cdata.WriteString(assetCdata)
|
||||
@@ -160,9 +164,9 @@ func (a *AssetBundle) WriteToCFile(targetDir string) (string, error) {
|
||||
}
|
||||
|
||||
if assetVariables.Length() > 0 {
|
||||
cdata.WriteString(fmt.Sprintf("\nconst char *assets[] = { %s, 0x00 };", assetVariables.Join(", ")))
|
||||
cdata.WriteString(fmt.Sprintf("\nconst unsigned char *assets[] = { %s, 0x00 };", assetVariables.Join(", ")))
|
||||
} else {
|
||||
cdata.WriteString("\nconst char *assets[] = { 0x00 };")
|
||||
cdata.WriteString("\nconst unsigned char *assets[] = { 0x00 };")
|
||||
}
|
||||
|
||||
// Save file
|
||||
@@ -187,6 +191,7 @@ func (a *AssetBundle) ConvertToAssetDB() (*assetdb.AssetDB, error) {
|
||||
return assetdb, nil
|
||||
}
|
||||
|
||||
// Dump will output the assets to the terminal
|
||||
func (a *AssetBundle) Dump() {
|
||||
println("Assets:")
|
||||
for _, asset := range a.assets {
|
||||
|
||||
1
v2/internal/runtime/assets/desktop.js
Normal file
1
v2/internal/runtime/assets/desktop.js
Normal file
File diff suppressed because one or more lines are too long
@@ -46,4 +46,6 @@ export function Init() {
|
||||
|
||||
// Do platform specific Init
|
||||
Platform.Init();
|
||||
|
||||
window.wailsloader.runtime = true;
|
||||
}
|
||||
41
v2/internal/runtime/js/desktop/darwin.js
Normal file
41
v2/internal/runtime/js/desktop/darwin.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The lightweight framework for web-like apps
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
/* jshint esversion: 6 */
|
||||
|
||||
/**
|
||||
* Initialises platform specific code
|
||||
*/
|
||||
|
||||
export const System = {
|
||||
Platform: "darwin",
|
||||
AppType: "desktop"
|
||||
}
|
||||
|
||||
export function SendMessage(message) {
|
||||
window.webkit.messageHandlers.external.postMessage(message);
|
||||
}
|
||||
|
||||
export function Init() {
|
||||
|
||||
// Setup drag handler
|
||||
// Based on code from: https://github.com/patr0nus/DeskGap
|
||||
window.addEventListener('mousedown', function (e) {
|
||||
var currentElement = e.target;
|
||||
while (currentElement != null) {
|
||||
if (currentElement.hasAttribute('data-wails-no-drag')) {
|
||||
break;
|
||||
} else if (currentElement.hasAttribute('data-wails-drag')) {
|
||||
window.webkit.messageHandlers.windowDrag.postMessage(null);
|
||||
break;
|
||||
}
|
||||
currentElement = currentElement.parentElement;
|
||||
}
|
||||
});
|
||||
}
|
||||
21
v2/internal/runtime/js/server/darwin.js
Normal file
21
v2/internal/runtime/js/server/darwin.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The lightweight framework for web-like apps
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
/* jshint esversion: 6 */
|
||||
|
||||
/**
|
||||
* Initialises platform specific code
|
||||
*/
|
||||
|
||||
export const System = {
|
||||
Platform: "darwin",
|
||||
AppType: "server"
|
||||
}
|
||||
|
||||
export function Init() { }
|
||||
@@ -141,7 +141,7 @@ func (e *Event) notifyListeners(eventName string, message *message.EventMessage)
|
||||
// Get list of event listeners
|
||||
listeners := e.listeners[eventName]
|
||||
if listeners == nil {
|
||||
println("no listeners for", eventName)
|
||||
e.logger.Info("No listeners for %s", eventName)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
30
v2/internal/system/operatingsystem/os_darwin.go
Normal file
30
v2/internal/system/operatingsystem/os_darwin.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package operatingsystem
|
||||
|
||||
import "github.com/wailsapp/wails/v2/internal/shell"
|
||||
|
||||
func platformInfo() (*OS, error) {
|
||||
// Default value
|
||||
var result OS
|
||||
result.ID = "Unknown"
|
||||
result.Name = "MacOS"
|
||||
result.Version = "Unknown"
|
||||
|
||||
stdout, stderr, err := shell.RunCommand(".", "sysctl", "kern.osrelease")
|
||||
println(stdout)
|
||||
println(stderr)
|
||||
println(err)
|
||||
// cmd := CreateCommand(directory, command, args...)
|
||||
// var stdo, stde bytes.Buffer
|
||||
// cmd.Stdout = &stdo
|
||||
// cmd.Stderr = &stde
|
||||
// err := cmd.Run()
|
||||
// return stdo.String(), stde.String(), err
|
||||
// }
|
||||
// sysctl := shell.NewCommand("sysctl")
|
||||
// kern.ostype: Darwin
|
||||
// kern.osrelease: 20.1.0
|
||||
// kern.osrevision: 199506
|
||||
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
@@ -9,24 +9,6 @@ import (
|
||||
"github.com/wailsapp/wails/v2/internal/shell"
|
||||
)
|
||||
|
||||
// PackageManager is a common interface across all package managers
|
||||
type PackageManager interface {
|
||||
Name() string
|
||||
Packages() packagemap
|
||||
PackageInstalled(*Package) (bool, error)
|
||||
PackageAvailable(*Package) (bool, error)
|
||||
InstallCommand(*Package) string
|
||||
}
|
||||
|
||||
// Package contains information about a system package
|
||||
type Package struct {
|
||||
Name string
|
||||
Version string
|
||||
InstallCommand map[string]string
|
||||
SystemPackage bool
|
||||
Library bool
|
||||
Optional bool
|
||||
}
|
||||
|
||||
// A list of package manager commands
|
||||
var pmcommands = []string{
|
||||
@@ -38,8 +20,6 @@ var pmcommands = []string{
|
||||
"zypper",
|
||||
}
|
||||
|
||||
type packagemap = map[string][]*Package
|
||||
|
||||
// Find will attempt to find the system package manager
|
||||
func Find(osid string) PackageManager {
|
||||
|
||||
@@ -70,58 +50,6 @@ func newPackageManager(pmname string, osid string) PackageManager {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dependancy represents a system package that we require
|
||||
type Dependancy struct {
|
||||
Name string
|
||||
PackageName string
|
||||
Installed bool
|
||||
InstallCommand string
|
||||
Version string
|
||||
Optional bool
|
||||
External bool
|
||||
}
|
||||
|
||||
// DependencyList is a list of Dependency instances
|
||||
type DependencyList []*Dependancy
|
||||
|
||||
// InstallAllRequiredCommand returns the command you need to use to install all required dependencies
|
||||
func (d DependencyList) InstallAllRequiredCommand() string {
|
||||
|
||||
result := ""
|
||||
for _, dependency := range d {
|
||||
if dependency.PackageName != "" {
|
||||
if !dependency.Installed && !dependency.Optional {
|
||||
if result == "" {
|
||||
result = dependency.InstallCommand
|
||||
} else {
|
||||
result += " " + dependency.PackageName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// InstallAllOptionalCommand returns the command you need to use to install all optional dependencies
|
||||
func (d DependencyList) InstallAllOptionalCommand() string {
|
||||
|
||||
result := ""
|
||||
for _, dependency := range d {
|
||||
if dependency.PackageName != "" {
|
||||
if !dependency.Installed && dependency.Optional {
|
||||
if result == "" {
|
||||
result = dependency.InstallCommand
|
||||
} else {
|
||||
result += " " + dependency.PackageName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Dependancies scans the system for required dependancies
|
||||
// Returns a list of dependancies search for, whether they were found
|
||||
// and whether they were installed
|
||||
|
||||
77
v2/internal/system/packagemanager/pm.go
Normal file
77
v2/internal/system/packagemanager/pm.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package packagemanager
|
||||
|
||||
// Package contains information about a system package
|
||||
type Package struct {
|
||||
Name string
|
||||
Version string
|
||||
InstallCommand map[string]string
|
||||
SystemPackage bool
|
||||
Library bool
|
||||
Optional bool
|
||||
}
|
||||
|
||||
type packagemap = map[string][]*Package
|
||||
|
||||
// PackageManager is a common interface across all package managers
|
||||
type PackageManager interface {
|
||||
Name() string
|
||||
Packages() packagemap
|
||||
PackageInstalled(*Package) (bool, error)
|
||||
PackageAvailable(*Package) (bool, error)
|
||||
InstallCommand(*Package) string
|
||||
}
|
||||
|
||||
|
||||
// Dependancy represents a system package that we require
|
||||
type Dependancy struct {
|
||||
Name string
|
||||
PackageName string
|
||||
Installed bool
|
||||
InstallCommand string
|
||||
Version string
|
||||
Optional bool
|
||||
External bool
|
||||
}
|
||||
|
||||
// DependencyList is a list of Dependency instances
|
||||
type DependencyList []*Dependancy
|
||||
|
||||
|
||||
// InstallAllRequiredCommand returns the command you need to use to install all required dependencies
|
||||
func (d DependencyList) InstallAllRequiredCommand() string {
|
||||
|
||||
result := ""
|
||||
for _, dependency := range d {
|
||||
if dependency.PackageName != "" {
|
||||
if !dependency.Installed && !dependency.Optional {
|
||||
if result == "" {
|
||||
result = dependency.InstallCommand
|
||||
} else {
|
||||
result += " " + dependency.PackageName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// InstallAllOptionalCommand returns the command you need to use to install all optional dependencies
|
||||
func (d DependencyList) InstallAllOptionalCommand() string {
|
||||
|
||||
result := ""
|
||||
for _, dependency := range d {
|
||||
if dependency.PackageName != "" {
|
||||
if !dependency.Installed && dependency.Optional {
|
||||
if result == "" {
|
||||
result = dependency.InstallCommand
|
||||
} else {
|
||||
result += " " + dependency.PackageName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
8
v2/internal/system/system_darwin.go
Normal file
8
v2/internal/system/system_darwin.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// +build darwin
|
||||
|
||||
package system
|
||||
|
||||
func (i *Info) discover() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -59,7 +59,7 @@ func Build(options *Options) (string, error) {
|
||||
}
|
||||
|
||||
// Check platform
|
||||
validPlatforms := slicer.String([]string{"linux"})
|
||||
validPlatforms := slicer.String([]string{"linux", "darwin"})
|
||||
if !validPlatforms.Contains(options.Platform) {
|
||||
return "", fmt.Errorf("platform %s not supported", options.Platform)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ func packageProject(options *Options, platform string) error {
|
||||
var err error
|
||||
switch platform {
|
||||
case "linux":
|
||||
err = packageLinuxApplication(options)
|
||||
err = packageApplication(options)
|
||||
default:
|
||||
err = fmt.Errorf("packing not supported for %s yet", platform)
|
||||
}
|
||||
|
||||
6
v2/pkg/commands/build/packager_darwin.go
Normal file
6
v2/pkg/commands/build/packager_darwin.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package build
|
||||
|
||||
func packageApplication(options *Options) error {
|
||||
// TBD
|
||||
return nil
|
||||
}
|
||||
@@ -17,7 +17,7 @@ func deleteLinuxPackFiles(appDirBase string) {
|
||||
os.RemoveAll(appDir)
|
||||
}
|
||||
|
||||
func packageLinuxApplication(options *Options) error {
|
||||
func packageApplication(options *Options) error {
|
||||
|
||||
// Check we have AppImage tools
|
||||
|
||||
|
||||
1533
v2/test/runtime/frontend/package-lock.json
generated
1533
v2/test/runtime/frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -116,23 +116,11 @@
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-10">
|
||||
<button type="button" onclick="window.scripts.sendEvent()" class="btn btn-primary">Emit
|
||||
<button type="button" onclick="window.scripts.sendEvent()" placholder="testevent" class="btn btn-primary">Emit
|
||||
Event</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<form>
|
||||
<div class="form-group row">
|
||||
<label for="message" class="col-sm-2 col-form-label">Listening to Event 'oneoffevent'</label>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-10">
|
||||
<div class="col-sm-10">
|
||||
<div id="oneoffeventoutput"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="calls">
|
||||
<h1>Calls</h1>
|
||||
|
||||
@@ -51,6 +51,11 @@ func (r *RuntimeTest) Fullscreen() {
|
||||
r.runtime.Window.Fullscreen()
|
||||
}
|
||||
|
||||
// SetTitle will call the SetTitle method
|
||||
func (r *RuntimeTest) SetTitle(title string) {
|
||||
r.runtime.Window.SetTitle(title)
|
||||
}
|
||||
|
||||
// UnFullscreen will call the Runtime.UnFullscreen method
|
||||
func (r *RuntimeTest) UnFullscreen() {
|
||||
r.runtime.Window.UnFullscreen()
|
||||
|
||||
Reference in New Issue
Block a user