visibility: Forward panel height information to window creation
This commit is contained in:
@ -14,6 +14,9 @@ pub const HIDING_TIMEOUT: Duration = Duration::from_millis(200);
|
|||||||
/// The outwardly visible state of visibility
|
/// The outwardly visible state of visibility
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
pub enum Outcome {
|
pub enum Outcome {
|
||||||
Visible(OutputId),
|
Visible {
|
||||||
|
output: OutputId,
|
||||||
|
height: u32,
|
||||||
|
},
|
||||||
Hidden,
|
Hidden,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -176,7 +176,7 @@ mod test {
|
|||||||
|
|
||||||
let l = State::new(state, now);
|
let l = State::new(state, now);
|
||||||
let (l, commands) = handle_event(l, InputMethod::InactiveSince(now).into(), 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));
|
assert_eq!(l.scheduled_wakeup, Some(now + animation::HIDING_TIMEOUT));
|
||||||
|
|
||||||
now += animation::HIDING_TIMEOUT;
|
now += animation::HIDING_TIMEOUT;
|
||||||
|
|||||||
11
src/main.rs
11
src/main.rs
@ -75,7 +75,7 @@ mod c {
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#[allow(improper_ctypes)]
|
#[allow(improper_ctypes)]
|
||||||
fn init_wayland(wayland: *mut Wayland);
|
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_real_hide_keyboard(service: *const UIManager);
|
||||||
fn server_context_service_set_hint_purpose(service: *const UIManager, hint: u32, purpose: u32);
|
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,
|
// This should probably only get called from the gtk main loop,
|
||||||
@ -149,8 +149,8 @@ mod c {
|
|||||||
dbus_handler: *const DBusHandler,
|
dbus_handler: *const DBusHandler,
|
||||||
) {
|
) {
|
||||||
match msg.panel_visibility {
|
match msg.panel_visibility {
|
||||||
Some(PanelCommand::Show(output)) => unsafe {
|
Some(PanelCommand::Show { output, height }) => unsafe {
|
||||||
server_context_service_real_show_keyboard(ui_manager, output.0);
|
server_context_service_real_show_keyboard(ui_manager, output.0, height);
|
||||||
},
|
},
|
||||||
Some(PanelCommand::Hide) => unsafe {
|
Some(PanelCommand::Hide) => unsafe {
|
||||||
server_context_service_real_hide_keyboard(ui_manager);
|
server_context_service_real_hide_keyboard(ui_manager);
|
||||||
@ -176,7 +176,10 @@ mod c {
|
|||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub enum PanelCommand {
|
pub enum PanelCommand {
|
||||||
Show(OutputId),
|
Show {
|
||||||
|
output: OutputId,
|
||||||
|
height: u32,
|
||||||
|
},
|
||||||
Hide,
|
Hide,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -141,14 +141,12 @@ on_surface_configure(ServerContextService *self, PhoshLayerSurface *surface)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
make_window (ServerContextService *self, struct wl_output *output)
|
make_window (ServerContextService *self, struct wl_output *output, uint32_t height)
|
||||||
{
|
{
|
||||||
if (self->window) {
|
if (self->window) {
|
||||||
g_error("Window already present");
|
g_error("Window already present");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t height = squeek_uiman_get_perceptual_height(self->manager);
|
|
||||||
|
|
||||||
self->window = g_object_new (
|
self->window = g_object_new (
|
||||||
PHOSH_TYPE_LAYER_SURFACE,
|
PHOSH_TYPE_LAYER_SURFACE,
|
||||||
"layer-shell", squeek_wayland->layer_shell,
|
"layer-shell", squeek_wayland->layer_shell,
|
||||||
@ -204,10 +202,10 @@ make_widget (ServerContextService *self)
|
|||||||
|
|
||||||
// Called from rust
|
// Called from rust
|
||||||
void
|
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) {
|
if (!self->window) {
|
||||||
make_window (self, output);
|
make_window (self, output, height);
|
||||||
}
|
}
|
||||||
if (!self->widget) {
|
if (!self->widget) {
|
||||||
make_widget (self);
|
make_widget (self);
|
||||||
|
|||||||
55
src/state.rs
55
src/state.rs
@ -10,6 +10,7 @@ use crate::imservice::{ ContentHint, ContentPurpose };
|
|||||||
use crate::main::{ Commands, PanelCommand };
|
use crate::main::{ Commands, PanelCommand };
|
||||||
use crate::outputs;
|
use crate::outputs;
|
||||||
use crate::outputs::{OutputId, OutputState};
|
use crate::outputs::{OutputId, OutputState};
|
||||||
|
use std::cmp;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
@ -93,12 +94,12 @@ impl Outcome {
|
|||||||
pub fn get_commands_to_reach(&self, new_state: &Self) -> Commands {
|
pub fn get_commands_to_reach(&self, new_state: &Self) -> Commands {
|
||||||
let layout_hint_set = match new_state {
|
let layout_hint_set = match new_state {
|
||||||
Outcome {
|
Outcome {
|
||||||
visibility: animation::Outcome::Visible(_),
|
visibility: animation::Outcome::Visible{..},
|
||||||
im: InputMethod::Active(hints),
|
im: InputMethod::Active(hints),
|
||||||
} => Some(hints.clone()),
|
} => Some(hints.clone()),
|
||||||
|
|
||||||
Outcome {
|
Outcome {
|
||||||
visibility: animation::Outcome::Visible(_),
|
visibility: animation::Outcome::Visible{..},
|
||||||
im: InputMethod::InactiveSince(_),
|
im: InputMethod::InactiveSince(_),
|
||||||
} => Some(InputMethodDetails {
|
} => Some(InputMethodDetails {
|
||||||
hint: ContentHint::NONE,
|
hint: ContentHint::NONE,
|
||||||
@ -112,7 +113,8 @@ impl Outcome {
|
|||||||
};
|
};
|
||||||
// FIXME: handle switching outputs
|
// FIXME: handle switching outputs
|
||||||
let (dbus_visible_set, panel_visibility) = match new_state.visibility {
|
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)),
|
animation::Outcome::Hidden => (Some(false), Some(PanelCommand::Hide)),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -236,23 +238,48 @@ impl Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_preferred_height(output: &OutputState) -> Option<u32> {
|
||||||
|
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 {
|
pub fn get_outcome(&self, now: Instant) -> Outcome {
|
||||||
// FIXME: include physical keyboard presence
|
// FIXME: include physical keyboard presence
|
||||||
Outcome {
|
Outcome {
|
||||||
visibility: match self.preferred_output {
|
visibility: match self.preferred_output {
|
||||||
None => animation::Outcome::Hidden,
|
None => animation::Outcome::Hidden,
|
||||||
Some(output) => match (self.physical_keyboard, self.visibility_override) {
|
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::ForcedHidden) => animation::Outcome::Hidden,
|
||||||
(_, visibility::State::ForcedVisible) => animation::Outcome::Visible(output),
|
(_, visibility::State::ForcedVisible) => visible,
|
||||||
(Presence::Present, visibility::State::NotForced) => animation::Outcome::Hidden,
|
(Presence::Present, visibility::State::NotForced) => animation::Outcome::Hidden,
|
||||||
(Presence::Missing, visibility::State::NotForced) => match self.im {
|
(Presence::Missing, visibility::State::NotForced) => match self.im {
|
||||||
InputMethod::Active(_) => animation::Outcome::Visible(output),
|
InputMethod::Active(_) => visible,
|
||||||
InputMethod::InactiveSince(since) => {
|
InputMethod::InactiveSince(since) => {
|
||||||
if now < since + animation::HIDING_TIMEOUT { animation::Outcome::Visible(output) }
|
if now < since + animation::HIDING_TIMEOUT { visible }
|
||||||
else { animation::Outcome::Hidden }
|
else { animation::Outcome::Hidden }
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
im: self.im.clone(),
|
im: self.im.clone(),
|
||||||
}
|
}
|
||||||
@ -331,7 +358,7 @@ pub mod test {
|
|||||||
now += Duration::from_millis(1);
|
now += Duration::from_millis(1);
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
state.get_outcome(now).visibility,
|
state.get_outcome(now).visibility,
|
||||||
animation::Outcome::Visible(_),
|
animation::Outcome::Visible{..},
|
||||||
"Hidden when it should remain visible: {:?}",
|
"Hidden when it should remain visible: {:?}",
|
||||||
now.saturating_duration_since(start),
|
now.saturating_duration_since(start),
|
||||||
)
|
)
|
||||||
@ -339,7 +366,7 @@ pub mod test {
|
|||||||
|
|
||||||
let state = state.apply_event(Event::InputMethod(InputMethod::Active(imdetails_new())), now);
|
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
|
/// 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);
|
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);
|
now += Duration::from_millis(1);
|
||||||
assert!(
|
assert!(
|
||||||
now < start + Duration::from_millis(250),
|
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::Active(imdetails_new())), now);
|
||||||
let state = state.apply_event(Event::InputMethod(InputMethod::InactiveSince(now)), 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);
|
now += Duration::from_millis(1);
|
||||||
assert!(
|
assert!(
|
||||||
now < start + Duration::from_millis(250),
|
now < start + Duration::from_millis(250),
|
||||||
@ -422,7 +449,7 @@ pub mod test {
|
|||||||
let state = state.apply_event(Event::Visibility(visibility::Event::ForceVisible), now);
|
let state = state.apply_event(Event::Visibility(visibility::Event::ForceVisible), now);
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
state.get_outcome(now).visibility,
|
state.get_outcome(now).visibility,
|
||||||
animation::Outcome::Visible(_),
|
animation::Outcome::Visible{..},
|
||||||
"Failed to show: {:?}",
|
"Failed to show: {:?}",
|
||||||
now.saturating_duration_since(start),
|
now.saturating_duration_since(start),
|
||||||
);
|
);
|
||||||
@ -478,7 +505,7 @@ pub mod test {
|
|||||||
|
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
state.get_outcome(now).visibility,
|
state.get_outcome(now).visibility,
|
||||||
animation::Outcome::Visible(_),
|
animation::Outcome::Visible{..},
|
||||||
"Failed to appear: {:?}",
|
"Failed to appear: {:?}",
|
||||||
now.saturating_duration_since(start),
|
now.saturating_duration_since(start),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user