remove vendor

This commit is contained in:
liwei committed 2019-04-21 22:41:15 +08:00
1 parent 237fc0188a
commit dace77c07c
11 files changed
-3451

No files matched your search

-1
View File
@@ -1 +0,0 @@
*.h linguist-language=c
-7
View File
@@ -1,7 +0,0 @@
# Build atrifacts
/build
/examples/minimal-go/minimal-go
/examples/minimal/minimal
/examples/minimal/minimal.exe
/examples/minimal/build
/examples/timer-cxx/build
-22
View File
@@ -1,22 +0,0 @@
language: go
go:
- 1.x
matrix:
include:
- os: linux
before_install:
- sudo add-apt-repository ppa:webkit-team/ppa -y
- sudo apt-get update
- sudo apt-get install libwebkit2gtk-4.0-dev -y
- os: osx
osx_image: xcode8.3
script:
- cd examples/minimal && mkdir -p build && cd build && cmake .. && make && ls -l && cd ../../..
- cd examples/timer-cxx && mkdir -p build && cd build && cmake .. && make && ls -l && cd ../../..
- cd examples/minimal-go && go build && ls -l && cd ../..
- cd examples/todo-go && go build && ls -l && cd ../..
- cd examples/page-load-go && go build && ls -l && cd ../..
- cd examples/window-go && go build && ls -l && cd ../..
-32
View File
@@ -1,32 +0,0 @@
cmake_minimum_required(VERSION 2.8)
project(webview)
if(APPLE)
set(WEBVIEW_COMPILE_DEFS "-DWEBVIEW_COCOA=1")
set(WEBVIEW_LIBS "-framework WebKit")
elseif(WIN32)
set(WEBVIEW_COMPILE_DEFS "-DWEBVIEW_WINAPI=1")
set(WEBVIEW_LIBS "ole32 comctl32 oleaut32 uuid")
else()
set(WEBVIEW_COMPILE_DEFS "-DWEBVIEW_GTK=1")
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
pkg_check_modules(WEBKIT2 REQUIRED webkit2gtk-4.0)
set(WEBVIEW_COMPILE_INCS ${GTK3_INCLUDE_DIRS} ${WEBKIT2_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR})
set(WEBVIEW_LIBS ${GTK3_LIBRARIES} ${WEBKIT2_LIBRARIES})
endif()
add_library(webview ${CMAKE_CURRENT_BINARY_DIR}/webview.c)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/webview.c "#define WEBVIEW_IMPLEMENTATION\n#include <webview.h>")
target_include_directories(webview PUBLIC ${PROJECT_SOURCE_DIR} ${WEBVIEW_COMPILE_INCS})
target_compile_definitions(webview PUBLIC ${WEBVIEW_COMPILE_DEFS})
target_compile_options(webview PRIVATE ${WEBVIEW_COMPILE_OPTS})
target_link_libraries(webview ${WEBVIEW_LIBS})
add_executable(webview_test WIN32 MACOSX_BUNDLE webview_test.cc)
set_target_properties(webview_test PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO)
find_package(Threads)
target_link_libraries(webview_test PRIVATE webview ${CMAKE_THREAD_LIBS_INIT})
enable_testing ()
add_test(NAME webview_test COMMAND webview_test)
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 Serge Zaitsev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-315
View File
@@ -1,315 +0,0 @@
# webview
[![Join the chat at https://gitter.im/zserge/webview](https://badges.gitter.im/zserge/webview.svg)](https://gitter.im/zserge/webview?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/zserge/webview.svg?branch=master)](https://travis-ci.org/zserge/webview)
[![Build status](https://ci.appveyor.com/api/projects/status/ksii33qx18d94h6v?svg=true)](https://ci.appveyor.com/project/zserge/webview)
[![GoDoc](https://godoc.org/github.com/zserge/webview?status.svg)](https://godoc.org/github.com/zserge/webview)
[![Go Report Card](https://goreportcard.com/badge/github.com/zserge/webview)](https://goreportcard.com/report/github.com/zserge/webview)
A tiny cross-platform webview library for C/C++/Golang to build modern cross-platform GUIs. Also, there are [Rust bindings](https://github.com/Boscop/webview-rs), [Python bindings](https://github.com/zserge/webview-python), [Nim bindings](https://github.com/oskca/webview), [Haskell](https://github.com/lettier/webviewhs) and [C# bindings](https://github.com/iwillspeak/webview-cs) available.
**IMPORTANT NOTE: Webview is now being rewritten from scratch, with the support of EdgeHTML and using C++14 as a primary language (code becomes much shorter/cleaner, and we still have C and Go APIs as the primary interface). Please have a look at [webview-x](https://github.com/zserge/webview/tree/webview-x) branch before opening new issues. Current version of webview is still maintained, PRs with bugfixes are welcome, but new functionality will be added to the new branch. I expect to finish the new branch before March 2019, but no hard deadlines.**
It supports two-way JavaScript bindings (to call JavaScript from C/C++/Go and to call C/C++/Go from JavaScript).
It uses Cocoa/WebKit on macOS, gtk-webkit2 on Linux and MSHTML (IE10/11) on Windows.
<p align="center"><img alt="linux" src="examples/todo-go/screenshots/screenshots.png"></p>
## Webview for Go developers
If you are interested in writing Webview apps in C/C++, [skip to the next section](#webview-for-cc-developers).
### Getting started
Install Webview library with `go get`:
```
$ go get github.com/zserge/webview
```
Import the package and start using it:
```go
package main
import "github.com/zserge/webview"
func main() {
// Open wikipedia in a 800x600 resizable window
webview.Open("Minimal webview example",
"https://en.m.wikipedia.org/wiki/Main_Page", 800, 600, true)
}
```
It is not recommended to use `go run` (although it works perfectly fine on Linux). Use `go build` instead:
```bash
# Linux
$ go build -o webview-example && ./webview-example
# MacOS uses app bundles for GUI apps
$ mkdir -p example.app/Contents/MacOS
$ go build -o example.app/Contents/MacOS/example
$ open example.app # Or click on the app in Finder
# Windows requires special linker flags for GUI apps.
# It's also recommended to use TDM-GCC-64 compiler for CGo.
# http://tdm-gcc.tdragon.net/download
$ go build -ldflags="-H windowsgui" -o webview-example.exe
```
### API
See [godoc](https://godoc.org/github.com/zserge/webview).
### How to serve or inject the initial HTML/CSS/JavaScript into the webview?
First of all, you probably want to embed your assets (HTML/CSS/JavaScript) into the binary to have a standalone executable. Consider using [go-bindata](https://github.com/go-bindata/go-bindata) or any other similar tools.
Now there are two major approaches to deploy the content:
* Serve HTML/CSS/JS with an embedded HTTP server
* Injecting HTML/CSS/JS via the JavaScript binding API
To serve the content it is recommended to use ephemeral ports:
```go
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
log.Fatal(err)
}
defer ln.Close()
go func() {
// Set up your http server here
log.Fatal(http.Serve(ln, nil))
}()
webview.Open("Hello", "http://"+ln.Addr().String(), 400, 300, false)
```
Injecting the content via JS bindings is a bit more complicated, but feels more solid and does not expose any additional open TCP ports.
Leave `webview.Settings.URL` empty to start with bare minimal HTML5. It will open a webview with `<div id="app"></div>` in it. Alternatively, use a data URI to inject custom HTML code (don't forget to URL-encode it):
```go
const myHTML = `<!doctype html><html>....</html>`
w := webview.New(webview.Settings{
URL: `data:text/html,` + url.PathEscape(myHTML),
})
```
Keep your initial HTML short (a few kilobytes maximum).
Now you can inject more JavaScript once the webview becomes ready using `webview.Eval()`. You can also inject CSS styles using JavaScript:
```go
w.Dispatch(func() {
// Inject CSS
w.Eval(fmt.Sprintf(`(function(css){
var style = document.createElement('style');
var head = document.head || document.getElementsByTagName('head')[0];
style.setAttribute('type', 'text/css');
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
})("%s")`, template.JSEscapeString(myStylesCSS)))
// Inject JS
w.Eval(myJSFramework)
w.Eval(myAppJS)
})
```
This works fairly well across the platforms, see `counter-go` example for more details about how make a webview app with no web server. It also demonstrates how to use ReactJS, VueJS or Picodom with webview.
### How to communicate between native Go and web UI?
You already have seen how to use `w.Eval()` to run JavaScript inside the webview. There is also a way to call Go code from JavaScript.
On the low level there is a special callback, `webview.Settings.ExternalInvokeCallback` that receives a string argument. This string can be passed from JavaScript using `window.external.invoke(someString)`.
This might seem very inconvenient, and that is why there is a dedicated `webview.Bind()` API call. It binds an existing Go object (struct or struct pointer) and creates/injects JS API for it. Now you can call JS methods and they will result in calling native Go methods. Even more, if you modify the Go object - it can be automatically serialized to JSON and passed to the web UI to keep things in sync.
Please, see `counter-go` example for more details about how to bind Go controllers to the web UI.
## Debugging and development tips
If terminal output is unavailable (e.g. if you launch app bundle on MacOS or
GUI app on Windows) you may use `webview.Debug()` and `webview.Debugf()` to
print logs. On MacOS such logs will be printed via NSLog and can be seen in the
`Console` app. On Windows they use `OutputDebugString` and can be seen using
`DebugView` app. On Linux logging is done to stderr and can be seen in the
terminal or redirected to a file.
To debug the web part of your app you may use `webview.Settings.Debug` flag. It
enables the Web Inspector in WebKit and works on Linux and MacOS (use popup menu
to open the web inspector). On Windows there is no easy to way to enable
debugging, but you may include Firebug in your HTML code:
```html
<script type="text/javascript" src="https://getfirebug.com/firebug-lite.js"></script>
```
Even though Firebug browser extension development has been stopped, Firebug
Lite is still available and just works.
## Distributing webview apps
On Linux you get a standalone executable. It will depend on GTK3 and GtkWebkit2, so if you distribute your app in DEB or RPM format include those dependencies. An application icon can be specified by providing a `.desktop` file.
On MacOS you are likely to ship an app bundle. Make the following directory structure and just zip it:
```
example.app
└── Contents
   ├── Info.plist
   ├── MacOS
   | └── example
   └── Resources
└── example.icns
```
Here, `Info.plist` is a [property list file](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html) and `*.icns` is a special icon format. You may convert PNG to icns [online](https://iconverticons.com/online/).
On Windows you probably would like to have a custom icon for your executable. It can be done by providing a resource file, compiling it and linking with it. Typically, `windres` utility is used to compile resources.
You may find some example build scripts for all three platforms [here](https://github.com/naivesound/glitch/tree/master/dist).
Also, if you want to cross-compile your webview app - use [xgo](https://github.com/karalabe/xgo).
## Webview for C/C++ developers
### Getting started
Download [webview.h](https://raw.githubusercontent.com/zserge/webview/master/webview.h) and include it in your C/C++ code:
```c
// main.c
#define WEBVIEW_IMPLEMENTATION
#include "webview.h"
#ifdef WIN32
int WINAPI WinMain(HINSTANCE hInt, HINSTANCE hPrevInst, LPSTR lpCmdLine,
int nCmdShow) {
#else
int main() {
#endif
/* Open wikipedia in a 800x600 resizable window */
webview("Minimal webview example",
"https://en.m.wikipedia.org/wiki/Main_Page", 800, 600, 1);
return 0;
}
```
Build it:
```bash
# Linux
$ cc main.c -DWEBVIEW_GTK=1 `pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.0` -o webview-example
# MacOS
$ cc main.c -DWEBVIEW_COCOA=1 -framework WebKit -o webview-example
# Windows (mingw)
$ cc main.c -DWEBVIEW_WINAPI=1 -lole32 -lcomctl32 -loleaut32 -luuid -mwindows -o webview-example.exe
```
### API
For the most simple use cases there is only one function:
```c
int webview(const char *title, const char *url, int width, int height, int resizable);
```
The following URL schemes are supported:
* `http://` and `https://`, no surprises here.
* `file:///` can be useful if you want to unpack HTML/CSS assets to some
temporary directory and point a webview to open index.html from there.
* `data:text/html,<html>...</html>` allows to pass short HTML data inline
without using a web server or polluting the file system. Further
modifications of the webview contents can be done via JavaScript bindings.
If have chosen a regular http URL scheme, you can use Mongoose or any other web server/framework you like.
If you want to have more control over the app lifecycle you can use the following functions:
```c
struct webview webview = {
.title = title,
.url = url,
.width = w,
.height = h,
.debug = debug,
.resizable = resizable,
};
/* Create webview window using the provided options */
webview_init(&webview);
/* Main app loop, can be either blocking or non-blocking */
while (webview_loop(&webview, blocking) == 0);
/* Destroy webview window, often exits the app */
webview_exit(&webview);
/* To change window title later: */
webview_set_title(&webview, "New title");
/* To terminate the webview main loop: */
webview_terminate(&webview);
/* To print logs to stderr, MacOS Console or DebugView: */
webview_debug("exited: %d\n", 1);
```
To evaluate arbitrary JavaScript code use the following C function:
```c
webview_eval(&webview, "alert('hello, world');");
```
There is also a special callback (`webview.external_invoke_cb`) that can be invoked from JavaScript:
```javascript
// C
void my_cb(struct webview *w, const char *arg) {
...
}
// JS
window.external.invoke('some arg');
// Exactly one string argument must be provided, to pass more complex objects
// serialize them to JSON and parse it in C. To pass binary data consider using
// base64.
window.external.invoke(JSON.stringify({fn: 'sum', x: 5, y: 3}));
```
Webview library is meant to be used from a single UI thread only. So if you
want to call `webview_eval` or `webview_terminate` from some background thread
- you have to use `webview_dispatch` to post some arbitrary function with some
context to be executed inside the main UI thread:
```c
// This function will be executed on the UI thread
void render(struct webview *w, void *arg) {
webview_eval(w, ......);
}
// Dispatch render() function from another thread:
webview_dispatch(w, render, some_arg);
```
You may find some C/C++ examples in this repo that demonstrate the API above.
Also, there is a more more advanced complete C++ app, [Slide](https://github.com/zserge/slide), that uses webview as a GUI. You may have a look how webview apps can be built, packaged and how automatic CI/CD can be set up.
## Notes
Execution on OpenBSD requires `wxallowed` [mount(8)](https://man.openbsd.org/mount.8) option.
FreeBSD is also supported, to install webkit2 run `pkg install webkit2-gtk3`.
## License
Code is distributed under MIT license, feel free to use it in your proprietary
projects as well.
-38
View File
@@ -1,38 +0,0 @@
os: Visual Studio 2017
version: "{build}"
clone_folder: c:\gopath\src\github.com\zserge\webview
environment:
global:
GOPATH: C:\gopath
matrix:
- GETH_ARCH: amd64
GOARCH: amd64
CGO_ENABLED: 1
MSYS2_ARCH: x86_64
MSYS2_BITS: 64
MSYSTEM: MINGW64
PATH: C:\msys64\mingw64\bin\;C:\Program Files (x86)\NSIS\;%PATH%
- GETH_ARCH: 386
GOARCH: 386
CGO_ENABLED: 1
MSYS2_ARCH: i686
MSYS2_BITS: 32
MSYSTEM: MINGW32
PATH: C:\msys64\mingw32\bin\;C:\Program Files (x86)\NSIS\;%PATH%
install:
- echo %PATH%
- echo %GOPATH%
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
- go version
- go env
- gcc --version
build_script:
- go build -o buildOutput\minimal -i ./examples/minimal-go
- go build -o buildOutput\todo -i ./examples/todo-go
- go build -o buildOutput\window -i ./examples/window-go
- go build -o buildOutput\pageload -i ./examples/page-load-go
-572
View File
@@ -1,572 +0,0 @@
//
// Package webview implements Go bindings to https://github.com/zserge/webview C library.
//
// Bindings closely repeat the C APIs and include both, a simplified
// single-function API to just open a full-screen webview window, and a more
// advanced and featureful set of APIs, including Go-to-JavaScript bindings.
//
// The library uses gtk-webkit, Cocoa/Webkit and MSHTML (IE8..11) as a browser
// engine and supports Linux, MacOS and Windows 7..10 respectively.
//
package webview
/*
#cgo linux openbsd freebsd CFLAGS: -DWEBVIEW_GTK=1
#cgo linux openbsd freebsd pkg-config: gtk+-3.0 webkit2gtk-4.0
#cgo windows CFLAGS: -DWEBVIEW_WINAPI=1
#cgo windows LDFLAGS: -lole32 -lcomctl32 -loleaut32 -luuid -lgdi32
#cgo darwin CFLAGS: -DWEBVIEW_COCOA=1
#cgo darwin LDFLAGS: -framework WebKit
#include <stdlib.h>
#include <stdint.h>
#define WEBVIEW_STATIC
#define WEBVIEW_IMPLEMENTATION
#include "webview.h"
extern void _webviewExternalInvokeCallback(void *, void *);
static inline void CgoWebViewFree(void *w) {
free((void *)((struct webview *)w)->title);
free((void *)((struct webview *)w)->url);
free(w);
}
static inline void *CgoWebViewCreate(int width, int height, char *title, char *url, int resizable, int debug) {
struct webview *w = (struct webview *) calloc(1, sizeof(*w));
w->width = width;
w->height = height;
w->title = title;
w->url = url;
w->resizable = resizable;
w->debug = debug;
w->external_invoke_cb = (webview_external_invoke_cb_t) _webviewExternalInvokeCallback;
if (webview_init(w) != 0) {
CgoWebViewFree(w);
return NULL;
}
return (void *)w;
}
static inline int CgoWebViewLoop(void *w, int blocking) {
return webview_loop((struct webview *)w, blocking);
}
static inline void CgoWebViewTerminate(void *w) {
webview_terminate((struct webview *)w);
}
static inline void CgoWebViewExit(void *w) {
webview_exit((struct webview *)w);
}
static inline void CgoWebViewSetTitle(void *w, char *title) {
webview_set_title((struct webview *)w, title);
}
static inline void CgoWebViewSetFullscreen(void *w, int fullscreen) {
webview_set_fullscreen((struct webview *)w, fullscreen);
}
static inline void CgoWebViewSetColor(void *w, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
webview_set_color((struct webview *)w, r, g, b, a);
}
static inline void CgoDialog(void *w, int dlgtype, int flags,
char *title, char *arg, char *res, size_t ressz) {
webview_dialog(w, dlgtype, flags,
(const char*)title, (const char*) arg, res, ressz);
}
static inline int CgoWebViewEval(void *w, char *js) {
return webview_eval((struct webview *)w, js);
}
static inline void CgoWebViewInjectCSS(void *w, char *css) {
webview_inject_css((struct webview *)w, css);
}
extern void _webviewDispatchGoCallback(void *);
static inline void _webview_dispatch_cb(struct webview *w, void *arg) {
_webviewDispatchGoCallback(arg);
}
static inline void CgoWebViewDispatch(void *w, uintptr_t arg) {
webview_dispatch((struct webview *)w, _webview_dispatch_cb, (void *)arg);
}
*/
import "C"
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"html/template"
"log"
"reflect"
"runtime"
"sync"
"unicode"
"unsafe"
)
func init() {
// Ensure that main.main is called from the main thread
runtime.LockOSThread()
}
// Open is a simplified API to open a single native window with a full-size webview in
// it. It can be helpful if you want to communicate with the core app using XHR
// or WebSockets (as opposed to using JavaScript bindings).
//
// Window appearance can be customized using title, width, height and resizable parameters.
// URL must be provided and can user either a http or https protocol, or be a
// local file:// URL. On some platforms "data:" URLs are also supported
// (Linux/MacOS).
func Open(title, url string, w, h int, resizable bool) error {
titleStr := C.CString(title)
defer C.free(unsafe.Pointer(titleStr))
urlStr := C.CString(url)
defer C.free(unsafe.Pointer(urlStr))
resize := C.int(0)
if resizable {
resize = C.int(1)
}
r := C.webview(titleStr, urlStr, C.int(w), C.int(h), resize)
if r != 0 {
return errors.New("failed to create webview")
}
return nil
}
// Debug prints a debug string using stderr on Linux/BSD, NSLog on MacOS and
// OutputDebugString on Windows.
func Debug(a ...interface{}) {
s := C.CString(fmt.Sprint(a...))
defer C.free(unsafe.Pointer(s))
C.webview_print_log(s)
}
// Debugf prints a formatted debug string using stderr on Linux/BSD, NSLog on
// MacOS and OutputDebugString on Windows.
func Debugf(format string, a ...interface{}) {
s := C.CString(fmt.Sprintf(format, a...))
defer C.free(unsafe.Pointer(s))
C.webview_print_log(s)
}
// ExternalInvokeCallbackFunc is a function type that is called every time
// "window.external.invoke()" is called from JavaScript. Data is the only
// obligatory string parameter passed into the "invoke(data)" function from
// JavaScript. To pass more complex data serialized JSON or base64 encoded
// string can be used.
type ExternalInvokeCallbackFunc func(w WebView, data string)
// Settings is a set of parameters to customize the initial WebView appearance
// and behavior. It is passed into the webview.New() constructor.
type Settings struct {
// WebView main window title
Title string
// URL to open in a webview
URL string
// Window width in pixels
Width int
// Window height in pixels
Height int
// Allows/disallows window resizing
Resizable bool
// Enable debugging tools (Linux/BSD/MacOS, on Windows use Firebug)
Debug bool
// A callback that is executed when JavaScript calls "window.external.invoke()"
ExternalInvokeCallback ExternalInvokeCallbackFunc
}
// WebView is an interface that wraps the basic methods for controlling the UI
// loop, handling multithreading and providing JavaScript bindings.
type WebView interface {
// Run() starts the main UI loop until the user closes the webview window or
// Terminate() is called.
Run()
// Loop() runs a single iteration of the main UI.
Loop(blocking bool) bool
// SetTitle() changes window title. This method must be called from the main
// thread only. See Dispatch() for more details.
SetTitle(title string)
// SetFullscreen() controls window full-screen mode. This method must be
// called from the main thread only. See Dispatch() for more details.
SetFullscreen(fullscreen bool)
// SetColor() changes window background color. This method must be called from
// the main thread only. See Dispatch() for more details.
SetColor(r, g, b, a uint8)
// Eval() evaluates an arbitrary JS code inside the webview. This method must
// be called from the main thread only. See Dispatch() for more details.
Eval(js string) error
// InjectJS() injects an arbitrary block of CSS code using the JS API. This
// method must be called from the main thread only. See Dispatch() for more
// details.
InjectCSS(css string)
// Dialog() opens a system dialog of the given type and title. String
// argument can be provided for certain dialogs, such as alert boxes. For
// alert boxes argument is a message inside the dialog box.
Dialog(dlgType DialogType, flags int, title string, arg string) string
// Terminate() breaks the main UI loop. This method must be called from the main thread
// only. See Dispatch() for more details.
Terminate()
// Dispatch() schedules some arbitrary function to be executed on the main UI
// thread. This may be helpful if you want to run some JavaScript from
// background threads/goroutines, or to terminate the app.
Dispatch(func())
// Exit() closes the window and cleans up the resources. Use Terminate() to
// forcefully break out of the main UI loop.
Exit()
// Bind() registers a binding between a given value and a JavaScript object with the
// given name. A value must be a struct or a struct pointer. All methods are
// available under their camel-case names, starting with a lower-case letter,
// e.g. "FooBar" becomes "fooBar" in JavaScript.
// Bind() returns a function that updates JavaScript object with the current
// Go value. You only need to call it if you change Go value asynchronously.
Bind(name string, v interface{}) (sync func(), err error)
}
// DialogType is an enumeration of all supported system dialog types
type DialogType int
const (
// DialogTypeOpen is a system file open dialog
DialogTypeOpen DialogType = iota
// DialogTypeSave is a system file save dialog
DialogTypeSave
// DialogTypeAlert is a system alert dialog (message box)
DialogTypeAlert
)
const (
// DialogFlagFile is a normal file picker dialog
DialogFlagFile = C.WEBVIEW_DIALOG_FLAG_FILE
// DialogFlagDirectory is an open directory dialog
DialogFlagDirectory = C.WEBVIEW_DIALOG_FLAG_DIRECTORY
// DialogFlagInfo is an info alert dialog
DialogFlagInfo = C.WEBVIEW_DIALOG_FLAG_INFO
// DialogFlagWarning is a warning alert dialog
DialogFlagWarning = C.WEBVIEW_DIALOG_FLAG_WARNING
// DialogFlagError is an error dialog
DialogFlagError = C.WEBVIEW_DIALOG_FLAG_ERROR
)
var (
m sync.Mutex
index uintptr
fns = map[uintptr]func(){}
cbs = map[WebView]ExternalInvokeCallbackFunc{}
)
type webview struct {
w unsafe.Pointer
}
var _ WebView = &webview{}
func boolToInt(b bool) int {
if b {
return 1
}
return 0
}
// New creates and opens a new webview window using the given settings. The
// returned object implements the WebView interface. This function returns nil
// if a window can not be created.
func New(settings Settings) WebView {
if settings.Width == 0 {
settings.Width = 640
}
if settings.Height == 0 {
settings.Height = 480
}
if settings.Title == "" {
settings.Title = "WebView"
}
w := &webview{}
w.w = C.CgoWebViewCreate(C.int(settings.Width), C.int(settings.Height),
C.CString(settings.Title), C.CString(settings.URL),
C.int(boolToInt(settings.Resizable)), C.int(boolToInt(settings.Debug)))
m.Lock()
if settings.ExternalInvokeCallback != nil {
cbs[w] = settings.ExternalInvokeCallback
} else {
cbs[w] = func(w WebView, data string) {}
}
m.Unlock()
return w
}
func (w *webview) Loop(blocking bool) bool {
block := C.int(0)
if blocking {
block = 1
}
return C.CgoWebViewLoop(w.w, block) == 0
}
func (w *webview) Run() {
for w.Loop(true) {
}
}
func (w *webview) Exit() {
C.CgoWebViewExit(w.w)
}
func (w *webview) Dispatch(f func()) {
m.Lock()
for ; fns[index] != nil; index++ {
}
fns[index] = f
m.Unlock()
C.CgoWebViewDispatch(w.w, C.uintptr_t(index))
}
func (w *webview) SetTitle(title string) {
p := C.CString(title)
defer C.free(unsafe.Pointer(p))
C.CgoWebViewSetTitle(w.w, p)
}
func (w *webview) SetColor(r, g, b, a uint8) {
C.CgoWebViewSetColor(w.w, C.uint8_t(r), C.uint8_t(g), C.uint8_t(b), C.uint8_t(a))
}
func (w *webview) SetFullscreen(fullscreen bool) {
C.CgoWebViewSetFullscreen(w.w, C.int(boolToInt(fullscreen)))
}
func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string) string {
const maxPath = 4096
titlePtr := C.CString(title)
defer C.free(unsafe.Pointer(titlePtr))
argPtr := C.CString(arg)
defer C.free(unsafe.Pointer(argPtr))
resultPtr := (*C.char)(C.calloc((C.size_t)(unsafe.Sizeof((*C.char)(nil))), (C.size_t)(maxPath)))
defer C.free(unsafe.Pointer(resultPtr))
C.CgoDialog(w.w, C.int(dlgType), C.int(flags), titlePtr,
argPtr, resultPtr, C.size_t(maxPath))
return C.GoString(resultPtr)
}
func (w *webview) Eval(js string) error {
p := C.CString(js)
defer C.free(unsafe.Pointer(p))
switch C.CgoWebViewEval(w.w, p) {
case -1:
return errors.New("evaluation failed")
}
return nil
}
func (w *webview) InjectCSS(css string) {
p := C.CString(css)
defer C.free(unsafe.Pointer(p))
C.CgoWebViewInjectCSS(w.w, p)
}
func (w *webview) Terminate() {
C.CgoWebViewTerminate(w.w)
}
//export _webviewDispatchGoCallback
func _webviewDispatchGoCallback(index unsafe.Pointer) {
var f func()
m.Lock()
f = fns[uintptr(index)]
delete(fns, uintptr(index))
m.Unlock()
f()
}
//export _webviewExternalInvokeCallback
func _webviewExternalInvokeCallback(w unsafe.Pointer, data unsafe.Pointer) {
m.Lock()
var (
cb ExternalInvokeCallbackFunc
wv WebView
)
for wv, cb = range cbs {
if wv.(*webview).w == w {
break
}
}
m.Unlock()
cb(wv, C.GoString((*C.char)(data)))
}
var bindTmpl = template.Must(template.New("").Parse(`
if (typeof {{.Name}} === 'undefined') {
{{.Name}} = {};
}
{{ range .Methods }}
{{$.Name}}.{{.JSName}} = function({{.JSArgs}}) {
window.external.invoke(JSON.stringify({scope: "{{$.Name}}", method: "{{.Name}}", params: [{{.JSArgs}}]}));
};
{{ end }}
`))
type binding struct {
Value interface{}
Name string
Methods []methodInfo
}
func newBinding(name string, v interface{}) (*binding, error) {
methods, err := getMethods(v)
if err != nil {
return nil, err
}
return &binding{Name: name, Value: v, Methods: methods}, nil
}
func (b *binding) JS() (string, error) {
js := &bytes.Buffer{}
err := bindTmpl.Execute(js, b)
return js.String(), err
}
func (b *binding) Sync() (string, error) {
js, err := json.Marshal(b.Value)
if err == nil {
return fmt.Sprintf("%[1]s.data=%[2]s;if(%[1]s.render){%[1]s.render(%[2]s);}", b.Name, string(js)), nil
}
return "", err
}
func (b *binding) Call(js string) bool {
type rpcCall struct {
Scope string `json:"scope"`
Method string `json:"method"`
Params []interface{} `json:"params"`
}
rpc := rpcCall{}
if err := json.Unmarshal([]byte(js), &rpc); err != nil {
return false
}
if rpc.Scope != b.Name {
return false
}
var mi *methodInfo
for i := 0; i < len(b.Methods); i++ {
if b.Methods[i].Name == rpc.Method {
mi = &b.Methods[i]
break
}
}
if mi == nil {
return false
}
args := make([]reflect.Value, mi.Arity(), mi.Arity())
for i := 0; i < mi.Arity(); i++ {
val := reflect.ValueOf(rpc.Params[i])
arg := mi.Value.Type().In(i)
u := reflect.New(arg)
if b, err := json.Marshal(val.Interface()); err == nil {
if err = json.Unmarshal(b, u.Interface()); err == nil {
args[i] = reflect.Indirect(u)
}
}
if !args[i].IsValid() {
return false
}
}
mi.Value.Call(args)
return true
}
type methodInfo struct {
Name string
Value reflect.Value
}
func (mi methodInfo) Arity() int { return mi.Value.Type().NumIn() }
func (mi methodInfo) JSName() string {
r := []rune(mi.Name)
if len(r) > 0 {
r[0] = unicode.ToLower(r[0])
}
return string(r)
}
func (mi methodInfo) JSArgs() (js string) {
for i := 0; i < mi.Arity(); i++ {
if i > 0 {
js = js + ","
}
js = js + fmt.Sprintf("a%d", i)
}
return js
}
func getMethods(obj interface{}) ([]methodInfo, error) {
p := reflect.ValueOf(obj)
v := reflect.Indirect(p)
t := reflect.TypeOf(obj)
if t == nil {
return nil, errors.New("object can not be nil")
}
k := t.Kind()
if k == reflect.Ptr {
k = v.Type().Kind()
}
if k != reflect.Struct {
return nil, errors.New("must be a struct or a pointer to a struct")
}
methods := []methodInfo{}
for i := 0; i < t.NumMethod(); i++ {
method := t.Method(i)
if !unicode.IsUpper([]rune(method.Name)[0]) {
continue
}
mi := methodInfo{
Name: method.Name,
Value: p.MethodByName(method.Name),
}
methods = append(methods, mi)
}
return methods, nil
}
func (w *webview) Bind(name string, v interface{}) (sync func(), err error) {
b, err := newBinding(name, v)
if err != nil {
return nil, err
}
js, err := b.JS()
if err != nil {
return nil, err
}
sync = func() {
if js, err := b.Sync(); err != nil {
log.Println(err)
} else {
w.Eval(js)
}
}
m.Lock()
cb := cbs[w]
cbs[w] = func(w WebView, data string) {
if ok := b.Call(data); ok {
sync()
} else {
cb(w, data)
}
}
m.Unlock()
w.Eval(js)
sync()
return sync, nil
}
-2265
View File
File diff suppressed because it is too large. Load diff
-176
View File
@@ -1,176 +0,0 @@
// +build ignore
#include <cassert>
#include <cstdio>
#include <functional>
#include <iostream>
#include <string>
#include <thread>
#include <utility>
#include <vector>
#define WEBVIEW_IMPLEMENTATION
#include "webview.h"
extern "C" void webview_dispatch_proxy(struct webview *w, void *arg) {
(*static_cast<std::function<void(struct webview *)> *>(arg))(w);
}
class runner {
public:
runner(struct webview *w) : w(w) { webview_init(this->w); }
~runner() { webview_exit(this->w); }
runner &then(std::function<void(struct webview *w)> fn) {
auto arg = new std::pair<std::function<void(struct webview *)>, void *>(
fn, nullptr);
this->queue.push_back([=](struct webview *w) {
webview_dispatch(
w,
[](struct webview *w, void *arg) {
auto dispatch_arg = reinterpret_cast<
std::pair<std::function<void(struct webview *)>, void *> *>(
arg);
dispatch_arg->first(w);
delete dispatch_arg;
},
reinterpret_cast<void *>(arg));
});
return *this;
}
runner &sleep(const int millis) {
this->queue.push_back([=](struct webview *w) {
(void)w;
std::this_thread::sleep_for(std::chrono::milliseconds(millis));
});
return *this;
}
void wait() {
this->then([](struct webview *w) { webview_terminate(w); });
auto q = this->queue;
auto w = this->w;
std::thread bg_thread([w, q]() {
for (auto f : q) {
f(w);
}
});
while (webview_loop(w, 1) == 0) {
}
bg_thread.join();
}
private:
struct webview *w;
std::vector<std::function<void(struct webview *)>> queue;
};
static void test_minimal() {
struct webview w = {};
std::cout << "TEST: minimal" << std::endl;
w.title = "Minimal test";
w.width = 480;
w.height = 320;
webview_init(&w);
webview_dispatch(&w,
[](struct webview *w, void *arg) {
(void)arg;
webview_terminate(w);
},
nullptr);
while (webview_loop(&w, 1) == 0) {
}
webview_exit(&w);
}
static void test_window_size() {
struct webview w = {};
std::vector<std::string> results;
std::cout << "TEST: window size" << std::endl;
w.width = 480;
w.height = 320;
w.resizable = 1;
w.userdata = static_cast<void *>(&results);
w.external_invoke_cb = [](struct webview *w, const char *arg) {
auto *v = static_cast<std::vector<std::string> *>(w->userdata);
v->push_back(std::string(arg));
};
runner(&w)
.then([](struct webview *w) {
webview_eval(w, "window.external.invoke(''+window.screen.width+' ' + "
"window.screen.height)");
webview_eval(w, "window.external.invoke(''+window.innerWidth+' ' + "
"window.innerHeight)");
})
.sleep(200)
.then([](struct webview *w) { webview_set_fullscreen(w, 1); })
.sleep(500)
.then([](struct webview *w) {
webview_eval(w, "window.external.invoke(''+window.innerWidth+' ' + "
"window.innerHeight)");
})
.sleep(200)
.then([](struct webview *w) { webview_set_fullscreen(w, 0); })
.sleep(500)
.then([](struct webview *w) {
webview_eval(w, "window.external.invoke(''+window.innerWidth+' ' + "
"window.innerHeight)");
})
.wait();
assert(results.size() == 4);
assert(results[1] == "480 320");
assert(results[0] == results[2]);
assert(results[1] == results[3]);
}
static void test_inject_js() {
struct webview w = {};
std::vector<std::string> results;
std::cout << "TEST: inject JS" << std::endl;
w.width = 480;
w.height = 320;
w.userdata = static_cast<void *>(&results);
w.external_invoke_cb = [](struct webview *w, const char *arg) {
auto *v = static_cast<std::vector<std::string> *>(w->userdata);
v->push_back(std::string(arg));
};
runner(&w)
.then([](struct webview *w) {
webview_eval(w,
R"(document.body.innerHTML = '<div id="foo">Foo</div>';)");
webview_eval(
w,
"window.external.invoke(document.getElementById('foo').innerText)");
})
.wait();
assert(results.size() == 1);
assert(results[0] == "Foo");
}
static void test_inject_css() {
struct webview w = {};
std::vector<std::string> results;
std::cout << "TEST: inject CSS" << std::endl;
w.width = 480;
w.height = 320;
w.userdata = static_cast<void *>(&results);
w.external_invoke_cb = [](struct webview *w, const char *arg) {
auto *v = static_cast<std::vector<std::string> *>(w->userdata);
v->push_back(std::string(arg));
};
runner(&w)
.then([](struct webview *w) {
webview_inject_css(w, "#app { margin-left: 4px; }");
webview_eval(w, "window.external.invoke(getComputedStyle(document."
"getElementById('app')).marginLeft)");
})
.wait();
assert(results.size() == 1);
assert(results[0] == "4px");
}
int main() {
test_minimal();
test_window_size();
test_inject_js();
test_inject_css();
return 0;
}
-2
View File
@@ -1,2 +0,0 @@
# github.com/zserge/webview v0.0.0-20190123072648-16c93bcaeaeb
github.com/zserge/webview