From 701cfe1ef208829d3eda234b3801627ede6f32ce Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 28 Dec 2021 09:52:05 -0500 Subject: [PATCH] move launcher window to center when it is resized --- examples/launcher/main.rs | 21 +++++--- examples/launcher/window/mod.rs | 87 +++++++++++++++++++++++++++------ 2 files changed, 86 insertions(+), 22 deletions(-) diff --git a/examples/launcher/main.rs b/examples/launcher/main.rs index 5d8aeb5a..03c54c55 100644 --- a/examples/launcher/main.rs +++ b/examples/launcher/main.rs @@ -1,27 +1,26 @@ mod application_object; mod application_row; mod window; - +use self::application_object::ApplicationObject; +use self::window::Window; use gdk4::Display; use gio::DesktopAppInfo; +use gtk::gio; +use gtk::glib; +use gtk::prelude::*; use gtk::Application; use gtk4 as gtk; use gtk4::CssProvider; use gtk4::StyleContext; use once_cell::sync::OnceCell; - -use gtk::gio; -use gtk::glib; -use gtk::prelude::*; use pop_launcher_service::IpcClient; use postage::mpsc::Sender; use postage::prelude::*; - -use self::application_object::ApplicationObject; -use self::window::Window; +use x11rb::rust_connection::RustConnection; const NUM_LAUNCHER_ITEMS: u8 = 10; static TX: OnceCell> = OnceCell::new(); +static X11_CONN: OnceCell = OnceCell::new(); fn icon_source(icon: >k::Image, source: &Option) { match source { @@ -96,6 +95,12 @@ fn main() { println!("failed to set global Sender. Exiting"); std::process::exit(1); }; + let (conn, _screen_num) = x11rb::connect(None).expect("Failed to connect to X"); + if X11_CONN.set(conn).is_err() { + println!("failed to set X11_CONN. Exiting"); + std::process::exit(1); + }; + let window = Window::new(app); window.show(); diff --git a/examples/launcher/window/mod.rs b/examples/launcher/window/mod.rs index 3fc0bada..36c8db38 100644 --- a/examples/launcher/window/mod.rs +++ b/examples/launcher/window/mod.rs @@ -1,17 +1,24 @@ mod imp; +use crate::application_row::ApplicationRow; use crate::ApplicationObject; use crate::TX; -use gtk4 as gtk; -use postage::prelude::Sink; - -use crate::application_row::ApplicationRow; +use crate::X11_CONN; +use gdk4::Rectangle; +use gdk4_x11::X11Display; +use gdk4_x11::X11Surface; use glib::Object; use gtk::prelude::*; use gtk::subclass::prelude::*; use gtk::{gio, glib}; use gtk::{Application, SignalListItemFactory}; - +use gtk4 as gtk; use libcosmic::x; +use postage::prelude::Sink; +use x11rb::connection::Connection; +use x11rb::protocol::xproto; +use x11rb::protocol::xproto::ConnectionExt as OtherConnectionExt; +use x11rb::protocol::xproto::*; +use x11rb::wrapper::ConnectionExt; glib::wrapper! { pub struct Window(ObjectSubclass) @@ -133,15 +140,67 @@ impl Window { window.connect_realize(move |window| { if let Some((display, surface)) = x::get_window_x11(window) { - unsafe { - x::change_property( - &display, - &surface, - "_NET_WM_WINDOW_TYPE", - x::PropMode::Replace, - &[x::Atom::new(&display, "_NET_WM_WINDOW_TYPE_DIALOG").unwrap()], - ); - } + // ignore all x11 errors... + let xdisplay = display.clone().downcast::().expect("Failed to downgrade X11 Display."); + xdisplay.error_trap_push(); + let conn = X11_CONN.get().expect("Failed to get X11 connection"); + let window_type_atom = conn.intern_atom(false, b"_NET_WM_WINDOW_TYPE").unwrap().reply().unwrap().atom; + let dock_type_atom = conn.intern_atom(false, b"_NET_WM_WINDOW_TYPE_DOCK").unwrap().reply().unwrap().atom; + conn.change_property32( + PropMode::REPLACE, + surface.xid().try_into().unwrap(), + window_type_atom, + AtomEnum::ATOM, + &[dock_type_atom] + ).unwrap(); + let resize = glib::clone!(@weak window => move || { + let s = window.surface().expect("Failed to get Surface for Window"); + let height = window.height(); + let width = window.width(); + + if let Some((display, _surface)) = x::get_window_x11(&window) { + let monitor = display + .primary_monitor() + .expect("Failed to get Monitor"); + let Rectangle { + x: monitor_x, + y: monitor_y, + width: monitor_width, + height: monitor_height, + } = monitor.geometry(); + // dbg!(monitor_width); + // dbg!(monitor_height); + // dbg!(width); + // dbg!(height); + let w_conf = xproto::ConfigureWindowAux::default() + .x((monitor_x + monitor_width / 2 - width / 2).clamp(0, monitor_x + monitor_width - 1)) + .y((monitor_y + monitor_height / 2 - height / 2).clamp(0, monitor_y + monitor_height - 1)); + let conn = X11_CONN.get().expect("Failed to get X11_CONN"); + + let x11surface = gdk4_x11::X11Surface::xid( + &s.clone().downcast::() + .expect("Failed to downcast Surface to X11Surface"), + ); + conn.configure_window( + x11surface.try_into().expect("Failed to convert XID"), + &w_conf, + ) + .expect("failed to configure window..."); + conn.flush().expect("failed to flush"); + } + }); + let s = window.surface().expect("Failed to get Surface for Window"); + let resize_height = resize.clone(); + s.connect_height_notify(move |_s| { + glib::source::idle_add_local_once(resize_height.clone()); + }); + let resize_width = resize.clone(); + s.connect_width_notify(move |_s| { + glib::source::idle_add_local_once(resize_width.clone()); + }); + s.connect_scale_factor_notify(move |_s| { + glib::source::idle_add_local_once(resize.clone()); + }); } else { println!("failed to get X11 window"); }