mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-03-20 16:43:57 +01:00
feat(wm): allow setting wallpaper per monitor
This commit adds the option to set `Wallpaper` per monitor. When changing workspaces it will first check for a workspace wallpaper, if there is none it then checks for a monitor wallpaper.
This commit is contained in:
@@ -21,6 +21,7 @@ use crate::workspace::WorkspaceLayer;
|
||||
use crate::DefaultLayout;
|
||||
use crate::Layout;
|
||||
use crate::OperationDirection;
|
||||
use crate::Wallpaper;
|
||||
use crate::WindowsApi;
|
||||
use crate::DEFAULT_CONTAINER_PADDING;
|
||||
use crate::DEFAULT_WORKSPACE_PADDING;
|
||||
@@ -60,6 +61,8 @@ pub struct Monitor {
|
||||
pub container_padding: Option<i32>,
|
||||
#[getset(get_copy = "pub", set = "pub")]
|
||||
pub workspace_padding: Option<i32>,
|
||||
#[getset(get = "pub", get_mut = "pub", set = "pub")]
|
||||
pub wallpaper: Option<Wallpaper>,
|
||||
}
|
||||
|
||||
impl_ring_elements!(Monitor, Workspace);
|
||||
@@ -115,6 +118,7 @@ pub fn new(
|
||||
workspace_names: HashMap::default(),
|
||||
container_padding: None,
|
||||
workspace_padding: None,
|
||||
wallpaper: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +160,7 @@ impl Monitor {
|
||||
workspace_names: Default::default(),
|
||||
container_padding: None,
|
||||
workspace_padding: None,
|
||||
wallpaper: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,9 +183,10 @@ impl Monitor {
|
||||
pub fn load_focused_workspace(&mut self, mouse_follows_focus: bool) -> Result<()> {
|
||||
let focused_idx = self.focused_workspace_idx();
|
||||
let hmonitor = self.id();
|
||||
let monitor_wp = self.wallpaper.clone();
|
||||
for (i, workspace) in self.workspaces_mut().iter_mut().enumerate() {
|
||||
if i == focused_idx {
|
||||
workspace.restore(mouse_follows_focus, hmonitor)?;
|
||||
workspace.restore(mouse_follows_focus, hmonitor, &monitor_wp)?;
|
||||
} else {
|
||||
workspace.hide(None);
|
||||
}
|
||||
|
||||
@@ -553,6 +553,7 @@ where
|
||||
workspace_names: cached.workspace_names.clone(),
|
||||
container_padding: cached.container_padding,
|
||||
workspace_padding: cached.workspace_padding,
|
||||
wallpaper: cached.wallpaper.clone(),
|
||||
};
|
||||
|
||||
let focused_workspace_idx = m.focused_workspace_idx();
|
||||
|
||||
@@ -326,6 +326,9 @@ pub struct MonitorConfig {
|
||||
/// Workspace padding (default: global)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub workspace_padding: Option<i32>,
|
||||
/// Specify a wallpaper for this monitor
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub wallpaper: Option<Wallpaper>,
|
||||
}
|
||||
|
||||
impl From<&Monitor> for MonitorConfig {
|
||||
@@ -361,6 +364,7 @@ impl From<&Monitor> for MonitorConfig {
|
||||
window_based_work_area_offset_limit: Some(value.window_based_work_area_offset_limit()),
|
||||
container_padding,
|
||||
workspace_padding,
|
||||
wallpaper: value.wallpaper().clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1357,6 +1361,7 @@ impl StaticConfig {
|
||||
);
|
||||
monitor.set_container_padding(monitor_config.container_padding);
|
||||
monitor.set_workspace_padding(monitor_config.workspace_padding);
|
||||
monitor.set_wallpaper(monitor_config.wallpaper.clone());
|
||||
|
||||
monitor.update_workspaces_globals(offset);
|
||||
for (j, ws) in monitor.workspaces_mut().iter_mut().enumerate() {
|
||||
|
||||
@@ -359,6 +359,7 @@ impl From<&WindowManager> for State {
|
||||
workspace_names: monitor.workspace_names.clone(),
|
||||
container_padding: monitor.container_padding,
|
||||
workspace_padding: monitor.workspace_padding,
|
||||
wallpaper: monitor.wallpaper.clone(),
|
||||
})
|
||||
.collect::<VecDeque<_>>();
|
||||
stripped_monitors.focus(wm.monitors.focused_idx());
|
||||
@@ -1015,6 +1016,7 @@ impl WindowManager {
|
||||
monitor.update_workspace_globals(focused_workspace_idx, offset);
|
||||
|
||||
let hmonitor = monitor.id();
|
||||
let monitor_wp = monitor.wallpaper.clone();
|
||||
let workspace = monitor
|
||||
.focused_workspace_mut()
|
||||
.ok_or_else(|| anyhow!("there is no workspace"))?;
|
||||
@@ -1026,8 +1028,8 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
if workspace.wallpaper().is_some() {
|
||||
if let Err(error) = workspace.apply_wallpaper(hmonitor) {
|
||||
if workspace.wallpaper().is_some() || monitor_wp.is_some() {
|
||||
if let Err(error) = workspace.apply_wallpaper(hmonitor, &monitor_wp) {
|
||||
tracing::error!("failed to apply wallpaper: {}", error);
|
||||
}
|
||||
}
|
||||
@@ -1729,13 +1731,14 @@ impl WindowManager {
|
||||
.ok_or_else(|| anyhow!("there is no monitor"))?;
|
||||
|
||||
let hmonitor = monitor.id();
|
||||
let monitor_wp = monitor.wallpaper.clone();
|
||||
|
||||
let workspace = monitor
|
||||
.workspaces()
|
||||
.get(workspace_idx)
|
||||
.ok_or_else(|| anyhow!("there is no workspace"))?;
|
||||
|
||||
workspace.apply_wallpaper(hmonitor)
|
||||
workspace.apply_wallpaper(hmonitor, &monitor_wp)
|
||||
}
|
||||
|
||||
pub fn update_focused_workspace_by_monitor_idx(&mut self, idx: usize) -> Result<()> {
|
||||
|
||||
@@ -1385,4 +1385,23 @@ impl WindowsApi {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_wallpaper(hmonitor: isize) -> Result<String> {
|
||||
let wallpaper: IDesktopWallpaper =
|
||||
unsafe { CoCreateInstance(&DesktopWallpaper, None, CLSCTX_ALL)? };
|
||||
|
||||
let monitor_id = if let Some(path) = Self::monitor_device_path(hmonitor) {
|
||||
PCWSTR::from_raw(HSTRING::from(path).as_ptr())
|
||||
} else {
|
||||
PCWSTR::null()
|
||||
};
|
||||
|
||||
// Set the wallpaper
|
||||
unsafe {
|
||||
wallpaper
|
||||
.GetWallpaper(monitor_id)
|
||||
.and_then(|pwstr| pwstr.to_string().map_err(|e| e.into()))
|
||||
}
|
||||
.process()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,13 +302,12 @@ impl Workspace {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_wallpaper(&self, hmonitor: isize) -> Result<()> {
|
||||
if let Some(wallpaper) = &self.wallpaper {
|
||||
pub fn apply_wallpaper(&self, hmonitor: isize, monitor_wp: &Option<Wallpaper>) -> Result<()> {
|
||||
if let Some(wallpaper) = self.wallpaper.as_ref().or(monitor_wp.as_ref()) {
|
||||
if let Err(error) = WindowsApi::set_wallpaper(&wallpaper.path, hmonitor) {
|
||||
tracing::error!("failed to set wallpaper: {error}");
|
||||
}
|
||||
|
||||
// if !cfg!(debug_assertions) && wallpaper.generate_theme.unwrap_or(true) {
|
||||
if wallpaper.generate_theme.unwrap_or(true) {
|
||||
let variant = wallpaper
|
||||
.theme_options
|
||||
@@ -419,12 +418,17 @@ impl Workspace {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn restore(&mut self, mouse_follows_focus: bool, hmonitor: isize) -> Result<()> {
|
||||
pub fn restore(
|
||||
&mut self,
|
||||
mouse_follows_focus: bool,
|
||||
hmonitor: isize,
|
||||
monitor_wp: &Option<Wallpaper>,
|
||||
) -> Result<()> {
|
||||
if let Some(container) = self.monocle_container() {
|
||||
if let Some(window) = container.focused_window() {
|
||||
container.restore();
|
||||
window.focus(mouse_follows_focus)?;
|
||||
return self.apply_wallpaper(hmonitor);
|
||||
return self.apply_wallpaper(hmonitor, monitor_wp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,7 +472,7 @@ impl Workspace {
|
||||
floating_window.focus(mouse_follows_focus)?;
|
||||
}
|
||||
|
||||
self.apply_wallpaper(hmonitor)
|
||||
self.apply_wallpaper(hmonitor, monitor_wp)
|
||||
}
|
||||
|
||||
pub fn update(&mut self) -> Result<()> {
|
||||
|
||||
251
schema.json
251
schema.json
@@ -1131,6 +1131,257 @@
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"wallpaper": {
|
||||
"description": "Specify a wallpaper for this monitor",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"properties": {
|
||||
"generate_theme": {
|
||||
"description": "Generate and apply Base16 theme for this wallpaper (default: true)",
|
||||
"type": "boolean"
|
||||
},
|
||||
"path": {
|
||||
"description": "Path to the wallpaper image file",
|
||||
"type": "string"
|
||||
},
|
||||
"theme_options": {
|
||||
"description": "Specify Light or Dark variant for theme generation (default: Dark)",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bar_accent": {
|
||||
"description": "Komorebi status bar accent (default: Base0D)",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Base00",
|
||||
"Base01",
|
||||
"Base02",
|
||||
"Base03",
|
||||
"Base04",
|
||||
"Base05",
|
||||
"Base06",
|
||||
"Base07",
|
||||
"Base08",
|
||||
"Base09",
|
||||
"Base0A",
|
||||
"Base0B",
|
||||
"Base0C",
|
||||
"Base0D",
|
||||
"Base0E",
|
||||
"Base0F"
|
||||
]
|
||||
},
|
||||
"floating_border": {
|
||||
"description": "Border colour when the window is floating (default: Base09)",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Base00",
|
||||
"Base01",
|
||||
"Base02",
|
||||
"Base03",
|
||||
"Base04",
|
||||
"Base05",
|
||||
"Base06",
|
||||
"Base07",
|
||||
"Base08",
|
||||
"Base09",
|
||||
"Base0A",
|
||||
"Base0B",
|
||||
"Base0C",
|
||||
"Base0D",
|
||||
"Base0E",
|
||||
"Base0F"
|
||||
]
|
||||
},
|
||||
"monocle_border": {
|
||||
"description": "Border colour when the container is in monocle mode (default: Base0F)",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Base00",
|
||||
"Base01",
|
||||
"Base02",
|
||||
"Base03",
|
||||
"Base04",
|
||||
"Base05",
|
||||
"Base06",
|
||||
"Base07",
|
||||
"Base08",
|
||||
"Base09",
|
||||
"Base0A",
|
||||
"Base0B",
|
||||
"Base0C",
|
||||
"Base0D",
|
||||
"Base0E",
|
||||
"Base0F"
|
||||
]
|
||||
},
|
||||
"single_border": {
|
||||
"description": "Border colour when the container contains a single window (default: Base0D)",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Base00",
|
||||
"Base01",
|
||||
"Base02",
|
||||
"Base03",
|
||||
"Base04",
|
||||
"Base05",
|
||||
"Base06",
|
||||
"Base07",
|
||||
"Base08",
|
||||
"Base09",
|
||||
"Base0A",
|
||||
"Base0B",
|
||||
"Base0C",
|
||||
"Base0D",
|
||||
"Base0E",
|
||||
"Base0F"
|
||||
]
|
||||
},
|
||||
"stack_border": {
|
||||
"description": "Border colour when the container contains multiple windows (default: Base0B)",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Base00",
|
||||
"Base01",
|
||||
"Base02",
|
||||
"Base03",
|
||||
"Base04",
|
||||
"Base05",
|
||||
"Base06",
|
||||
"Base07",
|
||||
"Base08",
|
||||
"Base09",
|
||||
"Base0A",
|
||||
"Base0B",
|
||||
"Base0C",
|
||||
"Base0D",
|
||||
"Base0E",
|
||||
"Base0F"
|
||||
]
|
||||
},
|
||||
"stackbar_background": {
|
||||
"description": "Stackbar tab background colour (default: Base01)",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Base00",
|
||||
"Base01",
|
||||
"Base02",
|
||||
"Base03",
|
||||
"Base04",
|
||||
"Base05",
|
||||
"Base06",
|
||||
"Base07",
|
||||
"Base08",
|
||||
"Base09",
|
||||
"Base0A",
|
||||
"Base0B",
|
||||
"Base0C",
|
||||
"Base0D",
|
||||
"Base0E",
|
||||
"Base0F"
|
||||
]
|
||||
},
|
||||
"stackbar_focused_text": {
|
||||
"description": "Stackbar focused tab text colour (default: Base0B)",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Base00",
|
||||
"Base01",
|
||||
"Base02",
|
||||
"Base03",
|
||||
"Base04",
|
||||
"Base05",
|
||||
"Base06",
|
||||
"Base07",
|
||||
"Base08",
|
||||
"Base09",
|
||||
"Base0A",
|
||||
"Base0B",
|
||||
"Base0C",
|
||||
"Base0D",
|
||||
"Base0E",
|
||||
"Base0F"
|
||||
]
|
||||
},
|
||||
"stackbar_unfocused_text": {
|
||||
"description": "Stackbar unfocused tab text colour (default: Base05)",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Base00",
|
||||
"Base01",
|
||||
"Base02",
|
||||
"Base03",
|
||||
"Base04",
|
||||
"Base05",
|
||||
"Base06",
|
||||
"Base07",
|
||||
"Base08",
|
||||
"Base09",
|
||||
"Base0A",
|
||||
"Base0B",
|
||||
"Base0C",
|
||||
"Base0D",
|
||||
"Base0E",
|
||||
"Base0F"
|
||||
]
|
||||
},
|
||||
"theme_variant": {
|
||||
"description": "Specify Light or Dark variant for theme generation (default: Dark)",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Dark",
|
||||
"Light"
|
||||
]
|
||||
},
|
||||
"unfocused_border": {
|
||||
"description": "Border colour when the container is unfocused (default: Base01)",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Base00",
|
||||
"Base01",
|
||||
"Base02",
|
||||
"Base03",
|
||||
"Base04",
|
||||
"Base05",
|
||||
"Base06",
|
||||
"Base07",
|
||||
"Base08",
|
||||
"Base09",
|
||||
"Base0A",
|
||||
"Base0B",
|
||||
"Base0C",
|
||||
"Base0D",
|
||||
"Base0E",
|
||||
"Base0F"
|
||||
]
|
||||
},
|
||||
"unfocused_locked_border": {
|
||||
"description": "Border colour when the container is unfocused and locked (default: Base08)",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Base00",
|
||||
"Base01",
|
||||
"Base02",
|
||||
"Base03",
|
||||
"Base04",
|
||||
"Base05",
|
||||
"Base06",
|
||||
"Base07",
|
||||
"Base08",
|
||||
"Base09",
|
||||
"Base0A",
|
||||
"Base0B",
|
||||
"Base0C",
|
||||
"Base0D",
|
||||
"Base0E",
|
||||
"Base0F"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"window_based_work_area_offset": {
|
||||
"description": "Window based work area offset (default: None)",
|
||||
"type": "object",
|
||||
|
||||
Reference in New Issue
Block a user