#!/usr/bin/python3 import gi, json, os gi.require_version("Gtk", "3.0") gi.require_version("WebKit2", "4.1") from gi.repository import Gtk, Gdk, WebKit2, GLib from gi.repository.GdkPixbuf import Pixbuf # 优先尝试使用指示器, 没有再使用 Gtk.StatusIcon try: gi.require_version('AyatanaAppIndicator3', '0.1') # 需要安装这个包 gir1.2-ayatanaappindicator3-0.1 from gi.repository import AyatanaAppIndicator3 as AppIndicator3 except (ValueError, ImportError): AppIndicator3 = None def get_monitor_info(monitor): return { "model": monitor.props.model, "scale_factor": monitor.props.scale_factor, "manufacturer": monitor.props.manufacturer, "refresh_rate": monitor.props.refresh_rate, "is_primary": monitor.is_primary(), "geometry": { "width": monitor.props.geometry.width, "height": monitor.props.geometry.height, "x": monitor.props.geometry.x, "y": monitor.props.geometry.y, } } class WebKitWindow(Gtk.Window): def __init__(self): Gtk.Window.__init__(self, title="WebKit Example") self.set_default_size(800, 600) settings = WebKit2.Settings() settings.set_enable_page_cache(True) settings.set_enable_offline_web_application_cache(True) settings.set_enable_developer_extras(True) settings.set_enable_html5_database(True) settings.set_enable_html5_local_storage(True) settings.set_javascript_can_access_clipboard(True) settings.set_javascript_can_open_windows_automatically(True) settings.set_user_agent("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/605.1.15 (KHTML, like Gecko) weapp/1.0.0 Version/16.4 Safari/605.1.15") manager = WebKit2.UserContentManager() script = open(self.file_path('./inject.js'), 'r').read() frame = WebKit2.UserContentInjectedFrames.ALL_FRAMES time = WebKit2.UserScriptInjectionTime.END script = WebKit2.UserScript(script, frame, time, None, None) manager.add_script(script) manager.connect('script-message-received::app', self.on_script_message) manager.register_script_message_handler('app') self.webview = WebKit2.WebView.new_with_user_content_manager(manager) self.webview.set_settings(settings) self.webview.load_uri("http://127.0.0.1:10086/index.html") # self.webview.load_uri("https://benchmark.wkit.fun") self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) self.add(self.webview) def create_tray(self): if AppIndicator3 : indicator = AppIndicator3.Indicator.new( "youtube", "youtube", AppIndicator3.IndicatorCategory.APPLICATION_STATUS ) indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE) else: # windows 和 macos 必须传二进制图标, linux可传图标名称(自会去主题中找) indicator = Gtk.StatusIcon.new_from_pixbuf(get_logo(32)) # linux indicator = Gtk.StatusIcon.new_from_icon_name('youtube') return indicator # indicator = Gtk.StatusIcon.new_from_icon_name('youtube') # indicator.connect('activate', self.toggle_visible) # return indicator def toggle_visible(self, icon): # trayIcon print(icon) if self.is_active(): self.hide() else: self.present() def file_path(self, filepath): root = os.path.dirname(os.path.realpath(__file__)) return os.path.join(root, filepath) def on_script_message(self, webview, message): data = json.loads(message.get_js_value().to_json(0)) event = data.get('event') callback = data.get('callback') params = data.get('data') match event: case 'fs': pass case 'clipboard': output = None # 读文本 if params['action'] == 'wait_for_text': output = self.clipboard.wait_for_text() # 写文本 elif params['action'] == 'set_text': self.clipboard.set_text(params['value'], -1) # 写图片 elif params['action'] == 'set_image': image = params['value'] # 前端传进来的值, 如果是路径的话, 直接读取 if type(image) == str: image = Pixbuf.new_from_file(image) else: image = Pixbuf.new_from_data( data = bytes(image['bytes']), colorspace = image['colorspace'], has_alpha = image['has_alpha'], bits_per_sample = image['bits_per_sample'], width = image['width'], height = image['height'], rowstride = image['rowstride'] ) self.clipboard.set_image(image) self.clipboard.store() # 清除剪切板 elif params['action'] == 'clear': self.clipboard.clear() # 回调给前端 if callback and output: scripts = 'native.$emit("' + callback + '",' + json.dumps(output) + ')' print(scripts) self.webview.evaluate_javascript(scripts, -1) # 退出app case 'quit': Gtk.main_quit() # 读取图片, 返回图片像素数据 case 'image': filename = params['value'] pixbuf = Pixbuf.new_from_file(filename) image = { "width": pixbuf.get_width(), "height": pixbuf.get_height(), "colorspace": pixbuf.get_colorspace(), "has_alpha": pixbuf. get_has_alpha(), "bits_per_sample": pixbuf.get_bits_per_sample(), "rowstride": pixbuf.get_rowstride(), "filepath": filename, "bytes": list(pixbuf.get_pixels()) } scripts = 'native.$emit("' + callback + '",' + json.dumps(image) + ')' self.webview.send_message_to_page(WebKit2.UserMessage.new('blabla')) self.webview.evaluate_javascript(scripts, -1) case 'monitor': if params['action'] == 'get-all': display = Gdk.Display.get_default() monitor_num = display.get_n_monitors() monitors = [display.get_monitor(i) for i in range(monitor_num)] monitors = [get_monitor_info(m) for m in monitors] scripts = 'native.$emit("' + callback + '",' + json.dumps(monitors) + ')' self.webview.evaluate_javascript(scripts, -1) elif params['action'] == 'get-primary': display = Gdk.Display.get_default() monitor = display.get_primary_monitor() info = get_monitor_info(monitor) scripts = 'native.$emit("' + callback + '",' + json.dumps(info) + ')' self.webview.evaluate_javascript(scripts, -1) case _: if callback : res = {"foo": 123, "bar": (11,22,33)} scripts = 'native.$emit("' + callback + '",' + json.dumps(res) + ')' print(scripts) self.webview.evaluate_javascript(scripts, -1) win = WebKitWindow() win.connect("destroy", Gtk.main_quit) win.show_all() tray = win.create_tray() Gtk.main()