diff --git a/src/animation.rs b/src/animation.rs index ec7fc100..8a602fbd 100644 --- a/src/animation.rs +++ b/src/animation.rs @@ -14,6 +14,9 @@ pub const HIDING_TIMEOUT: Duration = Duration::from_millis(200); /// The outwardly visible state of visibility #[derive(PartialEq, Debug, Clone)] pub enum Outcome { - Visible(OutputId), + Visible { + output: OutputId, + height: u32, + }, Hidden, } diff --git a/src/event_loop/mod.rs b/src/event_loop/mod.rs index 99f7cdc9..118bb082 100644 --- a/src/event_loop/mod.rs +++ b/src/event_loop/mod.rs @@ -176,7 +176,7 @@ mod test { let l = State::new(state, now); let (l, commands) = handle_event(l, InputMethod::InactiveSince(now).into(), now); - assert_matches!(commands.panel_visibility, Some(PanelCommand::Show(_))); + assert_matches!(commands.panel_visibility, Some(PanelCommand::Show{..})); assert_eq!(l.scheduled_wakeup, Some(now + animation::HIDING_TIMEOUT)); now += animation::HIDING_TIMEOUT; diff --git a/src/main.rs b/src/main.rs index b1186fac..76266258 100644 --- a/src/main.rs +++ b/src/main.rs @@ -75,7 +75,7 @@ mod c { extern "C" { #[allow(improper_ctypes)] fn init_wayland(wayland: *mut Wayland); - fn server_context_service_real_show_keyboard(service: *const UIManager, output: WlOutput); + fn server_context_service_real_show_keyboard(service: *const UIManager, output: WlOutput, height: u32); fn server_context_service_real_hide_keyboard(service: *const UIManager); fn server_context_service_set_hint_purpose(service: *const UIManager, hint: u32, purpose: u32); // This should probably only get called from the gtk main loop, @@ -149,8 +149,8 @@ mod c { dbus_handler: *const DBusHandler, ) { match msg.panel_visibility { - Some(PanelCommand::Show(output)) => unsafe { - server_context_service_real_show_keyboard(ui_manager, output.0); + Some(PanelCommand::Show { output, height }) => unsafe { + server_context_service_real_show_keyboard(ui_manager, output.0, height); }, Some(PanelCommand::Hide) => unsafe { server_context_service_real_hide_keyboard(ui_manager); @@ -176,7 +176,10 @@ mod c { #[derive(Clone, PartialEq, Debug)] pub enum PanelCommand { - Show(OutputId), + Show { + output: OutputId, + height: u32, + }, Hide, } diff --git a/src/server-context-service.c b/src/server-context-service.c index 7a90e251..23fe42d7 100644 --- a/src/server-context-service.c +++ b/src/server-context-service.c @@ -141,14 +141,12 @@ on_surface_configure(ServerContextService *self, PhoshLayerSurface *surface) } static void -make_window (ServerContextService *self, struct wl_output *output) +make_window (ServerContextService *self, struct wl_output *output, uint32_t height) { if (self->window) { g_error("Window already present"); } - uint32_t height = squeek_uiman_get_perceptual_height(self->manager); - self->window = g_object_new ( PHOSH_TYPE_LAYER_SURFACE, "layer-shell", squeek_wayland->layer_shell, @@ -204,10 +202,10 @@ make_widget (ServerContextService *self) // Called from rust void -server_context_service_real_show_keyboard (ServerContextService *self, struct wl_output *output) +server_context_service_real_show_keyboard (ServerContextService *self, struct wl_output *output, uint32_t height) { if (!self->window) { - make_window (self, output); + make_window (self, output, height); } if (!self->widget) { make_widget (self); diff --git a/src/state.rs b/src/state.rs index e2085aa5..b4927bca 100644 --- a/src/state.rs +++ b/src/state.rs @@ -10,6 +10,7 @@ use crate::imservice::{ ContentHint, ContentPurpose }; use crate::main::{ Commands, PanelCommand }; use crate::outputs; use crate::outputs::{OutputId, OutputState}; +use std::cmp; use std::collections::HashMap; use std::time::Instant; @@ -93,12 +94,12 @@ impl Outcome { pub fn get_commands_to_reach(&self, new_state: &Self) -> Commands { let layout_hint_set = match new_state { Outcome { - visibility: animation::Outcome::Visible(_), + visibility: animation::Outcome::Visible{..}, im: InputMethod::Active(hints), } => Some(hints.clone()), Outcome { - visibility: animation::Outcome::Visible(_), + visibility: animation::Outcome::Visible{..}, im: InputMethod::InactiveSince(_), } => Some(InputMethodDetails { hint: ContentHint::NONE, @@ -112,7 +113,8 @@ impl Outcome { }; // FIXME: handle switching outputs let (dbus_visible_set, panel_visibility) = match new_state.visibility { - animation::Outcome::Visible(output) => (Some(true), Some(PanelCommand::Show(output))), + animation::Outcome::Visible{output, height} + => (Some(true), Some(PanelCommand::Show{output, height})), animation::Outcome::Hidden => (Some(false), Some(PanelCommand::Hide)), }; @@ -236,23 +238,48 @@ impl Application { } } + fn get_preferred_height(output: &OutputState) -> Option { + output.get_pixel_size() + .map(|px_size| { + if px_size.width > px_size.height { + px_size.width / 5 + } else { + if (px_size.width < 540) & (px_size.width > 0) { + px_size.width * 7 / 12 // to match 360×210 + } else { + // Here we switch to wide layout, less height needed + px_size.width * 7 / 22 + } + } + }) + } + pub fn get_outcome(&self, now: Instant) -> Outcome { // FIXME: include physical keyboard presence Outcome { visibility: match self.preferred_output { None => animation::Outcome::Hidden, - Some(output) => match (self.physical_keyboard, self.visibility_override) { - (_, visibility::State::ForcedHidden) => animation::Outcome::Hidden, - (_, visibility::State::ForcedVisible) => animation::Outcome::Visible(output), - (Presence::Present, visibility::State::NotForced) => animation::Outcome::Hidden, - (Presence::Missing, visibility::State::NotForced) => match self.im { - InputMethod::Active(_) => animation::Outcome::Visible(output), - InputMethod::InactiveSince(since) => { - if now < since + animation::HIDING_TIMEOUT { animation::Outcome::Visible(output) } - else { animation::Outcome::Hidden } + Some(output) => { + // Hoping that this will get optimized out on branches not using `visible`. + let height = Self::get_preferred_height(self.outputs.get(&output).unwrap()) + .unwrap_or(0); + // TODO: Instead of setting size to 0 when the output is invalid, + // simply go invisible. + let visible = animation::Outcome::Visible{output, height}; + + match (self.physical_keyboard, self.visibility_override) { + (_, visibility::State::ForcedHidden) => animation::Outcome::Hidden, + (_, visibility::State::ForcedVisible) => visible, + (Presence::Present, visibility::State::NotForced) => animation::Outcome::Hidden, + (Presence::Missing, visibility::State::NotForced) => match self.im { + InputMethod::Active(_) => visible, + InputMethod::InactiveSince(since) => { + if now < since + animation::HIDING_TIMEOUT { visible } + else { animation::Outcome::Hidden } + }, }, - }, - }, + } + } }, im: self.im.clone(), } @@ -331,7 +358,7 @@ pub mod test { now += Duration::from_millis(1); assert_matches!( state.get_outcome(now).visibility, - animation::Outcome::Visible(_), + animation::Outcome::Visible{..}, "Hidden when it should remain visible: {:?}", now.saturating_duration_since(start), ) @@ -339,7 +366,7 @@ pub mod test { let state = state.apply_event(Event::InputMethod(InputMethod::Active(imdetails_new())), now); - assert_matches!(state.get_outcome(now).visibility, animation::Outcome::Visible(_)); + assert_matches!(state.get_outcome(now).visibility, animation::Outcome::Visible{..}); } /// Make sure that hiding works when input method goes away @@ -356,7 +383,7 @@ pub mod test { let state = state.apply_event(Event::InputMethod(InputMethod::InactiveSince(now)), now); - while let animation::Outcome::Visible(_) = state.get_outcome(now).visibility { + while let animation::Outcome::Visible{..} = state.get_outcome(now).visibility { now += Duration::from_millis(1); assert!( now < start + Duration::from_millis(250), @@ -386,7 +413,7 @@ pub mod test { let state = state.apply_event(Event::InputMethod(InputMethod::Active(imdetails_new())), now); let state = state.apply_event(Event::InputMethod(InputMethod::InactiveSince(now)), now); - while let animation::Outcome::Visible(_) = state.get_outcome(now).visibility { + while let animation::Outcome::Visible{..} = state.get_outcome(now).visibility { now += Duration::from_millis(1); assert!( now < start + Duration::from_millis(250), @@ -422,7 +449,7 @@ pub mod test { let state = state.apply_event(Event::Visibility(visibility::Event::ForceVisible), now); assert_matches!( state.get_outcome(now).visibility, - animation::Outcome::Visible(_), + animation::Outcome::Visible{..}, "Failed to show: {:?}", now.saturating_duration_since(start), ); @@ -478,7 +505,7 @@ pub mod test { assert_matches!( state.get_outcome(now).visibility, - animation::Outcome::Visible(_), + animation::Outcome::Visible{..}, "Failed to appear: {:?}", now.saturating_duration_since(start), );