Compare commits
2 Commits
c1f7e8e503
...
6f7141560a
Author | SHA1 | Date |
---|---|---|
yutent | 6f7141560a | |
yutent | 4ef23a703d |
|
@ -1,10 +1,10 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import gi, os, json, shutil, hashlib, time, threading
|
import gi
|
||||||
|
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
gi.require_version("WebKit2", "4.1")
|
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):
|
def create_same_window(origin, req):
|
||||||
|
@ -37,6 +37,12 @@ def create_custom_window(origin, options):
|
||||||
win.set_wmclass(wmclass, 'WebEngine')
|
win.set_wmclass(wmclass, 'WebEngine')
|
||||||
win.set_title(options.get('title') or '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:
|
if options.get('frame') == False:
|
||||||
win.set_decorated(False)
|
win.set_decorated(False)
|
||||||
|
|
||||||
|
@ -50,9 +56,7 @@ def create_custom_window(origin, options):
|
||||||
win.set_resizable(False)
|
win.set_resizable(False)
|
||||||
|
|
||||||
|
|
||||||
|
web = WebEngine(win, origin, options.get('uuid'))
|
||||||
|
|
||||||
web = WebEngine(win, origin)
|
|
||||||
web.set_root(origin.root, True)
|
web.set_root(origin.root, True)
|
||||||
web.set_zoom_level(origin.get_zoom_level())
|
web.set_zoom_level(origin.get_zoom_level())
|
||||||
web.set_settings(origin.get_settings())
|
web.set_settings(origin.get_settings())
|
||||||
|
|
|
@ -13,13 +13,12 @@ from gi.repository import WebKit2
|
||||||
class Inject:
|
class Inject:
|
||||||
def __init__(self, webview, env = {}):
|
def __init__(self, webview, env = {}):
|
||||||
|
|
||||||
self.webview = webview
|
|
||||||
self.manager = webview.get_user_content_manager()
|
self.manager = webview.get_user_content_manager()
|
||||||
|
|
||||||
script_data = open(self.abspath('./inject.js'), 'r').read()
|
script_data = open(self.abspath('./inject.js'), 'r').read()
|
||||||
frame = WebKit2.UserContentInjectedFrames.ALL_FRAMES
|
frame = WebKit2.UserContentInjectedFrames.ALL_FRAMES
|
||||||
time = WebKit2.UserScriptInjectionTime.END
|
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)
|
script = WebKit2.UserScript(script_data, frame, time, None, None)
|
||||||
|
|
||||||
self.manager.add_script(script)
|
self.manager.add_script(script)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# @date 2023/08/08 14:07:26
|
# @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('Gtk', '3.0')
|
||||||
gi.require_version("WebKit2", "4.1")
|
gi.require_version("WebKit2", "4.1")
|
||||||
|
@ -54,18 +54,6 @@ def noop():
|
||||||
pass
|
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):
|
class WebEngine(WebKit2.WebView):
|
||||||
|
|
||||||
|
@ -73,18 +61,28 @@ class WebEngine(WebKit2.WebView):
|
||||||
'quit': (GObject.SignalFlags.RUN_FIRST, None, ())
|
'quit': (GObject.SignalFlags.RUN_FIRST, None, ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uuid = None
|
||||||
root = None
|
root = None
|
||||||
window = None
|
window = None
|
||||||
opener = None
|
opener = None
|
||||||
|
children = set()
|
||||||
custom_bridge = None
|
custom_bridge = None
|
||||||
|
|
||||||
def __init__(self, win, opener = None):
|
def __init__(self, win, opener = None, uuid = None):
|
||||||
|
|
||||||
WebKit2.WebView.__init__(self)
|
WebKit2.WebView.__init__(self)
|
||||||
|
|
||||||
|
if uuid is None:
|
||||||
|
self.uuid = random.randbytes(8).hex()
|
||||||
|
else:
|
||||||
|
self.uuid = uuid
|
||||||
|
|
||||||
self.opener = opener
|
self.opener = opener
|
||||||
self.window = win
|
self.window = win
|
||||||
|
|
||||||
|
if opener is not None:
|
||||||
|
opener.children.add(self)
|
||||||
|
|
||||||
if win.get_title() is None:
|
if win.get_title() is None:
|
||||||
win.set_title('WebEngine')
|
win.set_title('WebEngine')
|
||||||
|
|
||||||
|
@ -109,9 +107,22 @@ class WebEngine(WebKit2.WebView):
|
||||||
self.connect('create', self.create_new_window)
|
self.connect('create', self.create_new_window)
|
||||||
|
|
||||||
# 允许前端 widnow.close() 关闭窗口
|
# 允许前端 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
|
# 响应原生js的 window.open
|
||||||
def create_new_window(self, webview, nav):
|
def create_new_window(self, webview, nav):
|
||||||
|
@ -185,7 +196,7 @@ class WebEngine(WebKit2.WebView):
|
||||||
|
|
||||||
# 退出app
|
# 退出app
|
||||||
case 'quit':
|
case 'quit':
|
||||||
self.window.close()
|
self.close_window()
|
||||||
self.emit('quit')
|
self.emit('quit')
|
||||||
|
|
||||||
# 读取图片, 返回图片像素数据
|
# 读取图片, 返回图片像素数据
|
||||||
|
@ -219,12 +230,30 @@ class WebEngine(WebKit2.WebView):
|
||||||
case 'opener':
|
case 'opener':
|
||||||
callback = 'opener_message'
|
callback = 'opener_message'
|
||||||
output = params.get('data')
|
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:
|
if self.opener is None:
|
||||||
self.evaluate_javascript(scripts, -1)
|
self.evaluate_javascript(scripts, -1)
|
||||||
else:
|
else:
|
||||||
self.opener.evaluate_javascript(scripts, -1)
|
self.opener.evaluate_javascript(scripts, -1)
|
||||||
return
|
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':
|
case 'window':
|
||||||
_error, output = self._window_setting(params)
|
_error, output = self._window_setting(params)
|
||||||
|
@ -414,7 +443,7 @@ class WebEngine(WebKit2.WebView):
|
||||||
self.new_window_by_custom(params.get('options'))
|
self.new_window_by_custom(params.get('options'))
|
||||||
|
|
||||||
case 'close':
|
case 'close':
|
||||||
self.window.close()
|
self.close_window()
|
||||||
|
|
||||||
case 'fullscreen':
|
case 'fullscreen':
|
||||||
self.window.fullscreen()
|
self.window.fullscreen()
|
||||||
|
|
|
@ -90,6 +90,19 @@ function base64(str = '') {
|
||||||
return btoa(str).replace(/[+=\/]/g, '')
|
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 {
|
class NativeImage {
|
||||||
#origin
|
#origin
|
||||||
|
|
||||||
|
@ -192,7 +205,7 @@ class EventEmitter {
|
||||||
|
|
||||||
window.native = new 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, {
|
Object.assign(native, {
|
||||||
env: '{{env}}',
|
env: '{{env}}',
|
||||||
|
@ -345,12 +358,21 @@ Object.assign(native, {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
opener: {
|
opener: {
|
||||||
//
|
|
||||||
postMessage(data = {}) {
|
postMessage(data = {}) {
|
||||||
return handler('opener', { action: 'postmessage', data }, NO_CALLBACK)
|
return handler('opener', { action: 'postmessage', data }, NO_CALLBACK)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
children: {
|
||||||
|
postMessage(data = {}, uuid = null) {
|
||||||
|
return handler(
|
||||||
|
'children',
|
||||||
|
{ action: 'postmessage', data, uuid },
|
||||||
|
NO_CALLBACK
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
window: {
|
window: {
|
||||||
|
uuid: '{{uuid}}',
|
||||||
create(options = {}) {
|
create(options = {}) {
|
||||||
return handler('window', { action: 'create', options })
|
return handler('window', { action: 'create', options })
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue