shell: read in config, if available
This commit is contained in:
parent
55c10830e8
commit
a9d6b8c3d7
8 changed files with 276 additions and 46 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -1311,7 +1311,7 @@ checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay"
|
name = "smithay"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/pop-os/smithay?branch=main#bca8fab55e41474a6466ade0ae5073c0ecc57ccd"
|
source = "git+https://github.com/pop-os/smithay?branch=main#f3e6921298e061ed4289c68bbbec798a2534d132"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"appendlist",
|
"appendlist",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
|
|
||||||
|
|
@ -301,7 +301,7 @@ impl State {
|
||||||
&mut self.common.display.borrow_mut(),
|
&mut self.common.display.borrow_mut(),
|
||||||
&mut self.common.event_loop_handle,
|
&mut self.common.event_loop_handle,
|
||||||
) {
|
) {
|
||||||
Ok(output) => self.common.shell.map_output(&output),
|
Ok(output) => self.common.shell.map_output(&output, &mut self.backend, &self.common.config),
|
||||||
Err(err) => slog_scope::warn!("Failed to initialize output: {}", err),
|
Err(err) => slog_scope::warn!("Failed to initialize output: {}", err),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -332,7 +332,7 @@ impl State {
|
||||||
&mut self.common.display.borrow_mut(),
|
&mut self.common.display.borrow_mut(),
|
||||||
&mut self.common.event_loop_handle,
|
&mut self.common.event_loop_handle,
|
||||||
) {
|
) {
|
||||||
Ok(output) => self.common.shell.map_output(&output),
|
Ok(output) => self.common.shell.map_output(&output, &mut self.backend, &self.common.config),
|
||||||
Err(err) => slog_scope::warn!("Failed to initialize output: {}", err),
|
Err(err) => slog_scope::warn!("Failed to initialize output: {}", err),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -571,6 +571,10 @@ impl Surface {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KmsState {
|
impl KmsState {
|
||||||
|
pub fn apply_config_for_output(&mut self, output: &Output) -> Result<(), impl std::error::Error> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
pub fn schedule_render(&mut self, output: &Output) {
|
pub fn schedule_render(&mut self, output: &Output) {
|
||||||
if let Some((device, surface)) = self
|
if let Some((device, surface)) = self
|
||||||
.devices
|
.devices
|
||||||
|
|
|
||||||
|
|
@ -102,8 +102,6 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
|
||||||
);
|
);
|
||||||
output.set_preferred(mode);
|
output.set_preferred(mode);
|
||||||
|
|
||||||
state.common.shell.map_output(&output);
|
|
||||||
|
|
||||||
let (event_ping, event_source) =
|
let (event_ping, event_source) =
|
||||||
ping::make_ping().with_context(|| "Failed to init eventloop timer for winit")?;
|
ping::make_ping().with_context(|| "Failed to init eventloop timer for winit")?;
|
||||||
let (render_ping, render_source) =
|
let (render_ping, render_source) =
|
||||||
|
|
@ -150,6 +148,7 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
fps: Fps::default(),
|
fps: Fps::default(),
|
||||||
});
|
});
|
||||||
|
state.common.shell.map_output(&output, &mut state.backend, &state.common.config);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,7 @@ pub fn init_backend(event_loop: &mut EventLoop<State>, state: &mut State) -> Res
|
||||||
.x11()
|
.x11()
|
||||||
.add_window(&mut *state.common.display.borrow_mut(), event_loop.handle())
|
.add_window(&mut *state.common.display.borrow_mut(), event_loop.handle())
|
||||||
.with_context(|| "Failed to create wl_output")?;
|
.with_context(|| "Failed to create wl_output")?;
|
||||||
state.common.shell.map_output(&output);
|
state.common.shell.map_output(&output, &mut state.backend, &state.common.config);
|
||||||
|
|
||||||
event_loop
|
event_loop
|
||||||
.handle()
|
.handle()
|
||||||
|
|
|
||||||
160
src/config.rs
160
src/config.rs
|
|
@ -1,25 +1,105 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::shell::layout::FocusDirection;
|
use crate::shell::layout::FocusDirection;
|
||||||
use serde::Deserialize;
|
use serde::{Deserialize, Serialize};
|
||||||
use smithay::wayland::seat::Keysym;
|
use smithay::wayland::seat::Keysym;
|
||||||
pub use smithay::{
|
pub use smithay::{
|
||||||
backend::input::KeyState,
|
backend::input::KeyState,
|
||||||
wayland::seat::{keysyms as KeySyms, ModifiersState as KeyModifiers},
|
wayland::{
|
||||||
|
output::Output,
|
||||||
|
seat::{keysyms as KeySyms, ModifiersState as KeyModifiers},
|
||||||
|
},
|
||||||
|
utils::{Point, Size, Logical, Physical, Transform},
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, fs::OpenOptions, path::PathBuf};
|
use std::{collections::HashMap, fs::OpenOptions, path::PathBuf};
|
||||||
use xkbcommon::xkb;
|
use xkbcommon::xkb;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
pub static_conf: StaticConfig,
|
||||||
|
pub dynamic_conf: DynamicConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct StaticConfig {
|
||||||
pub key_bindings: HashMap<KeyPattern, Action>,
|
pub key_bindings: HashMap<KeyPattern, Action>,
|
||||||
pub workspace_mode: crate::shell::Mode,
|
pub workspace_mode: crate::shell::Mode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct DynamicConfig {
|
||||||
|
outputs: (Option<PathBuf>, OutputsConfig),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub struct OutputsConfig {
|
||||||
|
pub config: HashMap<Vec<OutputInfo>, Vec<OutputConfig>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct OutputInfo {
|
||||||
|
pub connector: String,
|
||||||
|
pub make: String,
|
||||||
|
pub model: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Output> for OutputInfo {
|
||||||
|
fn from(o: Output) -> OutputInfo {
|
||||||
|
let physical = o.physical_properties();
|
||||||
|
OutputInfo {
|
||||||
|
connector: o.name(),
|
||||||
|
make: physical.make,
|
||||||
|
model: physical.model,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
|
||||||
|
pub struct OutputConfig {
|
||||||
|
pub mode: ((i32, i32), Option<String>),
|
||||||
|
pub vrr: bool,
|
||||||
|
pub scale: f64,
|
||||||
|
#[serde(with="TransformDef")]
|
||||||
|
pub transform: Transform,
|
||||||
|
pub position: (i32, i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutputConfig {
|
||||||
|
fn mode_size(&self) -> Size<i32, Physical> {
|
||||||
|
self.mode.0.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mode_refresh(&self) -> i32 {
|
||||||
|
self.mode.1.as_deref().map(|x| str::parse::<f64>(x).unwrap().round() as i32).unwrap_or(60)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(remote = "Transform")]
|
||||||
|
enum TransformDef {
|
||||||
|
Normal,
|
||||||
|
_90,
|
||||||
|
_180,
|
||||||
|
_270,
|
||||||
|
Flipped,
|
||||||
|
Flipped90,
|
||||||
|
Flipped180,
|
||||||
|
Flipped270,
|
||||||
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn load() -> Config {
|
pub fn load() -> Config {
|
||||||
let mut locations = if let Ok(base) = xdg::BaseDirectories::new() {
|
let xdg = xdg::BaseDirectories::new().ok();
|
||||||
base.list_config_files_once("cosmic-comp.ron")
|
Config {
|
||||||
|
static_conf: Self::load_static(xdg.as_ref()),
|
||||||
|
dynamic_conf: Self::load_dynamic(xdg.as_ref()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_static(xdg: Option<&xdg::BaseDirectories>) -> StaticConfig {
|
||||||
|
let mut locations = if let Some(base) = xdg {
|
||||||
|
vec![
|
||||||
|
base.get_config_file("cosmic-comp.ron"),
|
||||||
|
base.get_config_file("cosmic-comp/config.ron"),
|
||||||
|
]
|
||||||
} else {
|
} else {
|
||||||
Vec::with_capacity(3)
|
Vec::with_capacity(3)
|
||||||
};
|
};
|
||||||
|
|
@ -33,17 +113,85 @@ impl Config {
|
||||||
locations.push(PathBuf::from("/etc/cosmic-comp.ron"));
|
locations.push(PathBuf::from("/etc/cosmic-comp.ron"));
|
||||||
|
|
||||||
for path in locations {
|
for path in locations {
|
||||||
|
slog_scope::debug!("Trying config location: {}", path.display());
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
|
slog_scope::info!("Using config at {}", path.display());
|
||||||
return ron::de::from_reader(OpenOptions::new().read(true).open(path).unwrap())
|
return ron::de::from_reader(OpenOptions::new().read(true).open(path).unwrap())
|
||||||
.expect("Malformed config file");
|
.expect("Malformed config file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Config {
|
StaticConfig {
|
||||||
key_bindings: HashMap::new(),
|
key_bindings: HashMap::new(),
|
||||||
workspace_mode: crate::shell::Mode::global(),
|
workspace_mode: crate::shell::Mode::global(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_dynamic(xdg: Option<&xdg::BaseDirectories>) -> DynamicConfig {
|
||||||
|
let output_path = xdg.and_then(|base| base.place_state_file("cosmic-comp/outputs.ron").ok());
|
||||||
|
let outputs = Self::load_outputs(&output_path);
|
||||||
|
|
||||||
|
DynamicConfig {
|
||||||
|
outputs: (output_path, outputs),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_outputs(path: &Option<PathBuf>) -> OutputsConfig {
|
||||||
|
if let Some(path) = path.as_ref() {
|
||||||
|
if path.exists() {
|
||||||
|
match ron::de::from_reader(OpenOptions::new().read(true).open(path).unwrap()) {
|
||||||
|
Ok(config) => return config,
|
||||||
|
Err(err) => {
|
||||||
|
slog_scope::warn!("Failed to read output_config ({}), resetting..", err);
|
||||||
|
std::fs::remove_file(path);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputsConfig {
|
||||||
|
config: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PersistenceGuard<'a, T: Serialize>(Option<PathBuf>, &'a mut T);
|
||||||
|
|
||||||
|
impl<'a, T: Serialize> std::ops::Deref for PersistenceGuard<'a, T> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
&self.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Serialize> std::ops::DerefMut for PersistenceGuard<'a, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
|
&mut self.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Serialize> Drop for PersistenceGuard<'a, T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(path) = self.0.as_ref() {
|
||||||
|
let writer = match OpenOptions::new().write(true).open(path) {
|
||||||
|
Ok(writer) => writer,
|
||||||
|
Err(err) => {
|
||||||
|
slog_scope::warn!("Failed to persist {}: {}", path.display(), err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ron::ser::to_writer(writer, &self.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynamicConfig {
|
||||||
|
pub fn outputs(&self) -> &OutputsConfig {
|
||||||
|
&self.outputs.1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn outputs_mut<'a>(&'a mut self) -> PersistenceGuard<'a, OutputsConfig> {
|
||||||
|
PersistenceGuard(self.outputs.0.clone(), &mut self.outputs.1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ impl Common {
|
||||||
}
|
}
|
||||||
|
|
||||||
// here we can handle global shortcuts and the like
|
// here we can handle global shortcuts and the like
|
||||||
for (binding, action) in self.config.key_bindings.iter() {
|
for (binding, action) in self.config.static_conf.key_bindings.iter() {
|
||||||
if state == KeyState::Pressed
|
if state == KeyState::Pressed
|
||||||
&& binding.modifiers == *modifiers
|
&& binding.modifiers == *modifiers
|
||||||
&& handle.raw_syms().contains(&binding.key)
|
&& handle.raw_syms().contains(&binding.key)
|
||||||
|
|
|
||||||
133
src/shell/mod.rs
133
src/shell/mod.rs
|
|
@ -1,12 +1,16 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{config::Config, input::active_output, state::Common};
|
use crate::{
|
||||||
|
config::{Config, OutputInfo, OutputConfig},
|
||||||
|
input::active_output,
|
||||||
|
state::{BackendData, Common},
|
||||||
|
};
|
||||||
pub use smithay::{
|
pub use smithay::{
|
||||||
desktop::{PopupGrab, PopupManager, PopupUngrabStrategy, Space, Window},
|
desktop::{PopupGrab, PopupManager, PopupUngrabStrategy, Space, Window},
|
||||||
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||||
utils::{Logical, Point, Rectangle, Size},
|
utils::{Logical, Point, Rectangle, Size},
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::with_states, output::Output, seat::Seat,
|
compositor::with_states, output::{Mode as OutputMode, Output}, seat::Seat,
|
||||||
shell::xdg::XdgToplevelSurfaceRoleAttributes, Serial, SERIAL_COUNTER,
|
shell::xdg::XdgToplevelSurfaceRoleAttributes, Serial, SERIAL_COUNTER,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -73,7 +77,7 @@ impl Shell {
|
||||||
fn new(config: &Config) -> Self {
|
fn new(config: &Config) -> Self {
|
||||||
Shell {
|
Shell {
|
||||||
popups: PopupManager::new(None),
|
popups: PopupManager::new(None),
|
||||||
mode: config.workspace_mode,
|
mode: config.static_conf.workspace_mode,
|
||||||
outputs: Vec::new(),
|
outputs: Vec::new(),
|
||||||
spaces: unsafe {
|
spaces: unsafe {
|
||||||
let mut spaces = [UNINIT_SPACE; MAX_WORKSPACES];
|
let mut spaces = [UNINIT_SPACE; MAX_WORKSPACES];
|
||||||
|
|
@ -85,38 +89,103 @@ impl Shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_output(&mut self, output: &Output) {
|
fn apply_config(output: &Output, backend: &mut BackendData) -> Result<(), impl std::error::Error> {
|
||||||
match self.mode {
|
backend.apply_config_for_output(output)?;
|
||||||
Mode::OutputBound => {
|
|
||||||
output
|
|
||||||
.user_data()
|
|
||||||
.insert_if_missing(|| ActiveWorkspace::new());
|
|
||||||
|
|
||||||
let (idx, workspace) = self
|
let final_config = output.user_data().get::<RefCell<OutputConfig>>().unwrap().borrow();
|
||||||
.spaces
|
let mode = Some(OutputMode {
|
||||||
.iter_mut()
|
size: final_config.mode_size(),
|
||||||
.enumerate()
|
refresh: final_config.mode_refresh(),
|
||||||
.find(|(_, x)| x.space.outputs().next().is_none())
|
}).filter(|m| match output.current_mode() {
|
||||||
.expect("More then 10 outputs?");
|
None => true,
|
||||||
output
|
Some(c_m) => m.size != c_m.size || m.refresh != c_m.refresh,
|
||||||
.user_data()
|
});
|
||||||
.get::<ActiveWorkspace>()
|
let transform = Some(final_config.transform.into()).filter(|x| *x != output.current_transform());
|
||||||
.unwrap()
|
let scale = Some(final_config.scale.ceil() as i32).filter(|x| *x != output.current_scale());
|
||||||
.set(idx);
|
let location = Some(final_config.position.into()).filter(|x| *x != output.current_location());
|
||||||
workspace.space.map_output(output, 1.0, (0, 0));
|
output.change_current_state(
|
||||||
self.outputs.push(output.clone());
|
mode,
|
||||||
|
transform,
|
||||||
|
scale,
|
||||||
|
location,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_output(&mut self, output: &Output, backend: &mut BackendData, config: &Config) {
|
||||||
|
self.outputs.push(output.clone());
|
||||||
|
|
||||||
|
let mut infos = self.outputs().cloned().map(Into::<crate::config::OutputInfo>::into).collect::<Vec<_>>();
|
||||||
|
infos.sort();
|
||||||
|
if let Some(configs) = config.dynamic_conf.outputs().config.get(&infos) {
|
||||||
|
let mut reset = false;
|
||||||
|
let known_good_configs = self.outputs.iter().map(|output| {
|
||||||
|
output.user_data().get::<RefCell<OutputConfig>>().unwrap().borrow().clone()
|
||||||
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for (name, config) in infos.iter().map(|o| &o.connector).zip(configs.into_iter().cloned()) {
|
||||||
|
let output = self.outputs.iter().find(|o| &o.name() == name).unwrap();
|
||||||
|
*output.user_data().get::<RefCell<OutputConfig>>().unwrap().borrow_mut() = config;
|
||||||
|
if let Err(err) = Self::apply_config(output, backend) {
|
||||||
|
slog_scope::warn!("Failed to set new config for output {}: {}", output.name(), err);
|
||||||
|
reset = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Mode::Global { active } => {
|
|
||||||
// just put new outputs on the right of the previous ones.
|
if reset {
|
||||||
// in the future we will only need that as a fallback and need to read saved configurations here
|
for (output, config) in self.outputs.iter().zip(known_good_configs.into_iter()) {
|
||||||
|
*output.user_data().get::<RefCell<OutputConfig>>().unwrap().borrow_mut() = config;
|
||||||
|
if let Err(err) = Self::apply_config(output, backend) {
|
||||||
|
slog_scope::error!("Failed to reset config for output {}: {}", output.name(), err);
|
||||||
|
self.unmap_output(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Mode::Global { active } = self.mode {
|
||||||
let workspace = &mut self.spaces[active];
|
let workspace = &mut self.spaces[active];
|
||||||
let x = workspace
|
for output in self.outputs.iter() {
|
||||||
.space
|
let config = output.user_data().get::<RefCell<OutputConfig>>().unwrap().borrow();
|
||||||
.outputs()
|
workspace.space.map_output(output, config.scale, config.position);
|
||||||
.map(|output| workspace.space.output_geometry(&output).unwrap())
|
}
|
||||||
.fold(0, |acc, geo| std::cmp::max(acc, geo.loc.x + geo.size.w));
|
}
|
||||||
workspace.space.map_output(output, 1.0, (x, 0));
|
} else {
|
||||||
self.outputs.push(output.clone());
|
let new_pos_x = self.outputs().map(|o| {
|
||||||
|
let logical_size = self.active_space(o).space.output_geometry(o).map(|x| x.size).unwrap_or((0, 0).into());
|
||||||
|
o.user_data().get::<RefCell<OutputConfig>>().unwrap().borrow().position.0 + logical_size.w
|
||||||
|
}).max().unwrap_or(0);
|
||||||
|
|
||||||
|
let new_pos = (new_pos_x, 0);
|
||||||
|
output.user_data().get::<RefCell<OutputConfig>>().unwrap().borrow_mut().position = new_pos;
|
||||||
|
output.change_current_state(None, None, None, Some(new_pos.into()));
|
||||||
|
|
||||||
|
match self.mode {
|
||||||
|
Mode::OutputBound => {
|
||||||
|
output
|
||||||
|
.user_data()
|
||||||
|
.insert_if_missing(|| ActiveWorkspace::new());
|
||||||
|
|
||||||
|
let (idx, workspace) = self
|
||||||
|
.spaces
|
||||||
|
.iter_mut()
|
||||||
|
.enumerate()
|
||||||
|
.find(|(_, x)| x.space.outputs().next().is_none())
|
||||||
|
.expect("More then 10 outputs?");
|
||||||
|
output
|
||||||
|
.user_data()
|
||||||
|
.get::<ActiveWorkspace>()
|
||||||
|
.unwrap()
|
||||||
|
.set(idx);
|
||||||
|
workspace.space.map_output(output, 1.0, (0, 0));
|
||||||
|
}
|
||||||
|
Mode::Global { active } => {
|
||||||
|
// just put new outputs on the right of the previous ones.
|
||||||
|
// in the future we will only need that as a fallback and need to read saved configurations here
|
||||||
|
let workspace = &mut self.spaces[active];
|
||||||
|
workspace.space.map_output(output, 1.0, new_pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
src/state.rs
12
src/state.rs
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{kms::KmsState, winit::WinitState, x11::X11State},
|
backend::{kms::KmsState, winit::WinitState, x11::X11State},
|
||||||
config::Config,
|
config::{Config, OutputConfig},
|
||||||
logger::LogState,
|
logger::LogState,
|
||||||
shell::{init_shell, Shell},
|
shell::{init_shell, Shell},
|
||||||
};
|
};
|
||||||
|
|
@ -105,6 +105,16 @@ impl BackendData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn apply_config_for_output(&mut self, output: &Output) -> Result<(), impl std::error::Error> {
|
||||||
|
match self {
|
||||||
|
BackendData::Kms(ref mut state) => state.apply_config_for_output(output),
|
||||||
|
_ => {
|
||||||
|
// TODO: reset the mode for nested backends, because we have no control over it
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn schedule_render(&mut self, output: &Output) {
|
pub fn schedule_render(&mut self, output: &Output) {
|
||||||
match self {
|
match self {
|
||||||
BackendData::Winit(_) => {} // We cannot do this on the winit backend.
|
BackendData::Winit(_) => {} // We cannot do this on the winit backend.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue