libcosmic/examples/app_library/window/mod.rs

172 lines
6.1 KiB
Rust
Raw Normal View History

2022-01-19 16:00:02 -05:00
use crate::window_inner::AppLibraryWindowInner;
use cascade::cascade;
2022-01-19 16:00:02 -05:00
use gdk4::subclass::prelude::ObjectSubclassExt;
use gdk4_x11::X11Display;
use glib::Object;
2021-12-30 17:53:06 -05:00
use gtk4::prelude::*;
2022-01-14 17:53:11 -05:00
use gtk4::Application;
2022-01-19 16:00:02 -05:00
use gtk4::{gdk, gio, glib};
use libcosmic::x;
2022-01-19 16:00:02 -05:00
pub fn create(app: &Application, monitor: gdk::Monitor) {
//quit shortcut
2022-01-21 11:54:55 -05:00
app.set_accels_for_action("app.quit", &["<primary>W", "Escape"]);
setup_shortcuts(app);
2022-01-19 16:00:02 -05:00
#[cfg(feature = "layer-shell")]
if let Some(wayland_monitor) = monitor.downcast_ref() {
wayland_create(&app, wayland_monitor);
return;
}
cascade! {
AppLibraryWindow::new(&app);
..show();
};
}
2022-01-21 11:54:55 -05:00
fn setup_shortcuts(app: &Application) {
2022-01-19 16:00:02 -05:00
let action_quit = gio::SimpleAction::new("quit", None);
2022-01-21 11:54:55 -05:00
action_quit.connect_activate(glib::clone!(@weak app => move |_, _| {
app.quit();
2022-01-19 16:00:02 -05:00
}));
2022-01-21 11:54:55 -05:00
app.add_action(&action_quit);
2022-01-19 16:00:02 -05:00
}
#[cfg(feature = "layer-shell")]
fn wayland_create(app: &Application, monitor: &gdk4_wayland::WaylandMonitor) {
2022-01-21 11:54:55 -05:00
use libcosmic::wayland::{Anchor, KeyboardInteractivity, Layer, LayerShellWindow};
2022-01-19 16:00:02 -05:00
let window = cascade! {
LayerShellWindow::new(Some(monitor), Layer::Top, "");
2022-01-21 11:54:55 -05:00
..set_width_request(800);
..set_height_request(600);
2022-01-19 16:00:02 -05:00
// ..set_title(Some("Cosmic App Library"));
// ..set_decorated(false);
2022-01-21 11:54:55 -05:00
..set_keyboard_interactivity(KeyboardInteractivity::OnDemand);
2022-01-19 16:00:02 -05:00
..add_css_class("root_window");
..set_anchor(Anchor::empty());
..show();
};
let app_library = AppLibraryWindowInner::new();
window.set_child(Some(&app_library));
dbg!(&window);
2022-01-21 11:54:55 -05:00
window.connect_is_active_notify(glib::clone!(@weak app => move |w| {
if !w.is_active() {
app.quit();
}
}));
2022-01-19 16:00:02 -05:00
window.show();
2022-01-21 11:54:55 -05:00
2022-01-19 16:00:02 -05:00
// setup_shortcuts(window.clone().upcast::<gtk4::ApplicationWindow>());
// XXX
unsafe { window.set_data("cosmic-app-hold", app.hold()) };
}
mod imp;
glib::wrapper! {
2022-01-14 17:53:11 -05:00
pub struct AppLibraryWindow(ObjectSubclass<imp::AppLibraryWindow>)
2021-12-30 16:54:35 -05:00
@extends gtk4::ApplicationWindow, gtk4::Window, gtk4::Widget,
@implements gio::ActionGroup, gio::ActionMap, gtk4::Accessible, gtk4::Buildable,
gtk4::ConstraintTarget, gtk4::Native, gtk4::Root, gtk4::ShortcutManager;
}
2022-01-14 17:53:11 -05:00
impl AppLibraryWindow {
pub fn new(app: &Application) -> Self {
2022-01-14 17:53:11 -05:00
let self_: Self =
Object::new(&[("application", app)]).expect("Failed to create `AppLibraryWindow`.");
let imp = imp::AppLibraryWindow::from_instance(&self_);
cascade! {
&self_;
..set_width_request(1200);
..set_title(Some("Cosmic App Library"));
..set_decorated(false);
..add_css_class("root_window");
};
2022-01-19 16:00:02 -05:00
let app_library = AppLibraryWindowInner::new();
self_.set_child(Some(&app_library));
2022-01-19 16:00:02 -05:00
imp.inner.set(app_library).unwrap();
2022-01-14 17:53:11 -05:00
Self::setup_callbacks(&self_);
2022-01-19 16:00:02 -05:00
self_
}
fn setup_callbacks(&self) {
// Get state
2021-12-30 16:54:35 -05:00
let window = self.clone().upcast::<gtk4::Window>();
window.connect_realize(move |window| {
2022-01-21 11:54:55 -05:00
println!("gtk window setup");
if let Some((display, surface)) = x::get_window_x11(window) {
// ignore all x11 errors...
let xdisplay = display
.clone()
.downcast::<X11Display>()
.expect("Failed to downgrade X11 Display.");
xdisplay.error_trap_push();
unsafe {
x::change_property(
&display,
&surface,
"_NET_WM_WINDOW_TYPE",
x::PropMode::Replace,
&[x::Atom::new(&display, "_NET_WM_WINDOW_TYPE_DIALOG").unwrap()],
);
}
2022-01-19 13:56:20 -05:00
let resize = glib::clone!(@weak window => move || {
let height = window.height();
let width = window.width();
if let Some((display, _surface)) = x::get_window_x11(&window) {
2022-01-19 10:19:56 -05:00
let geom = display
.primary_monitor().geometry();
let monitor_x = geom.x();
let monitor_y = geom.y();
let monitor_width = geom.width();
let monitor_height = geom.height();
// dbg!(monitor_width);
// dbg!(monitor_height);
// dbg!(width);
// dbg!(height);
2022-01-19 13:56:20 -05:00
unsafe { x::set_position(&display, &surface,
monitor_x + monitor_width / 2 - width / 2,
monitor_y + monitor_height / 2 - height / 2)};
}
});
2022-01-19 10:19:56 -05:00
let s = window.surface();
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");
}
});
let imp = imp::AppLibraryWindow::from_instance(&self);
let inner = imp.inner.get().unwrap();
window.connect_is_active_notify(glib::clone!(@weak inner => move |win| {
let app = win
.application()
.expect("could not get application from window");
let active_window = app
.active_window()
.expect("no active window available, closing app library.");
if win == &active_window && !win.is_active() && !inner.is_popup_active() {
2022-01-21 11:54:55 -05:00
win.close();
}
}));
}
}