jadeui 0.2.0__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {jadeui-0.2.0 → jadeui-0.3.2}/PKG-INFO +1 -1
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/__init__.py +1 -1
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/core/dll.py +1 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/core/types.py +3 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/downloader.py +22 -4
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/events.py +103 -41
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/window.py +159 -6
- {jadeui-0.2.0 → jadeui-0.3.2}/pyproject.toml +1 -1
- {jadeui-0.2.0 → jadeui-0.3.2}/.gitignore +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/README.md +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/examples/README.md +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/examples/backdrop_demo/README.md +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/examples/calculator/README.md +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/examples/custom_template/README.md +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/examples/router_demo/README.md +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/examples/simple/README.md +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/examples/vue_app/README.md +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/app.py +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/core/__init__.py +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/core/lifecycle.py +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/exceptions.py +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/ipc.py +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/router.py +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/server.py +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/templates/__init__.py +0 -0
- {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/utils.py +0 -0
|
@@ -293,6 +293,7 @@ class DLLManager:
|
|
|
293
293
|
self._try_bind("is_window_minimized", [ctypes.c_uint32], ctypes.c_int)
|
|
294
294
|
self._try_bind("is_window_visible", [ctypes.c_uint32], ctypes.c_int)
|
|
295
295
|
self._try_bind("is_window_focused", [ctypes.c_uint32], ctypes.c_int)
|
|
296
|
+
self._try_bind("is_window_fullscreen", [ctypes.c_uint32], ctypes.c_int)
|
|
296
297
|
|
|
297
298
|
# Window focus
|
|
298
299
|
self._try_bind("focus_window", [ctypes.c_uint32], ctypes.c_int)
|
|
@@ -146,6 +146,7 @@ class WebViewSettings(ctypes.Structure):
|
|
|
146
146
|
("disable_right_click", ctypes.c_int),
|
|
147
147
|
("ua", ctypes.c_char_p),
|
|
148
148
|
("preload_js", ctypes.c_char_p),
|
|
149
|
+
("allow_fullscreen", ctypes.c_int), # JadeView 0.2.1+: 控制是否允许页面全屏
|
|
149
150
|
]
|
|
150
151
|
|
|
151
152
|
def __init__(
|
|
@@ -155,6 +156,7 @@ class WebViewSettings(ctypes.Structure):
|
|
|
155
156
|
disable_right_click: bool = False,
|
|
156
157
|
ua: Optional[bytes] = None,
|
|
157
158
|
preload_js: Optional[bytes] = None,
|
|
159
|
+
allow_fullscreen: bool = True, # 默认允许全屏
|
|
158
160
|
):
|
|
159
161
|
super().__init__(
|
|
160
162
|
int(autoplay),
|
|
@@ -162,6 +164,7 @@ class WebViewSettings(ctypes.Structure):
|
|
|
162
164
|
int(disable_right_click),
|
|
163
165
|
ua,
|
|
164
166
|
preload_js,
|
|
167
|
+
int(allow_fullscreen),
|
|
165
168
|
)
|
|
166
169
|
|
|
167
170
|
|
|
@@ -23,7 +23,7 @@ GITHUB_RELEASE_URL = f"https://github.com/{GITHUB_REPO}/releases/download"
|
|
|
23
23
|
|
|
24
24
|
# DLL 版本号(可能与 SDK 版本不同)
|
|
25
25
|
# 当 SDK 修复 bug 但 DLL 未更新时,此版本保持不变
|
|
26
|
-
DLL_VERSION = "0.2
|
|
26
|
+
DLL_VERSION = "0.3.2"
|
|
27
27
|
|
|
28
28
|
# 链接类型: "static" (推荐) 或 "dynamic"
|
|
29
29
|
# static: DLL内嵌所有依赖,无需额外运行时
|
|
@@ -259,8 +259,18 @@ def download_dll(
|
|
|
259
259
|
print("📂 正在解压...")
|
|
260
260
|
|
|
261
261
|
with zipfile.ZipFile(tmp_path, "r") as zip_ref:
|
|
262
|
-
#
|
|
263
|
-
zip_ref.
|
|
262
|
+
# Check if ZIP contains the expected directory structure
|
|
263
|
+
namelist = zip_ref.namelist()
|
|
264
|
+
has_top_dir = any(
|
|
265
|
+
name.startswith(dist_dir + "/") or name == dist_dir + "/" for name in namelist
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
if has_top_dir:
|
|
269
|
+
# ZIP contains the directory, extract to install_dir
|
|
270
|
+
zip_ref.extractall(install_dir)
|
|
271
|
+
else:
|
|
272
|
+
# ZIP doesn't contain directory, extract to target_dir
|
|
273
|
+
zip_ref.extractall(target_dir)
|
|
264
274
|
|
|
265
275
|
print("✅ 解压完成")
|
|
266
276
|
|
|
@@ -274,7 +284,15 @@ def download_dll(
|
|
|
274
284
|
# Verify DLL exists
|
|
275
285
|
dll_path = target_dir / dll_name
|
|
276
286
|
if not dll_path.exists():
|
|
277
|
-
|
|
287
|
+
# Also check if DLL is directly in install_dir (fallback)
|
|
288
|
+
alt_path = install_dir / dll_name
|
|
289
|
+
if alt_path.exists():
|
|
290
|
+
# Move to correct location
|
|
291
|
+
import shutil
|
|
292
|
+
|
|
293
|
+
shutil.move(str(alt_path), str(dll_path))
|
|
294
|
+
else:
|
|
295
|
+
raise RuntimeError(f"解压后未找到 DLL 文件: {dll_path}")
|
|
278
296
|
|
|
279
297
|
print("\n🎉 安装成功!")
|
|
280
298
|
print(f" DLL 路径: {dll_path}")
|
|
@@ -248,44 +248,106 @@ class GlobalEventManager:
|
|
|
248
248
|
# Standard event names
|
|
249
249
|
# 参考: https://jade.run/guides/events/event-types
|
|
250
250
|
class Events:
|
|
251
|
-
"""Standard event name constants
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
251
|
+
"""Standard event name constants
|
|
252
|
+
|
|
253
|
+
事件注册方式指南:
|
|
254
|
+
|
|
255
|
+
1. 应用生命周期事件 - 通过 JadeUIApp 注册:
|
|
256
|
+
```python
|
|
257
|
+
from jadeui import JadeUIApp
|
|
258
|
+
app = JadeUIApp()
|
|
259
|
+
|
|
260
|
+
@app.on_ready
|
|
261
|
+
def handle_ready():
|
|
262
|
+
print("应用已就绪")
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
2. 窗口事件 - 通过 Window.on() 或专用装饰器注册:
|
|
266
|
+
```python
|
|
267
|
+
from jadeui import Window
|
|
268
|
+
|
|
269
|
+
window = Window(title="示例")
|
|
270
|
+
|
|
271
|
+
# 使用专用装饰器(推荐,有类型提示)
|
|
272
|
+
@window.on_resized
|
|
273
|
+
def handle_resize(width: int, height: int):
|
|
274
|
+
print(f"大小: {width}x{height}")
|
|
275
|
+
|
|
276
|
+
# 或使用通用 on() 方法
|
|
277
|
+
@window.on("window-moved")
|
|
278
|
+
def handle_move(x: int, y: int):
|
|
279
|
+
print(f"位置: ({x}, {y})")
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
3. IPC 事件 - 通过 IPCManager 注册:
|
|
283
|
+
```python
|
|
284
|
+
from jadeui.ipc import IPCManager
|
|
285
|
+
|
|
286
|
+
ipc = IPCManager()
|
|
287
|
+
|
|
288
|
+
@ipc.on("myChannel")
|
|
289
|
+
def handle_message(window_id: int, message: str):
|
|
290
|
+
return "收到"
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Window 专用装饰器列表:
|
|
294
|
+
- @window.on_resized -> WINDOW_RESIZED
|
|
295
|
+
- @window.on_moved -> WINDOW_MOVED
|
|
296
|
+
- @window.on_focused -> WINDOW_FOCUSED
|
|
297
|
+
- @window.on_blurred -> WINDOW_BLURRED
|
|
298
|
+
- @window.on_closing -> WINDOW_CLOSING (可阻止关闭)
|
|
299
|
+
- @window.on_state_changed -> WINDOW_STATE_CHANGED
|
|
300
|
+
- @window.on_navigate -> WEBVIEW_WILL_NAVIGATE (可阻止导航)
|
|
301
|
+
- @window.on_page_loaded -> WEBVIEW_DID_FINISH_LOAD
|
|
302
|
+
- @window.on_title_updated -> WEBVIEW_PAGE_TITLE_UPDATED
|
|
303
|
+
- @window.on_new_window -> WEBVIEW_NEW_WINDOW (可阻止新窗口)
|
|
304
|
+
- @window.on_download_started -> WEBVIEW_DOWNLOAD_STARTED (可阻止下载, v0.3.1+)
|
|
305
|
+
- @window.on_file_dropped -> FILE_DROP
|
|
306
|
+
- @window.on_js_result -> JAVASCRIPT_RESULT
|
|
307
|
+
"""
|
|
308
|
+
|
|
309
|
+
# ==================== 应用生命周期事件 ====================
|
|
310
|
+
# 注册方式: @app.on_ready, @app.on_all_windows_closed 等
|
|
311
|
+
APP_READY = "app-ready" # 应用初始化完成
|
|
312
|
+
WINDOW_ALL_CLOSED = "window-all-closed" # 所有窗口关闭
|
|
313
|
+
BEFORE_QUIT = "before-quit" # 应用即将退出
|
|
314
|
+
|
|
315
|
+
# ==================== 窗口事件 ====================
|
|
316
|
+
# 注册方式: @window.on("事件名") 或专用装饰器
|
|
317
|
+
WINDOW_CREATED = "window-created" # 窗口创建完成
|
|
318
|
+
APP_WINDOW_CREATED = "app-window-created" # 同上,别名
|
|
319
|
+
WINDOW_CLOSED = "window-closed" # 窗口已关闭
|
|
320
|
+
WINDOW_CLOSING = "window-closing" # 窗口即将关闭,可返回1阻止 -> @window.on_closing
|
|
321
|
+
WINDOW_RESIZED = "window-resized" # 窗口大小改变 -> @window.on_resized
|
|
322
|
+
WINDOW_STATE_CHANGED = "window-state-changed" # 最大化/还原状态改变 -> @window.on_state_changed
|
|
323
|
+
WINDOW_MOVED = "window-moved" # 窗口位置改变 -> @window.on_moved
|
|
324
|
+
WINDOW_FOCUSED = "window-focused" # 窗口获得焦点 -> @window.on_focused
|
|
325
|
+
WINDOW_BLURRED = "window-blurred" # 窗口失去焦点 -> @window.on_blurred
|
|
326
|
+
WINDOW_DESTROYED = "window-destroyed" # 窗口销毁
|
|
327
|
+
RESIZED = "resized" # 窗口大小改变(旧格式,兼容用)
|
|
328
|
+
|
|
329
|
+
# ==================== WebView 事件 ====================
|
|
330
|
+
# 注册方式: @window.on("事件名") 或专用装饰器
|
|
331
|
+
WEBVIEW_WILL_NAVIGATE = "webview-will-navigate" # 即将导航,可返回1阻止 -> @window.on_navigate
|
|
332
|
+
WEBVIEW_DID_START_LOADING = "webview-did-start-loading" # 开始加载
|
|
333
|
+
WEBVIEW_DID_FINISH_LOAD = "webview-did-finish-load" # 加载完成 -> @window.on_page_loaded
|
|
334
|
+
WEBVIEW_NEW_WINDOW = "webview-new-window" # 请求新窗口,可返回1阻止 -> @window.on_new_window
|
|
335
|
+
WEBVIEW_PAGE_TITLE_UPDATED = (
|
|
336
|
+
"webview-page-title-updated" # 标题更新 -> @window.on_title_updated
|
|
337
|
+
)
|
|
338
|
+
WEBVIEW_PAGE_ICON_UPDATED = "webview-page-icon-updated" # 图标更新
|
|
339
|
+
FAVICON_UPDATED = "favicon-updated" # 图标更新(别名)
|
|
340
|
+
JAVASCRIPT_RESULT = "javascript-result" # JS执行结果 -> @window.on_js_result
|
|
341
|
+
WEBVIEW_DOWNLOAD_STARTED = (
|
|
342
|
+
"webview-download-started" # 下载开始,可返回1阻止 -> @window.on_download_started (v0.3.1+)
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
# ==================== 文件事件 ====================
|
|
346
|
+
FILE_DROP = "file-drop" # 文件拖放到窗口 -> @window.on_file_dropped
|
|
347
|
+
|
|
348
|
+
# ==================== 主题事件 ====================
|
|
349
|
+
THEME_CHANGED = "theme-changed" # 系统主题改变
|
|
350
|
+
|
|
351
|
+
# ==================== 其他事件 ====================
|
|
352
|
+
UPDATE_WINDOW_ICON = "update-window-icon" # 更新窗口图标
|
|
353
|
+
IPC_MESSAGE = "ipc-message" # IPC 消息(通过 IPCManager 注册)
|
|
@@ -92,6 +92,10 @@ def _extract_js_result(d: Dict) -> tuple:
|
|
|
92
92
|
return (d.get("callbackId"), d.get("result"))
|
|
93
93
|
|
|
94
94
|
|
|
95
|
+
def _extract_download(d: Dict) -> tuple:
|
|
96
|
+
return (d.get("url", ""), d.get("filename", ""))
|
|
97
|
+
|
|
98
|
+
|
|
95
99
|
# Event extractors mapping: event_name -> (extractor, pass_dict_if_no_extractor)
|
|
96
100
|
_EVENT_EXTRACTORS: Dict[str, Callable[[Dict], tuple]] = {
|
|
97
101
|
# Window events
|
|
@@ -111,6 +115,7 @@ _EVENT_EXTRACTORS: Dict[str, Callable[[Dict], tuple]] = {
|
|
|
111
115
|
"webview-new-window": _extract_new_window,
|
|
112
116
|
"webview-page-title-updated": _extract_title,
|
|
113
117
|
"favicon-updated": _extract_favicon,
|
|
118
|
+
"webview-download-started": _extract_download, # v0.3.1+
|
|
114
119
|
# Other events
|
|
115
120
|
"javascript-result": _extract_js_result,
|
|
116
121
|
}
|
|
@@ -190,6 +195,8 @@ class Window(EventEmitter):
|
|
|
190
195
|
- disable_right_click (bool): Disable right-click menu (default: True)
|
|
191
196
|
- user_agent (str): Custom user agent string
|
|
192
197
|
- preload_js (str): JavaScript to run before page load
|
|
198
|
+
- allow_fullscreen (bool): Allow page to enter fullscreen (default: True)
|
|
199
|
+
Note: Requires JadeView DLL 0.2.1+
|
|
193
200
|
"""
|
|
194
201
|
super().__init__()
|
|
195
202
|
|
|
@@ -231,6 +238,7 @@ class Window(EventEmitter):
|
|
|
231
238
|
self._options.setdefault("disable_right_click", True)
|
|
232
239
|
self._options.setdefault("user_agent", None)
|
|
233
240
|
self._options.setdefault("preload_js", None)
|
|
241
|
+
self._options.setdefault("allow_fullscreen", True) # JadeView 0.2.1+
|
|
234
242
|
|
|
235
243
|
# Callback references to prevent garbage collection
|
|
236
244
|
self._callbacks: list = []
|
|
@@ -241,6 +249,10 @@ class Window(EventEmitter):
|
|
|
241
249
|
# 待应用的设置(在窗口创建前设置的属性)
|
|
242
250
|
self._pending_backdrop: Optional[str] = None
|
|
243
251
|
|
|
252
|
+
# JavaScript 执行回调注册表: callbackId -> callback
|
|
253
|
+
self._js_callbacks: Dict[int, Callable[[Any], Any]] = {}
|
|
254
|
+
self._js_callback_id_counter: int = 0
|
|
255
|
+
|
|
244
256
|
# 需要通过 jade_on 注册到 DLL 的事件列表
|
|
245
257
|
# 参考: https://jade.run/guides/events/event-types
|
|
246
258
|
JADE_ON_EVENTS = {
|
|
@@ -263,6 +275,7 @@ class Window(EventEmitter):
|
|
|
263
275
|
"webview-page-title-updated", # {"title": "新标题", "window_id": 窗口ID}
|
|
264
276
|
"webview-page-icon-updated", # JSON对象
|
|
265
277
|
"favicon-updated", # {"favicon": "图标URL"}
|
|
278
|
+
"webview-download-started", # {"url": "下载URL", ...} 可返回1阻止 (v0.3.1+)
|
|
266
279
|
# 其他事件
|
|
267
280
|
"theme-changed", # {}
|
|
268
281
|
"javascript-result", # {"callbackId": 回调ID, "result": 执行结果}
|
|
@@ -509,6 +522,52 @@ class Window(EventEmitter):
|
|
|
509
522
|
self._register_jade_on_event("webview-new-window", callback)
|
|
510
523
|
return callback
|
|
511
524
|
|
|
525
|
+
def on_js_result(self, callback: Callable[[int, Any], Any]) -> Callable[[int, Any], Any]:
|
|
526
|
+
"""Register a callback for JavaScript execution result events.
|
|
527
|
+
|
|
528
|
+
This listens to the native javascript-result event from the DLL.
|
|
529
|
+
For simpler usage, consider using execute_js() with a callback parameter.
|
|
530
|
+
|
|
531
|
+
Args:
|
|
532
|
+
callback: Function to call when JS execution completes.
|
|
533
|
+
- callback_id (int): The callback ID
|
|
534
|
+
- result (Any): The execution result
|
|
535
|
+
|
|
536
|
+
Example:
|
|
537
|
+
@window.on_js_result
|
|
538
|
+
def handle_js_result(callback_id: int, result):
|
|
539
|
+
print(f"JS result [{callback_id}]: {result}")
|
|
540
|
+
"""
|
|
541
|
+
self._register_jade_on_event("javascript-result", callback)
|
|
542
|
+
return callback
|
|
543
|
+
|
|
544
|
+
def on_download_started(
|
|
545
|
+
self, callback: Callable[[str, str], Union[bool, int, None]]
|
|
546
|
+
) -> Callable[[str, str], Union[bool, int, None]]:
|
|
547
|
+
"""Register a callback for download started events.
|
|
548
|
+
|
|
549
|
+
Return True or 1 to prevent the download.
|
|
550
|
+
|
|
551
|
+
Note:
|
|
552
|
+
Requires JadeView DLL version 0.3.1 or above.
|
|
553
|
+
|
|
554
|
+
Args:
|
|
555
|
+
callback: Function to call when a download starts.
|
|
556
|
+
- url (str): Download URL
|
|
557
|
+
- filename (str): Suggested filename
|
|
558
|
+
Returns: True/1 to prevent download, False/0/None to allow.
|
|
559
|
+
|
|
560
|
+
Example:
|
|
561
|
+
@window.on_download_started
|
|
562
|
+
def handle_download(url: str, filename: str):
|
|
563
|
+
print(f"Download: {filename} from {url}")
|
|
564
|
+
if filename.endswith(".exe"):
|
|
565
|
+
return True # Block exe downloads
|
|
566
|
+
return False # Allow download
|
|
567
|
+
"""
|
|
568
|
+
self._register_jade_on_event("webview-download-started", callback)
|
|
569
|
+
return callback
|
|
570
|
+
|
|
512
571
|
# ==================== Internal Event Registration ====================
|
|
513
572
|
|
|
514
573
|
def _register_jade_on_event(self, event: str, callback: Callable[..., Any]) -> None:
|
|
@@ -793,12 +852,16 @@ class Window(EventEmitter):
|
|
|
793
852
|
def set_fullscreen(self, fullscreen: bool) -> "Window":
|
|
794
853
|
"""Set fullscreen mode
|
|
795
854
|
|
|
855
|
+
Note:
|
|
856
|
+
Requires JadeView DLL version 0.2.1 or above.
|
|
857
|
+
|
|
796
858
|
Args:
|
|
797
859
|
fullscreen: Whether to enable fullscreen
|
|
798
860
|
|
|
799
861
|
Returns:
|
|
800
862
|
Self for chaining
|
|
801
863
|
"""
|
|
864
|
+
self._options["fullscreen"] = fullscreen
|
|
802
865
|
if self.id is not None:
|
|
803
866
|
self.dll_manager.set_window_fullscreen(self.id, 1 if fullscreen else 0)
|
|
804
867
|
return self
|
|
@@ -1025,29 +1088,109 @@ class Window(EventEmitter):
|
|
|
1025
1088
|
"""
|
|
1026
1089
|
return self.load_url(url)
|
|
1027
1090
|
|
|
1028
|
-
def execute_js(
|
|
1091
|
+
def execute_js(
|
|
1092
|
+
self,
|
|
1093
|
+
script: str,
|
|
1094
|
+
callback: Optional[Callable[[Any], Any]] = None,
|
|
1095
|
+
) -> "Window":
|
|
1029
1096
|
"""Execute JavaScript in the window
|
|
1030
1097
|
|
|
1031
1098
|
Args:
|
|
1032
1099
|
script: JavaScript code to execute
|
|
1100
|
+
callback: Optional callback function to receive the result.
|
|
1101
|
+
Will be called with the JavaScript execution result.
|
|
1102
|
+
Note: Requires registering javascript-result event handler.
|
|
1033
1103
|
|
|
1034
1104
|
Returns:
|
|
1035
1105
|
Self for chaining
|
|
1106
|
+
|
|
1107
|
+
Example:
|
|
1108
|
+
# Without callback
|
|
1109
|
+
window.execute_js("console.log('Hello')")
|
|
1110
|
+
|
|
1111
|
+
# With callback
|
|
1112
|
+
def on_result(result):
|
|
1113
|
+
print(f"Result: {result}")
|
|
1114
|
+
window.execute_js("1 + 1", callback=on_result)
|
|
1036
1115
|
"""
|
|
1037
1116
|
if self.id is not None:
|
|
1038
|
-
|
|
1117
|
+
if callback is not None:
|
|
1118
|
+
# 生成唯一的 callbackId 并注册回调
|
|
1119
|
+
self._js_callback_id_counter += 1
|
|
1120
|
+
callback_id = self._js_callback_id_counter
|
|
1121
|
+
self._js_callbacks[callback_id] = callback
|
|
1122
|
+
|
|
1123
|
+
# 确保已注册 javascript-result 事件处理器
|
|
1124
|
+
self._ensure_js_result_handler()
|
|
1125
|
+
|
|
1126
|
+
# 包装脚本以返回 callbackId
|
|
1127
|
+
wrapped_script = f"""
|
|
1128
|
+
(function() {{
|
|
1129
|
+
try {{
|
|
1130
|
+
var result = eval({repr(script)});
|
|
1131
|
+
if (typeof jade !== 'undefined' && jade.ipcSend) {{
|
|
1132
|
+
jade.ipcSend('__js_result__', JSON.stringify({{
|
|
1133
|
+
callbackId: {callback_id},
|
|
1134
|
+
result: result
|
|
1135
|
+
}}));
|
|
1136
|
+
}}
|
|
1137
|
+
}} catch (e) {{
|
|
1138
|
+
if (typeof jade !== 'undefined' && jade.ipcSend) {{
|
|
1139
|
+
jade.ipcSend('__js_result__', JSON.stringify({{
|
|
1140
|
+
callbackId: {callback_id},
|
|
1141
|
+
error: e.message
|
|
1142
|
+
}}));
|
|
1143
|
+
}}
|
|
1144
|
+
}}
|
|
1145
|
+
}})();
|
|
1146
|
+
"""
|
|
1147
|
+
self.dll_manager.execute_javascript(self.id, wrapped_script.encode("utf-8"))
|
|
1148
|
+
else:
|
|
1149
|
+
self.dll_manager.execute_javascript(self.id, script.encode("utf-8"))
|
|
1039
1150
|
return self
|
|
1040
1151
|
|
|
1041
|
-
def
|
|
1152
|
+
def _ensure_js_result_handler(self) -> None:
|
|
1153
|
+
"""确保已注册 JavaScript 结果处理器"""
|
|
1154
|
+
if "__js_result__" in self._registered_jade_events:
|
|
1155
|
+
return
|
|
1156
|
+
|
|
1157
|
+
from .ipc import IPCManager
|
|
1158
|
+
|
|
1159
|
+
ipc = IPCManager(self.dll_manager)
|
|
1160
|
+
|
|
1161
|
+
@ipc.on("__js_result__")
|
|
1162
|
+
def handle_js_result(window_id: int, message: str) -> int:
|
|
1163
|
+
try:
|
|
1164
|
+
data = _json_loads(message) if message else {}
|
|
1165
|
+
callback_id = data.get("callbackId")
|
|
1166
|
+
result = data.get("result")
|
|
1167
|
+
error = data.get("error")
|
|
1168
|
+
|
|
1169
|
+
if callback_id and callback_id in self._js_callbacks:
|
|
1170
|
+
callback = self._js_callbacks.pop(callback_id)
|
|
1171
|
+
if error:
|
|
1172
|
+
logger.error(f"JS execution error: {error}")
|
|
1173
|
+
callback(None)
|
|
1174
|
+
else:
|
|
1175
|
+
callback(result)
|
|
1176
|
+
except Exception as e:
|
|
1177
|
+
logger.error(f"Error handling JS result: {e}")
|
|
1178
|
+
return 1
|
|
1179
|
+
|
|
1180
|
+
self._registered_jade_events.add("__js_result__")
|
|
1181
|
+
logger.info("JavaScript result handler registered")
|
|
1182
|
+
|
|
1183
|
+
def eval(self, script: str, callback: Optional[Callable[[Any], Any]] = None) -> "Window":
|
|
1042
1184
|
"""Execute JavaScript (alias for execute_js)
|
|
1043
1185
|
|
|
1044
1186
|
Args:
|
|
1045
1187
|
script: JavaScript code to execute
|
|
1188
|
+
callback: Optional callback function to receive the result
|
|
1046
1189
|
|
|
1047
1190
|
Returns:
|
|
1048
1191
|
Self for chaining
|
|
1049
1192
|
"""
|
|
1050
|
-
return self.execute_js(script)
|
|
1193
|
+
return self.execute_js(script, callback)
|
|
1051
1194
|
|
|
1052
1195
|
def reload(self) -> "Window":
|
|
1053
1196
|
"""Reload the current page in the WebView
|
|
@@ -1104,8 +1247,17 @@ class Window(EventEmitter):
|
|
|
1104
1247
|
|
|
1105
1248
|
@property
|
|
1106
1249
|
def is_fullscreen(self) -> bool:
|
|
1107
|
-
"""Check if window is in fullscreen mode
|
|
1108
|
-
|
|
1250
|
+
"""Check if window is in fullscreen mode
|
|
1251
|
+
|
|
1252
|
+
Note:
|
|
1253
|
+
Requires JadeView DLL version 0.2.1 or above for accurate query.
|
|
1254
|
+
Falls back to local state tracking for older versions.
|
|
1255
|
+
"""
|
|
1256
|
+
if self.id is not None:
|
|
1257
|
+
# Try to query DLL first (JadeView 0.2.1+)
|
|
1258
|
+
if self.dll_manager.has_function("is_window_fullscreen"):
|
|
1259
|
+
return self.dll_manager.is_window_fullscreen(self.id) == 1
|
|
1260
|
+
# Fallback to local tracking
|
|
1109
1261
|
return self._options.get("fullscreen", False)
|
|
1110
1262
|
|
|
1111
1263
|
# ==================== Window Creation ====================
|
|
@@ -1166,6 +1318,7 @@ class Window(EventEmitter):
|
|
|
1166
1318
|
disable_right_click=self._options.get("disable_right_click", False),
|
|
1167
1319
|
ua=user_agent.encode("utf-8") if user_agent else None,
|
|
1168
1320
|
preload_js=preload_js.encode("utf-8") if preload_js else None,
|
|
1321
|
+
allow_fullscreen=self._options.get("allow_fullscreen", True),
|
|
1169
1322
|
)
|
|
1170
1323
|
|
|
1171
1324
|
# Prepare URL
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|