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.
Files changed (26) hide show
  1. {jadeui-0.2.0 → jadeui-0.3.2}/PKG-INFO +1 -1
  2. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/__init__.py +1 -1
  3. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/core/dll.py +1 -0
  4. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/core/types.py +3 -0
  5. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/downloader.py +22 -4
  6. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/events.py +103 -41
  7. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/window.py +159 -6
  8. {jadeui-0.2.0 → jadeui-0.3.2}/pyproject.toml +1 -1
  9. {jadeui-0.2.0 → jadeui-0.3.2}/.gitignore +0 -0
  10. {jadeui-0.2.0 → jadeui-0.3.2}/README.md +0 -0
  11. {jadeui-0.2.0 → jadeui-0.3.2}/examples/README.md +0 -0
  12. {jadeui-0.2.0 → jadeui-0.3.2}/examples/backdrop_demo/README.md +0 -0
  13. {jadeui-0.2.0 → jadeui-0.3.2}/examples/calculator/README.md +0 -0
  14. {jadeui-0.2.0 → jadeui-0.3.2}/examples/custom_template/README.md +0 -0
  15. {jadeui-0.2.0 → jadeui-0.3.2}/examples/router_demo/README.md +0 -0
  16. {jadeui-0.2.0 → jadeui-0.3.2}/examples/simple/README.md +0 -0
  17. {jadeui-0.2.0 → jadeui-0.3.2}/examples/vue_app/README.md +0 -0
  18. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/app.py +0 -0
  19. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/core/__init__.py +0 -0
  20. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/core/lifecycle.py +0 -0
  21. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/exceptions.py +0 -0
  22. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/ipc.py +0 -0
  23. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/router.py +0 -0
  24. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/server.py +0 -0
  25. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/templates/__init__.py +0 -0
  26. {jadeui-0.2.0 → jadeui-0.3.2}/jadeui/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jadeui
3
- Version: 0.2.0
3
+ Version: 0.3.2
4
4
  Summary: Python SDK for JadeView - Create desktop applications with WebView
5
5
  Project-URL: Homepage, https://jade.run
6
6
  Project-URL: Documentation, https://jade.run/python-sdk
@@ -67,7 +67,7 @@ from .router import Router
67
67
  from .server import LocalServer
68
68
  from .window import Backdrop, Theme, Window
69
69
 
70
- __version__ = "0.2.0"
70
+ __version__ = "0.3.2"
71
71
  __author__ = "JadeView Team"
72
72
  __license__ = "MIT"
73
73
 
@@ -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.0"
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
- # Extract all files
263
- zip_ref.extractall(install_dir)
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
- raise RuntimeError(f"解压后未找到 DLL 文件: {dll_path}")
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
- # App lifecycle events
254
- APP_READY = "app-ready"
255
- WINDOW_ALL_CLOSED = "window-all-closed"
256
- BEFORE_QUIT = "before-quit"
257
-
258
- # Window events
259
- WINDOW_CREATED = "window-created"
260
- APP_WINDOW_CREATED = "app-window-created"
261
- WINDOW_CLOSED = "window-closed"
262
- WINDOW_CLOSING = "window-closing"
263
- WINDOW_RESIZED = "window-resized"
264
- WINDOW_STATE_CHANGED = "window-state-changed"
265
- WINDOW_MOVED = "window-moved"
266
- WINDOW_FOCUSED = "window-focused"
267
- WINDOW_BLURRED = "window-blurred"
268
- WINDOW_DESTROYED = "window-destroyed"
269
- RESIZED = "resized" # 字符串形式
270
-
271
- # WebView events
272
- WEBVIEW_WILL_NAVIGATE = "webview-will-navigate"
273
- WEBVIEW_DID_START_LOADING = "webview-did-start-loading"
274
- WEBVIEW_DID_FINISH_LOAD = "webview-did-finish-load"
275
- WEBVIEW_NEW_WINDOW = "webview-new-window"
276
- WEBVIEW_PAGE_TITLE_UPDATED = "webview-page-title-updated"
277
- WEBVIEW_PAGE_ICON_UPDATED = "webview-page-icon-updated"
278
- FAVICON_UPDATED = "favicon-updated"
279
- JAVASCRIPT_RESULT = "javascript-result"
280
-
281
- # File events
282
- FILE_DROP = "file-drop"
283
-
284
- # Theme events
285
- THEME_CHANGED = "theme-changed"
286
-
287
- # Other events
288
- UPDATE_WINDOW_ICON = "update-window-icon"
289
-
290
- # IPC events
291
- IPC_MESSAGE = "ipc-message"
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(self, script: str) -> "Window":
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
- self.dll_manager.execute_javascript(self.id, script.encode("utf-8"))
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 eval(self, script: str) -> "Window":
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
- # Note: DLL might not provide this query, track locally
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "jadeui"
3
- version = "0.2.0"
3
+ version = "0.3.2"
4
4
  description = "Python SDK for JadeView - Create desktop applications with WebView"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
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