mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-26 21:58:10 +01:00
Merge pull request #168 from pinnacle-comp/update_smithay_but_not_in_a_single_900_line_commit
Update Smithay but not in a single 900 line commit
This commit is contained in:
commit
8d2c5d4dcb
18 changed files with 1066 additions and 1186 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -831,9 +831,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gbm"
|
name = "gbm"
|
||||||
version = "0.14.1"
|
version = "0.14.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f177420f6650dcd50042121adf7ff7ab265abdaf4862fe2624066e36e3a9ef34"
|
checksum = "313702b30cdeb83ddc72bc14dcee67803cd0ae2d12282ea06e368c25a900c844"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"drm",
|
"drm",
|
||||||
|
@ -2053,7 +2053,7 @@ checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay"
|
name = "smithay"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/Smithay/smithay?rev=1074914#1074914492783b25a4c2c49ce49a126d39994596"
|
source = "git+https://github.com/Smithay/smithay?rev=418190e#418190e4992ce642e6bac873307d4fc4fa9a1e89"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"appendlist",
|
"appendlist",
|
||||||
"ash",
|
"ash",
|
||||||
|
@ -2128,7 +2128,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay-drm-extras"
|
name = "smithay-drm-extras"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/Smithay/smithay?rev=1074914#1074914492783b25a4c2c49ce49a126d39994596"
|
source = "git+https://github.com/Smithay/smithay?rev=418190e#418190e4992ce642e6bac873307d4fc4fa9a1e89"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"drm",
|
"drm",
|
||||||
"edid-rs",
|
"edid-rs",
|
||||||
|
|
|
@ -34,8 +34,8 @@ repository.workspace = true
|
||||||
keywords = ["wayland", "compositor", "smithay", "lua"]
|
keywords = ["wayland", "compositor", "smithay", "lua"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
smithay = { git = "https://github.com/Smithay/smithay", rev = "1074914", default-features = false, features = ["desktop", "wayland_frontend"] }
|
smithay = { git = "https://github.com/Smithay/smithay", rev = "418190e", default-features = false, features = ["desktop", "wayland_frontend"] }
|
||||||
smithay-drm-extras = { git = "https://github.com/Smithay/smithay", rev = "1074914" }
|
smithay-drm-extras = { git = "https://github.com/Smithay/smithay", rev = "418190e" }
|
||||||
|
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "registry"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "registry"] }
|
||||||
|
|
114
src/api.rs
114
src/api.rs
|
@ -34,11 +34,11 @@ use pinnacle_api_defs::pinnacle::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::space::SpaceElement,
|
desktop::{space::SpaceElement, WindowSurface},
|
||||||
input::keyboard::XkbConfig,
|
input::keyboard::XkbConfig,
|
||||||
reexports::{calloop, input as libinput, wayland_protocols::xdg::shell::server},
|
reexports::{calloop, input as libinput, wayland_protocols::xdg::shell::server},
|
||||||
utils::{Point, Rectangle, SERIAL_COUNTER},
|
utils::{Point, Rectangle, SERIAL_COUNTER},
|
||||||
wayland::{compositor, shell::xdg::XdgToplevelSurfaceData},
|
wayland::seat::WaylandFocus,
|
||||||
};
|
};
|
||||||
use sysinfo::ProcessRefreshKind;
|
use sysinfo::ProcessRefreshKind;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
|
@ -48,15 +48,16 @@ use tokio::{
|
||||||
};
|
};
|
||||||
use tokio_stream::{Stream, StreamExt};
|
use tokio_stream::{Stream, StreamExt};
|
||||||
use tonic::{Request, Response, Status, Streaming};
|
use tonic::{Request, Response, Status, Streaming};
|
||||||
|
use tracing::{error, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::ConnectorSavedState,
|
config::ConnectorSavedState,
|
||||||
focus::FocusTarget,
|
focus::keyboard::KeyboardFocusTarget,
|
||||||
input::ModifierMask,
|
input::ModifierMask,
|
||||||
output::OutputName,
|
output::OutputName,
|
||||||
state::{State, WithState},
|
state::{State, WithState},
|
||||||
tag::{Tag, TagId},
|
tag::{Tag, TagId},
|
||||||
window::{window_state::WindowId, WindowElement},
|
window::window_state::WindowId,
|
||||||
};
|
};
|
||||||
|
|
||||||
type ResponseStream<T> = Pin<Box<dyn Stream<Item = Result<T, Status>> + Send>>;
|
type ResponseStream<T> = Pin<Box<dyn Stream<Item = Result<T, Status>> + Send>>;
|
||||||
|
@ -316,7 +317,7 @@ impl input_service_server::InputService for InputService {
|
||||||
};
|
};
|
||||||
if let Some(kb) = state.seat.get_keyboard() {
|
if let Some(kb) = state.seat.get_keyboard() {
|
||||||
if let Err(err) = kb.set_xkb_config(state, new_config) {
|
if let Err(err) = kb.set_xkb_config(state, new_config) {
|
||||||
tracing::error!("Failed to set xkbconfig: {err}");
|
error!("Failed to set xkbconfig: {err}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -557,7 +558,7 @@ impl process_service_server::ProcessService for ProcessService {
|
||||||
.args(command)
|
.args(command)
|
||||||
.spawn()
|
.spawn()
|
||||||
else {
|
else {
|
||||||
tracing::warn!("Tried to run {arg0}, but it doesn't exist",);
|
warn!("Tried to run {arg0}, but it doesn't exist",);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -584,7 +585,7 @@ impl process_service_server::ProcessService for ProcessService {
|
||||||
match sender.send(response) {
|
match sender.send(response) {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
tracing::error!(err = ?err);
|
error!(err = ?err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -608,7 +609,7 @@ impl process_service_server::ProcessService for ProcessService {
|
||||||
match sender.send(response) {
|
match sender.send(response) {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
tracing::error!(err = ?err);
|
error!(err = ?err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -627,7 +628,7 @@ impl process_service_server::ProcessService for ProcessService {
|
||||||
// TODO: handle error
|
// TODO: handle error
|
||||||
let _ = sender.send(response);
|
let _ = sender.send(response);
|
||||||
}
|
}
|
||||||
Err(err) => tracing::warn!("child wait() err: {err}"),
|
Err(err) => warn!("child wait() err: {err}"),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -1122,13 +1123,17 @@ impl window_service_server::WindowService for WindowService {
|
||||||
run_unary_no_response(&self.sender, move |state| {
|
run_unary_no_response(&self.sender, move |state| {
|
||||||
let Some(window) = window_id.window(state) else { return };
|
let Some(window) = window_id.window(state) else { return };
|
||||||
|
|
||||||
match window {
|
match window.underlying_surface() {
|
||||||
WindowElement::Wayland(window) => window.toplevel().send_close(),
|
WindowSurface::Wayland(toplevel) => toplevel.send_close(),
|
||||||
WindowElement::X11(surface) => surface.close().expect("failed to close x11 win"),
|
WindowSurface::X11(surface) => {
|
||||||
WindowElement::X11OverrideRedirect(_) => {
|
if !surface.is_override_redirect() {
|
||||||
tracing::warn!("tried to close override redirect window");
|
if let Err(err) = surface.close() {
|
||||||
|
error!("failed to close x11 window: {err}");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("tried to close OR window");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -1354,32 +1359,14 @@ impl window_service_server::WindowService for WindowService {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if window.is_x11_override_redirect() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let Some(output) = window.output(state) else {
|
let Some(output) = window.output(state) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// if !matches!(
|
|
||||||
// &focus,
|
|
||||||
// FocusTarget::Window(WindowElement::X11OverrideRedirect(_))
|
|
||||||
// ) {
|
|
||||||
// keyboard.set_focus(self, Some(focus.clone()), serial);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// self.space.elements().for_each(|window| {
|
|
||||||
// if let WindowElement::Wayland(window) = window {
|
|
||||||
// window.toplevel().send_configure();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// } else {
|
|
||||||
// self.space.elements().for_each(|window| {
|
|
||||||
// window.set_activate(false);
|
|
||||||
// if let WindowElement::Wayland(window) = window {
|
|
||||||
// window.toplevel().send_configure();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// keyboard.set_focus(self, None, serial);
|
|
||||||
// }
|
|
||||||
|
|
||||||
for win in state.space.elements() {
|
for win in state.space.elements() {
|
||||||
win.set_activate(false);
|
win.set_activate(false);
|
||||||
}
|
}
|
||||||
|
@ -1392,7 +1379,7 @@ impl window_service_server::WindowService for WindowService {
|
||||||
if let Some(keyboard) = state.seat.get_keyboard() {
|
if let Some(keyboard) = state.seat.get_keyboard() {
|
||||||
keyboard.set_focus(
|
keyboard.set_focus(
|
||||||
state,
|
state,
|
||||||
Some(FocusTarget::Window(window)),
|
Some(KeyboardFocusTarget::Window(window)),
|
||||||
SERIAL_COUNTER.next_serial(),
|
SERIAL_COUNTER.next_serial(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1420,7 +1407,7 @@ impl window_service_server::WindowService for WindowService {
|
||||||
if let Some(keyboard) = state.seat.get_keyboard() {
|
if let Some(keyboard) = state.seat.get_keyboard() {
|
||||||
keyboard.set_focus(
|
keyboard.set_focus(
|
||||||
state,
|
state,
|
||||||
Some(FocusTarget::Window(window)),
|
Some(KeyboardFocusTarget::Window(window)),
|
||||||
SERIAL_COUNTER.next_serial(),
|
SERIAL_COUNTER.next_serial(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1430,8 +1417,8 @@ impl window_service_server::WindowService for WindowService {
|
||||||
}
|
}
|
||||||
|
|
||||||
for window in state.space.elements() {
|
for window in state.space.elements() {
|
||||||
if let WindowElement::Wayland(window) = window {
|
if let Some(toplevel) = window.toplevel() {
|
||||||
window.toplevel().send_configure();
|
toplevel.send_configure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1531,12 +1518,17 @@ impl window_service_server::WindowService for WindowService {
|
||||||
.ok_or_else(|| Status::invalid_argument("no button specified"))?;
|
.ok_or_else(|| Status::invalid_argument("no button specified"))?;
|
||||||
|
|
||||||
run_unary_no_response(&self.sender, move |state| {
|
run_unary_no_response(&self.sender, move |state| {
|
||||||
let Some((FocusTarget::Window(window), _)) =
|
let Some((pointer_focus, _)) = state.pointer_focus_target_under(state.pointer_location)
|
||||||
state.focus_target_under(state.pointer_location)
|
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Some(wl_surf) = window.wl_surface() else { return };
|
let Some(window) = pointer_focus.window_for(state) else {
|
||||||
|
tracing::info!("Move grabs are currently not implemented for non-windows");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(wl_surf) = window.wl_surface() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
let seat = state.seat.clone();
|
let seat = state.seat.clone();
|
||||||
|
|
||||||
crate::grab::move_grab::move_request_server(
|
crate::grab::move_grab::move_request_server(
|
||||||
|
@ -1562,12 +1554,17 @@ impl window_service_server::WindowService for WindowService {
|
||||||
|
|
||||||
run_unary_no_response(&self.sender, move |state| {
|
run_unary_no_response(&self.sender, move |state| {
|
||||||
let pointer_loc = state.pointer_location;
|
let pointer_loc = state.pointer_location;
|
||||||
let Some((FocusTarget::Window(window), window_loc)) =
|
let Some((pointer_focus, window_loc)) = state.pointer_focus_target_under(pointer_loc)
|
||||||
state.focus_target_under(pointer_loc)
|
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Some(wl_surf) = window.wl_surface() else { return };
|
let Some(window) = pointer_focus.window_for(state) else {
|
||||||
|
tracing::info!("Move grabs are currently not implemented for non-windows");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(wl_surf) = window.wl_surface() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let window_geometry = window.geometry();
|
let window_geometry = window.geometry();
|
||||||
let window_x = window_loc.x as f64;
|
let window_x = window_loc.x as f64;
|
||||||
|
@ -1675,27 +1672,8 @@ impl window_service_server::WindowService for WindowService {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let (class, title) = window.as_ref().map_or((None, None), |win| match &win {
|
let class = window.as_ref().and_then(|win| win.class());
|
||||||
WindowElement::Wayland(_) => {
|
let title = window.as_ref().and_then(|win| win.title());
|
||||||
if let Some(wl_surf) = win.wl_surface() {
|
|
||||||
compositor::with_states(&wl_surf, |states| {
|
|
||||||
let lock = states
|
|
||||||
.data_map
|
|
||||||
.get::<XdgToplevelSurfaceData>()
|
|
||||||
.expect("XdgToplevelSurfaceData wasn't in surface's data map")
|
|
||||||
.lock()
|
|
||||||
.expect("failed to acquire lock");
|
|
||||||
(lock.app_id.clone(), lock.title.clone())
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
(None, None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
(Some(surface.class()), Some(surface.title()))
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let focused = window.as_ref().and_then(|win| {
|
let focused = window.as_ref().and_then(|win| {
|
||||||
state
|
state
|
||||||
|
|
|
@ -91,8 +91,12 @@ const SUPPORTED_FORMATS: &[Fourcc] = &[
|
||||||
const SUPPORTED_FORMATS_8BIT_ONLY: &[Fourcc] = &[Fourcc::Abgr8888, Fourcc::Argb8888];
|
const SUPPORTED_FORMATS_8BIT_ONLY: &[Fourcc] = &[Fourcc::Abgr8888, Fourcc::Argb8888];
|
||||||
|
|
||||||
/// A [`MultiRenderer`] that uses the [`GbmGlesBackend`].
|
/// A [`MultiRenderer`] that uses the [`GbmGlesBackend`].
|
||||||
type UdevRenderer<'a, 'b> =
|
type UdevRenderer<'a> = MultiRenderer<
|
||||||
MultiRenderer<'a, 'a, 'b, GbmGlesBackend<GlesRenderer>, GbmGlesBackend<GlesRenderer>>;
|
'a,
|
||||||
|
'a,
|
||||||
|
GbmGlesBackend<GlesRenderer, DrmDeviceFd>,
|
||||||
|
GbmGlesBackend<GlesRenderer, DrmDeviceFd>,
|
||||||
|
>;
|
||||||
|
|
||||||
/// Udev state attached to each [`Output`].
|
/// Udev state attached to each [`Output`].
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
@ -110,7 +114,7 @@ pub struct Udev {
|
||||||
pub(super) dmabuf_state: Option<(DmabufState, DmabufGlobal)>,
|
pub(super) dmabuf_state: Option<(DmabufState, DmabufGlobal)>,
|
||||||
pub(super) primary_gpu: DrmNode,
|
pub(super) primary_gpu: DrmNode,
|
||||||
allocator: Option<Box<dyn Allocator<Buffer = Dmabuf, Error = AnyError>>>,
|
allocator: Option<Box<dyn Allocator<Buffer = Dmabuf, Error = AnyError>>>,
|
||||||
pub(super) gpu_manager: GpuManager<GbmGlesBackend<GlesRenderer>>,
|
pub(super) gpu_manager: GpuManager<GbmGlesBackend<GlesRenderer, DrmDeviceFd>>,
|
||||||
backends: HashMap<DrmNode, UdevBackendData>,
|
backends: HashMap<DrmNode, UdevBackendData>,
|
||||||
pointer_images: Vec<(xcursor::parser::Image, TextureBuffer<MultiTexture>)>,
|
pointer_images: Vec<(xcursor::parser::Image, TextureBuffer<MultiTexture>)>,
|
||||||
pointer_element: PointerElement<MultiTexture>,
|
pointer_element: PointerElement<MultiTexture>,
|
||||||
|
@ -226,10 +230,7 @@ impl BackendData for Udev {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn early_import(&mut self, surface: &WlSurface) {
|
fn early_import(&mut self, surface: &WlSurface) {
|
||||||
if let Err(err) =
|
if let Err(err) = self.gpu_manager.early_import(self.primary_gpu, surface) {
|
||||||
self.gpu_manager
|
|
||||||
.early_import(Some(self.primary_gpu), self.primary_gpu, surface)
|
|
||||||
{
|
|
||||||
tracing::warn!("early buffer import failed: {}", err);
|
tracing::warn!("early buffer import failed: {}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -556,7 +557,7 @@ enum DeviceAddError {
|
||||||
fn get_surface_dmabuf_feedback(
|
fn get_surface_dmabuf_feedback(
|
||||||
primary_gpu: DrmNode,
|
primary_gpu: DrmNode,
|
||||||
render_node: DrmNode,
|
render_node: DrmNode,
|
||||||
gpu_manager: &mut GpuManager<GbmGlesBackend<GlesRenderer>>,
|
gpu_manager: &mut GpuManager<GbmGlesBackend<GlesRenderer, DrmDeviceFd>>,
|
||||||
composition: &GbmDrmCompositor,
|
composition: &GbmDrmCompositor,
|
||||||
) -> Option<DrmSurfaceDmabufFeedback> {
|
) -> Option<DrmSurfaceDmabufFeedback> {
|
||||||
let primary_formats = gpu_manager
|
let primary_formats = gpu_manager
|
||||||
|
@ -1210,18 +1211,8 @@ impl State {
|
||||||
udev.gpu_manager.single_renderer(&render_node)
|
udev.gpu_manager.single_renderer(&render_node)
|
||||||
} else {
|
} else {
|
||||||
let format = surface.compositor.format();
|
let format = surface.compositor.format();
|
||||||
udev.gpu_manager.renderer(
|
udev.gpu_manager
|
||||||
&primary_gpu,
|
.renderer(&primary_gpu, &render_node, format)
|
||||||
&render_node,
|
|
||||||
udev
|
|
||||||
.allocator
|
|
||||||
.as_mut()
|
|
||||||
// TODO: We could build some kind of `GLAllocator` using Renderbuffers in theory for this case.
|
|
||||||
// That would work for memcpy's of offscreen contents.
|
|
||||||
.expect("We need an allocator for multigpu systems")
|
|
||||||
.as_mut(),
|
|
||||||
format,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
.expect("failed to create MultiRenderer");
|
.expect("failed to create MultiRenderer");
|
||||||
|
|
||||||
|
@ -1294,7 +1285,7 @@ fn render_surface_for_output<'a>(
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn render_surface(
|
fn render_surface(
|
||||||
surface: &mut RenderSurface,
|
surface: &mut RenderSurface,
|
||||||
renderer: &mut UdevRenderer<'_, '_>,
|
renderer: &mut UdevRenderer<'_>,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
|
|
||||||
space: &Space<WindowElement>,
|
space: &Space<WindowElement>,
|
||||||
|
|
326
src/focus.rs
326
src/focus.rs
|
@ -1,23 +1,15 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{output::Output, utils::SERIAL_COUNTER};
|
||||||
desktop::{LayerSurface, PopupKind},
|
|
||||||
input::{
|
|
||||||
keyboard::KeyboardTarget,
|
|
||||||
pointer::{MotionEvent, PointerTarget},
|
|
||||||
Seat,
|
|
||||||
},
|
|
||||||
output::Output,
|
|
||||||
reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource},
|
|
||||||
utils::{IsAlive, SERIAL_COUNTER},
|
|
||||||
wayland::seat::WaylandFocus,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
state::{State, WithState},
|
state::{State, WithState},
|
||||||
window::WindowElement,
|
window::WindowElement,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub mod keyboard;
|
||||||
|
pub mod pointer;
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
/// Get the currently focused window on `output`
|
/// Get the currently focused window on `output`
|
||||||
/// that isn't an override redirect window, if any.
|
/// that isn't an override redirect window, if any.
|
||||||
|
@ -55,8 +47,8 @@ impl State {
|
||||||
if let Some(win) = ¤t_focus {
|
if let Some(win) = ¤t_focus {
|
||||||
assert!(!win.is_x11_override_redirect());
|
assert!(!win.is_x11_override_redirect());
|
||||||
|
|
||||||
if let WindowElement::Wayland(w) = win {
|
if let Some(toplevel) = win.toplevel() {
|
||||||
w.toplevel().send_configure();
|
toplevel.send_configure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,309 +102,3 @@ impl<T: PartialEq> FocusStack<T> {
|
||||||
self.focused.then(|| self.stack.last())?
|
self.focused.then(|| self.stack.last())?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Different focusable objects.
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum FocusTarget {
|
|
||||||
Window(WindowElement),
|
|
||||||
Popup(PopupKind),
|
|
||||||
LayerSurface(LayerSurface),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IsAlive for FocusTarget {
|
|
||||||
fn alive(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
FocusTarget::Window(window) => window.alive(),
|
|
||||||
FocusTarget::Popup(popup) => popup.alive(),
|
|
||||||
FocusTarget::LayerSurface(surf) => surf.alive(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<FocusTarget> for WlSurface {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(value: FocusTarget) -> Result<Self, Self::Error> {
|
|
||||||
value.wl_surface().ok_or(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PointerTarget<State> for FocusTarget {
|
|
||||||
fn frame(&self, seat: &Seat<State>, data: &mut State) {
|
|
||||||
match self {
|
|
||||||
FocusTarget::Window(window) => window.frame(seat, data),
|
|
||||||
FocusTarget::Popup(popup) => popup.wl_surface().frame(seat, data),
|
|
||||||
FocusTarget::LayerSurface(surf) => surf.frame(seat, data),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
|
||||||
match self {
|
|
||||||
FocusTarget::Window(window) => PointerTarget::enter(window, seat, data, event),
|
|
||||||
FocusTarget::Popup(popup) => {
|
|
||||||
PointerTarget::enter(popup.wl_surface(), seat, data, event);
|
|
||||||
}
|
|
||||||
FocusTarget::LayerSurface(surf) => PointerTarget::enter(surf, seat, data, event),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &MotionEvent) {
|
|
||||||
match self {
|
|
||||||
FocusTarget::Window(window) => PointerTarget::motion(window, seat, data, event),
|
|
||||||
FocusTarget::Popup(popup) => {
|
|
||||||
PointerTarget::motion(popup.wl_surface(), seat, data, event);
|
|
||||||
}
|
|
||||||
FocusTarget::LayerSurface(surf) => PointerTarget::motion(surf, seat, data, event),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn relative_motion(
|
|
||||||
&self,
|
|
||||||
seat: &Seat<State>,
|
|
||||||
data: &mut State,
|
|
||||||
event: &smithay::input::pointer::RelativeMotionEvent,
|
|
||||||
) {
|
|
||||||
match self {
|
|
||||||
FocusTarget::Window(window) => {
|
|
||||||
PointerTarget::relative_motion(window, seat, data, event);
|
|
||||||
}
|
|
||||||
FocusTarget::Popup(popup) => {
|
|
||||||
PointerTarget::relative_motion(popup.wl_surface(), seat, data, event);
|
|
||||||
}
|
|
||||||
FocusTarget::LayerSurface(surf) => {
|
|
||||||
PointerTarget::relative_motion(surf, seat, data, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn button(
|
|
||||||
&self,
|
|
||||||
seat: &Seat<State>,
|
|
||||||
data: &mut State,
|
|
||||||
event: &smithay::input::pointer::ButtonEvent,
|
|
||||||
) {
|
|
||||||
match self {
|
|
||||||
FocusTarget::Window(window) => PointerTarget::button(window, seat, data, event),
|
|
||||||
FocusTarget::Popup(popup) => {
|
|
||||||
PointerTarget::button(popup.wl_surface(), seat, data, event);
|
|
||||||
}
|
|
||||||
FocusTarget::LayerSurface(surf) => PointerTarget::button(surf, seat, data, event),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn axis(
|
|
||||||
&self,
|
|
||||||
seat: &Seat<State>,
|
|
||||||
data: &mut State,
|
|
||||||
frame: smithay::input::pointer::AxisFrame,
|
|
||||||
) {
|
|
||||||
match self {
|
|
||||||
FocusTarget::Window(window) => PointerTarget::axis(window, seat, data, frame),
|
|
||||||
FocusTarget::Popup(popup) => PointerTarget::axis(popup.wl_surface(), seat, data, frame),
|
|
||||||
FocusTarget::LayerSurface(surf) => PointerTarget::axis(surf, seat, data, frame),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn leave(
|
|
||||||
&self,
|
|
||||||
seat: &Seat<State>,
|
|
||||||
data: &mut State,
|
|
||||||
serial: smithay::utils::Serial,
|
|
||||||
time: u32,
|
|
||||||
) {
|
|
||||||
match self {
|
|
||||||
FocusTarget::Window(window) => PointerTarget::leave(window, seat, data, serial, time),
|
|
||||||
FocusTarget::Popup(popup) => {
|
|
||||||
PointerTarget::leave(popup.wl_surface(), seat, data, serial, time);
|
|
||||||
}
|
|
||||||
FocusTarget::LayerSurface(surf) => PointerTarget::leave(surf, seat, data, serial, time),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_swipe_begin(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_data: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GestureSwipeBeginEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_swipe_update(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_data: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GestureSwipeUpdateEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_swipe_end(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_data: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GestureSwipeEndEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_pinch_begin(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_data: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GesturePinchBeginEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_pinch_update(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_data: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GesturePinchUpdateEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_pinch_end(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_data: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GesturePinchEndEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_hold_begin(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_data: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GestureHoldBeginEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_hold_end(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_data: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GestureHoldEndEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KeyboardTarget<State> for FocusTarget {
|
|
||||||
fn enter(
|
|
||||||
&self,
|
|
||||||
seat: &Seat<State>,
|
|
||||||
data: &mut State,
|
|
||||||
keys: Vec<smithay::input::keyboard::KeysymHandle<'_>>,
|
|
||||||
serial: smithay::utils::Serial,
|
|
||||||
) {
|
|
||||||
match self {
|
|
||||||
FocusTarget::Window(window) => KeyboardTarget::enter(window, seat, data, keys, serial),
|
|
||||||
FocusTarget::Popup(popup) => {
|
|
||||||
KeyboardTarget::enter(popup.wl_surface(), seat, data, keys, serial);
|
|
||||||
}
|
|
||||||
FocusTarget::LayerSurface(surf) => {
|
|
||||||
KeyboardTarget::enter(surf, seat, data, keys, serial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: smithay::utils::Serial) {
|
|
||||||
match self {
|
|
||||||
FocusTarget::Window(window) => KeyboardTarget::leave(window, seat, data, serial),
|
|
||||||
FocusTarget::Popup(popup) => {
|
|
||||||
KeyboardTarget::leave(popup.wl_surface(), seat, data, serial);
|
|
||||||
}
|
|
||||||
FocusTarget::LayerSurface(surf) => KeyboardTarget::leave(surf, seat, data, serial),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn key(
|
|
||||||
&self,
|
|
||||||
seat: &Seat<State>,
|
|
||||||
data: &mut State,
|
|
||||||
key: smithay::input::keyboard::KeysymHandle<'_>,
|
|
||||||
state: smithay::backend::input::KeyState,
|
|
||||||
serial: smithay::utils::Serial,
|
|
||||||
time: u32,
|
|
||||||
) {
|
|
||||||
match self {
|
|
||||||
FocusTarget::Window(window) => {
|
|
||||||
KeyboardTarget::key(window, seat, data, key, state, serial, time);
|
|
||||||
}
|
|
||||||
FocusTarget::Popup(popup) => {
|
|
||||||
KeyboardTarget::key(popup.wl_surface(), seat, data, key, state, serial, time);
|
|
||||||
}
|
|
||||||
FocusTarget::LayerSurface(surf) => {
|
|
||||||
KeyboardTarget::key(surf, seat, data, key, state, serial, time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn modifiers(
|
|
||||||
&self,
|
|
||||||
seat: &Seat<State>,
|
|
||||||
data: &mut State,
|
|
||||||
modifiers: smithay::input::keyboard::ModifiersState,
|
|
||||||
serial: smithay::utils::Serial,
|
|
||||||
) {
|
|
||||||
match self {
|
|
||||||
FocusTarget::Window(window) => {
|
|
||||||
KeyboardTarget::modifiers(window, seat, data, modifiers, serial);
|
|
||||||
}
|
|
||||||
FocusTarget::Popup(popup) => {
|
|
||||||
KeyboardTarget::modifiers(popup.wl_surface(), seat, data, modifiers, serial);
|
|
||||||
}
|
|
||||||
FocusTarget::LayerSurface(surf) => {
|
|
||||||
KeyboardTarget::modifiers(surf, seat, data, modifiers, serial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WaylandFocus for FocusTarget {
|
|
||||||
fn wl_surface(&self) -> Option<WlSurface> {
|
|
||||||
match self {
|
|
||||||
FocusTarget::Window(window) => window.wl_surface(),
|
|
||||||
FocusTarget::Popup(popup) => Some(popup.wl_surface().clone()),
|
|
||||||
FocusTarget::LayerSurface(surf) => Some(surf.wl_surface().clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn same_client_as(
|
|
||||||
&self,
|
|
||||||
object_id: &smithay::reexports::wayland_server::backend::ObjectId,
|
|
||||||
) -> bool {
|
|
||||||
match self {
|
|
||||||
FocusTarget::Window(WindowElement::Wayland(window)) => window.same_client_as(object_id),
|
|
||||||
FocusTarget::Window(
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface),
|
|
||||||
) => surface.same_client_as(object_id),
|
|
||||||
FocusTarget::Popup(popup) => popup.wl_surface().id().same_client_as(object_id),
|
|
||||||
FocusTarget::LayerSurface(surf) => surf.wl_surface().id().same_client_as(object_id),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<WindowElement> for FocusTarget {
|
|
||||||
fn from(value: WindowElement) -> Self {
|
|
||||||
FocusTarget::Window(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<PopupKind> for FocusTarget {
|
|
||||||
fn from(value: PopupKind) -> Self {
|
|
||||||
FocusTarget::Popup(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<LayerSurface> for FocusTarget {
|
|
||||||
fn from(value: LayerSurface) -> Self {
|
|
||||||
FocusTarget::LayerSurface(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
230
src/focus/keyboard.rs
Normal file
230
src/focus/keyboard.rs
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
use smithay::{
|
||||||
|
backend::input::KeyState,
|
||||||
|
desktop::{LayerSurface, PopupKind, WindowSurface},
|
||||||
|
input::{
|
||||||
|
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
||||||
|
Seat,
|
||||||
|
},
|
||||||
|
reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource},
|
||||||
|
utils::{IsAlive, Serial},
|
||||||
|
wayland::seat::WaylandFocus,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{state::State, window::WindowElement};
|
||||||
|
|
||||||
|
/// Keyboard focusable objects
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum KeyboardFocusTarget {
|
||||||
|
Window(WindowElement),
|
||||||
|
Popup(PopupKind),
|
||||||
|
LayerSurface(LayerSurface),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyboardTarget<State> for KeyboardFocusTarget {
|
||||||
|
fn enter(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
keys: Vec<KeysymHandle<'_>>,
|
||||||
|
serial: Serial,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
KeyboardFocusTarget::Window(window) => {
|
||||||
|
KeyboardTarget::enter(window, seat, data, keys, serial)
|
||||||
|
}
|
||||||
|
KeyboardFocusTarget::Popup(popup) => {
|
||||||
|
KeyboardTarget::enter(popup.wl_surface(), seat, data, keys, serial);
|
||||||
|
}
|
||||||
|
KeyboardFocusTarget::LayerSurface(surf) => {
|
||||||
|
KeyboardTarget::enter(surf.wl_surface(), seat, data, keys, serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial) {
|
||||||
|
match self {
|
||||||
|
KeyboardFocusTarget::Window(window) => {
|
||||||
|
KeyboardTarget::leave(window, seat, data, serial)
|
||||||
|
}
|
||||||
|
KeyboardFocusTarget::Popup(popup) => {
|
||||||
|
KeyboardTarget::leave(popup.wl_surface(), seat, data, serial);
|
||||||
|
}
|
||||||
|
KeyboardFocusTarget::LayerSurface(surf) => {
|
||||||
|
KeyboardTarget::leave(surf.wl_surface(), seat, data, serial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
key: KeysymHandle<'_>,
|
||||||
|
state: smithay::backend::input::KeyState,
|
||||||
|
serial: Serial,
|
||||||
|
time: u32,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
KeyboardFocusTarget::Window(window) => {
|
||||||
|
KeyboardTarget::key(window, seat, data, key, state, serial, time);
|
||||||
|
}
|
||||||
|
KeyboardFocusTarget::Popup(popup) => {
|
||||||
|
KeyboardTarget::key(popup.wl_surface(), seat, data, key, state, serial, time);
|
||||||
|
}
|
||||||
|
KeyboardFocusTarget::LayerSurface(surf) => {
|
||||||
|
KeyboardTarget::key(surf.wl_surface(), seat, data, key, state, serial, time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modifiers(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
modifiers: smithay::input::keyboard::ModifiersState,
|
||||||
|
serial: Serial,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
KeyboardFocusTarget::Window(window) => {
|
||||||
|
KeyboardTarget::modifiers(window, seat, data, modifiers, serial);
|
||||||
|
}
|
||||||
|
KeyboardFocusTarget::Popup(popup) => {
|
||||||
|
KeyboardTarget::modifiers(popup.wl_surface(), seat, data, modifiers, serial);
|
||||||
|
}
|
||||||
|
KeyboardFocusTarget::LayerSurface(surf) => {
|
||||||
|
KeyboardTarget::modifiers(surf.wl_surface(), seat, data, modifiers, serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IsAlive for KeyboardFocusTarget {
|
||||||
|
fn alive(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
KeyboardFocusTarget::Window(window) => window.alive(),
|
||||||
|
KeyboardFocusTarget::Popup(popup) => popup.alive(),
|
||||||
|
KeyboardFocusTarget::LayerSurface(surf) => surf.alive(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WaylandFocus for KeyboardFocusTarget {
|
||||||
|
fn wl_surface(&self) -> Option<WlSurface> {
|
||||||
|
match self {
|
||||||
|
KeyboardFocusTarget::Window(window) => window.wl_surface(),
|
||||||
|
KeyboardFocusTarget::Popup(popup) => Some(popup.wl_surface().clone()),
|
||||||
|
KeyboardFocusTarget::LayerSurface(surf) => Some(surf.wl_surface().clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn same_client_as(
|
||||||
|
&self,
|
||||||
|
object_id: &smithay::reexports::wayland_server::backend::ObjectId,
|
||||||
|
) -> bool {
|
||||||
|
match self {
|
||||||
|
KeyboardFocusTarget::Window(window) => window.same_client_as(object_id),
|
||||||
|
KeyboardFocusTarget::Popup(popup) => popup.wl_surface().id().same_client_as(object_id),
|
||||||
|
KeyboardFocusTarget::LayerSurface(surf) => {
|
||||||
|
surf.wl_surface().id().same_client_as(object_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<KeyboardFocusTarget> for WlSurface {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: KeyboardFocusTarget) -> Result<Self, Self::Error> {
|
||||||
|
value.wl_surface().ok_or(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<WindowElement> for KeyboardFocusTarget {
|
||||||
|
fn from(value: WindowElement) -> Self {
|
||||||
|
KeyboardFocusTarget::Window(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PopupKind> for KeyboardFocusTarget {
|
||||||
|
fn from(value: PopupKind) -> Self {
|
||||||
|
KeyboardFocusTarget::Popup(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LayerSurface> for KeyboardFocusTarget {
|
||||||
|
fn from(value: LayerSurface) -> Self {
|
||||||
|
KeyboardFocusTarget::LayerSurface(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyboardTarget<State> for WindowElement {
|
||||||
|
fn enter(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
state: &mut State,
|
||||||
|
keys: Vec<KeysymHandle<'_>>,
|
||||||
|
serial: Serial,
|
||||||
|
) {
|
||||||
|
match self.underlying_surface() {
|
||||||
|
WindowSurface::Wayland(toplevel) => {
|
||||||
|
KeyboardTarget::enter(toplevel.wl_surface(), seat, state, keys, serial);
|
||||||
|
}
|
||||||
|
WindowSurface::X11(surface) => {
|
||||||
|
KeyboardTarget::enter(surface, seat, state, keys, serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leave(&self, seat: &Seat<State>, state: &mut State, serial: Serial) {
|
||||||
|
match self.underlying_surface() {
|
||||||
|
WindowSurface::Wayland(toplevel) => {
|
||||||
|
KeyboardTarget::leave(toplevel.wl_surface(), seat, state, serial);
|
||||||
|
}
|
||||||
|
WindowSurface::X11(surface) => KeyboardTarget::leave(surface, seat, state, serial),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
state: &mut State,
|
||||||
|
key: KeysymHandle<'_>,
|
||||||
|
key_state: KeyState,
|
||||||
|
serial: Serial,
|
||||||
|
time: u32,
|
||||||
|
) {
|
||||||
|
match self.underlying_surface() {
|
||||||
|
WindowSurface::Wayland(toplevel) => {
|
||||||
|
KeyboardTarget::key(
|
||||||
|
toplevel.wl_surface(),
|
||||||
|
seat,
|
||||||
|
state,
|
||||||
|
key,
|
||||||
|
key_state,
|
||||||
|
serial,
|
||||||
|
time,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
WindowSurface::X11(surface) => {
|
||||||
|
KeyboardTarget::key(surface, seat, state, key, key_state, serial, time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modifiers(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
state: &mut State,
|
||||||
|
modifiers: ModifiersState,
|
||||||
|
serial: Serial,
|
||||||
|
) {
|
||||||
|
match self.underlying_surface() {
|
||||||
|
WindowSurface::Wayland(toplevel) => {
|
||||||
|
KeyboardTarget::modifiers(toplevel.wl_surface(), seat, state, modifiers, serial);
|
||||||
|
}
|
||||||
|
WindowSurface::X11(surface) => {
|
||||||
|
KeyboardTarget::modifiers(surface, seat, state, modifiers, serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
428
src/focus/pointer.rs
Normal file
428
src/focus/pointer.rs
Normal file
|
@ -0,0 +1,428 @@
|
||||||
|
use pinnacle_api_defs::pinnacle::signal::v0alpha1::{
|
||||||
|
WindowPointerEnterResponse, WindowPointerLeaveResponse,
|
||||||
|
};
|
||||||
|
use smithay::{
|
||||||
|
desktop::{
|
||||||
|
layer_map_for_output, utils::with_surfaces_surface_tree, LayerSurface, PopupKind,
|
||||||
|
WindowSurface,
|
||||||
|
},
|
||||||
|
input::{
|
||||||
|
pointer::{self, PointerTarget},
|
||||||
|
touch::{self, TouchTarget},
|
||||||
|
Seat,
|
||||||
|
},
|
||||||
|
reexports::wayland_server::{backend::ObjectId, protocol::wl_surface::WlSurface},
|
||||||
|
utils::{IsAlive, Serial},
|
||||||
|
wayland::seat::WaylandFocus,
|
||||||
|
xwayland::X11Surface,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
state::{State, WithState},
|
||||||
|
window::WindowElement,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::keyboard::KeyboardFocusTarget;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum PointerFocusTarget {
|
||||||
|
WlSurface(WlSurface),
|
||||||
|
X11Surface(X11Surface),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PointerFocusTarget {
|
||||||
|
/// If the pointer focus's surface is owned by a window, get that window.
|
||||||
|
pub fn window_for(&self, state: &State) -> Option<WindowElement> {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => state
|
||||||
|
.windows
|
||||||
|
.iter()
|
||||||
|
.find(|win| {
|
||||||
|
let Some(surface) = win.wl_surface() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let mut found = false;
|
||||||
|
with_surfaces_surface_tree(&surface, |surface, _| {
|
||||||
|
if surface == surf {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
found
|
||||||
|
})
|
||||||
|
.cloned(),
|
||||||
|
PointerFocusTarget::X11Surface(surf) => state
|
||||||
|
.windows
|
||||||
|
.iter()
|
||||||
|
.find(|win| win.x11_surface() == Some(surf))
|
||||||
|
.cloned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn layer_for(&self, state: &State) -> Option<LayerSurface> {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => {
|
||||||
|
for output in state.space.outputs() {
|
||||||
|
let map = layer_map_for_output(output);
|
||||||
|
for layer in map.layers() {
|
||||||
|
let mut found = false;
|
||||||
|
with_surfaces_surface_tree(layer.wl_surface(), |surface, _| {
|
||||||
|
if surface == surf {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if found {
|
||||||
|
return Some(layer.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
PointerFocusTarget::X11Surface(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn popup_for(&self, state: &State) -> Option<PopupKind> {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => state.popup_manager.find_popup(surf),
|
||||||
|
PointerFocusTarget::X11Surface(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_keyboard_focus_target(&self, state: &State) -> Option<KeyboardFocusTarget> {
|
||||||
|
#[allow(clippy::manual_map)] // screw off clippy
|
||||||
|
if let Some(window) = self.window_for(state) {
|
||||||
|
Some(KeyboardFocusTarget::Window(window))
|
||||||
|
} else if let Some(layer) = self.layer_for(state) {
|
||||||
|
Some(KeyboardFocusTarget::LayerSurface(layer))
|
||||||
|
} else if let Some(popup) = self.popup_for(state) {
|
||||||
|
Some(KeyboardFocusTarget::Popup(popup))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IsAlive for PointerFocusTarget {
|
||||||
|
fn alive(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => surf.alive(),
|
||||||
|
PointerFocusTarget::X11Surface(surf) => surf.alive(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PointerTarget<State> for PointerFocusTarget {
|
||||||
|
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &pointer::MotionEvent) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => PointerTarget::enter(surf, seat, data, event),
|
||||||
|
PointerFocusTarget::X11Surface(surf) => PointerTarget::enter(surf, seat, data, event),
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(window) = self.window_for(data) {
|
||||||
|
let window_id = Some(window.with_state(|state| state.id.0));
|
||||||
|
|
||||||
|
data.signal_state
|
||||||
|
.window_pointer_enter
|
||||||
|
.signal(|buffer| buffer.push_back(WindowPointerEnterResponse { window_id }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &pointer::MotionEvent) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => PointerTarget::motion(surf, seat, data, event),
|
||||||
|
PointerFocusTarget::X11Surface(surf) => PointerTarget::motion(surf, seat, data, event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn relative_motion(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
event: &pointer::RelativeMotionEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => {
|
||||||
|
PointerTarget::relative_motion(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
PointerFocusTarget::X11Surface(surf) => {
|
||||||
|
PointerTarget::relative_motion(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn button(&self, seat: &Seat<State>, data: &mut State, event: &pointer::ButtonEvent) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => PointerTarget::button(surf, seat, data, event),
|
||||||
|
PointerFocusTarget::X11Surface(surf) => PointerTarget::button(surf, seat, data, event),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: pointer::AxisFrame) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => PointerTarget::axis(surf, seat, data, frame),
|
||||||
|
PointerFocusTarget::X11Surface(surf) => PointerTarget::axis(surf, seat, data, frame),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(&self, seat: &Seat<State>, data: &mut State) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => PointerTarget::frame(surf, seat, data),
|
||||||
|
PointerFocusTarget::X11Surface(surf) => PointerTarget::frame(surf, seat, data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gesture_swipe_begin(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
event: &pointer::GestureSwipeBeginEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => {
|
||||||
|
PointerTarget::gesture_swipe_begin(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
PointerFocusTarget::X11Surface(surf) => {
|
||||||
|
PointerTarget::gesture_swipe_begin(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gesture_swipe_update(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
event: &pointer::GestureSwipeUpdateEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => {
|
||||||
|
PointerTarget::gesture_swipe_update(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
PointerFocusTarget::X11Surface(surf) => {
|
||||||
|
PointerTarget::gesture_swipe_update(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gesture_swipe_end(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
event: &pointer::GestureSwipeEndEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => {
|
||||||
|
PointerTarget::gesture_swipe_end(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
PointerFocusTarget::X11Surface(surf) => {
|
||||||
|
PointerTarget::gesture_swipe_end(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gesture_pinch_begin(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
event: &pointer::GesturePinchBeginEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => {
|
||||||
|
PointerTarget::gesture_pinch_begin(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
PointerFocusTarget::X11Surface(surf) => {
|
||||||
|
PointerTarget::gesture_pinch_begin(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gesture_pinch_update(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
event: &pointer::GesturePinchUpdateEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => {
|
||||||
|
PointerTarget::gesture_pinch_update(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
PointerFocusTarget::X11Surface(surf) => {
|
||||||
|
PointerTarget::gesture_pinch_update(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gesture_pinch_end(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
event: &pointer::GesturePinchEndEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => {
|
||||||
|
PointerTarget::gesture_pinch_end(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
PointerFocusTarget::X11Surface(surf) => {
|
||||||
|
PointerTarget::gesture_pinch_end(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gesture_hold_begin(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
event: &pointer::GestureHoldBeginEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => {
|
||||||
|
PointerTarget::gesture_hold_begin(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
PointerFocusTarget::X11Surface(surf) => {
|
||||||
|
PointerTarget::gesture_hold_begin(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gesture_hold_end(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
event: &pointer::GestureHoldEndEvent,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => {
|
||||||
|
PointerTarget::gesture_hold_end(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
PointerFocusTarget::X11Surface(surf) => {
|
||||||
|
PointerTarget::gesture_hold_end(surf, seat, data, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => {
|
||||||
|
PointerTarget::leave(surf, seat, data, serial, time);
|
||||||
|
}
|
||||||
|
PointerFocusTarget::X11Surface(surf) => {
|
||||||
|
PointerTarget::leave(surf, seat, data, serial, time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(window) = self.window_for(data) {
|
||||||
|
let window_id = Some(window.with_state(|state| state.id.0));
|
||||||
|
|
||||||
|
data.signal_state
|
||||||
|
.window_pointer_leave
|
||||||
|
.signal(|buffer| buffer.push_back(WindowPointerLeaveResponse { window_id }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TouchTarget<State> for PointerFocusTarget {
|
||||||
|
fn down(&self, seat: &Seat<State>, data: &mut State, event: &touch::DownEvent, seq: Serial) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => TouchTarget::down(surf, seat, data, event, seq),
|
||||||
|
PointerFocusTarget::X11Surface(surf) => TouchTarget::down(surf, seat, data, event, seq),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn up(&self, seat: &Seat<State>, data: &mut State, event: &touch::UpEvent, seq: Serial) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => TouchTarget::up(surf, seat, data, event, seq),
|
||||||
|
PointerFocusTarget::X11Surface(surf) => TouchTarget::up(surf, seat, data, event, seq),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
event: &touch::MotionEvent,
|
||||||
|
seq: Serial,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => {
|
||||||
|
TouchTarget::motion(surf, seat, data, event, seq);
|
||||||
|
}
|
||||||
|
PointerFocusTarget::X11Surface(surf) => {
|
||||||
|
TouchTarget::motion(surf, seat, data, event, seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(&self, seat: &Seat<State>, data: &mut State, seq: Serial) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => TouchTarget::frame(surf, seat, data, seq),
|
||||||
|
PointerFocusTarget::X11Surface(surf) => TouchTarget::frame(surf, seat, data, seq),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cancel(&self, seat: &Seat<State>, data: &mut State, seq: Serial) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => TouchTarget::cancel(surf, seat, data, seq),
|
||||||
|
PointerFocusTarget::X11Surface(surf) => TouchTarget::cancel(surf, seat, data, seq),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shape(&self, seat: &Seat<State>, data: &mut State, event: &touch::ShapeEvent, seq: Serial) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => TouchTarget::shape(surf, seat, data, event, seq),
|
||||||
|
PointerFocusTarget::X11Surface(surf) => {
|
||||||
|
TouchTarget::shape(surf, seat, data, event, seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn orientation(
|
||||||
|
&self,
|
||||||
|
seat: &Seat<State>,
|
||||||
|
data: &mut State,
|
||||||
|
event: &touch::OrientationEvent,
|
||||||
|
seq: Serial,
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => {
|
||||||
|
TouchTarget::orientation(surf, seat, data, event, seq);
|
||||||
|
}
|
||||||
|
PointerFocusTarget::X11Surface(surf) => {
|
||||||
|
TouchTarget::orientation(surf, seat, data, event, seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WaylandFocus for PointerFocusTarget {
|
||||||
|
fn wl_surface(&self) -> Option<WlSurface> {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => Some(surf.clone()),
|
||||||
|
PointerFocusTarget::X11Surface(surf) => surf.wl_surface(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn same_client_as(&self, object_id: &ObjectId) -> bool {
|
||||||
|
match self {
|
||||||
|
PointerFocusTarget::WlSurface(surf) => surf.same_client_as(object_id),
|
||||||
|
PointerFocusTarget::X11Surface(surf) => surf.same_client_as(object_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<KeyboardFocusTarget> for PointerFocusTarget {
|
||||||
|
fn from(target: KeyboardFocusTarget) -> Self {
|
||||||
|
match target {
|
||||||
|
KeyboardFocusTarget::Window(window) => match window.underlying_surface() {
|
||||||
|
WindowSurface::Wayland(toplevel) => {
|
||||||
|
PointerFocusTarget::WlSurface(toplevel.wl_surface().clone())
|
||||||
|
}
|
||||||
|
WindowSurface::X11(surface) => PointerFocusTarget::X11Surface(surface.clone()),
|
||||||
|
},
|
||||||
|
KeyboardFocusTarget::Popup(popup) => {
|
||||||
|
PointerFocusTarget::WlSurface(popup.wl_surface().clone())
|
||||||
|
}
|
||||||
|
KeyboardFocusTarget::LayerSurface(layer) => {
|
||||||
|
PointerFocusTarget::WlSurface(layer.wl_surface().clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/grab.rs
16
src/grab.rs
|
@ -4,26 +4,20 @@ pub mod move_grab;
|
||||||
pub mod resize_grab;
|
pub mod resize_grab;
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
input::{
|
input::pointer::{GrabStartData, PointerHandle},
|
||||||
pointer::{GrabStartData, PointerHandle},
|
|
||||||
SeatHandler,
|
|
||||||
},
|
|
||||||
reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource},
|
reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource},
|
||||||
utils::Serial,
|
utils::Serial,
|
||||||
wayland::seat::WaylandFocus,
|
wayland::seat::WaylandFocus,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::focus::FocusTarget;
|
use crate::state::State;
|
||||||
|
|
||||||
/// Returns the [GrabStartData] from a pointer grab, if any.
|
/// Returns the [GrabStartData] from a pointer grab, if any.
|
||||||
pub fn pointer_grab_start_data<S>(
|
pub fn pointer_grab_start_data(
|
||||||
pointer: &PointerHandle<S>,
|
pointer: &PointerHandle<State>,
|
||||||
surface: &WlSurface,
|
surface: &WlSurface,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
) -> Option<GrabStartData<S>>
|
) -> Option<GrabStartData<State>> {
|
||||||
where
|
|
||||||
S: SeatHandler<PointerFocus = FocusTarget> + 'static,
|
|
||||||
{
|
|
||||||
tracing::debug!("start of pointer_grab_start_data");
|
tracing::debug!("start of pointer_grab_start_data");
|
||||||
if !pointer.has_grab(serial) {
|
if !pointer.has_grab(serial) {
|
||||||
tracing::debug!("pointer doesn't have grab");
|
tracing::debug!("pointer doesn't have grab");
|
||||||
|
|
|
@ -6,14 +6,13 @@ use smithay::{
|
||||||
// | input::keyboard
|
// | input::keyboard
|
||||||
input::{
|
input::{
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, ButtonEvent, GrabStartData, MotionEvent, PointerInnerHandle,
|
AxisFrame, ButtonEvent, Focus, GrabStartData, MotionEvent, PointerGrab,
|
||||||
RelativeMotionEvent,
|
PointerInnerHandle, RelativeMotionEvent,
|
||||||
},
|
},
|
||||||
pointer::{Focus, PointerGrab},
|
|
||||||
Seat, SeatHandler,
|
Seat, SeatHandler,
|
||||||
},
|
},
|
||||||
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||||
utils::{IsAlive, Logical, Point, Rectangle},
|
utils::{IsAlive, Logical, Point, Rectangle, Serial},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -51,13 +50,16 @@ impl PointerGrab<State> for MoveSurfaceGrab {
|
||||||
}
|
}
|
||||||
|
|
||||||
state.space.raise_element(&self.window, false);
|
state.space.raise_element(&self.window, false);
|
||||||
if let WindowElement::X11(surface) = &self.window {
|
if let Some(surface) = self.window.x11_surface() {
|
||||||
state
|
// INFO: can you raise OR windows or no idk
|
||||||
.xwm
|
if !surface.is_override_redirect() {
|
||||||
.as_mut()
|
state
|
||||||
.expect("no xwm")
|
.xwm
|
||||||
.raise_window(surface)
|
.as_mut()
|
||||||
.expect("failed to raise x11 win");
|
.expect("no xwm")
|
||||||
|
.raise_window(surface)
|
||||||
|
.expect("failed to raise x11 win");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_tiled = self
|
let is_tiled = self
|
||||||
|
@ -136,12 +138,14 @@ impl PointerGrab<State> for MoveSurfaceGrab {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if let WindowElement::X11(surface) = &self.window {
|
if let Some(surface) = self.window.x11_surface() {
|
||||||
let geo = surface.geometry();
|
if !surface.is_override_redirect() {
|
||||||
let new_geo = Rectangle::from_loc_and_size(new_loc, geo.size);
|
let geo = surface.geometry();
|
||||||
surface
|
let new_geo = Rectangle::from_loc_and_size(new_loc, geo.size);
|
||||||
.configure(new_geo)
|
surface
|
||||||
.expect("failed to configure x11 win");
|
.configure(new_geo)
|
||||||
|
.expect("failed to configure x11 win");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let outputs = state.space.outputs_for_element(&self.window);
|
let outputs = state.space.outputs_for_element(&self.window);
|
||||||
|
@ -265,7 +269,7 @@ pub fn move_request_client(
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
surface: &WlSurface,
|
surface: &WlSurface,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
serial: smithay::utils::Serial,
|
serial: Serial,
|
||||||
button_used: u32,
|
button_used: u32,
|
||||||
) {
|
) {
|
||||||
let pointer = seat.get_pointer().expect("seat had no pointer");
|
let pointer = seat.get_pointer().expect("seat had no pointer");
|
||||||
|
@ -298,7 +302,7 @@ pub fn move_request_server(
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
surface: &WlSurface,
|
surface: &WlSurface,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
serial: smithay::utils::Serial,
|
serial: Serial,
|
||||||
button_used: u32,
|
button_used: u32,
|
||||||
) {
|
) {
|
||||||
let pointer = seat.get_pointer().expect("seat had no pointer");
|
let pointer = seat.get_pointer().expect("seat had no pointer");
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::space::SpaceElement,
|
desktop::{space::SpaceElement, WindowSurface},
|
||||||
input::{
|
input::{
|
||||||
pointer::{AxisFrame, ButtonEvent, Focus, GrabStartData, PointerGrab, PointerInnerHandle},
|
pointer::{AxisFrame, ButtonEvent, Focus, GrabStartData, PointerGrab, PointerInnerHandle},
|
||||||
Seat, SeatHandler,
|
Seat, SeatHandler,
|
||||||
},
|
},
|
||||||
reexports::{
|
reexports::{
|
||||||
wayland_protocols::xdg::shell::server::xdg_toplevel::{self},
|
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
||||||
wayland_server::protocol::wl_surface::WlSurface,
|
wayland_server::protocol::wl_surface::WlSurface,
|
||||||
},
|
},
|
||||||
utils::{IsAlive, Logical, Point, Rectangle, Size},
|
utils::{IsAlive, Logical, Point, Rectangle, Size},
|
||||||
wayland::{compositor, shell::xdg::SurfaceCachedState},
|
wayland::{compositor, seat::WaylandFocus, shell::xdg::SurfaceCachedState},
|
||||||
xwayland,
|
xwayland,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -158,28 +158,26 @@ impl PointerGrab<State> for ResizeSurfaceGrab {
|
||||||
new_window_height.clamp(min_height, max_height),
|
new_window_height.clamp(min_height, max_height),
|
||||||
));
|
));
|
||||||
|
|
||||||
match &self.window {
|
match self.window.underlying_surface() {
|
||||||
WindowElement::Wayland(window) => {
|
WindowSurface::Wayland(toplevel) => {
|
||||||
let toplevel_surface = window.toplevel();
|
toplevel.with_pending_state(|state| {
|
||||||
|
|
||||||
toplevel_surface.with_pending_state(|state| {
|
|
||||||
state.states.set(xdg_toplevel::State::Resizing);
|
state.states.set(xdg_toplevel::State::Resizing);
|
||||||
state.size = Some(self.last_window_size);
|
state.size = Some(self.last_window_size);
|
||||||
});
|
});
|
||||||
|
|
||||||
toplevel_surface.send_pending_configure();
|
toplevel.send_pending_configure();
|
||||||
}
|
}
|
||||||
WindowElement::X11(surface) => {
|
WindowSurface::X11(surface) => {
|
||||||
let loc = data
|
if !surface.is_override_redirect() {
|
||||||
.space
|
let loc = data
|
||||||
.element_location(&self.window)
|
.space
|
||||||
.expect("failed to get x11 win loc");
|
.element_location(&self.window)
|
||||||
surface
|
.expect("failed to get x11 win loc");
|
||||||
.configure(Rectangle::from_loc_and_size(loc, self.last_window_size))
|
surface
|
||||||
.expect("failed to configure x11 win");
|
.configure(Rectangle::from_loc_and_size(loc, self.last_window_size))
|
||||||
|
.expect("failed to configure x11 win");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
WindowElement::X11OverrideRedirect(_) => (),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,17 +206,16 @@ impl PointerGrab<State> for ResizeSurfaceGrab {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match &self.window {
|
match self.window.underlying_surface() {
|
||||||
WindowElement::Wayland(window) => {
|
WindowSurface::Wayland(toplevel) => {
|
||||||
let toplevel_surface = window.toplevel();
|
toplevel.with_pending_state(|state| {
|
||||||
toplevel_surface.with_pending_state(|state| {
|
|
||||||
state.states.unset(xdg_toplevel::State::Resizing);
|
state.states.unset(xdg_toplevel::State::Resizing);
|
||||||
state.size = Some(self.last_window_size);
|
state.size = Some(self.last_window_size);
|
||||||
});
|
});
|
||||||
|
|
||||||
toplevel_surface.send_pending_configure();
|
toplevel.send_pending_configure();
|
||||||
|
|
||||||
toplevel_surface.wl_surface().with_state(|state| {
|
toplevel.wl_surface().with_state(|state| {
|
||||||
// TODO: validate resize state
|
// TODO: validate resize state
|
||||||
state.resize_state = ResizeSurfaceState::WaitingForLastCommit {
|
state.resize_state = ResizeSurfaceState::WaitingForLastCommit {
|
||||||
edges: self.edges,
|
edges: self.edges,
|
||||||
|
@ -226,7 +223,10 @@ impl PointerGrab<State> for ResizeSurfaceGrab {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
WindowElement::X11(surface) => {
|
WindowSurface::X11(surface) => {
|
||||||
|
if surface.is_override_redirect() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let Some(surface) = surface.wl_surface() else { return };
|
let Some(surface) = surface.wl_surface() else { return };
|
||||||
surface.with_state(|state| {
|
surface.with_state(|state| {
|
||||||
state.resize_state = ResizeSurfaceState::WaitingForLastCommit {
|
state.resize_state = ResizeSurfaceState::WaitingForLastCommit {
|
||||||
|
@ -235,8 +235,6 @@ impl PointerGrab<State> for ResizeSurfaceGrab {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
WindowElement::X11OverrideRedirect(_) => (),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -418,12 +416,14 @@ pub fn handle_commit(state: &mut State, surface: &WlSurface) -> Option<()> {
|
||||||
if new_loc.x.is_some() || new_loc.y.is_some() {
|
if new_loc.x.is_some() || new_loc.y.is_some() {
|
||||||
state.space.map_element(window.clone(), window_loc, false);
|
state.space.map_element(window.clone(), window_loc, false);
|
||||||
|
|
||||||
if let WindowElement::X11(surface) = window {
|
if let Some(surface) = window.x11_surface() {
|
||||||
let geo = surface.geometry();
|
if !surface.is_override_redirect() {
|
||||||
let new_geo = Rectangle::from_loc_and_size(window_loc, geo.size);
|
let geo = surface.geometry();
|
||||||
surface
|
let new_geo = Rectangle::from_loc_and_size(window_loc, geo.size);
|
||||||
.configure(new_geo)
|
surface
|
||||||
.expect("failed to configure x11 win");
|
.configure(new_geo)
|
||||||
|
.expect("failed to configure x11 win");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,12 +458,14 @@ pub fn resize_request_client(
|
||||||
.expect("resize request called on unmapped window");
|
.expect("resize request called on unmapped window");
|
||||||
let initial_window_size = window.geometry().size;
|
let initial_window_size = window.geometry().size;
|
||||||
|
|
||||||
if let Some(WindowElement::Wayland(window)) = state.window_for_surface(surface) {
|
if let Some(window) = state.window_for_surface(surface) {
|
||||||
window.toplevel().with_pending_state(|state| {
|
if let Some(toplevel) = window.toplevel() {
|
||||||
state.states.set(xdg_toplevel::State::Resizing);
|
toplevel.with_pending_state(|state| {
|
||||||
});
|
state.states.set(xdg_toplevel::State::Resizing);
|
||||||
|
});
|
||||||
|
|
||||||
window.toplevel().send_pending_configure();
|
toplevel.send_pending_configure();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let grab = ResizeSurfaceGrab::start(
|
let grab = ResizeSurfaceGrab::start(
|
||||||
|
@ -506,12 +508,14 @@ pub fn resize_request_server(
|
||||||
.expect("resize request called on unmapped window");
|
.expect("resize request called on unmapped window");
|
||||||
let initial_window_size = window.geometry().size;
|
let initial_window_size = window.geometry().size;
|
||||||
|
|
||||||
if let Some(WindowElement::Wayland(window)) = state.window_for_surface(surface) {
|
if let Some(window) = state.window_for_surface(surface) {
|
||||||
window.toplevel().with_pending_state(|state| {
|
if let Some(toplevel) = window.toplevel() {
|
||||||
state.states.set(xdg_toplevel::State::Resizing);
|
toplevel.with_pending_state(|state| {
|
||||||
});
|
state.states.set(xdg_toplevel::State::Resizing);
|
||||||
|
});
|
||||||
|
|
||||||
window.toplevel().send_pending_configure();
|
toplevel.send_pending_configure();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let start_data = smithay::input::pointer::GrabStartData {
|
let start_data = smithay::input::pointer::GrabStartData {
|
||||||
|
|
|
@ -58,9 +58,8 @@ use smithay::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
focus::FocusTarget,
|
focus::{keyboard::KeyboardFocusTarget, pointer::PointerFocusTarget},
|
||||||
state::{ClientState, State, WithState},
|
state::{ClientState, State, WithState},
|
||||||
window::WindowElement,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
impl BufferHandler for State {
|
impl BufferHandler for State {
|
||||||
|
@ -107,9 +106,10 @@ impl CompositorHandler for State {
|
||||||
fn commit(&mut self, surface: &WlSurface) {
|
fn commit(&mut self, surface: &WlSurface) {
|
||||||
tracing::trace!("commit on surface {surface:?}");
|
tracing::trace!("commit on surface {surface:?}");
|
||||||
|
|
||||||
|
utils::on_commit_buffer_handler::<State>(surface);
|
||||||
|
|
||||||
X11Wm::commit_hook::<State>(surface);
|
X11Wm::commit_hook::<State>(surface);
|
||||||
|
|
||||||
utils::on_commit_buffer_handler::<State>(surface);
|
|
||||||
self.backend.early_import(surface);
|
self.backend.early_import(surface);
|
||||||
|
|
||||||
let mut root = surface.clone();
|
let mut root = surface.clone();
|
||||||
|
@ -118,10 +118,10 @@ impl CompositorHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !compositor::is_sync_subsurface(surface) {
|
if !compositor::is_sync_subsurface(surface) {
|
||||||
if let Some(win @ WindowElement::Wayland(window)) = &self.window_for_surface(&root) {
|
if let Some(window) = self.window_for_surface(&root) {
|
||||||
window.on_commit();
|
window.on_commit();
|
||||||
if let Some(loc) = win.with_state(|state| state.target_loc.take()) {
|
if let Some(loc) = window.with_state(|state| state.target_loc.take()) {
|
||||||
self.space.map_element(win.clone(), loc, false);
|
self.space.map_element(window.clone(), loc, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -149,7 +149,7 @@ impl CompositorHandler for State {
|
||||||
self.output_focus_stack.current_focus(),
|
self.output_focus_stack.current_focus(),
|
||||||
self.space.outputs().next(),
|
self.space.outputs().next(),
|
||||||
) {
|
) {
|
||||||
tracing::debug!("PLACING TOPLEVEL");
|
tracing::debug!("Placing toplevel");
|
||||||
new_window.place_on_output(output);
|
new_window.place_on_output(output);
|
||||||
output.with_state(|state| state.focus_stack.set_focus(new_window.clone()));
|
output.with_state(|state| state.focus_stack.set_focus(new_window.clone()));
|
||||||
}
|
}
|
||||||
|
@ -176,26 +176,13 @@ impl CompositorHandler for State {
|
||||||
.expect("Seat had no keyboard") // FIXME: actually handle error
|
.expect("Seat had no keyboard") // FIXME: actually handle error
|
||||||
.set_focus(
|
.set_focus(
|
||||||
state,
|
state,
|
||||||
Some(FocusTarget::Window(new_window)),
|
Some(KeyboardFocusTarget::Window(new_window)),
|
||||||
SERIAL_COUNTER.next_serial(),
|
SERIAL_COUNTER.next_serial(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
} else if let WindowElement::Wayland(window) = &new_window {
|
} else if new_window.toplevel().is_some() {
|
||||||
window.on_commit();
|
new_window.on_commit();
|
||||||
let initial_configure_sent = compositor::with_states(surface, |states| {
|
ensure_initial_configure(surface, self);
|
||||||
states
|
|
||||||
.data_map
|
|
||||||
.get::<XdgToplevelSurfaceData>()
|
|
||||||
.expect("XdgToplevelSurfaceData wasn't in surface's data map")
|
|
||||||
.lock()
|
|
||||||
.expect("Failed to lock Mutex<XdgToplevelSurfaceData>")
|
|
||||||
.initial_configure_sent
|
|
||||||
});
|
|
||||||
|
|
||||||
if !initial_configure_sent {
|
|
||||||
tracing::debug!("Initial configure");
|
|
||||||
window.toplevel().send_configure();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -266,8 +253,11 @@ impl CompositorHandler for State {
|
||||||
delegate_compositor!(State);
|
delegate_compositor!(State);
|
||||||
|
|
||||||
fn ensure_initial_configure(surface: &WlSurface, state: &mut State) {
|
fn ensure_initial_configure(surface: &WlSurface, state: &mut State) {
|
||||||
if let Some(window) = state.window_for_surface(surface) {
|
if let (Some(window), _) | (None, Some(window)) = (
|
||||||
if let WindowElement::Wayland(window) = &window {
|
state.window_for_surface(surface),
|
||||||
|
state.new_window_for_surface(surface),
|
||||||
|
) {
|
||||||
|
if let Some(toplevel) = window.toplevel() {
|
||||||
let initial_configure_sent = compositor::with_states(surface, |states| {
|
let initial_configure_sent = compositor::with_states(surface, |states| {
|
||||||
states
|
states
|
||||||
.data_map
|
.data_map
|
||||||
|
@ -280,7 +270,7 @@ fn ensure_initial_configure(surface: &WlSurface, state: &mut State) {
|
||||||
|
|
||||||
if !initial_configure_sent {
|
if !initial_configure_sent {
|
||||||
tracing::debug!("Initial configure");
|
tracing::debug!("Initial configure");
|
||||||
window.toplevel().send_configure();
|
toplevel.send_configure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -404,8 +394,9 @@ impl DataControlHandler for State {
|
||||||
delegate_data_control!(State);
|
delegate_data_control!(State);
|
||||||
|
|
||||||
impl SeatHandler for State {
|
impl SeatHandler for State {
|
||||||
type KeyboardFocus = FocusTarget;
|
type KeyboardFocus = KeyboardFocusTarget;
|
||||||
type PointerFocus = FocusTarget;
|
type PointerFocus = PointerFocusTarget;
|
||||||
|
type TouchFocus = PointerFocusTarget;
|
||||||
|
|
||||||
fn seat_state(&mut self) -> &mut SeatState<Self> {
|
fn seat_state(&mut self) -> &mut SeatState<Self> {
|
||||||
&mut self.seat_state
|
&mut self.seat_state
|
||||||
|
|
|
@ -17,13 +17,16 @@ use smithay::{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
utils::{Logical, Point, Rectangle, Serial, SERIAL_COUNTER},
|
utils::{Logical, Point, Rectangle, Serial, SERIAL_COUNTER},
|
||||||
wayland::shell::xdg::{
|
wayland::{
|
||||||
PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState,
|
seat::WaylandFocus,
|
||||||
|
shell::xdg::{
|
||||||
|
PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
focus::FocusTarget,
|
focus::keyboard::KeyboardFocusTarget,
|
||||||
state::{State, WithState},
|
state::{State, WithState},
|
||||||
window::WindowElement,
|
window::WindowElement,
|
||||||
};
|
};
|
||||||
|
@ -41,65 +44,8 @@ impl XdgShellHandler for State {
|
||||||
state.states.set(xdg_toplevel::State::TiledRight);
|
state.states.set(xdg_toplevel::State::TiledRight);
|
||||||
});
|
});
|
||||||
|
|
||||||
let window = WindowElement::Wayland(Window::new(surface.clone()));
|
let window = WindowElement::new(Window::new_wayland_window(surface.clone()));
|
||||||
self.new_windows.push(window);
|
self.new_windows.push(window);
|
||||||
|
|
||||||
// if let (Some(output), _) | (None, Some(output)) = (
|
|
||||||
// &self.focus_state.focused_output,
|
|
||||||
// self.space.outputs().next(),
|
|
||||||
// ) {
|
|
||||||
// tracing::debug!("PLACING TOPLEVEL");
|
|
||||||
// window.place_on_output(output);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // note to self: don't reorder this
|
|
||||||
// // TODO: fix it so that reordering this doesn't break stuff
|
|
||||||
// self.windows.push(window.clone());
|
|
||||||
//
|
|
||||||
// self.space.map_element(window.clone(), (0, 0), true);
|
|
||||||
//
|
|
||||||
// let win_clone = window.clone();
|
|
||||||
//
|
|
||||||
// // Let the initial configure happen before updating the windows
|
|
||||||
// self.schedule(
|
|
||||||
// move |_data| {
|
|
||||||
// if let WindowElement::Wayland(window) = &win_clone {
|
|
||||||
// let initial_configure_sent =
|
|
||||||
// compositor::with_states(window.toplevel().wl_surface(), |states| {
|
|
||||||
// states
|
|
||||||
// .data_map
|
|
||||||
// .get::<smithay::wayland::shell::xdg::XdgToplevelSurfaceData>()
|
|
||||||
// .expect("XdgToplevelSurfaceData wasn't in surface's data map")
|
|
||||||
// .lock()
|
|
||||||
// .expect("Failed to lock Mutex<XdgToplevelSurfaceData>")
|
|
||||||
// .initial_configure_sent
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// initial_configure_sent
|
|
||||||
// } else {
|
|
||||||
// true
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// |data| {
|
|
||||||
// data.state.apply_window_rules(&window);
|
|
||||||
//
|
|
||||||
// if let Some(focused_output) = data.state.focus_state.focused_output.clone() {
|
|
||||||
// data.state.update_windows(&focused_output);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// data.state.loop_handle.insert_idle(move |data| {
|
|
||||||
// data.state
|
|
||||||
// .seat
|
|
||||||
// .get_keyboard()
|
|
||||||
// .expect("Seat had no keyboard") // FIXME: actually handle error
|
|
||||||
// .set_focus(
|
|
||||||
// &mut data.state,
|
|
||||||
// Some(FocusTarget::Window(window)),
|
|
||||||
// SERIAL_COUNTER.next_serial(),
|
|
||||||
// );
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toplevel_destroyed(&mut self, surface: ToplevelSurface) {
|
fn toplevel_destroyed(&mut self, surface: ToplevelSurface) {
|
||||||
|
@ -132,14 +78,16 @@ impl XdgShellHandler for State {
|
||||||
|
|
||||||
if let Some(output) = window.output(self) {
|
if let Some(output) = window.output(self) {
|
||||||
self.update_windows(&output);
|
self.update_windows(&output);
|
||||||
let focus = self.focused_window(&output).map(FocusTarget::Window);
|
let focus = self
|
||||||
if let Some(FocusTarget::Window(win)) = &focus {
|
.focused_window(&output)
|
||||||
|
.map(KeyboardFocusTarget::Window);
|
||||||
|
if let Some(KeyboardFocusTarget::Window(win)) = &focus {
|
||||||
tracing::debug!("Focusing on prev win");
|
tracing::debug!("Focusing on prev win");
|
||||||
// TODO:
|
// TODO:
|
||||||
self.space.raise_element(win, true);
|
self.space.raise_element(win, true);
|
||||||
self.z_index_stack.set_focus(win.clone());
|
self.z_index_stack.set_focus(win.clone());
|
||||||
if let WindowElement::Wayland(win) = &win {
|
if let Some(toplevel) = win.toplevel() {
|
||||||
win.toplevel().send_configure();
|
toplevel.send_configure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.seat
|
self.seat
|
||||||
|
@ -692,13 +640,13 @@ impl XdgShellHandler for State {
|
||||||
let popup_kind = PopupKind::Xdg(surface);
|
let popup_kind = PopupKind::Xdg(surface);
|
||||||
if let Some(root) = find_popup_root_surface(&popup_kind).ok().and_then(|root| {
|
if let Some(root) = find_popup_root_surface(&popup_kind).ok().and_then(|root| {
|
||||||
self.window_for_surface(&root)
|
self.window_for_surface(&root)
|
||||||
.map(FocusTarget::Window)
|
.map(KeyboardFocusTarget::Window)
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
self.space.outputs().find_map(|op| {
|
self.space.outputs().find_map(|op| {
|
||||||
layer_map_for_output(op)
|
layer_map_for_output(op)
|
||||||
.layer_for_surface(&root, WindowSurfaceType::TOPLEVEL)
|
.layer_for_surface(&root, WindowSurfaceType::TOPLEVEL)
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(FocusTarget::LayerSurface)
|
.map(KeyboardFocusTarget::LayerSurface)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}) {
|
}) {
|
||||||
|
@ -733,27 +681,6 @@ impl XdgShellHandler for State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn ack_configure(&mut self, surface: WlSurface, configure: Configure) {
|
|
||||||
// if let Some(window) = self.window_for_surface(&surface) {
|
|
||||||
// if let LocationRequestState::Requested(serial, new_loc) =
|
|
||||||
// window.with_state(|state| state.loc_request_state.clone())
|
|
||||||
// {
|
|
||||||
// match &configure {
|
|
||||||
// Configure::Toplevel(configure) => {
|
|
||||||
// if configure.serial >= serial {
|
|
||||||
// tracing::debug!("acked configure, new loc is {:?}", new_loc);
|
|
||||||
// window.with_state(|state| {
|
|
||||||
// state.loc_request_state =
|
|
||||||
// LocationRequestState::Acknowledged(new_loc);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// Configure::Popup(_) => todo!(),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn fullscreen_request(&mut self, surface: ToplevelSurface, mut wl_output: Option<WlOutput>) {
|
fn fullscreen_request(&mut self, surface: ToplevelSurface, mut wl_output: Option<WlOutput>) {
|
||||||
if !surface
|
if !surface
|
||||||
.current_state()
|
.current_state()
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
|
desktop::Window,
|
||||||
utils::{Logical, Point, Rectangle, SERIAL_COUNTER},
|
utils::{Logical, Point, Rectangle, SERIAL_COUNTER},
|
||||||
wayland::{
|
wayland::{
|
||||||
selection::data_device::{
|
seat::WaylandFocus,
|
||||||
clear_data_device_selection, current_data_device_selection_userdata,
|
|
||||||
request_data_device_client_selection, set_data_device_selection,
|
|
||||||
},
|
|
||||||
selection::{
|
selection::{
|
||||||
|
data_device::{
|
||||||
|
clear_data_device_selection, current_data_device_selection_userdata,
|
||||||
|
request_data_device_client_selection, set_data_device_selection,
|
||||||
|
},
|
||||||
primary_selection::{
|
primary_selection::{
|
||||||
clear_primary_selection, current_primary_selection_userdata,
|
clear_primary_selection, current_primary_selection_userdata,
|
||||||
request_primary_client_selection, set_primary_selection,
|
request_primary_client_selection, set_primary_selection,
|
||||||
|
@ -22,7 +24,7 @@ use smithay::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
focus::FocusTarget,
|
focus::keyboard::KeyboardFocusTarget,
|
||||||
state::{State, WithState},
|
state::{State, WithState},
|
||||||
window::{window_state::FloatingOrTiled, WindowElement},
|
window::{window_state::FloatingOrTiled, WindowElement},
|
||||||
};
|
};
|
||||||
|
@ -36,12 +38,12 @@ impl XwmHandler for State {
|
||||||
|
|
||||||
fn new_override_redirect_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
|
fn new_override_redirect_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
|
||||||
|
|
||||||
fn map_window_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
fn map_window_request(&mut self, _xwm: XwmId, surface: X11Surface) {
|
||||||
tracing::trace!("map_window_request");
|
tracing::trace!("map_window_request");
|
||||||
|
|
||||||
assert!(!window.is_override_redirect());
|
assert!(!surface.is_override_redirect());
|
||||||
|
|
||||||
let window = WindowElement::X11(window);
|
let window = WindowElement::new(Window::new_x11_window(surface));
|
||||||
self.space.map_element(window.clone(), (0, 0), true);
|
self.space.map_element(window.clone(), (0, 0), true);
|
||||||
let bbox = self
|
let bbox = self
|
||||||
.space
|
.space
|
||||||
|
@ -70,7 +72,7 @@ impl XwmHandler for State {
|
||||||
)
|
)
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
let WindowElement::X11(surface) = &window else {
|
let Some(surface) = window.x11_surface() else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -116,20 +118,20 @@ impl XwmHandler for State {
|
||||||
.expect("Seat had no keyboard") // FIXME: actually handle error
|
.expect("Seat had no keyboard") // FIXME: actually handle error
|
||||||
.set_focus(
|
.set_focus(
|
||||||
state,
|
state,
|
||||||
Some(FocusTarget::Window(window)),
|
Some(KeyboardFocusTarget::Window(window)),
|
||||||
SERIAL_COUNTER.next_serial(),
|
SERIAL_COUNTER.next_serial(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mapped_override_redirect_window(&mut self, _xwm: XwmId, window: X11Surface) {
|
fn mapped_override_redirect_window(&mut self, _xwm: XwmId, surface: X11Surface) {
|
||||||
tracing::trace!("mapped_override_redirect_window");
|
tracing::trace!("mapped_override_redirect_window");
|
||||||
|
|
||||||
assert!(window.is_override_redirect());
|
assert!(surface.is_override_redirect());
|
||||||
|
|
||||||
let loc = window.geometry().loc;
|
let loc = surface.geometry().loc;
|
||||||
|
|
||||||
let window = WindowElement::X11OverrideRedirect(window);
|
let window = WindowElement::new(Window::new_x11_window(surface));
|
||||||
|
|
||||||
self.windows.push(window.clone());
|
self.windows.push(window.clone());
|
||||||
self.z_index_stack.set_focus(window.clone());
|
self.z_index_stack.set_focus(window.clone());
|
||||||
|
@ -139,18 +141,20 @@ impl XwmHandler for State {
|
||||||
self.space.outputs().next(),
|
self.space.outputs().next(),
|
||||||
) {
|
) {
|
||||||
window.place_on_output(output);
|
window.place_on_output(output);
|
||||||
|
// FIXME: setting focus here may possibly muck things up
|
||||||
|
// | or maybe they won't idk
|
||||||
output.with_state(|state| state.focus_stack.set_focus(window.clone()))
|
output.with_state(|state| state.focus_stack.set_focus(window.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.space.map_element(window, loc, true);
|
self.space.map_element(window, loc, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unmapped_window(&mut self, _xwm: XwmId, window: X11Surface) {
|
fn unmapped_window(&mut self, _xwm: XwmId, surface: X11Surface) {
|
||||||
for output in self.space.outputs() {
|
for output in self.space.outputs() {
|
||||||
output.with_state(|state| {
|
output.with_state(|state| {
|
||||||
state.focus_stack.stack.retain(|win| {
|
state.focus_stack.stack.retain(|win| {
|
||||||
win.wl_surface()
|
win.wl_surface()
|
||||||
.is_some_and(|surf| Some(surf) != window.wl_surface())
|
.is_some_and(|surf| Some(surf) != surface.wl_surface())
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -158,7 +162,7 @@ impl XwmHandler for State {
|
||||||
let win = self
|
let win = self
|
||||||
.space
|
.space
|
||||||
.elements()
|
.elements()
|
||||||
.find(|elem| matches!(elem, WindowElement::X11(surface) if surface == &window))
|
.find(|elem| matches!(elem.x11_surface(), Some(surf) if surf == &surface))
|
||||||
.cloned();
|
.cloned();
|
||||||
|
|
||||||
if let Some(win) = win {
|
if let Some(win) = win {
|
||||||
|
@ -173,13 +177,15 @@ impl XwmHandler for State {
|
||||||
if let Some(output) = win.output(self) {
|
if let Some(output) = win.output(self) {
|
||||||
self.update_windows(&output);
|
self.update_windows(&output);
|
||||||
|
|
||||||
let focus = self.focused_window(&output).map(FocusTarget::Window);
|
let focus = self
|
||||||
|
.focused_window(&output)
|
||||||
|
.map(KeyboardFocusTarget::Window);
|
||||||
|
|
||||||
if let Some(FocusTarget::Window(win)) = &focus {
|
if let Some(KeyboardFocusTarget::Window(win)) = &focus {
|
||||||
self.space.raise_element(win, true);
|
self.space.raise_element(win, true);
|
||||||
self.z_index_stack.set_focus(win.clone());
|
self.z_index_stack.set_focus(win.clone());
|
||||||
if let WindowElement::Wayland(win) = &win {
|
if let Some(toplevel) = win.toplevel() {
|
||||||
win.toplevel().send_configure();
|
toplevel.send_configure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,18 +198,18 @@ impl XwmHandler for State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !window.is_override_redirect() {
|
if !surface.is_override_redirect() {
|
||||||
tracing::debug!("set mapped to false");
|
tracing::debug!("set mapped to false");
|
||||||
window.set_mapped(false).expect("failed to unmap x11 win");
|
surface.set_mapped(false).expect("failed to unmap x11 win");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroyed_window(&mut self, _xwm: XwmId, window: X11Surface) {
|
fn destroyed_window(&mut self, _xwm: XwmId, surface: X11Surface) {
|
||||||
for output in self.space.outputs() {
|
for output in self.space.outputs() {
|
||||||
output.with_state(|state| {
|
output.with_state(|state| {
|
||||||
state.focus_stack.stack.retain(|win| {
|
state.focus_stack.stack.retain(|win| {
|
||||||
win.wl_surface()
|
win.wl_surface()
|
||||||
.is_some_and(|surf| Some(surf) != window.wl_surface())
|
.is_some_and(|surf| Some(surf) != surface.wl_surface())
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -213,10 +219,8 @@ impl XwmHandler for State {
|
||||||
.iter()
|
.iter()
|
||||||
.find(|elem| {
|
.find(|elem| {
|
||||||
matches!(
|
matches!(
|
||||||
elem,
|
elem.x11_surface(),
|
||||||
WindowElement::X11(surface)
|
Some(surf) if surf.wl_surface() == surface.wl_surface()
|
||||||
| WindowElement::X11OverrideRedirect(surface)
|
|
||||||
if surface.wl_surface() == window.wl_surface()
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.cloned();
|
.cloned();
|
||||||
|
@ -236,13 +240,15 @@ impl XwmHandler for State {
|
||||||
if let Some(output) = win.output(self) {
|
if let Some(output) = win.output(self) {
|
||||||
self.update_windows(&output);
|
self.update_windows(&output);
|
||||||
|
|
||||||
let focus = self.focused_window(&output).map(FocusTarget::Window);
|
let focus = self
|
||||||
|
.focused_window(&output)
|
||||||
|
.map(KeyboardFocusTarget::Window);
|
||||||
|
|
||||||
if let Some(FocusTarget::Window(win)) = &focus {
|
if let Some(KeyboardFocusTarget::Window(win)) = &focus {
|
||||||
self.space.raise_element(win, true);
|
self.space.raise_element(win, true);
|
||||||
self.z_index_stack.set_focus(win.clone());
|
self.z_index_stack.set_focus(win.clone());
|
||||||
if let WindowElement::Wayland(win) = &win {
|
if let Some(toplevel) = win.toplevel() {
|
||||||
win.toplevel().send_configure();
|
toplevel.send_configure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,14 +289,14 @@ impl XwmHandler for State {
|
||||||
fn configure_notify(
|
fn configure_notify(
|
||||||
&mut self,
|
&mut self,
|
||||||
_xwm: XwmId,
|
_xwm: XwmId,
|
||||||
window: X11Surface,
|
surface: X11Surface,
|
||||||
geometry: Rectangle<i32, Logical>,
|
geometry: Rectangle<i32, Logical>,
|
||||||
_above: Option<smithay::reexports::x11rb::protocol::xproto::Window>,
|
_above: Option<smithay::reexports::x11rb::protocol::xproto::Window>,
|
||||||
) {
|
) {
|
||||||
let Some(win) = self
|
let Some(win) = self
|
||||||
.space
|
.space
|
||||||
.elements()
|
.elements()
|
||||||
.find(|elem| matches!(elem, WindowElement::X11(surface) if surface == &window))
|
.find(|elem| matches!(elem.x11_surface(), Some(surf) if surf == &surface))
|
||||||
.cloned()
|
.cloned()
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
|
@ -409,11 +415,12 @@ impl XwmHandler for State {
|
||||||
.get_keyboard()
|
.get_keyboard()
|
||||||
.and_then(|kb| kb.current_focus())
|
.and_then(|kb| kb.current_focus())
|
||||||
.is_some_and(|focus| {
|
.is_some_and(|focus| {
|
||||||
if let FocusTarget::Window(WindowElement::X11(surface)) = focus {
|
if let KeyboardFocusTarget::Window(window) = focus {
|
||||||
surface.xwm_id().expect("x11surface had no xwm id") == xwm
|
if let Some(surface) = window.x11_surface() {
|
||||||
} else {
|
return surface.xwm_id().expect("x11surface had no xwm id") == xwm;
|
||||||
false
|
}
|
||||||
}
|
}
|
||||||
|
false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
79
src/input.rs
79
src/input.rs
|
@ -4,7 +4,7 @@ pub mod libinput;
|
||||||
|
|
||||||
use std::{collections::HashMap, mem::Discriminant};
|
use std::{collections::HashMap, mem::Discriminant};
|
||||||
|
|
||||||
use crate::{focus::FocusTarget, state::WithState, window::WindowElement};
|
use crate::{focus::pointer::PointerFocusTarget, state::WithState};
|
||||||
use pinnacle_api_defs::pinnacle::input::v0alpha1::{
|
use pinnacle_api_defs::pinnacle::input::v0alpha1::{
|
||||||
set_libinput_setting_request::Setting, set_mousebind_request, SetKeybindResponse,
|
set_libinput_setting_request::Setting, set_mousebind_request, SetKeybindResponse,
|
||||||
SetMousebindResponse,
|
SetMousebindResponse,
|
||||||
|
@ -14,7 +14,7 @@ use smithay::{
|
||||||
AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputBackend, InputEvent,
|
AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputBackend, InputEvent,
|
||||||
KeyState, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, PointerMotionEvent,
|
KeyState, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, PointerMotionEvent,
|
||||||
},
|
},
|
||||||
desktop::{layer_map_for_output, space::SpaceElement},
|
desktop::{layer_map_for_output, space::SpaceElement, WindowSurfaceType},
|
||||||
input::{
|
input::{
|
||||||
keyboard::{keysyms, FilterResult, ModifiersState},
|
keyboard::{keysyms, FilterResult, ModifiersState},
|
||||||
pointer::{AxisFrame, ButtonEvent, MotionEvent, RelativeMotionEvent},
|
pointer::{AxisFrame, ButtonEvent, MotionEvent, RelativeMotionEvent},
|
||||||
|
@ -148,8 +148,11 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the [`FocusTarget`] under `point`.
|
/// Get the [`PointerFocusTarget`] under `point` along with its origin in the global space.
|
||||||
pub fn focus_target_under<P>(&self, point: P) -> Option<(FocusTarget, Point<i32, Logical>)>
|
pub fn pointer_focus_target_under<P>(
|
||||||
|
&self,
|
||||||
|
point: P,
|
||||||
|
) -> Option<(PointerFocusTarget, Point<i32, Logical>)>
|
||||||
where
|
where
|
||||||
P: Into<Point<f64, Logical>>,
|
P: Into<Point<f64, Logical>>,
|
||||||
{
|
{
|
||||||
|
@ -185,14 +188,33 @@ impl State {
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(window) = top_fullscreen_window {
|
if let Some(window) = top_fullscreen_window {
|
||||||
Some((FocusTarget::from(window.clone()), output_geo.loc))
|
let loc = self
|
||||||
|
.space
|
||||||
|
.element_location(&window)
|
||||||
|
.expect("called elem loc on unmapped win")
|
||||||
|
- window.geometry().loc;
|
||||||
|
|
||||||
|
window
|
||||||
|
.surface_under(point - loc.to_f64(), WindowSurfaceType::ALL)
|
||||||
|
.map(|(surf, surf_loc)| (PointerFocusTarget::WlSurface(surf), surf_loc + loc))
|
||||||
} else if let (Some(layer), _) | (None, Some(layer)) = (
|
} else if let (Some(layer), _) | (None, Some(layer)) = (
|
||||||
layers.layer_under(wlr_layer::Layer::Overlay, point),
|
layers.layer_under(wlr_layer::Layer::Overlay, point),
|
||||||
layers.layer_under(wlr_layer::Layer::Top, point),
|
layers.layer_under(wlr_layer::Layer::Top, point),
|
||||||
) {
|
) {
|
||||||
let layer_loc = layers.layer_geometry(layer).expect("no layer geo").loc;
|
let layer_loc = layers.layer_geometry(layer).expect("no layer geo").loc;
|
||||||
Some((FocusTarget::from(layer.clone()), output_geo.loc + layer_loc))
|
|
||||||
} else if let Some(ret) = self
|
layer
|
||||||
|
.surface_under(
|
||||||
|
point - layer_loc.to_f64() - output_geo.loc.to_f64(),
|
||||||
|
WindowSurfaceType::ALL,
|
||||||
|
)
|
||||||
|
.map(|(surf, surf_loc)| {
|
||||||
|
(
|
||||||
|
PointerFocusTarget::WlSurface(surf),
|
||||||
|
surf_loc + layer_loc + output_geo.loc,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else if let Some((surface, loc)) = self
|
||||||
.space
|
.space
|
||||||
.elements()
|
.elements()
|
||||||
.rev()
|
.rev()
|
||||||
|
@ -204,17 +226,28 @@ impl State {
|
||||||
.expect("called elem loc on unmapped win")
|
.expect("called elem loc on unmapped win")
|
||||||
- win.geometry().loc;
|
- win.geometry().loc;
|
||||||
|
|
||||||
win.is_in_input_region(&(point - loc.to_f64()))
|
win.surface_under(point - loc.to_f64(), WindowSurfaceType::ALL)
|
||||||
.then(|| (win.clone().into(), loc))
|
.map(|(surf, surf_loc)| (surf, surf_loc + loc))
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
Some(ret)
|
Some((PointerFocusTarget::WlSurface(surface), loc))
|
||||||
} else if let (Some(layer), _) | (None, Some(layer)) = (
|
} else if let (Some(layer), _) | (None, Some(layer)) = (
|
||||||
layers.layer_under(wlr_layer::Layer::Overlay, point),
|
layers.layer_under(wlr_layer::Layer::Overlay, point),
|
||||||
layers.layer_under(wlr_layer::Layer::Top, point),
|
layers.layer_under(wlr_layer::Layer::Top, point),
|
||||||
) {
|
) {
|
||||||
let layer_loc = layers.layer_geometry(layer).expect("no layer geo").loc;
|
let layer_loc = layers.layer_geometry(layer).expect("no layer geo").loc;
|
||||||
Some((FocusTarget::from(layer.clone()), output_geo.loc + layer_loc))
|
|
||||||
|
layer
|
||||||
|
.surface_under(
|
||||||
|
point - layer_loc.to_f64() - output_geo.loc.to_f64(),
|
||||||
|
WindowSurfaceType::ALL,
|
||||||
|
)
|
||||||
|
.map(|(surf, surf_loc)| {
|
||||||
|
(
|
||||||
|
PointerFocusTarget::WlSurface(surf),
|
||||||
|
surf_loc + layer_loc + output_geo.loc,
|
||||||
|
)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -334,15 +367,15 @@ impl State {
|
||||||
// If the button was clicked, focus on the window below if exists, else
|
// If the button was clicked, focus on the window below if exists, else
|
||||||
// unfocus on windows.
|
// unfocus on windows.
|
||||||
if button_state == ButtonState::Pressed {
|
if button_state == ButtonState::Pressed {
|
||||||
if let Some((focus, _)) = self.focus_target_under(pointer_loc) {
|
if let Some((focus, _)) = self.pointer_focus_target_under(pointer_loc) {
|
||||||
// NOTE: *Do not* set keyboard focus to an override redirect window. This leads
|
// NOTE: *Do not* set keyboard focus to an override redirect window. This leads
|
||||||
// | to wonky things like right-click menus not correctly getting pointer
|
// | to wonky things like right-click menus not correctly getting pointer
|
||||||
// | clicks or showing up at all.
|
// | clicks or showing up at all.
|
||||||
|
|
||||||
// TODO: use update_keyboard_focus from anvil
|
// TODO: use update_keyboard_focus from anvil
|
||||||
|
|
||||||
if let FocusTarget::Window(window) = &focus {
|
if let Some(window) = focus.window_for(self) {
|
||||||
self.space.raise_element(window, true);
|
self.space.raise_element(&window, true);
|
||||||
self.z_index_stack.set_focus(window.clone());
|
self.z_index_stack.set_focus(window.clone());
|
||||||
if let Some(output) = window.output(self) {
|
if let Some(output) = window.output(self) {
|
||||||
output.with_state(|state| state.focus_stack.set_focus(window.clone()));
|
output.with_state(|state| state.focus_stack.set_focus(window.clone()));
|
||||||
|
@ -350,15 +383,15 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !matches!(
|
if !matches!(
|
||||||
&focus,
|
focus.window_for(self),
|
||||||
FocusTarget::Window(WindowElement::X11OverrideRedirect(_))
|
Some(window) if window.is_x11_override_redirect()
|
||||||
) {
|
) {
|
||||||
keyboard.set_focus(self, Some(focus.clone()), serial);
|
keyboard.set_focus(self, focus.to_keyboard_focus_target(self), serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
for window in self.space.elements() {
|
for window in self.space.elements() {
|
||||||
if let WindowElement::Wayland(window) = window {
|
if let Some(toplevel) = window.toplevel() {
|
||||||
window.toplevel().send_configure();
|
toplevel.send_configure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -367,8 +400,8 @@ impl State {
|
||||||
state.focus_stack.unset_focus();
|
state.focus_stack.unset_focus();
|
||||||
for window in state.focus_stack.stack.iter() {
|
for window in state.focus_stack.stack.iter() {
|
||||||
window.set_activate(false);
|
window.set_activate(false);
|
||||||
if let WindowElement::Wayland(window) = window {
|
if let Some(toplevel) = window.toplevel() {
|
||||||
window.toplevel().send_configure();
|
toplevel.send_configure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -496,7 +529,7 @@ impl State {
|
||||||
|
|
||||||
pointer.motion(
|
pointer.motion(
|
||||||
self,
|
self,
|
||||||
self.focus_target_under(pointer_loc),
|
self.pointer_focus_target_under(pointer_loc),
|
||||||
&MotionEvent {
|
&MotionEvent {
|
||||||
location: pointer_loc,
|
location: pointer_loc,
|
||||||
serial,
|
serial,
|
||||||
|
@ -533,7 +566,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let surface_under = self.focus_target_under(self.pointer_location);
|
let surface_under = self.pointer_focus_target_under(self.pointer_location);
|
||||||
|
|
||||||
if let Some(pointer) = self.seat.get_pointer() {
|
if let Some(pointer) = self.seat.get_pointer() {
|
||||||
pointer.motion(
|
pointer.motion(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::layer_map_for_output,
|
desktop::{layer_map_for_output, WindowSurface},
|
||||||
output::Output,
|
output::Output,
|
||||||
utils::{Logical, Point, Rectangle, Serial, Size},
|
utils::{Logical, Point, Rectangle, Serial, Size},
|
||||||
wayland::{compositor, shell::xdg::XdgToplevelSurfaceData},
|
wayland::{compositor, shell::xdg::XdgToplevelSurfaceData},
|
||||||
|
@ -115,21 +115,20 @@ impl State {
|
||||||
|
|
||||||
for win in windows_on_foc_tags.iter() {
|
for win in windows_on_foc_tags.iter() {
|
||||||
if win.with_state(|state| state.target_loc.is_some()) {
|
if win.with_state(|state| state.target_loc.is_some()) {
|
||||||
match win {
|
match win.underlying_surface() {
|
||||||
WindowElement::Wayland(wl_win) => {
|
WindowSurface::Wayland(toplevel) => {
|
||||||
let pending =
|
let pending = compositor::with_states(toplevel.wl_surface(), |states| {
|
||||||
compositor::with_states(wl_win.toplevel().wl_surface(), |states| {
|
states
|
||||||
states
|
.data_map
|
||||||
.data_map
|
.get::<XdgToplevelSurfaceData>()
|
||||||
.get::<XdgToplevelSurfaceData>()
|
.expect("XdgToplevelSurfaceData wasn't in surface's data map")
|
||||||
.expect("XdgToplevelSurfaceData wasn't in surface's data map")
|
.lock()
|
||||||
.lock()
|
.expect("Failed to lock Mutex<XdgToplevelSurfaceData>")
|
||||||
.expect("Failed to lock Mutex<XdgToplevelSurfaceData>")
|
.has_pending_changes()
|
||||||
.has_pending_changes()
|
});
|
||||||
});
|
|
||||||
|
|
||||||
if pending {
|
if pending {
|
||||||
pending_wins.push((win.clone(), wl_win.toplevel().send_configure()))
|
pending_wins.push((win.clone(), toplevel.send_configure()))
|
||||||
} else {
|
} else {
|
||||||
let loc = win.with_state(|state| state.target_loc.take());
|
let loc = win.with_state(|state| state.target_loc.take());
|
||||||
if let Some(loc) = loc {
|
if let Some(loc) = loc {
|
||||||
|
@ -137,14 +136,12 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WindowElement::X11(_) => {
|
WindowSurface::X11(_) => {
|
||||||
let loc = win.with_state(|state| state.target_loc.take());
|
let loc = win.with_state(|state| state.target_loc.take());
|
||||||
if let Some(loc) = loc {
|
if let Some(loc) = loc {
|
||||||
self.space.map_element(win.clone(), loc, false);
|
self.space.map_element(win.clone(), loc, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WindowElement::X11OverrideRedirect(_) => (),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
use std::sync::Mutex;
|
use std::{ops::Deref, sync::Mutex};
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::{
|
backend::renderer::{
|
||||||
|
@ -71,18 +71,8 @@ where
|
||||||
scale: Scale<f64>,
|
scale: Scale<f64>,
|
||||||
alpha: f32,
|
alpha: f32,
|
||||||
) -> Vec<C> {
|
) -> Vec<C> {
|
||||||
match self {
|
self.deref()
|
||||||
WindowElement::Wayland(window) => {
|
.render_elements(renderer, location, scale, alpha)
|
||||||
window.render_elements(renderer, location, scale, alpha)
|
|
||||||
}
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
surface.render_elements(renderer, location, scale, alpha)
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
.into_iter()
|
|
||||||
.map(C::from)
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,9 +297,8 @@ where
|
||||||
|
|
||||||
let top_fullscreen_window = windows.iter().rev().find(|win| {
|
let top_fullscreen_window = windows.iter().rev().find(|win| {
|
||||||
let is_wayland_actually_fullscreen = {
|
let is_wayland_actually_fullscreen = {
|
||||||
if let WindowElement::Wayland(window) = win {
|
if let Some(toplevel) = win.toplevel() {
|
||||||
window
|
toplevel
|
||||||
.toplevel()
|
|
||||||
.current_state()
|
.current_state()
|
||||||
.states
|
.states
|
||||||
.contains(xdg_toplevel::State::Fullscreen)
|
.contains(xdg_toplevel::State::Fullscreen)
|
||||||
|
|
493
src/window.rs
493
src/window.rs
|
@ -2,40 +2,14 @@
|
||||||
|
|
||||||
pub mod rules;
|
pub mod rules;
|
||||||
|
|
||||||
use std::{cell::RefCell, time::Duration};
|
use std::{cell::RefCell, ops::Deref};
|
||||||
|
|
||||||
use pinnacle_api_defs::pinnacle::signal::v0alpha1::{
|
|
||||||
WindowPointerEnterResponse, WindowPointerLeaveResponse,
|
|
||||||
};
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::input::KeyState,
|
desktop::{space::SpaceElement, Window, WindowSurface},
|
||||||
desktop::{
|
|
||||||
utils::{
|
|
||||||
send_dmabuf_feedback_surface_tree, send_frames_surface_tree,
|
|
||||||
take_presentation_feedback_surface_tree, with_surfaces_surface_tree,
|
|
||||||
OutputPresentationFeedback,
|
|
||||||
},
|
|
||||||
Window,
|
|
||||||
},
|
|
||||||
input::{
|
|
||||||
keyboard::{KeyboardTarget, KeysymHandle, ModifiersState},
|
|
||||||
pointer::{AxisFrame, MotionEvent, PointerTarget},
|
|
||||||
Seat,
|
|
||||||
},
|
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::{
|
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||||
wayland_protocols::wp::presentation_time::server::wp_presentation_feedback,
|
utils::{IsAlive, Logical, Point, Rectangle},
|
||||||
wayland_server::protocol::wl_surface::WlSurface,
|
wayland::{compositor, seat::WaylandFocus, shell::xdg::XdgToplevelSurfaceData},
|
||||||
},
|
|
||||||
space_elements,
|
|
||||||
utils::{user_data::UserDataMap, Logical, Rectangle, Serial},
|
|
||||||
wayland::{
|
|
||||||
compositor::{self, SurfaceData},
|
|
||||||
dmabuf::DmabufFeedback,
|
|
||||||
seat::WaylandFocus,
|
|
||||||
shell::xdg::XdgToplevelSurfaceData,
|
|
||||||
},
|
|
||||||
xwayland::X11Surface,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::state::{State, WithState};
|
use crate::state::{State, WithState};
|
||||||
|
@ -44,143 +18,20 @@ use self::window_state::WindowElementState;
|
||||||
|
|
||||||
pub mod window_state;
|
pub mod window_state;
|
||||||
|
|
||||||
space_elements! {
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
/// The different types of windows.
|
pub struct WindowElement(Window);
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub WindowElement;
|
impl Deref for WindowElement {
|
||||||
/// This is a native Wayland window.
|
type Target = Window;
|
||||||
Wayland = Window,
|
|
||||||
/// This is an Xwayland window.
|
fn deref(&self) -> &Self::Target {
|
||||||
X11 = X11Surface,
|
&self.0
|
||||||
/// This is an Xwayland override redirect window, which should not be messed with.
|
}
|
||||||
X11OverrideRedirect = X11Surface,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowElement {
|
impl WindowElement {
|
||||||
pub fn with_surfaces<F>(&self, processor: F)
|
pub fn new(window: Window) -> Self {
|
||||||
where
|
Self(window)
|
||||||
F: FnMut(&WlSurface, &SurfaceData) + Copy,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => window.with_surfaces(processor),
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
if let Some(surface) = surface.wl_surface() {
|
|
||||||
with_surfaces_surface_tree(&surface, processor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_frame<T, F>(
|
|
||||||
&self,
|
|
||||||
output: &Output,
|
|
||||||
time: T,
|
|
||||||
throttle: Option<Duration>,
|
|
||||||
primary_scan_out_output: F,
|
|
||||||
) where
|
|
||||||
T: Into<Duration>,
|
|
||||||
F: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => {
|
|
||||||
window.send_frame(output, time, throttle, primary_scan_out_output)
|
|
||||||
}
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
if let Some(surface) = surface.wl_surface() {
|
|
||||||
send_frames_surface_tree(
|
|
||||||
&surface,
|
|
||||||
output,
|
|
||||||
time,
|
|
||||||
throttle,
|
|
||||||
primary_scan_out_output,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_dmabuf_feedback<'a, P, F>(
|
|
||||||
&self,
|
|
||||||
output: &Output,
|
|
||||||
primary_scan_out_output: P,
|
|
||||||
select_dmabuf_feedback: F,
|
|
||||||
) where
|
|
||||||
P: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy,
|
|
||||||
F: Fn(&WlSurface, &SurfaceData) -> &'a DmabufFeedback + Copy,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => {
|
|
||||||
window.send_dmabuf_feedback(
|
|
||||||
output,
|
|
||||||
primary_scan_out_output,
|
|
||||||
select_dmabuf_feedback,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
if let Some(surface) = surface.wl_surface() {
|
|
||||||
send_dmabuf_feedback_surface_tree(
|
|
||||||
&surface,
|
|
||||||
output,
|
|
||||||
primary_scan_out_output,
|
|
||||||
select_dmabuf_feedback,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn take_presentation_feedback<F1, F2>(
|
|
||||||
&self,
|
|
||||||
output_feedback: &mut OutputPresentationFeedback,
|
|
||||||
primary_scan_out_output: F1,
|
|
||||||
presentation_feedback_flags: F2,
|
|
||||||
) where
|
|
||||||
F1: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy,
|
|
||||||
F2: FnMut(&WlSurface, &SurfaceData) -> wp_presentation_feedback::Kind + Copy,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => {
|
|
||||||
window.take_presentation_feedback(
|
|
||||||
output_feedback,
|
|
||||||
primary_scan_out_output,
|
|
||||||
presentation_feedback_flags,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
if let Some(surface) = surface.wl_surface() {
|
|
||||||
take_presentation_feedback_surface_tree(
|
|
||||||
&surface,
|
|
||||||
output_feedback,
|
|
||||||
primary_scan_out_output,
|
|
||||||
presentation_feedback_flags,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wl_surface(&self) -> Option<WlSurface> {
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => window.wl_surface(),
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
surface.wl_surface()
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn user_data(&self) -> &UserDataMap {
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => window.user_data(),
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
surface.user_data()
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a geometry change without mapping windows or sending
|
/// Send a geometry change without mapping windows or sending
|
||||||
|
@ -191,13 +42,13 @@ impl WindowElement {
|
||||||
/// RefCell Safety: This method uses a [`RefCell`] on this window.
|
/// RefCell Safety: This method uses a [`RefCell`] on this window.
|
||||||
// TODO: ^ does that make things flicker?
|
// TODO: ^ does that make things flicker?
|
||||||
pub fn change_geometry(&self, new_geo: Rectangle<i32, Logical>) {
|
pub fn change_geometry(&self, new_geo: Rectangle<i32, Logical>) {
|
||||||
match self {
|
match self.0.underlying_surface() {
|
||||||
WindowElement::Wayland(window) => {
|
WindowSurface::Wayland(toplevel) => {
|
||||||
window.toplevel().with_pending_state(|state| {
|
toplevel.with_pending_state(|state| {
|
||||||
state.size = Some(new_geo.size);
|
state.size = Some(new_geo.size);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
WindowSurface::X11(surface) => {
|
||||||
// TODO: maybe move this check elsewhere idk
|
// TODO: maybe move this check elsewhere idk
|
||||||
if !surface.is_override_redirect() {
|
if !surface.is_override_redirect() {
|
||||||
surface
|
surface
|
||||||
|
@ -205,20 +56,16 @@ impl WindowElement {
|
||||||
.expect("failed to configure x11 win");
|
.expect("failed to configure x11 win");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
self.with_state(|state| {
|
self.with_state(|state| {
|
||||||
state.target_loc = Some(new_geo.loc);
|
state.target_loc = Some(new_geo.loc);
|
||||||
});
|
});
|
||||||
// self.with_state(|state| {
|
|
||||||
// state.loc_request_state = LocationRequestState::Sent(new_geo.loc);
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn class(&self) -> Option<String> {
|
pub fn class(&self) -> Option<String> {
|
||||||
match self {
|
match self.0.underlying_surface() {
|
||||||
WindowElement::Wayland(window) => {
|
WindowSurface::Wayland(toplevel) => {
|
||||||
compositor::with_states(window.toplevel().wl_surface(), |states| {
|
compositor::with_states(toplevel.wl_surface(), |states| {
|
||||||
states
|
states
|
||||||
.data_map
|
.data_map
|
||||||
.get::<XdgToplevelSurfaceData>()
|
.get::<XdgToplevelSurfaceData>()
|
||||||
|
@ -229,17 +76,14 @@ impl WindowElement {
|
||||||
.clone()
|
.clone()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
WindowSurface::X11(surface) => Some(surface.class()),
|
||||||
Some(surface.class())
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn title(&self) -> Option<String> {
|
pub fn title(&self) -> Option<String> {
|
||||||
match self {
|
match self.0.underlying_surface() {
|
||||||
WindowElement::Wayland(window) => {
|
WindowSurface::Wayland(toplevel) => {
|
||||||
compositor::with_states(window.toplevel().wl_surface(), |states| {
|
compositor::with_states(toplevel.wl_surface(), |states| {
|
||||||
states
|
states
|
||||||
.data_map
|
.data_map
|
||||||
.get::<XdgToplevelSurfaceData>()
|
.get::<XdgToplevelSurfaceData>()
|
||||||
|
@ -250,10 +94,7 @@ impl WindowElement {
|
||||||
.clone()
|
.clone()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
WindowSurface::X11(surface) => Some(surface.title()),
|
||||||
Some(surface.title())
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,274 +148,48 @@ impl WindowElement {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the window element is [`Wayland`].
|
|
||||||
///
|
|
||||||
/// [`Wayland`]: WindowElement::Wayland
|
|
||||||
#[must_use]
|
|
||||||
pub fn is_wayland(&self) -> bool {
|
|
||||||
matches!(self, Self::Wayland(..))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if the window element is [`X11`].
|
|
||||||
///
|
|
||||||
/// [`X11`]: WindowElement::X11
|
|
||||||
#[must_use]
|
|
||||||
pub fn is_x11(&self) -> bool {
|
|
||||||
matches!(self, Self::X11(..))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if the window element is [`X11OverrideRedirect`].
|
|
||||||
///
|
|
||||||
/// [`X11OverrideRedirect`]: WindowElement::X11OverrideRedirect
|
|
||||||
#[must_use]
|
|
||||||
pub fn is_x11_override_redirect(&self) -> bool {
|
pub fn is_x11_override_redirect(&self) -> bool {
|
||||||
matches!(self, Self::X11OverrideRedirect(..))
|
matches!(self.x11_surface(), Some(surface) if surface.is_override_redirect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PointerTarget<State> for WindowElement {
|
impl SpaceElement for WindowElement {
|
||||||
fn frame(&self, seat: &Seat<State>, state: &mut State) {
|
fn bbox(&self) -> Rectangle<i32, Logical> {
|
||||||
match self {
|
self.0.bbox()
|
||||||
WindowElement::Wayland(window) => window.frame(seat, state),
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
surface.frame(seat, state)
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enter(&self, seat: &Seat<State>, state: &mut State, event: &MotionEvent) {
|
fn is_in_input_region(&self, point: &Point<f64, Logical>) -> bool {
|
||||||
// TODO: ssd
|
self.0.is_in_input_region(point)
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => PointerTarget::enter(window, seat, state, event),
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
PointerTarget::enter(surface, seat, state, event)
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
let window_id = Some(self.with_state(|state| state.id.0));
|
|
||||||
|
|
||||||
state
|
|
||||||
.signal_state
|
|
||||||
.window_pointer_enter
|
|
||||||
.signal(|buffer| buffer.push_back(WindowPointerEnterResponse { window_id }));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn motion(&self, seat: &Seat<State>, state: &mut State, event: &MotionEvent) {
|
fn set_activate(&self, activated: bool) {
|
||||||
// TODO: ssd
|
self.0.set_activate(activated)
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => PointerTarget::motion(window, seat, state, event),
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
PointerTarget::motion(surface, seat, state, event)
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn relative_motion(
|
fn output_enter(&self, output: &Output, overlap: Rectangle<i32, Logical>) {
|
||||||
&self,
|
self.0.output_enter(output, overlap)
|
||||||
seat: &Seat<State>,
|
|
||||||
state: &mut State,
|
|
||||||
event: &smithay::input::pointer::RelativeMotionEvent,
|
|
||||||
) {
|
|
||||||
// TODO: ssd
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => {
|
|
||||||
PointerTarget::relative_motion(window, seat, state, event);
|
|
||||||
}
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
PointerTarget::relative_motion(surface, seat, state, event);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn button(
|
fn output_leave(&self, output: &Output) {
|
||||||
&self,
|
self.0.output_leave(output)
|
||||||
seat: &Seat<State>,
|
|
||||||
state: &mut State,
|
|
||||||
event: &smithay::input::pointer::ButtonEvent,
|
|
||||||
) {
|
|
||||||
// TODO: ssd
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => PointerTarget::button(window, seat, state, event),
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
PointerTarget::button(surface, seat, state, event)
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn axis(&self, seat: &Seat<State>, state: &mut State, frame: AxisFrame) {
|
fn geometry(&self) -> Rectangle<i32, Logical> {
|
||||||
// TODO: ssd
|
self.0.geometry()
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => PointerTarget::axis(window, seat, state, frame),
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
PointerTarget::axis(surface, seat, state, frame)
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leave(&self, seat: &Seat<State>, state: &mut State, serial: Serial, time: u32) {
|
fn z_index(&self) -> u8 {
|
||||||
// TODO: ssd
|
self.0.z_index()
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => {
|
|
||||||
PointerTarget::leave(window, seat, state, serial, time);
|
|
||||||
}
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
PointerTarget::leave(surface, seat, state, serial, time)
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
let window_id = Some(self.with_state(|state| state.id.0));
|
|
||||||
|
|
||||||
state
|
|
||||||
.signal_state
|
|
||||||
.window_pointer_leave
|
|
||||||
.signal(|buffer| buffer.push_back(WindowPointerLeaveResponse { window_id }));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gesture_swipe_begin(
|
fn refresh(&self) {
|
||||||
&self,
|
self.0.refresh();
|
||||||
_seat: &Seat<State>,
|
|
||||||
_state: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GestureSwipeBeginEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_swipe_update(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_state: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GestureSwipeUpdateEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_swipe_end(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_state: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GestureSwipeEndEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_pinch_begin(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_state: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GesturePinchBeginEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_pinch_update(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_state: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GesturePinchUpdateEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_pinch_end(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_state: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GesturePinchEndEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_hold_begin(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_state: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GestureHoldBeginEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gesture_hold_end(
|
|
||||||
&self,
|
|
||||||
_seat: &Seat<State>,
|
|
||||||
_state: &mut State,
|
|
||||||
_event: &smithay::input::pointer::GestureHoldEndEvent,
|
|
||||||
) {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyboardTarget<State> for WindowElement {
|
impl IsAlive for WindowElement {
|
||||||
fn enter(
|
fn alive(&self) -> bool {
|
||||||
&self,
|
self.0.alive()
|
||||||
seat: &Seat<State>,
|
|
||||||
state: &mut State,
|
|
||||||
keys: Vec<KeysymHandle<'_>>,
|
|
||||||
serial: Serial,
|
|
||||||
) {
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => {
|
|
||||||
KeyboardTarget::enter(window, seat, state, keys, serial);
|
|
||||||
}
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
KeyboardTarget::enter(surface, seat, state, keys, serial)
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn leave(&self, seat: &Seat<State>, state: &mut State, serial: Serial) {
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => KeyboardTarget::leave(window, seat, state, serial),
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
KeyboardTarget::leave(surface, seat, state, serial)
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn key(
|
|
||||||
&self,
|
|
||||||
seat: &Seat<State>,
|
|
||||||
state: &mut State,
|
|
||||||
key: KeysymHandle<'_>,
|
|
||||||
key_state: KeyState,
|
|
||||||
serial: Serial,
|
|
||||||
time: u32,
|
|
||||||
) {
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => {
|
|
||||||
KeyboardTarget::key(window, seat, state, key, key_state, serial, time);
|
|
||||||
}
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
KeyboardTarget::key(surface, seat, state, key, key_state, serial, time);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn modifiers(
|
|
||||||
&self,
|
|
||||||
seat: &Seat<State>,
|
|
||||||
state: &mut State,
|
|
||||||
modifiers: ModifiersState,
|
|
||||||
serial: Serial,
|
|
||||||
) {
|
|
||||||
match self {
|
|
||||||
WindowElement::Wayland(window) => {
|
|
||||||
KeyboardTarget::modifiers(window, seat, state, modifiers, serial);
|
|
||||||
}
|
|
||||||
WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => {
|
|
||||||
KeyboardTarget::modifiers(surface, seat, state, modifiers, serial);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,12 +214,18 @@ impl State {
|
||||||
self.space
|
self.space
|
||||||
.elements()
|
.elements()
|
||||||
.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()
|
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
self.windows
|
self.windows
|
||||||
.iter()
|
.iter()
|
||||||
.find(|&win| win.wl_surface().is_some_and(|surf| &surf == surface))
|
.find(|&win| win.wl_surface().is_some_and(|surf| &surf == surface))
|
||||||
.cloned()
|
|
||||||
})
|
})
|
||||||
|
.cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_window_for_surface(&self, surface: &WlSurface) -> Option<WindowElement> {
|
||||||
|
self.new_windows
|
||||||
|
.iter()
|
||||||
|
.find(|&win| win.wl_surface().is_some_and(|surf| &surf == surface))
|
||||||
|
.cloned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use std::sync::atomic::{AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::space::SpaceElement,
|
desktop::{space::SpaceElement, WindowSurface},
|
||||||
reexports::wayland_protocols::xdg::shell::server::xdg_toplevel,
|
reexports::wayland_protocols::xdg::shell::server::xdg_toplevel,
|
||||||
utils::{Logical, Point, Rectangle},
|
utils::{Logical, Point, Rectangle},
|
||||||
};
|
};
|
||||||
|
@ -81,9 +81,9 @@ impl WindowElement {
|
||||||
state.fullscreen_or_maximized = FullscreenOrMaximized::Fullscreen;
|
state.fullscreen_or_maximized = FullscreenOrMaximized::Fullscreen;
|
||||||
});
|
});
|
||||||
|
|
||||||
match self {
|
match self.underlying_surface() {
|
||||||
WindowElement::Wayland(window) => {
|
WindowSurface::Wayland(toplevel) => {
|
||||||
window.toplevel().with_pending_state(|state| {
|
toplevel.with_pending_state(|state| {
|
||||||
state.states.unset(xdg_toplevel::State::Maximized);
|
state.states.unset(xdg_toplevel::State::Maximized);
|
||||||
state.states.set(xdg_toplevel::State::Fullscreen);
|
state.states.set(xdg_toplevel::State::Fullscreen);
|
||||||
state.states.set(xdg_toplevel::State::TiledTop);
|
state.states.set(xdg_toplevel::State::TiledTop);
|
||||||
|
@ -92,16 +92,16 @@ impl WindowElement {
|
||||||
state.states.set(xdg_toplevel::State::TiledRight);
|
state.states.set(xdg_toplevel::State::TiledRight);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
WindowElement::X11(surface) => {
|
WindowSurface::X11(surface) => {
|
||||||
surface
|
if !surface.is_override_redirect() {
|
||||||
.set_maximized(false)
|
surface
|
||||||
.expect("failed to set x11 win to maximized");
|
.set_maximized(false)
|
||||||
surface
|
.expect("failed to set x11 win to maximized");
|
||||||
.set_fullscreen(true)
|
surface
|
||||||
.expect("failed to set x11 win to not fullscreen");
|
.set_fullscreen(true)
|
||||||
|
.expect("failed to set x11 win to not fullscreen");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
WindowElement::X11OverrideRedirect(_) => (),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FullscreenOrMaximized::Fullscreen => {
|
FullscreenOrMaximized::Fullscreen => {
|
||||||
|
@ -128,9 +128,9 @@ impl WindowElement {
|
||||||
state.fullscreen_or_maximized = FullscreenOrMaximized::Maximized;
|
state.fullscreen_or_maximized = FullscreenOrMaximized::Maximized;
|
||||||
});
|
});
|
||||||
|
|
||||||
match self {
|
match self.underlying_surface() {
|
||||||
WindowElement::Wayland(window) => {
|
WindowSurface::Wayland(toplevel) => {
|
||||||
window.toplevel().with_pending_state(|state| {
|
toplevel.with_pending_state(|state| {
|
||||||
state.states.set(xdg_toplevel::State::Maximized);
|
state.states.set(xdg_toplevel::State::Maximized);
|
||||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
state.states.unset(xdg_toplevel::State::Fullscreen);
|
||||||
state.states.set(xdg_toplevel::State::TiledTop);
|
state.states.set(xdg_toplevel::State::TiledTop);
|
||||||
|
@ -139,16 +139,16 @@ impl WindowElement {
|
||||||
state.states.set(xdg_toplevel::State::TiledRight);
|
state.states.set(xdg_toplevel::State::TiledRight);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
WindowElement::X11(surface) => {
|
WindowSurface::X11(surface) => {
|
||||||
surface
|
if !surface.is_override_redirect() {
|
||||||
.set_maximized(true)
|
surface
|
||||||
.expect("failed to set x11 win to maximized");
|
.set_maximized(true)
|
||||||
surface
|
.expect("failed to set x11 win to maximized");
|
||||||
.set_fullscreen(false)
|
surface
|
||||||
.expect("failed to set x11 win to not fullscreen");
|
.set_fullscreen(false)
|
||||||
|
.expect("failed to set x11 win to not fullscreen");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
WindowElement::X11OverrideRedirect(_) => (),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FullscreenOrMaximized::Maximized => {
|
FullscreenOrMaximized::Maximized => {
|
||||||
|
@ -170,9 +170,9 @@ impl WindowElement {
|
||||||
/// Unsets maximized and fullscreen states for both wayland and xwayland windows
|
/// Unsets maximized and fullscreen states for both wayland and xwayland windows
|
||||||
/// and unsets tiled states for wayland windows.
|
/// and unsets tiled states for wayland windows.
|
||||||
fn set_floating_states(&self) {
|
fn set_floating_states(&self) {
|
||||||
match self {
|
match self.underlying_surface() {
|
||||||
WindowElement::Wayland(window) => {
|
WindowSurface::Wayland(toplevel) => {
|
||||||
window.toplevel().with_pending_state(|state| {
|
toplevel.with_pending_state(|state| {
|
||||||
state.states.unset(xdg_toplevel::State::Maximized);
|
state.states.unset(xdg_toplevel::State::Maximized);
|
||||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
state.states.unset(xdg_toplevel::State::Fullscreen);
|
||||||
state.states.unset(xdg_toplevel::State::TiledTop);
|
state.states.unset(xdg_toplevel::State::TiledTop);
|
||||||
|
@ -181,25 +181,25 @@ impl WindowElement {
|
||||||
state.states.unset(xdg_toplevel::State::TiledRight);
|
state.states.unset(xdg_toplevel::State::TiledRight);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
WindowElement::X11(surface) => {
|
WindowSurface::X11(surface) => {
|
||||||
surface
|
if !surface.is_override_redirect() {
|
||||||
.set_maximized(false)
|
surface
|
||||||
.expect("failed to set x11 win to maximized");
|
.set_maximized(false)
|
||||||
surface
|
.expect("failed to set x11 win to maximized");
|
||||||
.set_fullscreen(false)
|
surface
|
||||||
.expect("failed to set x11 win to not fullscreen");
|
.set_fullscreen(false)
|
||||||
|
.expect("failed to set x11 win to not fullscreen");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
WindowElement::X11OverrideRedirect(_) => (),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unsets maximized and fullscreen states for both wayland and xwayland windows
|
/// Unsets maximized and fullscreen states for both wayland and xwayland windows
|
||||||
/// and sets tiled states for wayland windows.
|
/// and sets tiled states for wayland windows.
|
||||||
fn set_tiled_states(&self) {
|
fn set_tiled_states(&self) {
|
||||||
match self {
|
match self.underlying_surface() {
|
||||||
WindowElement::Wayland(window) => {
|
WindowSurface::Wayland(toplevel) => {
|
||||||
window.toplevel().with_pending_state(|state| {
|
toplevel.with_pending_state(|state| {
|
||||||
state.states.unset(xdg_toplevel::State::Maximized);
|
state.states.unset(xdg_toplevel::State::Maximized);
|
||||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
state.states.unset(xdg_toplevel::State::Fullscreen);
|
||||||
state.states.set(xdg_toplevel::State::TiledTop);
|
state.states.set(xdg_toplevel::State::TiledTop);
|
||||||
|
@ -208,16 +208,16 @@ impl WindowElement {
|
||||||
state.states.set(xdg_toplevel::State::TiledRight);
|
state.states.set(xdg_toplevel::State::TiledRight);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
WindowElement::X11(surface) => {
|
WindowSurface::X11(surface) => {
|
||||||
surface
|
if !surface.is_override_redirect() {
|
||||||
.set_maximized(false)
|
surface
|
||||||
.expect("failed to set x11 win to maximized");
|
.set_maximized(false)
|
||||||
surface
|
.expect("failed to set x11 win to maximized");
|
||||||
.set_fullscreen(false)
|
surface
|
||||||
.expect("failed to set x11 win to not fullscreen");
|
.set_fullscreen(false)
|
||||||
|
.expect("failed to set x11 win to not fullscreen");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
WindowElement::X11OverrideRedirect(_) => (),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue