Skip to content
This repository was archived by the owner on Apr 23, 2025. It is now read-only.

Commit 31b2197

Browse files
author
vars1ty
committed
Spacings can now be styled via CSS
1 parent 8df27c3 commit 31b2197

12 files changed

+94
-85
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "hybrid-bar"
33
authors = [ "varsity <[email protected]>" ]
4-
version = "0.2.1"
4+
version = "0.2.2"
55
edition = "2021"
66
description = "A simple status bar made for wlroots compositors."
77
license = "MIT"

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ It supports:
1111
- Buttons with `on click` actions via a bash command;
1212
- Spacings;
1313
- Transparency (+ blur if your compositor supports it);
14-
- Custom CSS
14+
- Custom CSS;
15+
- Custom update-frequency for dynamic widgets (ones with a `command` set)
1516

1617
In other words, it's a simple Wayland status bar that does one thing: Display the stuff __you__ put onto it. Nothing more, nothing less, no over-engineered dogshit.
1718
## I have no config
@@ -27,7 +28,7 @@ Here's an example:
2728

2829
```json
2930
{
30-
"background": {
31+
"hybrid": {
3132
"r": 10,
3233
"g": 10,
3334
"b": 10,

WIDGETS.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
# Widgets
2+
> **Warning**:
3+
> Widgets with a command set are updated every few milliseconds from the value at `hybrid:update_rate`.
4+
>
5+
> An unspecified value (or one below `5`) will default to `5`, meaning it calls bash-commands every 5 milliseconds.
6+
>
7+
> This can be performance intensive, so it's recommended that you set the update-rate to something like `100`.
8+
***
29
Available widgets:
310

411
Labels:

examples/config.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
2-
"background": {
2+
"hybrid": {
3+
"update_rate": 100,
34
"r": 10,
45
"g": 10,
56
"b": 10,

src/config.rs

+11-12
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
use crate::{
2-
constant_messages::{FAILED_PARSING_CONFIG, FAILED_PARSING_CONTENT},
3-
environment, proc,
4-
};
1+
use crate::{environment, proc};
52
use json::JsonValue;
6-
use std::{any::TypeId, fmt::Display, fs, io::Error};
3+
use std::{any::TypeId, fmt::Display, fs};
74

85
/// Gets the root home path to Hybrid.
96
pub fn get_path() -> String {
@@ -21,27 +18,29 @@ pub fn read_config() -> JsonValue {
2118
&fs::read_to_string(&conf_path)
2219
.expect(format!("[ERROR] Failed reading config file from '{conf_path}'!\n").as_str()),
2320
)
24-
.expect(FAILED_PARSING_CONFIG)
21+
.expect(format!("[ERROR] Failed parsing config from '{conf_path}'!\n").as_str())
2522
}
2623

2724
/// If the `key` exists inside `root`, the value of it is returned.
2825
/// If not, a default value is instead returned.
29-
pub fn try_get<T>(root: &str, key: &str) -> Result<(String, i32), Error>
26+
pub fn try_get<T>(root: &str, key: &str) -> (String, i32)
3027
where
3128
T: Display + 'static,
3229
{
3330
let cfg = &read_config()[root];
3431
let is_string = TypeId::of::<T>() == TypeId::of::<String>();
3532
if cfg.has_key(key) {
3633
if !is_string {
37-
return Ok((
34+
return (
3835
String::default(),
39-
cfg[key].as_i32().expect(FAILED_PARSING_CONTENT),
40-
));
36+
cfg[key]
37+
.as_i32()
38+
.expect(format!("[ERROR] Failed parsing {root}:{key} as i32!\n").as_str()),
39+
);
4140
}
4241

43-
Ok((cfg[key].to_string(), 0))
42+
(cfg[key].to_string(), 0)
4443
} else {
45-
Ok((String::default(), 0))
44+
(String::default(), 0)
4645
}
4746
}

src/constant_messages.rs

-16
This file was deleted.

src/loop.rs

+26-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{constant_messages::CANNOT_ACCESS_VEC, debug::log, proc, ui};
1+
use crate::{config, debug::log, proc, ui};
22
use gtk::traits::*;
33
use std::time::Duration;
44

@@ -10,13 +10,35 @@ pub fn update() {
1010
glib::Continue(true)
1111
};
1212

13-
// Executes the "tick" closure every 100ms.
14-
glib::timeout_add_local(Duration::from_millis(100), tick);
13+
// Executes the "tick" closure for every millisecond specified in hybrid:update_rate.
14+
15+
glib::timeout_add_local(Duration::from_millis(get_update_rate()), tick);
16+
}
17+
18+
/// Returns the set update-rate.
19+
fn get_update_rate() -> u64 {
20+
let mut update_rate = config::try_get::<i32>("hybrid", "update_rate").1;
21+
// Clamp the value to a minimum of 5.
22+
if update_rate < 5 {
23+
update_rate = 5;
24+
}
25+
26+
if update_rate < 100 {
27+
println!("[HYBRID] [CRITICAL WARNING] Your update-rate is {update_rate}ms! Expect performance drawbacks")
28+
}
29+
30+
update_rate
31+
.try_into()
32+
.expect("[ERROR] Cannot convert update_rate into u64!\n")
1533
}
1634

1735
/// Updates all of the labels.
1836
fn update_labels() {
19-
for widget in ui::VEC.lock().expect(CANNOT_ACCESS_VEC).iter() {
37+
for widget in ui::VEC
38+
.lock()
39+
.expect("[ERROR] Cannot access ui::VEC!\n")
40+
.iter()
41+
{
2042
let mut text = widget.text.clone();
2143
// Append to the cloned text if the command isn't empty.
2244
if !widget.command.is_empty() {

src/main.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ extern crate lazy_static;
44
#[path = "widgets/button_widget.rs"]
55
mod button_widget;
66
mod config;
7-
mod constant_messages;
87
mod debug;
98
mod environment;
109
#[path = "widgets/label_widget.rs"]
@@ -17,9 +16,9 @@ mod structures;
1716
mod ui;
1817
mod widget;
1918

20-
use constant_messages::*;
2119
use debug::log;
2220
use gtk::gdk::*;
21+
use gtk::gio::ApplicationFlags;
2322
use gtk::prelude::*;
2423
use gtk::*;
2524
use gtk_layer_shell::Edge;
@@ -32,7 +31,7 @@ use widget::HWidget;
3231
fn get_anchors() -> [(gtk_layer_shell::Edge, bool); 4] {
3332
let pos = environment::try_get_var("HYBRID_POS", "TOP");
3433
if pos != "TOP" && pos != "BOTTOM" {
35-
panic!("{}", INVALID_BAR_POSITION)
34+
panic!("[ERROR] Invalid position! Values: [ TOP, BOTTOM ]\n")
3635
}
3736

3837
// If the position was valid, return the result.
@@ -88,7 +87,7 @@ fn load_css() {
8887

8988
// Add the provider to the default screen
9089
StyleContext::add_provider_for_screen(
91-
&Screen::default().expect(MISSING_DISPLAY),
90+
&Screen::default().expect("[ERROR] Couldn't find any valid displays!\n"),
9291
&provider,
9392
STYLE_PROVIDER_PRIORITY_APPLICATION,
9493
);
@@ -97,7 +96,7 @@ fn load_css() {
9796
/// Called upon application startup.
9897
fn main() {
9998
log("Building application...");
100-
let application = Application::new(None, Default::default());
99+
let application = Application::new(None, ApplicationFlags::default());
101100
log("Loading CSS...");
102101
application.connect_startup(|_| load_css());
103102
log("Creating viewport...");
@@ -120,9 +119,9 @@ fn set_visual(window: &ApplicationWindow, _screen: Option<&gdk::Screen>) {
120119

121120
/// Converts the value of a child inside `background` to a `f64`.
122121
fn get_background_float(cfg: &JsonValue, identifier: &str, from_255: bool) -> f64 {
123-
let mut res = cfg["background"][identifier]
122+
let mut res = cfg["hybrid"][identifier]
124123
.as_f64()
125-
.expect("[ERROR] Failed converting background:{identifier} to f64!\n");
124+
.expect(format!("[ERROR] Failed converting hybrid:{identifier} to f64!\n").as_str());
126125

127126
// Only divide by 255 if explicitly told to.
128127
if from_255 {
@@ -144,6 +143,6 @@ fn draw(_: &ApplicationWindow, ctx: &cairo::Context) -> Inhibit {
144143
// Apply
145144
ctx.set_source_rgba(r, g, b, a);
146145
ctx.set_operator(cairo::Operator::Screen);
147-
ctx.paint().expect(FAILED_PAINTING);
146+
ctx.paint().expect("[ERROR] Failed painting!\n");
148147
Inhibit(false)
149148
}

src/ui.rs

+27-23
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
use crate::{
2-
button_widget::ButtonWidget,
3-
constant_messages::{INVALID_IDENTIFIER, INVALID_WIDGET_ALIGNMENT},
4-
debug::log,
5-
r#loop::update,
6-
spacing_widget::SpacingWidget,
7-
*,
2+
button_widget::ButtonWidget, debug::log, r#loop::update, spacing_widget::SpacingWidget, *,
83
};
94
use gtk::traits::*;
105
use std::{str::FromStr, sync::Mutex};
@@ -37,6 +32,21 @@ pub fn build_widgets(window: &gtk::ApplicationWindow) {
3732
update();
3833
}
3934

35+
/// Gets the widget name for a specific key.
36+
fn get_widget_name(identifiers: Vec<&str>, separator: char, count: usize) -> String {
37+
// Stores the unique widget name temporarily.
38+
let mut widget_name = String::default();
39+
for i in 1..count {
40+
widget_name.push_str(identifiers[i]);
41+
// Only add '_' to the end if the remaining amount of items isn't 1.
42+
if i != count - 1 {
43+
widget_name.push(separator);
44+
}
45+
}
46+
47+
widget_name
48+
}
49+
4050
/// Creates all of the widgets.
4151
fn create_components(left: &Box, centered: &Box, right: &Box) {
4252
// Add all of the widgets defined from the config.
@@ -60,28 +70,21 @@ fn create_components(left: &Box, centered: &Box, right: &Box) {
6070
let widget_alignment = key
6171
.split(ALIGNMENT)
6272
.nth(0)
63-
.expect(INVALID_WIDGET_ALIGNMENT)
73+
.expect("[ERROR] Invalid widget alignment!\n")
6474
.to_uppercase();
6575

66-
// Stores the unique widget name temporarily.
67-
let mut widget_name = String::default();
68-
for i in 1..count {
69-
widget_name.push_str(identifiers[i]);
70-
// Only add '_' to the end if the remaining amount of items isn't 1.
71-
if i != count - 1 {
72-
widget_name.push(SEPARATOR);
73-
}
74-
}
75-
7676
// Base keys, text and command being optional.
77-
let text = config::try_get::<String>(key, "text").unwrap().0;
78-
let command = config::try_get::<String>(key, "command").unwrap().0;
79-
let alignment = structures::Align::from_str(&widget_alignment).expect(INVALID_IDENTIFIER);
77+
let text = config::try_get::<String>(key, "text").0;
78+
let command = config::try_get::<String>(key, "command").0;
79+
let alignment = structures::Align::from_str(&widget_alignment)
80+
.expect("[ERROR] Invalid widget alignment!\n");
8081

8182
log(format!(
8283
"Adding widget '{identifier}' with alignment '{widget_alignment}'",
8384
));
8485

86+
let widget_name = get_widget_name(identifiers, SEPARATOR, count);
87+
8588
// Check for identifiers.
8689
// Defo. not clean or pretty, will probably fix it later.
8790
if identifier.contains("label") {
@@ -103,14 +106,15 @@ fn create_components(left: &Box, centered: &Box, right: &Box) {
103106
button.add(alignment, left, centered, right)
104107
} else if identifier.contains("spacing") {
105108
let spacing = SpacingWidget {
106-
spacing_start: config::try_get::<i32>(key, "spacing_start").unwrap().1,
107-
spacing_end: config::try_get::<i32>(key, "spacing_end").unwrap().1,
109+
name: widget_name,
110+
spacing_start: config::try_get::<i32>(key, "spacing_start").1,
111+
spacing_end: config::try_get::<i32>(key, "spacing_end").1,
108112
};
109113

110114
spacing.add(alignment, left, centered, right)
111115
} else {
112116
// You are stupid.
113-
panic!("{}", INVALID_WIDGET_IDENTIFIER)
117+
panic!("[ERROR] There are no widgets identified as '{identifier}'!\n")
114118
}
115119
}
116120
}

src/widgets/button_widget.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
use crate::{debug::log, structures::Align, widget::HWidget};
2-
use gtk::{
3-
traits::{ButtonExt, ContainerExt, WidgetExt},
4-
Box, Button,
5-
};
2+
use gtk::{traits::*, *};
63

74
/// Creates a new button widget.
85
pub struct ButtonWidget {
@@ -34,4 +31,3 @@ impl HWidget for ButtonWidget {
3431
log(format!("Added a new button widget named '{}'", self.name));
3532
}
3633
}
37-

src/widgets/label_widget.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
1-
use gtk::{
2-
traits::{ContainerExt, WidgetExt},
3-
Box, Label,
4-
};
5-
6-
use crate::{
7-
constant_messages::CANNOT_ACCESS_VEC, debug::log, structures::Align, ui::VEC, widget::HWidget,
8-
};
1+
use crate::{debug::log, structures::Align, ui::VEC, widget::HWidget};
2+
use gtk::{traits::*, *};
93

104
/// Creates a new label widget.
115
pub struct LabelWidget {
@@ -32,6 +26,8 @@ impl HWidget for LabelWidget {
3226
}
3327

3428
log(format!("Added a new label widget named '{}'", self.name));
35-
VEC.lock().expect(CANNOT_ACCESS_VEC).push(self);
29+
VEC.lock()
30+
.expect("[ERROR] Cannot access ui::VEC!\n")
31+
.push(self);
3632
}
3733
}

src/widgets/spacing_widget.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
use crate::{debug::log, structures::Align, widget::HWidget};
2-
use gtk::{
3-
traits::{ContainerExt, WidgetExt},
4-
Box, Orientation,
5-
};
2+
use gtk::{traits::*, *};
63

74
/// Creates a new basic spacing widget.
85
pub struct SpacingWidget {
6+
pub name: String,
97
pub spacing_start: i32,
108
pub spacing_end: i32,
119
}
@@ -14,6 +12,8 @@ pub struct SpacingWidget {
1412
impl HWidget for SpacingWidget {
1513
fn add(self, align: Align, left: &Box, centered: &Box, right: &Box) {
1614
let widget = Box::new(Orientation::Horizontal, 0);
15+
// 0.2.2: Allow for named spacings
16+
widget.set_widget_name(&self.name);
1717
widget.set_margin_start(self.spacing_start);
1818
widget.set_margin_end(self.spacing_end);
1919

0 commit comments

Comments
 (0)