mirror of
https://github.com/Zedfrigg/ironbar.git
synced 2025-07-01 10:41:03 +02:00
feat: ability to set bar layer and exclusive zone
This commit is contained in:
parent
c28de8d902
commit
aa45396062
7 changed files with 145 additions and 36 deletions
|
@ -295,23 +295,25 @@ The following table lists each of the top-level bar config options:
|
||||||
|
|
||||||
The following table lists each of the bar-level bar config options:
|
The following table lists each of the bar-level bar config options:
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
|-------------------|----------------------------------------|--------------------------------------|----------------------------------------------------------------------------------------------------------------------------|
|
|-------------------|------------------------------------------------|------------------------------------------|----------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `name` | `string` | `bar-<n>` | A unique identifier for the bar, used for controlling it over IPC. If not set, uses a generated integer suffix. |
|
| `name` | `string` | `bar-<n>` | A unique identifier for the bar, used for controlling it over IPC. If not set, uses a generated integer suffix. |
|
||||||
| `position` | `top` or `bottom` or `left` or `right` | `bottom` | The bar's position on screen. |
|
| `position` | `top` or `bottom` or `left` or `right` | `bottom` | The bar's position on screen. |
|
||||||
| `anchor_to_edges` | `boolean` | `false` | Whether to anchor the bar to the edges of the screen. Setting to false centres the bar. |
|
| `anchor_to_edges` | `boolean` | `false` | Whether to anchor the bar to the edges of the screen. Setting to false centres the bar. |
|
||||||
| `height` | `integer` | `42` | The bar's height in pixels. |
|
| `height` | `integer` | `42` | The bar's height in pixels. |
|
||||||
| `popup_gap` | `integer` | `5` | The gap between the bar and popup window. |
|
| `margin.top` | `integer` | `0` | The margin on the top of the bar |
|
||||||
| `margin.top` | `integer` | `0` | The margin on the top of the bar |
|
| `margin.bottom` | `integer` | `0` | The margin on the bottom of the bar |
|
||||||
| `margin.bottom` | `integer` | `0` | The margin on the bottom of the bar |
|
| `margin.left` | `integer` | `0` | The margin on the left of the bar |
|
||||||
| `margin.left` | `integer` | `0` | The margin on the left of the bar |
|
| `margin.right` | `integer` | `0` | The margin on the right of the bar |
|
||||||
| `margin.right` | `integer` | `0` | The margin on the right of the bar |
|
| `layer` | `background` or `bottom` or `top` or `overlay` | `top` | The layer-shell layer to place the bar on. |
|
||||||
| `icon_theme` | `string` | `null` | Name of the GTK icon theme to use. Leave blank to use default. |
|
| `exclusive_zone` | `boolean` | `true` unless `start_hidden` is enabled. | Whether the bar should reserve an exclusive zone around it. |
|
||||||
| `start_hidden` | `boolean` | `false`, or `true` if `autohide` set | Whether the bar should be hidden when the application starts. Enabled by default when `autohide` is set. |
|
| `popup_gap` | `integer` | `5` | The gap between the bar and popup window. |
|
||||||
| `autohide` | `integer` | `null` | The duration in milliseconds before the bar is hidden after the cursor leaves. Leave unset to disable auto-hide behaviour. |
|
| `icon_theme` | `string` | `null` | Name of the GTK icon theme to use. Leave blank to use default. |
|
||||||
| `start` | `Module[]` | `[]` | Array of left or top modules. |
|
| `start_hidden` | `boolean` | `false`, or `true` if `autohide` set | Whether the bar should be hidden when the application starts. Enabled by default when `autohide` is set. |
|
||||||
| `center` | `Module[]` | `[]` | Array of center modules. |
|
| `autohide` | `integer` | `null` | The duration in milliseconds before the bar is hidden after the cursor leaves. Leave unset to disable auto-hide behaviour. |
|
||||||
| `end` | `Module[]` | `[]` | Array of right or bottom modules. |
|
| `start` | `Module[]` | `[]` | Array of left or top modules. |
|
||||||
|
| `center` | `Module[]` | `[]` | Array of center modules. |
|
||||||
|
| `end` | `Module[]` | `[]` | Array of right or bottom modules. |
|
||||||
|
|
||||||
### 3.2 Module-level options
|
### 3.2 Module-level options
|
||||||
|
|
||||||
|
|
|
@ -289,6 +289,18 @@ Gets the popup's current visibility state.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `set_exclusive`
|
||||||
|
|
||||||
|
Sets whether the bar reserves an exclusive zone.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "bar",
|
||||||
|
"subcommand": "set_exclusive",
|
||||||
|
"exclusive": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Responses
|
## Responses
|
||||||
|
|
||||||
### `ok`
|
### `ok`
|
||||||
|
|
48
src/bar.rs
48
src/bar.rs
|
@ -120,27 +120,28 @@ impl Bar {
|
||||||
self.name, self.monitor_name
|
self.name, self.monitor_name
|
||||||
);
|
);
|
||||||
|
|
||||||
self.setup_layer_shell(
|
|
||||||
&self.window,
|
|
||||||
true,
|
|
||||||
config.anchor_to_edges,
|
|
||||||
config.margin,
|
|
||||||
monitor,
|
|
||||||
);
|
|
||||||
|
|
||||||
let start_hidden = config
|
let start_hidden = config
|
||||||
.start_hidden
|
.start_hidden
|
||||||
.unwrap_or_else(|| config.autohide.is_some());
|
.unwrap_or_else(|| config.autohide.is_some());
|
||||||
|
|
||||||
|
self.setup_layer_shell(
|
||||||
|
&self.window,
|
||||||
|
config.exclusive_zone.unwrap_or(!start_hidden),
|
||||||
|
config.anchor_to_edges,
|
||||||
|
config.margin,
|
||||||
|
config.layer,
|
||||||
|
monitor,
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(autohide) = config.autohide {
|
if let Some(autohide) = config.autohide {
|
||||||
let hotspot_window = Window::new(WindowType::Toplevel);
|
let hotspot_window = Window::new(WindowType::Toplevel);
|
||||||
|
|
||||||
Self::setup_autohide(&self.window, &hotspot_window, autohide);
|
Self::setup_autohide(&self.window, &hotspot_window, autohide);
|
||||||
self.setup_layer_shell(
|
self.setup_layer_shell(
|
||||||
&hotspot_window,
|
&hotspot_window,
|
||||||
false,
|
false,
|
||||||
config.anchor_to_edges,
|
config.anchor_to_edges,
|
||||||
config.margin,
|
config.margin,
|
||||||
|
gtk_layer_shell::Layer::Top,
|
||||||
monitor,
|
monitor,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -166,43 +167,46 @@ impl Bar {
|
||||||
exclusive_zone: bool,
|
exclusive_zone: bool,
|
||||||
anchor_to_edges: bool,
|
anchor_to_edges: bool,
|
||||||
margin: MarginConfig,
|
margin: MarginConfig,
|
||||||
|
layer: gtk_layer_shell::Layer,
|
||||||
monitor: &Monitor,
|
monitor: &Monitor,
|
||||||
) {
|
) {
|
||||||
|
use gtk_layer_shell::Edge;
|
||||||
|
|
||||||
let position = self.position;
|
let position = self.position;
|
||||||
|
|
||||||
win.init_layer_shell();
|
win.init_layer_shell();
|
||||||
win.set_monitor(monitor);
|
win.set_monitor(monitor);
|
||||||
win.set_layer(gtk_layer_shell::Layer::Top);
|
win.set_layer(layer);
|
||||||
win.set_namespace(env!("CARGO_PKG_NAME"));
|
win.set_namespace(env!("CARGO_PKG_NAME"));
|
||||||
|
|
||||||
if exclusive_zone {
|
if exclusive_zone {
|
||||||
win.auto_exclusive_zone_enable();
|
win.auto_exclusive_zone_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
win.set_layer_shell_margin(gtk_layer_shell::Edge::Top, margin.top);
|
win.set_layer_shell_margin(Edge::Top, margin.top);
|
||||||
win.set_layer_shell_margin(gtk_layer_shell::Edge::Bottom, margin.bottom);
|
win.set_layer_shell_margin(Edge::Bottom, margin.bottom);
|
||||||
win.set_layer_shell_margin(gtk_layer_shell::Edge::Left, margin.left);
|
win.set_layer_shell_margin(Edge::Left, margin.left);
|
||||||
win.set_layer_shell_margin(gtk_layer_shell::Edge::Right, margin.right);
|
win.set_layer_shell_margin(Edge::Right, margin.right);
|
||||||
|
|
||||||
let bar_orientation = position.orientation();
|
let bar_orientation = position.orientation();
|
||||||
|
|
||||||
win.set_anchor(
|
win.set_anchor(
|
||||||
gtk_layer_shell::Edge::Top,
|
Edge::Top,
|
||||||
position == BarPosition::Top
|
position == BarPosition::Top
|
||||||
|| (bar_orientation == Orientation::Vertical && anchor_to_edges),
|
|| (bar_orientation == Orientation::Vertical && anchor_to_edges),
|
||||||
);
|
);
|
||||||
win.set_anchor(
|
win.set_anchor(
|
||||||
gtk_layer_shell::Edge::Bottom,
|
Edge::Bottom,
|
||||||
position == BarPosition::Bottom
|
position == BarPosition::Bottom
|
||||||
|| (bar_orientation == Orientation::Vertical && anchor_to_edges),
|
|| (bar_orientation == Orientation::Vertical && anchor_to_edges),
|
||||||
);
|
);
|
||||||
win.set_anchor(
|
win.set_anchor(
|
||||||
gtk_layer_shell::Edge::Left,
|
Edge::Left,
|
||||||
position == BarPosition::Left
|
position == BarPosition::Left
|
||||||
|| (bar_orientation == Orientation::Horizontal && anchor_to_edges),
|
|| (bar_orientation == Orientation::Horizontal && anchor_to_edges),
|
||||||
);
|
);
|
||||||
win.set_anchor(
|
win.set_anchor(
|
||||||
gtk_layer_shell::Edge::Right,
|
Edge::Right,
|
||||||
position == BarPosition::Right
|
position == BarPosition::Right
|
||||||
|| (bar_orientation == Orientation::Horizontal && anchor_to_edges),
|
|| (bar_orientation == Orientation::Horizontal && anchor_to_edges),
|
||||||
);
|
);
|
||||||
|
@ -329,6 +333,14 @@ impl Bar {
|
||||||
pub fn set_visible(&self, visible: bool) {
|
pub fn set_visible(&self, visible: bool) {
|
||||||
self.window.set_visible(visible)
|
self.window.set_visible(visible)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_exclusive(&self, exclusive: bool) {
|
||||||
|
if exclusive {
|
||||||
|
self.window.auto_exclusive_zone_enable();
|
||||||
|
} else {
|
||||||
|
self.window.set_exclusive_zone(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `gtk::Box` container to place widgets inside.
|
/// Creates a `gtk::Box` container to place widgets inside.
|
||||||
|
|
|
@ -35,6 +35,37 @@ impl<'de> Deserialize<'de> for MonitorConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_layer<'de, D>(deserializer: D) -> Result<gtk_layer_shell::Layer, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
use gtk_layer_shell::Layer;
|
||||||
|
|
||||||
|
let value = Option::<String>::deserialize(deserializer)?;
|
||||||
|
value
|
||||||
|
.map(|v| match v.as_str() {
|
||||||
|
"background" => Ok(Layer::Background),
|
||||||
|
"bottom" => Ok(Layer::Bottom),
|
||||||
|
"top" => Ok(Layer::Top),
|
||||||
|
"overlay" => Ok(Layer::Overlay),
|
||||||
|
_ => Err(serde::de::Error::custom("invalid value for orientation")),
|
||||||
|
})
|
||||||
|
.unwrap_or(Ok(Layer::Top))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "schema")]
|
||||||
|
pub fn schema_layer(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
let mut schema: schemars::schema::SchemaObject = <String>::json_schema(gen).into();
|
||||||
|
schema.enum_values = Some(vec![
|
||||||
|
"background".into(),
|
||||||
|
"bottom".into(),
|
||||||
|
"top".into(),
|
||||||
|
"overlay".into(),
|
||||||
|
]);
|
||||||
|
schema.into()
|
||||||
|
}
|
||||||
|
|
||||||
impl BarPosition {
|
impl BarPosition {
|
||||||
/// Gets the orientation the bar and widgets should use
|
/// Gets the orientation the bar and widgets should use
|
||||||
/// based on this position.
|
/// based on this position.
|
||||||
|
|
|
@ -216,6 +216,36 @@ pub struct BarConfig {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub margin: MarginConfig,
|
pub margin: MarginConfig,
|
||||||
|
|
||||||
|
/// The layer-shell layer to place the bar on.
|
||||||
|
///
|
||||||
|
/// Taken from the
|
||||||
|
/// [wlr_layer_shell](https://wayland.app/protocols/wlr-layer-shell-unstable-v1#zwlr_layer_shell_v1:enum:layer) definition:
|
||||||
|
///
|
||||||
|
/// > These values indicate which layers a surface can be rendered in.
|
||||||
|
/// > They are ordered by z depth, bottom-most first.
|
||||||
|
/// > Traditional shell surfaces will typically be rendered between the bottom and top layers.
|
||||||
|
/// > Fullscreen shell surfaces are typically rendered at the top layer.
|
||||||
|
/// > Multiple surfaces can share a single layer, and ordering within a single layer is undefined.
|
||||||
|
///
|
||||||
|
/// **Valid options**: `background`, `bottom`, `top`, `overlay`
|
||||||
|
/// <br>
|
||||||
|
/// **Default**: `top`
|
||||||
|
#[serde(
|
||||||
|
default = "default_layer",
|
||||||
|
deserialize_with = "r#impl::deserialize_layer"
|
||||||
|
)]
|
||||||
|
#[cfg_attr(feature = "schema", schemars(schema_with = "r#impl::schema_layer"))]
|
||||||
|
pub layer: gtk_layer_shell::Layer,
|
||||||
|
|
||||||
|
/// Whether the bar should reserve an exclusive zone around it.
|
||||||
|
///
|
||||||
|
/// When true, this prevents windows from rendering in the same space
|
||||||
|
/// as the bar, causing them to shift.
|
||||||
|
///
|
||||||
|
/// **Default**: `true` unless `start_hidden` is set.
|
||||||
|
#[serde(default)]
|
||||||
|
pub exclusive_zone: Option<bool>,
|
||||||
|
|
||||||
/// The size of the gap in pixels
|
/// The size of the gap in pixels
|
||||||
/// between the bar and the popup window.
|
/// between the bar and the popup window.
|
||||||
///
|
///
|
||||||
|
@ -282,9 +312,11 @@ impl Default for BarConfig {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
position: BarPosition::default(),
|
position: BarPosition::default(),
|
||||||
height: default_bar_height(),
|
|
||||||
margin: MarginConfig::default(),
|
margin: MarginConfig::default(),
|
||||||
name: None,
|
name: None,
|
||||||
|
layer: default_layer(),
|
||||||
|
exclusive_zone: None,
|
||||||
|
height: default_bar_height(),
|
||||||
start_hidden: None,
|
start_hidden: None,
|
||||||
autohide: None,
|
autohide: None,
|
||||||
icon_theme: None,
|
icon_theme: None,
|
||||||
|
@ -340,6 +372,10 @@ pub struct Config {
|
||||||
pub monitors: Option<HashMap<String, MonitorConfig>>,
|
pub monitors: Option<HashMap<String, MonitorConfig>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fn default_layer() -> gtk_layer_shell::Layer {
|
||||||
|
gtk_layer_shell::Layer::Top
|
||||||
|
}
|
||||||
|
|
||||||
const fn default_bar_height() -> i32 {
|
const fn default_bar_height() -> i32 {
|
||||||
42
|
42
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,4 +118,15 @@ pub enum BarCommandType {
|
||||||
},
|
},
|
||||||
/// Get the popup's current visibility state.
|
/// Get the popup's current visibility state.
|
||||||
GetPopupVisible,
|
GetPopupVisible,
|
||||||
|
|
||||||
|
// == Exclusivity == \\
|
||||||
|
/// Set whether the bar reserves an exclusive zone.
|
||||||
|
SetExclusive {
|
||||||
|
#[clap(
|
||||||
|
num_args(1),
|
||||||
|
require_equals(true),
|
||||||
|
action = ArgAction::Set,
|
||||||
|
)]
|
||||||
|
exclusive: bool,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,11 @@ pub fn handle_command(command: BarCommand, ironbar: &Rc<Ironbar>) -> Response {
|
||||||
GetPopupVisible => Response::OkValue {
|
GetPopupVisible => Response::OkValue {
|
||||||
value: bar.popup().visible().to_string(),
|
value: bar.popup().visible().to_string(),
|
||||||
},
|
},
|
||||||
|
SetExclusive { exclusive } => {
|
||||||
|
bar.set_exclusive(exclusive);
|
||||||
|
|
||||||
|
Response::Ok
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue