Merge pull request #50 from Ottatop/vt

Add vt switching
This commit is contained in:
Ottatop 2023-08-08 12:58:07 -05:00 committed by GitHub
commit 34d643aae6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 123 additions and 102 deletions

View file

@ -59,14 +59,14 @@ So, this is my attempt at making an Awesome-esque Wayland compositor.
## Dependencies ## Dependencies
You'll need the following packages, as specified by [Smithay](https://github.com/Smithay/smithay): You'll need the following packages, as specified by [Smithay](https://github.com/Smithay/smithay):
`libwayland libxkbcommon libudev libinput libgdm libseat` `libwayland libxkbcommon libudev libinput libgdm libseat`, as well as `xwayland`.
- Arch: - Arch:
``` ```
sudo pacman -S wayland wayland-protocols libxkbcommon systemd-libs libinput mesa seatd sudo pacman -S wayland wayland-protocols libxkbcommon systemd-libs libinput mesa seatda xwayland
``` ```
- Debian: - Debian:
``` ```
sudo apt install libwayland-dev libxkbcommon-dev libudev-dev libinput-dev libgdm-dev libseat-dev sudo apt install libwayland-dev libxkbcommon-dev libudev-dev libinput-dev libgdm-dev libseat-dev xwayland
``` ```
- NixOS: Use the provided [`shell.nix`](shell.nix). - NixOS: Use the provided [`shell.nix`](shell.nix).
- TODO: other distros. - TODO: other distros.

View file

@ -122,7 +122,7 @@ struct UdevOutputId {
} }
pub struct UdevData { pub struct UdevData {
session: LibSeatSession, pub session: LibSeatSession,
display_handle: DisplayHandle, display_handle: DisplayHandle,
dmabuf_state: Option<(DmabufState, DmabufGlobal)>, dmabuf_state: Option<(DmabufState, DmabufGlobal)>,
primary_gpu: DrmNode, primary_gpu: DrmNode,
@ -303,7 +303,7 @@ pub fn run_udev() -> Result<(), Box<dyn Error>> {
libinput_context.suspend(); libinput_context.suspend();
tracing::info!("pausing session"); tracing::info!("pausing session");
for backend in data.state.backend_data.backends.values() { for backend in data.state.backend_data.backends.values_mut() {
backend.drm.pause(); backend.drm.pause();
} }
} }
@ -1076,9 +1076,7 @@ impl State<UdevData> {
} }
fn device_removed(&mut self, node: DrmNode) { fn device_removed(&mut self, node: DrmNode) {
let device = if let Some(device) = self.backend_data.backends.get_mut(&node) { let Some(device) = self.backend_data.backends.get_mut(&node) else {
device
} else {
return; return;
}; };
@ -1291,15 +1289,11 @@ impl State<UdevData> {
} }
fn render_surface(&mut self, node: DrmNode, crtc: crtc::Handle) { fn render_surface(&mut self, node: DrmNode, crtc: crtc::Handle) {
let device = if let Some(device) = self.backend_data.backends.get_mut(&node) { let Some(device) = self.backend_data.backends.get_mut(&node) else {
device
} else {
return; return;
}; };
let surface = if let Some(surface) = device.surfaces.get_mut(&crtc) { let Some(surface) = device.surfaces.get_mut(&crtc) else {
surface
} else {
return; return;
}; };
@ -1584,7 +1578,7 @@ fn render_surface<'a>(
let time = clock.now(); let time = clock.now();
// We need to send frames to the cursor surface so that xwayland windows will properly // We need to send frames to the cursor surface so that xwayland windows will properly
// update on motion. // update the cursor on motion.
if let CursorImageStatus::Surface(surf) = cursor_status { if let CursorImageStatus::Surface(surf) = cursor_status {
send_frames_surface_tree(surf, output, time, Some(Duration::ZERO), |_, _| None); send_frames_surface_tree(surf, output, time, Some(Duration::ZERO), |_, _| None);
} }

View file

@ -8,9 +8,12 @@ use crate::{
window::WindowElement, window::WindowElement,
}; };
use smithay::{ use smithay::{
backend::input::{ backend::{
AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputBackend, InputEvent, input::{
KeyState, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, PointerMotionEvent, AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputBackend, InputEvent,
KeyState, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, PointerMotionEvent,
},
session::Session,
}, },
desktop::{layer_map_for_output, space::SpaceElement}, desktop::{layer_map_for_output, space::SpaceElement},
input::{ input::{
@ -41,6 +44,13 @@ impl InputState {
} }
} }
#[derive(Debug)]
enum KeyAction {
CallCallback(CallbackId),
Quit,
SwitchVt(i32),
}
impl<B: Backend> State<B> { impl<B: Backend> State<B> {
pub fn surface_under<P>(&self, point: P) -> Option<(FocusTarget, Point<i32, Logical>)> pub fn surface_under<P>(&self, point: P) -> Option<(FocusTarget, Point<i32, Logical>)>
where where
@ -87,6 +97,107 @@ impl<B: Backend> State<B> {
}) })
} }
fn keyboard<I: InputBackend>(&mut self, event: I::KeyboardKeyEvent) {
let serial = SERIAL_COUNTER.next_serial();
let time = event.time_msec();
let press_state = event.state();
let mut move_mode = false;
let action = self
.seat
.get_keyboard()
.expect("Seat has no keyboard") // FIXME: handle err
.input(
self,
event.key_code(),
press_state,
serial,
time,
|state, modifiers, keysym| {
if press_state == KeyState::Pressed {
let mut modifier_mask = Vec::<Modifier>::new();
if modifiers.alt {
modifier_mask.push(Modifier::Alt);
}
if modifiers.shift {
modifier_mask.push(Modifier::Shift);
}
if modifiers.ctrl {
modifier_mask.push(Modifier::Ctrl);
}
if modifiers.logo {
modifier_mask.push(Modifier::Super);
}
let raw_sym = if keysym.raw_syms().len() == 1 {
keysym.raw_syms()[0]
} else {
keysyms::KEY_NoSymbol
};
if let Some(callback_id) = state
.input_state
.keybinds
.get(&(modifier_mask.into(), raw_sym))
{
return FilterResult::Intercept(KeyAction::CallCallback(*callback_id));
} else if modifiers.ctrl
&& modifiers.shift
&& modifiers.alt
&& keysym.modified_sym() == keysyms::KEY_Escape
{
return FilterResult::Intercept(KeyAction::Quit);
} else if let mut vt @ keysyms::KEY_XF86Switch_VT_1..=keysyms::KEY_XF86Switch_VT_12 =
keysym.modified_sym() {
vt = vt - keysyms::KEY_XF86Switch_VT_1 + 1;
tracing::info!("Switching to vt {vt}");
return FilterResult::Intercept(KeyAction::SwitchVt(vt as i32));
}
}
if keysym.modified_sym() == keysyms::KEY_Control_L {
match press_state {
KeyState::Pressed => {
move_mode = true;
}
KeyState::Released => {
move_mode = false;
}
}
}
FilterResult::Forward
},
);
self.move_mode = move_mode;
match action {
Some(KeyAction::CallCallback(callback_id)) => {
if let Some(stream) = self.api_state.stream.as_ref() {
if let Err(err) = crate::api::send_to_client(
&mut stream.lock().expect("Could not lock stream mutex"),
&OutgoingMsg::CallCallback {
callback_id,
args: None,
},
) {
tracing::error!("error sending msg to client: {err}");
}
}
}
Some(KeyAction::SwitchVt(vt)) => {
if let Some(st) = (self as &mut dyn std::any::Any).downcast_mut::<State<UdevData>>()
{
if let Err(err) = st.backend_data.session.change_vt(vt) {
tracing::error!("Failed to switch to vt {vt}: {err}");
}
}
}
Some(KeyAction::Quit) => {
self.loop_signal.stop();
}
_ => {}
}
}
fn pointer_button<I: InputBackend>(&mut self, event: I::PointerButtonEvent) { fn pointer_button<I: InputBackend>(&mut self, event: I::PointerButtonEvent) {
let pointer = self.seat.get_pointer().expect("Seat has no pointer"); // FIXME: handle err let pointer = self.seat.get_pointer().expect("Seat has no pointer"); // FIXME: handle err
let keyboard = self.seat.get_keyboard().expect("Seat has no keyboard"); // FIXME: handle err let keyboard = self.seat.get_keyboard().expect("Seat has no keyboard"); // FIXME: handle err
@ -303,90 +414,6 @@ impl<B: Backend> State<B> {
.expect("Seat has no pointer") .expect("Seat has no pointer")
.axis(self, frame); .axis(self, frame);
} }
fn keyboard<I: InputBackend>(&mut self, event: I::KeyboardKeyEvent) {
let serial = SERIAL_COUNTER.next_serial();
let time = event.time_msec();
let press_state = event.state();
let mut move_mode = false;
let action = self
.seat
.get_keyboard()
.expect("Seat has no keyboard") // FIXME: handle err
.input(
self,
event.key_code(),
press_state,
serial,
time,
|state, modifiers, keysym| {
if press_state == KeyState::Pressed {
let mut modifier_mask = Vec::<Modifier>::new();
if modifiers.alt {
modifier_mask.push(Modifier::Alt);
}
if modifiers.shift {
modifier_mask.push(Modifier::Shift);
}
if modifiers.ctrl {
modifier_mask.push(Modifier::Ctrl);
}
if modifiers.logo {
modifier_mask.push(Modifier::Super);
}
let raw_sym = if keysym.raw_syms().len() == 1 {
keysym.raw_syms()[0]
} else {
keysyms::KEY_NoSymbol
};
if let Some(callback_id) = state
.input_state
.keybinds
.get(&(modifier_mask.into(), raw_sym))
{
return FilterResult::Intercept(*callback_id);
} else if modifiers.ctrl
&& modifiers.shift
&& modifiers.alt
&& keysym.modified_sym() == keysyms::KEY_Escape
{
return FilterResult::Intercept(CallbackId(999999));
}
}
if keysym.modified_sym() == keysyms::KEY_Control_L {
match press_state {
KeyState::Pressed => {
move_mode = true;
}
KeyState::Released => {
move_mode = false;
}
}
}
FilterResult::Forward
},
);
self.move_mode = move_mode;
if let Some(callback_id) = action {
if callback_id.0 == 999999 {
self.loop_signal.stop();
}
if let Some(stream) = self.api_state.stream.as_ref() {
if let Err(err) = crate::api::send_to_client(
&mut stream.lock().expect("Could not lock stream mutex"),
&OutgoingMsg::CallCallback {
callback_id,
args: None,
},
) {
tracing::warn!("error sending msg to client: {err}");
}
}
}
}
} }
impl State<WinitData> { impl State<WinitData> {