1
0
Fork 0
mirror of https://github.com/Zedfrigg/ironbar.git synced 2025-04-20 11:54:23 +02:00
ironbar/src/popup.rs

142 lines
4.3 KiB
Rust
Raw Normal View History

use std::collections::HashMap;
use crate::config::BarPosition;
use crate::modules::ModuleInfo;
2022-08-15 21:11:00 +01:00
use gtk::gdk::Monitor;
2022-08-14 14:30:13 +01:00
use gtk::prelude::*;
use gtk::{ApplicationWindow, Button};
use tracing::debug;
2022-08-14 14:30:13 +01:00
#[derive(Debug, Clone)]
pub struct Popup {
pub window: ApplicationWindow,
pub cache: HashMap<usize, gtk::Box>,
2022-08-15 21:11:00 +01:00
monitor: Monitor,
2022-08-14 14:30:13 +01:00
}
impl Popup {
/// Creates a new popup window.
/// This includes setting up gtk-layer-shell
/// and an empty `gtk::Box` container.
pub fn new(module_info: &ModuleInfo) -> Self {
let pos = module_info.bar_position;
let win = ApplicationWindow::builder()
.application(module_info.app)
.build();
2022-08-14 14:30:13 +01:00
gtk_layer_shell::init_for_window(&win);
gtk_layer_shell::set_layer(&win, gtk_layer_shell::Layer::Overlay);
gtk_layer_shell::set_margin(
&win,
gtk_layer_shell::Edge::Top,
if pos == &BarPosition::Top { 5 } else { 0 },
);
gtk_layer_shell::set_margin(
&win,
gtk_layer_shell::Edge::Bottom,
if pos == &BarPosition::Bottom { 5 } else { 0 },
);
2022-08-14 14:30:13 +01:00
gtk_layer_shell::set_margin(&win, gtk_layer_shell::Edge::Left, 0);
gtk_layer_shell::set_margin(&win, gtk_layer_shell::Edge::Right, 0);
gtk_layer_shell::set_anchor(&win, gtk_layer_shell::Edge::Top, pos == &BarPosition::Top);
gtk_layer_shell::set_anchor(
&win,
gtk_layer_shell::Edge::Bottom,
pos == &BarPosition::Bottom,
);
2022-08-14 14:30:13 +01:00
gtk_layer_shell::set_anchor(&win, gtk_layer_shell::Edge::Left, true);
gtk_layer_shell::set_anchor(&win, gtk_layer_shell::Edge::Right, false);
win.connect_leave_notify_event(|win, ev| {
2022-08-15 21:11:00 +01:00
const THRESHOLD: f64 = 3.0;
2022-08-14 14:30:13 +01:00
let (w, _h) = win.size();
let (x, y) = ev.position();
// some child widgets trigger this event
// so check we're actually outside the window
if x < THRESHOLD || y < THRESHOLD || x > f64::from(w) - THRESHOLD {
win.hide();
}
Inhibit(false)
});
Self {
window: win,
cache: HashMap::new(),
monitor: module_info.monitor.clone(),
}
}
pub fn register_content(&mut self, key: usize, content: gtk::Box) {
debug!("Registered popup content for #{}", key);
self.cache.insert(key, content);
}
pub fn show_content(&self, key: usize) {
self.clear_window();
if let Some(content) = self.cache.get(&key) {
content.style_context().add_class("popup");
self.window.add(content);
}
}
fn clear_window(&self) {
let children = self.window.children();
for child in children {
self.window.remove(&child);
2022-08-14 14:30:13 +01:00
}
}
/// Shows the popover
pub fn show(&self, button_x: i32, button_width: i32) {
2022-08-14 14:30:13 +01:00
self.window.show_all();
self.set_pos(button_x, button_width);
2022-08-14 14:30:13 +01:00
}
/// Hides the popover
pub fn hide(&self) {
self.window.hide();
}
2022-08-15 21:11:00 +01:00
/// Checks if the popup is currently visible
pub fn is_visible(&self) -> bool {
self.window.is_visible()
}
2022-08-15 21:11:00 +01:00
/// Sets the popover's X position relative to the left border of the screen
fn set_pos(&self, button_x: i32, button_width: i32) {
2022-08-15 21:11:00 +01:00
let screen_width = self.monitor.workarea().width();
let (popup_width, _popup_height) = self.window.size();
2022-08-15 21:11:00 +01:00
let widget_center = f64::from(button_x) + f64::from(button_width) / 2.0;
2022-08-15 21:11:00 +01:00
let mut offset = (widget_center - (f64::from(popup_width) / 2.0)).round();
if offset < 5.0 {
offset = 5.0;
} else if offset > f64::from(screen_width - popup_width) - 5.0 {
offset = f64::from(screen_width - popup_width) - 5.0;
}
gtk_layer_shell::set_margin(&self.window, gtk_layer_shell::Edge::Left, offset as i32);
}
/// Gets the absolute X position of the button
/// and its width.
pub fn button_pos(button: &Button) -> (i32, i32) {
let button_width = button.allocation().width();
let top_level = button.toplevel().expect("Failed to get top-level widget");
let (button_x, _) = button
.translate_coordinates(&top_level, 0, 0)
.unwrap_or((0, 0));
(button_x, button_width)
}
2022-08-14 14:30:13 +01:00
}