The on-screen keyboard is capped at 40 % of the screen height, and the runtime publishes the logical size of the output the main surface is on
The keyboard. The keys of the on-screen panel are as tall as one unit of the widest row is wide, so the panel's height follows its width. On a portrait phone that is about a quarter of the screen; turned to landscape the width becomes the long side, the keys grow with it and the six rows of a terminal keyboard take more than the screen. `Panel::height_within( width, scale, screen_height )` keeps `height` within 40 % of the screen height, the new `MAX_HEIGHT_FRACTION`, and `place_osk` uses it for the keyboard of a surface of ltk's own. `set_rect` no longer assumes it was given the natural height: the key height is the smaller of the unit and what the rectangle left after the padding and the gaps shares among the rows, so a capped panel gets wide and low keys, as the keyboards of other platforms have in landscape, while the key widths and the centring of the narrower rows are as before. A portrait screen is not affected, the natural height being below the cap there. A host that lays the panel out itself, as a compositor does, calls `height_within` for the height it reserves and `set_rect` with the rectangle it gets, so both agree. The output's size. `ltk::output_logical_size()` returns the logical size of the screen the main surface is on, or `None` before the compositor has described one, and `set_output_logical_size` records it. `viewport_size` follows the window, which is the wrong reference for a thing that has to be sized relative to the display, such as a window that must not be wider than the screen. The runtime now publishes the size when an output appears, changes or goes away, and when the main surface enters one, preferring the output of the main surface to the first one listed, and taking the current mode over the scale when the compositor sent no logical size. `window_fit` shares that lookup, `output_logical_size`, with what it did before, so the bounds it keeps a window size hint inside are unchanged. Not done. The 40 % is a constant and not a setting, the key labels are not scaled to the lower keys, and nothing offers the keyboard at the side of the screen in landscape, which would give the application more room on a wide display.
This commit is contained in:
@@ -154,7 +154,13 @@ impl<A: App> CompositorHandler for AppData<A>
|
||||
// exclusively by input events, poll_external messages, and configure events.
|
||||
}
|
||||
|
||||
fn surface_enter( &mut self, _: &Connection, _: &QueueHandle<Self>, _: &WlSurface, _: &WlOutput ) {}
|
||||
fn surface_enter( &mut self, _: &Connection, _: &QueueHandle<Self>, surface: &WlSurface, output: &WlOutput )
|
||||
{
|
||||
if self.main.surface.try_wl_surface() == Some( surface )
|
||||
{
|
||||
self.publish_output_size( Some( output ) );
|
||||
}
|
||||
}
|
||||
|
||||
fn surface_leave( &mut self, _: &Connection, _: &QueueHandle<Self>, _: &WlSurface, _: &WlOutput ) {}
|
||||
}
|
||||
@@ -333,6 +339,7 @@ impl<A: App> OutputHandler for AppData<A>
|
||||
|
||||
fn new_output( &mut self, _: &Connection, qh: &QueueHandle<Self>, output: WlOutput )
|
||||
{
|
||||
self.publish_output_size( None );
|
||||
// If we were waiting for an output to assign the layer surface to, create it now.
|
||||
// Same for any overlays that were created before an output existed.
|
||||
if let Some( ref layer_shell ) = self.layer_shell
|
||||
@@ -394,7 +401,10 @@ impl<A: App> OutputHandler for AppData<A>
|
||||
}
|
||||
}
|
||||
|
||||
fn update_output( &mut self, _: &Connection, _: &QueueHandle<Self>, _: WlOutput ) {}
|
||||
fn update_output( &mut self, _: &Connection, _: &QueueHandle<Self>, _: WlOutput )
|
||||
{
|
||||
self.publish_output_size( None );
|
||||
}
|
||||
|
||||
fn output_destroyed( &mut self, _: &Connection, _: &QueueHandle<Self>, output: WlOutput )
|
||||
{
|
||||
@@ -403,6 +413,7 @@ impl<A: App> OutputHandler for AppData<A>
|
||||
{
|
||||
self.main_output = None;
|
||||
}
|
||||
self.publish_output_size( None );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ use crate::types::{ Point, Rect };
|
||||
pub( crate ) fn place_osk( osk: &mut Option<Panel>, pw: u32, ph: u32, sf: f32 ) -> f32
|
||||
{
|
||||
let Some( panel ) = osk.as_mut() else { return 0.0 };
|
||||
let h = panel.height( pw as f32, sf ).min( ph as f32 );
|
||||
let h = panel.height_within( pw as f32, sf, ph as f32 );
|
||||
panel.set_rect( Rect { x: 0.0, y: ph as f32 - h, width: pw as f32, height: h }, sf );
|
||||
h
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
//! Keeps [`App::window_size_hint`](crate::App::window_size_hint) inside the screen.
|
||||
|
||||
use smithay_client_toolkit::reexports::client::protocol::wl_output::WlOutput;
|
||||
use smithay_client_toolkit::shell::xdg::window::Window;
|
||||
|
||||
use crate::app::App;
|
||||
@@ -42,15 +43,29 @@ impl<A: App> AppData<A>
|
||||
|
||||
fn output_bounds( &self ) -> Option<( u32, u32 )>
|
||||
{
|
||||
let info = self.output_state.outputs().find_map( |o| self.output_state.info( &o ) )?;
|
||||
let ( w, h ) = self.output_logical_size( None )?;
|
||||
Some( ( ( w as f32 * OUTPUT_SHARE ) as u32, ( h as f32 * OUTPUT_SHARE ) as u32 ) )
|
||||
}
|
||||
|
||||
fn output_logical_size( &self, preferred: Option<&WlOutput> ) -> Option<( u32, u32 )>
|
||||
{
|
||||
let info = preferred
|
||||
.or( self.main_output.as_ref() )
|
||||
.and_then( |o| self.output_state.info( o ) )
|
||||
.or_else( || self.output_state.outputs().find_map( |o| self.output_state.info( &o ) ) )?;
|
||||
let ( w, h ) = info.logical_size.or_else( ||
|
||||
{
|
||||
let mode = info.modes.iter().find( |m| m.current )?;
|
||||
let scale = info.scale_factor.max( 1 );
|
||||
Some( ( mode.dimensions.0 / scale, mode.dimensions.1 / scale ) )
|
||||
} )?;
|
||||
if w <= 0 || h <= 0 { return None; }
|
||||
Some( ( ( w as f32 * OUTPUT_SHARE ) as u32, ( h as f32 * OUTPUT_SHARE ) as u32 ) )
|
||||
( w > 0 && h > 0 ).then_some( ( w as u32, h as u32 ) )
|
||||
}
|
||||
|
||||
pub( crate ) fn publish_output_size( &self, preferred: Option<&WlOutput> )
|
||||
{
|
||||
let ( w, h ) = self.output_logical_size( preferred ).unwrap_or( ( 0, 0 ) );
|
||||
crate::types::set_output_logical_size( w, h );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -358,6 +358,7 @@ pub use types::{ density, set_density };
|
||||
pub use types::{ set_text_scale, text_scale };
|
||||
pub use types::{ widget_scaling, set_widget_scaling };
|
||||
pub use types::{ Orientation, orientation, viewport_size, set_viewport_size };
|
||||
pub use types::{ output_logical_size, set_output_logical_size };
|
||||
pub use widget::{ Element, button, icon_button, text_edit, image as img_widget, text, container };
|
||||
pub use text_shaping::measure_text;
|
||||
pub use widget::rich_text::{ rich_text, RichText, LinkSpan };
|
||||
|
||||
+11
-2
@@ -24,6 +24,7 @@ const SHIFT_DOUBLE_TAP: Duration = Duration::from_millis( 350 );
|
||||
const GAP: f32 = 6.0;
|
||||
const ROW_GAP: f32 = 2.0 * GAP;
|
||||
const PADDING: f32 = 6.0;
|
||||
const MAX_HEIGHT_FRACTION: f32 = 0.4;
|
||||
|
||||
/// What the field being typed into is for; picks the extra row above the layout.
|
||||
#[ derive( Clone, Copy, Debug, PartialEq, Eq, Default ) ]
|
||||
@@ -228,6 +229,12 @@ impl Panel
|
||||
rows * self.key_unit( width, scale ) + ( ( rows - 1.0 ).max( 0.0 ) * ROW_GAP + 2.0 * PADDING ) * scale
|
||||
}
|
||||
|
||||
/// [`Self::height`] kept within 40 % of `screen_height`, so a wide screen gets short keys instead of a keyboard that covers it.
|
||||
pub fn height_within( &self, width: f32, scale: f32, screen_height: f32 ) -> f32
|
||||
{
|
||||
self.height( width, scale ).min( screen_height * MAX_HEIGHT_FRACTION )
|
||||
}
|
||||
|
||||
/// Width of one key unit of the layout's rows, `width` pixels wide: the
|
||||
/// widest row fills the panel. Keys are as tall as one unit is wide.
|
||||
fn key_unit( &self, width: f32, scale: f32 ) -> f32
|
||||
@@ -250,7 +257,10 @@ impl Panel
|
||||
let gap = GAP * scale;
|
||||
let row_gap = ROW_GAP * scale;
|
||||
let pad = PADDING * scale;
|
||||
let key_h = self.key_unit( rect.width, scale );
|
||||
let unit = self.key_unit( rect.width, scale );
|
||||
let rows_n = ( self.bar_rows().len() + self.layout().rows( &self.layer ).len() ) as f32;
|
||||
let fit = ( rect.height - 2.0 * pad - ( rows_n - 1.0 ).max( 0.0 ) * row_gap ) / rows_n.max( 1.0 );
|
||||
let key_h = unit.min( fit.max( 1.0 ) );
|
||||
let avail = rect.width - 2.0 * pad;
|
||||
let mut y = rect.y + pad;
|
||||
|
||||
@@ -266,7 +276,6 @@ impl Panel
|
||||
let rows: Vec<Vec<Key>> = self.layout().rows( &self.layer ).iter()
|
||||
.map( |row| row.iter().map( |k| self.labelled( k ) ).collect() )
|
||||
.collect();
|
||||
let unit = key_h;
|
||||
for row in &rows
|
||||
{
|
||||
let units: f32 = row.iter().map( |k| k.width ).sum();
|
||||
|
||||
@@ -790,6 +790,27 @@ pub fn viewport_size() -> ( u32, u32 )
|
||||
( VIEWPORT_W.load( Ordering::Relaxed ), VIEWPORT_H.load( Ordering::Relaxed ) )
|
||||
}
|
||||
|
||||
static OUTPUT_W: AtomicU32 = AtomicU32::new( 0 );
|
||||
static OUTPUT_H: AtomicU32 = AtomicU32::new( 0 );
|
||||
|
||||
/// Record the logical size of the output the main surface is on. The
|
||||
/// runtime calls this when outputs appear, change or go away, and when the
|
||||
/// main surface enters one. `( 0, 0 )` clears it.
|
||||
pub fn set_output_logical_size( width: u32, height: u32 )
|
||||
{
|
||||
OUTPUT_W.store( width, Ordering::Relaxed );
|
||||
OUTPUT_H.store( height, Ordering::Relaxed );
|
||||
}
|
||||
|
||||
/// Logical size of the screen the main surface is on, or `None` before the
|
||||
/// compositor has described one. Unlike [`viewport_size`] it does not follow
|
||||
/// the window, so it can size things relative to the display.
|
||||
pub fn output_logical_size() -> Option<( u32, u32 )>
|
||||
{
|
||||
let size = ( OUTPUT_W.load( Ordering::Relaxed ), OUTPUT_H.load( Ordering::Relaxed ) );
|
||||
( size.0 > 0 && size.1 > 0 ).then_some( size )
|
||||
}
|
||||
|
||||
/// Orientation of the main surface: [`Orientation::Landscape`] when wider
|
||||
/// than tall, [`Orientation::Portrait`] otherwise (square counts as
|
||||
/// portrait, matching [`Length::orient`]'s resolution rule). Usable
|
||||
|
||||
Reference in New Issue
Block a user