Skip to content

Commit

Permalink
fix(linux): include border and titlebars in `Window::{outer_position,…
Browse files Browse the repository at this point in the history
… outer_size}` and `WindowEvent::Moved` event (#1001)
  • Loading branch information
amrbashir authored Nov 2, 2024
1 parent 0f7e95a commit aff33fb
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 85 deletions.
5 changes: 5 additions & 0 deletions .changes/outer-position-linux.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": "patch"
---

On Linux, `Window::outer_position`, `Window::outer_size` and `WindowEvent::Moved` to include/account for borders and titlebar.
5 changes: 4 additions & 1 deletion src/platform_impl/linux/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,10 @@ impl<T: 'static> EventLoop<T> {
window.connect_configure_event(move |window, event| {
let scale_factor = window.scale_factor();

let (x, y) = event.position();
let (x, y) = window
.window()
.map(|w| w.root_origin())
.unwrap_or_else(|| event.position());
if let Err(e) = tx_clone.send(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::Moved(
Expand Down
195 changes: 111 additions & 84 deletions src/platform_impl/linux/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ pub struct Window {
/// Window requests sender
pub(crate) window_requests_tx: glib::Sender<(WindowId, WindowRequest)>,
scale_factor: Rc<AtomicI32>,
position: Rc<(AtomicI32, AtomicI32)>,
size: Rc<(AtomicI32, AtomicI32)>,
inner_position: Rc<(AtomicI32, AtomicI32)>,
outer_position: Rc<(AtomicI32, AtomicI32)>,
outer_size: Rc<(AtomicI32, AtomicI32)>,
inner_size: Rc<(AtomicI32, AtomicI32)>,
maximized: Rc<AtomicBool>,
is_always_on_top: Rc<AtomicBool>,
minimized: Rc<AtomicBool>,
Expand Down Expand Up @@ -198,10 +200,6 @@ impl Window {
window.stick();
}

if let Some(icon) = attributes.window_icon {
window.set_icon(Some(&icon.inner.into()));
}

let preferred_theme = if let Some(settings) = Settings::default() {
if let Some(preferred_theme) = attributes.preferred_theme {
match preferred_theme {
Expand Down Expand Up @@ -247,48 +245,6 @@ impl Window {
signal_id.borrow_mut().replace(id);
}

let w_pos = window.position();
let position: Rc<(AtomicI32, AtomicI32)> = Rc::new((w_pos.0.into(), w_pos.1.into()));
let position_clone = position.clone();

let w_size = window.size();
let size: Rc<(AtomicI32, AtomicI32)> = Rc::new((w_size.0.into(), w_size.1.into()));
let size_clone = size.clone();

window.connect_configure_event(move |_, event| {
let (x, y) = event.position();
position_clone.0.store(x, Ordering::Release);
position_clone.1.store(y, Ordering::Release);

let (w, h) = event.size();
size_clone.0.store(w as i32, Ordering::Release);
size_clone.1.store(h as i32, Ordering::Release);

false
});

let w_max = window.is_maximized();
let maximized: Rc<AtomicBool> = Rc::new(w_max.into());
let max_clone = maximized.clone();
let minimized = Rc::new(AtomicBool::new(false));
let minimized_clone = minimized.clone();
let is_always_on_top = Rc::new(AtomicBool::new(attributes.always_on_top));
let is_always_on_top_clone = is_always_on_top.clone();

window.connect_window_state_event(move |_, event| {
let state = event.new_window_state();
max_clone.store(state.contains(WindowState::MAXIMIZED), Ordering::Release);
minimized_clone.store(state.contains(WindowState::ICONIFIED), Ordering::Release);
is_always_on_top_clone.store(state.contains(WindowState::ABOVE), Ordering::Release);
glib::Propagation::Proceed
});

let scale_factor: Rc<AtomicI32> = Rc::new(win_scale_factor.into());
let scale_factor_clone = scale_factor.clone();
window.connect_scale_factor_notify(move |window| {
scale_factor_clone.store(window.scale_factor(), Ordering::Release);
});

// Check if we should paint the transparent background ourselves.
let mut transparent = false;
if attributes.transparent && pl_attribs.auto_transparent {
Expand All @@ -306,8 +262,19 @@ impl Window {
log::warn!("Fail to send wire up events request: {}", e);
}

if let Err(e) = draw_tx.send(window_id) {
log::warn!("Failed to send redraw event to event channel: {}", e);
let (
scale_factor,
outer_position,
inner_position,
outer_size,
inner_size,
maximized,
minimized,
is_always_on_top,
) = Self::setup_signals(&window, Some(&attributes));

if let Some(icon) = attributes.window_icon {
window.set_icon(Some(&icon.inner.into()));
}

let win = Self {
Expand All @@ -317,8 +284,10 @@ impl Window {
window_requests_tx,
draw_tx,
scale_factor,
position,
size,
outer_position,
inner_position,
outer_size,
inner_size,
maximized,
minimized,
is_always_on_top,
Expand All @@ -334,37 +303,59 @@ impl Window {
Ok(win)
}

pub(crate) fn new_from_gtk_window<T>(
event_loop_window_target: &EventLoopWindowTarget<T>,
window: gtk::ApplicationWindow,
) -> Result<Self, RootOsError> {
let window_requests_tx = event_loop_window_target.window_requests_tx.clone();
let draw_tx = event_loop_window_target.draw_tx.clone();

let window_id = WindowId(window.id());
event_loop_window_target
.windows
.borrow_mut()
.insert(window_id);

fn setup_signals(
window: &gtk::ApplicationWindow,
attributes: Option<&WindowAttributes>,
) -> (
Rc<AtomicI32>,
Rc<(AtomicI32, AtomicI32)>,
Rc<(AtomicI32, AtomicI32)>,
Rc<(AtomicI32, AtomicI32)>,
Rc<(AtomicI32, AtomicI32)>,
Rc<AtomicBool>,
Rc<AtomicBool>,
Rc<AtomicBool>,
) {
let win_scale_factor = window.scale_factor();

let w_pos = window.position();
let position: Rc<(AtomicI32, AtomicI32)> = Rc::new((w_pos.0.into(), w_pos.1.into()));
let position_clone = position.clone();
let inner_position: Rc<(AtomicI32, AtomicI32)> = Rc::new((w_pos.0.into(), w_pos.1.into()));
let inner_position_clone = inner_position.clone();

let o_pos = window.window().map(|w| w.root_origin()).unwrap_or(w_pos);
let outer_position: Rc<(AtomicI32, AtomicI32)> = Rc::new((o_pos.0.into(), o_pos.1.into()));
let outer_position_clone = outer_position.clone();

let w_size = window.size();
let size: Rc<(AtomicI32, AtomicI32)> = Rc::new((w_size.0.into(), w_size.1.into()));
let size_clone = size.clone();
let inner_size: Rc<(AtomicI32, AtomicI32)> = Rc::new((w_size.0.into(), w_size.1.into()));
let inner_size_clone = inner_size.clone();

window.connect_configure_event(move |_, event| {
let o_size = window.window().map(|w| w.root_origin()).unwrap_or(w_pos);
let outer_size: Rc<(AtomicI32, AtomicI32)> = Rc::new((o_size.0.into(), o_size.1.into()));
let outer_size_clone = outer_size.clone();

window.connect_configure_event(move |window, event| {
let (x, y) = event.position();
position_clone.0.store(x, Ordering::Release);
position_clone.1.store(y, Ordering::Release);
inner_position_clone.0.store(x, Ordering::Release);
inner_position_clone.1.store(y, Ordering::Release);

let (w, h) = event.size();
size_clone.0.store(w as i32, Ordering::Release);
size_clone.1.store(h as i32, Ordering::Release);
inner_size_clone.0.store(w as i32, Ordering::Release);
inner_size_clone.1.store(h as i32, Ordering::Release);

let (x, y, w, h) = window
.window()
.map(|w| {
let rect = w.frame_extents();
(rect.x(), rect.y(), rect.width(), rect.height())
})
.unwrap_or((x, y, w as i32, h as i32));

outer_position_clone.0.store(x, Ordering::Release);
outer_position_clone.1.store(y, Ordering::Release);

outer_size_clone.0.store(w, Ordering::Release);
outer_size_clone.1.store(h, Ordering::Release);

false
});
Expand All @@ -374,7 +365,9 @@ impl Window {
let max_clone = maximized.clone();
let minimized = Rc::new(AtomicBool::new(false));
let minimized_clone = minimized.clone();
let is_always_on_top = Rc::new(AtomicBool::new(false));
let is_always_on_top = Rc::new(AtomicBool::new(
attributes.map(|a| a.always_on_top).unwrap_or(false),
));
let is_always_on_top_clone = is_always_on_top.clone();

window.connect_window_state_event(move |_, event| {
Expand All @@ -391,9 +384,41 @@ impl Window {
scale_factor_clone.store(window.scale_factor(), Ordering::Release);
});

if let Err(e) = draw_tx.send(window_id) {
log::warn!("Failed to send redraw event to event channel: {}", e);
}
(
scale_factor,
outer_position,
inner_position,
outer_size,
inner_size,
maximized,
minimized,
is_always_on_top,
)
}

pub(crate) fn new_from_gtk_window<T>(
event_loop_window_target: &EventLoopWindowTarget<T>,
window: gtk::ApplicationWindow,
) -> Result<Self, RootOsError> {
let window_requests_tx = event_loop_window_target.window_requests_tx.clone();
let draw_tx = event_loop_window_target.draw_tx.clone();

let window_id = WindowId(window.id());
event_loop_window_target
.windows
.borrow_mut()
.insert(window_id);

let (
scale_factor,
outer_position,
inner_position,
outer_size,
inner_size,
maximized,
minimized,
is_always_on_top,
) = Self::setup_signals(&window, None);

let win = Self {
window_id,
Expand All @@ -402,8 +427,10 @@ impl Window {
window_requests_tx,
draw_tx,
scale_factor,
position,
size,
outer_position,
inner_position,
outer_size,
inner_size,
maximized,
minimized,
is_always_on_top,
Expand Down Expand Up @@ -431,15 +458,15 @@ impl Window {
}

pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
let (x, y) = &*self.position;
let (x, y) = &*self.inner_position;
Ok(
LogicalPosition::new(x.load(Ordering::Acquire), y.load(Ordering::Acquire))
.to_physical(self.scale_factor.load(Ordering::Acquire) as f64),
)
}

pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
let (x, y) = &*self.position;
let (x, y) = &*self.outer_position;
Ok(
LogicalPosition::new(x.load(Ordering::Acquire), y.load(Ordering::Acquire))
.to_physical(self.scale_factor.load(Ordering::Acquire) as f64),
Expand Down Expand Up @@ -470,7 +497,7 @@ impl Window {
}

pub fn inner_size(&self) -> PhysicalSize<u32> {
let (width, height) = &*self.size;
let (width, height) = &*self.inner_size;

LogicalSize::new(
width.load(Ordering::Acquire) as u32,
Expand All @@ -491,7 +518,7 @@ impl Window {
}

pub fn outer_size(&self) -> PhysicalSize<u32> {
let (width, height) = &*self.size;
let (width, height) = &*self.outer_size;

LogicalSize::new(
width.load(Ordering::Acquire) as u32,
Expand Down

0 comments on commit aff33fb

Please sign in to comment.