Files
feresaria/compositor/src/handlers/mod.rs
T

333 lines
12 KiB
Rust

mod activation;
mod compositor;
mod input_method;
mod layer_shell;
pub(crate) mod screencopy;
pub(crate) mod screenshot;
pub(crate) mod screenshot_worker;
pub(crate) mod window_capture;
mod xdg_shell;
use smithay::desktop::{PopupManager, layer_map_for_output};
use smithay::input::pointer::{CursorImageStatus, PointerHandle};
use smithay::input::{Seat, SeatHandler, SeatState};
use smithay::reexports::wayland_server::Resource;
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
use smithay::wayland::compositor::{TraversalAction, with_states, with_surface_tree_downward};
use smithay::wayland::fractional_scale::{FractionalScaleHandler, with_fractional_scale};
use smithay::wayland::idle_inhibit::IdleInhibitHandler;
use smithay::wayland::idle_notify::{IdleNotifierHandler, IdleNotifierState};
use smithay::wayland::keyboard_shortcuts_inhibit::{
KeyboardShortcutsInhibitHandler, KeyboardShortcutsInhibitState, KeyboardShortcutsInhibitor,
KeyboardShortcutsInhibitorSeat,
};
use smithay::wayland::output::OutputHandler;
use smithay::wayland::pointer_constraints::{PointerConstraint, PointerConstraintsHandler, with_pointer_constraint};
use smithay::wayland::selection::SelectionHandler;
use smithay::wayland::selection::data_device::{
ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler, set_data_device_focus,
};
use smithay::wayland::selection::primary_selection::{
PrimarySelectionHandler, PrimarySelectionState, set_primary_focus,
};
use smithay::wayland::tablet_manager::TabletSeatHandler;
use smithay::wayland::xdg_foreign::{XdgForeignHandler, XdgForeignState};
use smithay::wayland::xdg_toplevel_icon::XdgToplevelIconHandler;
use crate::Ferese;
impl SeatHandler for Ferese {
type KeyboardFocus = WlSurface;
type PointerFocus = WlSurface;
type TouchFocus = WlSurface;
fn seat_state(&mut self) -> &mut SeatState<Self> {
&mut self.seat_state
}
fn cursor_image(&mut self, _seat: &Seat<Self>, image: CursorImageStatus) {
if let CursorImageStatus::Named(icon) = &image {
self.named_cursors
.entry(*icon)
.or_insert_with(|| crate::cursor::load_named_cursor(&self.cursor_theme, *icon));
}
self.cursor_status = image;
// Pointer focus transitions invoke this with the pointer lock held.
// render_all -> cursor_elements -> current_location would try to
// acquire that same lock, freezing the entire compositor thread.
self.cursor_redraw_pending = true;
}
fn focus_changed(&mut self, seat: &Seat<Self>, focused: Option<&WlSurface>) {
if let Some(id) = focused.and_then(|surface| self.windows.id_for_surface(surface)) {
self.focus_history.record(id);
}
if let Some(inhibitor) = self.active_shortcuts_inhibitor.take()
&& inhibitor.is_active()
{
inhibitor.inactivate();
}
if let Some(inhibitor) = focused.and_then(|surface| seat.keyboard_shortcuts_inhibitor_for_surface(surface)) {
inhibitor.activate();
self.active_shortcuts_inhibitor = Some(inhibitor);
}
let client = focused.and_then(|surface| self.display_handle.get_client(surface.id()).ok());
set_data_device_focus(&self.display_handle, seat, client.clone());
set_primary_focus(&self.display_handle, seat, client);
}
}
impl OutputHandler for Ferese {}
impl FractionalScaleHandler for Ferese {
fn new_fractional_scale(&mut self, surface: WlSurface) {
self.update_surface_preferences(&surface);
}
}
impl IdleNotifierHandler for Ferese {
fn idle_notifier_state(&mut self) -> &mut IdleNotifierState<Self> {
&mut self.idle_notifier_state
}
}
impl IdleInhibitHandler for Ferese {
fn inhibit(&mut self, surface: WlSurface) {
let count = self.idle_inhibitors.entry(surface).or_default();
*count = count.saturating_add(1);
self.refresh_idle_inhibition();
}
fn uninhibit(&mut self, surface: WlSurface) {
if let Some(count) = self.idle_inhibitors.get_mut(&surface) {
*count = count.saturating_sub(1);
if *count == 0 {
self.idle_inhibitors.remove(&surface);
}
}
self.refresh_idle_inhibition();
}
}
impl KeyboardShortcutsInhibitHandler for Ferese {
fn keyboard_shortcuts_inhibit_state(&mut self) -> &mut KeyboardShortcutsInhibitState {
&mut self.keyboard_shortcuts_inhibit_state
}
fn new_inhibitor(&mut self, inhibitor: KeyboardShortcutsInhibitor) {
let focused = self.seat.get_keyboard().and_then(|keyboard| keyboard.current_focus());
if focused.as_ref() == Some(inhibitor.wl_surface()) {
inhibitor.activate();
self.active_shortcuts_inhibitor = Some(inhibitor);
}
}
fn inhibitor_destroyed(&mut self, inhibitor: KeyboardShortcutsInhibitor) {
if self.active_shortcuts_inhibitor.as_ref() == Some(&inhibitor) {
self.active_shortcuts_inhibitor = None;
}
}
}
impl Ferese {
pub(crate) fn surface_outputs(&self, surface: &WlSurface) -> Vec<smithay::output::Output> {
use smithay::desktop::{WindowSurfaceType, find_popup_root_surface};
use smithay::wayland::compositor::get_parent;
let mut root = surface.clone();
while let Some(parent) = get_parent(&root) {
root = parent;
}
if let Some(popup) = self.popups.find_popup(&root)
&& let Ok(parent) = find_popup_root_surface(&popup)
{
root = parent;
}
let window = self.windows.id_for_surface(&root);
self.space
.outputs()
.filter(|output| {
window.is_some_and(|id| self.window_belongs_to_output(id, output))
|| layer_map_for_output(output)
.layer_for_surface(&root, WindowSurfaceType::ALL)
.is_some()
|| self
.session_lock
.surfaces
.get(output)
.is_some_and(|lock| lock.wl_surface() == &root)
})
.cloned()
.collect()
}
pub(crate) fn update_surface_preferences(&self, surface: &WlSurface) {
use smithay::desktop::{WindowSurfaceType, find_popup_root_surface};
use smithay::wayland::compositor::get_parent;
let mut root = surface.clone();
while let Some(parent) = get_parent(&root) {
root = parent;
}
if let Some(popup) = self.popups.find_popup(&root)
&& let Ok(parent) = find_popup_root_surface(&popup)
{
root = parent;
}
let window = self.windows.id_for_surface(&root);
let output = self.space.outputs().find(|output| {
window.is_some_and(|id| self.window_belongs_to_output(id, output))
|| layer_map_for_output(output)
.layer_for_surface(&root, WindowSurfaceType::ALL)
.is_some()
|| self
.session_lock
.surfaces
.get(output)
.is_some_and(|lock| lock.wl_surface() == &root)
});
// Hidden workspaces retain their last output preferences until presented again.
if window.is_some() && output.is_none() {
return;
}
let output = output
.or_else(|| self.focused_output())
.or_else(|| self.space.outputs().next());
with_states(surface, |states| set_surface_preferences(surface, states, output));
}
}
fn set_surface_preferences(
surface: &WlSurface,
states: &smithay::wayland::compositor::SurfaceData,
output: Option<&smithay::output::Output>,
) {
let scale = output.map_or(1.0, |output| output.current_scale().fractional_scale());
let transform = output.map_or(smithay::utils::Transform::Normal, |output| output.current_transform());
smithay::wayland::compositor::send_surface_state(surface, states, scale.ceil() as i32, transform);
with_fractional_scale(states, |surface_scale| surface_scale.set_preferred_scale(scale));
}
pub(crate) fn set_surface_tree_output(surface: &WlSurface, output: &smithay::output::Output) {
let update_tree = |root: &WlSurface| {
with_surface_tree_downward(
root,
(),
|_, _, &()| TraversalAction::DoChildren(()),
|surface, states, &()| set_surface_preferences(surface, states, Some(output)),
|_, _, &()| true,
);
};
update_tree(surface);
for (popup, _) in PopupManager::popups_for_surface(surface) {
update_tree(popup.wl_surface());
}
}
impl PointerConstraintsHandler for Ferese {
fn new_constraint(&mut self, surface: &WlSurface, pointer: &PointerHandle<Self>) {
if self
.locked_pointer_hint
.as_ref()
.is_some_and(|hint| hint.surface == *surface)
{
self.locked_pointer_hint = None;
}
self.activate_focused_pointer_constraint(pointer);
}
fn cursor_position_hint(
&mut self,
surface: &WlSurface,
pointer: &PointerHandle<Self>,
location: smithay::utils::Point<f64, smithay::utils::Logical>,
) {
let locked = with_pointer_constraint(surface, pointer, |constraint| {
constraint.is_some_and(|constraint| {
constraint.is_active() && matches!(&*constraint, PointerConstraint::Locked(_))
})
});
if !locked || pointer.current_focus().as_ref() != Some(surface) {
return;
}
self.locked_pointer_hint = Some(crate::input::LockedPointerHint {
surface: surface.clone(),
local: location,
});
}
}
impl SelectionHandler for Ferese {
type SelectionUserData = ();
}
impl ClientDndGrabHandler for Ferese {}
impl ServerDndGrabHandler for Ferese {}
impl TabletSeatHandler for Ferese {}
impl DataDeviceHandler for Ferese {
fn data_device_state(&self) -> &DataDeviceState {
&self.data_device_state
}
}
impl PrimarySelectionHandler for Ferese {
fn primary_selection_state(&self) -> &PrimarySelectionState {
&self.primary_selection_state
}
}
impl smithay::wayland::selection::wlr_data_control::DataControlHandler for Ferese {
fn data_control_state(&self) -> &smithay::wayland::selection::wlr_data_control::DataControlState {
&self.wlr_data_control_state
}
}
impl smithay::wayland::selection::ext_data_control::DataControlHandler for Ferese {
fn data_control_state(&self) -> &smithay::wayland::selection::ext_data_control::DataControlState {
&self.ext_data_control_state
}
}
impl XdgForeignHandler for Ferese {
fn xdg_foreign_state(&mut self) -> &mut XdgForeignState {
&mut self.xdg_foreign_state
}
}
impl XdgToplevelIconHandler for Ferese {}
smithay::delegate_compositor!(Ferese);
smithay::delegate_alpha_modifier!(Ferese);
smithay::delegate_cursor_shape!(Ferese);
smithay::delegate_data_device!(Ferese);
smithay::delegate_dmabuf!(Ferese);
smithay::delegate_fractional_scale!(Ferese);
smithay::delegate_idle_inhibit!(Ferese);
smithay::delegate_idle_notify!(Ferese);
smithay::delegate_input_method_manager!(Ferese);
smithay::delegate_keyboard_shortcuts_inhibit!(Ferese);
smithay::delegate_layer_shell!(Ferese);
smithay::delegate_output!(Ferese);
smithay::delegate_pointer_constraints!(Ferese);
smithay::delegate_presentation!(Ferese);
smithay::delegate_primary_selection!(Ferese);
smithay::delegate_relative_pointer!(Ferese);
smithay::delegate_seat!(Ferese);
smithay::delegate_shm!(Ferese);
smithay::delegate_single_pixel_buffer!(Ferese);
smithay::delegate_text_input_manager!(Ferese);
smithay::delegate_viewporter!(Ferese);
smithay::delegate_xdg_activation!(Ferese);
smithay::delegate_xdg_decoration!(Ferese);
smithay::delegate_xdg_foreign!(Ferese);
smithay::delegate_xdg_shell!(Ferese);
smithay::delegate_xdg_toplevel_icon!(Ferese);
smithay::delegate_data_control!(Ferese);
smithay::delegate_ext_data_control!(Ferese);