Skip to content

Commit

Permalink
Add id option for opening new windows
Browse files Browse the repository at this point in the history
  • Loading branch information
WilfSilver committed Apr 19, 2022
1 parent 285f519 commit a99a070
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 32 deletions.
109 changes: 78 additions & 31 deletions crates/eww/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub enum DaemonCommand {
},
OpenWindow {
window_name: String,
instance_id: Option<String>,
pos: Option<Coords>,
size: Option<Coords>,
anchor: Option<AnchorPoint>,
Expand All @@ -67,9 +68,30 @@ pub enum DaemonCommand {
PrintWindows(DaemonResponseSender),
}

#[derive(Debug, Clone)]
pub struct WindowInitiator {
pub config_name: String,
pub pos: Option<Coords>,
pub size: Option<Coords>,
pub monitor: Option<i32>,
pub anchor: Option<AnchorPoint>,
}

impl WindowInitiator {
pub fn new(
config_name: String,
pos: Option<Coords>,
size: Option<Coords>,
monitor: Option<i32>,
anchor: Option<AnchorPoint>,
) -> Self {
WindowInitiator { config_name, pos, size, monitor, anchor }
}
}

#[derive(Debug, Clone)]
pub struct EwwWindow {
pub name: String,
pub instance_id: String,
pub definition: yuck::config::window_definition::WindowDefinition,
pub scope_index: ScopeIndex,
pub gtk_window: gtk::Window,
Expand All @@ -85,6 +107,7 @@ pub struct App {
pub scope_graph: Rc<RefCell<ScopeGraph>>,
pub eww_config: config::EwwConfig,
pub open_windows: HashMap<String, EwwWindow>,
pub window_initiators: HashMap<String, WindowInitiator>,
/// Window names that are supposed to be open, but failed.
/// When reloading the config, these should be opened again.
pub failed_windows: HashSet<String>,
Expand All @@ -103,6 +126,7 @@ impl std::fmt::Debug for App {
.field("eww_config", &self.eww_config)
.field("open_windows", &self.open_windows)
.field("failed_windows", &self.failed_windows)
.field("window_initiators", &self.window_initiators)
.field("paths", &self.paths)
.finish()
}
Expand Down Expand Up @@ -168,23 +192,37 @@ impl App {
if should_toggle && self.open_windows.contains_key(w) {
self.close_window(w)
} else {
self.open_window(w, None, None, None, None)
self.open_window(w, &WindowInitiator::new(w.clone(), None, None, None, None))
}
})
.filter_map(Result::err);
sender.respond_with_error_list(errors)?;
}
DaemonCommand::OpenWindow { window_name, pos, size, anchor, screen: monitor, should_toggle, sender } => {
DaemonCommand::OpenWindow {
window_name,
instance_id,
pos,
size,
anchor,
screen: monitor,
should_toggle,
sender,
} => {
let is_open = self.open_windows.contains_key(&window_name);
let id = match instance_id {
Some(x) => x,
None => window_name.clone(),
};

let result = if is_open {
if should_toggle {
self.close_window(&window_name)
self.close_window(&id)
} else {
// user should use `eww reload` to reload windows (https://github.com/elkowar/eww/issues/260)
Ok(())
}
} else {
self.open_window(&window_name, pos, size, monitor, anchor)
self.open_window(&id, &WindowInitiator::new(window_name, pos, size, monitor, anchor))
};
sender.respond_with_result(result)?;
}
Expand Down Expand Up @@ -279,11 +317,11 @@ impl App {
// Due to poll vars not being able to be per window, these do not need to be updated
}

fn close_window(&mut self, window_name: &str) -> Result<()> {
fn close_window(&mut self, instance_id: &str) -> Result<()> {
let eww_window = self
.open_windows
.remove(window_name)
.with_context(|| format!("Tried to close window named '{}', but no such window was open", window_name))?;
.remove(instance_id)
.with_context(|| format!("Tried to close window named '{}', but no such window was open", instance_id))?;

self.scope_graph.borrow_mut().remove_scope(eww_window.scope_index);

Expand All @@ -295,28 +333,26 @@ impl App {
self.script_var_handler.stop_for_variable(unused_var.clone());
}

self.window_initiators.remove(instance_id);

Ok(())
}

fn open_window(
&mut self,
window_call: &str,
pos: Option<Coords>,
size: Option<Coords>,
monitor: Option<i32>,
anchor: Option<AnchorPoint>,
) -> Result<()> {
self.failed_windows.remove(window_call);
log::info!("Opening window {}", window_call);
fn open_window(&mut self, instance_id: &str, initiator: &WindowInitiator) -> Result<()> {
self.failed_windows.remove(instance_id);
log::info!("Opening window {} as '{}'", initiator.config_name, instance_id);

// if an instance of this is already running, close it
let _ = self.close_window(window_call);
let _ = self.close_window(instance_id);

self.window_initiators.insert(instance_id.to_string(), initiator.clone());

let open_result: Result<_> = try {
let (window_name, params) = extract_window_info(window_call);
let (window_name, params) = extract_window_info(&initiator.config_name);

let mut window_def = self.eww_config.get_window(window_name)?.clone();
window_def.geometry = window_def.geometry.map(|x| x.override_if_given(anchor, pos, size));
window_def.geometry =
window_def.geometry.map(|x| x.override_if_given(initiator.anchor, initiator.pos, initiator.size));

if params.len() != window_def.expected_args.len() {
// Throw error
Expand All @@ -339,7 +375,7 @@ impl App {
)?;

let global_window_scope = self.scope_graph.borrow_mut().register_new_scope(
window_call.to_string() + "_global",
instance_id.to_string() + "_global",
Some(root_index),
root_index,
self.eww_config
Expand All @@ -360,10 +396,11 @@ impl App {

root_widget.style_context().add_class(&window_name.to_string());

let monitor_number = monitor.or(window_def.get_monitor_number(&local_variables)?);
let monitor_number = initiator.monitor.or(window_def.get_monitor_number(&local_variables)?);
let monitor_geometry = get_monitor_geometry(monitor_number)?;

let eww_window = initialize_window(monitor_number, monitor_geometry, root_widget, window_def, window_scope)?;
let eww_window =
initialize_window(instance_id, monitor_number, monitor_geometry, root_widget, window_def, window_scope)?;

// initialize script var handlers for variables that where not used before opening this window.
// TODO maybe this could be handled by having a track_newly_used_variables function in the scope tree?
Expand All @@ -379,12 +416,12 @@ impl App {
let _ = scope_graph_sender.send(ScopeGraphEvent::RemoveScope(eww_window.scope_index));
}
});
self.open_windows.insert(window_call.to_string(), eww_window);
self.open_windows.insert(instance_id.to_string(), eww_window);
};

if let Err(err) = open_result {
self.failed_windows.insert(window_call.to_string());
Err(err).with_context(|| format!("failed to open window `{}`", window_call))
self.failed_windows.insert(instance_id.to_string());
Err(err).with_context(|| format!("failed to open window `{}`", instance_id))
} else {
Ok(())
}
Expand All @@ -402,10 +439,19 @@ impl App {
self.eww_config = config;
self.scope_graph.borrow_mut().clear(self.eww_config.generate_initial_state()?);

let window_names: Vec<String> =
let instances: Vec<String> =
self.open_windows.keys().cloned().chain(self.failed_windows.iter().cloned()).dedup().collect();
for window_name in &window_names {
self.open_window(window_name, None, None, None, None)?;
let initiators = self.window_initiators.clone();
for instance_id in &instances {
let window_initiator;
match initiators.get(instance_id) {
Some(x) => window_initiator = x,
None => {
return Err(anyhow!("Cannot reopen window, initial parameters were not saved correctly for {}", instance_id))
}
};

self.open_window(instance_id, window_initiator)?;
}
Ok(())
}
Expand All @@ -417,6 +463,7 @@ impl App {
}

fn initialize_window(
instance_id: &str,
monitor_number: Option<i32>,
monitor_geometry: gdk::Rectangle,
root_widget: gtk::Widget,
Expand Down Expand Up @@ -463,7 +510,7 @@ fn initialize_window(

window.show_all();

Ok(EwwWindow { name: window_def.name.clone(), definition: window_def, gtk_window: window, scope_index: window_scope })
Ok(EwwWindow { instance_id: instance_id.to_string(), definition: window_def, gtk_window: window, scope_index: window_scope })
}

/// Apply the provided window-positioning rules to the window.
Expand Down
6 changes: 5 additions & 1 deletion crates/eww/src/opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ pub enum ActionWithServer {
/// Name of the window you want to open.
window_name: String,

#[structopt(long)]
id: Option<String>,

/// Monitor-index the window should open on
#[structopt(long)]
screen: Option<i32>,
Expand Down Expand Up @@ -211,9 +214,10 @@ impl ActionWithServer {
ActionWithServer::OpenMany { windows, should_toggle } => {
return with_response_channel(|sender| app::DaemonCommand::OpenMany { windows, should_toggle, sender });
}
ActionWithServer::OpenWindow { window_name, pos, size, screen, anchor, should_toggle } => {
ActionWithServer::OpenWindow { window_name, id, pos, size, screen, anchor, should_toggle } => {
return with_response_channel(|sender| app::DaemonCommand::OpenWindow {
window_name,
instance_id: id,
pos,
size,
anchor,
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 @@ -73,6 +73,7 @@ pub fn initialize_server(paths: EwwPaths, action: Option<DaemonCommand>, should_
eww_config,
open_windows: HashMap::new(),
failed_windows: HashSet::new(),
window_initiators: HashMap::new(),
css_provider: gtk::CssProvider::new(),
script_var_handler,
app_evt_send: ui_send.clone(),
Expand Down

0 comments on commit a99a070

Please sign in to comment.