fix: fractional scaling on popup

This commit is contained in:
drendog 2025-10-26 02:53:19 +01:00
parent 4ea4171eb7
commit b14cb51f86
Signed by: dwenya
GPG key ID: 8DD77074645332D0
5 changed files with 88 additions and 11 deletions

View file

@ -72,6 +72,23 @@ impl PopupSurface {
Rc::new(vp.get_viewport(&surface, params.queue_handle, ()))
});
#[allow(clippy::cast_possible_wrap)]
#[allow(clippy::cast_precision_loss)]
#[allow(clippy::cast_possible_truncation)]
if let Some(ref vp) = viewport {
let logical_width = (params.size.width as f32 / params.scale_factor) as i32;
let logical_height = (params.size.height as f32 / params.scale_factor) as i32;
info!(
"Setting viewport destination to logical size: {}x{} (physical: {}x{}, scale: {})",
logical_width,
logical_height,
params.size.width,
params.size.height,
params.scale_factor
);
vp.set_destination(logical_width, logical_height);
}
surface.set_buffer_scale(1);
surface.commit();

View file

@ -57,30 +57,44 @@ struct ActivePopup {
pub struct PopupManager {
context: PopupContext,
popups: RefCell<Vec<ActivePopup>>,
current_scale_factor: RefCell<f32>,
}
impl PopupManager {
pub const fn new(context: PopupContext) -> Self {
pub const fn new(context: PopupContext, initial_scale_factor: f32) -> Self {
Self {
context,
popups: RefCell::new(Vec::new()),
current_scale_factor: RefCell::new(initial_scale_factor),
}
}
pub fn update_scale_factor(&self, scale_factor: f32) {
*self.current_scale_factor.borrow_mut() = scale_factor;
}
pub fn create_popup(
&self,
queue_handle: &QueueHandle<WindowState>,
parent_layer_surface: &ZwlrLayerSurfaceV1,
last_pointer_serial: u32,
scale_factor: f32,
) -> Result<Rc<PopupWindow>> {
let xdg_wm_base = self.context.xdg_wm_base.as_ref().ok_or_else(|| {
LayerShikaError::WaylandProtocol("xdg-shell not available for popups".into())
})?;
info!("Creating popup window");
let scale_factor = *self.current_scale_factor.borrow();
info!("Creating popup window with scale factor {scale_factor}");
let popup_size = PhysicalSize::new(360, 524);
let logical_size = slint::LogicalSize::new(360.0, 524.0);
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_sign_loss)]
let popup_size = PhysicalSize::new(
(logical_size.width * scale_factor) as u32,
(logical_size.height * scale_factor) as u32,
);
info!("Popup logical size: {logical_size:?}, physical size: {popup_size:?}");
let popup_surface = PopupSurface::create(&super::popup::PopupSurfaceParams {
compositor: &self.context.compositor,
@ -107,8 +121,8 @@ impl PopupManager {
.map_err(|e| LayerShikaError::FemtoVGRendererCreation(e.to_string()))?;
let popup_window = PopupWindow::new(renderer);
popup_window.set_size(WindowSize::Physical(popup_size));
popup_window.set_scale_factor(scale_factor);
popup_window.set_size(WindowSize::Logical(logical_size));
info!("Popup window created successfully");
@ -151,6 +165,20 @@ impl PopupManager {
None
}
pub fn find_popup_index_by_fractional_scale_id(
&self,
fractional_scale_id: &ObjectId,
) -> Option<usize> {
for (index, popup) in self.popups.borrow().iter().enumerate() {
if let Some(ref fs) = popup.surface.fractional_scale {
if fs.id() == *fractional_scale_id {
return Some(index);
}
}
}
None
}
pub fn get_popup_window(&self, index: usize) -> Option<Rc<PopupWindow>> {
self.popups
.borrow()

View file

@ -218,7 +218,7 @@ impl Dispatch<WlPointer, ()> for WindowState {
impl Dispatch<WpFractionalScaleV1, ()> for WindowState {
fn event(
state: &mut Self,
_proxy: &WpFractionalScaleV1,
proxy: &WpFractionalScaleV1,
event: wp_fractional_scale_v1::Event,
_data: &(),
_conn: &Connection,
@ -228,7 +228,7 @@ impl Dispatch<WpFractionalScaleV1, ()> for WindowState {
#[allow(clippy::cast_precision_loss)]
let scale_float = scale as f32 / 120.0;
info!("Fractional scale received: {scale_float} ({scale}x)");
state.update_scale_factor(scale);
state.update_scale_for_fractional_scale_object(proxy, scale);
}
}
}

View file

@ -6,6 +6,7 @@ use slint::platform::{WindowAdapter, WindowEvent};
use slint_interpreter::ComponentInstance;
use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
use wayland_client::{protocol::{wl_output::WlOutput, wl_surface::WlSurface}, Proxy};
use wayland_protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1;
use crate::rendering::femtovg_window::FemtoVGWindow;
use crate::errors::{LayerShikaError, Result};
use crate::windowing::surface_dimensions::SurfaceDimensions;
@ -269,6 +270,10 @@ impl WindowState {
);
self.scale_factor = new_scale_factor;
if let Some(popup_manager) = &self.popup_manager {
popup_manager.update_scale_factor(new_scale_factor);
}
let current_logical_size = self.logical_size;
if current_logical_size.width > 0 && current_logical_size.height > 0 {
self.update_size(current_logical_size.width, current_logical_size.height);
@ -324,4 +329,33 @@ impl WindowState {
None => {}
}
}
#[allow(clippy::cast_precision_loss)]
pub fn update_scale_for_fractional_scale_object(
&mut self,
fractional_scale_proxy: &WpFractionalScaleV1,
scale_120ths: u32,
) {
let fractional_scale_id = fractional_scale_proxy.id();
if let Some(ref main_fractional_scale) = self.fractional_scale {
if (**main_fractional_scale.inner()).id() == fractional_scale_id {
self.update_scale_factor(scale_120ths);
return;
}
}
if let Some(popup_manager) = &self.popup_manager {
if let Some(popup_index) =
popup_manager.find_popup_index_by_fractional_scale_id(&fractional_scale_id)
{
if let Some(popup_window) = popup_manager.get_popup_window(popup_index) {
let new_scale_factor = scale_120ths as f32 / 120.0;
info!("Updating popup scale factor to {new_scale_factor} ({scale_120ths}x)");
popup_window.set_scale_factor(new_scale_factor);
popup_window.request_redraw();
}
}
}
}
}

View file

@ -52,7 +52,7 @@ impl WindowingSystem {
Rc::clone(&connection),
);
let popup_manager = Rc::new(PopupManager::new(popup_context));
let popup_manager = Rc::new(PopupManager::new(popup_context, state.scale_factor()));
Self::setup_popup_creator(&popup_manager, &platform, &state, &event_queue);
@ -156,14 +156,12 @@ impl WindowingSystem {
let popup_manager_clone = Rc::clone(popup_manager);
let layer_surface = state.layer_surface();
let queue_handle = event_queue.handle();
let scale_factor = state.scale_factor();
let last_serial = state.last_pointer_serial();
platform.set_popup_creator(move || {
info!("Popup creator called! Creating popup window...");
let result = popup_manager_clone
.create_popup(&queue_handle, &layer_surface, last_serial, scale_factor)
.create_popup(&queue_handle, &layer_surface, 0)
.map(|w| w as Rc<dyn WindowAdapter>)
.map_err(|e| PlatformError::Other(format!("Failed to create popup: {e}")));