mirror of https://github.com/wayvr-org/wayvr.git
wvr_server: scale windows based on resolution
This commit is contained in:
parent
2d820f1d1b
commit
b2037feacf
|
|
@ -424,12 +424,12 @@ impl WayVRClient {
|
|||
|
||||
pub async fn fn_wlx_handsfree(
|
||||
client: WayVRClientMutex,
|
||||
params: HandsfreeParams
|
||||
params: HandsfreeParams,
|
||||
) -> anyhow::Result<()> {
|
||||
send_only!(client, &PacketClient::WlxHandsfree(params));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub async fn fn_wlx_modify_panel(
|
||||
client: WayVRClientMutex,
|
||||
params: packet_client::WlxModifyPanelParams,
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ impl Application {
|
|||
self.redraw_requests.remove(surface_id)
|
||||
}
|
||||
|
||||
fn output_logical_size(&self) -> Size<i32, Logical> {
|
||||
pub fn output_logical_size(&self) -> Size<i32, Logical> {
|
||||
self.output
|
||||
.current_mode()
|
||||
.map(|mode| Size::new(mode.size.w, mode.size.h))
|
||||
|
|
@ -520,36 +520,60 @@ impl XdgShellHandler for Application {
|
|||
surface.send_repositioned(token);
|
||||
}
|
||||
|
||||
// If the app wants to be fullscreen, make it think that it's fullscreen.
|
||||
// If the app requests fullscreen, make it fill the virtual output
|
||||
fn fullscreen_request(
|
||||
&mut self,
|
||||
surface: ToplevelSurface,
|
||||
_output: Option<wl_output::WlOutput>,
|
||||
) {
|
||||
let size = self.output_logical_size();
|
||||
|
||||
surface.with_pending_state(|state| {
|
||||
state.bounds = Some(size);
|
||||
state.size = Some(size);
|
||||
state.states.set(xdg_toplevel::State::Fullscreen);
|
||||
});
|
||||
|
||||
surface.send_configure();
|
||||
}
|
||||
fn unfullscreen_request(&mut self, surface: ToplevelSurface) {
|
||||
surface.with_pending_state(|state| {
|
||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
||||
});
|
||||
surface.send_configure();
|
||||
}
|
||||
// If the app wants to be maximized, make it think that it's maximized.
|
||||
|
||||
// If the app requests maximize, make it fill the virtual output
|
||||
fn maximize_request(&mut self, surface: ToplevelSurface) {
|
||||
let size = self.output_logical_size();
|
||||
|
||||
surface.with_pending_state(|state| {
|
||||
state.bounds = Some(size);
|
||||
state.size = Some(size);
|
||||
state.states.set(xdg_toplevel::State::Maximized);
|
||||
});
|
||||
|
||||
surface.send_configure();
|
||||
}
|
||||
fn unmaximize_request(&mut self, surface: ToplevelSurface) {
|
||||
|
||||
fn unfullscreen_request(&mut self, surface: ToplevelSurface) {
|
||||
let bounds = self.output_logical_size();
|
||||
|
||||
surface.with_pending_state(|state| {
|
||||
state.bounds = Some(bounds);
|
||||
state.size = None;
|
||||
state.states.unset(xdg_toplevel::State::Fullscreen);
|
||||
});
|
||||
|
||||
surface.send_configure();
|
||||
}
|
||||
|
||||
fn unmaximize_request(&mut self, surface: ToplevelSurface) {
|
||||
let bounds = self.output_logical_size();
|
||||
|
||||
surface.with_pending_state(|state| {
|
||||
state.bounds = Some(bounds);
|
||||
state.size = None;
|
||||
state.states.unset(xdg_toplevel::State::Maximized);
|
||||
});
|
||||
|
||||
surface.send_configure();
|
||||
}
|
||||
|
||||
// If the app requests minimize, hide its window
|
||||
fn minimize_request(&mut self, surface: ToplevelSurface) {
|
||||
if let Some(client) = surface.wl_surface().client() {
|
||||
|
|
|
|||
|
|
@ -343,28 +343,35 @@ impl WvrServerState {
|
|||
continue;
|
||||
};
|
||||
|
||||
let output_bounds = wvr_server.manager.state.output_logical_size();
|
||||
|
||||
let (min_size, max_size) = with_states(toplevel.wl_surface(), |state| {
|
||||
let mut guard = state.cached_state.get::<SurfaceCachedState>();
|
||||
let (mut min_size, mut max_size) =
|
||||
{ (guard.current().min_size, guard.current().max_size) };
|
||||
let current = guard.current();
|
||||
|
||||
let mut min_size = current.min_size;
|
||||
let mut max_size = current.max_size;
|
||||
|
||||
if min_size.is_empty() {
|
||||
min_size = Size::new(1, 1);
|
||||
}
|
||||
|
||||
if max_size.is_empty() {
|
||||
max_size = Size::new(4096, 4096);
|
||||
max_size = output_bounds;
|
||||
} else {
|
||||
max_size = max_size.clamp(Size::new(1, 1), output_bounds);
|
||||
}
|
||||
|
||||
(min_size, max_size)
|
||||
});
|
||||
|
||||
// Size, icon & fallback title comes from process
|
||||
let (size, pos, fallback_title, icon, is_cage) =
|
||||
let (fallback_size, pos, fallback_title, icon, is_cage) =
|
||||
match wvr_server.processes.get(&process_handle) {
|
||||
Some(Process::Managed(p)) => {
|
||||
let size: Size<i32, Logical> =
|
||||
Size::new(p.resolution[0] as _, p.resolution[1] as _);
|
||||
|
||||
(
|
||||
size.clamp(min_size, max_size),
|
||||
p.pos_mode,
|
||||
|
|
@ -382,6 +389,21 @@ impl WvrServerState {
|
|||
),
|
||||
};
|
||||
|
||||
let window_handle = wvr_server.wm.create_window(
|
||||
toplevel.clone(),
|
||||
process_handle,
|
||||
fallback_size.w as _,
|
||||
fallback_size.h as _,
|
||||
);
|
||||
|
||||
toplevel.with_pending_state(|state| {
|
||||
state.bounds = Some(output_bounds);
|
||||
// suggest an initial size but let the app request a different one
|
||||
state.size = Some(fallback_size);
|
||||
state.states.set(xdg_toplevel::State::Activated);
|
||||
});
|
||||
toplevel.send_configure();
|
||||
|
||||
let mut title: Arc<str> = fallback_title
|
||||
.unwrap_or_else(|| format!("P{}", client.pid))
|
||||
.into();
|
||||
|
|
@ -392,19 +414,6 @@ impl WvrServerState {
|
|||
SpawnPos::Parent(OverlaySelector::Id(oid))
|
||||
});
|
||||
|
||||
let window_handle = wvr_server.wm.create_window(
|
||||
toplevel.clone(),
|
||||
process_handle,
|
||||
size.w as _,
|
||||
size.h as _,
|
||||
);
|
||||
toplevel.with_pending_state(|state| {
|
||||
state.size = Some(size);
|
||||
state.states.set(xdg_toplevel::State::Activated);
|
||||
state.states.set(xdg_toplevel::State::Maximized);
|
||||
});
|
||||
toplevel.send_configure();
|
||||
|
||||
let mut icon = icon;
|
||||
|
||||
// Try to get title from xdg_toplevel, unless it's running in cage
|
||||
|
|
@ -456,7 +465,7 @@ impl WvrServerState {
|
|||
app,
|
||||
window_handle,
|
||||
icon,
|
||||
[size.w as _, size.h as _],
|
||||
[fallback_size.w as _, fallback_size.h as _],
|
||||
pos,
|
||||
)
|
||||
.context("Could not create WvrWindow overlay")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use smithay::utils::{Logical, Size};
|
||||
use smithay::wayland::shell::xdg::ToplevelSurface;
|
||||
use wayvr_ipc::packet_server;
|
||||
|
||||
|
|
@ -25,15 +26,33 @@ impl Window {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_size(&mut self, size_x: u32, size_y: u32) {
|
||||
pub fn configure_size(&mut self, size: Option<Size<i32, Logical>>, bounds: Size<i32, Logical>) {
|
||||
self.toplevel.with_pending_state(|state| {
|
||||
//state.bounds = Some((size_x as i32, size_y as i32).into());
|
||||
state.size = Some((size_x as i32, size_y as i32).into());
|
||||
state.bounds = Some(bounds);
|
||||
state.size = size;
|
||||
});
|
||||
self.toplevel.send_configure();
|
||||
|
||||
if let Some(size) = size {
|
||||
self.remember_committed_size(size);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_size(&mut self, size: Size<i32, Logical>, bounds: Size<i32, Logical>) {
|
||||
let size = size.clamp(Size::new(1, 1), bounds);
|
||||
self.configure_size(Some(size), bounds);
|
||||
}
|
||||
|
||||
pub fn remember_committed_size(&mut self, size: Size<i32, Logical>) -> bool {
|
||||
let size_x = size.w.max(1) as u32;
|
||||
let size_y = size.h.max(1) as u32;
|
||||
|
||||
let changed = self.size_x != size_x || self.size_y != size_y;
|
||||
|
||||
self.size_x = size_x;
|
||||
self.size_y = size_y;
|
||||
|
||||
changed
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +97,7 @@ impl WindowManager {
|
|||
size_y: u32,
|
||||
) -> WindowHandle {
|
||||
let mut window = Window::new(toplevel, process);
|
||||
window.set_size(size_x, size_y);
|
||||
window.remember_committed_size(Size::new(size_x as i32, size_y as i32));
|
||||
self.windows.add(window)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use glam::{Affine2, Affine3A, Quat, Vec2, Vec3, vec2, vec3};
|
||||
use slotmap::Key;
|
||||
use smithay::{
|
||||
desktop::PopupManager,
|
||||
reexports::wayland_server::{Resource, backend::ObjectId, protocol::wl_surface::WlSurface},
|
||||
utils::{Logical, Point},
|
||||
utils::{Logical, Point, Size},
|
||||
wayland::{
|
||||
compositor::{
|
||||
SUBSURFACE_ROLE, SubsurfaceCachedState, SurfaceAttributes, TraversalAction,
|
||||
|
|
@ -37,6 +38,7 @@ use crate::{
|
|||
backend::{
|
||||
XrBackend,
|
||||
input::{self, HoverResult},
|
||||
task::{OverlayTask, TaskType},
|
||||
wayvr::{
|
||||
self, PointerFocusTarget, SurfaceBufWithImage, process::KillSignal,
|
||||
window::WindowHandle,
|
||||
|
|
@ -51,6 +53,7 @@ use crate::{
|
|||
state::{self, AppState},
|
||||
subsystem::{hid::WheelDelta, input::KeyboardFocus},
|
||||
windowing::{
|
||||
OverlayID, OverlaySelector,
|
||||
backend::{
|
||||
FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender,
|
||||
ui_transform,
|
||||
|
|
@ -75,8 +78,7 @@ pub fn create_wl_window_overlay(
|
|||
size: [u32; 2],
|
||||
pos_mode: PositionMode,
|
||||
) -> anyhow::Result<OverlayWindowConfig> {
|
||||
let scale = size[0].max(size[1]) as f32 / 1920.0;
|
||||
let curve_scale = size[0] as f32 / 1920.0;
|
||||
let (scale, curve_scale) = overlay_scale_from_extent(size);
|
||||
|
||||
let z_dist = if matches!(pos_mode, PositionMode::Anchor) {
|
||||
0.0
|
||||
|
|
@ -106,7 +108,11 @@ pub fn create_wl_window_overlay(
|
|||
category: OverlayCategory::WayVR,
|
||||
show_on_spawn: true,
|
||||
..OverlayWindowConfig::from_backend(Box::new(WvrWindowBackend::new(
|
||||
name, app, window, icon,
|
||||
name,
|
||||
app,
|
||||
window,
|
||||
icon,
|
||||
(scale, curve_scale),
|
||||
)?))
|
||||
})
|
||||
}
|
||||
|
|
@ -167,6 +173,8 @@ pub struct WvrWindowBackend {
|
|||
uv_range: RangeInclusive<f32>,
|
||||
panel_hovered: bool,
|
||||
scrolling: bool,
|
||||
overlay_id: OverlayID,
|
||||
scale: (f32, f32),
|
||||
}
|
||||
|
||||
impl WvrWindowBackend {
|
||||
|
|
@ -175,6 +183,7 @@ impl WvrWindowBackend {
|
|||
app: &mut AppState,
|
||||
window: wayvr::window::WindowHandle,
|
||||
icon: Arc<str>,
|
||||
scale: (f32, f32),
|
||||
) -> anyhow::Result<Self> {
|
||||
let subsurface_pipeline = app.gfx.create_pipeline(
|
||||
app.gfx_extras.shaders.get("vert_quad").unwrap(), // want panic
|
||||
|
|
@ -274,10 +283,43 @@ impl WvrWindowBackend {
|
|||
uv_range: 0.0..=1.0,
|
||||
panel_hovered: false,
|
||||
scrolling: false,
|
||||
overlay_id: OverlayID::null(),
|
||||
scale,
|
||||
})
|
||||
}
|
||||
|
||||
fn apply_extent(&mut self, app: &mut AppState, meta: &FrameMeta) -> anyhow::Result<()> {
|
||||
let (old_scale, old_curve_scale) = self.scale;
|
||||
let (new_scale, curve_scale) = overlay_scale_from_extent(meta.extent);
|
||||
self.scale = (new_scale, curve_scale);
|
||||
|
||||
if new_scale.abs() > f32::EPSILON {
|
||||
let scale_delta = new_scale / old_scale;
|
||||
let curve_scale_delta = curve_scale / old_curve_scale;
|
||||
|
||||
if (scale_delta - 1.0).abs() > f32::EPSILON
|
||||
|| (curve_scale_delta - 1.0).abs() > f32::EPSILON
|
||||
{
|
||||
app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify(
|
||||
OverlaySelector::Id(self.overlay_id),
|
||||
Box::new(move |_app, owc| {
|
||||
if let Some(state) = owc.active_state.as_mut() {
|
||||
if let Some(curvature) = state.curvature.as_mut() {
|
||||
*curvature = (curve_scale_delta * *curvature).clamp(0.0, 0.5);
|
||||
}
|
||||
|
||||
if let Some(saved) = state.saved_transform.as_mut() {
|
||||
saved.matrix3 = saved.matrix3.mul_scalar(scale_delta);
|
||||
}
|
||||
|
||||
state.transform.matrix3 =
|
||||
state.transform.matrix3.mul_scalar(scale_delta);
|
||||
}
|
||||
}),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
self.interaction_transform = Some(ui_transform(meta.extent));
|
||||
|
||||
let mut scale = vec2(
|
||||
|
|
@ -441,6 +483,35 @@ impl WvrWindowBackend {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sync_committed_toplevel_size(
|
||||
&mut self,
|
||||
app: &mut AppState,
|
||||
inner_extent: [u32; 2],
|
||||
) -> anyhow::Result<()> {
|
||||
let Some(wvr_server) = app.wvr_server.as_mut() else {
|
||||
return Ok(());
|
||||
};
|
||||
let bounds = wvr_server.manager.state.output_logical_size();
|
||||
let requested = Size::new(inner_extent[0].max(1) as i32, inner_extent[1].max(1) as i32);
|
||||
let clamped = requested.clamp(Size::new(1, 1), bounds);
|
||||
|
||||
let Some(window) = wvr_server.wm.windows.get_mut(&self.window) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
if requested == clamped {
|
||||
// client picked a new size that fits
|
||||
window.remember_committed_size(requested);
|
||||
} else {
|
||||
// client committed something outside the output bounds
|
||||
if window.size_x != clamped.w as u32 || window.size_y != clamped.h as u32 {
|
||||
window.request_size(clamped, bounds);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl OverlayBackend for WvrWindowBackend {
|
||||
|
|
@ -556,6 +627,8 @@ impl OverlayBackend for WvrWindowBackend {
|
|||
}
|
||||
|
||||
let inner_extent = meta.extent;
|
||||
self.sync_committed_toplevel_size(app, inner_extent)?;
|
||||
|
||||
meta.extent[0] += BORDER_SIZE * 2;
|
||||
meta.extent[1] += BORDER_SIZE * 2 + BAR_SIZE;
|
||||
|
||||
|
|
@ -695,6 +768,7 @@ impl OverlayBackend for WvrWindowBackend {
|
|||
) -> anyhow::Result<()> {
|
||||
match event_data {
|
||||
OverlayEventData::IdAssigned(oid) => {
|
||||
self.overlay_id = oid;
|
||||
let wvr_server = app.wvr_server.as_mut().unwrap(); //never None
|
||||
wvr_server.overlay_added(oid, self.window);
|
||||
}
|
||||
|
|
@ -1093,3 +1167,12 @@ fn surface_tree_input_hit_test(
|
|||
|
||||
hit
|
||||
}
|
||||
|
||||
fn overlay_scale_from_extent(size: [u32; 2]) -> (f32, f32) {
|
||||
const RELATIVE_SIZE: f32 = 1440.0; // sqrt(1920 * 1080)
|
||||
|
||||
let w = size[0].max(1) as f32;
|
||||
let h = size[1].max(1) as f32;
|
||||
|
||||
((w * h).sqrt() / RELATIVE_SIZE, w / 1920.0)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue