mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-10 15:12:52 +02: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::DefaultLayout;
|
||||||
use crate::Layout;
|
use crate::Layout;
|
||||||
use crate::OperationDirection;
|
use crate::OperationDirection;
|
||||||
|
use crate::Wallpaper;
|
||||||
use crate::WindowsApi;
|
use crate::WindowsApi;
|
||||||
use crate::DEFAULT_CONTAINER_PADDING;
|
use crate::DEFAULT_CONTAINER_PADDING;
|
||||||
use crate::DEFAULT_WORKSPACE_PADDING;
|
use crate::DEFAULT_WORKSPACE_PADDING;
|
||||||
@@ -60,6 +61,8 @@ pub struct Monitor {
|
|||||||
pub container_padding: Option<i32>,
|
pub container_padding: Option<i32>,
|
||||||
#[getset(get_copy = "pub", set = "pub")]
|
#[getset(get_copy = "pub", set = "pub")]
|
||||||
pub workspace_padding: Option<i32>,
|
pub workspace_padding: Option<i32>,
|
||||||
|
#[getset(get = "pub", get_mut = "pub", set = "pub")]
|
||||||
|
pub wallpaper: Option<Wallpaper>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_ring_elements!(Monitor, Workspace);
|
impl_ring_elements!(Monitor, Workspace);
|
||||||
@@ -115,6 +118,7 @@ pub fn new(
|
|||||||
workspace_names: HashMap::default(),
|
workspace_names: HashMap::default(),
|
||||||
container_padding: None,
|
container_padding: None,
|
||||||
workspace_padding: None,
|
workspace_padding: None,
|
||||||
|
wallpaper: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,6 +160,7 @@ impl Monitor {
|
|||||||
workspace_names: Default::default(),
|
workspace_names: Default::default(),
|
||||||
container_padding: None,
|
container_padding: None,
|
||||||
workspace_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<()> {
|
pub fn load_focused_workspace(&mut self, mouse_follows_focus: bool) -> Result<()> {
|
||||||
let focused_idx = self.focused_workspace_idx();
|
let focused_idx = self.focused_workspace_idx();
|
||||||
let hmonitor = self.id();
|
let hmonitor = self.id();
|
||||||
|
let monitor_wp = self.wallpaper.clone();
|
||||||
for (i, workspace) in self.workspaces_mut().iter_mut().enumerate() {
|
for (i, workspace) in self.workspaces_mut().iter_mut().enumerate() {
|
||||||
if i == focused_idx {
|
if i == focused_idx {
|
||||||
workspace.restore(mouse_follows_focus, hmonitor)?;
|
workspace.restore(mouse_follows_focus, hmonitor, &monitor_wp)?;
|
||||||
} else {
|
} else {
|
||||||
workspace.hide(None);
|
workspace.hide(None);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -553,6 +553,7 @@ where
|
|||||||
workspace_names: cached.workspace_names.clone(),
|
workspace_names: cached.workspace_names.clone(),
|
||||||
container_padding: cached.container_padding,
|
container_padding: cached.container_padding,
|
||||||
workspace_padding: cached.workspace_padding,
|
workspace_padding: cached.workspace_padding,
|
||||||
|
wallpaper: cached.wallpaper.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let focused_workspace_idx = m.focused_workspace_idx();
|
let focused_workspace_idx = m.focused_workspace_idx();
|
||||||
|
|||||||
@@ -326,6 +326,9 @@ pub struct MonitorConfig {
|
|||||||
/// Workspace padding (default: global)
|
/// Workspace padding (default: global)
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub workspace_padding: Option<i32>,
|
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 {
|
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()),
|
window_based_work_area_offset_limit: Some(value.window_based_work_area_offset_limit()),
|
||||||
container_padding,
|
container_padding,
|
||||||
workspace_padding,
|
workspace_padding,
|
||||||
|
wallpaper: value.wallpaper().clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1357,6 +1361,7 @@ impl StaticConfig {
|
|||||||
);
|
);
|
||||||
monitor.set_container_padding(monitor_config.container_padding);
|
monitor.set_container_padding(monitor_config.container_padding);
|
||||||
monitor.set_workspace_padding(monitor_config.workspace_padding);
|
monitor.set_workspace_padding(monitor_config.workspace_padding);
|
||||||
|
monitor.set_wallpaper(monitor_config.wallpaper.clone());
|
||||||
|
|
||||||
monitor.update_workspaces_globals(offset);
|
monitor.update_workspaces_globals(offset);
|
||||||
for (j, ws) in monitor.workspaces_mut().iter_mut().enumerate() {
|
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(),
|
workspace_names: monitor.workspace_names.clone(),
|
||||||
container_padding: monitor.container_padding,
|
container_padding: monitor.container_padding,
|
||||||
workspace_padding: monitor.workspace_padding,
|
workspace_padding: monitor.workspace_padding,
|
||||||
|
wallpaper: monitor.wallpaper.clone(),
|
||||||
})
|
})
|
||||||
.collect::<VecDeque<_>>();
|
.collect::<VecDeque<_>>();
|
||||||
stripped_monitors.focus(wm.monitors.focused_idx());
|
stripped_monitors.focus(wm.monitors.focused_idx());
|
||||||
@@ -1015,6 +1016,7 @@ impl WindowManager {
|
|||||||
monitor.update_workspace_globals(focused_workspace_idx, offset);
|
monitor.update_workspace_globals(focused_workspace_idx, offset);
|
||||||
|
|
||||||
let hmonitor = monitor.id();
|
let hmonitor = monitor.id();
|
||||||
|
let monitor_wp = monitor.wallpaper.clone();
|
||||||
let workspace = monitor
|
let workspace = monitor
|
||||||
.focused_workspace_mut()
|
.focused_workspace_mut()
|
||||||
.ok_or_else(|| anyhow!("there is no workspace"))?;
|
.ok_or_else(|| anyhow!("there is no workspace"))?;
|
||||||
@@ -1026,8 +1028,8 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if workspace.wallpaper().is_some() {
|
if workspace.wallpaper().is_some() || monitor_wp.is_some() {
|
||||||
if let Err(error) = workspace.apply_wallpaper(hmonitor) {
|
if let Err(error) = workspace.apply_wallpaper(hmonitor, &monitor_wp) {
|
||||||
tracing::error!("failed to apply wallpaper: {}", error);
|
tracing::error!("failed to apply wallpaper: {}", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1729,13 +1731,14 @@ impl WindowManager {
|
|||||||
.ok_or_else(|| anyhow!("there is no monitor"))?;
|
.ok_or_else(|| anyhow!("there is no monitor"))?;
|
||||||
|
|
||||||
let hmonitor = monitor.id();
|
let hmonitor = monitor.id();
|
||||||
|
let monitor_wp = monitor.wallpaper.clone();
|
||||||
|
|
||||||
let workspace = monitor
|
let workspace = monitor
|
||||||
.workspaces()
|
.workspaces()
|
||||||
.get(workspace_idx)
|
.get(workspace_idx)
|
||||||
.ok_or_else(|| anyhow!("there is no workspace"))?;
|
.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<()> {
|
pub fn update_focused_workspace_by_monitor_idx(&mut self, idx: usize) -> Result<()> {
|
||||||
|
|||||||
@@ -1385,4 +1385,23 @@ impl WindowsApi {
|
|||||||
}
|
}
|
||||||
Ok(())
|
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<()> {
|
pub fn apply_wallpaper(&self, hmonitor: isize, monitor_wp: &Option<Wallpaper>) -> Result<()> {
|
||||||
if let Some(wallpaper) = &self.wallpaper {
|
if let Some(wallpaper) = self.wallpaper.as_ref().or(monitor_wp.as_ref()) {
|
||||||
if let Err(error) = WindowsApi::set_wallpaper(&wallpaper.path, hmonitor) {
|
if let Err(error) = WindowsApi::set_wallpaper(&wallpaper.path, hmonitor) {
|
||||||
tracing::error!("failed to set wallpaper: {error}");
|
tracing::error!("failed to set wallpaper: {error}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// if !cfg!(debug_assertions) && wallpaper.generate_theme.unwrap_or(true) {
|
|
||||||
if wallpaper.generate_theme.unwrap_or(true) {
|
if wallpaper.generate_theme.unwrap_or(true) {
|
||||||
let variant = wallpaper
|
let variant = wallpaper
|
||||||
.theme_options
|
.theme_options
|
||||||
@@ -419,12 +418,17 @@ impl Workspace {
|
|||||||
Ok(())
|
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(container) = self.monocle_container() {
|
||||||
if let Some(window) = container.focused_window() {
|
if let Some(window) = container.focused_window() {
|
||||||
container.restore();
|
container.restore();
|
||||||
window.focus(mouse_follows_focus)?;
|
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)?;
|
floating_window.focus(mouse_follows_focus)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.apply_wallpaper(hmonitor)
|
self.apply_wallpaper(hmonitor, monitor_wp)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self) -> Result<()> {
|
pub fn update(&mut self) -> Result<()> {
|
||||||
|
|||||||
+251
@@ -1131,6 +1131,257 @@
|
|||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int32"
|
"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": {
|
"window_based_work_area_offset": {
|
||||||
"description": "Window based work area offset (default: None)",
|
"description": "Window based work area offset (default: None)",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|||||||
Reference in New Issue
Block a user