使用python在多窗口之间做桥接

master
yutent 2023-09-08 15:06:42 +08:00
parent 1f2273150c
commit 80872e0678
4 changed files with 83 additions and 35 deletions

View File

@ -8,15 +8,19 @@ from gi.repository import GObject, Gtk, Gdk, WebKit2, GLib, Gio, GdkPixbuf
def create_same_window(origin, req): def create_same_window(origin, req):
WebEngine = type(origin)
w, h = origin.window.get_size() w, h = origin.window.get_size()
win = Gtk.Window() win = Gtk.Window()
win.set_default_size(w, h) win.set_default_size(w, h)
web = WebKit2.WebView.new_with_related_view(origin)
web = WebEngine(win, origin)
web.set_zoom_level(origin.get_zoom_level())
web.set_settings(origin.get_settings())
web.load_request(req) web.load_request(req)
win.add(web) win.add(web)
win.show_all() win.show_all()
return web
@ -47,11 +51,8 @@ def create_custom_window(origin, options):
web = WebEngine(win)
# web = WebEngine(win, origin) web = WebEngine(win, origin)
# web = WebKit2.WebView.new_with_related_view(origin)
# web = WebEngine.new_with(win, origin)
# web.window = win
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())

View File

@ -13,6 +13,7 @@ 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()

View File

@ -75,12 +75,14 @@ class WebEngine(WebKit2.WebView):
root = None root = None
window = None window = None
opener = None
custom_bridge = None custom_bridge = None
def __init__(self, win): def __init__(self, win, opener = None):
WebKit2.WebView.__init__(self) WebKit2.WebView.__init__(self)
self.opener = opener
self.window = win self.window = win
if win.get_title() is None: if win.get_title() is None:
@ -106,6 +108,8 @@ class WebEngine(WebKit2.WebView):
self.connect('create', self.create_new_window) self.connect('create', self.create_new_window)
# 允许前端 widnow.close() 关闭窗口
self.connect('close', lambda w: win.close())
@ -182,7 +186,7 @@ class WebEngine(WebKit2.WebView):
# 退出app # 退出app
case 'quit': case 'quit':
self.window.close() self.window.close()
# self.emit('quit') self.emit('quit')
# 读取图片, 返回图片像素数据 # 读取图片, 返回图片像素数据
case 'image': case 'image':
@ -212,6 +216,16 @@ class WebEngine(WebKit2.WebView):
elif params['action'] == 'remove': elif params['action'] == 'remove':
pass pass
case 'opener':
callback = 'opener_message'
output = params.get('data')
scripts = 'native.$emit("opener_message", ' + json.dumps(output) + ')'
if self.opener is None:
self.evaluate_javascript(scripts, -1)
else:
self.opener.evaluate_javascript(scripts, -1)
return
case 'window': case 'window':
_error, output = self._window_setting(params) _error, output = self._window_setting(params)
@ -399,6 +413,9 @@ class WebEngine(WebKit2.WebView):
case 'create': case 'create':
self.new_window_by_custom(params.get('options')) self.new_window_by_custom(params.get('options'))
case 'close':
self.window.close()
case 'fullscreen': case 'fullscreen':
self.window.fullscreen() self.window.fullscreen()

View File

@ -45,6 +45,9 @@ const KEYS_MAP = {
super: '<Super>' super: '<Super>'
} }
const NO_CALLBACK = false
const CALL_ONCE = true
function defer() { function defer() {
let obj = {} let obj = {}
obj.promise = new Promise((resolve, reject) => { obj.promise = new Promise((resolve, reject) => {
@ -58,22 +61,23 @@ function rand(prefix = 'cb_') {
return prefix + Math.random().toString().slice(2) return prefix + Math.random().toString().slice(2)
} }
function handler(event, data = {}, once = true) { function handler(event, data = {}, need = CALL_ONCE) {
let _ = defer() let _ = defer()
let callback let callback
if (typeof once === 'boolean') { if (need === NO_CALLBACK) {
_.resolve(true)
} else {
callback = rand() callback = rand()
native[once ? '$once' : '$on'](callback, (err, res) => { native.$once(callback, (err, res) => {
if (err) { if (err) {
_.reject(err) _.reject(err)
} else { } else {
_.resolve(res) _.resolve(res)
} }
}) })
} else {
_.resolve(true)
} }
window.webkit.messageHandlers.app.postMessage({ window.webkit.messageHandlers.app.postMessage({
event, event,
data, data,
@ -188,11 +192,13 @@ class EventEmitter {
window.native = new EventEmitter() window.native = new EventEmitter()
native.$on('opener_message', data => window.postMessage(data))
Object.assign(native, { Object.assign(native, {
env: '{{env}}', env: '{{env}}',
quit() { quit() {
return handler('quit', {}, null) return handler('quit', {}, NO_CALLBACK)
}, },
fs: { fs: {
access(filepath, mode = 'r') { access(filepath, mode = 'r') {
@ -250,7 +256,7 @@ Object.assign(native, {
return handler('clipboard', { action: 'wait_for_text' }) return handler('clipboard', { action: 'wait_for_text' })
}, },
writeText(value) { writeText(value) {
return handler('clipboard', { action: 'set_text', value }, null) return handler('clipboard', { action: 'set_text', value }, NO_CALLBACK)
}, },
readImage() { readImage() {
return handler('clipboard', { action: 'wait_for_image' }).then(r => return handler('clipboard', { action: 'wait_for_image' }).then(r =>
@ -262,10 +268,10 @@ Object.assign(native, {
if (typeof value === 'object') { if (typeof value === 'object') {
value = value.toJSON() value = value.toJSON()
} }
return handler('clipboard', { action: 'set_image', value }, null) return handler('clipboard', { action: 'set_image', value }, NO_CALLBACK)
}, },
clear() { clear() {
return handler('clipboard', { action: 'clear' }) return handler('clipboard', { action: 'clear' }, NO_CALLBACK)
} }
}, },
screen: { screen: {
@ -338,51 +344,74 @@ Object.assign(native, {
return handler('tray', { action: 'set_status', value: status }) return handler('tray', { action: 'set_status', value: status })
} }
}, },
opener: {
//
postMessage(data = {}) {
return handler('opener', { action: 'postmessage', data }, NO_CALLBACK)
}
},
window: { window: {
create(options = {}) { create(options = {}) {
return handler('window', { action: 'create', options }) return handler('window', { action: 'create', options })
}, },
close() {
return handler('window', { action: 'close' })
},
isVisible() { isVisible() {
return handler('window', { action: 'is_visible' }) return handler('window', { action: 'is_visible' })
}, },
toggleVisible() { toggleVisible() {
handler('window', { action: 'toggle_visible' }, null) handler('window', { action: 'toggle_visible' }, NO_CALLBACK)
}, },
hide() { hide() {
handler('window', { action: 'hide' }, null) handler('window', { action: 'hide' }, NO_CALLBACK)
}, },
show() { show() {
handler('window', { action: 'show' }, null) handler('window', { action: 'show' }, NO_CALLBACK)
}, },
fullscreen() { fullscreen() {
handler('window', { action: 'fullscreen' }, null) handler('window', { action: 'fullscreen' }, NO_CALLBACK)
}, },
unfullscreen() { unfullscreen() {
handler('window', { action: 'unfullscreen' }, null) handler('window', { action: 'unfullscreen' }, NO_CALLBACK)
}, },
maximize() { maximize() {
handler('window', { action: 'maximize' }, null) handler('window', { action: 'maximize' }, NO_CALLBACK)
}, },
unmaximize() { unmaximize() {
handler('window', { action: 'unmaximize' }, null) handler('window', { action: 'unmaximize' }, NO_CALLBACK)
}, },
setTitle(title = '') { setTitle(title = '') {
handler('window', { action: 'set_title', value: title }, null) handler('window', { action: 'set_title', value: title }, NO_CALLBACK)
}, },
resize(width = 0, height = 0) { resize(width = 0, height = 0) {
handler('window', { action: 'resize', value: { width, height } }, null) handler(
'window',
{ action: 'resize', value: { width, height } },
NO_CALLBACK
)
}, },
move(x = 0, y = 0) { move(x = 0, y = 0) {
handler('window', { action: 'move', value: { x, y } }, null) handler('window', { action: 'move', value: { x, y } }, NO_CALLBACK)
}, },
setOpacity(opacity = 1) { setOpacity(opacity = 1) {
handler('window', { action: 'set_opacity', value: opacity }, null) handler('window', { action: 'set_opacity', value: opacity }, NO_CALLBACK)
}, },
alwayOnTop(setting = true) { alwayOnTop(setting = true) {
handler('window', { action: 'set_keep_above', value: setting }, null) handler(
'window',
{ action: 'set_keep_above', value: setting },
NO_CALLBACK
)
}, },
alwayOnBotttom(setting = true) { alwayOnBotttom(setting = true) {
handler('window', { action: 'set_keep_below', value: setting }, null) handler(
'window',
{ action: 'set_keep_below', value: setting },
NO_CALLBACK
)
} }
}, },
notify({ title, summary, icon, progress = 0, urgency = 0, callback }) { notify({ title, summary, icon, progress = 0, urgency = 0, callback }) {
@ -394,7 +423,7 @@ Object.assign(native, {
handler( handler(
'notify', 'notify',
{ title, summary, icon, progress, urgency, callback: eventName }, { title, summary, icon, progress, urgency, callback: eventName },
null NO_CALLBACK
) )
}, },
@ -404,13 +433,13 @@ Object.assign(native, {
proxy: { proxy: {
disable() { disable() {
return handler('proxy', { action: 'disable' }) return handler('proxy', { action: 'disable' }, NO_CALLBACK)
}, },
system() { system() {
return handler('proxy', { action: 'system' }) return handler('proxy', { action: 'system' }, NO_CALLBACK)
}, },
custom(url = '', ignore = null) { custom(url = '', ignore = null) {
return handler('proxy', { action: 'enable', url, ignore }) return handler('proxy', { action: 'enable', url, ignore }, NO_CALLBACK)
} }
}, },