Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Lanpingner authored Jan 17, 2024
2 parents b84d38a + 65d622c commit f940cbe
Show file tree
Hide file tree
Showing 19 changed files with 908 additions and 233 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ All notable changes to eww will be listed here, starting at changes since versio

## [Unreleased]

### BREAKING CHANGES
- Remove `eww windows` command, replace with `eww active-windows` and `eww list-windows`

### Features
- Add `:namespace` window option
- Default to building with x11 and wayland support simultaneously
Expand All @@ -21,6 +24,8 @@ All notable changes to eww will be listed here, starting at changes since versio
- Add trigonometric functions (`sin`, `cos`, `tan`, `cot`) and degree/radian conversions (`degtorad`, `radtodeg`) (By: end-4)
- Add `substring` function to simplexpr
- Add `--duration` flag to `eww open`
- Add support for referring to monitor with `<primary>`
- Add support for multiple matchers in `monitor` field

## [0.4.0] (04.09.2022)

Expand Down Expand Up @@ -72,6 +77,7 @@ All notable changes to eww will be listed here, starting at changes since versio
- Add `:onaccept` to input field, add `:onclick` to eventbox
- Add `EWW_CMD`, `EWW_CONFIG_DIR`, `EWW_EXECUTABLE` magic variables
- Add `overlay` widget (By: viandoxdev)
- Add arguments option to `defwindow` (By: WilfSilver)

### Notable Internal changes
- Rework state management completely, now making local state and dynamic widget hierarchy changes possible.
Expand Down
235 changes: 135 additions & 100 deletions crates/eww/src/app.rs

Large diffs are not rendered by default.

80 changes: 40 additions & 40 deletions crates/eww/src/display_backend.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use yuck::config::window_definition::WindowDefinition;
use crate::window_initiator::WindowInitiator;

#[cfg(feature = "wayland")]
pub use platform_wayland::WaylandBackend;
Expand All @@ -8,26 +8,25 @@ pub use platform_x11::{set_xprops, X11Backend};

pub trait DisplayBackend: Send + Sync + 'static {
const IS_X11: bool;
fn initialize_window(window_def: &WindowDefinition, monitor: gdk::Rectangle) -> Option<gtk::Window>;

fn initialize_window(window_init: &WindowInitiator, monitor: gdk::Rectangle) -> Option<gtk::Window>;
}

pub struct NoBackend;

impl DisplayBackend for NoBackend {
const IS_X11: bool = false;

fn initialize_window(_window_def: &WindowDefinition, _monitor: gdk::Rectangle) -> Option<gtk::Window> {
fn initialize_window(_window_init: &WindowInitiator, _monitor: gdk::Rectangle) -> Option<gtk::Window> {
Some(gtk::Window::new(gtk::WindowType::Toplevel))
}
}

#[cfg(feature = "wayland")]
mod platform_wayland {
use crate::window_initiator::WindowInitiator;
use gtk::prelude::*;
use yuck::config::{
window_definition::{WindowDefinition, WindowStacking},
window_geometry::AnchorAlignment,
};
use yuck::config::{window_definition::WindowStacking, window_geometry::AnchorAlignment};

use super::DisplayBackend;

Expand All @@ -36,37 +35,37 @@ mod platform_wayland {
impl DisplayBackend for WaylandBackend {
const IS_X11: bool = false;

fn initialize_window(window_def: &WindowDefinition, monitor: gdk::Rectangle) -> Option<gtk::Window> {
fn initialize_window(window_init: &WindowInitiator, monitor: gdk::Rectangle) -> Option<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
if let Some(ident) = window_def.monitor.clone() {
if let Some(ident) = window_init.monitor.clone() {
let display = gdk::Display::default().expect("could not get default display");
if let Some(monitor) = crate::app::get_monitor_from_display(&display, &ident) {
gtk_layer_shell::set_monitor(&window, &monitor);
} else {
return None;
}
};
window.set_resizable(window_def.resizable);
window.set_resizable(window_init.resizable);

// Sets the layer where the layer shell surface will spawn
match window_def.stacking {
match window_init.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),
}

if let Some(namespace) = &window_def.backend_options.wayland.namespace {
if let Some(namespace) = &window_init.backend_options.wayland.namespace {
gtk_layer_shell::set_namespace(&window, namespace);
}

// Sets the keyboard interactivity
gtk_layer_shell::set_keyboard_interactivity(&window, window_def.backend_options.wayland.focusable);
gtk_layer_shell::set_keyboard_interactivity(&window, window_init.backend_options.wayland.focusable);

if let Some(geometry) = window_def.geometry {
if let Some(geometry) = window_init.geometry {
// Positioning surface
let mut top = false;
let mut left = false;
Expand Down Expand Up @@ -103,7 +102,7 @@ mod platform_wayland {
gtk_layer_shell::set_margin(&window, gtk_layer_shell::Edge::Top, yoffset);
}
}
if window_def.backend_options.wayland.exclusive {
if window_init.backend_options.wayland.exclusive {
gtk_layer_shell::auto_exclusive_zone_enable(&window);
}
Some(window)
Expand All @@ -113,7 +112,9 @@ mod platform_wayland {

#[cfg(feature = "x11")]
mod platform_x11 {
use crate::window_initiator::WindowInitiator;
use anyhow::{Context, Result};
use gdk::Monitor;
use gtk::{self, prelude::*};
use x11rb::protocol::xproto::ConnectionExt;

Expand All @@ -125,7 +126,7 @@ mod platform_x11 {
};
use yuck::config::{
backend_window_options::{Side, X11WindowType},
window_definition::{WindowDefinition, WindowStacking},
window_definition::WindowStacking,
};

use super::DisplayBackend;
Expand All @@ -134,14 +135,14 @@ mod platform_x11 {
impl DisplayBackend for X11Backend {
const IS_X11: bool = true;

fn initialize_window(window_def: &WindowDefinition, _monitor: gdk::Rectangle) -> Option<gtk::Window> {
fn initialize_window(window_init: &WindowInitiator, _monitor: gdk::Rectangle) -> Option<gtk::Window> {
let window_type =
if window_def.backend_options.x11.wm_ignore { gtk::WindowType::Popup } else { gtk::WindowType::Toplevel };
if window_init.backend_options.x11.wm_ignore { gtk::WindowType::Popup } else { gtk::WindowType::Toplevel };
let window = gtk::Window::new(window_type);
window.set_resizable(window_def.resizable);
window.set_keep_above(window_def.stacking == WindowStacking::Foreground);
window.set_keep_below(window_def.stacking == WindowStacking::Background);
if window_def.backend_options.x11.sticky {
window.set_resizable(window_init.resizable);
window.set_keep_above(window_init.stacking == WindowStacking::Foreground);
window.set_keep_below(window_init.stacking == WindowStacking::Background);
if window_init.backend_options.x11.sticky {
window.stick();
} else {
window.unstick();
Expand All @@ -150,9 +151,9 @@ mod platform_x11 {
}
}

pub fn set_xprops(window: &gtk::Window, monitor: gdk::Rectangle, window_def: &WindowDefinition) -> Result<()> {
pub fn set_xprops(window: &gtk::Window, monitor: Monitor, window_init: &WindowInitiator) -> Result<()> {
let backend = X11BackendConnection::new()?;
backend.set_xprops_for(window, monitor, window_def)?;
backend.set_xprops_for(window, monitor, window_init)?;
Ok(())
}

Expand All @@ -170,35 +171,34 @@ mod platform_x11 {
Ok(X11BackendConnection { conn, root_window: screen.root, atoms })
}

fn set_xprops_for(
&self,
window: &gtk::Window,
monitor_rect: gdk::Rectangle,
window_def: &WindowDefinition,
) -> Result<()> {
fn set_xprops_for(&self, window: &gtk::Window, monitor: Monitor, window_init: &WindowInitiator) -> Result<()> {
let monitor_rect = monitor.geometry();
let scale_factor = monitor.scale_factor() as u32;
let gdk_window = window.window().context("Couldn't get gdk window from gtk window")?;
let win_id =
gdk_window.downcast_ref::<gdkx11::X11Window>().context("Failed to get x11 window for gtk window")?.xid() as u32;
let strut_def = window_def.backend_options.x11.struts;
let strut_def = window_init.backend_options.x11.struts;
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 mon_x = scale_factor * monitor_rect.x() as u32;
let mon_y = scale_factor * monitor_rect.y() as u32;
let mon_end_x = scale_factor * (monitor_rect.x() + monitor_rect.width()) as u32 - 1u32;
let mon_end_y = scale_factor * (monitor_rect.y() + monitor_rect.height()) as u32 - 1u32;

let dist = match strut_def.side {
Side::Left | Side::Right => strut_def.dist.pixels_relative_to(monitor_rect.width()) as u32,
Side::Top | Side::Bottom => strut_def.dist.pixels_relative_to(monitor_rect.height()) as u32,
Side::Left | Side::Right => strut_def.distance.pixels_relative_to(monitor_rect.width()) as u32,
Side::Top | Side::Bottom => strut_def.distance.pixels_relative_to(monitor_rect.height()) 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],
Side::Left => vec![dist + mon_x, 0, 0, 0, mon_x, 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, mon_x, mon_end_y, 0, 0, 0, 0],
Side::Top => vec![0, 0, dist + mon_y as u32, 0, 0, 0, 0, 0, mon_x, 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, mon_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
}.iter().flat_map(|x| x.to_le_bytes().to_vec()).collect();
Expand Down Expand Up @@ -233,7 +233,7 @@ mod platform_x11 {
win_id,
self.atoms._NET_WM_WINDOW_TYPE,
self.atoms.ATOM,
&[match window_def.backend_options.x11.window_type {
&[match window_init.backend_options.x11.window_type {
X11WindowType::Dock => self.atoms._NET_WM_WINDOW_TYPE_DOCK,
X11WindowType::Normal => self.atoms._NET_WM_WINDOW_TYPE_NORMAL,
X11WindowType::Dialog => self.atoms._NET_WM_WINDOW_TYPE_DIALOG,
Expand Down
3 changes: 3 additions & 0 deletions crates/eww/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#![feature(slice_concat_trait)]
#![feature(try_blocks)]
#![feature(hash_extract_if)]
#![feature(let_chains)]
#![allow(rustdoc::private_intra_doc_links)]

extern crate gtk;
Expand Down Expand Up @@ -36,6 +37,8 @@ mod server;
mod state;
mod util;
mod widgets;
mod window_arguments;
mod window_initiator;

fn main() {
let eww_binary_name = std::env::args().next().unwrap();
Expand Down
56 changes: 48 additions & 8 deletions crates/eww/src/opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ pub enum ActionWithServer {
/// Name of the window you want to open.
window_name: String,

// The id of the window instance
#[arg(long)]
id: Option<String>,

/// The identifier of the monitor the window should open on
#[arg(long)]
screen: Option<MonitorIdentifier>,
Expand All @@ -124,13 +128,23 @@ pub enum ActionWithServer {
/// Automatically close the window after a specified amount of time, i.e.: 1s
#[arg(long, value_parser=parse_duration)]
duration: Option<std::time::Duration>,

/// Define a variable for the window, i.e.: `--arg "var_name=value"`
#[arg(long = "arg", value_parser = parse_var_update_arg)]
args: Option<Vec<(VarName, DynVal)>>,
},

/// Open multiple windows at once.
/// NOTE: This will in the future be part of eww open, and will then be removed.
#[command(name = "open-many")]
OpenMany {
windows: Vec<String>,
/// List the windows to open, optionally including their id, i.e.: `--window "window_name:window_id"`
#[arg(value_parser = parse_window_config_and_id)]
windows: Vec<(String, String)>,

/// Define a variable for the window, i.e.: `--arg "window_id:var_name=value"`
#[arg(long = "arg", value_parser = parse_window_id_args)]
args: Vec<(String, VarName, DynVal)>,

/// If a window is already open, close it instead
#[arg(long = "toggle")]
Expand Down Expand Up @@ -165,9 +179,13 @@ pub enum ActionWithServer {
#[command(name = "get")]
GetVar { name: String },

/// Print the names of all configured windows. Windows with a * in front of them are currently opened.
#[command(name = "windows")]
ShowWindows,
/// List the names of active windows
#[command(name = "list-windows")]
ListWindows,

/// Show active window IDs, formatted linewise `<window_id>: <window_name>`
#[command(name = "active-windows")]
ListActiveWindows,

/// Print out the widget structure as seen by eww.
///
Expand Down Expand Up @@ -195,6 +213,25 @@ impl From<RawOpt> for Opt {
}
}

/// Parse a window-name:window-id pair of the form `name:id` or `name` into a tuple of `(name, id)`.
fn parse_window_config_and_id(s: &str) -> Result<(String, String)> {
let (name, id) = s.split_once(':').unwrap_or((s, s));

Ok((name.to_string(), id.to_string()))
}

/// Parse a window-id specific variable value declaration with the syntax `window-id:variable_name="new_value"`
/// into a tuple of `(id, variable_name, new_value)`.
fn parse_window_id_args(s: &str) -> Result<(String, VarName, DynVal)> {
// Parse the = first so we know if an id has not been given
let (name, value) = parse_var_update_arg(s)?;

let (id, var_name) = name.0.split_once(':').unwrap_or(("", &name.0));

Ok((id.to_string(), var_name.into(), value))
}

/// Split the input string at `=`, parsing the value into a [`DynVal`].
fn parse_var_update_arg(s: &str) -> Result<(VarName, DynVal)> {
let (name, value) = s
.split_once('=')
Expand All @@ -219,26 +256,29 @@ impl ActionWithServer {
let _ = send.send(DaemonResponse::Success("pong".to_owned()));
return (app::DaemonCommand::NoOp, Some(recv));
}
ActionWithServer::OpenMany { windows, should_toggle } => {
return with_response_channel(|sender| app::DaemonCommand::OpenMany { windows, should_toggle, sender });
ActionWithServer::OpenMany { windows, args, should_toggle } => {
return with_response_channel(|sender| app::DaemonCommand::OpenMany { windows, args, should_toggle, sender });
}
ActionWithServer::OpenWindow { window_name, pos, size, screen, anchor, should_toggle, duration } => {
ActionWithServer::OpenWindow { window_name, id, pos, size, screen, anchor, should_toggle, duration, args } => {
return with_response_channel(|sender| app::DaemonCommand::OpenWindow {
window_name,
instance_id: id,
pos,
size,
anchor,
screen,
should_toggle,
duration,
sender,
args,
})
}
ActionWithServer::CloseWindows { windows } => {
return with_response_channel(|sender| app::DaemonCommand::CloseWindows { windows, sender });
}
ActionWithServer::Reload => return with_response_channel(app::DaemonCommand::ReloadConfigAndCss),
ActionWithServer::ShowWindows => return with_response_channel(app::DaemonCommand::PrintWindows),
ActionWithServer::ListWindows => return with_response_channel(app::DaemonCommand::ListWindows),
ActionWithServer::ListActiveWindows => return with_response_channel(app::DaemonCommand::ListActiveWindows),
ActionWithServer::ShowState { all } => {
return with_response_channel(|sender| app::DaemonCommand::PrintState { all, sender })
}
Expand Down
1 change: 1 addition & 0 deletions crates/eww/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ pub fn initialize_server<B: DisplayBackend>(
eww_config,
open_windows: HashMap::new(),
failed_windows: HashSet::new(),
instance_id_to_args: HashMap::new(),
css_provider: gtk::CssProvider::new(),
script_var_handler,
app_evt_send: ui_send.clone(),
Expand Down
Loading

0 comments on commit f940cbe

Please sign in to comment.