Skip to content

Commit 39997fc

Browse files
committed
X11: implement non-resizable window
1 parent 5bcc8b7 commit 39997fc

8 files changed

Lines changed: 91 additions & 4 deletions

File tree

examples/plugin_clack/src/gui.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,19 @@ impl PluginGuiImpl for ExamplePluginMainThread<'_> {
7777
}
7878

7979
fn can_resize(&mut self) -> bool {
80-
true // Non-resizeable windows not supported yet
80+
let Some(gui) = &self.gui else { return false };
81+
82+
gui.handle.is_resizable()
8183
}
8284

8385
fn get_resize_hints(&mut self) -> Option<GuiResizeHints> {
86+
let can_resize = self.can_resize();
87+
8488
Some(GuiResizeHints {
8589
strategy: AspectRatioStrategy::Disregard, // Not supported
8690

87-
// Non-resizeable windows not supported yet
88-
can_resize_vertically: true,
89-
can_resize_horizontally: true,
91+
can_resize_vertically: can_resize,
92+
can_resize_horizontally: can_resize,
9093
})
9194
}
9295

src/platform/x11/window_shared.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::platform::x11::event_loop::EventLoop;
22
use crate::platform::x11::visual_info::WindowVisualConfig;
33
use crate::platform::x11::window_thread::WindowThreadShared;
4+
use crate::platform::x11::xcb_connection::{get_size_hints, WmSizeHintsExt};
45
use crate::platform::x11::xcb_window::XcbWindow;
56
use crate::platform::*;
67
use crate::{warn, MouseCursor, WindowHandler, WindowSettings, WindowSize};
@@ -10,6 +11,7 @@ use raw_window_handle::{DisplayHandle, XlibWindowHandle};
1011
use std::cell::Cell;
1112
use std::rc::Rc;
1213
use std::sync::Arc;
14+
use x11rb::properties::WmSizeHints;
1315
use x11rb::protocol::xproto::{ChangeWindowAttributesAux, ConnectionExt, InputFocus, Visualid};
1416
use x11rb::CURRENT_TIME;
1517

@@ -49,6 +51,7 @@ pub(crate) struct WindowInner {
4951
pub(crate) scaling_factor: ScalingFactor,
5052

5153
window_size: Cell<PhysicalSize<u16>>,
54+
pub(crate) is_resizable: bool,
5255
mouse_cursor: Cell<MouseCursor>,
5356
pub(crate) visual_id: Visualid,
5457

@@ -73,6 +76,8 @@ impl WindowInner {
7376

7477
let physical_size = options.size.to_physical(initial_scale_factor);
7578

79+
let size_hints = get_size_hints(&options, initial_scale_factor);
80+
7681
#[cfg(feature = "opengl")]
7782
let visual_info =
7883
WindowVisualConfig::find_best_visual_config_for_gl(&xcb_connection, options.gl_config)?;
@@ -93,6 +98,7 @@ impl WindowInner {
9398
xcb_window.set_title(&options.title)?,
9499
xcb_window.enable_wm_protocols()?,
95100
xcb_window.enable_dnd_protocols()?,
101+
xcb_window.set_size_hints(size_hints)?,
96102
];
97103

98104
for cookie in cookies {
@@ -121,6 +127,7 @@ impl WindowInner {
121127
system: scaling.into(),
122128
suggested: options.fallback_scale_factor.into(),
123129
},
130+
is_resizable: options.resizable,
124131
mouse_cursor: MouseCursor::default().into(),
125132
loop_signal: ev_loop.get_signal(),
126133

@@ -186,6 +193,11 @@ impl WindowInner {
186193
let new_physical_size = size.to_physical(self.scaling_factor.get());
187194
self.xcb_window.resize(new_physical_size)?.check()?;
188195

196+
if !self.is_resizable {
197+
let size_hints = WmSizeHints::new().with_fixed_size(new_physical_size.cast());
198+
self.xcb_window.set_size_hints(size_hints)?.check()?;
199+
}
200+
189201
// This will trigger a `ConfigureNotify` event which will in turn change `self.window_info`
190202
// and notify the window handler about it
191203

@@ -210,6 +222,10 @@ impl WindowInner {
210222
}
211223

212224
self.xcb_window.resize(new_size.cast())?.check()?; // Will not call handler, as size is the same as above.
225+
if !self.is_resizable {
226+
let size_hints = WmSizeHints::new().with_fixed_size(new_size.cast());
227+
self.xcb_window.set_size_hints(size_hints)?.check()?;
228+
}
213229

214230
// These come from the Host, no need to notify it about the new size
215231

src/platform/x11/window_thread.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub(crate) struct WindowThreadShared {
2222
size: AtomicU32,
2323
final_error: Mutex<Option<String>>,
2424
stopped_requested_from_host: AtomicBool,
25+
is_resizable: AtomicBool,
2526
}
2627

2728
impl WindowThreadShared {
@@ -32,12 +33,14 @@ impl WindowThreadShared {
3233
size: 0.into(),
3334
scaling_factor: 0.into(),
3435
stopped_requested_from_host: false.into(),
36+
is_resizable: true.into(),
3537
}
3638
}
3739

3840
fn init(&self, window: &WindowInner) {
3941
self.set_size(window.get_size());
4042
self.set_scaling_factor(window.scale_factor());
43+
self.set_resizable(window.is_resizable);
4144
}
4245

4346
pub fn get_size(&self) -> PhysicalSize<u16> {
@@ -53,6 +56,14 @@ impl WindowThreadShared {
5356
self.size.store(bytes, Ordering::Relaxed);
5457
}
5558

59+
pub fn set_resizable(&self, resizable: bool) {
60+
self.is_resizable.store(resizable, Ordering::Relaxed);
61+
}
62+
63+
pub fn is_resizable(&self) -> bool {
64+
self.is_resizable.load(Ordering::Relaxed)
65+
}
66+
5667
pub fn get_scaling_factor(&self) -> f64 {
5768
f64::from_be_bytes(self.scaling_factor.load(Ordering::Relaxed).to_ne_bytes())
5869
}
@@ -201,6 +212,10 @@ impl WindowThreadHandle {
201212
!self.shared.stopped.load(Ordering::Relaxed)
202213
}
203214

215+
pub fn is_resizable(&self) -> bool {
216+
self.shared.is_resizable()
217+
}
218+
204219
pub fn handle_main_thread_callback(&mut self) {
205220
loop {
206221
let Some(receiver) = self.callback_receiver.as_mut() else { return };

src/platform/x11/xcb_connection.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use crate::MouseCursor;
1313

1414
mod get_property;
1515
pub use get_property::GetPropertyError;
16+
mod size_hints;
17+
pub use size_hints::{get_size_hints, WmSizeHintsExt};
1618

1719
x11rb::atom_manager! {
1820
pub Atoms: AtomsCookie {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use crate::WindowSettings;
2+
use dpi::PhysicalSize;
3+
use x11rb::properties::WmSizeHints;
4+
5+
pub fn get_size_hints(settings: &WindowSettings, scale_factor: f64) -> WmSizeHints {
6+
let mut size_hints = WmSizeHints::default();
7+
8+
if !settings.resizable {
9+
size_hints = size_hints.with_fixed_size(settings.size.to_physical(scale_factor));
10+
}
11+
12+
size_hints
13+
}
14+
15+
pub trait WmSizeHintsExt: Sized {
16+
fn with_fixed_size(self, size: PhysicalSize<i32>) -> Self;
17+
}
18+
19+
impl WmSizeHintsExt for WmSizeHints {
20+
fn with_fixed_size(mut self, size: PhysicalSize<i32>) -> Self {
21+
self.max_size = Some((size.width, size.height));
22+
self
23+
}
24+
}

src/platform/x11/xcb_window.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::rc::Rc;
77
use x11rb::connection::Connection;
88
use x11rb::cookie::VoidCookie;
99
use x11rb::errors::{ConnectionError, ReplyOrIdError};
10+
use x11rb::properties::WmSizeHints;
1011
use x11rb::protocol::xproto::{
1112
AtomEnum, ConfigureWindowAux, ConnectionExt as _, CreateWindowAux, EventMask, PropMode,
1213
WindowClass,
@@ -119,6 +120,13 @@ impl XcbWindow {
119120
)?)
120121
}
121122

123+
pub fn set_size_hints(
124+
&self, size_hints: WmSizeHints,
125+
) -> Result<VoidCookie<'_, XCBConnection>, ReplyOrIdError> {
126+
Ok(size_hints
127+
.set_normal_hints(&self.connection.conn as &XCBConnection, self.window_id.get())?)
128+
}
129+
122130
#[inline]
123131
pub fn id(&self) -> NonZeroU32 {
124132
self.window_id

src/settings.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ pub struct WindowSettings {
2727
/// If the `parent` field is already set, this does nothing and is ignored.
2828
pub wait_for_parent: bool,
2929

30+
/// Whether the window can be resized.
31+
pub resizable: bool,
32+
3033
/// A fallback scale factor, if Baseview couldn't get one from the platform.
3134
///
3235
/// If the platform does already provide an accurate scaling factor, this doesn't do anything.
@@ -101,6 +104,13 @@ impl WindowSettings {
101104
self
102105
}
103106

107+
/// Sets [`resizable`](Self::resizable) to the given value.
108+
#[inline]
109+
pub fn with_resizable(mut self, resizable: bool) -> Self {
110+
self.resizable = resizable;
111+
self
112+
}
113+
104114
/// Sets [`gl_config`](Self::gl_config) to the given value.
105115
#[cfg(feature = "opengl")]
106116
#[inline]
@@ -118,6 +128,7 @@ impl Default for WindowSettings {
118128
parent: None,
119129
wait_for_parent: false,
120130
fallback_scale_factor: None,
131+
resizable: true,
121132
#[cfg(feature = "opengl")]
122133
gl_config: None,
123134
}

src/window.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,14 @@ impl Window {
151151
self.inner.is_open()
152152
}
153153

154+
/// Returns `true` if the window can be resized by the user, `false` otherwise.
155+
///
156+
/// This is set by the [`WindowSettings::resizable`] field.
157+
#[inline]
158+
pub fn is_resizable(&self) -> bool {
159+
self.inner.is_resizable()
160+
}
161+
154162
/// Performs the work the window thread had scheduled for the main thread.
155163
///
156164
/// This must be called back on the main thread, as a response to [`HostMainThreadCaller::call_main_thread`](host::HostMainThreadCaller::call_main_thread).

0 commit comments

Comments
 (0)