diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1a3e34c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+.vscode/settings.json
+build/
+dist/
+__pycache__
+*.pyc
+*.egg-info
+*.dist-info
+*.pyd
+*.so
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..5a6a3f3
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "webview"]
+ path = webview
+ url = https://github.com/webview/webview
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..0059440
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,19 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "WebView: Test",
+ "type": "python",
+ "request": "launch",
+ "program": "${workspaceFolder}/test.py",
+ "args": [
+ "${file}"
+ ],
+ "console": "integratedTerminal",
+ "justMyCode": true
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/make_settings_json.py b/.vscode/make_settings_json.py
new file mode 100644
index 0000000..86b1a35
--- /dev/null
+++ b/.vscode/make_settings_json.py
@@ -0,0 +1,16 @@
+#!/usr/bin/python3
+import os
+import platform
+import string
+import sys
+import sysconfig
+
+webview_platform = {'Linux': 'GTK', 'Darwin': 'COCOA', 'Windows': 'WINAPI'}.get(platform.system(), 'GTK')
+python_include_dir = sysconfig.get_path('include').replace('\\', '\\\\')
+py_major_version = sys.version_info[0]
+
+with open('settings.json.template') as f:
+ settings = string.Template(f.read()).safe_substitute(locals())
+
+with open('settings.json', 'w') as f:
+ f.write(settings)
diff --git a/.vscode/settings.json.template b/.vscode/settings.json.template
new file mode 100644
index 0000000..6e36431
--- /dev/null
+++ b/.vscode/settings.json.template
@@ -0,0 +1,9 @@
+{
+ "C_Cpp.default.defines": [
+ "PY_MAJOR_VERSION=${py_major_version}",
+ "WEBVIEW_${webview_platform}"
+ ],
+ "C_Cpp.default.includePath": [
+ "${python_include_dir}"
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..6c6c120
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,61 @@
+{
+ // See https://go.microsoft.com/fwlink/?LinkId=733558
+ // for the documentation about the tasks.json format
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "Build",
+ "type": "shell",
+ "options": {
+ "cwd": "${workspaceFolder}"
+ },
+ "command": "${config:python.pythonPath} setup.py build_ext -f --inplace",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ },
+ "problemMatcher": [
+ "$msCompile",
+ "$gcc"
+ ]
+ },
+ {
+ "label": "Build distributables",
+ "type": "shell",
+ "options": {
+ "cwd": "${workspaceFolder}"
+ },
+ "command": "${config:python.pythonPath} setup.py sdist bdist_wheel",
+ "group": "build",
+ "problemMatcher": []
+ },
+ {
+ "label": "Test",
+ "type": "shell",
+ "options": {
+ "cwd": "${workspaceFolder}"
+ },
+ "command": "${config:python.pythonPath} test.py",
+ "group": {
+ "kind": "test",
+ "isDefault": true
+ },
+ "problemMatcher": []
+ },
+ {
+ "label": "Create settings.json",
+ "type": "shell",
+ "command": "${config:python.pythonPath}",
+ "args": [
+ "make_settings_json.py"
+ ],
+ "options": {
+ "cwd": "${workspaceFolder}/.vscode"
+ },
+ "runOptions": {
+ "runOn": "folderOpen"
+ },
+ "problemMatcher": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/MANIFEST.in b/MANIFEST.in
index db6bb26..ffd87cf 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1 +1 @@
-graft webview
+graft webview
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d91d155
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,27 @@
+ifeq ($(OS),Windows_NT)
+ PY = python
+else
+ PY = python3
+endif
+
+all: dist
+
+build:
+ $(PY) setup.py build
+
+dist:
+ $(PY) setup.py sdist bdist_wheel
+
+install:
+ $(PY) -m pip install .
+
+test:
+ $(PY) test.py
+
+upload:
+ $(PY) -m twine upload dist/*
+
+clean:
+ $(RM) -r build dist *.egg-info *.dist-info __pycache__ *.pyc *.pyd *.so
+
+.PHONY: all build dist install test upload clean
diff --git a/README.md b/README.md
index 6062a8c..e1441c1 100644
--- a/README.md
+++ b/README.md
@@ -1,72 +1,10 @@
-# webview
+# webview-python
-Python extension that provides API for the [webview] library.
+Python extension that provides API for the [webview](https://github.com/webview/webview) library.
-## Getting started
-Install the bindings:
+## TODO
-```bash
-pip install webview
-```
-
-Try the following example:
-
-```python
-import webview
-
-w = webview.WebView(width=320, height=240, title="Hello", url="https://google.com", resizable=True, debug=False)
-w.run()
-```
-
-You may use most of the webview APIs:
-
-```python
-# Change window title
-w.set_title("New title")
-# Make window fullscreen
-w.set_fullscreen(True)
-# Change initial window background color
-w.set_color(255, 0, 0)
-# Inject some JS
-w.eval("alert('hello')")
-# Inject some CSS
-w.inject_css('* {background-color: yellow; }')
-# Show native OS dialog
-file_path = w.dialog(0, 0, "open file", "")
-# Post funciton to the UI thread
-w.dispatch(some_func)
-w.dispatch(lambda: some_func())
-# Control run loop
-while w.loop(True):
- pass
-```
-
-Dispatch is currently only a stub and is implemented as direct function call.
-Also, proper Python-to-JS object mapping is not implemented yet, but is highly
-
-## Development
-
-To build and install the library locally:
-
-```bash
-python setup.py install
-```
-
-To upload a new version:
-
-```bash
-python setup.py sdist
-twine upload dist/webview-*.tar.gz
-```
-
-To build and install it locally:
-
-```bash
-python setup.py install
-```
-
-Please, ensure that all sources are formatted using `yapf`.
-
-
-[webview]: https://github.com/zserge/webview
+- [ ] Figure out why `examples/with_server.py` doesn't work
+- [ ] Better function binding support (automate `json.dumps` and `json.loads`)
+- [ ] Remove support for Python 2.x
diff --git a/examples/minimal.py b/examples/minimal.py
new file mode 100644
index 0000000..f52bf88
--- /dev/null
+++ b/examples/minimal.py
@@ -0,0 +1,43 @@
+import json
+import time
+from urllib.parse import quote
+
+import webview
+
+
+HTML = '''
+This is a test
+
Time should tick here
+
+
+'''
+
+
+def get_time(w, req):
+ fmt = json.loads(req)[0]
+ return json.dumps(time.strftime(fmt))
+
+
+def quit(w, req):
+ w.terminate()
+
+
+def main():
+ w = webview.WebView(width=320, height=240, resizable=True, title="My App", debug=True)
+ w.bind('get_time', get_time)
+ w.bind('quit', quit)
+ w.navigate('data:text/html,' + quote(HTML))
+ w.run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/with_server.py b/examples/with_server.py
new file mode 100644
index 0000000..7a2865a
--- /dev/null
+++ b/examples/with_server.py
@@ -0,0 +1,71 @@
+import json
+import random
+import threading
+import time
+from http import HTTPStatus
+from http.server import BaseHTTPRequestHandler, HTTPServer
+from urllib.parse import quote
+from itertools import count
+
+import webview
+
+
+HTML = '''
+This is a test
+'''
+
+
+class MyHTTPRequestHandler(BaseHTTPRequestHandler):
+ def send_data(self, data, status=HTTPStatus.OK, mimetype='text/plain'):
+ if isinstance(data, str):
+ data = data.encode('utf8')
+ self.send_response(status)
+ self.send_header('Content-Type', mimetype)
+ self.send_header('Content-Length', len(data))
+ self.end_headers()
+ self.wfile.write(data)
+
+ def send_html(self, text):
+ self.send_data(text.encode('utf8'), mimetype='text/html')
+
+ def do_GET(self):
+ self.send_html(HTML)
+
+
+def run_server():
+ while 1:
+ port = random.randint(20000, 30000)
+ try:
+ server = HTTPServer(('localhost', port), MyHTTPRequestHandler)
+ except Exception:
+ continue
+ break
+ threading.Thread(target=server.serve_forever, daemon=True).start()
+ return server
+
+
+def callback(w, req):
+ # print(f'callback was called with {req!r}')
+ arg = json.loads(req)[0]
+ print(f'callback was called with {arg!r}')
+
+
+def threadfunc():
+ for n in count():
+ print(n)
+ time.sleep(0.1)
+
+
+def main():
+ s = run_server()
+ url = f'http://127.0.0.1:{s.server_port}'
+ print(url)
+ w = webview.WebView(width=320, height=240, title="My App", resizable=True, debug=True)
+ w.bind('invoke', callback)
+ w.navigate(url)
+ w.run()
+ s.shutdown()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/pywebview.py b/pywebview.py
new file mode 100644
index 0000000..fa00175
--- /dev/null
+++ b/pywebview.py
@@ -0,0 +1,28 @@
+import argparse
+import os
+
+import webview
+
+
+def main():
+ p = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ p.add_argument('url')
+ p.add_argument('-s', '--size', default='800x600', help='Window size in the form x')
+ p.add_argument('-f', '--fixed-size', action='store_true', help='Makes the window non-resizable')
+ p.add_argument('-t', '--title', default='Webview', help='Set the window title')
+ args = p.parse_args()
+
+ try:
+ width, height = map(int, args.size.split('x'))
+ except Exception:
+ p.error('Size must be of the form x')
+
+ if not os.path.exists(args.url) and '://' not in args.url:
+ args.url = 'http://' + args.url
+
+ w = webview.WebView(width, height, resizable=not args.fixed_size, url=args.url, title=args.title)
+ w.run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/setup.py b/setup.py
index 4084d94..cd70f25 100644
--- a/setup.py
+++ b/setup.py
@@ -1,42 +1,36 @@
-#!/bin/env python
-
-import os
+import platform
import subprocess
-import shutil
-from distutils.core import setup
-from distutils.extension import Extension
-from distutils.cmd import Command
+from setuptools import Extension, setup
-if hasattr(os, 'uname'):
- OSNAME = os.uname()[0]
-else:
- OSNAME = 'Windows'
+OSNAME = platform.system()
if OSNAME == 'Linux':
-
def pkgconfig(flags):
return subprocess.check_output(
- 'pkg-config %s gtk+-3.0 webkit2gtk-4.0' % flags,
+ 'pkg-config {} gtk+-3.0 webkit2gtk-4.0'.format(flags),
shell=True,
- stderr=subprocess.STDOUT).decode('utf-8')
+ stderr=subprocess.STDOUT).decode()
define_macros = [("WEBVIEW_GTK", '1')]
extra_cflags = pkgconfig("--cflags").split()
extra_ldflags = pkgconfig("--libs").split()
+
elif OSNAME == 'Darwin':
define_macros = [('WEBVIEW_COCOA', '1')]
- extra_cflags = ""
- extra_ldflags = ['-framework', 'CoreAudio']
+ extra_cflags = ['-std=c++11']
+ extra_ldflags = ['-framework', 'WebKit']
+
elif OSNAME == 'Windows':
define_macros = [('WEBVIEW_WINAPI', '1')]
- extra_cflags = ""
- extra_ldflags = ['-framework', 'CoreAudio']
+ extra_cflags = ['/std:c++17', '/Iwebview', '/Iwebview\\script']
+ extra_ldflags = [R'webview\script\microsoft.web.webview2.1.0.664.37\build\native\x64\WebView2Loader.dll.lib']
+
webview = Extension(
'webview',
- sources=['webview/webview.c'],
+ sources=['webview.cpp'],
define_macros=define_macros,
extra_compile_args=extra_cflags,
extra_link_args=extra_ldflags,
@@ -51,6 +45,31 @@ def pkgconfig(flags):
url='https://github.com/zserge/webview',
keywords=[],
license='MIT',
- classifiers=[],
+ classifiers=[
+ 'Development Status :: 3 - Alpha',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: MIT License',
+ 'Operating System :: MacOS :: MacOS X',
+ 'Operating System :: Microsoft :: Windows',
+ 'Operating System :: POSIX :: Linux',
+ 'Programming Language :: C',
+ 'Programming Language :: Python',
+ 'Topic :: Desktop Environment',
+ 'Topic :: Software Development :: Libraries',
+ 'Topic :: Software Development :: User Interfaces',
+ ],
ext_modules=[webview],
+ py_modules=['pywebview'],
+ entry_points=dict(
+ gui_scripts=[
+ 'pywv = pywebview:main',
+ ],
+ ),
+ extras_require=dict(
+ dev=[
+ 'pip',
+ 'setuptools',
+ 'wheel',
+ ],
+ ),
)
diff --git a/test.py b/test.py
new file mode 100644
index 0000000..5b4edd2
--- /dev/null
+++ b/test.py
@@ -0,0 +1,28 @@
+import os
+import runpy
+import subprocess
+import sys
+
+
+def dirname(path):
+ return os.path.abspath(os.path.dirname(path))
+
+
+def main():
+ base_dir = dirname(__file__)
+
+ # Build the package (if necessary)
+ # subprocess.check_call([sys.executable, 'setup.py', 'build_ext', '--inplace'], cwd=base_dir)
+
+ # Run code
+ if len(sys.argv) > 1:
+ fn = sys.argv[1]
+ else:
+ fn = os.path.join(base_dir, 'examples', 'minimal.py')
+
+ os.chdir(base_dir)
+ runpy.run_path(fn, run_name='__main__')
+
+
+if __name__ == "__main__":
+ main()
diff --git a/webview b/webview
new file mode 160000
index 0000000..7534ef6
--- /dev/null
+++ b/webview
@@ -0,0 +1 @@
+Subproject commit 7534ef6e476a1af6206ddb3d0efd3ebf131cba3c
diff --git a/webview.cpp b/webview.cpp
new file mode 100644
index 0000000..0ca5a20
--- /dev/null
+++ b/webview.cpp
@@ -0,0 +1,331 @@
+#include
+#include "structmember.h"
+#include "webview/webview.h"
+
+#ifndef PATH_MAX
+#define PATH_MAX MAX_PATH
+#endif
+
+typedef struct {
+ PyObject_HEAD
+ webview_t w;
+ PyObject *bindings;
+} WebView;
+
+static void WebView_dealloc(WebView *self) {
+ webview_destroy(self->w);
+ PyDict_Clear(self->bindings); // TODO: What about refcounts for keys and values?
+ Py_DECREF(self->bindings);
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+static PyObject *WebView_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ PyObject *bindings = PyDict_New(); // TODO: Should we call Py_INCREF(bindings)?
+ if (bindings == NULL) return NULL;
+
+ WebView *self = (WebView *)type->tp_alloc(type, 0);
+ if (self == NULL) return NULL;
+
+ self->bindings = bindings;
+
+ return (PyObject *)self;
+}
+
+static int WebView_init(WebView *self, PyObject *args, PyObject *kwds) {
+ int width = 0;
+ int height = 0;
+ int resizable = 1;
+ int debug = 0;
+ char *title = NULL;
+ char *kwlist[] = {"width", "height", "resizable", "debug", "title", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iiiis:WebView", kwlist, &width, &height, &resizable, &debug, &title)) {
+ return -1;
+ }
+
+ // printf("size=%dx%d, resizable=%d, debug=%d, title=\"%s\"\n", width, height, resizable, debug, title);
+
+ self->w = webview_create(debug, NULL);
+
+ if (title) {
+ webview_set_title(self->w, title);
+ }
+
+ if ((width && height) || !resizable) {
+ webview_set_size(self->w, width, height, resizable ? WEBVIEW_HINT_NONE: WEBVIEW_HINT_FIXED);
+ }
+
+ return 0;
+}
+
+static PyObject *WebView_run(WebView *self) {
+ // Py_BEGIN_ALLOW_THREADS
+ webview_run(self->w);
+ // Py_END_ALLOW_THREADS
+ Py_RETURN_NONE;
+}
+
+static PyObject *WebView_terminate(WebView *self) {
+ webview_terminate(self->w);
+ Py_RETURN_NONE;
+}
+
+static PyObject *WebView_set_title(WebView *self, PyObject *args) {
+ char *title = NULL;
+ if (!PyArg_ParseTuple(args, "s:set_title", &title)) {
+ return NULL;
+ }
+ webview_set_title(self->w, title);
+ Py_RETURN_NONE;
+}
+
+static PyObject *WebView_set_size(WebView *self, PyObject *args) {
+ int width = 0;
+ int height = 0;
+ int hint = WEBVIEW_HINT_NONE;
+
+ if (!PyArg_ParseTuple(args, "iii:set_size", &width, &height, &hint)) {
+ return NULL;
+ }
+
+ webview_set_size(self->w, width, height, hint);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *WebView_navigate(WebView *self, PyObject *args) {
+ const char *url;
+
+ if (!PyArg_ParseTuple(args, "s:navigate", &url)) {
+ return NULL;
+ }
+
+ webview_navigate(self->w, url);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *WebView_init_js(WebView *self, PyObject *args) {
+ const char *js = NULL;
+
+ if (!PyArg_ParseTuple(args, "s:init", &js)) {
+ return NULL;
+ }
+
+ webview_init(self->w, js);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *WebView_eval(WebView *self, PyObject *args) {
+ const char *js = NULL;
+
+ if (!PyArg_ParseTuple(args, "s:eval", &js)) {
+ return NULL;
+ }
+
+ webview_eval(self->w, js);
+
+ Py_RETURN_NONE;
+}
+
+static void webview_bind_cb(const char *seq, const char *req, void *binding) {
+ WebView *self = (WebView *)PyTuple_GetItem((PyObject *)binding, 0);
+ PyObject *name = PyTuple_GetItem((PyObject *)binding, 1);
+ PyObject *func = PyTuple_GetItem((PyObject *)binding, 2);
+
+ // printf("Calling %s(%s)\n", PyUnicode_AsUTF8(name), req);
+
+ PyObject *ret = PyObject_CallFunction(func, "Os", self, req);
+ if (!ret) {
+ webview_return(self->w, seq, 1, NULL); // TODO: Return error JSON
+ PyErr_Print();
+ return;
+ }
+
+ PyObject *str = PyObject_Str(ret);
+ Py_DECREF(ret);
+ if (!str) {
+ webview_return(self->w, seq, 1, NULL); // TODO: Return error JSON
+ PyErr_Print();
+ return;
+ }
+
+ // printf("Returning %s\n", PyUnicode_AsUTF8(str));
+ webview_return(self->w, seq, 0, PyUnicode_AsUTF8(str));
+
+ Py_DECREF(str);
+}
+
+static PyObject *WebView_bind(WebView *self, PyObject *args) {
+ PyObject *name, *func, *tuple;
+
+ if (!PyArg_ParseTuple(args, "OO:bind", &name, &func)) { // TODO: What about ref-counts?
+ return NULL;
+ }
+
+ // printf("Got name=%s func=%s\n", PyUnicode_AsUTF8(PyObject_ASCII(name)), PyUnicode_AsUTF8(PyObject_ASCII(func)));
+
+ if (!PyUnicode_Check(name)) {
+ PyErr_SetString(PyExc_TypeError, "name must be unicode");
+ return NULL;
+ }
+
+ if (!PyCallable_Check(func)) {
+ PyErr_SetString(PyExc_TypeError, "func must be callable");
+ return NULL;
+ }
+
+ if (PyDict_Contains(self->bindings, name)) {
+ PyErr_SetString(PyExc_ValueError, "name already exists");
+ return NULL;
+ }
+
+ tuple = PyTuple_Pack(3, self, name, func);
+ if (tuple == NULL) {
+ PyErr_SetString(PyExc_MemoryError, "Could not allocate binding tuple");
+ return NULL;
+ }
+
+ PyDict_SetItem(self->bindings, name, tuple);
+
+ // printf("Bindings: %s\n", PyUnicode_AsUTF8(PyObject_ASCII(self->bindings)));
+
+ webview_bind(self->w, PyUnicode_AsUTF8(name), webview_bind_cb, tuple);
+
+ Py_RETURN_NONE;
+}
+
+static void webview_dispatch_cb(webview_t w, void *arg) {
+ PyObject_CallObject((PyObject *)arg, NULL);
+}
+
+static PyObject *WebView_dispatch(WebView *self, PyObject *args) {
+ PyObject *func;
+
+ if (!PyArg_ParseTuple(args, "O:dispatch", &func)) {
+ return NULL;
+ }
+
+ if (!PyCallable_Check(func)) {
+ PyErr_SetString(PyExc_TypeError, "parameter must be callable");
+ return NULL;
+ }
+
+ webview_dispatch(self->w, webview_dispatch_cb, func);
+
+ Py_RETURN_NONE;
+}
+
+static PyMemberDef WebView_members[] = {
+ {"bindings", T_OBJECT, offsetof(WebView, bindings), 0, "Debug access to internal bindings"},
+ {NULL} /* Sentinel */
+};
+static PyMethodDef WebView_methods[] = {
+ {"run", (PyCFunction)WebView_run, METH_NOARGS, "WebView.run() -> None"},
+ {"terminate", (PyCFunction)WebView_terminate, METH_NOARGS, "WebView.terminate() -> None"},
+ {"set_title", (PyCFunction)WebView_set_title, METH_VARARGS, "WebView.set_title(title: str) -> None"},
+ {"set_size", (PyCFunction)WebView_set_size, METH_VARARGS, "WebView.set_size(width: Optional[int], height: Optional[int], hints: Optional[int]) -> None"},
+ {"navigate", (PyCFunction)WebView_navigate, METH_VARARGS, "WebView.navigate(url: str) -> None"},
+ {"init", (PyCFunction)WebView_init_js, METH_VARARGS, "WebView.init(js: str) -> None"},
+ {"eval", (PyCFunction)WebView_eval, METH_VARARGS, "WebView.eval(js: str) -> None"},
+ {"bind", (PyCFunction)WebView_bind, METH_VARARGS, "WebView.bind(name: str, func: Callable) -> None"},
+ {"dispatch", (PyCFunction)WebView_dispatch, METH_VARARGS, "WebView.dispatch(func: Callable) -> None"},
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject WebViewType = {
+ PyVarObject_HEAD_INIT(NULL, 0) "webview.WebView", /* tp_name */
+ sizeof(WebView), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)WebView_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ "webview.WebView("
+ "width: int, height: int, "
+ "resizable: bool = False, "
+ "debug: bool = False, "
+ "title: str = '')", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ WebView_methods, /* tp_methods */
+ WebView_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)WebView_init, /* tp_init */
+ 0, /* tp_alloc */
+ WebView_new, /* tp_new */
+};
+
+static PyMethodDef module_methods[] = {
+ {NULL} /* Sentinel */
+};
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "webview",
+ "Python bindings for the WebView C library.",
+ 0,
+ module_methods,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+#define MODINIT_ERROR NULL
+#define MODINIT_NAME PyInit_webview
+#else
+#define MODINIT_ERROR
+#define MODINIT_NAME initwebview
+#endif
+PyMODINIT_FUNC MODINIT_NAME(void) {
+ PyObject *m;
+
+ if (PyType_Ready(&WebViewType) < 0) {
+ return MODINIT_ERROR;
+ }
+
+#if PY_MAJOR_VERSION >= 3
+ m = PyModule_Create(&moduledef);
+#else
+ m = Py_InitModule3("webview", module_methods, "Python bindings for the WebView C library.");
+#endif
+
+ if (m == NULL) {
+ return MODINIT_ERROR;
+ }
+
+ Py_INCREF(&WebViewType);
+ PyModule_AddObject(m, "WebView", (PyObject *)&WebViewType);
+
+ PyModule_AddIntConstant(m, "SIZE_HINT_NONE", WEBVIEW_HINT_NONE);
+ PyModule_AddIntConstant(m, "SIZE_HINT_MIN", WEBVIEW_HINT_MIN);
+ PyModule_AddIntConstant(m, "SIZE_HINT_MAX", WEBVIEW_HINT_MAX);
+ PyModule_AddIntConstant(m, "SIZE_HINT_FIXED", WEBVIEW_HINT_FIXED);
+
+#if PY_MAJOR_VERSION >= 3
+ return m;
+#endif
+}
diff --git a/webview/webview.c b/webview/webview.c
deleted file mode 100644
index 8ae7244..0000000
--- a/webview/webview.c
+++ /dev/null
@@ -1,256 +0,0 @@
-#include
-
-#include "structmember.h"
-
-#define WEBVIEW_IMPLEMENTATION
-#include "webview.h"
-
-typedef struct { PyObject_HEAD struct webview w; } WebView;
-
-static void WebView_dealloc(WebView *self) {
- webview_exit(&self->w);
- Py_TYPE(self)->tp_free((PyObject *)self);
-}
-
-static PyObject *WebView_new(PyTypeObject *type, PyObject *args,
- PyObject *kwds) {
- WebView *self = (WebView *)type->tp_alloc(type, 0);
- if (self == NULL) {
- return NULL;
- }
- memset(&self->w, 0, sizeof(self->w));
- return (PyObject *)self;
-}
-
-static int WebView_init(WebView *self, PyObject *args, PyObject *kwds) {
- const char *url = NULL;
- const char *title = NULL;
- static char *kwlist[] = {"width", "height", "resizable", "debug",
- "url", "title", NULL};
-
- if (!PyArg_ParseTupleAndKeywords(
- args, kwds, "ii|iiss", kwlist, &self->w.width, &self->w.height,
- &self->w.resizable, &self->w.debug, &url, &title)) {
- return -1;
- }
-
- self->w.url = url;
- self->w.title = title;
-
- return webview_init(&self->w);
-}
-
-static PyObject *WebView_run(WebView *self) {
- while (webview_loop(&self->w, 1) == 0)
- ;
- Py_RETURN_NONE;
-}
-
-static PyObject *WebView_loop(WebView *self, PyObject *args, PyObject *kwds) {
- int blocking = 1;
- static char *kwlist[] = {"blocking", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &blocking)) {
- return NULL;
- }
- if (webview_loop(&self->w, blocking) == 0) {
- Py_RETURN_TRUE;
- } else {
- Py_RETURN_FALSE;
- }
-}
-
-static PyObject *WebView_terminate(WebView *self) {
- webview_terminate(&self->w);
- Py_RETURN_NONE;
-}
-
-static PyObject *WebView_set_title(WebView *self, PyObject *args) {
- const char *title = "";
- if (!PyArg_ParseTuple(args, "s", &title)) {
- return NULL;
- }
- webview_set_title(&self->w, title);
- Py_RETURN_NONE;
-}
-
-static PyObject *WebView_set_fullscreen(WebView *self, PyObject *args) {
- int fullscreen = 0;
- if (!PyArg_ParseTuple(args, "i", &fullscreen)) {
- return NULL;
- }
- webview_set_fullscreen(&self->w, fullscreen);
- Py_RETURN_NONE;
-}
-
-static PyObject *WebView_set_color(WebView *self, PyObject *args) {
- int r, g, b, a = 255;
- if (!PyArg_ParseTuple(args, "iii|i", &r, &g, &b, &a)) {
- return NULL;
- }
- webview_set_color(&self->w, r, g, b, a);
- Py_RETURN_NONE;
-}
-
-static PyObject *WebView_eval(WebView *self, PyObject *args) {
- const char *js = NULL;
- if (!PyArg_ParseTuple(args, "s", &js)) {
- return NULL;
- }
- webview_eval(&self->w, js);
- Py_RETURN_NONE;
-}
-
-static PyObject *WebView_inject_css(WebView *self, PyObject *args) {
- const char *css = NULL;
- if (!PyArg_ParseTuple(args, "s", &css)) {
- return NULL;
- }
- webview_inject_css(&self->w, css);
- Py_RETURN_NONE;
-}
-
-static PyObject *WebView_dialog(WebView *self, PyObject *args, PyObject *kwds) {
- int type = 0;
- int flags = 0;
- const char *title = NULL;
- const char *arg = NULL;
- char result[PATH_MAX];
- static char *kwlist[] = {"type", "flags", "title", "arg", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "iiss", kwlist, &type, &flags,
- &title, &arg)) {
- return NULL;
- }
- webview_dialog(&self->w, type, flags, title, arg, result, sizeof(result));
- return PyUnicode_FromString(result);
-}
-
-static void webview_dispatch_cb(struct webview *w, void *arg) {
- PyObject *cb = (PyObject *)arg;
- /* TODO */
- PyObject_CallObject(cb, NULL);
- Py_XINCREF(cb);
-}
-
-static PyObject *WebView_dispatch(WebView *self, PyObject *args) {
- PyObject *tmp;
- if (!PyArg_ParseTuple(args, "O:set_callback", &tmp)) {
- return NULL;
- }
- if (!PyCallable_Check(tmp)) {
- PyErr_SetString(PyExc_TypeError, "parameter must be callable");
- return NULL;
- }
- Py_XINCREF(tmp);
- webview_dispatch(&self->w, webview_dispatch_cb, tmp);
- Py_RETURN_NONE;
-}
-
-static PyObject *WebView_bind(WebView *self) {
- /* TODO, very complex implementation */
- Py_RETURN_NONE;
-}
-
-static PyMemberDef WebView_members[] = {
- {NULL} /* Sentinel */
-};
-static PyMethodDef WebView_methods[] = {
- {"run", (PyCFunction)WebView_run, METH_NOARGS, "..."},
- {"loop", (PyCFunction)WebView_loop, METH_KEYWORDS | METH_VARARGS, "..."},
- {"terminate", (PyCFunction)WebView_terminate, METH_NOARGS, "..."},
- {"dispatch", (PyCFunction)WebView_dispatch, METH_VARARGS, "..."},
- {"eval", (PyCFunction)WebView_eval, METH_VARARGS, "..."},
- {"inject_css", (PyCFunction)WebView_inject_css, METH_VARARGS, "..."},
- {"dialog", (PyCFunction)WebView_dialog, METH_KEYWORDS | METH_VARARGS, "..."},
- {"set_title", (PyCFunction)WebView_set_title, METH_VARARGS, "..."},
- {"set_fullscreen", (PyCFunction)WebView_set_fullscreen, METH_VARARGS,
- "..."},
- {"set_color", (PyCFunction)WebView_set_color, METH_VARARGS, "..."},
- {"bind", (PyCFunction)WebView_bind, METH_VARARGS, "..."},
- {NULL} /* Sentinel */
-};
-
-static PyTypeObject WebViewType = {
- PyVarObject_HEAD_INIT(NULL, 0) "webview.WebView", /* tp_name */
- sizeof(WebView), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor)WebView_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- "WebView objects", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- WebView_methods, /* tp_methods */
- WebView_members, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)WebView_init, /* tp_init */
- 0, /* tp_alloc */
- WebView_new, /* tp_new */
-};
-
-static PyMethodDef module_methods[] = {
- {NULL} /* Sentinel */
-};
-
-#if PY_MAJOR_VERSION >= 3
-static struct PyModuleDef moduledef = {
- PyModuleDef_HEAD_INIT,
- "webview",
- "Example module",
- 0,
- module_methods,
- NULL,
- NULL,
- NULL,
- NULL
-};
-#define MODINIT_ERROR NULL
-#define MODINIT_NAME PyInit_webview
-#else
-#define MODINIT_ERROR
-#define MODINIT_NAME initwebview
-#endif
-PyMODINIT_FUNC MODINIT_NAME(void) {
- PyObject *m;
-
- if (PyType_Ready(&WebViewType) < 0) {
- return MODINIT_ERROR;
- }
-
-#if PY_MAJOR_VERSION >= 3
- m = PyModule_Create(&moduledef);
-#else
- m = Py_InitModule3("webview", module_methods,
- "Example module that creates an extension type.");
-#endif
- if (m == NULL) {
- return MODINIT_ERROR;
- }
-
- Py_INCREF(&WebViewType);
- PyModule_AddObject(m, "WebView", (PyObject *)&WebViewType);
-#if PY_MAJOR_VERSION >= 3
- return m;
-#endif
-}
diff --git a/webview/webview.h b/webview/webview.h
deleted file mode 100644
index d1d2a1c..0000000
--- a/webview/webview.h
+++ /dev/null
@@ -1,1890 +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.
- */
-#ifndef WEBVIEW_H
-#define WEBVIEW_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef WEBVIEW_STATIC
-#define WEBVIEW_API static
-#else
-#define WEBVIEW_API extern
-#endif
-
-#include
-#include
-#include
-
-#if defined(WEBVIEW_GTK)
-#include
-#include
-#include
-
-struct webview_priv {
- GtkWidget *window;
- GtkWidget *scroller;
- GtkWidget *webview;
- GtkWidget *inspector_window;
- GAsyncQueue *queue;
- int ready;
- int js_busy;
- int should_exit;
-};
-#elif defined(WEBVIEW_WINAPI)
-#define CINTERFACE
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-struct webview_priv {
- HWND hwnd;
- IOleObject **browser;
- BOOL is_fullscreen;
- DWORD saved_style;
- DWORD saved_ex_style;
- RECT saved_rect;
-};
-#elif defined(WEBVIEW_COCOA)
-#import
-#import
-#import
-
-struct webview_priv {
- NSAutoreleasePool *pool;
- NSWindow *window;
- WebView *webview;
- id windowDelegate;
- int should_exit;
-};
-#else
-#error "Define one of: WEBVIEW_GTK, WEBVIEW_COCOA or WEBVIEW_WINAPI"
-#endif
-
-struct webview;
-
-typedef void (*webview_external_invoke_cb_t)(struct webview *w,
- const char *arg);
-
-struct webview {
- const char *url;
- const char *title;
- int width;
- int height;
- int resizable;
- int debug;
- webview_external_invoke_cb_t external_invoke_cb;
- struct webview_priv priv;
- void *userdata;
-};
-
-enum webview_dialog_type {
- WEBVIEW_DIALOG_TYPE_OPEN = 0,
- WEBVIEW_DIALOG_TYPE_SAVE = 1,
- WEBVIEW_DIALOG_TYPE_ALERT = 2
-};
-
-#define WEBVIEW_DIALOG_FLAG_FILE (0 << 0)
-#define WEBVIEW_DIALOG_FLAG_DIRECTORY (1 << 0)
-
-#define WEBVIEW_DIALOG_FLAG_INFO (1 << 1)
-#define WEBVIEW_DIALOG_FLAG_WARNING (2 << 1)
-#define WEBVIEW_DIALOG_FLAG_ERROR (3 << 1)
-#define WEBVIEW_DIALOG_FLAG_ALERT_MASK (3 << 1)
-
-typedef void (*webview_dispatch_fn)(struct webview *w, void *arg);
-
-struct webview_dispatch_arg {
- webview_dispatch_fn fn;
- struct webview *w;
- void *arg;
-};
-
-#define DEFAULT_URL \
- "data:text/" \
- "html,%3C%21DOCTYPE%20html%3E%0A%3Chtml%20lang=%22en%22%3E%0A%3Chead%3E%" \
- "3Cmeta%20charset=%22utf-8%22%3E%3Cmeta%20http-equiv=%22X-UA-Compatible%22%" \
- "20content=%22IE=edge%22%3E%3C%2Fhead%3E%0A%3Cbody%3E%3Cdiv%20id=%22app%22%" \
- "3E%3C%2Fdiv%3E%3Cscript%20type=%22text%2Fjavascript%22%3E%3C%2Fscript%3E%" \
- "3C%2Fbody%3E%0A%3C%2Fhtml%3E"
-
-#define CSS_INJECT_FUNCTION \
- "(function(e){var " \
- "t=document.createElement('style'),d=document.head||document." \
- "getElementsByTagName('head')[0];t.setAttribute('type','text/" \
- "css'),t.styleSheet?t.styleSheet.cssText=e:t.appendChild(document." \
- "createTextNode(e)),d.appendChild(t)})"
-
-static const char *webview_check_url(const char *url) {
- if (url == NULL || strlen(url) == 0) {
- return DEFAULT_URL;
- }
- return url;
-}
-
-WEBVIEW_API int webview(const char *title, const char *url, int width,
- int height, int resizable);
-
-WEBVIEW_API int webview_init(struct webview *w);
-WEBVIEW_API int webview_loop(struct webview *w, int blocking);
-WEBVIEW_API int webview_eval(struct webview *w, const char *js);
-WEBVIEW_API int webview_inject_css(struct webview *w, const char *css);
-WEBVIEW_API void webview_set_title(struct webview *w, const char *title);
-WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen);
-WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
- uint8_t b, uint8_t a);
-WEBVIEW_API void webview_dialog(struct webview *w,
- enum webview_dialog_type dlgtype, int flags,
- const char *title, const char *arg,
- char *result, size_t resultsz);
-WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
- void *arg);
-WEBVIEW_API void webview_terminate(struct webview *w);
-WEBVIEW_API void webview_exit(struct webview *w);
-WEBVIEW_API void webview_debug(const char *format, ...);
-WEBVIEW_API void webview_print_log(const char *s);
-
-#ifdef WEBVIEW_IMPLEMENTATION
-#undef WEBVIEW_IMPLEMENTATION
-
-WEBVIEW_API int webview(const char *title, const char *url, int width,
- int height, int resizable) {
- struct webview webview;
- memset(&webview, 0, sizeof(webview));
- webview.title = title;
- webview.url = url;
- webview.width = width;
- webview.height = height;
- webview.resizable = resizable;
- int r = webview_init(&webview);
- if (r != 0) {
- return r;
- }
- while (webview_loop(&webview, 1) == 0) {
- }
- webview_exit(&webview);
- return 0;
-}
-
-WEBVIEW_API void webview_debug(const char *format, ...) {
- char buf[4096];
- va_list ap;
- va_start(ap, format);
- vsnprintf(buf, sizeof(buf), format, ap);
- webview_print_log(buf);
- va_end(ap);
-}
-
-static int webview_js_encode(const char *s, char *esc, size_t n) {
- int r = 1; /* At least one byte for trailing zero */
- for (; *s; s++) {
- const unsigned char c = *s;
- if (c >= 0x20 && c < 0x80 && strchr("<>\\'\"", c) == NULL) {
- if (n > 0) {
- *esc++ = c;
- n--;
- }
- r++;
- } else {
- if (n > 0) {
- snprintf(esc, n, "\\x%02x", (int)c);
- esc += 4;
- n -= 4;
- }
- r += 4;
- }
- }
- return r;
-}
-
-WEBVIEW_API int webview_inject_css(struct webview *w, const char *css) {
- int n = webview_js_encode(css, NULL, 0);
- char *esc = (char *)calloc(1, sizeof(CSS_INJECT_FUNCTION) + n + 4);
- if (esc == NULL) {
- return -1;
- }
- char *js = (char *)calloc(1, n);
- webview_js_encode(css, js, n);
- snprintf(esc, sizeof(CSS_INJECT_FUNCTION) + n + 4, "%s(\"%s\")",
- CSS_INJECT_FUNCTION, js);
- int r = webview_eval(w, esc);
- free(js);
- free(esc);
- return r;
-}
-
-#if defined(WEBVIEW_GTK)
-static void external_message_received_cb(WebKitUserContentManager *m,
- WebKitJavascriptResult *r,
- gpointer arg) {
- (void)m;
- struct webview *w = (struct webview *)arg;
- if (w->external_invoke_cb == NULL) {
- return;
- }
- JSGlobalContextRef context = webkit_javascript_result_get_global_context(r);
- JSValueRef value = webkit_javascript_result_get_value(r);
- JSStringRef js = JSValueToStringCopy(context, value, NULL);
- size_t n = JSStringGetMaximumUTF8CStringSize(js);
- char *s = g_new(char, n);
- JSStringGetUTF8CString(js, s, n);
- w->external_invoke_cb(w, s);
- JSStringRelease(js);
- g_free(s);
-}
-
-static void webview_load_changed_cb(WebKitWebView *webview,
- WebKitLoadEvent event, gpointer arg) {
- (void)webview;
- struct webview *w = (struct webview *)arg;
- if (event == WEBKIT_LOAD_FINISHED) {
- w->priv.ready = 1;
- }
-}
-
-static void webview_destroy_cb(GtkWidget *widget, gpointer arg) {
- (void)widget;
- struct webview *w = (struct webview *)arg;
- webview_terminate(w);
-}
-
-static gboolean webview_context_menu_cb(WebKitWebView *webview,
- GtkWidget *default_menu,
- WebKitHitTestResult *hit_test_result,
- gboolean triggered_with_keyboard,
- gpointer userdata) {
- (void)webview;
- (void)default_menu;
- (void)hit_test_result;
- (void)triggered_with_keyboard;
- (void)userdata;
- return TRUE;
-}
-
-WEBVIEW_API int webview_init(struct webview *w) {
- if (gtk_init_check(0, NULL) == FALSE) {
- return -1;
- }
-
- w->priv.ready = 0;
- w->priv.should_exit = 0;
- w->priv.queue = g_async_queue_new();
- w->priv.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title(GTK_WINDOW(w->priv.window), w->title);
-
- if (w->resizable) {
- gtk_window_set_default_size(GTK_WINDOW(w->priv.window), w->width,
- w->height);
- } else {
- gtk_widget_set_size_request(w->priv.window, w->width, w->height);
- }
- gtk_window_set_resizable(GTK_WINDOW(w->priv.window), !!w->resizable);
- gtk_window_set_position(GTK_WINDOW(w->priv.window), GTK_WIN_POS_CENTER);
-
- w->priv.scroller = gtk_scrolled_window_new(NULL, NULL);
- gtk_container_add(GTK_CONTAINER(w->priv.window), w->priv.scroller);
-
- WebKitUserContentManager *m = webkit_user_content_manager_new();
- webkit_user_content_manager_register_script_message_handler(m, "external");
- g_signal_connect(m, "script-message-received::external",
- G_CALLBACK(external_message_received_cb), w);
-
- w->priv.webview = webkit_web_view_new_with_user_content_manager(m);
- webkit_web_view_load_uri(WEBKIT_WEB_VIEW(w->priv.webview),
- webview_check_url(w->url));
- g_signal_connect(G_OBJECT(w->priv.webview), "load-changed",
- G_CALLBACK(webview_load_changed_cb), w);
- gtk_container_add(GTK_CONTAINER(w->priv.scroller), w->priv.webview);
-
- if (w->debug) {
- WebKitSettings *settings =
- webkit_web_view_get_settings(WEBKIT_WEB_VIEW(w->priv.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(w->priv.webview), "context-menu",
- G_CALLBACK(webview_context_menu_cb), w);
- }
-
- gtk_widget_show_all(w->priv.window);
-
- webkit_web_view_run_javascript(
- WEBKIT_WEB_VIEW(w->priv.webview),
- "window.external={invoke:function(x){"
- "window.webkit.messageHandlers.external.postMessage(x);}}",
- NULL, NULL, NULL);
-
- g_signal_connect(G_OBJECT(w->priv.window), "destroy",
- G_CALLBACK(webview_destroy_cb), w);
- return 0;
-}
-
-WEBVIEW_API int webview_loop(struct webview *w, int blocking) {
- gtk_main_iteration_do(blocking);
- return w->priv.should_exit;
-}
-
-WEBVIEW_API void webview_set_title(struct webview *w, const char *title) {
- gtk_window_set_title(GTK_WINDOW(w->priv.window), title);
-}
-
-WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) {
- if (fullscreen) {
- gtk_window_fullscreen(GTK_WINDOW(w->priv.window));
- } else {
- gtk_window_unfullscreen(GTK_WINDOW(w->priv.window));
- }
-}
-
-WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
- uint8_t b, uint8_t a) {
- GdkRGBA color = {r / 255.0, g / 255.0, b / 255.0, a / 255.0};
- webkit_web_view_set_background_color(WEBKIT_WEB_VIEW(w->priv.webview),
- &color);
-}
-
-WEBVIEW_API void webview_dialog(struct webview *w,
- enum webview_dialog_type dlgtype, int flags,
- const char *title, const char *arg,
- char *result, size_t resultsz) {
- GtkWidget *dlg;
- if (result != NULL) {
- result[0] = '\0';
- }
- if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
- dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) {
- dlg = gtk_file_chooser_dialog_new(
- title, GTK_WINDOW(w->priv.window),
- (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN
- ? (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY
- ? GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
- : GTK_FILE_CHOOSER_ACTION_OPEN)
- : GTK_FILE_CHOOSER_ACTION_SAVE),
- "_Cancel", GTK_RESPONSE_CANCEL,
- (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ? "_Open" : "_Save"),
- GTK_RESPONSE_ACCEPT, NULL);
- gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg), FALSE);
- gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dlg), FALSE);
- gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dlg), TRUE);
- gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dlg), TRUE);
- gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dlg), TRUE);
- gint response = gtk_dialog_run(GTK_DIALOG(dlg));
- if (response == GTK_RESPONSE_ACCEPT) {
- gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg));
- g_strlcpy(result, filename, resultsz);
- g_free(filename);
- }
- gtk_widget_destroy(dlg);
- } else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) {
- GtkMessageType type = GTK_MESSAGE_OTHER;
- switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) {
- case WEBVIEW_DIALOG_FLAG_INFO:
- type = GTK_MESSAGE_INFO;
- break;
- case WEBVIEW_DIALOG_FLAG_WARNING:
- type = GTK_MESSAGE_WARNING;
- break;
- case WEBVIEW_DIALOG_FLAG_ERROR:
- type = GTK_MESSAGE_ERROR;
- break;
- }
- dlg = gtk_message_dialog_new(GTK_WINDOW(w->priv.window), GTK_DIALOG_MODAL,
- type, GTK_BUTTONS_OK, "%s", title);
- gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dlg), "%s",
- arg);
- gtk_dialog_run(GTK_DIALOG(dlg));
- gtk_widget_destroy(dlg);
- }
-}
-
-static void webview_eval_finished(GObject *object, GAsyncResult *result,
- gpointer userdata) {
- (void) object;
- (void) result;
- struct webview *w = (struct webview *)userdata;
- w->priv.js_busy = 0;
-}
-
-WEBVIEW_API int webview_eval(struct webview *w, const char *js) {
- while (w->priv.ready == 0) {
- g_main_context_iteration(NULL, TRUE);
- }
- w->priv.js_busy = 1;
- webkit_web_view_run_javascript(WEBKIT_WEB_VIEW(w->priv.webview), js, NULL,
- webview_eval_finished, w);
- while (w->priv.js_busy) {
- g_main_context_iteration(NULL, TRUE);
- }
- return 0;
-}
-
-static gboolean webview_dispatch_wrapper(gpointer userdata) {
- struct webview *w = (struct webview *)userdata;
- for (;;) {
- struct webview_dispatch_arg *arg =
- (struct webview_dispatch_arg *)g_async_queue_try_pop(w->priv.queue);
- if (arg == NULL) {
- break;
- }
- (arg->fn)(w, arg->arg);
- g_free(arg);
- }
- return FALSE;
-}
-
-WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
- void *arg) {
- struct webview_dispatch_arg *context =
- (struct webview_dispatch_arg *)g_new(struct webview_dispatch_arg, 1);
- context->w = w;
- context->arg = arg;
- context->fn = fn;
- g_async_queue_lock(w->priv.queue);
- g_async_queue_push_unlocked(w->priv.queue, context);
- if (g_async_queue_length_unlocked(w->priv.queue) == 1) {
- gdk_threads_add_idle(webview_dispatch_wrapper, w);
- }
- g_async_queue_unlock(w->priv.queue);
-}
-
-WEBVIEW_API void webview_terminate(struct webview *w) {
- w->priv.should_exit = 1;
-}
-
-WEBVIEW_API void webview_exit(struct webview *w) { (void)w; }
-WEBVIEW_API void webview_print_log(const char *s) {
- fprintf(stderr, "%s\n", s);
-}
-
-#endif /* WEBVIEW_GTK */
-
-#if defined(WEBVIEW_WINAPI)
-
-#pragma comment(lib, "user32.lib")
-#pragma comment(lib, "ole32.lib")
-#pragma comment(lib, "oleaut32.lib")
-
-#define WM_WEBVIEW_DISPATCH (WM_APP + 1)
-
-typedef struct {
- IOleInPlaceFrame frame;
- HWND window;
-} _IOleInPlaceFrameEx;
-
-typedef struct {
- IOleInPlaceSite inplace;
- _IOleInPlaceFrameEx frame;
-} _IOleInPlaceSiteEx;
-
-typedef struct { IDocHostUIHandler ui; } _IDocHostUIHandlerEx;
-
-typedef struct {
- IOleClientSite client;
- _IOleInPlaceSiteEx inplace;
- _IDocHostUIHandlerEx ui;
- IDispatch external;
-} _IOleClientSiteEx;
-
-#ifdef __cplusplus
-#define iid_ref(x) &(x)
-#define iid_unref(x) *(x)
-#else
-#define iid_ref(x) (x)
-#define iid_unref(x) (x)
-#endif
-
-static inline WCHAR *webview_to_utf16(const char *s) {
- DWORD size = MultiByteToWideChar(CP_UTF8, 0, s, -1, 0, 0);
- WCHAR *ws = (WCHAR *)GlobalAlloc(GMEM_FIXED, sizeof(WCHAR) * size);
- if (ws == NULL) {
- return NULL;
- }
- MultiByteToWideChar(CP_UTF8, 0, s, -1, ws, size);
- return ws;
-}
-
-static inline char *webview_from_utf16(WCHAR *ws) {
- int n = WideCharToMultiByte(CP_UTF8, 0, ws, -1, NULL, 0, NULL, NULL);
- char *s = (char *)GlobalAlloc(GMEM_FIXED, n);
- if (s == NULL) {
- return NULL;
- }
- WideCharToMultiByte(CP_UTF8, 0, ws, -1, s, n, NULL, NULL);
- return s;
-}
-
-static int iid_eq(REFIID a, const IID *b) {
- return memcmp((const void *)iid_ref(a), (const void *)b, sizeof(GUID)) == 0;
-}
-
-static HRESULT STDMETHODCALLTYPE JS_QueryInterface(IDispatch FAR *This,
- REFIID riid,
- LPVOID FAR *ppvObj) {
- if (iid_eq(riid, &IID_IDispatch)) {
- *ppvObj = This;
- return S_OK;
- }
- *ppvObj = 0;
- return E_NOINTERFACE;
-}
-static ULONG STDMETHODCALLTYPE JS_AddRef(IDispatch FAR *This) { return 1; }
-static ULONG STDMETHODCALLTYPE JS_Release(IDispatch FAR *This) { return 1; }
-static HRESULT STDMETHODCALLTYPE JS_GetTypeInfoCount(IDispatch FAR *This,
- UINT *pctinfo) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE JS_GetTypeInfo(IDispatch FAR *This,
- UINT iTInfo, LCID lcid,
- ITypeInfo **ppTInfo) {
- return S_OK;
-}
-#define WEBVIEW_JS_INVOKE_ID 0x1000
-static HRESULT STDMETHODCALLTYPE JS_GetIDsOfNames(IDispatch FAR *This,
- REFIID riid,
- LPOLESTR *rgszNames,
- UINT cNames, LCID lcid,
- DISPID *rgDispId) {
- if (cNames != 1) {
- return S_FALSE;
- }
- if (wcscmp(rgszNames[0], L"invoke") == 0) {
- rgDispId[0] = WEBVIEW_JS_INVOKE_ID;
- return S_OK;
- }
- return S_FALSE;
-}
-
-static HRESULT STDMETHODCALLTYPE
-JS_Invoke(IDispatch FAR *This, DISPID dispIdMember, REFIID riid, LCID lcid,
- WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
- EXCEPINFO *pExcepInfo, UINT *puArgErr) {
- size_t offset = (size_t) & ((_IOleClientSiteEx *)NULL)->external;
- _IOleClientSiteEx *ex = (_IOleClientSiteEx *)((char *)(This)-offset);
- struct webview *w = (struct webview *)GetWindowLongPtr(
- ex->inplace.frame.window, GWLP_USERDATA);
- if (pDispParams->cArgs == 1 && pDispParams->rgvarg[0].vt == VT_BSTR) {
- BSTR bstr = pDispParams->rgvarg[0].bstrVal;
- char *s = webview_from_utf16(bstr);
- if (s != NULL) {
- if (dispIdMember == WEBVIEW_JS_INVOKE_ID) {
- if (w->external_invoke_cb != NULL) {
- w->external_invoke_cb(w, s);
- }
- } else {
- return S_FALSE;
- }
- GlobalFree(s);
- }
- }
- return S_OK;
-}
-
-static IDispatchVtbl ExternalDispatchTable = {
- JS_QueryInterface, JS_AddRef, JS_Release, JS_GetTypeInfoCount,
- JS_GetTypeInfo, JS_GetIDsOfNames, JS_Invoke};
-
-static ULONG STDMETHODCALLTYPE Site_AddRef(IOleClientSite FAR *This) {
- return 1;
-}
-static ULONG STDMETHODCALLTYPE Site_Release(IOleClientSite FAR *This) {
- return 1;
-}
-static HRESULT STDMETHODCALLTYPE Site_SaveObject(IOleClientSite FAR *This) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE Site_GetMoniker(IOleClientSite FAR *This,
- DWORD dwAssign,
- DWORD dwWhichMoniker,
- IMoniker **ppmk) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE
-Site_GetContainer(IOleClientSite FAR *This, LPOLECONTAINER FAR *ppContainer) {
- *ppContainer = 0;
- return E_NOINTERFACE;
-}
-static HRESULT STDMETHODCALLTYPE Site_ShowObject(IOleClientSite FAR *This) {
- return NOERROR;
-}
-static HRESULT STDMETHODCALLTYPE Site_OnShowWindow(IOleClientSite FAR *This,
- BOOL fShow) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE
-Site_RequestNewObjectLayout(IOleClientSite FAR *This) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE Site_QueryInterface(IOleClientSite FAR *This,
- REFIID riid,
- void **ppvObject) {
- if (iid_eq(riid, &IID_IUnknown) || iid_eq(riid, &IID_IOleClientSite)) {
- *ppvObject = &((_IOleClientSiteEx *)This)->client;
- } else if (iid_eq(riid, &IID_IOleInPlaceSite)) {
- *ppvObject = &((_IOleClientSiteEx *)This)->inplace;
- } else if (iid_eq(riid, &IID_IDocHostUIHandler)) {
- *ppvObject = &((_IOleClientSiteEx *)This)->ui;
- } else {
- *ppvObject = 0;
- return (E_NOINTERFACE);
- }
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE InPlace_QueryInterface(
- IOleInPlaceSite FAR *This, REFIID riid, LPVOID FAR *ppvObj) {
- return (Site_QueryInterface(
- (IOleClientSite *)((char *)This - sizeof(IOleClientSite)), riid, ppvObj));
-}
-static ULONG STDMETHODCALLTYPE InPlace_AddRef(IOleInPlaceSite FAR *This) {
- return 1;
-}
-static ULONG STDMETHODCALLTYPE InPlace_Release(IOleInPlaceSite FAR *This) {
- return 1;
-}
-static HRESULT STDMETHODCALLTYPE InPlace_GetWindow(IOleInPlaceSite FAR *This,
- HWND FAR *lphwnd) {
- *lphwnd = ((_IOleInPlaceSiteEx FAR *)This)->frame.window;
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE
-InPlace_ContextSensitiveHelp(IOleInPlaceSite FAR *This, BOOL fEnterMode) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE
-InPlace_CanInPlaceActivate(IOleInPlaceSite FAR *This) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE
-InPlace_OnInPlaceActivate(IOleInPlaceSite FAR *This) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE
-InPlace_OnUIActivate(IOleInPlaceSite FAR *This) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE InPlace_GetWindowContext(
- IOleInPlaceSite FAR *This, LPOLEINPLACEFRAME FAR *lplpFrame,
- LPOLEINPLACEUIWINDOW FAR *lplpDoc, LPRECT lprcPosRect, LPRECT lprcClipRect,
- LPOLEINPLACEFRAMEINFO lpFrameInfo) {
- *lplpFrame = (LPOLEINPLACEFRAME) & ((_IOleInPlaceSiteEx *)This)->frame;
- *lplpDoc = 0;
- lpFrameInfo->fMDIApp = FALSE;
- lpFrameInfo->hwndFrame = ((_IOleInPlaceFrameEx *)*lplpFrame)->window;
- lpFrameInfo->haccel = 0;
- lpFrameInfo->cAccelEntries = 0;
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE InPlace_Scroll(IOleInPlaceSite FAR *This,
- SIZE scrollExtent) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE
-InPlace_OnUIDeactivate(IOleInPlaceSite FAR *This, BOOL fUndoable) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE
-InPlace_OnInPlaceDeactivate(IOleInPlaceSite FAR *This) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE
-InPlace_DiscardUndoState(IOleInPlaceSite FAR *This) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE
-InPlace_DeactivateAndUndo(IOleInPlaceSite FAR *This) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE
-InPlace_OnPosRectChange(IOleInPlaceSite FAR *This, LPCRECT lprcPosRect) {
- IOleObject *browserObject;
- IOleInPlaceObject *inplace;
- browserObject = *((IOleObject **)((char *)This - sizeof(IOleObject *) -
- sizeof(IOleClientSite)));
- if (!browserObject->lpVtbl->QueryInterface(browserObject,
- iid_unref(&IID_IOleInPlaceObject),
- (void **)&inplace)) {
- inplace->lpVtbl->SetObjectRects(inplace, lprcPosRect, lprcPosRect);
- inplace->lpVtbl->Release(inplace);
- }
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE Frame_QueryInterface(
- IOleInPlaceFrame FAR *This, REFIID riid, LPVOID FAR *ppvObj) {
- return E_NOTIMPL;
-}
-static ULONG STDMETHODCALLTYPE Frame_AddRef(IOleInPlaceFrame FAR *This) {
- return 1;
-}
-static ULONG STDMETHODCALLTYPE Frame_Release(IOleInPlaceFrame FAR *This) {
- return 1;
-}
-static HRESULT STDMETHODCALLTYPE Frame_GetWindow(IOleInPlaceFrame FAR *This,
- HWND FAR *lphwnd) {
- *lphwnd = ((_IOleInPlaceFrameEx *)This)->window;
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE
-Frame_ContextSensitiveHelp(IOleInPlaceFrame FAR *This, BOOL fEnterMode) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE Frame_GetBorder(IOleInPlaceFrame FAR *This,
- LPRECT lprectBorder) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE Frame_RequestBorderSpace(
- IOleInPlaceFrame FAR *This, LPCBORDERWIDTHS pborderwidths) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE Frame_SetBorderSpace(
- IOleInPlaceFrame FAR *This, LPCBORDERWIDTHS pborderwidths) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE Frame_SetActiveObject(
- IOleInPlaceFrame FAR *This, IOleInPlaceActiveObject *pActiveObject,
- LPCOLESTR pszObjName) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE
-Frame_InsertMenus(IOleInPlaceFrame FAR *This, HMENU hmenuShared,
- LPOLEMENUGROUPWIDTHS lpMenuWidths) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE Frame_SetMenu(IOleInPlaceFrame FAR *This,
- HMENU hmenuShared,
- HOLEMENU holemenu,
- HWND hwndActiveObject) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE Frame_RemoveMenus(IOleInPlaceFrame FAR *This,
- HMENU hmenuShared) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE Frame_SetStatusText(IOleInPlaceFrame FAR *This,
- LPCOLESTR pszStatusText) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE
-Frame_EnableModeless(IOleInPlaceFrame FAR *This, BOOL fEnable) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE
-Frame_TranslateAccelerator(IOleInPlaceFrame FAR *This, LPMSG lpmsg, WORD wID) {
- return E_NOTIMPL;
-}
-static HRESULT STDMETHODCALLTYPE UI_QueryInterface(IDocHostUIHandler FAR *This,
- REFIID riid,
- LPVOID FAR *ppvObj) {
- return (Site_QueryInterface((IOleClientSite *)((char *)This -
- sizeof(IOleClientSite) -
- sizeof(_IOleInPlaceSiteEx)),
- riid, ppvObj));
-}
-static ULONG STDMETHODCALLTYPE UI_AddRef(IDocHostUIHandler FAR *This) {
- return 1;
-}
-static ULONG STDMETHODCALLTYPE UI_Release(IDocHostUIHandler FAR *This) {
- return 1;
-}
-static HRESULT STDMETHODCALLTYPE UI_ShowContextMenu(
- IDocHostUIHandler FAR *This, DWORD dwID, POINT __RPC_FAR *ppt,
- IUnknown __RPC_FAR *pcmdtReserved, IDispatch __RPC_FAR *pdispReserved) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE
-UI_GetHostInfo(IDocHostUIHandler FAR *This, DOCHOSTUIINFO __RPC_FAR *pInfo) {
- pInfo->cbSize = sizeof(DOCHOSTUIINFO);
- pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER;
- pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT;
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE UI_ShowUI(
- IDocHostUIHandler FAR *This, DWORD dwID,
- IOleInPlaceActiveObject __RPC_FAR *pActiveObject,
- IOleCommandTarget __RPC_FAR *pCommandTarget,
- IOleInPlaceFrame __RPC_FAR *pFrame, IOleInPlaceUIWindow __RPC_FAR *pDoc) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE UI_HideUI(IDocHostUIHandler FAR *This) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE UI_UpdateUI(IDocHostUIHandler FAR *This) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE UI_EnableModeless(IDocHostUIHandler FAR *This,
- BOOL fEnable) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE
-UI_OnDocWindowActivate(IDocHostUIHandler FAR *This, BOOL fActivate) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE
-UI_OnFrameWindowActivate(IDocHostUIHandler FAR *This, BOOL fActivate) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE
-UI_ResizeBorder(IDocHostUIHandler FAR *This, LPCRECT prcBorder,
- IOleInPlaceUIWindow __RPC_FAR *pUIWindow, BOOL fRameWindow) {
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE
-UI_TranslateAccelerator(IDocHostUIHandler FAR *This, LPMSG lpMsg,
- const GUID __RPC_FAR *pguidCmdGroup, DWORD nCmdID) {
- return S_FALSE;
-}
-static HRESULT STDMETHODCALLTYPE UI_GetOptionKeyPath(
- IDocHostUIHandler FAR *This, LPOLESTR __RPC_FAR *pchKey, DWORD dw) {
- return S_FALSE;
-}
-static HRESULT STDMETHODCALLTYPE UI_GetDropTarget(
- IDocHostUIHandler FAR *This, IDropTarget __RPC_FAR *pDropTarget,
- IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget) {
- return S_FALSE;
-}
-static HRESULT STDMETHODCALLTYPE UI_GetExternal(
- IDocHostUIHandler FAR *This, IDispatch __RPC_FAR *__RPC_FAR *ppDispatch) {
- *ppDispatch = (IDispatch *)(This + 1);
- return S_OK;
-}
-static HRESULT STDMETHODCALLTYPE UI_TranslateUrl(
- IDocHostUIHandler FAR *This, DWORD dwTranslate, OLECHAR __RPC_FAR *pchURLIn,
- OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut) {
- *ppchURLOut = 0;
- return S_FALSE;
-}
-static HRESULT STDMETHODCALLTYPE
-UI_FilterDataObject(IDocHostUIHandler FAR *This, IDataObject __RPC_FAR *pDO,
- IDataObject __RPC_FAR *__RPC_FAR *ppDORet) {
- *ppDORet = 0;
- return S_FALSE;
-}
-
-static const TCHAR *classname = "WebView";
-static const SAFEARRAYBOUND ArrayBound = {1, 0};
-
-static IOleClientSiteVtbl MyIOleClientSiteTable = {
- Site_QueryInterface, Site_AddRef, Site_Release,
- Site_SaveObject, Site_GetMoniker, Site_GetContainer,
- Site_ShowObject, Site_OnShowWindow, Site_RequestNewObjectLayout};
-static IOleInPlaceSiteVtbl MyIOleInPlaceSiteTable = {
- InPlace_QueryInterface,
- InPlace_AddRef,
- InPlace_Release,
- InPlace_GetWindow,
- InPlace_ContextSensitiveHelp,
- InPlace_CanInPlaceActivate,
- InPlace_OnInPlaceActivate,
- InPlace_OnUIActivate,
- InPlace_GetWindowContext,
- InPlace_Scroll,
- InPlace_OnUIDeactivate,
- InPlace_OnInPlaceDeactivate,
- InPlace_DiscardUndoState,
- InPlace_DeactivateAndUndo,
- InPlace_OnPosRectChange};
-
-static IOleInPlaceFrameVtbl MyIOleInPlaceFrameTable = {
- Frame_QueryInterface,
- Frame_AddRef,
- Frame_Release,
- Frame_GetWindow,
- Frame_ContextSensitiveHelp,
- Frame_GetBorder,
- Frame_RequestBorderSpace,
- Frame_SetBorderSpace,
- Frame_SetActiveObject,
- Frame_InsertMenus,
- Frame_SetMenu,
- Frame_RemoveMenus,
- Frame_SetStatusText,
- Frame_EnableModeless,
- Frame_TranslateAccelerator};
-
-static IDocHostUIHandlerVtbl MyIDocHostUIHandlerTable = {
- UI_QueryInterface,
- UI_AddRef,
- UI_Release,
- UI_ShowContextMenu,
- UI_GetHostInfo,
- UI_ShowUI,
- UI_HideUI,
- UI_UpdateUI,
- UI_EnableModeless,
- UI_OnDocWindowActivate,
- UI_OnFrameWindowActivate,
- UI_ResizeBorder,
- UI_TranslateAccelerator,
- UI_GetOptionKeyPath,
- UI_GetDropTarget,
- UI_GetExternal,
- UI_TranslateUrl,
- UI_FilterDataObject};
-
-static void UnEmbedBrowserObject(struct webview *w) {
- if (w->priv.browser != NULL) {
- (*w->priv.browser)->lpVtbl->Close(*w->priv.browser, OLECLOSE_NOSAVE);
- (*w->priv.browser)->lpVtbl->Release(*w->priv.browser);
- GlobalFree(w->priv.browser);
- w->priv.browser = NULL;
- }
-}
-
-static int EmbedBrowserObject(struct webview *w) {
- RECT rect;
- IWebBrowser2 *webBrowser2 = NULL;
- LPCLASSFACTORY pClassFactory = NULL;
- _IOleClientSiteEx *_iOleClientSiteEx = NULL;
- IOleObject **browser = (IOleObject **)GlobalAlloc(
- GMEM_FIXED, sizeof(IOleObject *) + sizeof(_IOleClientSiteEx));
- if (browser == NULL) {
- goto error;
- }
- w->priv.browser = browser;
-
- _iOleClientSiteEx = (_IOleClientSiteEx *)(browser + 1);
- _iOleClientSiteEx->client.lpVtbl = &MyIOleClientSiteTable;
- _iOleClientSiteEx->inplace.inplace.lpVtbl = &MyIOleInPlaceSiteTable;
- _iOleClientSiteEx->inplace.frame.frame.lpVtbl = &MyIOleInPlaceFrameTable;
- _iOleClientSiteEx->inplace.frame.window = w->priv.hwnd;
- _iOleClientSiteEx->ui.ui.lpVtbl = &MyIDocHostUIHandlerTable;
- _iOleClientSiteEx->external.lpVtbl = &ExternalDispatchTable;
-
- if (CoGetClassObject(iid_unref(&CLSID_WebBrowser),
- CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, NULL,
- iid_unref(&IID_IClassFactory),
- (void **)&pClassFactory) != S_OK) {
- goto error;
- }
-
- if (pClassFactory == NULL) {
- goto error;
- }
-
- if (pClassFactory->lpVtbl->CreateInstance(pClassFactory, 0,
- iid_unref(&IID_IOleObject),
- (void **)browser) != S_OK) {
- goto error;
- }
- pClassFactory->lpVtbl->Release(pClassFactory);
- if ((*browser)->lpVtbl->SetClientSite(
- *browser, (IOleClientSite *)_iOleClientSiteEx) != S_OK) {
- goto error;
- }
- (*browser)->lpVtbl->SetHostNames(*browser, L"My Host Name", 0);
-
- if (OleSetContainedObject((struct IUnknown *)(*browser), TRUE) != S_OK) {
- goto error;
- }
- GetClientRect(w->priv.hwnd, &rect);
- if ((*browser)->lpVtbl->DoVerb((*browser), OLEIVERB_SHOW, NULL,
- (IOleClientSite *)_iOleClientSiteEx, -1,
- w->priv.hwnd, &rect) != S_OK) {
- goto error;
- }
- if ((*browser)->lpVtbl->QueryInterface((*browser),
- iid_unref(&IID_IWebBrowser2),
- (void **)&webBrowser2) != S_OK) {
- goto error;
- }
-
- webBrowser2->lpVtbl->put_Left(webBrowser2, 0);
- webBrowser2->lpVtbl->put_Top(webBrowser2, 0);
- webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right);
- webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom);
- webBrowser2->lpVtbl->Release(webBrowser2);
-
- return 0;
-error:
- UnEmbedBrowserObject(w);
- if (pClassFactory != NULL) {
- pClassFactory->lpVtbl->Release(pClassFactory);
- }
- if (browser != NULL) {
- GlobalFree(browser);
- }
- return -1;
-}
-
-#define WEBVIEW_DATA_URL_PREFIX "data:text/html,"
-static int DisplayHTMLPage(struct webview *w) {
- IWebBrowser2 *webBrowser2;
- VARIANT myURL;
- LPDISPATCH lpDispatch;
- IHTMLDocument2 *htmlDoc2;
- BSTR bstr;
- IOleObject *browserObject;
- SAFEARRAY *sfArray;
- VARIANT *pVar;
- browserObject = *w->priv.browser;
- int isDataURL = 0;
- const char *webview_url = webview_check_url(w->url);
- if (!browserObject->lpVtbl->QueryInterface(
- browserObject, iid_unref(&IID_IWebBrowser2), (void **)&webBrowser2)) {
- LPCSTR webPageName;
- isDataURL = (strncmp(webview_url, WEBVIEW_DATA_URL_PREFIX,
- strlen(WEBVIEW_DATA_URL_PREFIX)) == 0);
- if (isDataURL) {
- webPageName = "about:blank";
- } else {
- webPageName = (LPCSTR)webview_url;
- }
- VariantInit(&myURL);
- myURL.vt = VT_BSTR;
-#ifndef UNICODE
- {
- wchar_t *buffer = webview_to_utf16(webPageName);
- if (buffer == NULL) {
- goto badalloc;
- }
- myURL.bstrVal = SysAllocString(buffer);
- GlobalFree(buffer);
- }
-#else
- myURL.bstrVal = SysAllocString(webPageName);
-#endif
- if (!myURL.bstrVal) {
- badalloc:
- webBrowser2->lpVtbl->Release(webBrowser2);
- return (-6);
- }
- webBrowser2->lpVtbl->Navigate2(webBrowser2, &myURL, 0, 0, 0, 0);
- VariantClear(&myURL);
- if (!isDataURL) {
- return 0;
- }
-
- char *url = (char *)calloc(1, strlen(webview_url) + 1);
- char *q = url;
- for (const char *p = webview_url + strlen(WEBVIEW_DATA_URL_PREFIX); *q = *p;
- p++, q++) {
- if (*q == '%' && *(p + 1) && *(p + 2)) {
- sscanf(p + 1, "%02x", q);
- p = p + 2;
- }
- }
-
- if (webBrowser2->lpVtbl->get_Document(webBrowser2, &lpDispatch) == S_OK) {
- if (lpDispatch->lpVtbl->QueryInterface(lpDispatch,
- iid_unref(&IID_IHTMLDocument2),
- (void **)&htmlDoc2) == S_OK) {
- if ((sfArray = SafeArrayCreate(VT_VARIANT, 1,
- (SAFEARRAYBOUND *)&ArrayBound))) {
- if (!SafeArrayAccessData(sfArray, (void **)&pVar)) {
- pVar->vt = VT_BSTR;
-#ifndef UNICODE
- {
- wchar_t *buffer = webview_to_utf16(url);
- if (buffer == NULL) {
- goto release;
- }
- bstr = SysAllocString(buffer);
- GlobalFree(buffer);
- }
-#else
- bstr = SysAllocString(string);
-#endif
- if ((pVar->bstrVal = bstr)) {
- htmlDoc2->lpVtbl->write(htmlDoc2, sfArray);
- htmlDoc2->lpVtbl->close(htmlDoc2);
- }
- }
- SafeArrayDestroy(sfArray);
- }
- release:
- free(url);
- htmlDoc2->lpVtbl->Release(htmlDoc2);
- }
- lpDispatch->lpVtbl->Release(lpDispatch);
- }
- webBrowser2->lpVtbl->Release(webBrowser2);
- return (0);
- }
- return (-5);
-}
-
-static LRESULT CALLBACK wndproc(HWND hwnd, UINT uMsg, WPARAM wParam,
- LPARAM lParam) {
- struct webview *w = (struct webview *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
- switch (uMsg) {
- case WM_CREATE:
- w = (struct webview *)((CREATESTRUCT *)lParam)->lpCreateParams;
- w->priv.hwnd = hwnd;
- return EmbedBrowserObject(w);
- case WM_DESTROY:
- UnEmbedBrowserObject(w);
- PostQuitMessage(0);
- return TRUE;
- case WM_SIZE: {
- IWebBrowser2 *webBrowser2;
- IOleObject *browser = *w->priv.browser;
- if (browser->lpVtbl->QueryInterface(browser, iid_unref(&IID_IWebBrowser2),
- (void **)&webBrowser2) == S_OK) {
- RECT rect;
- GetClientRect(hwnd, &rect);
- webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right);
- webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom);
- }
- return TRUE;
- }
- case WM_WEBVIEW_DISPATCH: {
- webview_dispatch_fn f = (webview_dispatch_fn)wParam;
- void *arg = (void *)lParam;
- (*f)(w, arg);
- return TRUE;
- }
- }
- return DefWindowProc(hwnd, uMsg, wParam, lParam);
-}
-
-#define WEBVIEW_KEY_FEATURE_BROWSER_EMULATION \
- "Software\\Microsoft\\Internet " \
- "Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION"
-
-static int webview_fix_ie_compat_mode() {
- HKEY hKey;
- DWORD ie_version = 11000;
- TCHAR appname[MAX_PATH + 1];
- TCHAR *p;
- if (GetModuleFileName(NULL, appname, MAX_PATH + 1) == 0) {
- return -1;
- }
- for (p = &appname[strlen(appname) - 1]; p != appname && *p != '\\'; p--) {
- }
- p++;
- if (RegCreateKey(HKEY_CURRENT_USER, WEBVIEW_KEY_FEATURE_BROWSER_EMULATION,
- &hKey) != ERROR_SUCCESS) {
- return -1;
- }
- if (RegSetValueEx(hKey, p, 0, REG_DWORD, (BYTE *)&ie_version,
- sizeof(ie_version)) != ERROR_SUCCESS) {
- RegCloseKey(hKey);
- return -1;
- }
- RegCloseKey(hKey);
- return 0;
-}
-
-WEBVIEW_API int webview_init(struct webview *w) {
- WNDCLASSEX wc;
- HINSTANCE hInstance;
- DWORD style;
- RECT clientRect;
- RECT rect;
-
- if (webview_fix_ie_compat_mode() < 0) {
- return -1;
- }
-
- hInstance = GetModuleHandle(NULL);
- if (hInstance == NULL) {
- return -1;
- }
- if (OleInitialize(NULL) != S_OK) {
- return -1;
- }
- ZeroMemory(&wc, sizeof(WNDCLASSEX));
- wc.cbSize = sizeof(WNDCLASSEX);
- wc.hInstance = hInstance;
- wc.lpfnWndProc = wndproc;
- wc.lpszClassName = classname;
- RegisterClassEx(&wc);
-
- style = WS_OVERLAPPEDWINDOW;
- if (!w->resizable) {
- style = WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
- }
-
- rect.left = 0;
- rect.top = 0;
- rect.right = w->width;
- rect.bottom = w->height;
- AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, 0);
-
- GetClientRect(GetDesktopWindow(), &clientRect);
- int left = (clientRect.right / 2) - ((rect.right - rect.left) / 2);
- int top = (clientRect.bottom / 2) - ((rect.bottom - rect.top) / 2);
- rect.right = rect.right - rect.left + left;
- rect.left = left;
- rect.bottom = rect.bottom - rect.top + top;
- rect.top = top;
-
- w->priv.hwnd =
- CreateWindowEx(0, classname, w->title, style, rect.left, rect.top,
- rect.right - rect.left, rect.bottom - rect.top,
- HWND_DESKTOP, NULL, hInstance, (void *)w);
- if (w->priv.hwnd == 0) {
- OleUninitialize();
- return -1;
- }
-
- SetWindowLongPtr(w->priv.hwnd, GWLP_USERDATA, (LONG_PTR)w);
-
- DisplayHTMLPage(w);
-
- SetWindowText(w->priv.hwnd, w->title);
- ShowWindow(w->priv.hwnd, SW_SHOWDEFAULT);
- UpdateWindow(w->priv.hwnd);
- SetFocus(w->priv.hwnd);
-
- return 0;
-}
-
-WEBVIEW_API int webview_loop(struct webview *w, int blocking) {
- MSG msg;
- if (blocking) {
- GetMessage(&msg, 0, 0, 0);
- } else {
- PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
- }
- switch (msg.message) {
- case WM_QUIT:
- return -1;
- case WM_COMMAND:
- case WM_KEYDOWN:
- case WM_KEYUP: {
- HRESULT r = S_OK;
- IWebBrowser2 *webBrowser2;
- IOleObject *browser = *w->priv.browser;
- if (browser->lpVtbl->QueryInterface(browser, iid_unref(&IID_IWebBrowser2),
- (void **)&webBrowser2) == S_OK) {
- IOleInPlaceActiveObject *pIOIPAO;
- if (browser->lpVtbl->QueryInterface(
- browser, iid_unref(&IID_IOleInPlaceActiveObject),
- (void **)&pIOIPAO) == S_OK) {
- r = pIOIPAO->lpVtbl->TranslateAccelerator(pIOIPAO, &msg);
- pIOIPAO->lpVtbl->Release(pIOIPAO);
- }
- webBrowser2->lpVtbl->Release(webBrowser2);
- }
- if (r != S_FALSE) {
- break;
- }
- }
- default:
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return 0;
-}
-
-WEBVIEW_API int webview_eval(struct webview *w, const char *js) {
- IWebBrowser2 *webBrowser2;
- IHTMLDocument2 *htmlDoc2;
- IDispatch *docDispatch;
- IDispatch *scriptDispatch;
- if ((*w->priv.browser)
- ->lpVtbl->QueryInterface((*w->priv.browser),
- iid_unref(&IID_IWebBrowser2),
- (void **)&webBrowser2) != S_OK) {
- return -1;
- }
-
- if (webBrowser2->lpVtbl->get_Document(webBrowser2, &docDispatch) != S_OK) {
- return -1;
- }
- if (docDispatch->lpVtbl->QueryInterface(docDispatch,
- iid_unref(&IID_IHTMLDocument2),
- (void **)&htmlDoc2) != S_OK) {
- return -1;
- }
- if (htmlDoc2->lpVtbl->get_Script(htmlDoc2, &scriptDispatch) != S_OK) {
- return -1;
- }
- DISPID dispid;
- BSTR evalStr = SysAllocString(L"eval");
- if (scriptDispatch->lpVtbl->GetIDsOfNames(
- scriptDispatch, iid_unref(&IID_NULL), &evalStr, 1,
- LOCALE_SYSTEM_DEFAULT, &dispid) != S_OK) {
- SysFreeString(evalStr);
- return -1;
- }
- SysFreeString(evalStr);
-
- DISPPARAMS params;
- VARIANT arg;
- VARIANT result;
- EXCEPINFO excepInfo;
- UINT nArgErr = (UINT)-1;
- params.cArgs = 1;
- params.cNamedArgs = 0;
- params.rgvarg = &arg;
- arg.vt = VT_BSTR;
- static const char *prologue = "(function(){";
- static const char *epilogue = ";})();";
- int n = strlen(prologue) + strlen(epilogue) + strlen(js) + 1;
- char *eval = (char *)malloc(n);
- snprintf(eval, n, "%s%s%s", prologue, js, epilogue);
- wchar_t *buf = webview_to_utf16(eval);
- if (buf == NULL) {
- return -1;
- }
- arg.bstrVal = SysAllocString(buf);
- if (scriptDispatch->lpVtbl->Invoke(
- scriptDispatch, dispid, iid_unref(&IID_NULL), 0, DISPATCH_METHOD,
- ¶ms, &result, &excepInfo, &nArgErr) != S_OK) {
- return -1;
- }
- SysFreeString(arg.bstrVal);
- free(eval);
- scriptDispatch->lpVtbl->Release(scriptDispatch);
- htmlDoc2->lpVtbl->Release(htmlDoc2);
- docDispatch->lpVtbl->Release(docDispatch);
- return 0;
-}
-
-WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
- void *arg) {
- PostMessageW(w->priv.hwnd, WM_WEBVIEW_DISPATCH, (WPARAM)fn, (LPARAM)arg);
-}
-
-WEBVIEW_API void webview_set_title(struct webview *w, const char *title) {
- SetWindowText(w->priv.hwnd, title);
-}
-
-WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) {
- if (w->priv.is_fullscreen == !!fullscreen) {
- return;
- }
- if (w->priv.is_fullscreen == 0) {
- w->priv.saved_style = GetWindowLong(w->priv.hwnd, GWL_STYLE);
- w->priv.saved_ex_style = GetWindowLong(w->priv.hwnd, GWL_EXSTYLE);
- GetWindowRect(w->priv.hwnd, &w->priv.saved_rect);
- }
- w->priv.is_fullscreen = !!fullscreen;
- if (fullscreen) {
- MONITORINFO monitor_info;
- SetWindowLong(w->priv.hwnd, GWL_STYLE,
- w->priv.saved_style & ~(WS_CAPTION | WS_THICKFRAME));
- SetWindowLong(w->priv.hwnd, GWL_EXSTYLE,
- w->priv.saved_ex_style &
- ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
- WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
- monitor_info.cbSize = sizeof(monitor_info);
- GetMonitorInfo(MonitorFromWindow(w->priv.hwnd, MONITOR_DEFAULTTONEAREST),
- &monitor_info);
- RECT r;
- r.left = monitor_info.rcMonitor.left;
- r.top = monitor_info.rcMonitor.top;
- r.right = monitor_info.rcMonitor.right;
- r.bottom = monitor_info.rcMonitor.bottom;
- SetWindowPos(w->priv.hwnd, NULL, r.left, r.top, r.right - r.left,
- r.bottom - r.top,
- SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
- } else {
- SetWindowLong(w->priv.hwnd, GWL_STYLE, w->priv.saved_style);
- SetWindowLong(w->priv.hwnd, GWL_EXSTYLE, w->priv.saved_ex_style);
- SetWindowPos(w->priv.hwnd, NULL, w->priv.saved_rect.left,
- w->priv.saved_rect.top,
- w->priv.saved_rect.right - w->priv.saved_rect.left,
- w->priv.saved_rect.bottom - w->priv.saved_rect.top,
- SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
- }
-}
-
-WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
- uint8_t b, uint8_t a) {
- HBRUSH brush = CreateSolidBrush(RGB(r, g, b));
- SetClassLongPtr(w->priv.hwnd, GCLP_HBRBACKGROUND, (LONG_PTR)brush);
-}
-
-/* These are missing parts from MinGW */
-#ifndef __IFileDialog_INTERFACE_DEFINED__
-#define __IFileDialog_INTERFACE_DEFINED__
-enum _FILEOPENDIALOGOPTIONS {
- FOS_OVERWRITEPROMPT = 0x2,
- FOS_STRICTFILETYPES = 0x4,
- FOS_NOCHANGEDIR = 0x8,
- FOS_PICKFOLDERS = 0x20,
- FOS_FORCEFILESYSTEM = 0x40,
- FOS_ALLNONSTORAGEITEMS = 0x80,
- FOS_NOVALIDATE = 0x100,
- FOS_ALLOWMULTISELECT = 0x200,
- FOS_PATHMUSTEXIST = 0x800,
- FOS_FILEMUSTEXIST = 0x1000,
- FOS_CREATEPROMPT = 0x2000,
- FOS_SHAREAWARE = 0x4000,
- FOS_NOREADONLYRETURN = 0x8000,
- FOS_NOTESTFILECREATE = 0x10000,
- FOS_HIDEMRUPLACES = 0x20000,
- FOS_HIDEPINNEDPLACES = 0x40000,
- FOS_NODEREFERENCELINKS = 0x100000,
- FOS_DONTADDTORECENT = 0x2000000,
- FOS_FORCESHOWHIDDEN = 0x10000000,
- FOS_DEFAULTNOMINIMODE = 0x20000000,
- FOS_FORCEPREVIEWPANEON = 0x40000000
-};
-typedef DWORD FILEOPENDIALOGOPTIONS;
-typedef enum FDAP { FDAP_BOTTOM = 0, FDAP_TOP = 1 } FDAP;
-DEFINE_GUID(IID_IFileDialog, 0x42f85136, 0xdb7e, 0x439c, 0x85, 0xf1, 0xe4, 0x07,
- 0x5d, 0x13, 0x5f, 0xc8);
-typedef struct IFileDialogVtbl {
- BEGIN_INTERFACE
- HRESULT(STDMETHODCALLTYPE *QueryInterface)
- (IFileDialog *This, REFIID riid, void **ppvObject);
- ULONG(STDMETHODCALLTYPE *AddRef)(IFileDialog *This);
- ULONG(STDMETHODCALLTYPE *Release)(IFileDialog *This);
- HRESULT(STDMETHODCALLTYPE *Show)(IFileDialog *This, HWND hwndOwner);
- HRESULT(STDMETHODCALLTYPE *SetFileTypes)
- (IFileDialog *This, UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec);
- HRESULT(STDMETHODCALLTYPE *SetFileTypeIndex)
- (IFileDialog *This, UINT iFileType);
- HRESULT(STDMETHODCALLTYPE *GetFileTypeIndex)
- (IFileDialog *This, UINT *piFileType);
- HRESULT(STDMETHODCALLTYPE *Advise)
- (IFileDialog *This, IFileDialogEvents *pfde, DWORD *pdwCookie);
- HRESULT(STDMETHODCALLTYPE *Unadvise)(IFileDialog *This, DWORD dwCookie);
- HRESULT(STDMETHODCALLTYPE *SetOptions)
- (IFileDialog *This, FILEOPENDIALOGOPTIONS fos);
- HRESULT(STDMETHODCALLTYPE *GetOptions)
- (IFileDialog *This, FILEOPENDIALOGOPTIONS *pfos);
- HRESULT(STDMETHODCALLTYPE *SetDefaultFolder)
- (IFileDialog *This, IShellItem *psi);
- HRESULT(STDMETHODCALLTYPE *SetFolder)(IFileDialog *This, IShellItem *psi);
- HRESULT(STDMETHODCALLTYPE *GetFolder)(IFileDialog *This, IShellItem **ppsi);
- HRESULT(STDMETHODCALLTYPE *GetCurrentSelection)
- (IFileDialog *This, IShellItem **ppsi);
- HRESULT(STDMETHODCALLTYPE *SetFileName)(IFileDialog *This, LPCWSTR pszName);
- HRESULT(STDMETHODCALLTYPE *GetFileName)(IFileDialog *This, LPWSTR *pszName);
- HRESULT(STDMETHODCALLTYPE *SetTitle)(IFileDialog *This, LPCWSTR pszTitle);
- HRESULT(STDMETHODCALLTYPE *SetOkButtonLabel)
- (IFileDialog *This, LPCWSTR pszText);
- HRESULT(STDMETHODCALLTYPE *SetFileNameLabel)
- (IFileDialog *This, LPCWSTR pszLabel);
- HRESULT(STDMETHODCALLTYPE *GetResult)(IFileDialog *This, IShellItem **ppsi);
- HRESULT(STDMETHODCALLTYPE *AddPlace)
- (IFileDialog *This, IShellItem *psi, FDAP fdap);
- HRESULT(STDMETHODCALLTYPE *SetDefaultExtension)
- (IFileDialog *This, LPCWSTR pszDefaultExtension);
- HRESULT(STDMETHODCALLTYPE *Close)(IFileDialog *This, HRESULT hr);
- HRESULT(STDMETHODCALLTYPE *SetClientGuid)(IFileDialog *This, REFGUID guid);
- HRESULT(STDMETHODCALLTYPE *ClearClientData)(IFileDialog *This);
- HRESULT(STDMETHODCALLTYPE *SetFilter)
- (IFileDialog *This, IShellItemFilter *pFilter);
- END_INTERFACE
-} IFileDialogVtbl;
-interface IFileDialog {
- CONST_VTBL IFileDialogVtbl *lpVtbl;
-};
-DEFINE_GUID(IID_IFileOpenDialog, 0xd57c7288, 0xd4ad, 0x4768, 0xbe, 0x02, 0x9d,
- 0x96, 0x95, 0x32, 0xd9, 0x60);
-DEFINE_GUID(IID_IFileSaveDialog, 0x84bccd23, 0x5fde, 0x4cdb, 0xae, 0xa4, 0xaf,
- 0x64, 0xb8, 0x3d, 0x78, 0xab);
-#endif
-
-WEBVIEW_API void webview_dialog(struct webview *w,
- enum webview_dialog_type dlgtype, int flags,
- const char *title, const char *arg,
- char *result, size_t resultsz) {
- if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
- dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) {
- IFileDialog *dlg = NULL;
- IShellItem *res = NULL;
- WCHAR *ws = NULL;
- char *s = NULL;
- FILEOPENDIALOGOPTIONS opts, add_opts;
- if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN) {
- if (CoCreateInstance(
- iid_unref(&CLSID_FileOpenDialog), NULL, CLSCTX_INPROC_SERVER,
- iid_unref(&IID_IFileOpenDialog), (void **)&dlg) != S_OK) {
- goto error_dlg;
- }
- if (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY) {
- add_opts |= FOS_PICKFOLDERS;
- }
- add_opts |= FOS_NOCHANGEDIR | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE |
- FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_SHAREAWARE |
- FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS |
- FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE;
- } else {
- if (CoCreateInstance(
- iid_unref(&CLSID_FileSaveDialog), NULL, CLSCTX_INPROC_SERVER,
- iid_unref(&IID_IFileSaveDialog), (void **)&dlg) != S_OK) {
- goto error_dlg;
- }
- add_opts |= FOS_OVERWRITEPROMPT | FOS_NOCHANGEDIR |
- FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE | FOS_SHAREAWARE |
- FOS_NOTESTFILECREATE | FOS_NODEREFERENCELINKS |
- FOS_FORCESHOWHIDDEN | FOS_DEFAULTNOMINIMODE;
- }
- if (dlg->lpVtbl->GetOptions(dlg, &opts) != S_OK) {
- goto error_dlg;
- }
- opts &= ~FOS_NOREADONLYRETURN;
- opts |= add_opts;
- if (dlg->lpVtbl->SetOptions(dlg, opts) != S_OK) {
- goto error_dlg;
- }
- if (dlg->lpVtbl->Show(dlg, w->priv.hwnd) != S_OK) {
- goto error_dlg;
- }
- if (dlg->lpVtbl->GetResult(dlg, &res) != S_OK) {
- goto error_dlg;
- }
- if (res->lpVtbl->GetDisplayName(res, SIGDN_FILESYSPATH, &ws) != S_OK) {
- goto error_result;
- }
- s = webview_from_utf16(ws);
- strncpy(result, s, resultsz);
- result[resultsz - 1] = '\0';
- CoTaskMemFree(ws);
- error_result:
- res->lpVtbl->Release(res);
- error_dlg:
- dlg->lpVtbl->Release(dlg);
- return;
- } else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) {
-#if 0
- /* MinGW often doesn't contain TaskDialog, we'll use MessageBox for now */
- WCHAR *wtitle = webview_to_utf16(title);
- WCHAR *warg = webview_to_utf16(arg);
- TaskDialog(w->priv.hwnd, NULL, NULL, wtitle, warg, 0, NULL, NULL);
- GlobalFree(warg);
- GlobalFree(wtitle);
-#else
- UINT type = MB_OK;
- switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) {
- case WEBVIEW_DIALOG_FLAG_INFO:
- type |= MB_ICONINFORMATION;
- break;
- case WEBVIEW_DIALOG_FLAG_WARNING:
- type |= MB_ICONWARNING;
- break;
- case WEBVIEW_DIALOG_FLAG_ERROR:
- type |= MB_ICONERROR;
- break;
- }
- MessageBox(w->priv.hwnd, arg, title, type);
-#endif
- }
-}
-
-WEBVIEW_API void webview_terminate(struct webview *w) { PostQuitMessage(0); }
-WEBVIEW_API void webview_exit(struct webview *w) { OleUninitialize(); }
-WEBVIEW_API void webview_print_log(const char *s) { OutputDebugString(s); }
-
-#endif /* WEBVIEW_WINAPI */
-
-#if defined(WEBVIEW_COCOA)
-#if (!defined MAC_OS_X_VERSION_10_12) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
-#define NSAlertStyleWarning NSWarningAlertStyle
-#define NSAlertStyleCritical NSCriticalAlertStyle
-#define NSWindowStyleMaskResizable NSResizableWindowMask
-#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
-#define NSWindowStyleMaskTitled NSTitledWindowMask
-#define NSWindowStyleMaskClosable NSClosableWindowMask
-#define NSWindowStyleMaskFullScreen NSFullScreenWindowMask
-#define NSEventMaskAny NSAnyEventMask
-#define NSEventModifierFlagCommand NSCommandKeyMask
-#define NSEventModifierFlagOption NSAlternateKeyMask
-#define NSAlertStyleInformational NSInformationalAlertStyle
-#endif /* MAC_OS_X_VERSION_10_12 */
-#if (!defined MAC_OS_X_VERSION_10_13) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13
-#define NSModalResponseOK NSFileHandlingPanelOKButton
-#endif /* MAC_OS_X_VERSION_10_12, MAC_OS_X_VERSION_10_13 */
-static void webview_window_will_close(id self, SEL cmd, id notification) {
- struct webview *w =
- (struct webview *)objc_getAssociatedObject(self, "webview");
- webview_terminate(w);
-}
-
-static BOOL webview_is_selector_excluded_from_web_script(id self, SEL cmd,
- SEL selector) {
- return selector != @selector(invoke:);
-}
-
-static NSString *webview_webscript_name_for_selector(id self, SEL cmd,
- SEL selector) {
- return selector == @selector(invoke:) ? @"invoke" : nil;
-}
-
-static void webview_did_clear_window_object(id self, SEL cmd, id webview,
- id script, id frame) {
- [script setValue:self forKey:@"external"];
-}
-
-static void webview_external_invoke(id self, SEL cmd, id arg) {
- struct webview *w =
- (struct webview *)objc_getAssociatedObject(self, "webview");
- if (w == NULL || w->external_invoke_cb == NULL) {
- return;
- }
- if ([arg isKindOfClass:[NSString class]] == NO) {
- return;
- }
- w->external_invoke_cb(w, [(NSString *)(arg)UTF8String]);
-}
-
-WEBVIEW_API int webview_init(struct webview *w) {
- w->priv.pool = [[NSAutoreleasePool alloc] init];
- [NSApplication sharedApplication];
-
- Class webViewDelegateClass =
- objc_allocateClassPair([NSObject class], "WebViewDelegate", 0);
- class_addMethod(webViewDelegateClass, sel_registerName("windowWillClose:"),
- (IMP)webview_window_will_close, "v@:@");
- class_addMethod(object_getClass(webViewDelegateClass),
- sel_registerName("isSelectorExcludedFromWebScript:"),
- (IMP)webview_is_selector_excluded_from_web_script, "c@::");
- class_addMethod(object_getClass(webViewDelegateClass),
- sel_registerName("webScriptNameForSelector:"),
- (IMP)webview_webscript_name_for_selector, "c@::");
- class_addMethod(webViewDelegateClass,
- sel_registerName("webView:didClearWindowObject:forFrame:"),
- (IMP)webview_did_clear_window_object, "v@:@@@");
- class_addMethod(webViewDelegateClass, sel_registerName("invoke:"),
- (IMP)webview_external_invoke, "v@:@");
- objc_registerClassPair(webViewDelegateClass);
-
- w->priv.windowDelegate = [[webViewDelegateClass alloc] init];
- objc_setAssociatedObject(w->priv.windowDelegate, "webview", (id)(w),
- OBJC_ASSOCIATION_ASSIGN);
-
- NSString *nsTitle = [NSString stringWithUTF8String:w->title];
- NSRect r = NSMakeRect(0, 0, w->width, w->height);
- NSUInteger style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
- NSWindowStyleMaskMiniaturizable;
- if (w->resizable) {
- style = style | NSWindowStyleMaskResizable;
- }
- w->priv.window = [[NSWindow alloc] initWithContentRect:r
- styleMask:style
- backing:NSBackingStoreBuffered
- defer:NO];
- [w->priv.window autorelease];
- [w->priv.window setTitle:nsTitle];
- [w->priv.window setDelegate:w->priv.windowDelegate];
- [w->priv.window center];
-
- [[NSUserDefaults standardUserDefaults] setBool:!!w->debug
- forKey:@"WebKitDeveloperExtras"];
- [[NSUserDefaults standardUserDefaults] synchronize];
- w->priv.webview =
- [[WebView alloc] initWithFrame:r frameName:@"WebView" groupName:nil];
- NSURL *nsURL = [NSURL
- URLWithString:[NSString stringWithUTF8String:webview_check_url(w->url)]];
- [[w->priv.webview mainFrame] loadRequest:[NSURLRequest requestWithURL:nsURL]];
-
- [w->priv.webview setAutoresizesSubviews:YES];
- [w->priv.webview
- setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
- w->priv.webview.frameLoadDelegate = w->priv.windowDelegate;
- [[w->priv.window contentView] addSubview:w->priv.webview];
- [w->priv.window orderFrontRegardless];
-
- [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
- [NSApp finishLaunching];
- [NSApp activateIgnoringOtherApps:YES];
-
- NSMenu *menubar = [[[NSMenu alloc] initWithTitle:@""] autorelease];
-
- NSString *appName = [[NSProcessInfo processInfo] processName];
- NSMenuItem *appMenuItem =
- [[[NSMenuItem alloc] initWithTitle:appName action:NULL keyEquivalent:@""]
- autorelease];
- NSMenu *appMenu = [[[NSMenu alloc] initWithTitle:appName] autorelease];
- [appMenuItem setSubmenu:appMenu];
- [menubar addItem:appMenuItem];
-
- NSString *title = [@"Hide " stringByAppendingString:appName];
- NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:title
- action:@selector(hide:)
- keyEquivalent:@"h"] autorelease];
- [appMenu addItem:item];
- item = [[[NSMenuItem alloc] initWithTitle:@"Hide Others"
- action:@selector(hideOtherApplications:)
- keyEquivalent:@"h"] autorelease];
- [item setKeyEquivalentModifierMask:(NSEventModifierFlagOption |
- NSEventModifierFlagCommand)];
- [appMenu addItem:item];
- item = [[[NSMenuItem alloc] initWithTitle:@"Show All"
- action:@selector(unhideAllApplications:)
- keyEquivalent:@""] autorelease];
- [appMenu addItem:item];
- [appMenu addItem:[NSMenuItem separatorItem]];
-
- title = [@"Quit " stringByAppendingString:appName];
- item = [[[NSMenuItem alloc] initWithTitle:title
- action:@selector(terminate:)
- keyEquivalent:@"q"] autorelease];
- [appMenu addItem:item];
-
- [NSApp setMainMenu:menubar];
-
- w->priv.should_exit = 0;
- return 0;
-}
-
-WEBVIEW_API int webview_loop(struct webview *w, int blocking) {
- NSDate *until = (blocking ? [NSDate distantFuture] : [NSDate distantPast]);
- NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny
- untilDate:until
- inMode:NSDefaultRunLoopMode
- dequeue:YES];
- if (event) {
- [NSApp sendEvent:event];
- }
- return w->priv.should_exit;
-}
-
-WEBVIEW_API int webview_eval(struct webview *w, const char *js) {
- NSString *nsJS = [NSString stringWithUTF8String:js];
- [[w->priv.webview windowScriptObject] evaluateWebScript:nsJS];
- return 0;
-}
-
-WEBVIEW_API void webview_set_title(struct webview *w, const char *title) {
- NSString *nsTitle = [NSString stringWithUTF8String:title];
- [w->priv.window setTitle:nsTitle];
-}
-
-WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen) {
- int b = ((([w->priv.window styleMask] & NSWindowStyleMaskFullScreen) ==
- NSWindowStyleMaskFullScreen)
- ? 1
- : 0);
- if (b != fullscreen) {
- [w->priv.window toggleFullScreen:nil];
- }
-}
-
-WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
- uint8_t b, uint8_t a) {
- [w->priv.window setBackgroundColor:[NSColor colorWithRed:(CGFloat)r / 255.0
- green:(CGFloat)g / 255.0
- blue:(CGFloat)b / 255.0
- alpha:(CGFloat)a / 255.0]];
- if (0.5 >= ((r / 255.0 * 299.0) + (g / 255.0 * 587.0) + (b / 255.0 * 114.0)) /
- 1000.0) {
- [w->priv.window
- setAppearance:[NSAppearance
- appearanceNamed:NSAppearanceNameVibrantDark]];
- } else {
- [w->priv.window
- setAppearance:[NSAppearance
- appearanceNamed:NSAppearanceNameVibrantLight]];
- }
- [w->priv.window setOpaque:NO];
- [w->priv.window setTitlebarAppearsTransparent:YES];
- [w->priv.webview setDrawsBackground:NO];
-}
-
-WEBVIEW_API void webview_dialog(struct webview *w,
- enum webview_dialog_type dlgtype, int flags,
- const char *title, const char *arg,
- char *result, size_t resultsz) {
- if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN ||
- dlgtype == WEBVIEW_DIALOG_TYPE_SAVE) {
- NSSavePanel *panel;
- if (dlgtype == WEBVIEW_DIALOG_TYPE_OPEN) {
- NSOpenPanel *openPanel = [NSOpenPanel openPanel];
- if (flags & WEBVIEW_DIALOG_FLAG_DIRECTORY) {
- [openPanel setCanChooseFiles:NO];
- [openPanel setCanChooseDirectories:YES];
- } else {
- [openPanel setCanChooseFiles:YES];
- [openPanel setCanChooseDirectories:NO];
- }
- [openPanel setResolvesAliases:NO];
- [openPanel setAllowsMultipleSelection:NO];
- panel = openPanel;
- } else {
- panel = [NSSavePanel savePanel];
- }
- [panel setCanCreateDirectories:YES];
- [panel setShowsHiddenFiles:YES];
- [panel setExtensionHidden:NO];
- [panel setCanSelectHiddenExtension:NO];
- [panel setTreatsFilePackagesAsDirectories:YES];
- [panel beginSheetModalForWindow:w->priv.window
- completionHandler:^(NSInteger result) {
- [NSApp stopModalWithCode:result];
- }];
- if ([NSApp runModalForWindow:panel] == NSModalResponseOK) {
- const char *filename = [[[panel URL] path] UTF8String];
- strlcpy(result, filename, resultsz);
- }
- } else if (dlgtype == WEBVIEW_DIALOG_TYPE_ALERT) {
- NSAlert *a = [NSAlert new];
- switch (flags & WEBVIEW_DIALOG_FLAG_ALERT_MASK) {
- case WEBVIEW_DIALOG_FLAG_INFO:
- [a setAlertStyle:NSAlertStyleInformational];
- break;
- case WEBVIEW_DIALOG_FLAG_WARNING:
- NSLog(@"warning");
- [a setAlertStyle:NSAlertStyleWarning];
- break;
- case WEBVIEW_DIALOG_FLAG_ERROR:
- NSLog(@"error");
- [a setAlertStyle:NSAlertStyleCritical];
- break;
- }
- [a setShowsHelp:NO];
- [a setShowsSuppressionButton:NO];
- [a setMessageText:[NSString stringWithUTF8String:title]];
- [a setInformativeText:[NSString stringWithUTF8String:arg]];
- [a addButtonWithTitle:@"OK"];
- [a runModal];
- [a release];
- }
-}
-
-static void webview_dispatch_cb(void *arg) {
- struct webview_dispatch_arg *context = (struct webview_dispatch_arg *)arg;
- (context->fn)(context->w, context->arg);
- free(context);
-}
-
-WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
- void *arg) {
- struct webview_dispatch_arg *context = (struct webview_dispatch_arg *)malloc(
- sizeof(struct webview_dispatch_arg));
- context->w = w;
- context->arg = arg;
- context->fn = fn;
- dispatch_async_f(dispatch_get_main_queue(), context, webview_dispatch_cb);
-}
-
-WEBVIEW_API void webview_terminate(struct webview *w) {
- w->priv.should_exit = 1;
-}
-WEBVIEW_API void webview_exit(struct webview *w) { [NSApp terminate:NSApp]; }
-WEBVIEW_API void webview_print_log(const char *s) { NSLog(@"%s", s); }
-
-#endif /* WEBVIEW_COCOA */
-
-#endif /* WEBVIEW_IMPLEMENTATION */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* WEBVIEW_H */