Skip to content

Commit 497ca3d

Browse files
r0x0rfjmarsontdeckTroy DeckCopilot
authored
Maintenance: bug fixes, type hints, and documentation corrections (#1836)
* [Qt] Fix confirmation dialogs only rendering one button QMessageBox.question() was called with a single button flag as both the buttons and defaultButton arguments, so QMessageBox silently dropped the button that wasn't part of `buttons`. As a result, create_confirmation_dialog() could never return True (no Ok button was ever shown) and the close-confirmation dialog could never prevent a window from closing (no No button was ever shown). * [Core] Fix load_url() leaking a new HTTP server on every call load_url() assigned the newly started server to self.server instead of self._server, so self._server was never updated and stayed None. Since the reuse check reads self._server, every subsequent call to load_url() with a local/app URL spun up a brand-new BottleServer (new thread + listening socket) and orphaned the previous one instead of reusing it. * [Core] Fix custom server class being silently discarded Window.__init__ stored the user-supplied server class in self._server and then immediately overwrote it with None two lines later (that slot is meant to hold the running server instance, not the class). _initialize() then always passed self._server (always None) to http.start_server(), so a custom server= class passed to Window()/ create_window() was never actually used. The class is now kept in its own self._server_class attribute. * [Core] Fix mutable default arguments and bad server_args default menu=[], server_args={}/dict and localization={} defaults on Window, Menu, start() and create_window() were shared mutable objects: two windows created without an explicit menu= shared and mutated the same list, and start()'s server_args default was observably mutated in place (keyfile/certfile), corrupting a later start() call made without server_args. Window._initialize() also defaulted server_args to the dict class itself rather than an empty dict, raising TypeError on **dict when no server_args were supplied anywhere. All of these now use None sentinels normalized to a fresh list/dict per call. * [Core] Fix dead server-reuse check in create_window() create_window()'s dynamic-window path checked `server.is_running`, but `server` is a class (type[http.ServerType]), not an instance, so this read the unbound `is_running` property object -- always truthy. Combined with operator precedence, `is_app(url) or is_local_url(url) and not server.is_running` reduced to just `is_app(url)`, so windows created for local URLs from a background thread after start() never reused an already-running server. Now checks the actual global_server instance for whether a server is already running. * [DOM] Escape strings interpolated into generated JS dom.py, element.py and classlist.py built JS source by interpolating selectors, ids, text content, class names and event names directly into quoted JS string literals without escaping. Any value containing a quote character (a normal CSS selector like input[type="text"], or ordinary text like "Don't") broke the generated script; a value drawn from untrusted page content could inject arbitrary JS. propsdict.py already used webview.util.escape_string for this; the other DOM files now do too. * [DOM] Fix backwards escaping for attribute JSON payload PropsDict.__init__'s Attribute branch escaped individual key/value strings before running them through json.dumps, then embedded the result raw in a single-quoted JS literal. This left the JSON text's own quotes unescaped for the JS-string context (breaking/injecting into JSON.parse('...')) and double-escaped backslashes (corrupting round-tripped values). Now matches the correct pattern already used by the Style branch and __set_attribute/__set_style: escape the whole json.dumps() output once, after serialization. * [Core] Escape initial state JSON injected into state.js load_js_files() embedded json.dumps(window.state) directly into state.js's `var initialState = '%(state)s'` template. json.dumps does not escape single quotes, so any window.state value containing an apostrophe (e.g. a name like "O'Brien") broke pywebview's own injected startup script, preventing pywebview from initializing in the page. Now escaped the same way propsdict.py escapes its JSON payloads before embedding them in a single-quoted JS literal. * [DOM] Fix event handler cleanup on Element.remove() The JS injected by remove() referenced the undefined identifier handler_id instead of the handlerId closure parameter, throwing a ReferenceError for every removed element that had at least one registered event handler. Since this failing script ran before self._exists was set to False, and remove() is wrapped by @_exists (which swallows JavascriptException), the Python object could keep believing the removed node still existed, and pywebview._eventHandlers entries for the removed element were never cleaned up. * [DOM] Fix off() removing the whole element registry entry off() unconditionally deleted the element from window.dom._elements, regardless of whether other event handlers were still registered on it. This broke still-attached listeners for other events (pywebviewEventHandler looks the element up via dom._elements.get() and silently no-ops if missing) and raised an uncaught KeyError on a second off() call for a different callback on the same element, since the registry entry was already gone. Now only removed once no handlers remain tracked for the element. * [DOM] Key event handler ids by (event, callback), not callback alone _event_handler_ids was keyed by the Python callback only. Registering the same callable for two different events on the same element (e.g. on('click', cb) then on('mouseover', cb)) made the second on() call silently overwrite the tracked handler_id for the first, so a subsequent off(event, callback) could remove/detach the wrong handler_id and leave a phantom listener attached in the page. * [DOM] Fix DOMEvent.__sub__ raising on an unregistered handler __sub__ (event.event - handler) called list.remove() unguarded, raising an uncaught ValueError if the handler was never registered. __isub__ (event.event -= handler) already guarded this with an `if item in self._items` check and a warning log; __sub__ now does the same for consistency. * [Qt] Fix request_sent header values being replaced with their keys RequestInterceptor.interceptRequest() built the headers dict with k.data().decode('utf-8') for both the key and the value expression (reusing k instead of v), so every header delivered to the request_sent event had its value replaced with its own key name (e.g. {'User-Agent': 'User-Agent'}) instead of the real header value. * [Qt] Fix evaluate_js() hanging forever on the PySide TypeError fallback on_evaluate_js()'s except TypeError branch (hit on some PySide2/ PySide6 versions where runJavaScript() rejects a Python callback) fired the script with no result callback at all, so return_result() was never invoked and evaluate_js()'s result_semaphore.acquire() blocked forever. Now explicitly releases the wait with no result instead of silently dropping it. * [GTK] Fix dialog flags using bitwise AND instead of OR Gtk.DialogFlags.MODAL and DESTROY_WITH_PARENT are disjoint bit flags, so ANDing them together always produced 0. Every close-confirmation dialog, create_confirmation_dialog(), and message_box() dialog was therefore created non-modal (the user could interact with the main window while it was open) and without DESTROY_WITH_PARENT (left orphaned if the parent window was destroyed while it was showing). * [EdgeChromium] Fix crash on 3-digit hex background_color DefaultBackgroundColor parsing assumed a 6-hex-digit color string. A valid CSS shorthand like background_color='#FFF' made the [4:6] slice empty, so int('', 16) raised ValueError and crashed window creation. GTK and WinForms already handle 3-digit hex correctly; EdgeChromium now expands it to 6 digits first, same as GTK's _hex_to_rgba(). * [Winforms] Fix crash when .NET Framework registry key is missing _is_chromium() left net_key unbound if winreg.OpenKey() raised (e.g. the NDP\\v4\\Full key is absent on minimal/Server Core installs). The broad except swallowed that, but the finally block unconditionally called winreg.CloseKey(net_key), raising UnboundLocalError. Since _is_chromium() runs unconditionally at module import, this crashed the whole Winforms backend on import. net_key is now initialized to None and only closed if it was actually opened. * [CEF] Fix evaluate_js() deadlock on invalid JSON and ignored parse_json JSBridge.return_result() called json.loads(result) with no error handling; if the page returned something that wasn't valid JSON, the exception propagated out of the CEF-invoked callback before eval_events[uid].set() ran, so Browser.evaluate_js()'s unconditional .wait() blocked forever. return_result() also always attempted to JSON-decode the result regardless of the parse_json argument passed to evaluate_js(), unlike every other backend. parse_json is now tracked per call and return_result() falls back to the raw result (instead of raising) on a decode failure, matching gtk.py/mshtml.py/ edgechromium.py. * [GTK] Fix evaluate_js() hanging forever if the window closes mid-call self.js_results was initialized but never written to; close_window() looped over it to release any blocked evaluate_js() callers, but it was always empty, since the real evaluate_js() blocked on a purely local result_semaphore untracked anywhere. A call to evaluate_js() from a background thread would hang forever if the window/webview was torn down before the JS callback fired. evaluate_js() now registers its semaphore in self.js_results for the duration of the call so close_window() can actually release it. Also iterate over a copy of self.js_results.values() in close_window(), since a woken evaluate_js() call removes its own entry concurrently while the close loop is still iterating. * [Winforms/EdgeChromium/MSHTML] Fix evaluate_js() hanging forever on close EdgeChrome.evaluate_js() runs ExecuteScriptAsync().ContinueWith(...) and blocks on a purely local semaphore untracked anywhere; the instance's js_result_semaphore (which winforms.py's on_close/ destroy_window released on window close) was never the object the call actually waited on. If the window closed before the async script completed, the calling thread hung forever. MSHTML had the same dead-semaphore pattern, though its evaluate_js is synchronous via Control.Invoke so the practical risk there was lower. Both classes now register their per-call semaphore in a js_results dict (mirroring the same fix already applied to gtk.py), and winforms.py's on_close releases every pending entry instead of a single disconnected semaphore. destroy_window()'s separate release call is removed: i.Close() synchronously raises FormClosed (wired to on_close) before Invoke() returns, so that second release was already redundant (a double-release bug in its own right). * [CEF] Fix evaluate_js() hanging forever if the window closes mid-call close_window() closed the browser and removed the instance without touching eval_events, so a background thread blocked in evaluate_js()'s unbounded event.wait() (no timeout) would hang forever if the window was closed before the JS callback fired. close_window() now sets every pending event first. evaluate_js() also now uses .get()/.pop(..., None) when reading the JSON result back, since a call unblocked this way never gets a real result from JSBridge.return_result(). * [Cocoa] Fix get_cookies() deadlock for windows created without a URL self.url was only ever assigned when window.real_url was set; a window created with html= (or no url/html at all) never got the attribute, so get_cookies()'s async handler raised AttributeError on `domain not in self.url` before releasing cookie_semaphore -- since the exception occurred inside a WebKit-invoked callback, it was swallowed rather than propagated, and the calling thread's cookie_semaphore.acquire() blocked forever. self.url is now always initialized to None, and the domain filter is skipped when there is no current URL to filter against instead of crashing. * [Cocoa] Fix create_file_dialog(SAVE) returning a bare string The documented contract (and the Qt/GTK/Winforms backends) return a tuple of selected files, or None if cancelled. Cocoa's SAVE branch set self._file_name to save_dlg.filename() directly -- a bare str. Code written against the documented tuple contract (e.g. window.create_file_dialog(FileDialog.SAVE)[0]) silently got just the first character of the path on macOS instead of the full path. * [Cocoa] Fix <input type=file> dialog resolving to the wrong window webView_runOpenPanelWithParameters_initiatedByFrame_completionHandler_ hardcoded list(BrowserView.instances.values())[0] -- "the first window ever created" -- instead of resolving the instance that actually triggered the callback, unlike every other WKUIDelegate method in this file. In a multi-window app, opening a file picker from any window other than the first used the wrong window's localization context, and raised IndexError if the first-created window had since closed. * [Cocoa] Remove script message handlers on window close to avoid a leak addScriptMessageHandler_name_ was called for 'browserDelegate' and 'jsBridge' at window creation, but windowWillClose_ never called the matching removeScriptMessageHandlerForName_. WKUserContentController holds a strong reference to registered handlers, which is a documented WKWebView leak pattern that could keep JSBridge/ BrowserDelegate (and transitively the window/webview) alive after a window was closed. * [Cocoa] Fix DownloadDelegate leaking on every download download.setDelegate_() was given a DownloadDelegate with an explicit .retain() (needed since setDelegate_ doesn't retain), but nothing ever released it. Since this delegate only implements the single "decide destination" callback, it's now released right after that callback completes, balancing the retain. * [GTK] Fix minimized/maximized events dropped on combined state changes on_window_state_change() tested changed_mask == ICONIFIED / == MAXIMIZED as mutually exclusive branches. If a single window-state-event reported both bits changed simultaneously, neither equality matched and both the minimized/restored and maximized/ restored events were silently dropped for that transition. Now tests each bit independently with & instead of chaining as if/elif on ==. * [GTK] Fix dropped file paths not being percent-decoded on_drag_data() only stripped the 'file://' prefix from dropped-file URIs, leaving percent-encoded sequences intact (spaces as %20, unicode escaped, etc). Any dropped file with a space or non-ASCII character in its name produced a mangled path in _dnd_state['paths'], breaking os.path.basename and any later file open. Now uses GLib.filename_from_uri(), the same API family already used for the reverse conversion in on_download_decide_destination(), with a fallback to the old behavior if the URI can't be parsed. * [Winforms] Fix file dialog default directory using drive-relative path create_file_dialog() defaulted to os.environ['HOMEPATH'] alone, which is drive-relative on Windows (e.g. \Users\name, no drive letter). Without HOMEDRIVE, this could point at the wrong or a nonexistent location if the process's current drive differs from the user's home drive. Now prefers USERPROFILE (already an absolute path), falling back to HOMEDRIVE+HOMEPATH. * [Core] Fix Event.set() crashing when a handler returns an unhashable value execute() collected handler return values in a set() via .add(value). A handler returning an unhashable value (a list or dict) raised TypeError there, which was caught by the enclosing except and logged as if the handler call itself had failed, even though it succeeded -- losing the return value. return_values is now a plain list, which only requires the values to exist, not be hashable; the only consumer (checking for a False return) works identically on a list. * [Core] Fix Event.__sub__/__isub__ raising on an unregistered handler window.events.<event> -= handler (or `- handler`) called list.remove() unguarded, raising an uncaught ValueError if the handler was never registered on that event. Both now guard with an `in` check and log a warning instead, matching the fix already applied to webview.dom.event.DOMEvent for the same pattern. * [Core] Fix GUI backend probing not catching all expected import failures import_gtk/import_android already catch (ImportError, ValueError) since gi.require_version() raises ValueError when a binding isn't available, but import_qt/import_cocoa only caught ImportError. On Windows, a pythonnet/CLR load failure can raise RuntimeError rather than ImportError; import_winforms only caught ImportError too. In all three cases a real load failure would propagate uncaught out of initialize() instead of being logged and falling through to try the next backend. * [MSHTML] Fix debug-mode console forwarding script The script passed a stray trailing quote before the closing brace (`}',`), producing a JS syntax error, and passed the script as a bare string to InvokeScript('eval', ...) instead of the (script,) tuple form InvokeScript's object[] args expects -- the pattern already used correctly elsewhere in this file (evaluate_js). Both bugs silently broke window.console.log/error forwarding to the Python-side debug console in the legacy MSHTML backend's debug mode. * [CEF] Fix HTML content truncated at a literal '#' in data: URIs load_html() and create_browser() built data:text/html,{html} URIs with no percent-encoding. A literal '#' anywhere in the loaded HTML or an injected script was parsed as the URL fragment delimiter, truncating the document at that point -- a failure mode unique to CEF, since the other backends load HTML through APIs that don't URL-encode the content. HTML is now percent-encoded via urllib.parse.quote() before being embedded in the data: URI. * [Qt] Fix closeEvent() risking reentrant execution and a KeyError closeEvent() called self.close() on itself right after event.accept() and deleting the window from BrowserView.instances. self.close() synchronously re-dispatches a QCloseEvent (re-entering closeEvent) if the widget hasn't been hidden yet, which it hasn't at that point -- event.accept() only marks the event as accepted, Qt hides the widget after closeEvent returns. A reentrant call would re-fire events.closing (potentially showing a second confirmation dialog) and then hit del BrowserView.instances[self.uid] on an already- removed key, raising KeyError inside a Qt event callback. The call was redundant: event.accept() already tells Qt to proceed with the close. * [Core] Fix Response aliasing the caller's headers dict Request.__init__ copies the headers dict it's given; Response did not, so a caller-owned dict could be mutated later and silently change an already-constructed Response's headers (or vice versa). Response now copies headers the same way Request does. * [Core] Fix incorrect Python version comparison in create_cookie() `sys.version_info.major >= 3 and sys.version_info.minor >= 8` is not equivalent to Python >= 3.8 (e.g. it would be False on a hypothetical Python 4.0 with minor < 8). No practical impact under currently supported Python versions, but the tuple comparison is the correct way to express this. * [Core] Fix KeyError on a duplicate/late pywebviewAsyncCallback js_bridge_call() accessed window._callbacks[value_id] with [], raising an uncaught KeyError if a duplicate or late JS callback message arrived for a value_id whose callback had already been consumed and removed. Now checks membership first and logs a warning instead of raising. * [Core] Fix load_html()'s default base_uri being frozen at import time base_uri: str = base_uri() evaluated the default once when window.py was first imported, freezing it to whatever get_app_root() returned at that moment rather than recomputing it per call. Now uses a None sentinel and computes it fresh inside the function body when the caller doesn't pass one. * [Core] Remove misleading NameError handling in _api_call decorator The wrapper already raises WebViewException with a specific message for both failure cases it's meant to handle (event.wait() timeout, gui not initialized) before calling the wrapped function. Nothing in that path naturally raises NameError, so the except NameError clause was dead for its intended purpose, and would instead catch a genuine NameError bug in wrapped platform code and mischaracterize it as "create a window first", masking the real error. * [Core] Fix width/height/x/y/title bypassing the standard API error handling These accessed self.gui.get_size()/get_position()/set_title() directly after a raw self.events.shown/loaded.wait(15) call, without checking the wait's return value or whether self.gui was None. If the wait timed out or gui wasn't initialized yet, they raised a raw AttributeError ('NoneType' object has no attribute ...) instead of the WebViewException every other API method raises via the _shown_call/_loaded_call decorators. Now use those decorators like the rest of the class. * [Docs] Fix shadow default documented as False webview/window.py and webview/__init__.py both default shadow=True. The API docs showed shadow=False in the create_window() signature sample and stated "Default is False" in the parameter description. * [Docs] Fix response_received documenting a nonexistent 'status' property webview.models.Response only has status_code (constructed with status_code everywhere it's built across the gtk/edgechromium/cocoa backends). Code written against the doc's `response.status` raised AttributeError. * [Docs] Fix broken example links to nonexistent example pages The doc site generates /examples/<name>.html 1:1 from examples/<name>.py filenames. Several links referenced files that don't exist under that name: open_url -> simple_browser, show_hide -> hide_window, css_load -> load_css, html_load -> load_html, minimize -> window_state. * [Docs] Fix broken internal cross-reference links - faq.md linked to /guide/renderer, which doesn't exist; the actual content is at /guide/web_engine.html. - pywebview6.md linked to /guide/api.html for the API reference; the API docs live at /api.html, not under /guide/. - api/README.md's "Manipulation mode" links (4 occurrences) pointed to the anchor #manipulation-mode, but the actual heading is "webview.dom.ManipulationMode", which slugifies to #webviewdommanipulationmode. * [Docs] Fix syntax error in DOM guide example create_element('<h1>Warning</h1>' parent=..., ...) was missing the comma between the html argument and the parent kwarg, raising SyntaxError if copy-pasted as-is. * [Docs] Fix stale "icon supported only on GTK/QT" claims webview/platforms/cocoa.py and winforms.py both consume _state['icon'] at runtime too (cocoa.py's NSImage/dock icon and winforms.py's window Icon), contradicting the start()/create_window docstring, the FAQ, and examples/icon.py, all of which claimed only GTK and QT support setting the icon via webview.start(icon=...). This also directly contradicted docs/api/README.md's create_window icon docs, which already correctly listed .ico/Windows and .icns/macOS support. * [Docs] Fix stale SECURITY.md supported-versions table The project is currently at 6.2.1; SECURITY.md still listed only 3.x as supported, which would tell a real vulnerability reporter their current install isn't covered. Replaced the hardcoded version table with a policy that references the changelog instead, so it doesn't go stale on every major release. * [Docs] Fix webview.settings sample and document DEFAULT_HTTP_PORT The settings code sample showed 'pywebview-drag-region' (no leading dot) for DRAG_REGION_SELECTOR, contradicting both the actual default ('.pywebview-drag-region', a CSS class selector) and this doc's own prose two lines below. DEFAULT_HTTP_PORT and WEBVIEW2_RUNTIME_PATH were also missing from the code sample, and DEFAULT_HTTP_PORT had no description at all despite being a real settings key. * [Docs] Fix FileDialog.OPEN.SAVE typo FileDialog.OPEN, .FOLDER and .SAVE are sibling enum members, not nested attributes; the doc referenced the nonexistent webview.FileDialog.OPEN.SAVE. * [Docs] Fix stale Python 2/3 compatibility claim in module docstring pyproject.toml requires >=3.8 and there is no Python 2 support in the current codebase. Also added Android, which pywebview supports but the docstring didn't mention. * [Docs] Fix stale Python 3.7 references requires-python = ">=3.8" (and ruff's target-version = "py38") but pyproject.toml's classifiers still listed 3.7, and the contributing guide stated "Target Python version: 3.7+". Both now say 3.8+, matching the actual minimum. * Marshal Form.TopMost to the GUI thread in the WinForms backend (#1831) set_on_top assigned Form.TopMost directly on the calling thread. When called from a non-GUI thread (e.g. a js_api handler, which pywebview runs on a worker thread), this is an unmarshaled cross-thread operation on a WinForms control, and the message pump can deadlock permanently while the system is doing window activation work — the window goes to Not Responding with no exception raised. Every other window operation in this backend already marshals via Invoke (show, hide, toggle_fullscreen, maximize, minimize, restore); set_on_top was the exception. This applies the same pattern, with the InvokeRequired guard used by toggle_fullscreen so calls already on the GUI thread stay direct. * WinForms: Shift focus to menu bar when active (#1835) * WinForms: Shift focus to menu bar when active This allows keyboard navigation of the menu bar. Note: Alt+F style &File menu mnemonics are not supported with this change. They would require more complex forwarding of keystrokes. * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Troy Deck <troy@visitorlabs.com> Co-authored-by: Roman <roman@flowrl.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * [Cocoa] fix window coordinates on multi-monitor setups (#1828) move() added the cached screen's origin to coordinates that are already absolute, so a frameless window dragged on a screen with a non-zero origin jumped off-screen: the drag region JS sends ev.screenX/ev.screenY, which are absolute already. move() and get_position now treat x/y as absolute and flip y against the primary screen instead of the window's screen, so both agree on any monitor arrangement. initial_x and initial_y stay relative to the target screen, as on the qt backend. Fixes #1820 Co-authored-by: Victor Purcallas Marchesi <6121411+VictorPurMar@users.noreply.github.com> * Add type hints for functions and parameters across multiple modules * Add lock acquisition to various test functions for thread safety * Add caching for WebView2 Runtime in Windows CI setup * FIx CI * Add future annotations import to multiple modules * [QT] Skip response test * Add token validation to JS bridge calls and update related interfaces * Refactor test mode handling to use a dedicated utility function * Fix typos in documentation and improve token validation in JS bridge calls * Remove test for missing token validation in JS bridge calls * Use json.dumps for selector and id in DOM methods to ensure proper string formatting --------- Co-authored-by: fjmarson <fjmarson@gmail.com> Co-authored-by: Troy Deck <troy.deque@gmail.com> Co-authored-by: Troy Deck <troy@visitorlabs.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Victor Purcallas Marchesi <vpurcallas@gmail.com> Co-authored-by: Victor Purcallas Marchesi <6121411+VictorPurMar@users.noreply.github.com>
1 parent 8b02c10 commit 497ca3d

45 files changed

Lines changed: 470 additions & 258 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/ci.yml‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,13 @@ jobs:
152152
sleep 3
153153
154154
# Windows specific setup
155+
- name: Cache WebView2 Runtime (Windows)
156+
if: runner.os == 'Windows'
157+
uses: actions/cache@v3
158+
with:
159+
path: 'C:\Program Files\Microsoft\Edge WebView2 Runtime'
160+
key: ${{ runner.os }}-webview2-runtime
161+
155162
- name: Install WebView2 Runtime (Windows)
156163
if: runner.os == 'Windows'
157164
run: |
@@ -162,7 +169,7 @@ jobs:
162169
run: |
163170
python -m pip install --upgrade pip
164171
pip install -e "."
165-
pip install pytest
172+
pip install pytest pytest-timeout
166173
167174
- name: Install Qt dependencies (Ubuntu Qt)
168175
if: matrix.gui == 'qt'

‎SECURITY.md‎

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,8 @@
22

33
## Supported Versions
44

5-
Versions lower than 3.0 are not supported.
6-
7-
| Version | Supported |
8-
| ------- | ------------------ |
9-
| 3.x | :white_check_mark: |
10-
| < 3.0 | :x: |
5+
Only the latest released version of pywebview is supported. See the
6+
[changelog](https://pywebview.flowrl.com/CHANGELOG) for the current version.
117

128
## Reporting a Vulnerability
139

‎docs/api/README.md‎

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Get an instance of the currently active window
1515
webview.create_window(title, url=None, html=None, js_api=None, width=800, height=600,
1616
x=None, y=None, screen=None, resizable=True, fullscreen=False,
1717
min_size=(200, 100), hidden=False, frameless=False,
18-
easy_drag=True, shadow=False, focus=True, minimized=False, maximized=False, menu=[],
18+
easy_drag=True, shadow=True, focus=True, minimized=False, maximized=False, menu=[],
1919
on_top=False, confirm_close=False, background_color='#FFFFFF',
2020
transparent=False, text_select=False, zoomable=False,
2121
draggable=False, vibrancy=False, server=http.BottleServer, server_args={},
@@ -39,7 +39,7 @@ Create a new _pywebview_ window and returns its instance. Can be used to create
3939
* `hidden` - Create a window hidden by default. Default is False
4040
* `frameless` - Create a frameless window. Default is False.
4141
* `easy_drag` - Easy drag mode for frameless windows. Window can be moved by dragging any point. Default is True. Note that easy_drag has no effect with normal windows. To control dragging on an element basis, see [drag area](/api.html#drag-area) for details.
42-
* `shadow` - Add window shadow. Default is False. _Windows only_.
42+
* `shadow` - Add window shadow. Default is True. _Windows only_.
4343
* `focus` - Create a non-focusable window if False. Default is True.
4444
* `minimized` - Display window minimized
4545
* `maximized` - Display window maximized
@@ -85,7 +85,7 @@ Start a GUI loop and display previously created windows. This function must be c
8585

8686
#### Examples
8787

88-
* [Simple window](/examples/open_url.html)
88+
* [Simple window](/examples/simple_browser.html)
8989
* [Multi-window](/examples/multiple_windows.html)
9090

9191
## webview.screens
@@ -106,13 +106,15 @@ Return a list of available displays (as `Screen` objects) with the primary displ
106106
webview.settings = {
107107
'ALLOW_DOWNLOADS': False,
108108
'ALLOW_FILE_URLS': True,
109-
'DRAG_REGION_SELECTOR': 'pywebview-drag-region',
109+
'DRAG_REGION_SELECTOR': '.pywebview-drag-region',
110110
'DRAG_REGION_DIRECT_TARGET_ONLY': False,
111+
'DEFAULT_HTTP_PORT': 42001,
111112
'OPEN_EXTERNAL_LINKS_IN_BROWSER': True,
112113
'OPEN_DEVTOOLS_IN_DEBUG': True,
113-
'IGNORE_SSL_ERRORS': False,
114114
'REMOTE_DEBUGGING_PORT': None,
115-
'SHOW_DEFAULT_MENUS': True
115+
'IGNORE_SSL_ERRORS': False,
116+
'SHOW_DEFAULT_MENUS': True,
117+
'WEBVIEW2_RUNTIME_PATH': None
116118
}
117119
```
118120

@@ -122,6 +124,7 @@ Additional options that override default behaviour of _pywebview_ to address pop
122124
* `ALLOW_FILE_URLS` Enable `file://` urls. Disabled by default.
123125
* `DRAG_REGION_SELECTOR` CSS selector for a drag region in easy drag mode. Default selector is `.pywebview-drag-region`.
124126
* `DRAG_REGION_DIRECT_TARGET_ONLY` When set to True, only elements that directly match the drag region selector are draggable. When False, child elements of a drag region are also draggable. Default is False.
127+
* `DEFAULT_HTTP_PORT` Port used for the internal HTTP server when private mode is disabled and no explicit port is given. Default is 42001.
125128
* `IGNORE_SSL_ERRORS` Ignore SSL errors. Disabled by default.
126129
* `OPEN_EXTERNAL_LINKS_IN_BROWSER`. Open `target=_blank` link in an external browser. Enabled by default.
127130
* `OPEN_DEVTOOLS_IN_DEBUG` Open devtools automatically in debug mode. Enabled by default.
@@ -211,7 +214,7 @@ element.classes.toggle('dotted')
211214
element.append(html, mode=webview.dom.ManipulationMode.LastChild)
212215
```
213216

214-
Insert HTML content to the element as a last child. To control the position of the new element, use the `mode` parameter. See [Manipulation mode](/api.html#manipulation-mode) for possible values.
217+
Insert HTML content to the element as a last child. To control the position of the new element, use the `mode` parameter. See [Manipulation mode](/api.html#webviewdommanipulationmode) for possible values.
215218

216219
### element.blur
217220

@@ -235,7 +238,7 @@ Get element's children elements. Returns a list of `Element` objects.
235238
element.copy(target=None, mode=webview.dom.ManipulationMode.LastChild, id=None)
236239
```
237240

238-
Create a new copy of the element. `target` can be either another `Element` or a DOM selector string. If target is omitted, a copy is created in the current element's parent. To control the position of the new element, use the `mode` parameter. See [Manipulation mode](/api.html#manipulation-mode) for possible values. The id parameter is stripped from the copy. Optionally you can set the id of the copy by specifying the `id` parameter.
241+
Create a new copy of the element. `target` can be either another `Element` or a DOM selector string. If target is omitted, a copy is created in the current element's parent. To control the position of the new element, use the `mode` parameter. See [Manipulation mode](/api.html#webviewdommanipulationmode) for possible values. The id parameter is stripped from the copy. Optionally you can set the id of the copy by specifying the `id` parameter.
239242

240243
### element.empty
241244

@@ -291,7 +294,7 @@ Get or set element's id. None if id is not set.
291294
element.move(target, mode=webview.dom.ManipulationMode.LastChild)
292295
```
293296

294-
Move element to the `target` that can be either another `Element` or a DOM selector string. To control the position of the new element, use the `mode` parameter. See [Manipulation mode](/api.html#manipulation-mode) for possible values.
297+
Move element to the `target` that can be either another `Element` or a DOM selector string. To control the position of the new element, use the `mode` parameter. See [Manipulation mode](/api.html#webviewdommanipulationmode) for possible values.
295298

296299
#### Examples
297300

@@ -625,7 +628,7 @@ Create a confirmation (Ok / Cancel) dialog.
625628
window.create_file_dialog(dialog_type=FileDialog.OPEN, directory='', allow_multiple=False, save_filename='', file_types=())
626629
```
627630

628-
Create an open file (`webview.FileDialog.OPEN`), open folder (`webview.FileDialog.FOLDER`) or save file (`webview.FileDialog.OPEN.SAVE`) dialog.
631+
Create an open file (`webview.FileDialog.OPEN`), open folder (`webview.FileDialog.FOLDER`) or save file (`webview.FileDialog.SAVE`) dialog.
629632

630633
Return a tuple of selected files, None if cancelled.
631634

@@ -702,7 +705,7 @@ window.hide()
702705

703706
Hide the window.
704707

705-
[Example](/examples/show_hide.html)
708+
[Example](/examples/hide_window.html)
706709

707710

708711
### window.load_css
@@ -713,7 +716,7 @@ window.load_css(css)
713716

714717
Load CSS as a string.
715718

716-
[Example](/examples/css_load.html)
719+
[Example](/examples/load_css.html)
717720

718721

719722
### window.load_html
@@ -724,7 +727,7 @@ window.load_html(content, base_uri=base_uri())
724727

725728
Load HTML code. Base URL for resolving relative URLs is set to the directory the program is launched from. Note that you cannot use hashbang anchors when HTML is loaded this way.
726729

727-
[Example](/examples/html_load.html)
730+
[Example](/examples/load_html.html)
728731

729732
### window.load_url
730733

@@ -801,7 +804,7 @@ window.resize(width, height, fix_point=FixPoint.NORTH | FixPoint.WEST)
801804

802805
Resize window. `width` and `height` are in logical pixels. Optional parameter fix_point specifies in respect to which point the window is resized. The parameter accepts values of the `webview.window.FixPoint` enum (`NORTH`, `SOUTH`, `EAST`, `WEST`)
803806

804-
[Example](/examples/minimize.html)
807+
[Example](/examples/window_state.html)
805808

806809
### window.restore
807810

@@ -811,7 +814,7 @@ window.restore()
811814

812815
Restore minimized window.
813816

814-
[Example](/examples/minimize.html)
817+
[Example](/examples/window_state.html)
815818

816819
### window.run_js
817820

@@ -842,7 +845,7 @@ window.show()
842845

843846
Show the window if it is hidden. Has no effect otherwise
844847

845-
[Example](/examples/show_hide.html)
848+
[Example](/examples/hide_window.html)
846849

847850
### window.toggle_fullscreen
848851

@@ -868,7 +871,7 @@ Get document's body as an `Element` object
868871
window.create_element(html, parent=None, mode=webview.dom.ManipulationMode.LastChild)
869872
```
870873

871-
Insert HTML content and returns the Element of the root object. `parent` can be either another `Element` or a DOM selector string. If parent is omited, created DOM is attached to document's body. To control the position of the new element, use the `mode` parameter. See [Manipulation mode](/api.html#manipulation-mode) for possible values.
874+
Insert HTML content and returns the Element of the root object. `parent` can be either another `Element` or a DOM selector string. If parent is omitted, created DOM is attached to document's body. To control the position of the new element, use the `mode` parameter. See [Manipulation mode](/api.html#webviewdommanipulationmode) for possible values.
872875

873876
### window.dom.document
874877

@@ -968,7 +971,7 @@ The event is fired when a HTTP response is received. The event is emitted for ev
968971
The event handler can accept a single argument - a `Response` object that contains the following properties:
969972

970973
* `url` - URL of the response
971-
* `status` - HTTP status code
974+
* `status_code` - HTTP status code
972975
* `headers` - HTTP response headers as a dictionary
973976

974977
Not supported on QT.

‎docs/blog/pywebview6.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ Version 6 includes several breaking changes that modernize the API and removes d
103103

104104
## Learn more
105105

106-
Ready to explore _pywebview 6_? Check out the [usage guide](/guide/usage.html), [API reference](/guide/api.html) and [examples](/examples) to get started with the new features.
106+
Ready to explore _pywebview 6_? Check out the [usage guide](/guide/usage.html), [API reference](/api.html) and [examples](/examples) to get started with the new features.
107107

108108
## Support the project
109109

‎docs/contributing/development.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ The project uses the following Ruff configuration (defined in `pyproject.toml`):
103103
* **Line length**: 100 characters
104104
* **Quote style**: Single quotes for strings
105105
* **Import sorting**: Enabled with `webview` as a known first-party package
106-
* **Target Python version**: 3.7+
106+
* **Target Python version**: 3.8+
107107
* **Enabled rules**: Pyflakes (F), pycodestyle (E4, E7, E9), isort (I), and pyupgrade (UP)
108108

109109
### Manual Formatting

‎docs/guide/dom.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Starting from 5.0 _pywebview_ has got support for basic DOM manipulation, traver
66

77
``` python
88
element = window.dom.create_element('<div>new element</div>') # insert a new element as body's last child
9-
element = window.dom.create_element('<h1>Warning</h1>' parent='#container', mode=ManipulationMode.FirstChild) # insert a new element to #containaer as a first child
9+
element = window.dom.create_element('<h1>Warning</h1>', parent='#container', mode=ManipulationMode.FirstChild) # insert a new element to #container as a first child
1010
```
1111

1212
Manipulation Mode can be one of following `LastChild`, `FirstChild`, `Before`, `After` or `Replace`. `LastChild` is a default value.

‎docs/guide/faq.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## How do I set an application icon?
44

5-
For macOS, Windows, and Android, the application icon is set via a bundler and embedded in the resulting executable. For GTK and QT, you can set the application icon using `webview.start(icon=icon_path)`, but you might need some additional adjustments to get your icon visible depending on the window manager you use.
5+
For Android, the application icon is set via a bundler and embedded in the resulting executable. On other platforms, you can set the application icon using `webview.start(icon=icon_path)`, but on GTK you might need some additional adjustments to get your icon visible depending on the window manager you use.
66

77
## Why does _pywebview_ have to run on a main thread?
88

@@ -14,7 +14,7 @@ You probably have a file named `webview.py` in the current directory. Renaming i
1414

1515
## What renderer is used?
1616

17-
Set `PYWEBVIEW_LOG=debug` environment variable before running your programme. It will display used renderer in the first line of the program output. See available renderers [here](/guide/renderer)
17+
Set `PYWEBVIEW_LOG=debug` environment variable before running your programme. It will display used renderer in the first line of the program output. See available renderers [here](/guide/web_engine.html)
1818

1919
## Terminal window receives key events on macOS
2020

‎examples/icon.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
"""Set window icon using `webview.start(icon=<file_path>). This is supported only on GTK and QT. For other
2-
platforms, icon is set during freezing."""
1+
"""Set window icon using `webview.start(icon=<file_path>)`. This is supported on GTK, QT, macOS and Windows.
2+
On Android, icon is set during freezing."""
33

44
import webview
55

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package com.pywebview;
22

33
public interface JsApiCallbackWrapper {
4-
public void callback(String func, String params, String id);
4+
public void callback(String func, String params, String id, String token);
55
}

‎interop/android/lib/src/main/java/com/pywebview/PyJavascriptInterface.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ public void setCallback(JsApiCallbackWrapper callback) {
1313
}
1414

1515
@JavascriptInterface
16-
public void call(String func, String params, String id) {
16+
public void call(String func, String params, String id, String token) {
1717
if (this.callbackWrapper != null) {
18-
this.callbackWrapper.callback(func, params, id);
18+
this.callbackWrapper.callback(func, params, id, token);
1919
} else {
2020
Log.e("python", "No callback");
2121
}

0 commit comments

Comments
 (0)