mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-04-24 09:38:32 +02:00
feat(wm): add named workspace commands
This commit introduces three new commands, ensure-named-workspaces, named-workspace-rule, and focus-named-workspace, which email to reduce the configuration complexity by allowing users to refer to workspace names instead of monitor and workspace indices.
This commit is contained in:
@@ -77,6 +77,7 @@ pub enum SocketMessage {
|
|||||||
// Monitor and Workspace Commands
|
// Monitor and Workspace Commands
|
||||||
MonitorIndexPreference(usize, i32, i32, i32, i32),
|
MonitorIndexPreference(usize, i32, i32, i32, i32),
|
||||||
EnsureWorkspaces(usize, usize),
|
EnsureWorkspaces(usize, usize),
|
||||||
|
EnsureNamedWorkspaces(usize, Vec<String>),
|
||||||
NewWorkspace,
|
NewWorkspace,
|
||||||
ToggleTiling,
|
ToggleTiling,
|
||||||
Stop,
|
Stop,
|
||||||
@@ -91,6 +92,7 @@ pub enum SocketMessage {
|
|||||||
FocusMonitorNumber(usize),
|
FocusMonitorNumber(usize),
|
||||||
FocusWorkspaceNumber(usize),
|
FocusWorkspaceNumber(usize),
|
||||||
FocusMonitorWorkspaceNumber(usize, usize),
|
FocusMonitorWorkspaceNumber(usize, usize),
|
||||||
|
FocusNamedWorkspace(String),
|
||||||
ContainerPadding(usize, usize, i32),
|
ContainerPadding(usize, usize, i32),
|
||||||
WorkspacePadding(usize, usize, i32),
|
WorkspacePadding(usize, usize, i32),
|
||||||
WorkspaceTiling(usize, usize, bool),
|
WorkspaceTiling(usize, usize, bool),
|
||||||
@@ -114,6 +116,7 @@ pub enum SocketMessage {
|
|||||||
MonitorWorkAreaOffset(usize, Rect),
|
MonitorWorkAreaOffset(usize, Rect),
|
||||||
ResizeDelta(i32),
|
ResizeDelta(i32),
|
||||||
WorkspaceRule(ApplicationIdentifier, String, usize, usize),
|
WorkspaceRule(ApplicationIdentifier, String, usize, usize),
|
||||||
|
NamedWorkspaceRule(ApplicationIdentifier, String, String),
|
||||||
FloatRule(ApplicationIdentifier, String),
|
FloatRule(ApplicationIdentifier, String),
|
||||||
ManageRule(ApplicationIdentifier, String),
|
ManageRule(ApplicationIdentifier, String),
|
||||||
IdentifyObjectNameChangeApplication(ApplicationIdentifier, String),
|
IdentifyObjectNameChangeApplication(ApplicationIdentifier, String),
|
||||||
|
|||||||
@@ -208,6 +208,18 @@ impl WindowManager {
|
|||||||
|
|
||||||
self.enforce_workspace_rules()?;
|
self.enforce_workspace_rules()?;
|
||||||
}
|
}
|
||||||
|
SocketMessage::NamedWorkspaceRule(_, ref id, ref workspace) => {
|
||||||
|
if let Some((monitor_idx, workspace_idx)) =
|
||||||
|
self.monitor_workspace_index_by_name(workspace)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
let mut workspace_rules = WORKSPACE_RULES.lock();
|
||||||
|
workspace_rules.insert(id.to_string(), (monitor_idx, workspace_idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.enforce_workspace_rules()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
SocketMessage::ManageRule(_, ref id) => {
|
SocketMessage::ManageRule(_, ref id) => {
|
||||||
let mut manage_identifiers = MANAGE_IDENTIFIERS.lock();
|
let mut manage_identifiers = MANAGE_IDENTIFIERS.lock();
|
||||||
if !manage_identifiers.contains(id) {
|
if !manage_identifiers.contains(id) {
|
||||||
@@ -453,6 +465,25 @@ impl WindowManager {
|
|||||||
self.focus_monitor(monitor_idx)?;
|
self.focus_monitor(monitor_idx)?;
|
||||||
self.focus_workspace(workspace_idx)?;
|
self.focus_workspace(workspace_idx)?;
|
||||||
}
|
}
|
||||||
|
SocketMessage::FocusNamedWorkspace(ref name) => {
|
||||||
|
let reenable_border = if BORDER_ENABLED.load(Ordering::SeqCst) {
|
||||||
|
self.hide_border()?;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some((monitor_idx, workspace_idx)) =
|
||||||
|
self.monitor_workspace_index_by_name(name)
|
||||||
|
{
|
||||||
|
self.focus_monitor(monitor_idx)?;
|
||||||
|
self.focus_workspace(workspace_idx)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if reenable_border {
|
||||||
|
self.show_border()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
SocketMessage::Stop => {
|
SocketMessage::Stop => {
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"received stop command, restoring all hidden windows and terminating process"
|
"received stop command, restoring all hidden windows and terminating process"
|
||||||
@@ -480,6 +511,9 @@ impl WindowManager {
|
|||||||
SocketMessage::EnsureWorkspaces(monitor_idx, workspace_count) => {
|
SocketMessage::EnsureWorkspaces(monitor_idx, workspace_count) => {
|
||||||
self.ensure_workspaces_for_monitor(monitor_idx, workspace_count)?;
|
self.ensure_workspaces_for_monitor(monitor_idx, workspace_count)?;
|
||||||
}
|
}
|
||||||
|
SocketMessage::EnsureNamedWorkspaces(monitor_idx, ref names) => {
|
||||||
|
self.ensure_named_workspaces_for_monitor(monitor_idx, names)?;
|
||||||
|
}
|
||||||
SocketMessage::NewWorkspace => {
|
SocketMessage::NewWorkspace => {
|
||||||
self.new_workspace()?;
|
self.new_workspace()?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1876,6 +1876,30 @@ impl WindowManager {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
|
pub fn ensure_named_workspaces_for_monitor(
|
||||||
|
&mut self,
|
||||||
|
monitor_idx: usize,
|
||||||
|
names: &Vec<String>,
|
||||||
|
) -> Result<()> {
|
||||||
|
tracing::info!("ensuring workspace count");
|
||||||
|
|
||||||
|
let monitor = self
|
||||||
|
.monitors_mut()
|
||||||
|
.get_mut(monitor_idx)
|
||||||
|
.ok_or_else(|| anyhow!("there is no monitor"))?;
|
||||||
|
|
||||||
|
monitor.ensure_workspace_count(names.len());
|
||||||
|
|
||||||
|
for (workspace_idx, name) in names.iter().enumerate() {
|
||||||
|
if let Some(workspace) = monitor.workspaces_mut().get_mut(workspace_idx) {
|
||||||
|
workspace.set_name(Option::from(name.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn set_workspace_padding(
|
pub fn set_workspace_padding(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -2045,6 +2069,23 @@ impl WindowManager {
|
|||||||
self.update_focused_workspace(false)
|
self.update_focused_workspace(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
|
pub fn monitor_workspace_index_by_name(&mut self, name: &str) -> Option<(usize, usize)> {
|
||||||
|
tracing::info!("looking up workspace by name");
|
||||||
|
|
||||||
|
for (monitor_idx, monitor) in self.monitors().iter().enumerate() {
|
||||||
|
for (workspace_idx, workspace) in monitor.workspaces().iter().enumerate() {
|
||||||
|
if let Some(workspace_name) = workspace.name() {
|
||||||
|
if workspace_name == name {
|
||||||
|
return Option::from((monitor_idx, workspace_idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn new_workspace(&mut self) -> Result<()> {
|
pub fn new_workspace(&mut self) -> Result<()> {
|
||||||
tracing::info!("adding new workspace");
|
tracing::info!("adding new workspace");
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ use crate::INITIAL_CONFIGURATION_LOADED;
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Getters, CopyGetters, MutGetters, Setters, JsonSchema)]
|
#[derive(Debug, Clone, Serialize, Getters, CopyGetters, MutGetters, Setters, JsonSchema)]
|
||||||
pub struct Workspace {
|
pub struct Workspace {
|
||||||
#[getset(set = "pub")]
|
#[getset(get = "pub", set = "pub")]
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
containers: Ring<Container>,
|
containers: Ring<Container>,
|
||||||
#[getset(get = "pub", get_mut = "pub", set = "pub")]
|
#[getset(get = "pub", get_mut = "pub", set = "pub")]
|
||||||
|
|||||||
@@ -318,6 +318,14 @@ struct EnsureWorkspaces {
|
|||||||
workspace_count: usize,
|
workspace_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Parser, AhkFunction)]
|
||||||
|
struct EnsureNamedWorkspaces {
|
||||||
|
/// Monitor index (zero-indexed)
|
||||||
|
monitor: usize,
|
||||||
|
/// Names of desired workspaces
|
||||||
|
names: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Parser, AhkFunction)]
|
#[derive(Parser, AhkFunction)]
|
||||||
struct FocusMonitorWorkspace {
|
struct FocusMonitorWorkspace {
|
||||||
/// Target monitor index (zero-indexed)
|
/// Target monitor index (zero-indexed)
|
||||||
@@ -326,6 +334,12 @@ struct FocusMonitorWorkspace {
|
|||||||
target_workspace: usize,
|
target_workspace: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Parser, AhkFunction)]
|
||||||
|
struct FocusNamedWorkspace {
|
||||||
|
/// Target workspace name
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Parser, AhkFunction)]
|
#[derive(Parser, AhkFunction)]
|
||||||
pub struct SendToMonitorWorkspace {
|
pub struct SendToMonitorWorkspace {
|
||||||
/// Target monitor index (zero-indexed)
|
/// Target monitor index (zero-indexed)
|
||||||
@@ -412,6 +426,16 @@ struct WorkspaceRule {
|
|||||||
workspace: usize,
|
workspace: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Parser, AhkFunction)]
|
||||||
|
struct NamedWorkspaceRule {
|
||||||
|
#[clap(value_enum)]
|
||||||
|
identifier: ApplicationIdentifier,
|
||||||
|
/// Identifier as a string
|
||||||
|
id: String,
|
||||||
|
/// Name of a workspace
|
||||||
|
workspace: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Parser, AhkFunction)]
|
#[derive(Parser, AhkFunction)]
|
||||||
struct ToggleFocusFollowsMouse {
|
struct ToggleFocusFollowsMouse {
|
||||||
#[clap(value_enum, short, long, default_value = "windows")]
|
#[clap(value_enum, short, long, default_value = "windows")]
|
||||||
@@ -622,6 +646,9 @@ enum SubCommand {
|
|||||||
/// Focus the specified workspace on the target monitor
|
/// Focus the specified workspace on the target monitor
|
||||||
#[clap(arg_required_else_help = true)]
|
#[clap(arg_required_else_help = true)]
|
||||||
FocusMonitorWorkspace(FocusMonitorWorkspace),
|
FocusMonitorWorkspace(FocusMonitorWorkspace),
|
||||||
|
/// Focus the specified workspace on the target monitor
|
||||||
|
#[clap(arg_required_else_help = true)]
|
||||||
|
FocusNamedWorkspace(FocusNamedWorkspace),
|
||||||
/// Focus the monitor in the given cycle direction
|
/// Focus the monitor in the given cycle direction
|
||||||
#[clap(arg_required_else_help = true)]
|
#[clap(arg_required_else_help = true)]
|
||||||
CycleMonitor(CycleMonitor),
|
CycleMonitor(CycleMonitor),
|
||||||
@@ -673,6 +700,9 @@ enum SubCommand {
|
|||||||
/// Create at least this many workspaces for the specified monitor
|
/// Create at least this many workspaces for the specified monitor
|
||||||
#[clap(arg_required_else_help = true)]
|
#[clap(arg_required_else_help = true)]
|
||||||
EnsureWorkspaces(EnsureWorkspaces),
|
EnsureWorkspaces(EnsureWorkspaces),
|
||||||
|
/// Create at least this many workspaces for the specified monitor
|
||||||
|
#[clap(arg_required_else_help = true)]
|
||||||
|
EnsureNamedWorkspaces(EnsureNamedWorkspaces),
|
||||||
/// Set the container padding for the specified workspace
|
/// Set the container padding for the specified workspace
|
||||||
#[clap(arg_required_else_help = true)]
|
#[clap(arg_required_else_help = true)]
|
||||||
ContainerPadding(ContainerPadding),
|
ContainerPadding(ContainerPadding),
|
||||||
@@ -748,6 +778,9 @@ enum SubCommand {
|
|||||||
/// Add a rule to associate an application with a workspace
|
/// Add a rule to associate an application with a workspace
|
||||||
#[clap(arg_required_else_help = true)]
|
#[clap(arg_required_else_help = true)]
|
||||||
WorkspaceRule(WorkspaceRule),
|
WorkspaceRule(WorkspaceRule),
|
||||||
|
/// Add a rule to associate an application with a named workspace
|
||||||
|
#[clap(arg_required_else_help = true)]
|
||||||
|
NamedWorkspaceRule(NamedWorkspaceRule),
|
||||||
/// Identify an application that sends EVENT_OBJECT_NAMECHANGE on launch
|
/// Identify an application that sends EVENT_OBJECT_NAMECHANGE on launch
|
||||||
#[clap(arg_required_else_help = true)]
|
#[clap(arg_required_else_help = true)]
|
||||||
IdentifyObjectNameChangeApplication(IdentifyObjectNameChangeApplication),
|
IdentifyObjectNameChangeApplication(IdentifyObjectNameChangeApplication),
|
||||||
@@ -1158,6 +1191,12 @@ fn main() -> Result<()> {
|
|||||||
.as_bytes()?,
|
.as_bytes()?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
SubCommand::NamedWorkspaceRule(arg) => {
|
||||||
|
send_message(
|
||||||
|
&SocketMessage::NamedWorkspaceRule(arg.identifier, arg.id, arg.workspace)
|
||||||
|
.as_bytes()?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
SubCommand::Stack(arg) => {
|
SubCommand::Stack(arg) => {
|
||||||
send_message(&SocketMessage::StackWindow(arg.operation_direction).as_bytes()?)?;
|
send_message(&SocketMessage::StackWindow(arg.operation_direction).as_bytes()?)?;
|
||||||
}
|
}
|
||||||
@@ -1193,6 +1232,9 @@ fn main() -> Result<()> {
|
|||||||
.as_bytes()?,
|
.as_bytes()?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
SubCommand::FocusNamedWorkspace(arg) => {
|
||||||
|
send_message(&SocketMessage::FocusNamedWorkspace(arg.name).as_bytes()?)?;
|
||||||
|
}
|
||||||
SubCommand::CycleMonitor(arg) => {
|
SubCommand::CycleMonitor(arg) => {
|
||||||
send_message(&SocketMessage::CycleFocusMonitor(arg.cycle_direction).as_bytes()?)?;
|
send_message(&SocketMessage::CycleFocusMonitor(arg.cycle_direction).as_bytes()?)?;
|
||||||
}
|
}
|
||||||
@@ -1226,6 +1268,11 @@ fn main() -> Result<()> {
|
|||||||
.as_bytes()?,
|
.as_bytes()?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
SubCommand::EnsureNamedWorkspaces(arg) => {
|
||||||
|
send_message(
|
||||||
|
&SocketMessage::EnsureNamedWorkspaces(arg.monitor, arg.names).as_bytes()?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
SubCommand::State => {
|
SubCommand::State => {
|
||||||
let home = DATA_DIR.clone();
|
let home = DATA_DIR.clone();
|
||||||
let mut socket = home;
|
let mut socket = home;
|
||||||
|
|||||||
Reference in New Issue
Block a user