slint
slint copied to clipboard
expose window as RawWindowHandle
RawWindowHandle is a cross platform API for window handles. Some libraries like rfd can make use of a RawWindowHandle (in rfd's case, to parent a popup dialog to the appropriate window).
I pushed a WIP - see linked commit/branch. The Qt implementation is missing, which is a bit of work, but quite doable I think.
In C++ we can get the window handle for a QWidget
/Window
via QWindow::winId()
and the display connection via QPlatformNativeInterface
, which supports a per-window connection, for example for the xcb_connection_t
. After that we should be able to construct the different variants of https://docs.rs/raw-window-handle/0.4.2/raw_window_handle/index.html .
@tronical I couldn't find this code in the current Slint UI release. I'm guessing it was never finished?
Right, this was not yet merged to the master branch.
I had another look at this and this is not so easy as it looked originally:
- QWindow::winId is not a native handle on all platform (for example not with wayland https://bugreports.qt.io/browse/QTBUG-76983 ) and getting the actual meaning of it can't seem to be done with public API
- It's a bit difficult to uphold the unsafety rules. The implementation in the current
wip/raw-window-handle
branch is unsoud because the PlatformWindow trait could return an invalid window handle. It would be unfortunate to mark the PlatformWindow trait as unsafe just because of that. Also I don't exactly know what's the validity of the handle. For how long is it valid? - Would be nice if the RawWindowHandle had a variant that means "None". Right now, if I want to return that there is no handle, I need to make a null pointer for some random other platform.
consumer API
From the consumer point of view, we have two option:
-
impl HasRawWindowHandle for Window
andimpl HasRawDisplayHandle for Window
. That would be my preference. But one the issue with this is thatslint::Window
can only be accessed as a reference from the consumer side (given a ComponentHandle), and some API that consume the RawWindowHandle take the ownership of it. But they can take a&Window
as well. We'll have to see how this play with consumer API -
Add a getter:
fn Window::raw_handle(&slef) -> impl RawDisplayHandle + RawWindowHandle
platform API
Then from the platform point of view, we need to extend the WindowAdapter trait in some way.
- This would have to be optional to implement (with a default that would return an invalid handle)
- This shouldn't make the WindowAdapter unsafe to implement.
I wonder if this should be just one function, or two functions for the window and display handle. The example bellow use one function with a tuple, but it would be changed. So one suggestions:
trait WindowAdapter {
fn raw_handle(&self) -> (Option<&dyn HasRawWindowHandle>, Option<&dyn HasRawDisplayHandle>)
{ ... }
}
With such API, one would typically implement Has*Handle for the struct that implements WindowAdapter and just return self. But that means that the platform need to be unsafe.
trait WindowAdapter {
fn raw_handle(&self) -> (Option<Rc<dyn HasRawWindowHandle>>, Option<Rc<dyn HasRawDisplayHandle>>)
{ ... }
}
That would work fine for the winit platform when we keep a Rcwinit::Window. But otherwise we have the risk that we'd need to make an allocation just to put the return value in the Rc. Also the returned struct must have a 'static lifetime.
trait WindowAdapter {
type RawHandle<'a> : HasRawWindowHandle + HasRawDisplayHandle;
fn raw_handle<'a>(&'a self) -> Self::RawHandle<'a>;
}
But since there is no default for associated types, we can't make it optional. (Looking forward for the return impl in trait)
- If we implement the trait on slint::Window, something that would work and would be the most flexible would be using a callback, but it's also a bit ugly
trait WindowAdapter {
fn raw_handle(callback: &mut dyn FnMut(&dyn HasRawWindowHandle, &dyn HasRawDisplayHandle)) {}
}
I think i'd go with 2 at first
any progress?
We're trying to sort out how to model the RWH api with the interior mutability of the winit window owner. Meanwhile https://github.com/slint-ui/slint/pull/2617 adds API to the i-slint-backend-winit crate to provide you with access to the winit window and consequently the RWH. Can you give it a try?
For Qt, commit db9b6a5cf6f664bfdd4ca4cfc8207266e89392f2 in the Slint repo attempts to implement RHW support for the Qt backend. This works on macOS and Windows, but requires the use of private API. For Linux, the same could be done, but that kind of sucks because it means it can't be easily compiled against Linux distro package, which typically don't install private Qt headers.
One workaround would be to use QWindow::winId() and cast accordingly. By looking at the public QGuiApplication::platformName()
we could see if we need to cast that to a wl_surface* or xcb_window*. However, I don't see a way to retrieve the wl_display*
using public API.
So for now, I'll leave the Qt backend. If you need RWH support, the use of the winit backend is required.