Skip to content

Commit

Permalink
feat: Add Linux method to use existing GTK window (#938)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewbaxter authored Jun 27, 2024
1 parent dfe691f commit f54cc11
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changes/gtk-app-getter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": patch
---

Add `EventLoopWindowTargetExtUnix::gtk_app` getter.
5 changes: 5 additions & 0 deletions .changes/new-from-gtk-window.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": patch
---

Add `WindowExtUnix::new_from_gtk_window`.
27 changes: 26 additions & 1 deletion src/platform/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ pub use crate::platform_impl::x11;

pub use crate::platform_impl::EventLoop as UnixEventLoop;
use crate::{
error::OsError,
event_loop::{EventLoopBuilder, EventLoopWindowTarget},
platform_impl::{x11::xdisplay::XError, Parent},
platform_impl::{x11::xdisplay::XError, Parent, Window as UnixWindow},
window::{Window, WindowBuilder},
};

Expand Down Expand Up @@ -60,6 +61,14 @@ impl<T> EventLoopBuilderExtUnix for EventLoopBuilder<T> {

/// Additional methods on `Window` that are specific to Unix.
pub trait WindowExtUnix {
/// Create a new Tao window from an existing GTK window. Generally you should use
/// the non-Linux `WindowBuilder`, this is for those who need lower level window access
/// and know what they're doing.
fn new_from_gtk_window<T: 'static>(
event_loop_window_target: &EventLoopWindowTarget<T>,
window: gtk::ApplicationWindow,
) -> Result<Window, OsError>;

/// Returns the `gtk::ApplicatonWindow` from gtk crate that is used by this window.
fn gtk_window(&self) -> &gtk::ApplicationWindow;

Expand All @@ -83,6 +92,14 @@ impl WindowExtUnix for Window {
fn set_skip_taskbar(&self, skip: bool) {
self.window.set_skip_taskbar(skip);
}

fn new_from_gtk_window<T: 'static>(
event_loop_window_target: &EventLoopWindowTarget<T>,
window: gtk::ApplicationWindow,
) -> Result<Window, OsError> {
let window = UnixWindow::new_from_gtk_window(&event_loop_window_target.p, window)?;
Ok(Window { window: window })
}
}

pub trait WindowBuilderExtUnix {
Expand Down Expand Up @@ -188,6 +205,9 @@ pub trait EventLoopWindowTargetExtUnix {
// ///
// /// The pointer will become invalid when the winit `EventLoop` is destroyed.
// fn wayland_display(&self) -> Option<*mut raw::c_void>;

/// Returns the gtk application for this event loop.
fn gtk_app(&self) -> &gtk::Application;
}

impl<T> EventLoopWindowTargetExtUnix for EventLoopWindowTarget<T> {
Expand Down Expand Up @@ -224,6 +244,11 @@ impl<T> EventLoopWindowTargetExtUnix for EventLoopWindowTarget<T> {
// _ => None,
// }
// }

#[inline]
fn gtk_app(&self) -> &gtk::Application {
&self.p.app
}
}

unsafe extern "C" fn x_error_callback(
Expand Down
79 changes: 78 additions & 1 deletion src/platform_impl/linux/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,83 @@ 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);

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 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();

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);
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);
});

if let Err(e) = draw_tx.send(window_id) {
log::warn!("Failed to send redraw event to event channel: {}", e);
}

let win = Self {
window_id,
window,
default_vbox: None,
window_requests_tx,
draw_tx,
scale_factor,
position,
size,
maximized,
minimized,
fullscreen: RefCell::new(None),
inner_size_constraints: RefCell::new(WindowSizeConstraints::default()),
preferred_theme: None,
};

Ok(win)
}

pub fn id(&self) -> WindowId {
self.window_id
}
Expand Down Expand Up @@ -843,7 +920,7 @@ impl Window {
}
}

pub(crate) fn set_skip_taskbar(&self, skip: bool) {
pub fn set_skip_taskbar(&self, skip: bool) {
if let Err(e) = self
.window_requests_tx
.send((self.window_id, WindowRequest::SetSkipTaskbar(skip)))
Expand Down

0 comments on commit f54cc11

Please sign in to comment.