pywebview icon indicating copy to clipboard operation
pywebview copied to clipboard

Resizable frameless window

Open lukehugh opened this issue 7 months ago • 2 comments

I really like this project and have been using it to create portable user interfaces for my Python projects. While deeply integrating pywebview, I found it frustrating that frameless windows are not resizable — although I understand this might be a limitation of frameless windows themselves.

I looked into how the code handles dragging for frameless windows. The process involves capturing mousemove events on the JavaScript side and then calling the window.move method through the js_bridge. Inspired by this, I thought it might be possible to make frameless windows resizable as well.

https://github.com/user-attachments/assets/ba885253-5f55-4fd1-85f4-a8c4863e0e0e

To implement resizable frameless windows, my approach is to capture mouse events in JavaScript, handle the resize logic there, and finally call the window.resize method. The process can be broken down into the following parts:

1. Properly handle DPI scaling in window.resize

I noticed that webview/platforms/winforms.py does not correctly handle the scale factor.

https://github.com/r0x0r/pywebview/blob/eccca484120ad004907f541c5b40e9f5903d2071/webview/platforms/winforms.py#L533-L543

The first commit fix this issue. (1e3257202289d12447f7553a2203ffd3c29a7645)

2. Expose window.resize to the JavaScript side

We modified the resize method to accept an int as the fix_point parameter (f9384245bb04fac31074f08e5a8d345ef526b5f3). Then, similar to the move method, we exposed it to the JavaScript side (f73634fdae7ae5015a75c8b1a9589c94ae62a67c).

3. Determine when to enable frameless resize

When both window.frameless and window.resizable are set, we pass a flag easy_resize to customize.js to activate frameless resize functionality. (cb222ec488f6a5cef722deae59a9b5d93196a377)

4. Implement the resize logic

This part involves several tasks:

  1. Detect when the mouse is near the window edges.
  2. Override the mouse cursor style accordingly.
  3. Toggle the resizing state when the mouse is pressed or released.
  4. Ensure it doesn’t interfere with the existing easy_drag functionality.

commit: (b328925226aab05232501d2080fccd767ceeb684)

Limitations

When the page height exceeds the visible area, a native scrollbar appears on the left side of the window. The area covered by the scrollbar doesn't seem to respond to resize actions — possibly because the native scrollbar takes precedence?

Although resizable frameless windows are not a native feature, I think adding this could really make life a little easier.

lukehugh avatar May 27 '25 07:05 lukehugh

This is a clever approach. Nice work! I have tested it on different platforms and found a couple of problems

  • E direction does not work for me. May be related to scrollbar?
  • GTK resize is broken. Window keeps changing size during resize.
  • Replace const and let's with vars to keep code somewhat compatible with MSHTML. I am planning to introduce a transpiler, but for now minimum MSHTML compatibility is needed to be preserved by hand.
  • macOS has frameless window resizable by default, so exemption can be made to not apply this code on Cocoa.

r0x0r avatar May 29 '25 20:05 r0x0r

It seems that both Qt and GTK have their own implementations of easy_drag, which leads to conflicts. In any case, these two platforms are capable of handling mouse events themselves, so the resize logic should also be managed by them. Therefore, I’ve restricted easy_resize to edgechromium platform only.

As for the scrollbars, the temporary solution is to hide them. A better approach might be to handle mouse events like other platforms do. However, it seems that the WebView2 process intercepts some of the messages sent to WndProc. I’ve tried working around this, but it’s proven to be extremely difficult.

All in all, this PR only takes effect for edgechromium. As for the implementations on other platforms, hopefully someone else will be interested in taking them on.

lukehugh avatar Jun 08 '25 09:06 lukehugh

This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Jul 09 '25 03:07 github-actions[bot]

The message to post on the pr when closing it. If none provided, will not comment when closing a pull requests.

github-actions[bot] avatar Jul 14 '25 03:07 github-actions[bot]