Skip to content

Commit

Permalink
Merge pull request #46 from JakeStanger/feat/mouse-events
Browse files Browse the repository at this point in the history
feat: mouse event config options
  • Loading branch information
JakeStanger authored Dec 15, 2022
2 parents b2afe78 + fa67d07 commit 8076412
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 107 deletions.
24 changes: 15 additions & 9 deletions docs/Configuration guide.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
By default, you get a single bar at the bottom of all your screens.
To change that, you'll unsurprisingly need a config file.

This page details putting together the skeleton for your config to get you to a stage where you can start configuring modules.
It may look long and overwhelming, but that is just because the bar supports a lot of scenarios!
This page details putting together the skeleton for your config to get you to a stage where you can start configuring
modules.
It may look long and overwhelming, but that is just because the bar supports a lot of scenarios!

If you want to see some ready-to-go config files check the [examples folder](https://github.com/JakeStanger/ironbar/tree/master/examples)
If you want to see some ready-to-go config files check
the [examples folder](https://github.com/JakeStanger/ironbar/tree/master/examples)
and the example pages in the sidebar.

## 1. Create config file
Expand Down Expand Up @@ -239,7 +241,7 @@ monitors:
<details>
<summary>Corn</summary>
```
```corn
{
monitors.DP-1 = [
{ start = [] }
Expand Down Expand Up @@ -281,8 +283,12 @@ For details on available modules and each of their config options, check the sid

For information on the `Script` type, and embedding scripts in strings, see [here](script).

| Name | Type | Default | Description |
|------------|--------------------|---------|--------------------------------------------------------------------------------------------------------------------|
| `show_if` | `Script [polling]` | `null` | Polls the script to check its exit code. If exit code is zero, the module is shown. For other codes, it is hidden. |
| `on_click` | `Script [polling]` | `null` | Runs the script when the module is clicked. |
| `tooltip` | `string` | `null` | Shows this text on hover. Supports embedding scripts between `{{double braces}}`. |
| Name | Type | Default | Description |
|-------------------|--------------------|---------|--------------------------------------------------------------------------------------------------------------------|
| `show_if` | `Script [polling]` | `null` | Polls the script to check its exit code. If exit code is zero, the module is shown. For other codes, it is hidden. |
| `on_click_left` | `Script [oneshot]` | `null` | Runs the script when the module is left clicked. |
| `on_click_middle` | `Script [oneshot]` | `null` | Runs the script when the module is middle clicked. |
| `on_click_right` | `Script [oneshot]` | `null` | Runs the script when the module is right clicked. |
| `on_scroll_up` | `Script [oneshot]` | `null` | Runs the script when the module is scroll up on. |
| `on_scroll_down` | `Script [oneshot]` | `null` | Runs the script when the module is scrolled down on. |
| `tooltip` | `string` | `null` | Shows this text on hover. Supports embedding scripts between `{{double braces}}`. |
11 changes: 8 additions & 3 deletions docs/Scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ that allow script input to dynamically set values.

Scripts are passed to `sh -c`.

Two types of scripts exist: polling and watching:
Three types of scripts exist: polling, oneshot and watching:

- Polling scripts will run and wait for exit.
- **Polling** scripts will run and wait for exit.
Normally they will repeat this at an interval, hence the name, although in some cases they may only run on a user
event.
If the script exited code 0, the `stdout` will be used. Otherwise, `stderr` will be printed to the log.
- Watching scripts start a long-running process. Every time the process writes to `stdout`, the last line is captured
- **Oneshot** scripts are a variant of polling scripts.
They wait for script to exit, and may do something with the output, but are only fired by user events instead of the interval.
Generally options that accept oneshot scripts do not support the other types.
- **Watching** scripts start a long-running process. Every time the process writes to `stdout`, the last line is captured
and used.

One should prefer to use watch-mode where possible, as it removes the overhead of regularly spawning processes.
Expand All @@ -28,6 +31,8 @@ spawning the script.
Both `mode` and `interval` are optional and can be excluded to fall back to their defaults of `poll` and `5000`
respectively.

For oneshot scripts, both the mode and interval are ignored.

### Shorthand (string)

Shorthand scripts should be written in the format:
Expand Down
54 changes: 46 additions & 8 deletions src/bar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::popup::Popup;
use crate::script::{OutputStream, Script};
use crate::{await_sync, read_lock, send, write_lock, Config};
use color_eyre::Result;
use gtk::gdk::Monitor;
use gtk::gdk::{EventMask, Monitor, ScrollDirection};
use gtk::prelude::*;
use gtk::{Application, ApplicationWindow, EventBox, Orientation, Widget};
use std::sync::{Arc, RwLock};
Expand Down Expand Up @@ -313,6 +313,7 @@ fn setup_receiver<TSend>(
/// The event box container is returned.
fn wrap_widget<W: IsA<Widget>>(widget: &W) -> EventBox {
let container = EventBox::new();
container.add_events(EventMask::SCROLL_MASK);
container.add(widget);
container
}
Expand Down Expand Up @@ -345,18 +346,55 @@ fn setup_module_common_options(container: EventBox, common: CommonConfig) {
},
);

if let Some(on_click) = common.on_click {
let script = Script::new_polling(on_click);
container.connect_button_press_event(move |_, _| {
trace!("Running on-click script");
let left_click_script = common.on_click_left.map(Script::new_polling);
let middle_click_script = common.on_click_middle.map(Script::new_polling);
let right_click_script = common.on_click_right.map(Script::new_polling);

container.connect_button_press_event(move |_, event| {
let script = match event.button() {
1 => left_click_script.as_ref(),
2 => middle_click_script.as_ref(),
3 => right_click_script.as_ref(),
_ => None,
};

if let Some(script) = script {
trace!("Running on-click script: {}", event.button());

match await_sync(async { script.get_output().await }) {
Ok((OutputStream::Stderr(out), _)) => error!("{out}"),
Err(err) => error!("{err:?}"),
_ => {}
}
Inhibit(false)
});
}
}

Inhibit(false)
});

let scroll_up_script = common.on_scroll_up.map(Script::new_polling);
let scroll_down_script = common.on_scroll_down.map(Script::new_polling);

container.connect_scroll_event(move |_, event| {
println!("{:?}", event.direction());

let script = match event.direction() {
ScrollDirection::Up => scroll_up_script.as_ref(),
ScrollDirection::Down => scroll_down_script.as_ref(),
_ => None,
};

if let Some(script) = script {
trace!("Running on-scroll script: {}", event.direction());

match await_sync(async { script.get_output().await }) {
Ok((OutputStream::Stderr(out), _)) => error!("{out}"),
Err(err) => error!("{err:?}"),
_ => {}
}
}

Inhibit(false)
});

if let Some(tooltip) = common.tooltip {
DynamicString::new(&tooltip, move |string| {
Expand Down
91 changes: 4 additions & 87 deletions src/config.rs → src/config/impl.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,14 @@
use crate::modules::clock::ClockModule;
use crate::modules::custom::CustomModule;
use crate::modules::focused::FocusedModule;
use crate::modules::launcher::LauncherModule;
use crate::modules::mpd::MpdModule;
use crate::modules::script::ScriptModule;
use crate::modules::sysinfo::SysInfoModule;
use crate::modules::tray::TrayModule;
use crate::modules::workspaces::WorkspacesModule;
use crate::script::ScriptInput;
use color_eyre::eyre::{Context, ContextCompat};
use color_eyre::{eyre, Help, Report};
use super::{BarPosition, Config, MonitorConfig};
use color_eyre::eyre::Result;
use color_eyre::eyre::{ContextCompat, WrapErr};
use color_eyre::{Help, Report};
use dirs::config_dir;
use eyre::Result;
use gtk::Orientation;
use serde::{Deserialize, Deserializer};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::{env, fs};
use tracing::instrument;

#[derive(Debug, Deserialize, Clone)]
pub struct CommonConfig {
pub show_if: Option<ScriptInput>,
pub on_click: Option<ScriptInput>,
pub tooltip: Option<String>,
}

#[derive(Debug, Deserialize, Clone)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ModuleConfig {
Clock(ClockModule),
Mpd(MpdModule),
Tray(TrayModule),
Workspaces(WorkspacesModule),
SysInfo(SysInfoModule),
Launcher(LauncherModule),
Script(ScriptModule),
Focused(FocusedModule),
Custom(CustomModule),
}

#[derive(Debug, Clone)]
pub enum MonitorConfig {
Single(Config),
Multiple(Vec<Config>),
}

// Manually implement for better untagged enum error handling:
// currently open pr: https://github.com/serde-rs/serde/pull/1544
impl<'de> Deserialize<'de> for MonitorConfig {
Expand Down Expand Up @@ -78,21 +41,6 @@ impl<'de> Deserialize<'de> for MonitorConfig {
}
}

#[derive(Debug, Deserialize, Copy, Clone, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum BarPosition {
Top,
Bottom,
Left,
Right,
}

impl Default for BarPosition {
fn default() -> Self {
Self::Bottom
}
}

impl BarPosition {
/// Gets the orientation the bar and widgets should use
/// based on this position.
Expand All @@ -115,30 +63,6 @@ impl BarPosition {
}
}

#[derive(Debug, Deserialize, Clone)]
pub struct Config {
#[serde(default = "default_bar_position")]
pub position: BarPosition,
#[serde(default = "default_true")]
pub anchor_to_edges: bool,
#[serde(default = "default_bar_height")]
pub height: i32,

pub start: Option<Vec<ModuleConfig>>,
pub center: Option<Vec<ModuleConfig>>,
pub end: Option<Vec<ModuleConfig>>,

pub monitors: Option<HashMap<String, MonitorConfig>>,
}

const fn default_bar_position() -> BarPosition {
BarPosition::Bottom
}

const fn default_bar_height() -> i32 {
42
}

impl Config {
/// Attempts to load the config file from file,
/// parse it and return a new instance of `Self`.
Expand Down Expand Up @@ -214,10 +138,3 @@ impl Config {
}
}
}

pub const fn default_false() -> bool {
false
}
pub const fn default_true() -> bool {
true
}
94 changes: 94 additions & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
mod r#impl;

use crate::modules::clock::ClockModule;
use crate::modules::custom::CustomModule;
use crate::modules::focused::FocusedModule;
use crate::modules::launcher::LauncherModule;
use crate::modules::mpd::MpdModule;
use crate::modules::script::ScriptModule;
use crate::modules::sysinfo::SysInfoModule;
use crate::modules::tray::TrayModule;
use crate::modules::workspaces::WorkspacesModule;
use crate::script::ScriptInput;
use serde::Deserialize;
use std::collections::HashMap;

#[derive(Debug, Deserialize, Clone)]
pub struct CommonConfig {
pub show_if: Option<ScriptInput>,

pub on_click_left: Option<ScriptInput>,
pub on_click_right: Option<ScriptInput>,
pub on_click_middle: Option<ScriptInput>,
pub on_scroll_up: Option<ScriptInput>,
pub on_scroll_down: Option<ScriptInput>,

pub tooltip: Option<String>,
}

#[derive(Debug, Deserialize, Clone)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ModuleConfig {
Clock(ClockModule),
Mpd(MpdModule),
Tray(TrayModule),
Workspaces(WorkspacesModule),
SysInfo(SysInfoModule),
Launcher(LauncherModule),
Script(ScriptModule),
Focused(FocusedModule),
Custom(CustomModule),
}

#[derive(Debug, Clone)]
pub enum MonitorConfig {
Single(Config),
Multiple(Vec<Config>),
}

#[derive(Debug, Deserialize, Copy, Clone, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum BarPosition {
Top,
Bottom,
Left,
Right,
}

impl Default for BarPosition {
fn default() -> Self {
Self::Bottom
}
}

#[derive(Debug, Deserialize, Clone)]
pub struct Config {
#[serde(default = "default_bar_position")]
pub position: BarPosition,
#[serde(default = "default_true")]
pub anchor_to_edges: bool,
#[serde(default = "default_bar_height")]
pub height: i32,

pub start: Option<Vec<ModuleConfig>>,
pub center: Option<Vec<ModuleConfig>>,
pub end: Option<Vec<ModuleConfig>>,

pub monitors: Option<HashMap<String, MonitorConfig>>,
}

const fn default_bar_position() -> BarPosition {
BarPosition::Bottom
}

const fn default_bar_height() -> i32 {
42
}

pub const fn default_false() -> bool {
false
}

pub const fn default_true() -> bool {
true
}

0 comments on commit 8076412

Please sign in to comment.