diff --git a/default-config/src/lib.rs b/default-config/src/lib.rs index 4bc2f588..3e54ddf4 100644 --- a/default-config/src/lib.rs +++ b/default-config/src/lib.rs @@ -1,13 +1,10 @@ use jay_config::embedded::grab_input_device; use jay_config::keyboard::mods::{Modifiers, ALT, CTRL, SHIFT}; -use jay_config::keyboard::syms::{ - SYM_Super_L, SYM_b, SYM_comma, SYM_d, SYM_f, SYM_h, SYM_j, SYM_k, SYM_l, SYM_p, SYM_period, - SYM_q, SYM_r, SYM_t, SYM_v, SYM_y, -}; +use jay_config::keyboard::syms::{SYM_Super_L, SYM_b, SYM_comma, SYM_d, SYM_f, SYM_h, SYM_j, SYM_k, SYM_l, SYM_p, SYM_period, SYM_q, SYM_r, SYM_t, SYM_v, SYM_y, SYM_F1, SYM_F9, SYM_F12, SYM_F11, SYM_F10, SYM_F8, SYM_F7, SYM_F6, SYM_F5, SYM_F4, SYM_F3, SYM_F2}; use jay_config::theme::{get_title_height, set_title_color, set_title_height, Color}; use jay_config::Axis::{Horizontal, Vertical}; use jay_config::Direction::{Down, Left, Right, Up}; -use jay_config::{config, create_seat, input_devices, on_new_input_device, quit, Command, Seat}; +use jay_config::{config, create_seat, input_devices, on_new_input_device, quit, Command, Seat, switch_to_vt}; use rand::Rng; const MOD: Modifiers = ALT; @@ -71,6 +68,19 @@ fn configure_seat(s: Seat) { s.bind(MOD | SYM_q, || quit()); + s.bind(CTRL | ALT | SYM_F1, || switch_to_vt(1)); + s.bind(CTRL | ALT | SYM_F2, || switch_to_vt(2)); + s.bind(CTRL | ALT | SYM_F3, || switch_to_vt(3)); + s.bind(CTRL | ALT | SYM_F4, || switch_to_vt(4)); + s.bind(CTRL | ALT | SYM_F5, || switch_to_vt(5)); + s.bind(CTRL | ALT | SYM_F6, || switch_to_vt(6)); + s.bind(CTRL | ALT | SYM_F7, || switch_to_vt(7)); + s.bind(CTRL | ALT | SYM_F8, || switch_to_vt(8)); + s.bind(CTRL | ALT | SYM_F9, || switch_to_vt(9)); + s.bind(CTRL | ALT | SYM_F10, || switch_to_vt(10)); + s.bind(CTRL | ALT | SYM_F11, || switch_to_vt(11)); + s.bind(CTRL | ALT | SYM_F12, || switch_to_vt(12)); + fn do_grab(s: Seat, grab: bool) { for device in s.input_devices() { log::info!( diff --git a/jay-config/src/_private/client.rs b/jay-config/src/_private/client.rs index 967229ef..c81ccb5c 100644 --- a/jay-config/src/_private/client.rs +++ b/jay-config/src/_private/client.rs @@ -288,6 +288,10 @@ impl Client { self.send(&ClientMessage::Quit) } + pub fn switch_to_vt(&self, vtnr: u32) { + self.send(&ClientMessage::SwitchTo { vtnr }) + } + pub fn on_new_input_device(&self, f: F) { *self.on_new_input_device.borrow_mut() = Some(Rc::new(f)); } diff --git a/jay-config/src/_private/ipc.rs b/jay-config/src/_private/ipc.rs index 9e5afb76..6c8b3545 100644 --- a/jay-config/src/_private/ipc.rs +++ b/jay-config/src/_private/ipc.rs @@ -36,6 +36,9 @@ pub enum ClientMessage<'a> { name: &'a str, }, Quit, + SwitchTo { + vtnr: u32, + }, SetSeat { device: InputDevice, seat: Seat, diff --git a/jay-config/src/lib.rs b/jay-config/src/lib.rs index 7fc82139..423dd83e 100644 --- a/jay-config/src/lib.rs +++ b/jay-config/src/lib.rs @@ -165,6 +165,10 @@ pub fn quit() { get!().quit() } +pub fn switch_to_vt(n: u32) { + get!().switch_to_vt(n) +} + pub struct Command { prog: String, args: Vec, diff --git a/src/backend.rs b/src/backend.rs index 3d86b32d..0a41b935 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -5,7 +5,9 @@ use std::rc::Rc; linear_ids!(OutputIds, OutputId); linear_ids!(InputDeviceIds, InputDeviceId); -pub trait Backend {} +pub trait Backend { + fn switch_to(&self, vtnr: u32); +} pub trait Output { fn id(&self) -> OutputId; diff --git a/src/backends/metal.rs b/src/backends/metal.rs index 7d0cd2ae..57382d90 100644 --- a/src/backends/metal.rs +++ b/src/backends/metal.rs @@ -15,7 +15,7 @@ use crate::udev::{UdevError, UdevMonitor}; use crate::utils::copyhashmap::CopyHashMap; use crate::utils::oserror::OsError; use crate::utils::syncqueue::SyncQueue; -use crate::{AsyncError, CloneCell, RenderError, State, Udev}; +use crate::{AsyncError, CloneCell, ErrorFmt, RenderError, State, Udev}; use std::cell::{Cell, RefCell}; use std::ffi::{CStr, CString}; use std::future::pending; @@ -96,7 +96,15 @@ struct MetalBackend { drm_ids: DrmIds, } -impl Backend for MetalBackend {} +impl Backend for MetalBackend { + fn switch_to(&self, vtnr: u32) { + self.session.switch_to(vtnr, move |res| { + if let Err(e) = res { + log::error!("Could not switch to VT {}: {}", vtnr, ErrorFmt(e)); + } + }) + } +} async fn run_(state: Rc) -> Result<(), MetalError> { let socket = match state.dbus.system() { @@ -160,6 +168,7 @@ async fn run_(state: Rc) -> Result<(), MetalError> { if let Err(e) = metal.enumerate_devices() { return Err(MetalError::Enumerate(Box::new(e))); } + state.backend.set(Some(metal.clone())); pending().await } diff --git a/src/backends/xorg.rs b/src/backends/xorg.rs index f95525b5..d94bf66a 100644 --- a/src/backends/xorg.rs +++ b/src/backends/xorg.rs @@ -220,7 +220,11 @@ pub struct XorgBackend { b: Cell, } -impl Backend for XorgBackend {} +impl Backend for XorgBackend { + fn switch_to(&self, _vtnr: u32) { + log::error!("Xorg backend cannot switch vts"); + } +} fn get_drm(con: &XcbCon) -> Result { unsafe { diff --git a/src/config/handler.rs b/src/config/handler.rs index 2b2c93dc..35d6eca5 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -337,6 +337,13 @@ impl ConfigProxyHandler { self.state.el.stop(); } + fn handle_switch_to(&self, vtnr: u32) { + match self.state.backend.get() { + Some(b) => b.switch_to(vtnr), + _ => log::warn!("Cannot switch to VT {}: Backend has not yet started", vtnr), + } + } + fn handle_toggle_floating(&self, seat: Seat) -> Result<(), FocusParentError> { let seat = self.get_seat(seat)?; seat.toggle_floating(); @@ -472,6 +479,7 @@ impl ConfigProxyHandler { ClientMessage::FocusParent { seat } => self.handle_focus_parent(seat)?, ClientMessage::ToggleFloating { seat } => self.handle_toggle_floating(seat)?, ClientMessage::Quit => self.handle_quit(), + ClientMessage::SwitchTo { vtnr } => self.handle_switch_to(vtnr), } Ok(()) } diff --git a/src/logind.rs b/src/logind.rs index d8002852..d571936f 100644 --- a/src/logind.rs +++ b/src/logind.rs @@ -4,6 +4,7 @@ use crate::{org, FALSE}; use std::rc::Rc; use thiserror::Error; use uapi::c; +use crate::org::freedesktop::login1::seat::SwitchToReply; const LOGIND_NAME: &str = "org.freedesktop.login1"; const MANAGER_PATH: &str = "/org/freedesktop/login1"; @@ -22,7 +23,7 @@ pub enum LogindError { pub struct Session { socket: Rc, - _seat: String, + seat: String, session_path: String, } @@ -52,13 +53,13 @@ impl Session { .get_async::(LOGIND_NAME, &session_path) .await; match seat { - Ok(s) => s.get().0.to_string(), + Ok(s) => s.get().1.0.to_string(), Err(e) => return Err(LogindError::GetSeatName(e)), } }; Ok(Self { socket: socket.clone(), - _seat: seat, + seat, session_path, }) } @@ -123,4 +124,15 @@ impl Session { org::freedesktop::login1::session::PauseDeviceComplete { major, minor }, ); } + + pub fn switch_to(&self, vtnr: u32, f: F) + where F: FnOnce(Result<&SwitchToReply, DbusError>) + 'static + { + self.socket.call( + LOGIND_NAME, + &self.seat, + org::freedesktop::login1::seat::SwitchTo { vtnr }, + |r| f(r), + ); + } } diff --git a/src/main.rs b/src/main.rs index b3efdd06..44acd41a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -150,6 +150,7 @@ fn main_() -> Result<(), MainError> { let node_ids = NodeIds::default(); let state = Rc::new(State { xkb_ctx, + backend: Default::default(), forker: Default::default(), default_keymap: xkb_keymap, eng: engine.clone(), diff --git a/src/state.rs b/src/state.rs index 0339678a..a18cc2f0 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,7 +1,5 @@ use crate::async_engine::{AsyncEngine, SpawnedFuture}; -use crate::backend::{ - BackendEvent, InputDevice, InputDeviceId, InputDeviceIds, OutputId, OutputIds, -}; +use crate::backend::{Backend, BackendEvent, InputDevice, InputDeviceId, InputDeviceIds, OutputId, OutputIds}; use crate::client::{Client, Clients}; use crate::config::ConfigProxy; use crate::cursor::ServerCursors; @@ -33,6 +31,7 @@ use std::sync::Arc; pub struct State { pub xkb_ctx: XkbContext, + pub backend: CloneCell>>, pub forker: CloneCell>>, pub default_keymap: Rc, pub eng: Rc, diff --git a/src/tasks/start_backend.rs b/src/tasks/start_backend.rs index f4e1162e..bcc3c5c3 100644 --- a/src/tasks/start_backend.rs +++ b/src/tasks/start_backend.rs @@ -5,7 +5,10 @@ use std::rc::Rc; pub async fn start_backend(state: Rc) { log::info!("Trying to start X backend"); let e = match XorgBackend::new(&state) { - Ok(_b) => pending().await, + Ok(b) => { + state.backend.set(Some(b)); + pending().await + }, Err(e) => e, }; log::warn!("Could not start X backend: {}", ErrorFmt(e)); diff --git a/wire-dbus/org.freedesktop.login1.Seat.txt b/wire-dbus/org.freedesktop.login1.Seat.txt new file mode 100644 index 00000000..112abbca --- /dev/null +++ b/wire-dbus/org.freedesktop.login1.Seat.txt @@ -0,0 +1,2 @@ +fn SwitchTo(vtnr: u32) { +}