mirror of
https://codeberg.org/waydeer/layer-shika.git
synced 2025-11-06 14:14:23 +00:00
fix: popup positioning
This commit is contained in:
parent
bb26ce9e6b
commit
f565dd556b
4 changed files with 137 additions and 27 deletions
|
|
@ -179,7 +179,7 @@ impl WaylandWindowingSystem {
|
||||||
|
|
||||||
let serial = serial_holder.get();
|
let serial = serial_holder.get();
|
||||||
|
|
||||||
let params = if let Some((request, width, height)) = popup_manager_clone.take_pending_popup() {
|
let (params, request) = if let Some((request, width, height)) = popup_manager_clone.take_pending_popup() {
|
||||||
log::info!(
|
log::info!(
|
||||||
"Using popup request: component='{}', position=({}, {}), size={}x{}, mode={:?}",
|
"Using popup request: component='{}', position=({}, {}), size={}x{}, mode={:?}",
|
||||||
request.component,
|
request.component,
|
||||||
|
|
@ -190,14 +190,15 @@ impl WaylandWindowingSystem {
|
||||||
request.mode
|
request.mode
|
||||||
);
|
);
|
||||||
|
|
||||||
CreatePopupParams {
|
let params = CreatePopupParams {
|
||||||
last_pointer_serial: serial,
|
last_pointer_serial: serial,
|
||||||
reference_x: request.at.position().0,
|
reference_x: request.at.position().0,
|
||||||
reference_y: request.at.position().1,
|
reference_y: request.at.position().1,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
positioning_mode: request.mode,
|
positioning_mode: request.mode,
|
||||||
}
|
};
|
||||||
|
(params, request)
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Popup creator called without pending popup request - aborting");
|
log::warn!("Popup creator called without pending popup request - aborting");
|
||||||
return Err(PlatformError::Other(
|
return Err(PlatformError::Other(
|
||||||
|
|
@ -210,6 +211,7 @@ impl WaylandWindowingSystem {
|
||||||
&queue_handle,
|
&queue_handle,
|
||||||
&layer_surface,
|
&layer_surface,
|
||||||
params,
|
params,
|
||||||
|
request,
|
||||||
)
|
)
|
||||||
.map_err(|e| PlatformError::Other(format!("Failed to create popup: {e}")))?;
|
.map_err(|e| PlatformError::Other(format!("Failed to create popup: {e}")))?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ impl<'a> PopupBuilder<'a> {
|
||||||
self.queue_handle,
|
self.queue_handle,
|
||||||
self.parent_layer_surface,
|
self.parent_layer_surface,
|
||||||
params,
|
params,
|
||||||
|
request.clone(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let instance = Self::create_component_instance(component_def, &popup_window)?;
|
let instance = Self::create_component_instance(component_def, &popup_window)?;
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,8 @@ impl PopupContext {
|
||||||
struct ActivePopup {
|
struct ActivePopup {
|
||||||
surface: PopupSurface,
|
surface: PopupSurface,
|
||||||
window: Rc<PopupWindow>,
|
window: Rc<PopupWindow>,
|
||||||
|
request: PopupRequest,
|
||||||
|
last_serial: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ActivePopup {
|
impl Drop for ActivePopup {
|
||||||
|
|
@ -160,6 +162,7 @@ impl PopupManager {
|
||||||
queue_handle: &QueueHandle<WindowState>,
|
queue_handle: &QueueHandle<WindowState>,
|
||||||
parent_layer_surface: &ZwlrLayerSurfaceV1,
|
parent_layer_surface: &ZwlrLayerSurfaceV1,
|
||||||
params: CreatePopupParams,
|
params: CreatePopupParams,
|
||||||
|
request: PopupRequest,
|
||||||
) -> Result<Rc<PopupWindow>> {
|
) -> Result<Rc<PopupWindow>> {
|
||||||
let xdg_wm_base = self.context.xdg_wm_base.as_ref().ok_or_else(|| {
|
let xdg_wm_base = self.context.xdg_wm_base.as_ref().ok_or_else(|| {
|
||||||
LayerShikaError::WindowConfiguration {
|
LayerShikaError::WindowConfiguration {
|
||||||
|
|
@ -227,6 +230,8 @@ impl PopupManager {
|
||||||
let key = self.popups.borrow_mut().insert(ActivePopup {
|
let key = self.popups.borrow_mut().insert(ActivePopup {
|
||||||
surface: popup_surface,
|
surface: popup_surface,
|
||||||
window: Rc::clone(&popup_window),
|
window: Rc::clone(&popup_window),
|
||||||
|
request,
|
||||||
|
last_serial: params.last_pointer_serial,
|
||||||
});
|
});
|
||||||
popup_window.set_popup_manager(Rc::downgrade(self), key);
|
popup_window.set_popup_manager(Rc::downgrade(self), key);
|
||||||
*self.current_popup_key.borrow_mut() = Some(key);
|
*self.current_popup_key.borrow_mut() = Some(key);
|
||||||
|
|
@ -303,4 +308,11 @@ impl PopupManager {
|
||||||
popup.surface.update_viewport_size(logical_width, logical_height);
|
popup.surface.update_viewport_size(logical_width, logical_height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_popup_info(&self, key: usize) -> Option<(PopupRequest, u32)> {
|
||||||
|
self.popups
|
||||||
|
.borrow()
|
||||||
|
.get(key)
|
||||||
|
.map(|popup| (popup.request.clone(), popup.last_serial))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use layer_shika_adapters::platform::calloop::{
|
||||||
EventSource, Generic, Interest, Mode, PostAction, RegistrationToken, TimeoutAction, Timer,
|
EventSource, Generic, Interest, Mode, PostAction, RegistrationToken, TimeoutAction, Timer,
|
||||||
channel,
|
channel,
|
||||||
};
|
};
|
||||||
use layer_shika_adapters::platform::slint::ComponentHandle;
|
use layer_shika_adapters::platform::slint::{ComponentHandle, SharedString};
|
||||||
use layer_shika_adapters::platform::slint_interpreter::{
|
use layer_shika_adapters::platform::slint_interpreter::{
|
||||||
CompilationResult, ComponentDefinition, ComponentInstance, Value,
|
CompilationResult, ComponentDefinition, ComponentInstance, Value,
|
||||||
};
|
};
|
||||||
|
|
@ -28,6 +28,11 @@ use std::time::{Duration, Instant};
|
||||||
enum PopupCommand {
|
enum PopupCommand {
|
||||||
Show(PopupRequest),
|
Show(PopupRequest),
|
||||||
Close(PopupHandle),
|
Close(PopupHandle),
|
||||||
|
Resize {
|
||||||
|
key: usize,
|
||||||
|
width: f32,
|
||||||
|
height: f32,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoopHandle {
|
pub struct EventLoopHandle {
|
||||||
|
|
@ -137,7 +142,7 @@ impl RuntimeState<'_> {
|
||||||
self.window_state.compilation_result()
|
self.window_state.compilation_result()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_popup(&mut self, req: PopupRequest) -> Result<PopupHandle> {
|
pub fn show_popup(&mut self, req: PopupRequest, resize_sender: Option<channel::Sender<PopupCommand>>) -> Result<PopupHandle> {
|
||||||
let compilation_result = self.compilation_result().ok_or_else(|| {
|
let compilation_result = self.compilation_result().ok_or_else(|| {
|
||||||
Error::Domain(DomainError::Configuration {
|
Error::Domain(DomainError::Configuration {
|
||||||
message: "No compilation result available for popup creation".to_string(),
|
message: "No compilation result available for popup creation".to_string(),
|
||||||
|
|
@ -175,7 +180,7 @@ impl RuntimeState<'_> {
|
||||||
}
|
}
|
||||||
PopupSize::Content => {
|
PopupSize::Content => {
|
||||||
log::debug!("Using content-based sizing - will measure after instance creation");
|
log::debug!("Using content-based sizing - will measure after instance creation");
|
||||||
(600.0, 300.0)
|
(2.0, 2.0)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -191,7 +196,7 @@ impl RuntimeState<'_> {
|
||||||
|
|
||||||
popup_manager.set_pending_popup(req, initial_dimensions.0, initial_dimensions.1);
|
popup_manager.set_pending_popup(req, initial_dimensions.0, initial_dimensions.1);
|
||||||
|
|
||||||
let instance = Self::create_popup_instance(&definition, &popup_manager, 0)?;
|
let instance = Self::create_popup_instance(&definition, &popup_manager, 0, resize_sender)?;
|
||||||
|
|
||||||
let popup_key = popup_manager.current_popup_key().ok_or_else(|| {
|
let popup_key = popup_manager.current_popup_key().ok_or_else(|| {
|
||||||
Error::Domain(DomainError::Configuration {
|
Error::Domain(DomainError::Configuration {
|
||||||
|
|
@ -224,10 +229,62 @@ impl RuntimeState<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn resize_popup(&mut self, key: usize, width: f32, height: f32, resize_sender: Option<channel::Sender<PopupCommand>>) -> Result<()> {
|
||||||
|
let popup_manager = self
|
||||||
|
.window_state
|
||||||
|
.popup_manager()
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
Error::Domain(DomainError::Configuration {
|
||||||
|
message: "No popup manager available".to_string(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map(Rc::clone)?;
|
||||||
|
|
||||||
|
let (request, _serial) = popup_manager.get_popup_info(key).ok_or_else(|| {
|
||||||
|
Error::Domain(DomainError::Configuration {
|
||||||
|
message: format!("Popup with key {} not found", key),
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let current_size = request.size.dimensions();
|
||||||
|
let size_changed = current_size.map_or(true, |(w, h)| {
|
||||||
|
(w - width).abs() > 0.01 || (h - height).abs() > 0.01
|
||||||
|
});
|
||||||
|
|
||||||
|
let needs_repositioning = request.mode.center_x() || request.mode.center_y();
|
||||||
|
|
||||||
|
if needs_repositioning && size_changed {
|
||||||
|
log::info!(
|
||||||
|
"Popup needs repositioning due to mode {:?} and size change - recreating with new size {}x{}",
|
||||||
|
request.mode,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
);
|
||||||
|
|
||||||
|
self.close_popup(PopupHandle::new(key))?;
|
||||||
|
|
||||||
|
let new_request = PopupRequest::builder(request.component)
|
||||||
|
.at(request.at)
|
||||||
|
.size(PopupSize::fixed(width, height))
|
||||||
|
.mode(request.mode)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
self.show_popup(new_request, resize_sender)?;
|
||||||
|
} else if size_changed {
|
||||||
|
if let Some(popup_window) = popup_manager.get_popup_window(key) {
|
||||||
|
popup_window.request_resize(width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn create_popup_instance(
|
fn create_popup_instance(
|
||||||
definition: &ComponentDefinition,
|
definition: &ComponentDefinition,
|
||||||
popup_manager: &Rc<PopupManager>,
|
popup_manager: &Rc<PopupManager>,
|
||||||
popup_key: usize,
|
popup_key: usize,
|
||||||
|
resize_sender: Option<channel::Sender<PopupCommand>>,
|
||||||
) -> Result<ComponentInstance> {
|
) -> Result<ComponentInstance> {
|
||||||
let instance = definition.create().map_err(|e| {
|
let instance = definition.create().map_err(|e| {
|
||||||
Error::Domain(DomainError::Configuration {
|
Error::Domain(DomainError::Configuration {
|
||||||
|
|
@ -249,8 +306,8 @@ impl RuntimeState<'_> {
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let popup_manager_for_resize = Rc::downgrade(popup_manager);
|
let result = if let Some(sender) = resize_sender {
|
||||||
let result = instance.set_callback("change_popup_size", move |args| {
|
instance.set_callback("change_popup_size", move |args| {
|
||||||
let width: f32 = args
|
let width: f32 = args
|
||||||
.first()
|
.first()
|
||||||
.and_then(|v| v.clone().try_into().ok())
|
.and_then(|v| v.clone().try_into().ok())
|
||||||
|
|
@ -262,13 +319,41 @@ impl RuntimeState<'_> {
|
||||||
|
|
||||||
log::info!("change_popup_size callback invoked: {}x{}", width, height);
|
log::info!("change_popup_size callback invoked: {}x{}", width, height);
|
||||||
|
|
||||||
if let Some(popup_mgr) = popup_manager_for_resize.upgrade() {
|
if sender
|
||||||
if let Some(popup_window) = popup_mgr.get_popup_window(popup_key) {
|
.send(PopupCommand::Resize {
|
||||||
popup_window.request_resize(width, height);
|
key: popup_key,
|
||||||
}
|
width,
|
||||||
|
height,
|
||||||
|
})
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
log::error!("Failed to send popup resize command through channel");
|
||||||
}
|
}
|
||||||
Value::Void
|
Value::Void
|
||||||
});
|
})
|
||||||
|
} else {
|
||||||
|
let popup_manager_for_resize = Rc::downgrade(popup_manager);
|
||||||
|
instance.set_callback("change_popup_size", move |args| {
|
||||||
|
let width: f32 = args
|
||||||
|
.first()
|
||||||
|
.and_then(|v| v.clone().try_into().ok())
|
||||||
|
.unwrap_or(200.0);
|
||||||
|
let height: f32 = args
|
||||||
|
.get(1)
|
||||||
|
.and_then(|v| v.clone().try_into().ok())
|
||||||
|
.unwrap_or(150.0);
|
||||||
|
|
||||||
|
log::info!("change_popup_size callback invoked: {}x{}", width, height);
|
||||||
|
|
||||||
|
if let Some(popup_window) = popup_manager_for_resize
|
||||||
|
.upgrade()
|
||||||
|
.and_then(|mgr| mgr.get_popup_window(popup_key))
|
||||||
|
{
|
||||||
|
popup_window.request_resize(width, height);
|
||||||
|
}
|
||||||
|
Value::Void
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
if let Err(e) = result {
|
if let Err(e) = result {
|
||||||
log::warn!("Failed to set change_popup_size callback: {}", e);
|
log::warn!("Failed to set change_popup_size callback: {}", e);
|
||||||
|
|
@ -322,15 +407,16 @@ impl WindowingSystem {
|
||||||
|
|
||||||
fn setup_popup_command_handler(&self, receiver: channel::Channel<PopupCommand>) -> Result<()> {
|
fn setup_popup_command_handler(&self, receiver: channel::Channel<PopupCommand>) -> Result<()> {
|
||||||
let loop_handle = self.inner.borrow().event_loop_handle();
|
let loop_handle = self.inner.borrow().event_loop_handle();
|
||||||
|
let sender_for_handler = self.popup_command_sender.clone();
|
||||||
|
|
||||||
loop_handle
|
loop_handle
|
||||||
.insert_source(receiver, |event, (), window_state| {
|
.insert_source(receiver, move |event, (), window_state| {
|
||||||
if let channel::Event::Msg(command) = event {
|
if let channel::Event::Msg(command) = event {
|
||||||
let mut runtime_state = RuntimeState { window_state };
|
let mut runtime_state = RuntimeState { window_state };
|
||||||
|
|
||||||
match command {
|
match command {
|
||||||
PopupCommand::Show(request) => {
|
PopupCommand::Show(request) => {
|
||||||
if let Err(e) = runtime_state.show_popup(request) {
|
if let Err(e) = runtime_state.show_popup(request, Some(sender_for_handler.clone())) {
|
||||||
log::error!("Failed to show popup: {}", e);
|
log::error!("Failed to show popup: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -339,6 +425,11 @@ impl WindowingSystem {
|
||||||
log::error!("Failed to close popup: {}", e);
|
log::error!("Failed to close popup: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PopupCommand::Resize { key, width, height } => {
|
||||||
|
if let Err(e) = runtime_state.resize_popup(key, width, height, Some(sender_for_handler.clone())) {
|
||||||
|
log::error!("Failed to resize popup: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -371,6 +462,12 @@ impl WindowingSystem {
|
||||||
|
|
||||||
let mode = PopupPositioningMode::from_flags(center_x, center_y);
|
let mode = PopupPositioningMode::from_flags(center_x, center_y);
|
||||||
*popup_mode_clone.borrow_mut() = mode;
|
*popup_mode_clone.borrow_mut() = mode;
|
||||||
|
log::info!(
|
||||||
|
"Popup positioning mode set to: {:?} (center_x: {}, center_y: {})",
|
||||||
|
mode,
|
||||||
|
center_x,
|
||||||
|
center_y
|
||||||
|
);
|
||||||
Value::Void
|
Value::Void
|
||||||
})
|
})
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
|
|
@ -387,8 +484,6 @@ impl WindowingSystem {
|
||||||
|
|
||||||
component_instance
|
component_instance
|
||||||
.set_callback("show_popup", move |args| {
|
.set_callback("show_popup", move |args| {
|
||||||
use layer_shika_adapters::platform::slint::SharedString;
|
|
||||||
|
|
||||||
let component_name: SharedString = args
|
let component_name: SharedString = args
|
||||||
.first()
|
.first()
|
||||||
.and_then(|v| v.clone().try_into().ok())
|
.and_then(|v| v.clone().try_into().ok())
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue