-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 78e0850
Showing
4 changed files
with
379 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
graft webview |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# webview | ||
|
||
Python extension that provides API for the [webview] library. | ||
|
||
## Getting started | ||
|
||
Install the bindings: | ||
|
||
```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 sync install | ||
``` | ||
|
||
To upload a new version: | ||
|
||
```bash | ||
python setup.py sync sdist | ||
twine upload dist/webview-*.tar.gz | ||
``` | ||
|
||
To build and install it locally: | ||
|
||
```bash | ||
python setup.py sync install | ||
``` | ||
|
||
Please, ensure that all sources are formatted using `yapf`. | ||
|
||
|
||
[webview]: https://github.com/zserge/webview |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
#!/bin/env python | ||
|
||
import os | ||
import commands | ||
import shutil | ||
|
||
from distutils.core import setup | ||
from distutils.extension import Extension | ||
from distutils.cmd import Command | ||
|
||
|
||
class sync_command(Command): | ||
"""A custom command to synchronize top-level webview.h implementation | ||
with the one included in the Python bindings source package.""" | ||
description = 'synchronize webview.h' | ||
user_options = [] | ||
|
||
def initialize_options(self): | ||
pass | ||
|
||
def finalize_options(self): | ||
pass | ||
|
||
def run(self): | ||
shutil.copyfile('../../webview.h', 'webview/webview.h') | ||
pass | ||
|
||
|
||
if hasattr(os, 'uname'): | ||
OSNAME = os.uname()[0] | ||
else: | ||
OSNAME = 'Windows' | ||
|
||
if OSNAME == 'Linux': | ||
|
||
def pkgconfig(flags): | ||
return commands.getoutput( | ||
"pkg-config %s gtk+-3.0 webkit2gtk-4.0" % flags) | ||
|
||
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'] | ||
elif OSNAME == 'Windows': | ||
define_macros = [('WEBVIEW_WINAPI', '1')] | ||
extra_cflags = "" | ||
extra_ldflags = ['-framework', 'CoreAudio'] | ||
|
||
webview = Extension( | ||
'webview', | ||
sources=['webview/webview.c'], | ||
define_macros=define_macros, | ||
extra_compile_args=extra_cflags, | ||
extra_link_args=extra_ldflags, | ||
) | ||
|
||
setup( | ||
name='webview', | ||
version='0.1.4', | ||
description='Python WebView bindings', | ||
author='Serge Zaitsev', | ||
author_email='[email protected]', | ||
url='https://github.com/zserge/webview', | ||
keywords=[], | ||
license='MIT', | ||
classifiers=[], | ||
ext_modules=[webview], | ||
cmdclass={'sync': sync_command}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
#include <Python.h> | ||
|
||
#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, "..."}, | ||
{"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, "..."}, | ||
{"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 */ | ||
}; | ||
|
||
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ | ||
#define PyMODINIT_FUNC void | ||
#endif | ||
PyMODINIT_FUNC initwebview(void) { | ||
PyObject *m; | ||
|
||
if (PyType_Ready(&WebViewType) < 0) { | ||
return; | ||
} | ||
|
||
m = Py_InitModule3("webview", module_methods, | ||
"Example module that creates an extension type."); | ||
if (m == NULL) { | ||
return; | ||
} | ||
|
||
Py_INCREF(&WebViewType); | ||
PyModule_AddObject(m, "WebView", (PyObject *)&WebViewType); | ||
} |