eww/src/display_backend.rs
snakedye 9ea20cd753
Proper wayland support (#125)
* Initial commit for wayland support

* Improvements to Wayland backend, structs and enums

* gtk-layer-shell-rs imported

* Eww compiles with wayland backend

* Full layershell support

* Compatibility with x11 backend

* updated docs and better compatibily with X config

* error in example

* "screen" in config works

* Updated documentation

* bar example for wayland

* eww follow focus when screen is undefined

* NumWithUnit

* Removed SurfaceDefinition for StrutDefinition
again...

* cargo fmt

* fix match statement for screen number

* fix focusable / kb interactivity

* revision #2

* fix: compile error and example

* feat: I fixed the deps
X11 doesn't compile because of some x11 fuckery

* fix: x11 fuckery
PR NOW REEEEEEEEEEEEEEEEEEEEEEEEE

* fix conflics and cargo fmt

* i can't read

* conflicts: a never ending loop...

* dammit ptr

* conflicts: Cargo.lock

* Expression language (#124)

* Add AST

* add make-shift testing parser, and make stuff ocmpile

* add proper expression parser

* make string format use '

* Add empty doc page for expressions

* add tests

* Clean up file structure and add unary operators

* Write documentation

* make multiple daemons possible and make commands time out

* Add EwwPaths struct and refactor path handling in general

* Update docs to include <reserve>

* Improve handling of paths and daemon-ids

* Add elvis operator

* Allow literal-tag content to use user-defined widgets

* Add support for overriding monitor in CLI

* change formatting config

* Improve error messages for non-existant config dir

* Added tooltips (#127)

* update dependencies

* Explicetely states where to look for installing eww (#131)

I think this should be added, because we already had a couple of people opening issues because they didn't read the docs on how to install eww.

* (Very) Rudimentry gif support (#143)

* rudimentry gif support

* revert main.rs

* Fix variable reference detection, should fix #144

* cleanup TextPos in eww debug

* Manually resolve escaped symbols in xml.

This shouldn't be necesary.
Fixes #154 and fixes #147

* Add JSON support for exprs (fixes #146)

* Add docs for json values and make value related names shorter

* Add animated icon

* Initial commit for wayland support

* Improvements to Wayland backend, structs and enums

* gtk-layer-shell-rs imported

* Eww compiles with wayland backend

* Full layershell support

* Compatibility with x11 backend

* updated docs and better compatibily with X config

* "screen" in config works

* Updated documentation

* eww follow focus when screen is undefined

* Removed SurfaceDefinition for StrutDefinition
again...

* cargo fmt

* fix match statement for screen number

* fix focusable / kb interactivity

* revision #2

* fix: compile error and example

* feat: I fixed the deps
X11 doesn't compile because of some x11 fuckery

* fix conflics and cargo fmt

* i can't read

* conflicts: a never ending loop...

* dammit ptr

* conflicts: Cargo.lock

* yeeting git syntax

* trying to resolve conflicts

* yeeting Cargo.lock...

* i try

* revision: removing duplicates

* fix geometry, example and improving docs

* clearing up the documentation

* I forgot the scss file.
I also edited the bar to take advantage of eww expressions.

* more yeeting and moved exclusive to window

Co-authored-by: Bryan Ndjeutcha <ndjeutcha@gmail.com>
Co-authored-by: ElKowar <5300871+elkowar@users.noreply.github.com>
Co-authored-by: undefinedDarkness <38278035+undefinedDarkness@users.noreply.github.com>
Co-authored-by: legendofmiracles <30902201+legendofmiracles@users.noreply.github.com>
2021-05-03 21:14:34 +02:00

230 lines
9.8 KiB
Rust

pub use platform::*;
#[cfg(feature = "no-x11-wayland")]
mod platform {
use crate::config::{Side, StrutDefinition};
use anyhow::*;
pub fn reserve_space_for(window: &gtk::Window, monitor: gdk::Rectangle, strut_def: StrutDefinition) -> Result<()> {
Err(anyhow!("Cannot reserve space on non X11 or and wayland backends"))
}
}
#[cfg(feature = "wayland")]
mod platform {
use gdk;
use crate::{
config::{EwwWindowDefinition, AnchorAlignment, Side, WindowStacking},
};
use anyhow::*;
use gtk::prelude::*;
pub fn initialize_window(window_def: &mut EwwWindowDefinition, monitor: gdk::Rectangle) -> gtk::Window {
let window = gtk::Window::new(gtk::WindowType::Toplevel);
// Initialising a layer shell surface
gtk_layer_shell::init_for_window(&window);
// Sets the monitor where the surface is shown
match window_def.screen_number {
Some(index) => {
if let Some(monitor) = gdk::Display::get_default()
.expect("could not get default display")
.get_monitor(index) {
gtk_layer_shell::set_monitor(&window, &monitor);
};
}
None => {}
};
window.set_resizable(true);
// Sets the layer where the layer shell surface will spawn
match window_def.stacking {
WindowStacking::Foreground => gtk_layer_shell::set_layer(&window, gtk_layer_shell::Layer::Top),
WindowStacking::Background => gtk_layer_shell::set_layer(&window, gtk_layer_shell::Layer::Background),
WindowStacking::Bottom => gtk_layer_shell::set_layer(&window, gtk_layer_shell::Layer::Bottom),
WindowStacking::Overlay => gtk_layer_shell::set_layer(&window, gtk_layer_shell::Layer::Overlay),
}
// Sets the keyboard interactivity
gtk_layer_shell::set_keyboard_interactivity(&window, window_def.focusable);
// Positioning surface
let mut top = false;
let mut left = false;
let mut right = false;
let mut bottom = false;
match window_def.geometry.anchor_point.x {
AnchorAlignment::START => left = true,
AnchorAlignment::CENTER => {}
AnchorAlignment::END => right = true,
}
match window_def.geometry.anchor_point.y {
AnchorAlignment::START => top = true,
AnchorAlignment::CENTER => {}
AnchorAlignment::END => bottom = true,
}
gtk_layer_shell::set_anchor(&window, gtk_layer_shell::Edge::Left, left);
gtk_layer_shell::set_anchor(&window, gtk_layer_shell::Edge::Right, right);
gtk_layer_shell::set_anchor(&window, gtk_layer_shell::Edge::Top, top);
gtk_layer_shell::set_anchor(&window, gtk_layer_shell::Edge::Bottom, bottom);
let xoffset = window_def.geometry.offset.x.relative_to(monitor.width);
let yoffset = window_def.geometry.offset.y.relative_to(monitor.height);
if left {
gtk_layer_shell::set_margin(&window, gtk_layer_shell::Edge::Left, xoffset);
} else {
gtk_layer_shell::set_margin(&window, gtk_layer_shell::Edge::Right, xoffset);
}
if bottom {
gtk_layer_shell::set_margin(&window, gtk_layer_shell::Edge::Bottom, yoffset);
} else {
gtk_layer_shell::set_margin(&window, gtk_layer_shell::Edge::Top, yoffset);
}
if window_def.exclusive {
gtk_layer_shell::auto_exclusive_zone_enable(&window);
}
window
}
}
#[cfg(feature = "x11")]
mod platform {
use crate::config::{EwwWindowDefinition, Side, StrutDefinition, WindowStacking};
use anyhow::*;
use gdkx11;
use gtk::{self, prelude::*};
use x11rb::protocol::xproto::ConnectionExt;
use x11rb::{
self,
connection::Connection,
protocol::xproto::*,
rust_connection::{DefaultStream, RustConnection},
};
pub fn initialize_window(window_def: &mut EwwWindowDefinition, _monitor: gdk::Rectangle) -> gtk::Window {
let window = if window_def.focusable {
gtk::Window::new(gtk::WindowType::Toplevel)
} else {
gtk::Window::new(gtk::WindowType::Popup)
};
window.set_resizable(true);
if !window_def.focusable {
window.set_type_hint(gdk::WindowTypeHint::Dock);
}
if window_def.stacking == WindowStacking::Foreground {
window.set_keep_above(true);
} else {
window.set_keep_below(true);
}
window
}
pub fn reserve_space_for(window: &gtk::Window, monitor: gdk::Rectangle, strut_def: StrutDefinition) -> Result<()> {
let backend = X11Backend::new()?;
backend.reserve_space_for(window, monitor, strut_def)?;
Ok(())
}
struct X11Backend {
conn: RustConnection<DefaultStream>,
root_window: u32,
atoms: AtomCollection,
}
impl X11Backend {
fn new() -> Result<Self> {
let (conn, screen_num) = RustConnection::connect(None)?;
let screen = conn.setup().roots[screen_num].clone();
let atoms = AtomCollection::new(&conn)?.reply()?;
Ok(X11Backend { conn, root_window: screen.root, atoms })
}
fn reserve_space_for(
&self,
window: &gtk::Window,
monitor_rect: gdk::Rectangle,
strut_def: StrutDefinition,
) -> Result<()> {
let win_id = window
.get_window()
.context("Couldn't get gdk window from gtk window")?
.downcast::<gdkx11::X11Window>()
.ok()
.context("Failed to get x11 window for gtk window")?
.get_xid() as u32;
let root_window_geometry = self.conn.get_geometry(self.root_window)?.reply()?;
let mon_end_x = (monitor_rect.x + monitor_rect.width) as u32 - 1u32;
let mon_end_y = (monitor_rect.y + monitor_rect.height) as u32 - 1u32;
let dist = match strut_def.side {
Side::Left | Side::Right => strut_def.dist.relative_to(monitor_rect.width) as u32,
Side::Top | Side::Bottom => strut_def.dist.relative_to(monitor_rect.height) as u32,
_ => (monitor_rect.height / 2) as u32,
};
// don't question it,.....
// it's how the X gods want it to be.
// left, right, top, bottom, left_start_y, left_end_y, right_start_y, right_end_y, top_start_x, top_end_x, bottom_start_x, bottom_end_x
#[rustfmt::skip]
let strut_list: Vec<u8> = match strut_def.side {
Side::Left => vec![dist + monitor_rect.x as u32, 0, 0, 0, monitor_rect.y as u32, mon_end_y, 0, 0, 0, 0, 0, 0],
Side::Right => vec![0, root_window_geometry.width as u32 - mon_end_x + dist, 0, 0, 0, 0, monitor_rect.y as u32, mon_end_y, 0, 0, 0, 0],
Side::Top => vec![0, 0, dist + monitor_rect.y as u32, 0, 0, 0, 0, 0, monitor_rect.x as u32, mon_end_x, 0, 0],
Side::Bottom => vec![0, 0, 0, root_window_geometry.height as u32 - mon_end_y + dist, 0, 0, 0, 0, 0, 0, monitor_rect.x as u32, mon_end_x],
// This should never happen but if it does the window will be anchored on the
// right of the screen
_ => vec![0, root_window_geometry.width as u32 - mon_end_x + dist, 0, 0, 0, 0, monitor_rect.y as u32, mon_end_y, 0, 0, 0, 0],
}.iter().flat_map(|x| x.to_le_bytes().to_vec()).collect();
self.conn
.change_property(
PropMode::REPLACE,
win_id,
self.atoms._NET_WM_STRUT,
self.atoms.CARDINAL,
32,
4,
&strut_list[0..16],
)?
.check()?;
self.conn
.change_property(
PropMode::REPLACE,
win_id,
self.atoms._NET_WM_STRUT_PARTIAL,
self.atoms.CARDINAL,
32,
12,
&strut_list,
)?
.check()?;
self.conn.flush()?;
Ok(())
}
}
x11rb::atom_manager! {
pub AtomCollection: AtomCollectionCookie {
_NET_WM_WINDOW_TYPE,
_NET_WM_WINDOW_TYPE_DOCK,
_NET_WM_WINDOW_TYPE_DIALOG,
_NET_WM_STATE,
_NET_WM_STATE_STICKY,
_NET_WM_STATE_ABOVE,
_NET_WM_STATE_BELOW,
_NET_WM_NAME,
_NET_WM_STRUT,
_NET_WM_STRUT_PARTIAL,
WM_NAME,
UTF8_STRING,
COMPOUND_TEXT,
CARDINAL,
ATOM,
WM_CLASS,
STRING,
}
}
}