Compare commits

..

2 Commits

4 changed files with 81 additions and 27 deletions

View File

@ -1,10 +1,10 @@
#!/usr/bin/env python3
import gi, os, json, shutil, hashlib, time, threading
import gi
gi.require_version('Gtk', '3.0')
gi.require_version("WebKit2", "4.1")
from gi.repository import GObject, Gtk, Gdk, WebKit2, GLib, Gio, GdkPixbuf
from gi.repository import Gtk, WebKit2
def create_same_window(origin, req):
@ -37,6 +37,12 @@ def create_custom_window(origin, options):
win.set_wmclass(wmclass, 'WebEngine')
win.set_title(options.get('title') or 'WebEngine')
if options.get('icon_path'):
win.set_icon_from_file(options['icon_path'])
if options.get('icon'):
win.set_icon_name(options['icon'])
if options.get('frame') == False:
win.set_decorated(False)
@ -50,9 +56,7 @@ def create_custom_window(origin, options):
win.set_resizable(False)
web = WebEngine(win, origin)
web = WebEngine(win, origin, options.get('uuid'))
web.set_root(origin.root, True)
web.set_zoom_level(origin.get_zoom_level())
web.set_settings(origin.get_settings())

View File

@ -13,13 +13,12 @@ from gi.repository import WebKit2
class Inject:
def __init__(self, webview, env = {}):
self.webview = webview
self.manager = webview.get_user_content_manager()
script_data = open(self.abspath('./inject.js'), 'r').read()
frame = WebKit2.UserContentInjectedFrames.ALL_FRAMES
time = WebKit2.UserScriptInjectionTime.END
script_data = script_data.replace("'{{env}}'", json.dumps(env))
script_data = script_data.replace("'{{env}}'", json.dumps(env)).replace("{{uuid}}", webview.uuid)
script = WebKit2.UserScript(script_data, frame, time, None, None)
self.manager.add_script(script)

View File

@ -3,7 +3,7 @@
# @date 2023/08/08 14:07:26
import gi, os, json, shutil, hashlib, time, threading
import gi, os, json, shutil, hashlib, random
gi.require_version('Gtk', '3.0')
gi.require_version("WebKit2", "4.1")
@ -54,18 +54,6 @@ def noop():
pass
# 类型js的settimeout的修饰器
def set_timeout(timeout = 0.5):
def decorator(callback):
def wrapper(*args):
t = threading.Timer(timeout, callback, args=args)
t.start()
return t
return wrapper
return decorator
class WebEngine(WebKit2.WebView):
@ -73,18 +61,28 @@ class WebEngine(WebKit2.WebView):
'quit': (GObject.SignalFlags.RUN_FIRST, None, ())
}
uuid = None
root = None
window = None
opener = None
children = set()
custom_bridge = None
def __init__(self, win, opener = None):
def __init__(self, win, opener = None, uuid = None):
WebKit2.WebView.__init__(self)
if uuid is None:
self.uuid = random.randbytes(8).hex()
else:
self.uuid = uuid
self.opener = opener
self.window = win
if opener is not None:
opener.children.add(self)
if win.get_title() is None:
win.set_title('WebEngine')
@ -109,9 +107,22 @@ class WebEngine(WebKit2.WebView):
self.connect('create', self.create_new_window)
# 允许前端 widnow.close() 关闭窗口
self.connect('close', lambda w: win.close())
self.connect('close', self.close_window)
win.connect("destroy", self.remove_from_opener) # 通过外部关闭窗口时从父级中移除
def remove_from_opener(self, win = None):
if self.opener is not None:
try:
self.opener.children.remove(self)
except:
pass
def close_window(self, wv = None):
self.remove_from_opener()
self.window.close()
# 响应原生js的 window.open
def create_new_window(self, webview, nav):
@ -185,7 +196,7 @@ class WebEngine(WebKit2.WebView):
# 退出app
case 'quit':
self.window.close()
self.close_window()
self.emit('quit')
# 读取图片, 返回图片像素数据
@ -219,13 +230,31 @@ class WebEngine(WebKit2.WebView):
case 'opener':
callback = 'opener_message'
output = params.get('data')
scripts = 'native.$emit("opener_message", ' + json.dumps(output) + ')'
uuid = json.dumps(self.uuid if self.opener else None)
scripts = f"native.$emit('opener_message', {json.dumps(output)}, {uuid})"
if self.opener is None:
self.evaluate_javascript(scripts, -1)
else:
self.opener.evaluate_javascript(scripts, -1)
return
case 'children':
callback = 'opener_message'
output = params.get('data')
uuid = params.get('uuid')
scripts = f"native.$emit('opener_message', {json.dumps(output)})"
if len(self.children) == 0:
self.evaluate_javascript(scripts, -1)
else:
if uuid is None:
for child in self.children:
child.evaluate_javascript(scripts, -1)
else:
for child in self.children:
if child.uuid == uuid:
child.evaluate_javascript(scripts, -1)
return
case 'window':
_error, output = self._window_setting(params)
@ -414,7 +443,7 @@ class WebEngine(WebKit2.WebView):
self.new_window_by_custom(params.get('options'))
case 'close':
self.window.close()
self.close_window()
case 'fullscreen':
self.window.fullscreen()

View File

@ -90,6 +90,19 @@ function base64(str = '') {
return btoa(str).replace(/[+=\/]/g, '')
}
function _postMessage(data = {}, uuid = null) {
let ev = new Event('message')
Object.assign(ev, {
data,
source: {
postMessage(msg) {
native.children.postMessage(msg, uuid)
}
}
})
window.dispatchEvent(ev)
}
class NativeImage {
#origin
@ -192,7 +205,7 @@ class EventEmitter {
window.native = new EventEmitter()
native.$on('opener_message', data => window.postMessage(data))
native.$on('opener_message', (data, uuid) => _postMessage(data, uuid))
Object.assign(native, {
env: '{{env}}',
@ -345,12 +358,21 @@ Object.assign(native, {
}
},
opener: {
//
postMessage(data = {}) {
return handler('opener', { action: 'postmessage', data }, NO_CALLBACK)
}
},
children: {
postMessage(data = {}, uuid = null) {
return handler(
'children',
{ action: 'postmessage', data, uuid },
NO_CALLBACK
)
}
},
window: {
uuid: '{{uuid}}',
create(options = {}) {
return handler('window', { action: 'create', options })
},