On X11, allow building window with parent

This commit is contained in:
Shinichi Tanaka 2022-10-10 05:12:23 +09:00 committed by GitHub
parent bb0f965c57
commit 71094e5703
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 104 additions and 1 deletions

View file

@ -23,6 +23,7 @@ And please only add new entries to the top of this list, right below the `# Unre
- On Wayland, `wayland-csd-adwaita` now uses `ab_glyph` instead of `crossfont` to render the title for decorations.
- On Wayland, a new `wayland-csd-adwaita-crossfont` feature was added to use `crossfont` instead of `ab_glyph` for decorations.
- On Wayland, if not otherwise specified use upstream automatic CSD theme selection.
- On X11, added `WindowExtX11::with_parent` to create child windows.
# 0.27.3

View file

@ -137,6 +137,7 @@ If your PR makes notable changes to Winit's features, please update this section
* X11 Override Redirect Flag
* GTK Theme Variant
* Base window size
* Setting the X11 parent window
### iOS
* `winit` has a minimum OS requirement of iOS 8

83
examples/child_window.rs Normal file
View file

@ -0,0 +1,83 @@
#[cfg(all(target_os = "linux", feature = "x11"))]
use std::collections::HashMap;
#[cfg(all(target_os = "linux", feature = "x11"))]
use winit::{
dpi::{LogicalPosition, LogicalSize, Position},
event::{ElementState, Event, KeyboardInput, WindowEvent},
event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
platform::x11::{WindowBuilderExtX11, WindowExtX11},
window::{Window, WindowBuilder, WindowId},
};
#[cfg(all(target_os = "linux", feature = "x11"))]
fn spawn_child_window(
parent: u32,
event_loop: &EventLoopWindowTarget<()>,
windows: &mut HashMap<u32, Window>,
) {
let child_window = WindowBuilder::new()
.with_parent(WindowId::from(parent as u64))
.with_title("child window")
.with_inner_size(LogicalSize::new(200.0f32, 200.0f32))
.with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
.with_visible(true)
.build(event_loop)
.unwrap();
let id = child_window.xlib_window().unwrap() as u32;
windows.insert(id, child_window);
println!("child window created with id: {}", id);
}
#[cfg(all(target_os = "linux", feature = "x11"))]
fn main() {
let mut windows = HashMap::new();
let event_loop: EventLoop<()> = EventLoop::new();
let parent_window = WindowBuilder::new()
.with_title("parent window")
.with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
.with_inner_size(LogicalSize::new(640.0f32, 480.0f32))
.build(&event_loop)
.unwrap();
let root = parent_window.xlib_window().unwrap() as u32;
println!("parent window id: {})", root);
event_loop.run(move |event: Event<'_, ()>, event_loop, control_flow| {
*control_flow = ControlFlow::Wait;
if let Event::WindowEvent { event, window_id } = event {
match event {
WindowEvent::CloseRequested => {
windows.clear();
*control_flow = ControlFlow::Exit;
}
WindowEvent::CursorEntered { device_id: _ } => {
// println when the cursor entered in a window even if the child window is created
// by some key inputs.
// the child windows are always placed at (0, 0) with size (200, 200) in the parent window,
// so we also can see this log when we move the cursor arround (200, 200) in parent window.
println!("cursor entered in the window {:?}", window_id);
}
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
..
},
..
} => {
spawn_child_window(root, event_loop, &mut windows);
}
_ => (),
}
}
})
}
#[cfg(not(all(target_os = "linux", feature = "x11")))]
fn main() {
panic!("This example is supported only on x11.");
}

View file

@ -1,6 +1,7 @@
use std::os::raw;
use std::{ptr, sync::Arc};
use crate::window::WindowId;
use crate::{
event_loop::{EventLoopBuilder, EventLoopWindowTarget},
monitor::MonitorHandle,
@ -171,6 +172,8 @@ pub trait WindowBuilderExtX11 {
fn with_x11_visual<T>(self, visual_infos: *const T) -> Self;
fn with_x11_screen(self, screen_id: i32) -> Self;
/// Build window with parent window.
fn with_parent(self, parent_id: WindowId) -> Self;
/// Build window with the given `general` and `instance` names.
///
@ -227,6 +230,12 @@ impl WindowBuilderExtX11 for WindowBuilder {
self
}
#[inline]
fn with_parent(mut self, parent_id: WindowId) -> Self {
self.platform_specific.parent_id = Some(parent_id.0);
self
}
#[inline]
fn with_override_redirect(mut self, override_redirect: bool) -> Self {
self.platform_specific.override_redirect = override_redirect;

View file

@ -95,6 +95,8 @@ pub struct PlatformSpecificWindowBuilderAttributes {
#[cfg(feature = "x11")]
pub screen_id: Option<i32>,
#[cfg(feature = "x11")]
pub parent_id: Option<WindowId>,
#[cfg(feature = "x11")]
pub base_size: Option<Size>,
#[cfg(feature = "x11")]
pub override_redirect: bool,
@ -115,6 +117,8 @@ impl Default for PlatformSpecificWindowBuilderAttributes {
#[cfg(feature = "x11")]
screen_id: None,
#[cfg(feature = "x11")]
parent_id: None,
#[cfg(feature = "x11")]
base_size: None,
#[cfg(feature = "x11")]
override_redirect: false,

View file

@ -119,7 +119,12 @@ impl UnownedWindow {
pl_attribs: PlatformSpecificWindowBuilderAttributes,
) -> Result<UnownedWindow, RootOsError> {
let xconn = &event_loop.xconn;
let root = event_loop.root;
let root = if let Some(id) = pl_attribs.parent_id {
// WindowId is XID under the hood which doesn't exceed u32, so this conversion is lossless
u64::from(id) as _
} else {
event_loop.root
};
let mut monitors = xconn.available_monitors();
let guessed_monitor = if monitors.is_empty() {