Skip to content

Commit

Permalink
added more monitors to Stats widget, make it refresh every interval, …
Browse files Browse the repository at this point in the history
…update readme
  • Loading branch information
laudominik committed Sep 15, 2024
1 parent 9711329 commit 2c06370
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 36 deletions.
21 changes: 18 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
# XROAGWEM
Window manager written in Rust. Heavily inspired by DWM. The goal is to support all of the features from awesomewm I use on daily basis and switch to it:
Window manager for X11 written in Rust. Pretty usable (for a single display as of now), still many bugs.

The goal is to support all of the features from [awesomewm](https://github.com/awesomeWM/awesome) I use on daily basis (my config [here](https://github.com/laudominik/awesome-config)) and switch to it:
* auto cascade tiling ✔
* fullscreen window ✔
* floating window ✔
* wallpaper ✔
* spawning some scripts with shell on startup ✔
* top bar
* top bar
* mouse motions ✔
* multiple workspaces ✔
* keybindings ✔
* resetting the wm
* two screens support

See [config.rs](src/config.rs) for my wm configuration.
as you can probably tell, there's not too much functionality I care about.

## Installation
Clone, then
```
cargo build --release
```
Add the `exec <path to xroagwem binary>` to your xinitrc (it's in `target/release/xroagwem`).

## Configuration
See [config.rs](src/config.rs) for the wm configuration, it requires a rebuild on each config change.

## References
Heavily inspired by [dwm](https://dwm.suckless.org/).
1 change: 0 additions & 1 deletion script/xephyr-run
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@ export XROAGWEM_PATH=target/debug/xroagwem
Xephyr -screen 1920x1080 :1 &
sleep 1
$XROAGWEM_PATH
# & sleep 1 ; DISPLAY=:1 $XROAGWEM_PATH
8 changes: 6 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::HashSet;
use std::process::Command;
use std::sync::Arc;
use std::thread::spawn;
use std::time::Duration;

use x11::keysym;
use x11::xlib;
Expand All @@ -11,6 +11,7 @@ use crate::state::WIDGETS;
use crate::state::{self, Keybinding, Mousemotion, KEYBINDINGS, MOUSEMOTIONS};
use crate::style::Paddings;
use crate::style::{ColorScheme, ColorSchemes, Style};
use crate::widgets::Ctx;
use crate::widgets::Stats;
use crate::widgets::{TopBar, Widget};
use crate::wm::WindowExt;
Expand Down Expand Up @@ -52,6 +53,8 @@ pub static STYLE: Style = Style {
}
};

pub static WIDGET_REFRESH: Duration = Duration::from_secs(15);

const MODKEY: u32 = xlib::Mod4Mask;
const MODKEY_SHIFT: u32 = MODKEY | xlib::ShiftMask;
const MODKEY_CTRL: u32 = MODKEY | xlib::ControlMask;
Expand All @@ -61,6 +64,7 @@ pub fn make(state: &mut state::State){
/* widgets */
{
add_widget!(state, TopBar, "Noto Sans CJK JP-12");
add_widget!(state, Stats, "Noto Sans-12");
}

/* mouse motion */
Expand Down Expand Up @@ -163,7 +167,7 @@ macro_rules! custom {

impl state::State<'_> {
pub fn retile(&mut self){
self.draw_widgets();
self.draw_widgets(Ctx::Retile);

/* configurable grouping logic */
let mut tiled_windows: Vec<xlib::Window> = Vec::new();
Expand Down
5 changes: 3 additions & 2 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use x11::xlib::{self, EnterWindowMask, False, PointerMotionMask, StructureNotify

//use crate::init::widget_window;
use crate::state::MOUSEMOTIONS;
use crate::widgets::Ctx;
use crate::{active_workspace_wins, state::{State, KEYBINDINGS}, };


Expand Down Expand Up @@ -48,8 +49,8 @@ fn map_request(state: &mut State, ev: xlib::XMapRequestEvent) {
unsafe {XSync(state.dpy, False)};
}

fn expose(_: &mut State, __: xlib::XExposeEvent) {
println!("EXPOSE !!!");
fn expose(state: &mut State, __: xlib::XExposeEvent) {
state.draw_widgets(Ctx::Expose);
}

fn configure_request(_: &mut State, __: xlib::XConfigureRequestEvent) { }
Expand Down
2 changes: 1 addition & 1 deletion src/state.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::sync::{Arc, Mutex};
use std::sync::Arc;

use x11::{xft::XftDraw, xlib::{self, Window}};

Expand Down
2 changes: 1 addition & 1 deletion src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ macro_rules! add_widget {
$state,
"",
Box::new($widget {})
);
)
)
)
}
Expand Down
64 changes: 43 additions & 21 deletions src/widgets.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::ffi::CString;
use std::fmt::format;
use std::mem;
use std::ptr;
use chrono::Local;

use sysinfo::System;

Expand All @@ -10,20 +10,25 @@ use x11::xlib::{self, XSetWindowAttributes};
use x11::{xft, xrender};
use std::sync::Mutex;
use lazy_static::lazy_static;
use chrono::Local;

use crate::state;
use crate::config::STYLE;

#[derive(PartialEq, Clone, Copy)]
pub enum Ctx {
Retile,
Expose
}


pub struct Widget {
pub font: *mut xft::XftFont,
pub wspec: Box<dyn WidgetSpec>
}

impl Widget {
pub fn draw(&self, state: &mut state::State){
self.wspec.draw(state, self);
pub fn draw(&self, state: &mut state::State, context:Ctx){
self.wspec.draw(state, self, context);
}

pub fn new(state: &mut state::State, font: &str, wspec: Box<dyn WidgetSpec>) -> Widget {
Expand All @@ -35,22 +40,24 @@ impl Widget {
}

pub trait WidgetSpec {
fn draw(&self, state: &mut state::State, widget: &Widget);
fn draw(&self, state: &mut state::State, widget: &Widget, context: Ctx);
}

pub struct TopBar {}
pub struct TaskList {}
pub struct Stats {}

impl WidgetSpec for TopBar {
fn draw(&self, state: &mut state::State, widget: &Widget) {
fn draw(&self, state: &mut state::State, widget: &Widget, context: Ctx) {
unsafe {
let screen_width: u32 = xlib::XDisplayWidth(state.dpy, state.screen) as u32;
let box_wh = STYLE.paddings.top;
let pad: i32 = text_width_px(state, widget.font, state.workspaces[0].tag) / 4;

xft::XftDrawRect(state.xft_draw, &state.colors.normal.bg, 0, 0, screen_width, STYLE.paddings.top);

let pad: i32 = text_width_px(state, widget.font, state.workspaces[0].tag) / 2;

if context == Ctx::Expose {
xft::XftDrawRect(state.xft_draw, &state.colors.normal.bg, 0, 0, screen_width, STYLE.paddings.top);
}

for i in 0..state.workspaces.len() {
let offset = i as u32 * box_wh;
let mut bgcol = &state.colors.normal.bg;
Expand All @@ -68,27 +75,42 @@ impl WidgetSpec for TopBar {
}

impl WidgetSpec for TaskList {
fn draw(&self, _: &mut state::State, __: &Widget) {}
fn draw(&self, _: &mut state::State, __: &Widget, ___: Ctx) {}
}

lazy_static! {
static ref SYS: Mutex<System> = Mutex::new(System::new_all());
}

impl WidgetSpec for Stats {
fn draw(&self, state: &mut state::State, widget: &Widget) {
fn draw(&self, state: &mut state::State, widget: &Widget, context: Ctx) {
if context != Ctx::Expose { return }
let mut sys = SYS.lock().unwrap();
let screen_width = unsafe { xlib::XDisplayWidth(state.dpy, state.screen) as i32 };
sys.refresh_all();

let cpu: String = format!("{:02} % CPU", sys.global_cpu_usage() as u32);
let w_cpu = text_width_px(state, widget.font, cpu.as_str());

unsafe {
let screen_width: u32 = xlib::XDisplayWidth(state.dpy, state.screen) as u32;
let utf8_string = CString::new(cpu).unwrap();
let x =screen_width as i32 - w_cpu;
xft::XftDrawRect(state.xft_draw, &state.colors.normal.fg, x, 0, w_cpu as u32, STYLE.paddings.top);
xft::XftDrawStringUtf8(state.xft_draw, &state.colors.normal.bg, widget.font, x, STYLE.paddings.top as i32, utf8_string.as_ptr() as *const u8, utf8_string.to_bytes().len() as i32);
let mem_usg = (sys.used_memory() as f32 / sys.total_memory() as f32) * 100f32;

let stats = [
format!("{:02} % CPU", sys.global_cpu_usage() as u32),
format!("{}", Local::now()),
format!("{:02} % ({} / {} MiB)", mem_usg as u32, sys.used_memory() / 1024 / 1024, sys.total_memory() / 1024 / 1024)
];

let mut offset = 0;
let brk = text_width_px(state, widget.font, "A");
let pad = brk / 2;

for stat in stats.iter() {
let w = text_width_px(state, widget.font, stat.as_str());
offset += w;
offset += brk;

unsafe {
let utf8_string: CString = CString::new((*stat).clone()).unwrap();
xft::XftDrawRect(state.xft_draw, &state.colors.normal.fg, screen_width - offset - brk, 0, (brk + w + brk) as u32, STYLE.paddings.top);
xft::XftDrawStringUtf8(state.xft_draw, &state.colors.normal.bg, widget.font, screen_width - offset, STYLE.paddings.top as i32 - pad, utf8_string.as_ptr() as *const u8, utf8_string.to_bytes().len() as i32);
}
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/wm.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use x11::xlib::{self, XGrabServer};
use std::mem;

use crate::{config::{CustomData, STYLE}, state::{self, WIDGETS}};
use crate::{config::{CustomData, STYLE}, state::{self, WIDGETS}, widgets::Ctx};

pub struct Space<'a> {
pub tag: &'a str,
Expand Down Expand Up @@ -199,9 +199,9 @@ impl state::State<'_> {
}
}

pub fn draw_widgets(&mut self){
pub fn draw_widgets(&mut self, context: Ctx){
for widget in unsafe { WIDGETS.iter() } {
widget.draw(self);
widget.draw(self, context.clone());
}

}
Expand Down
5 changes: 3 additions & 2 deletions src/xroagwem.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@

use config::WIDGET_REFRESH;
use widgets::widget_refresh;
use x11::xlib::{self, XNextEvent};
use std::{env, mem, process::exit, ptr, thread, time::Duration};
use std::{env, mem, process::exit, ptr, thread};

mod init;
mod error;
Expand Down Expand Up @@ -35,7 +36,7 @@ pub fn main() {
thread::spawn(|| {
loop {
widget_refresh();
thread::sleep(Duration::from_secs(1));
thread::sleep(WIDGET_REFRESH);
}
});
loop_poll_events(&mut state);
Expand Down

0 comments on commit 2c06370

Please sign in to comment.