Work on focus mechanism

This commit is contained in:
Seaotatop 2023-06-17 21:02:58 -05:00
parent d1bfb48885
commit 3ea2452397
44 changed files with 124 additions and 87 deletions

View file

@ -4,10 +4,8 @@ local M = {}
---@param client_id integer? The id of the window you want closed, or nil to close the currently focused window, if any. ---@param client_id integer? The id of the window you want closed, or nil to close the currently focused window, if any.
function M.close_window(client_id) function M.close_window(client_id)
SendMsg({ SendMsg({
Action = { CloseWindow = {
CloseWindow = { client_id = client_id or "nil",
client_id = client_id or "nil",
},
}, },
}) })
end end

View file

@ -83,7 +83,6 @@ while true do
assert(msg_bytes) assert(msg_bytes)
local tb = msgpack.decode(msg_bytes) local tb = msgpack.decode(msg_bytes)
print(tb)
if tb.CallCallback then if tb.CallCallback then
CallbackTable[tb.CallCallback]() CallbackTable[tb.CallCallback]()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -2,7 +2,7 @@ pub mod msg;
use std::{ use std::{
io::{self, Read, Write}, io::{self, Read, Write},
os::unix::net::{UnixDatagram, UnixListener, UnixStream}, os::unix::net::{UnixListener, UnixStream},
path::Path, path::Path,
}; };

View file

@ -11,12 +11,9 @@ pub enum Msg {
SetMousebind { SetMousebind {
button: u8, button: u8,
}, },
// Action(Action), CloseWindow {
} client_id: Option<u32>,
},
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub enum Action {
CloseWindow { client_id: Option<u32> },
} }
#[derive(Debug, serde::Serialize, serde::Deserialize)] #[derive(Debug, serde::Serialize, serde::Deserialize)]
@ -42,7 +39,7 @@ impl<T: IntoIterator<Item = Modifiers>> From<T> for ModifierMask {
} }
} }
/// Messages sent from the server to each client. /// Messages sent from the server to the client.
#[derive(Debug, serde::Serialize, serde::Deserialize)] #[derive(Debug, serde::Serialize, serde::Deserialize)]
pub enum OutgoingMsg { pub enum OutgoingMsg {
CallCallback(u32), CallCallback(u32),

View file

@ -1,8 +1,4 @@
use smithay::{ use smithay::{output::Output, reexports::wayland_server::protocol::wl_surface::WlSurface};
backend::input::{InputBackend, InputEvent},
output::Output,
reexports::wayland_server::protocol::wl_surface::WlSurface,
};
pub mod udev; pub mod udev;
pub mod winit; pub mod winit;

View file

@ -3,7 +3,7 @@ use std::{
error::Error, error::Error,
os::fd::FromRawFd, os::fd::FromRawFd,
path::Path, path::Path,
sync::{atomic::Ordering, Mutex}, sync::Mutex,
time::Duration, time::Duration,
}; };
@ -67,9 +67,7 @@ use smithay::{
presentation_time::server::wp_presentation_feedback, presentation_time::server::wp_presentation_feedback,
}, },
wayland_server::{ wayland_server::{
backend::GlobalId, backend::GlobalId, protocol::wl_surface::WlSurface, Display, DisplayHandle,
protocol::wl_surface::{self, WlSurface},
Display, DisplayHandle,
}, },
}, },
utils::{Clock, DeviceFd, IsAlive, Logical, Monotonic, Point, Scale, Transform}, utils::{Clock, DeviceFd, IsAlive, Logical, Monotonic, Point, Scale, Transform},

48
src/focus.rs Normal file
View file

@ -0,0 +1,48 @@
use smithay::{
desktop::Window,
utils::{IsAlive, Serial},
};
use crate::{backend::Backend, state::State};
#[derive(Default)]
pub struct FocusState {
focus_stack: Vec<Window>,
}
impl FocusState {
pub fn new() -> Self {
Default::default()
}
pub fn current_focus(&mut self) -> Option<Window> {
while let Some(window) = self.focus_stack.last() {
if window.alive() {
return Some(window.clone());
}
self.focus_stack.pop();
}
None
}
pub fn set_focus(&mut self, window: Window) {
self.focus_stack.retain(|win| win != &window);
self.focus_stack.push(window);
}
}
impl<B: Backend> State<B> {
pub fn set_focus(&mut self, window: Window, serial: Serial) {
// INFO: this is inserted into the loop because foot didn't like it when you set the focus
// |` immediately after creating the toplevel
// TODO: figure out why
self.loop_handle.insert_idle(move |data| {
data.state.focus_state.set_focus(window.clone());
data.state.seat.get_keyboard().unwrap().set_focus(
&mut data.state,
Some(window.toplevel().wl_surface().clone()),
serial,
);
});
}
}

View file

@ -40,6 +40,7 @@ impl<B: Backend> PointerGrab<State<B>> for MoveSurfaceGrab<State<B>> {
let new_loc = self.initial_window_loc.to_f64() + delta; let new_loc = self.initial_window_loc.to_f64() + delta;
data.space data.space
.map_element(self.window.clone(), new_loc.to_i32_round(), true); .map_element(self.window.clone(), new_loc.to_i32_round(), true);
data.focus_state.set_focus(self.window.clone());
} }
fn relative_motion( fn relative_motion(

View file

@ -1,5 +1,5 @@
use smithay::{ use smithay::{
desktop::{Space, Window}, desktop::Window,
input::{ input::{
pointer::{AxisFrame, ButtonEvent, GrabStartData, PointerGrab, PointerInnerHandle}, pointer::{AxisFrame, ButtonEvent, GrabStartData, PointerGrab, PointerInnerHandle},
SeatHandler, SeatHandler,

View file

@ -4,8 +4,8 @@ use smithay::{
delegate_presentation, delegate_relative_pointer, delegate_seat, delegate_shm, delegate_presentation, delegate_relative_pointer, delegate_seat, delegate_shm,
delegate_viewporter, delegate_xdg_shell, delegate_viewporter, delegate_xdg_shell,
desktop::{ desktop::{
find_popup_root_surface, PopupKeyboardGrab, PopupKind, PopupManager, PopupPointerGrab, find_popup_root_surface, PopupKeyboardGrab, PopupKind, PopupPointerGrab,
PopupUngrabStrategy, Space, Window, PopupUngrabStrategy, Window,
}, },
input::{ input::{
pointer::{CursorImageStatus, Focus}, pointer::{CursorImageStatus, Focus},
@ -19,7 +19,7 @@ use smithay::{
Client, Resource, Client, Resource,
}, },
}, },
utils::Serial, utils::{Serial, SERIAL_COUNTER},
wayland::{ wayland::{
buffer::BufferHandler, buffer::BufferHandler,
compositor::{ compositor::{
@ -32,8 +32,8 @@ use smithay::{
dmabuf, dmabuf,
fractional_scale::{self, FractionalScaleHandler}, fractional_scale::{self, FractionalScaleHandler},
shell::xdg::{ shell::xdg::{
Configure, PopupSurface, PositionerState, ToplevelSurface, XdgPopupSurfaceData, PopupSurface, PositionerState, ToplevelSurface, XdgPopupSurfaceData, XdgShellHandler,
XdgShellHandler, XdgShellState, XdgToplevelSurfaceData, XdgShellState, XdgToplevelSurfaceData,
}, },
shm::{ShmHandler, ShmState}, shm::{ShmHandler, ShmState},
}, },
@ -112,6 +112,7 @@ impl<B: Backend> CompositorHandler for State<B> {
} }
} }
delegate_compositor!(@<B: Backend> State<B>); delegate_compositor!(@<B: Backend> State<B>);
fn ensure_initial_configure<B: Backend>(surface: &WlSurface, state: &mut State<B>) { fn ensure_initial_configure<B: Backend>(surface: &WlSurface, state: &mut State<B>) {
if let Some(window) = state.window_for_surface(surface) { if let Some(window) = state.window_for_surface(surface) {
let initial_configure_sent = compositor::with_states(surface, |states| { let initial_configure_sent = compositor::with_states(surface, |states| {
@ -194,15 +195,25 @@ impl<B: Backend> XdgShellHandler for State<B> {
fn new_toplevel(&mut self, surface: ToplevelSurface) { fn new_toplevel(&mut self, surface: ToplevelSurface) {
let window = Window::new(surface); let window = Window::new(surface);
self.space.map_element(window, (0, 0), true); self.space.map_element(window.clone(), (0, 0), true);
self.set_focus(window, SERIAL_COUNTER.next_serial());
let windows: Vec<Window> = self.space.elements().cloned().collect(); let windows: Vec<Window> = self.space.elements().cloned().collect();
Layout::master_stack(self, windows, crate::layout::Direction::Left); Layout::master_stack(self, windows, crate::layout::Direction::Left);
} }
fn toplevel_destroyed(&mut self, surface: ToplevelSurface) { fn toplevel_destroyed(&mut self, surface: ToplevelSurface) {
let windows: Vec<Window> = self.space.elements().cloned().collect(); let mut windows: Vec<Window> = self.space.elements().cloned().collect();
windows.retain(|window| window.toplevel() != &surface);
Layout::master_stack(self, windows, crate::layout::Direction::Left); Layout::master_stack(self, windows, crate::layout::Direction::Left);
let focus = self
.focus_state
.current_focus()
.map(|win| win.toplevel().wl_surface().clone());
self.seat
.get_keyboard()
.unwrap()
.set_focus(self, focus, SERIAL_COUNTER.next_serial());
} }
fn new_popup(&mut self, surface: PopupSurface, positioner: PositionerState) { fn new_popup(&mut self, surface: PopupSurface, positioner: PositionerState) {
@ -291,10 +302,6 @@ impl<B: Backend> XdgShellHandler for State<B> {
} }
} }
fn ack_configure(&mut self, surface: WlSurface, configure: Configure) {
// println!("surface ack_configure: {:?}", configure);
}
// TODO: impl the rest of the fns in XdgShellHandler // TODO: impl the rest of the fns in XdgShellHandler
} }
delegate_xdg_shell!(@<B: Backend> State<B>); delegate_xdg_shell!(@<B: Backend> State<B>);

View file

@ -9,7 +9,7 @@ use smithay::{
desktop::{Window, WindowSurfaceType}, desktop::{Window, WindowSurfaceType},
input::{ input::{
keyboard::{keysyms, FilterResult}, keyboard::{keysyms, FilterResult},
pointer::{AxisFrame, ButtonEvent, MotionEvent, RelativeMotionEvent}, pointer::{AxisFrame, ButtonEvent, MotionEvent},
}, },
reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::ResizeEdge, reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::ResizeEdge,
utils::{Logical, Point, SERIAL_COUNTER}, utils::{Logical, Point, SERIAL_COUNTER},
@ -21,8 +21,18 @@ use crate::{
state::State, state::State,
}; };
#[derive(Default)]
pub struct InputState { pub struct InputState {
/// A hashmap of modifier keys and keycodes to callback IDs
pub keybinds: HashMap<(ModifierMask, u32), u32>, pub keybinds: HashMap<(ModifierMask, u32), u32>,
/// A hashmap of modifier keys and mouse button codes to callback IDs
pub mousebinds: HashMap<(ModifierMask, u32), u32>,
}
impl InputState {
pub fn new() -> Self {
Default::default()
}
} }
impl<B: Backend> State<B> { impl<B: Backend> State<B> {
@ -121,8 +131,8 @@ impl<B: Backend> State<B> {
// Move window to top of stack. // Move window to top of stack.
self.space.raise_element(&window, true); self.space.raise_element(&window, true);
// Focus on window. self.set_focus(window, serial);
keyboard.set_focus(self, Some(window.toplevel().wl_surface().clone()), serial);
self.space.elements().for_each(|window| { self.space.elements().for_each(|window| {
window.toplevel().send_configure(); window.toplevel().send_configure();
}); });

View file

@ -1,9 +1,3 @@
use std::{error::Error, fmt::Display};
use smithay::desktop::Window;
use crate::{backend::Backend, state::State};
pub mod automatic; pub mod automatic;
pub mod manual; pub mod manual;

View file

@ -73,6 +73,7 @@ impl Layout {
// INFO: We send configures when the event loop is idle so // INFO: We send configures when the event loop is idle so
// | CompositorHandler::commit() sends the initial configure // | CompositorHandler::commit() sends the initial configure
// TODO: maybe check if the initial configure was sent instead?
state.loop_handle.insert_idle(|_calloop_data| { state.loop_handle.insert_idle(|_calloop_data| {
for win in windows { for win in windows {
win.toplevel().send_pending_configure(); win.toplevel().send_pending_configure();

View file

@ -1,6 +1,7 @@
mod api; mod api;
mod backend; mod backend;
mod cursor; mod cursor;
mod focus;
mod grab; mod grab;
mod handlers; mod handlers;
mod input; mod input;

View file

@ -1,11 +1,13 @@
use std::{ use std::{
collections::HashMap,
error::Error, error::Error,
os::{fd::AsRawFd, unix::net::UnixStream}, os::{fd::AsRawFd, unix::net::UnixStream},
sync::Arc, sync::Arc,
}; };
use crate::api::{msg::Msg, PinnacleSocketSource}; use crate::{
api::{msg::Msg, PinnacleSocketSource},
focus::FocusState,
};
use smithay::{ use smithay::{
backend::renderer::element::RenderElementStates, backend::renderer::element::RenderElementStates,
desktop::{ desktop::{
@ -28,7 +30,7 @@ use smithay::{
Display, Display,
}, },
}, },
utils::{Clock, Logical, Monotonic, Point}, utils::{Clock, IsAlive, Logical, Monotonic, Point},
wayland::{ wayland::{
compositor::{CompositorClientState, CompositorState}, compositor::{CompositorClientState, CompositorState},
data_device::DataDeviceState, data_device::DataDeviceState,
@ -68,6 +70,7 @@ pub struct State<B: Backend> {
pub fractional_scale_manager_state: FractionalScaleManagerState, pub fractional_scale_manager_state: FractionalScaleManagerState,
pub input_state: InputState, pub input_state: InputState,
pub api_state: ApiState, pub api_state: ApiState,
pub focus_state: FocusState,
pub popup_manager: PopupManager, pub popup_manager: PopupManager,
@ -122,41 +125,31 @@ impl<B: Backend> State<B> {
.insert((modifiers.into(), key), callback_id); .insert((modifiers.into(), key), callback_id);
} }
Msg::SetMousebind { button } => todo!(), Msg::SetMousebind { button } => todo!(),
Msg::CloseWindow { client_id } => {
tracing::info!("CloseWindow {:?}", client_id);
if let Some(window) = data
.state
.seat
.get_keyboard()
.unwrap()
.current_focus()
.and_then(|wl_surface| data.state.window_for_surface(&wl_surface))
{
window.toplevel().send_close();
}
}
}; };
} }
Event::Closed => todo!(), Event::Closed => todo!(),
})?; })?;
// std::thread::spawn(move || { // We want to replace the client id a new one pops up
// crate::api::init_api_socket(tx_channel).unwrap(); // INFO: this source try_clone()s the stream
// });
loop_handle.insert_source(PinnacleSocketSource::new(tx_channel)?, |stream, _, data| { loop_handle.insert_source(PinnacleSocketSource::new(tx_channel)?, |stream, _, data| {
if let Some(old_stream) = data.state.api_state.stream.replace(stream) { if let Some(old_stream) = data.state.api_state.stream.replace(stream) {
old_stream.shutdown(std::net::Shutdown::Both).unwrap(); old_stream.shutdown(std::net::Shutdown::Both).unwrap();
} }
})?; })?;
// data.state
// .loop_handle
// .insert_source(PinnacleStreamSource::new(stream), |msg, _, data| {
// // TODO: do stuff with msg
// match msg {
// Msg::SetKeybind {
// key,
// modifiers,
// callback_id,
// } => {
// tracing::info!("set keybind: {:?}, {}", modifiers, key);
// data.state
// .input_state
// .keybinds
// .insert((modifiers.into(), key), callback_id);
// }
// Msg::SetMousebind { button } => todo!(),
// };
// })
// .unwrap();
// })?;
let display_handle = display.handle(); let display_handle = display.handle();
let mut seat_state = SeatState::new(); let mut seat_state = SeatState::new();
@ -182,10 +175,9 @@ impl<B: Backend> State<B> {
fractional_scale_manager_state: FractionalScaleManagerState::new::<Self>( fractional_scale_manager_state: FractionalScaleManagerState::new::<Self>(
&display_handle, &display_handle,
), ),
input_state: InputState { input_state: InputState::new(),
keybinds: HashMap::new(), api_state: ApiState::new(),
}, focus_state: FocusState::new(),
api_state: ApiState { stream: None },
seat, seat,
@ -203,18 +195,6 @@ impl<B: Backend> State<B> {
.find(|window| window.wl_surface().map(|s| s == *surface).unwrap_or(false)) .find(|window| window.wl_surface().map(|s| s == *surface).unwrap_or(false))
.cloned() .cloned()
} }
// TODO:
pub fn handle_msg(msg: Msg) {
match msg {
Msg::SetKeybind {
key,
modifiers,
callback_id,
} => todo!(),
Msg::SetMousebind { button } => todo!(),
}
}
} }
pub struct CalloopData<B: Backend> { pub struct CalloopData<B: Backend> {
@ -272,6 +252,13 @@ pub fn take_presentation_feedback(
output_presentation_feedback output_presentation_feedback
} }
#[derive(Default)]
pub struct ApiState { pub struct ApiState {
pub stream: Option<UnixStream>, pub stream: Option<UnixStream>,
} }
impl ApiState {
pub fn new() -> Self {
Default::default()
}
}