Skip to content

Releases: xiaosuawa/QtWebView

v0.6.0rc10

v0.6.0rc10 Pre-release
Pre-release

Choose a tag to compare

@xiaosuawa xiaosuawa released this 13 Jul 10:46

v0.6.0rc10

⚠️ Release Candidate — API may still change before the final v0.6.0.

Reworks the transparent host window behind the WebView. rc9 and earlier faked
transparency with a WS_EX_LAYERED window kept alive by UpdateLayeredWindow,
GDI DIB sections, WM_SIZE throttling timers and WM_DWMCOMPOSITIONCHANGED
handling. That whole ctypes/GDI machinery is gone, replaced by a Qt-native
DirectComposition path. Visible behaviour is unchanged — same transparency, same
resize handling, fewer moving parts.

♻️ Rework

  • _AnchorWindow → QRhi Direct3D 11 transparent swapchain. The host is now a
    QWindow with a Direct3DSurface and an alpha-enabled swapchain
    (SurfaceHasPreMulAlpha); Qt builds the full DirectComposition chain and every
    frame clears to (0,0,0,0). The DWM composites that transparent surface, so
    transparent=True content shows the Qt widgets behind it and the black-edge
    flash on resize is absorbed — without any layered-window / GDI hacks or
    per-frame timers (the loop only runs on expose/resize).

⚠️ Requirements / Breaking

  • Windows transparency now requires PySide6 on Windows 8+. The RHI backend
    uses QRhi, which is Qt6-only and — among the Qt6 bindings — exposed only by
    PySide6; DirectComposition needs Windows 8+.
  • Auto fallback. The QRhi import is guarded, so
    import qtwebview2 still succeeds under PyQt6 / PyQt5 / PySide2. On those
    bindings the host falls back to an opaque plain QWindow (transparency and
    resize-flicker suppression disabled) and logs a warning at construction —
    instead of crashing at import.
  • macOS is unaffected — WKWebView handles transparency itself.

🪶 v0.6.0rc10 更新内容

⚠️ 候选版本 — API 在正式 v0.6.0 发布前仍可能调整。

重写了 WebView 背后的透明宿主窗口。rc9 及更早版本用 WS_EX_LAYERED 分层窗口
配合 UpdateLayeredWindow、GDI DIB、WM_SIZE 节流定时器和
WM_DWMCOMPOSITIONCHANGED 处理来伪造透明。这套 ctypes/GDI 机器全部移除,改用
Qt 原生的 DirectComposition 路径。可见行为不变 —— 一样的透明、一样的 resize
处理,但内部零件更少。

♻️ 重构

  • _AnchorWindow → QRhi Direct3D 11 透明 swapchain。 宿主现在是带
    Direct3DSurface 和 alpha swapchain(SurfaceHasPreMulAlpha)的 QWindow;
    Qt 自动搭好整条 DirectComposition 链,每帧清成 (0,0,0,0)。DWM 合成这个透明
    表面,于是 transparent=True 的内容能透出后面的 Qt 控件,resize 时的黑边闪烁
    也被吸收 —— 不再需要任何分层窗口/GDI hack 或每帧定时器(渲染循环只在
    expose/resize 时跑)。

⚠️ 要求 / 破坏性变更

  • Windows 透明现在需要 PySide6 且系统为 Windows 8+。 RHI 后端用到 QRhi,它
    是 Qt6 独有、且在 Qt6 各绑定中仅 PySide6 暴露;DirectComposition 需 Windows 8+。
  • 自动降级 QRhi 导入已加守卫,PyQt6 / PyQt5 / PySide2 下
    import qtwebview2 仍能成功。这些绑定下宿主退化为不透明的普通 QWindow
    (透明与 resize 抗闪失效),并在构造时打印一条警告 —— 而不是在导入时崩溃。
  • macOS 不受影响 —— 透明由 WKWebView 自身处理。

Full Changelog: v0.6.0rc9...v0.6.0rc10

v0.6.0rc9

v0.6.0rc9 Pre-release
Pre-release

Choose a tag to compare

@xiaosuawa xiaosuawa released this 16 Jun 16:59

v0.6.0rc9

Hotfix on top of rc8.

🐛 Fix

  • api.call() broken — window.qtwebview.api.call("funcName", ...) threw TypeError because the Proxy referenced a non-existent target.api instead of itself. Fixed by capturing the proxy in a variable before assignment.

v0.6.0rc8

v0.6.0rc8 Pre-release
Pre-release

Choose a tag to compare

@xiaosuawa xiaosuawa released this 16 Jun 16:03

v0.6.0rc8

Hotfix on top of rc7.

🐛 Fix

  • WebView not properly torn down on quit — closeEvent is only called when the window is closed via the window manager. QApplication.quit() or process exit could skip it, causing the Rust webview to be dropped without flushing localStorage. Added QApplication.aboutToQuit as a safety net that fires on any exit path.

🪶 v0.6.0rc8

rc7 的热修复。

🐛 修复

  • 退出时 WebView 未正确销毁 — closeEvent 仅在窗口管理器关闭时触发,QApplication.quit() 或进程退出可能跳过它,导致 Rust webview 未被正确释放、localStorage 数据丢失。新增 QApplication.aboutToQuit 兜底,保证所有退出路径都能正确清理。

v0.6.0rc7

v0.6.0rc7 Pre-release
Pre-release

Choose a tag to compare

@xiaosuawa xiaosuawa released this 16 Jun 15:56

What's New in v0.6.0rc7

This is likely the last release candidate before v0.6.0 stable.

✨ New Features

  • 🧩 Enums — PageLoadEvent, NewWindowResponse, DragDropEvent are now proper Python Enum types (re-exported from wryview). No more magic strings in callbacks.
  • 🔒 https_scheme (Windows, default True) — custom protocol pages are now secure contexts by default. Service Workers, Geolocation, Web Crypto all work out of the box.
  • 📥 Download handlers — download_started_handler(url, suggested_path) → bool|str and download_completed_handler(url, saved_path, success: bool).
  • 🖱️ context_menus — enable/disable native right-click context menu (Windows).
  • 🌐 proxy — {"type": "http"|"socks5", "host": "...", "port": "..."}.
  • 📜 initialization_script — three states: default (injects JS bridge + fullscreen), None (skip all injected scripts), str (custom script). Use with caution — setting to None or custom breaks the JS bridge and fullscreen handling.
  • 🔧 wsgi_port — specify a fixed TCP port for wsgi_scheme="localhost" mode.
  • 🔍 is_devtools_open() — check if DevTools is currently open.
  • back_forward_gestures gesture navigation (cross-platform, not macOS only).

⚠️ Breaking Changes

  • Callback return types now use enums:
    • new_window_handler → NewWindowResponse (was str)
    • page_loaded signal → (PageLoadEvent, url) (was (str, str))
    • drag_drop_handler → (DragDropEvent, paths, position) (was (str, ...))
  • initialization_done signal no longer carries (success, error_msg) — just ().
  • domContentLoaded signal removed — use page_loaded (event PageLoadEvent.Finished) instead.
  • user_data_folder default changed to sentinel-based tri-state: omit = auto-generate, None = skip, str = custom path.
  • incognito and user_data_folder are now independent — incognito no longer overrides the data directory.

🐛 Fixes

  • JS Bridge: error responses no longer misrouted to the wrong pending Promise.
  • JS Bridge: window.qtwebview.api.call("funcName", ...) meta-call now handled in JS, no Python round-trip.
  • web_message_received signal no longer emitted twice for non-JSON IPC messages.
  • GDI resource leak: _AnchorWindow now cleans up DIB section, DC, and bitmap on close.
  • Hide & show: DWM layered surface restored via WM_SHOWWINDOW (more robust than showEvent).
  • closeEvent order documented — child HWND dropped before parent anchor.

📦 Dependencies

  • wryview bumped to ~=0.4.0.

🪶 v0.6.0rc7 更新内容

这很可能是 v0.6.0 正式版前的最后一个候选版本。

✨ 新特性

  • 🧩 枚举类型 — PageLoadEvent、NewWindowResponse、DragDropEvent 替代了所有魔术字符串(从 wryview 转发)。
  • 🔒 https_scheme(Windows,默认 True)— 自定义协议页面默认已是安全上下文,Service Worker 等开箱即用。
  • 📥 下载回调 — download_started_handler / download_completed_handler。
  • 🖱️ context_menus — 原生右键菜单开关(Windows)。
  • 🌐 proxy — 代理配置 {"type": "http"|"socks5", "host": "...", "port": "..."}。
  • 📜 initialization_script — 三态:默认注入桥接+全屏 / None 跳过 / 字符串自定义。设 None 或自定义会破坏 JS 桥接和全屏,需手动重实现。
  • 🔧 wsgi_port — localhost 模式下指定固定端口。
  • 🔍 is_devtools_open() — 查询 DevTools 是否打开。
  • back_forward_gestures 手势导航(跨平台,不仅 macOS)。

⚠️ 破坏性变更

  • 回调改用枚举:
    • new_window_handler → NewWindowResponse
    • page_loaded 信号 → (PageLoadEvent, url)
    • drag_drop_handler → (DragDropEvent, paths, position)
  • initialization_done 信号不再携带 (success, error_msg)。
  • domContentLoaded 信号已移除,用 page_loaded(PageLoadEvent.Finished)替代。
  • user_data_folder 改为三态(不传=自动生成 / None=跳过 / 字符串=自定义路径)。
  • incognito 与 user_data_folder 解耦——incognito 不再覆盖数据目录。

🐛 修复

  • JS Bridge:错误响应不再路由到错误的 Promise。
  • JS Bridge:api.call("funcName") 元调用改为 JS 侧处理。
  • web_message_received 信号不再重复发射。
  • _AnchorWindow GDI 泄漏:关闭时正确释放 DIB、DC 和位图。
  • 隐藏/恢复:改用 WM_SHOWWINDOW 恢复 DWM 分层表面。
  • closeEvent 顺序注释。

📦 依赖

  • wryview 升级至 ~=0.4.0。

v0.6.0rc6

v0.6.0rc6 Pre-release
Pre-release

Choose a tag to compare

@xiaosuawa xiaosuawa released this 12 Jun 13:15

⚠️ Release Candidate — API may still change before the final v0.6.0.
⚠️ 候选版本 — API 在正式 v0.6.0 发布前仍可能调整。


🐛 Fixes / 修复

  • hide/show 后无法点击 — click-through after hide/show cycle。 窗口隐藏再显示后 DWM 丢弃了 layered surface(大小未变,不触发 WM_SIZE),导致全区域 alpha=0 点击穿透。修复:_AnchorWindow.showEvent 中立即调用 _fill_layered() 重建 alpha=1 表面。

    After hiding and re-showing the window, the DWM discards the layered surface. No WM_SIZE is sent (the size didn't change), so the entire surface stays alpha=0 and clicks pass through. Fixed by calling _fill_layered() in _AnchorWindow.showEvent to immediately rebuild the alpha=1 surface.

  • RDP / DWM 重启后点击穿透 — click-through after RDP disconnect or DWM restart。 远程桌面连接/断开、DWM 重启、主题切换等场景下 layered surface 可能被丢弃。修复:nativeEvent 中新增 WM_DWMCOMPOSITIONCHANGED(0x031E)处理,立即重建表面。

    The layered surface may be discarded after RDP connect/disconnect, DWM restart, or theme toggle. Fixed by handling WM_DWMCOMPOSITIONCHANGED (0x031E) in nativeEvent and rebuilding the surface immediately.

  • 全屏窗口遗失 — lost fullscreen window。 全屏状态下点击主窗口后全屏窗口可能被盖在后面找不到。修复:全屏窗口去掉了 Tool 标志(有任务栏入口,可被找到),showEvent 中自动 raise_() + activateWindow()。全屏窗口跟随主窗口 hide/show 联动。

    The fullscreen window could get lost behind the main window. Fixed by removing the Tool flag (so it appears in the taskbar), auto-raising it when the main window is shown, and syncing hide/show with the main window.

  • 全屏 FramelessWindowHint — 全屏窗口不再使用 Tool 标志,改用 FramelessWindowHint。

🔧 Improvements / 改进

  • 日志增强 Enhanced logging。 所有日志消息现在包含 widget 对象引用 [<QtWebViewWidget 0x...>],多 webview 实例时可区分来源。新增关键节点日志:WebView 创建模式/平台/耗时、pending calls 刷新、JS API 调用、WSGI 请求、关闭。

    All log messages now include the widget object reference [<QtWebViewWidget 0x...>] for multi-webview traceability. Added log points: WebView creation mode/platform/timing, pending call flush, JS API calls, WSGI requests, close.


Full Changelog: https://github.com/xiaosuawa/QtWebView/commits/v0.6.0rc6

v0.6.0rc5

v0.6.0rc5 Pre-release
Pre-release

Choose a tag to compare

@xiaosuawa xiaosuawa released this 12 Jun 09:43

⚠️ Release Candidate — API may still change before the final v0.6.0.
⚠️ 候选版本 — API 在正式 v0.6.0 发布前仍可能调整。


🐛 Fixes / 修复

  • Windows resize black-edge flicker — Windows resize 黑边闪烁。 窗口缩放时 WebView 边缘出现短暂黑色闪烁。根因:DWM layered surface 扩展后新区域 alpha=0,且 createWindowContainer 阻止了 _AnchorWindow 的 paintEvent 触发。修复方案:_AnchorWindow 监听 WM_SIZE / WM_EXITSIZEMOVE,直接调用 Win32 UpdateLayeredWindow API 提交 per-pixel alpha=1 的 32-bit BGRA 背景层 bitmap,绕过 Qt 的 paint 系统。调用频率节流至 ~30fps 避免 DWM 重合成导致 WebView 内容闪烁。缓存 DIB section 避免每次 resize 重建 GDI 对象。

    The WebView showed a brief black flash at the edges during window resize. Root cause: the DWM layered surface defaults new areas to alpha=0, and createWindowContainer suppresses _AnchorWindow's paintEvent. Fix: _AnchorWindow listens for WM_SIZE / WM_EXITSIZEMOVE and calls Win32 UpdateLayeredWindow directly to submit a per-pixel alpha=1 32-bit BGRA background bitmap — bypassing Qt's paint machinery entirely. Calls are throttled to ~30 fps to prevent DWM re-composition flicker of the WebView content. The DIB section is cached to avoid GDI object churn.

🔧 Internal / 内部重构

  • 模块拆分 Module split。 widget.py(~960 行)拆为三个文件:_bridge.py(JS Bridge:Signals、DictJsBridge、JS 脚本)、_anchor.py(_AnchorWindow:Windows layered surface resize 修复)、widget.py(QtWebViewWidget:~660 行)。下划线前缀表示内部模块,不暴露给用户。

    widget.py (~960 lines) split into three modules: _bridge.py (JS Bridge: Signals, DictJsBridge, JS payloads), _anchor.py (_AnchorWindow: Windows layered surface resize fix), widget.py (QtWebViewWidget: ~660 lines). Underscore prefix denotes internal modules — not part of the public API.


Full Changelog: v0.6.0rc4...v0.6.0rc5

v0.6.0rc4

v0.6.0rc4 Pre-release
Pre-release

Choose a tag to compare

@xiaosuawa xiaosuawa released this 11 Jun 02:49

⚠️ Release Candidate — API may still change before the final v0.6.0.
⚠️ 候选版本 — API 在正式 v0.6.0 发布前仍可能调整。

修复mac上启动时webview错位的问题
Fix the issue of WebView misalignment on startup on Mac


Full Changelog: v0.6.0rc3...v0.6.0rc4

v0.6.0rc3

v0.6.0rc3 Pre-release
Pre-release

Choose a tag to compare

@xiaosuawa xiaosuawa released this 10 Jun 10:50

⚠️ Release Candidate — API may still change before the final v0.6.0.
⚠️ 候选版本 — API 在正式 v0.6.0 发布前仍可能调整。


✨ New / 新增

  • Fullscreen API — 新增 fullscreen_handler 参数,通过注入 JS 拦截
    requestFullscreen / exitFullscreen。默认实现将 webview 容器 reparent
    到独立的全屏 QWidget(仅 anchor 模式)。
  • wsgi_executor 支持传入 Executor — 除了 int(线程数),现在也可以
    传入 concurrent.futures.Executor 实例,方便共享线程池。
  • new_window_handler 默认值 — 默认用系统浏览器打开 URL 并返回 'deny',
    不再需要手动提供。
  • _resize_webview() — widget resize 时自动同步 webview 尺寸。

🐛 Fixes / 修复

  • Windows 点击穿透 — 修复 _AnchorWindow 在 Windows 上使用
    WA_TranslucentBackground 导致的交互失效:createWindowContainer 嵌入后
    paintEvent 不再触发,扩展区域的 alpha-1 填充缺失,DWM hit-test 失败,
    点击穿透到桌面。修复方案:Windows 上去掉 WA_TranslucentBackground。
    macOS 保留(无 per-pixel hit-test 问题)。

🔧 Improvements / 改进

  • WSGI localhost 模式重构为通过线程池派发请求,与 custom protocol 模式
    共享同一个 wsgi_executor。
  • 移除 closeEvent 中不必要的 _wsgi_executor.shutdown(),避免破坏
    用户传入的共享 executor。
  • 导入整理,移除未使用的 QPainter / QColor。

Full Changelog: v0.6.0rc2...v0.6.0rc3

v0.6.0rc2

v0.6.0rc2 Pre-release
Pre-release

Choose a tag to compare

@xiaosuawa xiaosuawa released this 08 Jun 07:15

⚠️ Release Candidate — API may still change before the final v0.6.0.
⚠️ 候选版本 — API 在正式 v0.6.0 发布前仍可能调整。


🏗️ Architecture / 架构变更

WebView 嵌入方式从直接子窗口改为独立锚点窗口 + fromWinId + createWindowContainer。

The WebView is now hosted inside an independent anchor QWindow (floating, frameless, tool window) rather than as a direct native child of the Qt widget. The anchor is wrapped via QWindow.fromWinId() + createWindowContainer(), so Qt manages geometry automatically — no manual set_bounds, no resizeEvent syncing.

核心收益 / Key benefit:

  • 锚点窗口独立于 Qt widget 树 —— 父窗口 close/show 不会销毁 WebView。托盘应用不再需要担心 WebView 消失。
    The anchor window is independent of the Qt widget tree — parent window close/show cycles don't kill the WebView. Tray apps just work.

  • wry build() 自动管理大小 —— as_child=False 让 wry 通过 WM_SIZE 子类化自动填满锚点,无需手动调用 set_bounds。
    as_child=False lets wry's build() auto-fill the anchor via WM_SIZE subclassing — no manual set_bounds.

✨ New / 新增

  • native_child: bool = False — 设为 True 恢复旧行为(WebView 作为 widget 的直接原生子窗口)。默认 False 使用新锚点方案。
    Set to True to restore the old behaviour (WebView as a direct native child of the widget). Default False uses the new anchor scheme.

🗑️ Removed / 移除

  • 不再需要 WA_NativeWindow(默认路径下)。锚点窗口自己管理原生句柄。
    WA_NativeWindow no longer needed in the default path. The anchor window manages its own native handle.

📝 Docs / 文档

  • README 新增 System Tray / Hide & Show 章节(中英双语),说明 closeEvent 中应使用 event.ignore() + hide() 而非默认 close()。
    Added System Tray / Hide & Show section (EN & ZH) explaining event.ignore() + hide() instead of close() in tray apps.

📦 Dependencies / 依赖

  • wryview ~=0.2.0 → ~=0.3.0

Full Changelog: v0.6.0rc1...v0.6.0rc2

v0.6.0rc1

v0.6.0rc1 Pre-release
Pre-release

Choose a tag to compare

@xiaosuawa xiaosuawa released this 07 Jun 09:42

⚠️ Release Candidate — API may still change before the final v0.6.0.
⚠️ 候选版本 — API 在正式 v0.6.0 发布前仍可能调整。

🔄 Complete rewrite of the backend — pythonnet/.NET replaced by wryview (Rust/PyO3).
🔄 后端完全重写 — pythonnet/.NET 替换为 wryview (Rust/PyO3)。


💥 Breaking Changes / 破坏性变更

Backend switched to wryview v0.2.0 — a Rust/PyO3 binding for wry, the WebView engine used by Tauri. The old pythonnet + .NET CLR + WebView2 WinForms stack is fully removed.

后端切换为 wryview v0.2.0 — Rust/PyO3 的 wry 绑定。旧的 pythonnet + .NET CLR + WebView2 WinForms 技术栈已完全移除。

v0.5.x v0.6.0
QtWebView2Widget QtWebViewWidget (旧名保留为 deprecated 别名)
QtWebView2ApiBridge QtWebViewSignals
QtWebView2JsBridge QtWebViewJsBridge
handle_new_window=True/False new_window_handler=lambda url: "allow"/"deny"
wsgi_host_name="myapp.local" wsgi_scheme="qtwebview"
no_local_storage=True incognito=True
context_menus 已移除
fullscreen_support 已移除(尚未实现)
browser_executable_folder 已移除(wry 不支持)
init_settings_hook 已移除
user_data_folder ✅ 仍支持
wsgi_executor ✅ 仍支持(线程池大小)
requires-python >= 3.9 >= 3.10(与 wryview 一致)

所有已删除的旧文件:_dotnet_bridge.py、wsgi_server.py、exceptions.py、utils.py、logger.py、lib/(.NET 程序集)、__pyinstaller__/。

✨ New Features / 新功能

  • 🌍 跨平台 — Windows (WebView2)、macOS (WKWebView)、Linux (WebKitGTK)。统一 API。
  • ⚡ 更快的启动速度 — 无 .NET CLR
  • 🍪 完整的 wry API — Cookie 管理 (cookies、cookies_for_url、set_cookie、delete_cookie)、DevTools (open_devtools、close_devtools、is_devtools_open)、缩放、打印、拖放、代理、自定义请求头
  • 📦 新的构造参数
    • html — 直接加载 HTML 字符串
    • headers — 自定义 HTTP 请求头(dict 或 list of tuples)
    • navigation_handler — 导航拦截回调(返回 False 阻止)
    • incognito — 无痕模式
    • autoplay — 媒体自动播放
    • javascript_enabled — 启用/禁用 JavaScript
    • hotkeys_zoom — Ctrl+/- 缩放快捷键
    • drag_drop_handler — 拖放事件处理
  • eval_js(script) — 新的便捷别名,等价于 evaluate_js(script)
  • url() — 获取当前页面 URL
  • close_devtools() — 关闭 DevTools 窗口
  • cookies_for_url(url) — 获取特定 URL 的 cookie
  • set_background_color(r, g, b, a) — 动态设置背景色
  • JS Bridge 命名统一 — JS 端 window.qtwebview.api 和 window.qtwebview2 均可使用
  • incognito=True + user_data_folder 冲突警告 — 同时设置时输出 warning 日志

🐛 Fixes / 修复

  • 修复了 _pending_calls 重复声明的问题
  • 修复了旧版 README 迁移指南中多处不准确描述
  • 修复了 LICENSE 链接中的 GitHub 用户名不一致问题

📦 Packaging / 打包

  • 移除 __pyinstaller__/ hook(不再需要收集 .NET 程序集)
  • wryview 的 .pyd / .so 由 PyInstaller/Nuitka 自动收集
  • 如遇问题,在 PyInstaller 中添加 hiddenimports=['wryview._core']

Full Changelog: v0.5.0...v0.6.0rc1