mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
Add a way to embed the X11 window into another
Signed-off-by: John Nunley <dev@notgull.net> Tested-by: Kirill Chibisov <contact@kchibisov.com>
This commit is contained in:
parent
2233edb9a0
commit
dc973883c9
|
@ -60,6 +60,7 @@ And please only add new entries to the top of this list, right below the `# Unre
|
||||||
- **Breaking** `MainEventsCleared` removed ([#2900](https://github.com/rust-windowing/winit/issues/2900))
|
- **Breaking** `MainEventsCleared` removed ([#2900](https://github.com/rust-windowing/winit/issues/2900))
|
||||||
- Added `AboutToWait` event which is emitted when the event loop is about to block and wait for new events ([#2900](https://github.com/rust-windowing/winit/issues/2900))
|
- Added `AboutToWait` event which is emitted when the event loop is about to block and wait for new events ([#2900](https://github.com/rust-windowing/winit/issues/2900))
|
||||||
- **Breaking:** `with_x11_visual` now takes the visual ID instead of the bare pointer.
|
- **Breaking:** `with_x11_visual` now takes the visual ID instead of the bare pointer.
|
||||||
|
- On X11, add a `with_embedded_parent_window` function to the window builder to allow embedding a window into another window.
|
||||||
|
|
||||||
# 0.29.0-beta.0
|
# 0.29.0-beta.0
|
||||||
|
|
||||||
|
|
69
examples/x11_embed.rs
Normal file
69
examples/x11_embed.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
//! A demonstration of embedding a winit window in an existing X11 application.
|
||||||
|
|
||||||
|
#[cfg(x11_platform)]
|
||||||
|
#[path = "util/fill.rs"]
|
||||||
|
mod fill;
|
||||||
|
|
||||||
|
#[cfg(x11_platform)]
|
||||||
|
mod imple {
|
||||||
|
use super::fill;
|
||||||
|
use simple_logger::SimpleLogger;
|
||||||
|
use winit::{
|
||||||
|
event::{Event, WindowEvent},
|
||||||
|
event_loop::EventLoop,
|
||||||
|
platform::x11::WindowBuilderExtX11,
|
||||||
|
window::WindowBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(super) fn entry() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// First argument should be a 32-bit X11 window ID.
|
||||||
|
let parent_window_id = std::env::args()
|
||||||
|
.nth(1)
|
||||||
|
.ok_or("Expected a 32-bit X11 window ID as the first argument.")?
|
||||||
|
.parse::<u32>()?;
|
||||||
|
|
||||||
|
SimpleLogger::new().init().unwrap();
|
||||||
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
|
let window = WindowBuilder::new()
|
||||||
|
.with_title("An embedded window!")
|
||||||
|
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
|
||||||
|
.with_embed_parent_window(parent_window_id)
|
||||||
|
.build(&event_loop)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
event_loop.run(move |event, _, control_flow| {
|
||||||
|
control_flow.set_wait();
|
||||||
|
|
||||||
|
match event {
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
window_id,
|
||||||
|
} if window_id == window.id() => control_flow.set_exit(),
|
||||||
|
Event::AboutToWait => {
|
||||||
|
window.request_redraw();
|
||||||
|
}
|
||||||
|
Event::RedrawRequested(_) => {
|
||||||
|
// Notify the windowing system that we'll be presenting to the window.
|
||||||
|
window.pre_present_notify();
|
||||||
|
fill::fill_window(&window);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(x11_platform))]
|
||||||
|
mod imple {
|
||||||
|
pub(super) fn entry() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
println!("This example is only supported on X11 platforms.");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
imple::entry()
|
||||||
|
}
|
|
@ -20,6 +20,9 @@ pub type XlibErrorHook =
|
||||||
/// A unique identifer for an X11 visual.
|
/// A unique identifer for an X11 visual.
|
||||||
pub type XVisualID = u32;
|
pub type XVisualID = u32;
|
||||||
|
|
||||||
|
/// A unique identifier for an X11 window.
|
||||||
|
pub type XWindow = u32;
|
||||||
|
|
||||||
/// Hook to winit's xlib error handling callback.
|
/// Hook to winit's xlib error handling callback.
|
||||||
///
|
///
|
||||||
/// This method is provided as a safe way to handle the errors comming from X11
|
/// This method is provided as a safe way to handle the errors comming from X11
|
||||||
|
@ -118,18 +121,35 @@ pub trait WindowBuilderExtX11 {
|
||||||
/// WindowBuilder::new().with_base_size(PhysicalSize::new(400, 200));
|
/// WindowBuilder::new().with_base_size(PhysicalSize::new(400, 200));
|
||||||
/// ```
|
/// ```
|
||||||
fn with_base_size<S: Into<Size>>(self, base_size: S) -> Self;
|
fn with_base_size<S: Into<Size>>(self, base_size: S) -> Self;
|
||||||
|
|
||||||
|
/// Embed this window into another parent window.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use winit::window::WindowBuilder;
|
||||||
|
/// use winit::platform::x11::{XWindow, WindowBuilderExtX11};
|
||||||
|
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
/// let event_loop = winit::event_loop::EventLoop::new();
|
||||||
|
/// let parent_window_id = std::env::args().nth(1).unwrap().parse::<XWindow>()?;
|
||||||
|
/// let window = WindowBuilder::new()
|
||||||
|
/// .with_embed_parent_window(parent_window_id)
|
||||||
|
/// .build(&event_loop)?;
|
||||||
|
/// # Ok(()) }
|
||||||
|
/// ```
|
||||||
|
fn with_embed_parent_window(self, parent_window_id: XWindow) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowBuilderExtX11 for WindowBuilder {
|
impl WindowBuilderExtX11 for WindowBuilder {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_x11_visual(mut self, visual_id: XVisualID) -> Self {
|
fn with_x11_visual(mut self, visual_id: XVisualID) -> Self {
|
||||||
self.platform_specific.visual_id = Some(visual_id);
|
self.platform_specific.x11.visual_id = Some(visual_id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_x11_screen(mut self, screen_id: i32) -> Self {
|
fn with_x11_screen(mut self, screen_id: i32) -> Self {
|
||||||
self.platform_specific.screen_id = Some(screen_id);
|
self.platform_specific.x11.screen_id = Some(screen_id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,19 +161,25 @@ impl WindowBuilderExtX11 for WindowBuilder {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_override_redirect(mut self, override_redirect: bool) -> Self {
|
fn with_override_redirect(mut self, override_redirect: bool) -> Self {
|
||||||
self.platform_specific.override_redirect = override_redirect;
|
self.platform_specific.x11.override_redirect = override_redirect;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_x11_window_type(mut self, x11_window_types: Vec<XWindowType>) -> Self {
|
fn with_x11_window_type(mut self, x11_window_types: Vec<XWindowType>) -> Self {
|
||||||
self.platform_specific.x11_window_types = x11_window_types;
|
self.platform_specific.x11.x11_window_types = x11_window_types;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_base_size<S: Into<Size>>(mut self, base_size: S) -> Self {
|
fn with_base_size<S: Into<Size>>(mut self, base_size: S) -> Self {
|
||||||
self.platform_specific.base_size = Some(base_size.into());
|
self.platform_specific.x11.base_size = Some(base_size.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_embed_parent_window(mut self, parent_window_id: XWindow) -> Self {
|
||||||
|
self.platform_specific.x11.embed_window = Some(parent_window_id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,15 +96,20 @@ pub struct PlatformSpecificWindowBuilderAttributes {
|
||||||
pub name: Option<ApplicationName>,
|
pub name: Option<ApplicationName>,
|
||||||
pub activation_token: Option<ActivationToken>,
|
pub activation_token: Option<ActivationToken>,
|
||||||
#[cfg(x11_platform)]
|
#[cfg(x11_platform)]
|
||||||
|
pub x11: X11WindowBuilderAttributes,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
#[cfg(x11_platform)]
|
||||||
|
pub struct X11WindowBuilderAttributes {
|
||||||
pub visual_id: Option<x11rb::protocol::xproto::Visualid>,
|
pub visual_id: Option<x11rb::protocol::xproto::Visualid>,
|
||||||
#[cfg(x11_platform)]
|
|
||||||
pub screen_id: Option<i32>,
|
pub screen_id: Option<i32>,
|
||||||
#[cfg(x11_platform)]
|
|
||||||
pub base_size: Option<Size>,
|
pub base_size: Option<Size>,
|
||||||
#[cfg(x11_platform)]
|
|
||||||
pub override_redirect: bool,
|
pub override_redirect: bool,
|
||||||
#[cfg(x11_platform)]
|
|
||||||
pub x11_window_types: Vec<XWindowType>,
|
pub x11_window_types: Vec<XWindowType>,
|
||||||
|
|
||||||
|
/// The parent window to embed this window into.
|
||||||
|
pub embed_window: Option<x11rb::protocol::xproto::Window>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PlatformSpecificWindowBuilderAttributes {
|
impl Default for PlatformSpecificWindowBuilderAttributes {
|
||||||
|
@ -113,15 +118,14 @@ impl Default for PlatformSpecificWindowBuilderAttributes {
|
||||||
name: None,
|
name: None,
|
||||||
activation_token: None,
|
activation_token: None,
|
||||||
#[cfg(x11_platform)]
|
#[cfg(x11_platform)]
|
||||||
|
x11: X11WindowBuilderAttributes {
|
||||||
visual_id: None,
|
visual_id: None,
|
||||||
#[cfg(x11_platform)]
|
|
||||||
screen_id: None,
|
screen_id: None,
|
||||||
#[cfg(x11_platform)]
|
|
||||||
base_size: None,
|
base_size: None,
|
||||||
#[cfg(x11_platform)]
|
|
||||||
override_redirect: false,
|
override_redirect: false,
|
||||||
#[cfg(x11_platform)]
|
|
||||||
x11_window_types: vec![XWindowType::Normal],
|
x11_window_types: vec![XWindowType::Normal],
|
||||||
|
embed_window: None,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,8 @@ atom_manager! {
|
||||||
_NET_CLIENT_LIST,
|
_NET_CLIENT_LIST,
|
||||||
_NET_FRAME_EXTENTS,
|
_NET_FRAME_EXTENTS,
|
||||||
_NET_SUPPORTED,
|
_NET_SUPPORTED,
|
||||||
_NET_SUPPORTING_WM_CHECK
|
_NET_SUPPORTING_WM_CHECK,
|
||||||
|
_XEMBED
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<AtomName> for Atoms {
|
impl Index<AtomName> for Atoms {
|
||||||
|
|
|
@ -126,6 +126,15 @@ pub(crate) struct UnownedWindow {
|
||||||
activation_sender: WakeSender<super::ActivationToken>,
|
activation_sender: WakeSender<super::ActivationToken>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! leap {
|
||||||
|
($e:expr) => {
|
||||||
|
match $e {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(err) => return Err(os_error!(OsError::XError(X11Error::from(err).into()))),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
impl UnownedWindow {
|
impl UnownedWindow {
|
||||||
#[allow(clippy::unnecessary_cast)]
|
#[allow(clippy::unnecessary_cast)]
|
||||||
pub(crate) fn new<T>(
|
pub(crate) fn new<T>(
|
||||||
|
@ -133,15 +142,6 @@ impl UnownedWindow {
|
||||||
window_attrs: WindowAttributes,
|
window_attrs: WindowAttributes,
|
||||||
pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
||||||
) -> Result<UnownedWindow, RootOsError> {
|
) -> Result<UnownedWindow, RootOsError> {
|
||||||
macro_rules! leap {
|
|
||||||
($e:expr) => {
|
|
||||||
match $e {
|
|
||||||
Ok(x) => x,
|
|
||||||
Err(err) => return Err(os_error!(OsError::XError(X11Error::from(err).into()))),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let xconn = &event_loop.xconn;
|
let xconn = &event_loop.xconn;
|
||||||
let atoms = xconn.atoms();
|
let atoms = xconn.atoms();
|
||||||
let root = match window_attrs.parent_window {
|
let root = match window_attrs.parent_window {
|
||||||
|
@ -210,7 +210,7 @@ impl UnownedWindow {
|
||||||
dimensions
|
dimensions
|
||||||
};
|
};
|
||||||
|
|
||||||
let screen_id = match pl_attribs.screen_id {
|
let screen_id = match pl_attribs.x11.screen_id {
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
None => xconn.default_screen_index() as c_int,
|
None => xconn.default_screen_index() as c_int,
|
||||||
};
|
};
|
||||||
|
@ -230,7 +230,7 @@ impl UnownedWindow {
|
||||||
});
|
});
|
||||||
|
|
||||||
// creating
|
// creating
|
||||||
let (visualtype, depth, require_colormap) = match pl_attribs.visual_id {
|
let (visualtype, depth, require_colormap) = match pl_attribs.x11.visual_id {
|
||||||
Some(vi) => {
|
Some(vi) => {
|
||||||
// Find this specific visual.
|
// Find this specific visual.
|
||||||
let (visualtype, depth) = all_visuals
|
let (visualtype, depth) = all_visuals
|
||||||
|
@ -271,12 +271,12 @@ impl UnownedWindow {
|
||||||
|
|
||||||
aux = aux.event_mask(event_mask).border_pixel(0);
|
aux = aux.event_mask(event_mask).border_pixel(0);
|
||||||
|
|
||||||
if pl_attribs.override_redirect {
|
if pl_attribs.x11.override_redirect {
|
||||||
aux = aux.override_redirect(true as u32);
|
aux = aux.override_redirect(true as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a colormap if needed.
|
// Add a colormap if needed.
|
||||||
let colormap_visual = match pl_attribs.visual_id {
|
let colormap_visual = match pl_attribs.x11.visual_id {
|
||||||
Some(vi) => Some(vi),
|
Some(vi) => Some(vi),
|
||||||
None if require_colormap => Some(visual),
|
None if require_colormap => Some(visual),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -298,6 +298,9 @@ impl UnownedWindow {
|
||||||
aux
|
aux
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Figure out the window's parent.
|
||||||
|
let parent = pl_attribs.x11.embed_window.unwrap_or(root);
|
||||||
|
|
||||||
// finally creating the window
|
// finally creating the window
|
||||||
let xwindow = {
|
let xwindow = {
|
||||||
let (x, y) = position.map_or((0, 0), Into::into);
|
let (x, y) = position.map_or((0, 0), Into::into);
|
||||||
|
@ -305,7 +308,7 @@ impl UnownedWindow {
|
||||||
let result = xconn.xcb_connection().create_window(
|
let result = xconn.xcb_connection().create_window(
|
||||||
depth,
|
depth,
|
||||||
wid,
|
wid,
|
||||||
root,
|
parent,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
dimensions.0.try_into().unwrap(),
|
dimensions.0.try_into().unwrap(),
|
||||||
|
@ -357,6 +360,11 @@ impl UnownedWindow {
|
||||||
leap!(window.set_theme_inner(Some(theme))).ignore_error();
|
leap!(window.set_theme_inner(Some(theme))).ignore_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Embed the window if needed.
|
||||||
|
if pl_attribs.x11.embed_window.is_some() {
|
||||||
|
window.embed_window()?;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Enable drag and drop (TODO: extend API to make this toggleable)
|
// Enable drag and drop (TODO: extend API to make this toggleable)
|
||||||
{
|
{
|
||||||
|
@ -407,7 +415,7 @@ impl UnownedWindow {
|
||||||
flusher.ignore_error()
|
flusher.ignore_error()
|
||||||
}
|
}
|
||||||
|
|
||||||
leap!(window.set_window_types(pl_attribs.x11_window_types)).ignore_error();
|
leap!(window.set_window_types(pl_attribs.x11.x11_window_types)).ignore_error();
|
||||||
|
|
||||||
// Set size hints.
|
// Set size hints.
|
||||||
let mut min_inner_size = window_attrs
|
let mut min_inner_size = window_attrs
|
||||||
|
@ -430,7 +438,7 @@ impl UnownedWindow {
|
||||||
shared_state.min_inner_size = min_inner_size.map(Into::into);
|
shared_state.min_inner_size = min_inner_size.map(Into::into);
|
||||||
shared_state.max_inner_size = max_inner_size.map(Into::into);
|
shared_state.max_inner_size = max_inner_size.map(Into::into);
|
||||||
shared_state.resize_increments = window_attrs.resize_increments;
|
shared_state.resize_increments = window_attrs.resize_increments;
|
||||||
shared_state.base_size = pl_attribs.base_size;
|
shared_state.base_size = pl_attribs.x11.base_size;
|
||||||
|
|
||||||
let normal_hints = WmSizeHints {
|
let normal_hints = WmSizeHints {
|
||||||
position: position.map(|PhysicalPosition { x, y }| {
|
position: position.map(|PhysicalPosition { x, y }| {
|
||||||
|
@ -447,6 +455,7 @@ impl UnownedWindow {
|
||||||
.resize_increments
|
.resize_increments
|
||||||
.map(|size| cast_size_to_hint(size, scale_factor)),
|
.map(|size| cast_size_to_hint(size, scale_factor)),
|
||||||
base_size: pl_attribs
|
base_size: pl_attribs
|
||||||
|
.x11
|
||||||
.base_size
|
.base_size
|
||||||
.map(|size| cast_size_to_hint(size, scale_factor)),
|
.map(|size| cast_size_to_hint(size, scale_factor)),
|
||||||
aspect: None,
|
aspect: None,
|
||||||
|
@ -559,6 +568,21 @@ impl UnownedWindow {
|
||||||
Ok(window)
|
Ok(window)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Embed this window into a parent window.
|
||||||
|
pub(super) fn embed_window(&self) -> Result<(), RootOsError> {
|
||||||
|
let atoms = self.xconn.atoms();
|
||||||
|
leap!(leap!(self.xconn.change_property(
|
||||||
|
self.xwindow,
|
||||||
|
atoms[_XEMBED],
|
||||||
|
atoms[_XEMBED],
|
||||||
|
xproto::PropMode::REPLACE,
|
||||||
|
&[0u32, 1u32],
|
||||||
|
))
|
||||||
|
.check());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn shared_state_lock(&self) -> MutexGuard<'_, SharedState> {
|
pub(super) fn shared_state_lock(&self) -> MutexGuard<'_, SharedState> {
|
||||||
self.shared_state.lock().unwrap()
|
self.shared_state.lock().unwrap()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue