config: add Seat::show_workspace_on
This commit is contained in:
parent
d2ce140f54
commit
d320d2f3c1
12 changed files with 131 additions and 13 deletions
|
|
@ -122,6 +122,7 @@ pub(crate) struct ConfigClient {
|
|||
window_match_handlers: RefCell<HashMap<WindowMatcher, WindowMatchHandler>>,
|
||||
|
||||
feat_mod_mask: Cell<bool>,
|
||||
feat_show_workspace_on: Cell<bool>,
|
||||
}
|
||||
|
||||
struct ClientMatchHandler {
|
||||
|
|
@ -266,6 +267,7 @@ pub unsafe extern "C" fn init(
|
|||
client_match_handlers: Default::default(),
|
||||
window_match_handlers: Default::default(),
|
||||
feat_mod_mask: Cell::new(false),
|
||||
feat_show_workspace_on: Cell::new(false),
|
||||
});
|
||||
let init = unsafe { slice::from_raw_parts(init, size) };
|
||||
client.handle_init_msg(init);
|
||||
|
|
@ -591,6 +593,18 @@ impl ConfigClient {
|
|||
self.send(&ClientMessage::ShowWorkspace { seat, workspace });
|
||||
}
|
||||
|
||||
pub fn show_workspace_on(&self, seat: Seat, workspace: Workspace, connector: Connector) {
|
||||
if self.feat_show_workspace_on.get() && connector.connected() {
|
||||
self.send(&ClientMessage::ShowWorkspaceOn {
|
||||
seat,
|
||||
workspace,
|
||||
connector,
|
||||
});
|
||||
} else {
|
||||
self.show_workspace(seat, workspace);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_seat_workspace(&self, seat: Seat, workspace: Workspace) {
|
||||
self.send(&ClientMessage::SetSeatWorkspace { seat, workspace });
|
||||
}
|
||||
|
|
@ -2086,6 +2100,7 @@ impl ConfigClient {
|
|||
match feat {
|
||||
ServerFeature::NONE => {}
|
||||
ServerFeature::MOD_MASK => self.feat_mod_mask.set(true),
|
||||
ServerFeature::SHOW_WORKSPACE_ON => self.feat_show_workspace_on.set(true),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ pub struct ServerFeature(u16);
|
|||
impl ServerFeature {
|
||||
pub const NONE: Self = Self(0);
|
||||
pub const MOD_MASK: Self = Self(1);
|
||||
pub const SHOW_WORKSPACE_ON: Self = Self(2);
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
|
@ -782,6 +783,11 @@ pub enum ClientMessage<'a> {
|
|||
matcher: ClientMatcher,
|
||||
caps: ClientCapabilities,
|
||||
},
|
||||
ShowWorkspaceOn {
|
||||
seat: Seat,
|
||||
workspace: Workspace,
|
||||
connector: Connector,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
|
|
|||
|
|
@ -439,6 +439,15 @@ impl Seat {
|
|||
get!().show_workspace(self, workspace)
|
||||
}
|
||||
|
||||
/// Shows the workspace and sets the keyboard focus of the seat to that workspace.
|
||||
///
|
||||
/// If the workspace doesn't currently exist and the connector is connected, the
|
||||
/// workspace is created on the given connector. If the connector is not connected,
|
||||
/// the workspace is created on the output that contains the seat's cursor.
|
||||
pub fn show_workspace_on(self, workspace: Workspace, connector: Connector) {
|
||||
get!().show_workspace_on(self, workspace, connector)
|
||||
}
|
||||
|
||||
/// Moves the currently focused window to the workspace.
|
||||
pub fn set_workspace(self, workspace: Workspace) {
|
||||
get!().set_seat_workspace(self, workspace)
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ impl ConfigProxy {
|
|||
|
||||
pub fn configure(&self, reload: bool) {
|
||||
self.send(&ServerMessage::Features {
|
||||
features: vec![ServerFeature::MOD_MASK],
|
||||
features: vec![ServerFeature::MOD_MASK, ServerFeature::SHOW_WORKSPACE_ON],
|
||||
});
|
||||
self.send(&ServerMessage::Configure { reload });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1006,10 +1006,16 @@ impl ConfigProxyHandler {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_show_workspace(&self, seat: Seat, ws: Workspace) -> Result<(), CphError> {
|
||||
fn handle_show_workspace(
|
||||
&self,
|
||||
seat: Seat,
|
||||
ws: Workspace,
|
||||
output: Option<Connector>,
|
||||
) -> Result<(), CphError> {
|
||||
let seat = self.get_seat(seat)?;
|
||||
let name = self.get_workspace(ws)?;
|
||||
self.state.show_workspace(&seat, &name);
|
||||
let output = output.map(|o| self.get_output_node(o)).transpose()?;
|
||||
self.state.show_workspace(&seat, &name, output);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -2725,7 +2731,7 @@ impl ConfigProxyHandler {
|
|||
}
|
||||
ClientMessage::GetWorkspace { name } => self.handle_get_workspace(name),
|
||||
ClientMessage::ShowWorkspace { seat, workspace } => self
|
||||
.handle_show_workspace(seat, workspace)
|
||||
.handle_show_workspace(seat, workspace, None)
|
||||
.wrn("show_workspace")?,
|
||||
ClientMessage::SetSeatWorkspace { seat, workspace } => self
|
||||
.handle_set_seat_workspace(seat, workspace)
|
||||
|
|
@ -3203,6 +3209,13 @@ impl ConfigProxyHandler {
|
|||
ClientMessage::SetClientMatcherBoundingCapabilities { matcher, caps } => self
|
||||
.handle_set_client_matcher_bounding_capabilities(matcher, caps)
|
||||
.wrn("set_client_matcher_bounding_capabilities")?,
|
||||
ClientMessage::ShowWorkspaceOn {
|
||||
seat,
|
||||
workspace,
|
||||
connector,
|
||||
} => self
|
||||
.handle_show_workspace(seat, workspace, Some(connector))
|
||||
.wrn("show_workspace_on")?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -906,11 +906,16 @@ impl State {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn show_workspace(&self, seat: &Rc<WlSeatGlobal>, name: &str) {
|
||||
pub fn show_workspace(
|
||||
&self,
|
||||
seat: &Rc<WlSeatGlobal>,
|
||||
name: &str,
|
||||
output: Option<Rc<OutputNode>>,
|
||||
) {
|
||||
let ws = match self.workspaces.get(name) {
|
||||
Some(ws) => ws,
|
||||
_ => {
|
||||
let output = seat.get_output();
|
||||
let output = output.unwrap_or_else(|| seat.get_output());
|
||||
if output.is_dummy {
|
||||
log::warn!("Not showing workspace because seat is on dummy output");
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ pub enum Action {
|
|||
},
|
||||
ShowWorkspace {
|
||||
name: String,
|
||||
output: Option<OutputMatch>,
|
||||
},
|
||||
SimpleCommand {
|
||||
cmd: SimpleCommand,
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ pub enum ActionParserError {
|
|||
JumpToMark(#[source] MarkIdParserError),
|
||||
#[error("Could not parse a copy-mark action")]
|
||||
CopyMark(#[source] MarkIdParserError),
|
||||
#[error("Could not parse a show-workspace action")]
|
||||
ShowWorkspace(#[source] OutputMatchParserError),
|
||||
}
|
||||
|
||||
pub struct ActionParser<'a>(pub &'a Context<'a>);
|
||||
|
|
@ -184,8 +186,15 @@ impl ActionParser<'_> {
|
|||
}
|
||||
|
||||
fn parse_show_workspace(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let name = ext.extract(str("name"))?.value.to_string();
|
||||
Ok(Action::ShowWorkspace { name })
|
||||
let (name, output) = ext.extract((str("name"), opt(val("output"))))?;
|
||||
let name = name.value.to_string();
|
||||
let output = output
|
||||
.map(|o| {
|
||||
o.parse_map(&mut OutputMatchParser(self.0))
|
||||
.map_spanned_err(ActionParserError::ShowWorkspace)
|
||||
})
|
||||
.transpose()?;
|
||||
Ok(Action::ShowWorkspace { name, output })
|
||||
}
|
||||
|
||||
fn parse_move_to_workspace(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
|
|
|
|||
|
|
@ -235,9 +235,26 @@ impl Action {
|
|||
}
|
||||
Action::Exec { exec } => b.new(move || create_command(&exec).spawn()),
|
||||
Action::SwitchToVt { num } => b.new(move || switch_to_vt(num)),
|
||||
Action::ShowWorkspace { name } => {
|
||||
Action::ShowWorkspace { name, output } => {
|
||||
let workspace = get_workspace(&name);
|
||||
b.new(move || s.show_workspace(workspace))
|
||||
let state = state.clone();
|
||||
b.new(move || {
|
||||
let output = 'get_output: {
|
||||
let Some(output) = &output else {
|
||||
break 'get_output None;
|
||||
};
|
||||
for connector in connectors() {
|
||||
if connector.connected() && output.matches(connector, &state) {
|
||||
break 'get_output Some(connector);
|
||||
}
|
||||
}
|
||||
None
|
||||
};
|
||||
match output {
|
||||
Some(o) => s.show_workspace_on(workspace, o),
|
||||
_ => s.show_workspace(workspace),
|
||||
}
|
||||
})
|
||||
}
|
||||
Action::MoveToWorkspace { name } => {
|
||||
let workspace = get_workspace(&name);
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"description": "Switches to a workspace.\n\n- Example:\n\n ```toml\n [shortcuts]\n alt-F1 = { type = \"show-workspace\", name = \"1\" }\n ```\n",
|
||||
"description": "Switches to a workspace.\n\n- Example 1:\n\n ```toml\n [shortcuts]\n alt-F1 = { type = \"show-workspace\", name = \"1\" }\n ```\n\n- Example 2:\n\n ```toml\n [shortcuts]\n alt-F1 = { type = \"show-workspace\", name = \"1\", output.name = \"left\" }\n ```\n",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
|
|
@ -134,6 +134,10 @@
|
|||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the workspace."
|
||||
},
|
||||
"output": {
|
||||
"description": "The output to show a newly created workspace on. This has no effect on\nworkspaces that already exist.\n\nIf this is not set, then a new workspace is shown on the output that\ncontains the cursor.\n\nIf multiple outputs match, the workspace is shown on the first matching\noutput.\n",
|
||||
"$ref": "#/$defs/OutputMatch"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
|
|
|||
|
|
@ -232,12 +232,19 @@ This table is a tagged union. The variant is determined by the `type` field. It
|
|||
|
||||
Switches to a workspace.
|
||||
|
||||
- Example:
|
||||
- Example 1:
|
||||
|
||||
```toml
|
||||
[shortcuts]
|
||||
alt-F1 = { type = "show-workspace", name = "1" }
|
||||
```
|
||||
|
||||
- Example 2:
|
||||
|
||||
```toml
|
||||
[shortcuts]
|
||||
alt-F1 = { type = "show-workspace", name = "1", output.name = "left" }
|
||||
```
|
||||
|
||||
The table has the following fields:
|
||||
|
||||
|
|
@ -247,6 +254,19 @@ This table is a tagged union. The variant is determined by the `type` field. It
|
|||
|
||||
The value of this field should be a string.
|
||||
|
||||
- `output` (optional):
|
||||
|
||||
The output to show a newly created workspace on. This has no effect on
|
||||
workspaces that already exist.
|
||||
|
||||
If this is not set, then a new workspace is shown on the output that
|
||||
contains the cursor.
|
||||
|
||||
If multiple outputs match, the workspace is shown on the first matching
|
||||
output.
|
||||
|
||||
The value of this field should be a [OutputMatch](#types-OutputMatch).
|
||||
|
||||
- `move-to-workspace`:
|
||||
|
||||
Moves the currently focused window to a workspace.
|
||||
|
|
|
|||
|
|
@ -239,17 +239,36 @@ Action:
|
|||
description: |
|
||||
Switches to a workspace.
|
||||
|
||||
- Example:
|
||||
- Example 1:
|
||||
|
||||
```toml
|
||||
[shortcuts]
|
||||
alt-F1 = { type = "show-workspace", name = "1" }
|
||||
```
|
||||
|
||||
- Example 2:
|
||||
|
||||
```toml
|
||||
[shortcuts]
|
||||
alt-F1 = { type = "show-workspace", name = "1", output.name = "left" }
|
||||
```
|
||||
fields:
|
||||
name:
|
||||
description: The name of the workspace.
|
||||
required: true
|
||||
kind: string
|
||||
output:
|
||||
description: |
|
||||
The output to show a newly created workspace on. This has no effect on
|
||||
workspaces that already exist.
|
||||
|
||||
If this is not set, then a new workspace is shown on the output that
|
||||
contains the cursor.
|
||||
|
||||
If multiple outputs match, the workspace is shown on the first matching
|
||||
output.
|
||||
required: false
|
||||
ref: OutputMatch
|
||||
move-to-workspace:
|
||||
description: |
|
||||
Moves the currently focused window to a workspace.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue