2023-04-21 23:51:54 +01:00
|
|
|
use crate::config::{BarPosition, MarginConfig, ModuleConfig};
|
2023-05-06 00:40:06 +01:00
|
|
|
use crate::modules::{
|
|
|
|
create_module, set_widget_identifiers, wrap_widget, ModuleInfo, ModuleLocation,
|
|
|
|
};
|
2022-09-25 22:49:00 +01:00
|
|
|
use crate::popup::Popup;
|
2023-05-29 14:01:42 +01:00
|
|
|
use crate::unique_id::get_unique_usize;
|
2023-08-25 22:55:00 +01:00
|
|
|
use crate::{Config, GlobalState};
|
2022-08-21 23:36:07 +01:00
|
|
|
use color_eyre::Result;
|
2023-04-21 23:51:54 +01:00
|
|
|
use gtk::gdk::Monitor;
|
2022-08-14 14:30:13 +01:00
|
|
|
use gtk::prelude::*;
|
2023-04-21 23:51:54 +01:00
|
|
|
use gtk::{Application, ApplicationWindow, IconTheme, Orientation};
|
2023-07-16 18:57:00 +01:00
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::rc::Rc;
|
2023-04-21 23:51:54 +01:00
|
|
|
use tracing::{debug, info};
|
2022-08-14 14:30:13 +01:00
|
|
|
|
2022-08-28 16:57:41 +01:00
|
|
|
/// Creates a new window for a bar,
|
|
|
|
/// sets it up and adds its widgets.
|
2022-08-21 23:36:07 +01:00
|
|
|
pub fn create_bar(
|
|
|
|
app: &Application,
|
|
|
|
monitor: &Monitor,
|
|
|
|
monitor_name: &str,
|
|
|
|
config: Config,
|
2023-07-16 18:57:00 +01:00
|
|
|
global_state: &Rc<RefCell<GlobalState>>,
|
2022-08-21 23:36:07 +01:00
|
|
|
) -> Result<()> {
|
2022-08-14 14:30:13 +01:00
|
|
|
let win = ApplicationWindow::builder().application(app).build();
|
2023-07-12 18:17:04 -04:00
|
|
|
let bar_name = config
|
|
|
|
.name
|
|
|
|
.clone()
|
|
|
|
.unwrap_or_else(|| format!("bar-{}", get_unique_usize()));
|
|
|
|
|
|
|
|
win.set_widget_name(&bar_name);
|
|
|
|
info!("Creating bar {}", bar_name);
|
2022-08-14 14:30:13 +01:00
|
|
|
|
2023-02-08 11:40:33 +00:00
|
|
|
setup_layer_shell(
|
|
|
|
&win,
|
|
|
|
monitor,
|
|
|
|
config.position,
|
|
|
|
config.anchor_to_edges,
|
|
|
|
config.margin,
|
|
|
|
);
|
2022-08-14 14:30:13 +01:00
|
|
|
|
2022-10-15 16:35:31 +01:00
|
|
|
let orientation = config.position.get_orientation();
|
|
|
|
|
2022-08-14 14:30:13 +01:00
|
|
|
let content = gtk::Box::builder()
|
2022-10-15 16:35:31 +01:00
|
|
|
.orientation(orientation)
|
2022-08-14 14:30:13 +01:00
|
|
|
.spacing(0)
|
|
|
|
.hexpand(false)
|
2022-10-15 16:35:31 +01:00
|
|
|
.name("bar");
|
|
|
|
|
|
|
|
let content = if orientation == Orientation::Horizontal {
|
|
|
|
content.height_request(config.height)
|
|
|
|
} else {
|
|
|
|
content.width_request(config.height)
|
|
|
|
}
|
|
|
|
.build();
|
2022-08-14 14:30:13 +01:00
|
|
|
|
|
|
|
content.style_context().add_class("container");
|
2022-12-04 23:23:22 +00:00
|
|
|
|
|
|
|
let start = create_container("start", orientation);
|
|
|
|
let center = create_container("center", orientation);
|
|
|
|
let end = create_container("end", orientation);
|
2022-08-14 14:30:13 +01:00
|
|
|
|
2022-10-15 16:27:25 +01:00
|
|
|
content.add(&start);
|
2022-08-14 14:30:13 +01:00
|
|
|
content.set_center_widget(Some(¢er));
|
2022-10-15 16:27:25 +01:00
|
|
|
content.pack_end(&end, false, false, 0);
|
2022-08-14 14:30:13 +01:00
|
|
|
|
2023-07-16 18:57:00 +01:00
|
|
|
let load_result = load_modules(&start, ¢er, &end, app, config, monitor, monitor_name)?;
|
|
|
|
global_state
|
|
|
|
.borrow_mut()
|
|
|
|
.popups_mut()
|
|
|
|
.insert(bar_name.into(), load_result.popup);
|
|
|
|
|
2022-08-14 14:30:13 +01:00
|
|
|
win.add(&content);
|
|
|
|
|
|
|
|
win.connect_destroy_event(|_, _| {
|
2022-08-25 21:53:57 +01:00
|
|
|
info!("Shutting down");
|
2022-08-14 14:30:13 +01:00
|
|
|
gtk::main_quit();
|
|
|
|
Inhibit(false)
|
|
|
|
});
|
|
|
|
|
2022-08-25 21:53:57 +01:00
|
|
|
debug!("Showing bar");
|
2022-12-04 23:23:22 +00:00
|
|
|
|
|
|
|
// show each box but do not use `show_all`.
|
|
|
|
// this ensures `show_if` option works as intended.
|
2022-11-28 21:55:08 +00:00
|
|
|
start.show();
|
|
|
|
center.show();
|
|
|
|
end.show();
|
|
|
|
content.show();
|
|
|
|
win.show();
|
2022-08-21 23:36:07 +01:00
|
|
|
|
|
|
|
Ok(())
|
2022-08-14 14:30:13 +01:00
|
|
|
}
|
|
|
|
|
2022-12-04 23:23:22 +00:00
|
|
|
/// Sets up GTK layer shell for a provided application window.
|
|
|
|
fn setup_layer_shell(
|
|
|
|
win: &ApplicationWindow,
|
|
|
|
monitor: &Monitor,
|
|
|
|
position: BarPosition,
|
|
|
|
anchor_to_edges: bool,
|
2023-02-08 11:40:33 +00:00
|
|
|
margin: MarginConfig,
|
2022-12-04 23:23:22 +00:00
|
|
|
) {
|
|
|
|
gtk_layer_shell::init_for_window(win);
|
|
|
|
gtk_layer_shell::set_monitor(win, monitor);
|
|
|
|
gtk_layer_shell::set_layer(win, gtk_layer_shell::Layer::Top);
|
|
|
|
gtk_layer_shell::auto_exclusive_zone_enable(win);
|
2023-02-08 17:30:09 +00:00
|
|
|
gtk_layer_shell::set_namespace(win, env!("CARGO_PKG_NAME"));
|
2022-12-04 23:23:22 +00:00
|
|
|
|
2023-02-08 11:40:33 +00:00
|
|
|
gtk_layer_shell::set_margin(win, gtk_layer_shell::Edge::Top, margin.top);
|
|
|
|
gtk_layer_shell::set_margin(win, gtk_layer_shell::Edge::Bottom, margin.bottom);
|
|
|
|
gtk_layer_shell::set_margin(win, gtk_layer_shell::Edge::Left, margin.left);
|
|
|
|
gtk_layer_shell::set_margin(win, gtk_layer_shell::Edge::Right, margin.right);
|
2022-12-04 23:23:22 +00:00
|
|
|
|
|
|
|
let bar_orientation = position.get_orientation();
|
|
|
|
|
|
|
|
gtk_layer_shell::set_anchor(
|
|
|
|
win,
|
|
|
|
gtk_layer_shell::Edge::Top,
|
|
|
|
position == BarPosition::Top
|
|
|
|
|| (bar_orientation == Orientation::Vertical && anchor_to_edges),
|
|
|
|
);
|
|
|
|
gtk_layer_shell::set_anchor(
|
|
|
|
win,
|
|
|
|
gtk_layer_shell::Edge::Bottom,
|
|
|
|
position == BarPosition::Bottom
|
|
|
|
|| (bar_orientation == Orientation::Vertical && anchor_to_edges),
|
|
|
|
);
|
|
|
|
gtk_layer_shell::set_anchor(
|
|
|
|
win,
|
|
|
|
gtk_layer_shell::Edge::Left,
|
|
|
|
position == BarPosition::Left
|
|
|
|
|| (bar_orientation == Orientation::Horizontal && anchor_to_edges),
|
|
|
|
);
|
|
|
|
gtk_layer_shell::set_anchor(
|
|
|
|
win,
|
|
|
|
gtk_layer_shell::Edge::Right,
|
|
|
|
position == BarPosition::Right
|
|
|
|
|| (bar_orientation == Orientation::Horizontal && anchor_to_edges),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates a `gtk::Box` container to place widgets inside.
|
|
|
|
fn create_container(name: &str, orientation: Orientation) -> gtk::Box {
|
|
|
|
let container = gtk::Box::builder()
|
|
|
|
.orientation(orientation)
|
|
|
|
.spacing(0)
|
|
|
|
.name(name)
|
|
|
|
.build();
|
|
|
|
|
|
|
|
container.style_context().add_class("container");
|
|
|
|
container
|
|
|
|
}
|
|
|
|
|
2023-07-16 18:57:00 +01:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct BarLoadResult {
|
2023-08-25 22:55:00 +01:00
|
|
|
popup: Rc<RefCell<Popup>>,
|
2023-07-16 18:57:00 +01:00
|
|
|
}
|
|
|
|
|
2022-08-28 16:57:41 +01:00
|
|
|
/// Loads the configured modules onto a bar.
|
2022-08-14 14:30:13 +01:00
|
|
|
fn load_modules(
|
|
|
|
left: >k::Box,
|
|
|
|
center: >k::Box,
|
|
|
|
right: >k::Box,
|
|
|
|
app: &Application,
|
|
|
|
config: Config,
|
2022-08-15 21:11:00 +01:00
|
|
|
monitor: &Monitor,
|
2022-08-14 20:40:11 +01:00
|
|
|
output_name: &str,
|
2023-07-16 18:57:00 +01:00
|
|
|
) -> Result<BarLoadResult> {
|
2023-01-29 18:38:57 +00:00
|
|
|
let icon_theme = IconTheme::new();
|
|
|
|
if let Some(ref theme) = config.icon_theme {
|
|
|
|
icon_theme.set_custom_theme(Some(theme));
|
|
|
|
}
|
|
|
|
|
2022-12-04 23:23:22 +00:00
|
|
|
macro_rules! info {
|
|
|
|
($location:expr) => {
|
|
|
|
ModuleInfo {
|
|
|
|
app,
|
|
|
|
bar_position: config.position,
|
|
|
|
monitor,
|
|
|
|
output_name,
|
|
|
|
location: $location,
|
2023-01-29 18:38:57 +00:00
|
|
|
icon_theme: &icon_theme,
|
2022-12-04 23:23:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2022-09-25 22:49:00 +01:00
|
|
|
|
2023-05-20 13:17:07 +01:00
|
|
|
// popup ignores module location so can bodge this for now
|
|
|
|
let popup = Popup::new(&info!(ModuleLocation::Left), config.popup_gap);
|
2023-08-25 22:55:00 +01:00
|
|
|
let popup = Rc::new(RefCell::new(popup));
|
2023-05-20 13:17:07 +01:00
|
|
|
|
2022-10-15 16:27:25 +01:00
|
|
|
if let Some(modules) = config.start {
|
2022-12-04 23:23:22 +00:00
|
|
|
let info = info!(ModuleLocation::Left);
|
2023-05-20 13:17:07 +01:00
|
|
|
add_modules(left, modules, &info, &popup)?;
|
2022-08-14 14:30:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(modules) = config.center {
|
2022-12-04 23:23:22 +00:00
|
|
|
let info = info!(ModuleLocation::Center);
|
2023-05-20 13:17:07 +01:00
|
|
|
add_modules(center, modules, &info, &popup)?;
|
2022-08-14 14:30:13 +01:00
|
|
|
}
|
|
|
|
|
2022-10-15 16:27:25 +01:00
|
|
|
if let Some(modules) = config.end {
|
2022-12-04 23:23:22 +00:00
|
|
|
let info = info!(ModuleLocation::Right);
|
2023-05-20 13:17:07 +01:00
|
|
|
add_modules(right, modules, &info, &popup)?;
|
2022-08-14 14:30:13 +01:00
|
|
|
}
|
2022-08-21 23:36:07 +01:00
|
|
|
|
2023-07-16 18:57:00 +01:00
|
|
|
let result = BarLoadResult { popup };
|
|
|
|
|
|
|
|
Ok(result)
|
2022-08-14 14:30:13 +01:00
|
|
|
}
|
|
|
|
|
2022-08-28 16:57:41 +01:00
|
|
|
/// Adds modules into a provided GTK box,
|
|
|
|
/// which should be one of its left, center or right containers.
|
2023-04-07 14:36:12 +01:00
|
|
|
fn add_modules(
|
|
|
|
content: >k::Box,
|
|
|
|
modules: Vec<ModuleConfig>,
|
|
|
|
info: &ModuleInfo,
|
2023-08-25 22:55:00 +01:00
|
|
|
popup: &Rc<RefCell<Popup>>,
|
2023-04-07 14:36:12 +01:00
|
|
|
) -> Result<()> {
|
2023-04-22 14:49:15 +01:00
|
|
|
let orientation = info.bar_position.get_orientation();
|
|
|
|
|
2022-08-14 23:32:20 +01:00
|
|
|
macro_rules! add_module {
|
2022-12-04 23:23:22 +00:00
|
|
|
($module:expr, $id:expr) => {{
|
2023-07-16 18:57:00 +01:00
|
|
|
let common = $module.common.take().expect("common config to exist");
|
|
|
|
let widget_parts = create_module(
|
|
|
|
*$module,
|
|
|
|
$id,
|
|
|
|
common.name.clone(),
|
|
|
|
&info,
|
2023-08-25 22:55:00 +01:00
|
|
|
&Rc::clone(&popup),
|
2023-07-16 18:57:00 +01:00
|
|
|
)?;
|
2023-05-06 00:40:06 +01:00
|
|
|
set_widget_identifiers(&widget_parts, &common);
|
|
|
|
|
|
|
|
let container = wrap_widget(&widget_parts.widget, common, orientation);
|
2022-12-04 23:23:22 +00:00
|
|
|
content.add(&container);
|
|
|
|
}};
|
|
|
|
}
|
2022-09-25 22:49:00 +01:00
|
|
|
|
2023-06-29 16:57:47 +01:00
|
|
|
for config in modules {
|
2023-05-29 14:01:42 +01:00
|
|
|
let id = get_unique_usize();
|
2022-12-04 23:23:22 +00:00
|
|
|
match config {
|
2023-02-25 14:30:45 +00:00
|
|
|
#[cfg(feature = "clipboard")]
|
|
|
|
ModuleConfig::Clipboard(mut module) => add_module!(module, id),
|
2023-02-01 20:42:05 +00:00
|
|
|
#[cfg(feature = "clock")]
|
2022-12-04 23:23:22 +00:00
|
|
|
ModuleConfig::Clock(mut module) => add_module!(module, id),
|
2023-02-01 20:42:05 +00:00
|
|
|
ModuleConfig::Custom(mut module) => add_module!(module, id),
|
|
|
|
ModuleConfig::Focused(mut module) => add_module!(module, id),
|
2023-04-07 14:27:16 +01:00
|
|
|
ModuleConfig::Label(mut module) => add_module!(module, id),
|
2023-02-01 20:42:05 +00:00
|
|
|
ModuleConfig::Launcher(mut module) => add_module!(module, id),
|
|
|
|
#[cfg(feature = "music")]
|
|
|
|
ModuleConfig::Music(mut module) => add_module!(module, id),
|
2022-12-04 23:23:22 +00:00
|
|
|
ModuleConfig::Script(mut module) => add_module!(module, id),
|
2023-02-01 20:42:05 +00:00
|
|
|
#[cfg(feature = "sys_info")]
|
2022-12-04 23:23:22 +00:00
|
|
|
ModuleConfig::SysInfo(mut module) => add_module!(module, id),
|
2023-02-01 20:42:05 +00:00
|
|
|
#[cfg(feature = "tray")]
|
2022-12-04 23:23:22 +00:00
|
|
|
ModuleConfig::Tray(mut module) => add_module!(module, id),
|
2023-03-19 02:16:49 +05:30
|
|
|
#[cfg(feature = "upower")]
|
|
|
|
ModuleConfig::Upower(mut module) => add_module!(module, id),
|
2023-02-01 20:42:05 +00:00
|
|
|
#[cfg(feature = "workspaces")]
|
|
|
|
ModuleConfig::Workspaces(mut module) => add_module!(module, id),
|
2022-12-04 23:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
2022-09-25 22:49:00 +01:00
|
|
|
|
2022-12-04 23:23:22 +00:00
|
|
|
Ok(())
|
|
|
|
}
|