config: add move-to-output action
This commit is contained in:
parent
2a517f437a
commit
fecfd24ba0
15 changed files with 357 additions and 76 deletions
2
.github/workflows/toml-spec.yml
vendored
2
.github/workflows/toml-spec.yml
vendored
|
|
@ -11,7 +11,7 @@ env:
|
|||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
rustfmt:
|
||||
toml-spec:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use {
|
|||
crate::{
|
||||
_private::{
|
||||
bincode_ops,
|
||||
ipc::{ClientMessage, InitMessage, Response, ServerMessage},
|
||||
ipc::{ClientMessage, InitMessage, Response, ServerMessage, WorkspaceSource},
|
||||
logging, Config, ConfigEntry, ConfigEntryGen, PollableId, WireMode, VERSION,
|
||||
},
|
||||
exec::Command,
|
||||
|
|
@ -421,6 +421,13 @@ impl Client {
|
|||
self.send(&ClientMessage::DisablePointerConstraint { seat });
|
||||
}
|
||||
|
||||
pub fn move_to_output(&self, workspace: WorkspaceSource, connector: Connector) {
|
||||
self.send(&ClientMessage::MoveToOutput {
|
||||
workspace,
|
||||
connector,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_fullscreen(&self, seat: Seat, fullscreen: bool) {
|
||||
self.send(&ClientMessage::SetFullscreen { seat, fullscreen });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -424,6 +424,16 @@ pub enum ClientMessage<'a> {
|
|||
SetIdle {
|
||||
timeout: Duration,
|
||||
},
|
||||
MoveToOutput {
|
||||
workspace: WorkspaceSource,
|
||||
connector: Connector,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum WorkspaceSource {
|
||||
Seat(Seat),
|
||||
Explicit(Workspace),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ use {
|
|||
input::{acceleration::AccelProfile, capability::Capability},
|
||||
keyboard::Keymap,
|
||||
Axis, Direction, ModifiedKeySym, Workspace,
|
||||
_private::DEFAULT_SEAT_NAME,
|
||||
_private::{ipc::WorkspaceSource, DEFAULT_SEAT_NAME},
|
||||
video::Connector,
|
||||
},
|
||||
serde::{Deserialize, Serialize},
|
||||
std::time::Duration,
|
||||
|
|
@ -319,6 +320,11 @@ impl Seat {
|
|||
pub fn disable_pointer_constraint(self) {
|
||||
get!().disable_pointer_constraint(self)
|
||||
}
|
||||
|
||||
/// Moves the currently focused workspace to another output.
|
||||
pub fn move_to_output(self, connector: Connector) {
|
||||
get!().move_to_output(WorkspaceSource::Seat(self), connector);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns all seats.
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
)]
|
||||
|
||||
use {
|
||||
crate::keyboard::ModifiedKeySym,
|
||||
crate::{_private::ipc::WorkspaceSource, keyboard::ModifiedKeySym, video::Connector},
|
||||
serde::{Deserialize, Serialize},
|
||||
std::{
|
||||
fmt::{Debug, Display, Formatter},
|
||||
|
|
@ -159,6 +159,13 @@ impl Workspace {
|
|||
let get = get!();
|
||||
get.set_workspace_capture(self, !get.get_workspace_capture(self));
|
||||
}
|
||||
|
||||
/// Moves this workspace to another output.
|
||||
///
|
||||
/// This has no effect if the workspace is not currently being shown.
|
||||
pub fn move_to_output(self, output: Connector) {
|
||||
get!().move_to_output(WorkspaceSource::Explicit(self), output);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the workspace with the given name.
|
||||
|
|
|
|||
|
|
@ -440,9 +440,8 @@ fn create_dummy_output(state: &Rc<State>) {
|
|||
title_texture: Cell::new(None),
|
||||
attention_requests: Default::default(),
|
||||
});
|
||||
dummy_workspace.output_link.set(Some(
|
||||
dummy_output.workspaces.add_last(dummy_workspace.clone()),
|
||||
));
|
||||
*dummy_workspace.output_link.borrow_mut() =
|
||||
Some(dummy_output.workspaces.add_last(dummy_workspace.clone()));
|
||||
dummy_output.show_workspace(&dummy_workspace);
|
||||
state.dummy_output.set(Some(dummy_output));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@ use {
|
|||
scale::Scale,
|
||||
state::{ConnectorData, DeviceHandlerData, DrmDevData, OutputData, State},
|
||||
theme::{Color, ThemeSized, DEFAULT_FONT},
|
||||
tree::{ContainerNode, ContainerSplit, FloatNode, Node, NodeVisitorBase, OutputNode},
|
||||
tree::{
|
||||
move_ws_to_output, ContainerNode, ContainerSplit, FloatNode, Node, NodeVisitorBase,
|
||||
OutputNode, WsMoveConfig,
|
||||
},
|
||||
utils::{
|
||||
asyncevent::AsyncEvent,
|
||||
copyhashmap::CopyHashMap,
|
||||
|
|
@ -29,7 +32,7 @@ use {
|
|||
jay_config::{
|
||||
_private::{
|
||||
bincode_ops,
|
||||
ipc::{ClientMessage, Response, ServerMessage},
|
||||
ipc::{ClientMessage, Response, ServerMessage, WorkspaceSource},
|
||||
PollableId, WireMode,
|
||||
},
|
||||
input::{
|
||||
|
|
@ -753,6 +756,45 @@ impl ConfigProxyHandler {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_move_to_output(
|
||||
&self,
|
||||
workspace: WorkspaceSource,
|
||||
connector: Connector,
|
||||
) -> Result<(), CphError> {
|
||||
let output = self.get_output(connector)?;
|
||||
let ws = match workspace {
|
||||
WorkspaceSource::Explicit(ws) => {
|
||||
let name = self.get_workspace(ws)?;
|
||||
match self.state.workspaces.get(name.as_str()) {
|
||||
Some(ws) => ws,
|
||||
_ => return Ok(()),
|
||||
}
|
||||
}
|
||||
WorkspaceSource::Seat(s) => match self.get_seat(s)?.get_output().workspace.get() {
|
||||
Some(ws) => ws,
|
||||
_ => return Ok(()),
|
||||
},
|
||||
};
|
||||
if ws.is_dummy || output.node.is_dummy {
|
||||
return Ok(());
|
||||
}
|
||||
if ws.output.get().id == output.node.id {
|
||||
return Ok(());
|
||||
}
|
||||
let link = match &*ws.output_link.borrow() {
|
||||
None => return Ok(()),
|
||||
Some(l) => l.to_ref(),
|
||||
};
|
||||
let config = WsMoveConfig {
|
||||
make_visible_if_empty: true,
|
||||
source_is_destroyed: false,
|
||||
};
|
||||
move_ws_to_output(&link, &output.node, config);
|
||||
self.state.tree_changed();
|
||||
self.state.damage();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_set_idle(&self, timeout: Duration) {
|
||||
self.state.idle.set_timeout(timeout);
|
||||
}
|
||||
|
|
@ -1676,6 +1718,12 @@ impl ConfigProxyHandler {
|
|||
.handle_get_input_device_devnode(device)
|
||||
.wrn("get_input_device_devnode")?,
|
||||
ClientMessage::SetIdle { timeout } => self.handle_set_idle(timeout),
|
||||
ClientMessage::MoveToOutput {
|
||||
workspace,
|
||||
connector,
|
||||
} => self
|
||||
.handle_move_to_output(workspace, connector)
|
||||
.wrn("move_to_output")?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ impl OutputNode {
|
|||
stacked: Default::default(),
|
||||
seat_state: Default::default(),
|
||||
name: name.to_string(),
|
||||
output_link: Cell::new(None),
|
||||
output_link: Default::default(),
|
||||
visible: Cell::new(false),
|
||||
fullscreen: Default::default(),
|
||||
visible_on_desired_output: Cell::new(false),
|
||||
|
|
@ -347,8 +347,7 @@ impl OutputNode {
|
|||
title_texture: Default::default(),
|
||||
attention_requests: Default::default(),
|
||||
});
|
||||
ws.output_link
|
||||
.set(Some(self.workspaces.add_last(ws.clone())));
|
||||
*ws.output_link.borrow_mut() = Some(self.workspaces.add_last(ws.clone()));
|
||||
self.state.workspaces.set(name.to_string(), ws.clone());
|
||||
if self.workspace.is_none() {
|
||||
self.show_workspace(&ws);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,12 @@ use {
|
|||
},
|
||||
wire::JayWorkspaceId,
|
||||
},
|
||||
std::{cell::Cell, fmt::Debug, ops::Deref, rc::Rc},
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
fmt::Debug,
|
||||
ops::Deref,
|
||||
rc::Rc,
|
||||
},
|
||||
};
|
||||
|
||||
tree_id!(WorkspaceNodeId);
|
||||
|
|
@ -38,7 +43,7 @@ pub struct WorkspaceNode {
|
|||
pub stacked: LinkedList<Rc<dyn StackedNode>>,
|
||||
pub seat_state: NodeSeatState,
|
||||
pub name: String,
|
||||
pub output_link: Cell<Option<LinkedNode<Rc<WorkspaceNode>>>>,
|
||||
pub output_link: RefCell<Option<LinkedNode<Rc<WorkspaceNode>>>>,
|
||||
pub visible: Cell<bool>,
|
||||
pub fullscreen: CloneCell<Option<Rc<dyn ToplevelNode>>>,
|
||||
pub visible_on_desired_output: Cell<bool>,
|
||||
|
|
@ -52,7 +57,7 @@ pub struct WorkspaceNode {
|
|||
impl WorkspaceNode {
|
||||
pub fn clear(&self) {
|
||||
self.container.set(None);
|
||||
self.output_link.set(None);
|
||||
*self.output_link.borrow_mut() = None;
|
||||
self.fullscreen.set(None);
|
||||
self.jay_workspaces.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use {
|
|||
status::MessageFormat,
|
||||
theme::Color,
|
||||
video::{GfxApi, Transform},
|
||||
Axis, Direction,
|
||||
Axis, Direction, Workspace,
|
||||
},
|
||||
std::{
|
||||
error::Error,
|
||||
|
|
@ -53,26 +53,70 @@ pub enum SimpleCommand {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Action {
|
||||
ConfigureConnector { con: ConfigConnector },
|
||||
ConfigureDirectScanout { enabled: bool },
|
||||
ConfigureDrmDevice { dev: ConfigDrmDevice },
|
||||
ConfigureIdle { idle: Duration },
|
||||
ConfigureInput { input: Input },
|
||||
ConfigureOutput { out: Output },
|
||||
Exec { exec: Exec },
|
||||
MoveToWorkspace { name: String },
|
||||
Multi { actions: Vec<Action> },
|
||||
SetEnv { env: Vec<(String, String)> },
|
||||
SetGfxApi { api: GfxApi },
|
||||
SetKeymap { map: ConfigKeymap },
|
||||
SetLogLevel { level: LogLevel },
|
||||
SetRenderDevice { dev: DrmDeviceMatch },
|
||||
SetStatus { status: Option<Status> },
|
||||
SetTheme { theme: Box<Theme> },
|
||||
ShowWorkspace { name: String },
|
||||
SimpleCommand { cmd: SimpleCommand },
|
||||
SwitchToVt { num: u32 },
|
||||
UnsetEnv { env: Vec<String> },
|
||||
ConfigureConnector {
|
||||
con: ConfigConnector,
|
||||
},
|
||||
ConfigureDirectScanout {
|
||||
enabled: bool,
|
||||
},
|
||||
ConfigureDrmDevice {
|
||||
dev: ConfigDrmDevice,
|
||||
},
|
||||
ConfigureIdle {
|
||||
idle: Duration,
|
||||
},
|
||||
ConfigureInput {
|
||||
input: Input,
|
||||
},
|
||||
ConfigureOutput {
|
||||
out: Output,
|
||||
},
|
||||
Exec {
|
||||
exec: Exec,
|
||||
},
|
||||
MoveToWorkspace {
|
||||
name: String,
|
||||
},
|
||||
Multi {
|
||||
actions: Vec<Action>,
|
||||
},
|
||||
SetEnv {
|
||||
env: Vec<(String, String)>,
|
||||
},
|
||||
SetGfxApi {
|
||||
api: GfxApi,
|
||||
},
|
||||
SetKeymap {
|
||||
map: ConfigKeymap,
|
||||
},
|
||||
SetLogLevel {
|
||||
level: LogLevel,
|
||||
},
|
||||
SetRenderDevice {
|
||||
dev: DrmDeviceMatch,
|
||||
},
|
||||
SetStatus {
|
||||
status: Option<Status>,
|
||||
},
|
||||
SetTheme {
|
||||
theme: Box<Theme>,
|
||||
},
|
||||
ShowWorkspace {
|
||||
name: String,
|
||||
},
|
||||
SimpleCommand {
|
||||
cmd: SimpleCommand,
|
||||
},
|
||||
SwitchToVt {
|
||||
num: u32,
|
||||
},
|
||||
UnsetEnv {
|
||||
env: Vec<String>,
|
||||
},
|
||||
MoveToOutput {
|
||||
workspace: Option<Workspace>,
|
||||
output: OutputMatch,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
|
|
|
|||
|
|
@ -16,19 +16,24 @@ use {
|
|||
keymap::{KeymapParser, KeymapParserError},
|
||||
log_level::{LogLevelParser, LogLevelParserError},
|
||||
output::{OutputParser, OutputParserError},
|
||||
output_match::{OutputMatchParser, OutputMatchParserError},
|
||||
status::{StatusParser, StatusParserError},
|
||||
theme::{ThemeParser, ThemeParserError},
|
||||
StringParser, StringParserError,
|
||||
},
|
||||
spanned::SpannedErrorExt,
|
||||
Action,
|
||||
},
|
||||
toml::{
|
||||
toml_span::{Span, Spanned, SpannedExt},
|
||||
toml_span::{DespanExt, Span, Spanned, SpannedExt},
|
||||
toml_value::Value,
|
||||
},
|
||||
},
|
||||
indexmap::IndexMap,
|
||||
jay_config::Axis::{Horizontal, Vertical},
|
||||
jay_config::{
|
||||
get_workspace,
|
||||
Axis::{Horizontal, Vertical},
|
||||
},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
|
|
@ -45,31 +50,33 @@ pub enum ActionParserError {
|
|||
#[error(transparent)]
|
||||
Extract(#[from] ExtractorError),
|
||||
#[error("Could not parse the exec action")]
|
||||
Exec(#[from] ExecParserError),
|
||||
Exec(#[source] ExecParserError),
|
||||
#[error("Could not parse the configure-connector action")]
|
||||
ConfigureConnector(#[from] ConnectorParserError),
|
||||
ConfigureConnector(#[source] ConnectorParserError),
|
||||
#[error("Could not parse the configure-input action")]
|
||||
ConfigureInput(#[from] InputParserError),
|
||||
ConfigureInput(#[source] InputParserError),
|
||||
#[error("Could not parse the configure-output action")]
|
||||
ConfigureOutput(#[from] OutputParserError),
|
||||
ConfigureOutput(#[source] OutputParserError),
|
||||
#[error("Could not parse the environment variables")]
|
||||
Env(#[from] EnvParserError),
|
||||
Env(#[source] EnvParserError),
|
||||
#[error("Could not parse a set-keymap action")]
|
||||
SetKeymap(#[from] KeymapParserError),
|
||||
SetKeymap(#[source] KeymapParserError),
|
||||
#[error("Could not parse a set-status action")]
|
||||
Status(#[from] StatusParserError),
|
||||
Status(#[source] StatusParserError),
|
||||
#[error("Could not parse a set-theme action")]
|
||||
Theme(#[from] ThemeParserError),
|
||||
Theme(#[source] ThemeParserError),
|
||||
#[error("Could not parse a set-log-level action")]
|
||||
SetLogLevel(#[from] LogLevelParserError),
|
||||
SetLogLevel(#[source] LogLevelParserError),
|
||||
#[error("Could not parse a set-gfx-api action")]
|
||||
GfxApi(#[from] GfxApiParserError),
|
||||
GfxApi(#[source] GfxApiParserError),
|
||||
#[error("Could not parse a configure-drm-device action")]
|
||||
DrmDevice(#[from] DrmDeviceParserError),
|
||||
DrmDevice(#[source] DrmDeviceParserError),
|
||||
#[error("Could not parse a set-render-device action")]
|
||||
SetRenderDevice(#[from] DrmDeviceMatchParserError),
|
||||
SetRenderDevice(#[source] DrmDeviceMatchParserError),
|
||||
#[error("Could not parse a configure-idle action")]
|
||||
ConfigureIdle(#[from] IdleParserError),
|
||||
ConfigureIdle(#[source] IdleParserError),
|
||||
#[error("Could not parse a move-to-output action")]
|
||||
MoveToOutput(#[source] OutputMatchParserError),
|
||||
}
|
||||
|
||||
pub struct ActionParser<'a>(pub &'a Context<'a>);
|
||||
|
|
@ -117,7 +124,8 @@ impl ActionParser<'_> {
|
|||
fn parse_exec(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let exec = ext
|
||||
.extract(val("exec"))?
|
||||
.parse_map(&mut ExecParser(self.0))?;
|
||||
.parse_map(&mut ExecParser(self.0))
|
||||
.map_spanned_err(ActionParserError::Exec)?;
|
||||
Ok(Action::Exec { exec })
|
||||
}
|
||||
|
||||
|
|
@ -139,35 +147,46 @@ impl ActionParser<'_> {
|
|||
fn parse_configure_connector(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let con = ext
|
||||
.extract(val("connector"))?
|
||||
.parse_map(&mut ConnectorParser(self.0))?;
|
||||
.parse_map(&mut ConnectorParser(self.0))
|
||||
.map_spanned_err(ActionParserError::ConfigureConnector)?;
|
||||
Ok(Action::ConfigureConnector { con })
|
||||
}
|
||||
|
||||
fn parse_configure_input(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let input = ext.extract(val("input"))?.parse_map(&mut InputParser {
|
||||
cx: self.0,
|
||||
tag_ok: false,
|
||||
})?;
|
||||
let input = ext
|
||||
.extract(val("input"))?
|
||||
.parse_map(&mut InputParser {
|
||||
cx: self.0,
|
||||
tag_ok: false,
|
||||
})
|
||||
.map_spanned_err(ActionParserError::ConfigureInput)?;
|
||||
Ok(Action::ConfigureInput { input })
|
||||
}
|
||||
|
||||
fn parse_configure_idle(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let idle = ext
|
||||
.extract(val("idle"))?
|
||||
.parse_map(&mut IdleParser(self.0))?;
|
||||
.parse_map(&mut IdleParser(self.0))
|
||||
.map_spanned_err(ActionParserError::ConfigureIdle)?;
|
||||
Ok(Action::ConfigureIdle { idle })
|
||||
}
|
||||
|
||||
fn parse_configure_output(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let out = ext.extract(val("output"))?.parse_map(&mut OutputParser {
|
||||
cx: self.0,
|
||||
name_ok: false,
|
||||
})?;
|
||||
let out = ext
|
||||
.extract(val("output"))?
|
||||
.parse_map(&mut OutputParser {
|
||||
cx: self.0,
|
||||
name_ok: false,
|
||||
})
|
||||
.map_spanned_err(ActionParserError::ConfigureOutput)?;
|
||||
Ok(Action::ConfigureOutput { out })
|
||||
}
|
||||
|
||||
fn parse_set_env(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let env = ext.extract(val("env"))?.parse_map(&mut EnvParser)?;
|
||||
let env = ext
|
||||
.extract(val("env"))?
|
||||
.parse_map(&mut EnvParser)
|
||||
.map_spanned_err(ActionParserError::Env)?;
|
||||
Ok(Action::SetEnv { env })
|
||||
}
|
||||
|
||||
|
|
@ -195,17 +214,23 @@ impl ActionParser<'_> {
|
|||
}
|
||||
|
||||
fn parse_set_keymap(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let map = ext.extract(val("map"))?.parse_map(&mut KeymapParser {
|
||||
cx: self.0,
|
||||
definition: false,
|
||||
})?;
|
||||
let map = ext
|
||||
.extract(val("map"))?
|
||||
.parse_map(&mut KeymapParser {
|
||||
cx: self.0,
|
||||
definition: false,
|
||||
})
|
||||
.map_spanned_err(ActionParserError::SetKeymap)?;
|
||||
Ok(Action::SetKeymap { map })
|
||||
}
|
||||
|
||||
fn parse_set_status(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let status = match ext.extract(opt(val("status")))? {
|
||||
None => None,
|
||||
Some(v) => Some(v.parse_map(&mut StatusParser(self.0))?),
|
||||
Some(v) => Some(
|
||||
v.parse_map(&mut StatusParser(self.0))
|
||||
.map_spanned_err(ActionParserError::Status)?,
|
||||
),
|
||||
};
|
||||
Ok(Action::SetStatus { status })
|
||||
}
|
||||
|
|
@ -213,26 +238,34 @@ impl ActionParser<'_> {
|
|||
fn parse_set_theme(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let theme = ext
|
||||
.extract(val("theme"))?
|
||||
.parse_map(&mut ThemeParser(self.0))?;
|
||||
.parse_map(&mut ThemeParser(self.0))
|
||||
.map_spanned_err(ActionParserError::Theme)?;
|
||||
Ok(Action::SetTheme {
|
||||
theme: Box::new(theme),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_set_log_level(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let level = ext.extract(val("level"))?.parse_map(&mut LogLevelParser)?;
|
||||
let level = ext
|
||||
.extract(val("level"))?
|
||||
.parse_map(&mut LogLevelParser)
|
||||
.map_spanned_err(ActionParserError::SetLogLevel)?;
|
||||
Ok(Action::SetLogLevel { level })
|
||||
}
|
||||
|
||||
fn parse_set_gfx_api(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let api = ext.extract(val("api"))?.parse_map(&mut GfxApiParser)?;
|
||||
let api = ext
|
||||
.extract(val("api"))?
|
||||
.parse_map(&mut GfxApiParser)
|
||||
.map_spanned_err(ActionParserError::GfxApi)?;
|
||||
Ok(Action::SetGfxApi { api })
|
||||
}
|
||||
|
||||
fn parse_set_render_device(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let dev = ext
|
||||
.extract(val("dev"))?
|
||||
.parse_map(&mut DrmDeviceMatchParser(self.0))?;
|
||||
.parse_map(&mut DrmDeviceMatchParser(self.0))
|
||||
.map_spanned_err(ActionParserError::SetRenderDevice)?;
|
||||
Ok(Action::SetRenderDevice { dev })
|
||||
}
|
||||
|
||||
|
|
@ -242,12 +275,26 @@ impl ActionParser<'_> {
|
|||
}
|
||||
|
||||
fn parse_configure_drm_device(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let dev = ext.extract(val("dev"))?.parse_map(&mut DrmDeviceParser {
|
||||
cx: self.0,
|
||||
name_ok: false,
|
||||
})?;
|
||||
let dev = ext
|
||||
.extract(val("dev"))?
|
||||
.parse_map(&mut DrmDeviceParser {
|
||||
cx: self.0,
|
||||
name_ok: false,
|
||||
})
|
||||
.map_spanned_err(ActionParserError::DrmDevice)?;
|
||||
Ok(Action::ConfigureDrmDevice { dev })
|
||||
}
|
||||
|
||||
fn parse_move_to_output(&mut self, ext: &mut Extractor<'_>) -> ParseResult<Self> {
|
||||
let (ws, output) = ext.extract((opt(str("workspace")), val("output")))?;
|
||||
let output = output
|
||||
.parse_map(&mut OutputMatchParser(self.0))
|
||||
.map_spanned_err(ActionParserError::MoveToOutput)?;
|
||||
Ok(Action::MoveToOutput {
|
||||
workspace: ws.despan().map(get_workspace),
|
||||
output,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Parser for ActionParser<'a> {
|
||||
|
|
@ -297,6 +344,7 @@ impl<'a> Parser for ActionParser<'a> {
|
|||
"configure-drm-device" => self.parse_configure_drm_device(&mut ext),
|
||||
"set-render-device" => self.parse_set_render_device(&mut ext),
|
||||
"configure-idle" => self.parse_configure_idle(&mut ext),
|
||||
"move-to-output" => self.parse_move_to_output(&mut ext),
|
||||
v => {
|
||||
ext.ignore_unused();
|
||||
return Err(ActionParserError::UnknownType(v.to_string()).spanned(ty.span));
|
||||
|
|
|
|||
|
|
@ -154,6 +154,23 @@ impl Action {
|
|||
})
|
||||
}
|
||||
Action::ConfigureIdle { idle } => Box::new(move || set_idle(Some(idle))),
|
||||
Action::MoveToOutput { output, workspace } => {
|
||||
let state = state.clone();
|
||||
Box::new(move || {
|
||||
let output = 'get_output: {
|
||||
for connector in connectors() {
|
||||
if connector.connected() && output.matches(connector, &state) {
|
||||
break 'get_output connector;
|
||||
}
|
||||
}
|
||||
return;
|
||||
};
|
||||
match workspace {
|
||||
Some(ws) => ws.move_to_output(output),
|
||||
None => s.move_to_output(output),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,6 +136,27 @@
|
|||
"name"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Moves a workspace to a different output.\n\n- Example 1:\n\n ```toml\n [shortcuts]\n alt-F1 = { type = \"move-to-output\", workspace = \"1\", output.name = \"right\" }\n ```\n\n- Example 2:\n\n ```toml\n [shortcuts]\n alt-F1 = { type = \"move-to-output\", output.name = \"right\" }\n ```\n",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "move-to-output"
|
||||
},
|
||||
"workspace": {
|
||||
"type": "string",
|
||||
"description": "The name of the workspace.\n\nIf this is omitted, the currently active workspace is moved.\n"
|
||||
},
|
||||
"output": {
|
||||
"description": "The output to move to.\n\nIf multiple outputs match, the workspace is moved to the first matching\noutput.\n",
|
||||
"$ref": "#/$defs/OutputMatch"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type",
|
||||
"output"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Applies a configuration to connectors.\n\n- Example:\n\n ```toml\n [shortcuts]\n alt-j = { type = \"configure-connector\", connector = { match.name = \"eDP-1\", enabled = false } }\n alt-k = { type = \"configure-connector\", connector = { match.name = \"eDP-1\", enabled = true } }\n ```\n",
|
||||
"type": "object",
|
||||
|
|
|
|||
|
|
@ -214,6 +214,43 @@ This table is a tagged union. The variant is determined by the `type` field. It
|
|||
|
||||
The value of this field should be a string.
|
||||
|
||||
- `move-to-output`:
|
||||
|
||||
Moves a workspace to a different output.
|
||||
|
||||
- Example 1:
|
||||
|
||||
```toml
|
||||
[shortcuts]
|
||||
alt-F1 = { type = "move-to-output", workspace = "1", output.name = "right" }
|
||||
```
|
||||
|
||||
- Example 2:
|
||||
|
||||
```toml
|
||||
[shortcuts]
|
||||
alt-F1 = { type = "move-to-output", output.name = "right" }
|
||||
```
|
||||
|
||||
The table has the following fields:
|
||||
|
||||
- `workspace` (optional):
|
||||
|
||||
The name of the workspace.
|
||||
|
||||
If this is omitted, the currently active workspace is moved.
|
||||
|
||||
The value of this field should be a string.
|
||||
|
||||
- `output` (required):
|
||||
|
||||
The output to move to.
|
||||
|
||||
If multiple outputs match, the workspace is moved to the first matching
|
||||
output.
|
||||
|
||||
The value of this field should be a [OutputMatch](#types-OutputMatch).
|
||||
|
||||
- `configure-connector`:
|
||||
|
||||
Applies a configuration to connectors.
|
||||
|
|
|
|||
|
|
@ -219,6 +219,39 @@ Action:
|
|||
description: The name of the workspace.
|
||||
required: true
|
||||
kind: string
|
||||
move-to-output:
|
||||
description: |
|
||||
Moves a workspace to a different output.
|
||||
|
||||
- Example 1:
|
||||
|
||||
```toml
|
||||
[shortcuts]
|
||||
alt-F1 = { type = "move-to-output", workspace = "1", output.name = "right" }
|
||||
```
|
||||
|
||||
- Example 2:
|
||||
|
||||
```toml
|
||||
[shortcuts]
|
||||
alt-F1 = { type = "move-to-output", output.name = "right" }
|
||||
```
|
||||
fields:
|
||||
workspace:
|
||||
description: |
|
||||
The name of the workspace.
|
||||
|
||||
If this is omitted, the currently active workspace is moved.
|
||||
required: false
|
||||
kind: string
|
||||
output:
|
||||
description: |
|
||||
The output to move to.
|
||||
|
||||
If multiple outputs match, the workspace is moved to the first matching
|
||||
output.
|
||||
required: true
|
||||
ref: OutputMatch
|
||||
configure-connector:
|
||||
description: |
|
||||
Applies a configuration to connectors.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue