mirror of
https://codeberg.org/waydeer/layer-shika.git
synced 2025-11-06 12:04:23 +00:00
338 lines
11 KiB
Rust
338 lines
11 KiB
Rust
use crate::impl_empty_dispatch;
|
|
use crate::wayland::surfaces::surface_state::WindowState;
|
|
use log::info;
|
|
use slint::{
|
|
PhysicalSize,
|
|
platform::{PointerEventButton, WindowEvent},
|
|
};
|
|
use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::{
|
|
zwlr_layer_shell_v1::ZwlrLayerShellV1,
|
|
zwlr_layer_surface_v1::{self, ZwlrLayerSurfaceV1},
|
|
};
|
|
use wayland_client::WEnum;
|
|
use wayland_client::{
|
|
Connection, Dispatch, Proxy, QueueHandle,
|
|
globals::GlobalListContents,
|
|
protocol::{
|
|
wl_compositor::WlCompositor,
|
|
wl_output::{self, WlOutput},
|
|
wl_pointer::{self, WlPointer},
|
|
wl_registry::WlRegistry,
|
|
wl_seat::WlSeat,
|
|
wl_surface::WlSurface,
|
|
},
|
|
};
|
|
use wayland_protocols::wp::fractional_scale::v1::client::{
|
|
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1,
|
|
wp_fractional_scale_v1::{self, WpFractionalScaleV1},
|
|
};
|
|
use wayland_protocols::wp::viewporter::client::{
|
|
wp_viewport::WpViewport, wp_viewporter::WpViewporter,
|
|
};
|
|
use wayland_protocols::xdg::shell::client::{
|
|
xdg_popup::{self, XdgPopup},
|
|
xdg_positioner::XdgPositioner,
|
|
xdg_surface::{self, XdgSurface},
|
|
xdg_wm_base::{self, XdgWmBase},
|
|
};
|
|
|
|
impl Dispatch<ZwlrLayerSurfaceV1, ()> for WindowState {
|
|
#[allow(clippy::cast_possible_truncation)]
|
|
#[allow(clippy::cast_sign_loss)]
|
|
#[allow(clippy::cast_precision_loss)]
|
|
fn event(
|
|
state: &mut Self,
|
|
layer_surface: &ZwlrLayerSurfaceV1,
|
|
event: zwlr_layer_surface_v1::Event,
|
|
_data: &(),
|
|
_conn: &Connection,
|
|
_queue_handle: &QueueHandle<Self>,
|
|
) {
|
|
match event {
|
|
zwlr_layer_surface_v1::Event::Configure {
|
|
serial,
|
|
width,
|
|
height,
|
|
} => {
|
|
info!("Layer surface configured with compositor size: {width}x{height}");
|
|
layer_surface.ack_configure(serial);
|
|
|
|
let output_width = state.output_size().width;
|
|
let scale_factor = state.scale_factor();
|
|
|
|
let target_width = if width == 0 || (width == 1 && output_width > 1) {
|
|
if scale_factor > 1.0 {
|
|
(output_width as f32 / scale_factor).round() as u32
|
|
} else {
|
|
output_width
|
|
}
|
|
} else {
|
|
width
|
|
};
|
|
|
|
let target_height = if height > 0 {
|
|
height
|
|
} else {
|
|
let h = state.height();
|
|
if scale_factor > 1.0 {
|
|
(h as f32 / scale_factor).round() as u32
|
|
} else {
|
|
h
|
|
}
|
|
};
|
|
|
|
let clamped_width = target_width.min(output_width);
|
|
|
|
info!(
|
|
"Using dimensions: {}x{} (clamped from {}x{}, output: {}x{})",
|
|
clamped_width,
|
|
target_height,
|
|
target_width,
|
|
target_height,
|
|
output_width,
|
|
state.output_size().height
|
|
);
|
|
|
|
state.update_size(clamped_width, target_height);
|
|
}
|
|
zwlr_layer_surface_v1::Event::Closed => {
|
|
info!("Layer surface closed");
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Dispatch<WlOutput, ()> for WindowState {
|
|
fn event(
|
|
state: &mut Self,
|
|
_proxy: &WlOutput,
|
|
event: <WlOutput as Proxy>::Event,
|
|
_data: &(),
|
|
_conn: &Connection,
|
|
_qhandle: &QueueHandle<Self>,
|
|
) {
|
|
match event {
|
|
wl_output::Event::Mode { width, height, .. } => {
|
|
info!("WlOutput size changed to {width}x{height}");
|
|
let width = width.try_into().unwrap_or_default();
|
|
let height = height.try_into().unwrap_or_default();
|
|
state.set_output_size(PhysicalSize::new(width, height));
|
|
}
|
|
wl_output::Event::Description { ref description } => {
|
|
info!("WlOutput description: {description:?}");
|
|
}
|
|
wl_output::Event::Scale { ref factor } => {
|
|
info!("WlOutput factor scale: {factor:?}");
|
|
}
|
|
wl_output::Event::Name { ref name } => {
|
|
info!("WlOutput name: {name:?}");
|
|
}
|
|
wl_output::Event::Geometry {
|
|
x,
|
|
y,
|
|
physical_width,
|
|
physical_height,
|
|
subpixel,
|
|
make,
|
|
model,
|
|
transform,
|
|
} => {
|
|
info!(
|
|
"WlOutput geometry: x={x}, y={y}, physical_width={physical_width}, physical_height={physical_height}, subpixel={subpixel:?}, make={make:?}, model={model:?}, transform={transform:?}"
|
|
);
|
|
}
|
|
wl_output::Event::Done => {
|
|
info!("WlOutput done");
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Dispatch<WlPointer, ()> for WindowState {
|
|
fn event(
|
|
state: &mut Self,
|
|
_proxy: &WlPointer,
|
|
event: <WlPointer as Proxy>::Event,
|
|
_data: &(),
|
|
_conn: &Connection,
|
|
_qhandle: &QueueHandle<Self>,
|
|
) {
|
|
match event {
|
|
wl_pointer::Event::Enter {
|
|
serial,
|
|
surface,
|
|
surface_x,
|
|
surface_y,
|
|
} => {
|
|
info!("Pointer entered surface {:?}", surface.id());
|
|
state.set_last_pointer_serial(serial);
|
|
state.set_current_pointer_position(surface_x, surface_y);
|
|
|
|
state.find_window_for_surface(&surface);
|
|
let position = state.current_pointer_position();
|
|
|
|
state.dispatch_to_active_window(WindowEvent::PointerMoved { position });
|
|
}
|
|
|
|
wl_pointer::Event::Motion {
|
|
surface_x,
|
|
surface_y,
|
|
..
|
|
} => {
|
|
state.set_current_pointer_position(surface_x, surface_y);
|
|
let position = state.current_pointer_position();
|
|
|
|
state.dispatch_to_active_window(WindowEvent::PointerMoved { position });
|
|
}
|
|
|
|
wl_pointer::Event::Leave { .. } => {
|
|
state.dispatch_to_active_window(WindowEvent::PointerExited);
|
|
state.clear_active_window();
|
|
}
|
|
|
|
wl_pointer::Event::Button {
|
|
serial,
|
|
state: button_state,
|
|
..
|
|
} => {
|
|
state.set_last_pointer_serial(serial);
|
|
let position = state.current_pointer_position();
|
|
let event = match button_state {
|
|
WEnum::Value(wl_pointer::ButtonState::Pressed) => WindowEvent::PointerPressed {
|
|
button: PointerEventButton::Left,
|
|
position,
|
|
},
|
|
_ => WindowEvent::PointerReleased {
|
|
button: PointerEventButton::Left,
|
|
position,
|
|
},
|
|
};
|
|
|
|
state.dispatch_to_active_window(event);
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Dispatch<WpFractionalScaleV1, ()> for WindowState {
|
|
fn event(
|
|
state: &mut Self,
|
|
proxy: &WpFractionalScaleV1,
|
|
event: wp_fractional_scale_v1::Event,
|
|
_data: &(),
|
|
_conn: &Connection,
|
|
_qhandle: &QueueHandle<Self>,
|
|
) {
|
|
if let wp_fractional_scale_v1::Event::PreferredScale { scale } = event {
|
|
#[allow(clippy::cast_precision_loss)]
|
|
let scale_float = scale as f32 / 120.0;
|
|
info!("Fractional scale received: {scale_float} ({scale}x)");
|
|
state.update_scale_for_fractional_scale_object(proxy, scale);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Dispatch<XdgWmBase, ()> for WindowState {
|
|
fn event(
|
|
_state: &mut Self,
|
|
xdg_wm_base: &XdgWmBase,
|
|
event: xdg_wm_base::Event,
|
|
_data: &(),
|
|
_conn: &Connection,
|
|
_qhandle: &QueueHandle<Self>,
|
|
) {
|
|
if let xdg_wm_base::Event::Ping { serial } = event {
|
|
info!("XdgWmBase ping received, sending pong with serial {serial}");
|
|
xdg_wm_base.pong(serial);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Dispatch<XdgPopup, ()> for WindowState {
|
|
fn event(
|
|
state: &mut Self,
|
|
xdg_popup: &XdgPopup,
|
|
event: xdg_popup::Event,
|
|
_data: &(),
|
|
_conn: &Connection,
|
|
_qhandle: &QueueHandle<Self>,
|
|
) {
|
|
match event {
|
|
xdg_popup::Event::Configure {
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
} => {
|
|
info!("XdgPopup Configure: position=({x}, {y}), size=({width}x{height})");
|
|
|
|
if let Some(popup_manager) = &state.popup_manager() {
|
|
let popup_id = xdg_popup.id();
|
|
if let Some(key) = popup_manager.find_popup_key_by_xdg_popup_id(&popup_id) {
|
|
info!(
|
|
"Marking popup with key {key} as configured after XdgPopup::Configure"
|
|
);
|
|
popup_manager.mark_popup_configured(key);
|
|
popup_manager.mark_all_popups_dirty();
|
|
}
|
|
}
|
|
}
|
|
xdg_popup::Event::PopupDone => {
|
|
info!("XdgPopup dismissed by compositor");
|
|
let popup_id = xdg_popup.id();
|
|
let popup_key = state
|
|
.popup_manager()
|
|
.as_ref()
|
|
.and_then(|pm| pm.find_popup_key_by_xdg_popup_id(&popup_id));
|
|
|
|
if let Some(key) = popup_key {
|
|
info!("Destroying popup with key {key}");
|
|
state.clear_active_window_if_popup(key);
|
|
if let Some(popup_manager) = &state.popup_manager() {
|
|
popup_manager.destroy_popup(key);
|
|
}
|
|
}
|
|
}
|
|
xdg_popup::Event::Repositioned { token } => {
|
|
info!("XdgPopup repositioned with token {token}");
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Dispatch<XdgSurface, ()> for WindowState {
|
|
fn event(
|
|
state: &mut Self,
|
|
xdg_surface: &XdgSurface,
|
|
event: xdg_surface::Event,
|
|
_data: &(),
|
|
_conn: &Connection,
|
|
_qhandle: &QueueHandle<Self>,
|
|
) {
|
|
if let xdg_surface::Event::Configure { serial } = event {
|
|
info!("XdgSurface Configure received, sending ack with serial {serial}");
|
|
xdg_surface.ack_configure(serial);
|
|
|
|
if let Some(popup_manager) = &state.popup_manager() {
|
|
info!("Marking all popups as dirty after Configure");
|
|
popup_manager.mark_all_popups_dirty();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl_empty_dispatch!(
|
|
(WlRegistry, GlobalListContents),
|
|
(WlCompositor, ()),
|
|
(WlSurface, ()),
|
|
(ZwlrLayerShellV1, ()),
|
|
(WlSeat, ()),
|
|
(WpFractionalScaleManagerV1, ()),
|
|
(WpViewporter, ()),
|
|
(WpViewport, ()),
|
|
(XdgPositioner, ())
|
|
);
|