use crate::actors;
use crate::actors::external::debug;
use crate::animation;
use crate::data::loading;
use crate::event_loop;
use crate::panel;
use crate::state;
use glib::{ControlFlow, MainContext, Priority, Receiver};
mod c {
use super::*;
use std::ffi::CString;
use std::os::raw::{c_char, c_void};
use std::ptr;
use std::rc::Rc;
use std::time::Instant;
use crate::actors::Destination;
use crate::actors::popover;
use crate::event_loop::driver;
use crate::imservice::IMService;
use crate::imservice::c::InputMethod;
use crate::layout;
use crate::outputs::Outputs;
use crate::state;
use crate::submission::Submission;
use crate::util::c::{ArcWrapped, Wrapped};
use crate::vkeyboard::c::ZwpVirtualKeyboardV1;
#[repr(transparent)]
pub struct DBusHandler(*const c_void);
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct HintManager(*const c_void);
#[repr(C)]
pub struct RsObjects {
receiver: Wrapped<Receiver<Commands>>,
state_manager: Wrapped<EventLoop>,
submission: Wrapped<Submission>,
wayland: *mut Wayland,
popover: actors::popover::c::Actor,
}
#[repr(C)]
pub struct Wayland {
layer_shell: *const c_void,
virtual_keyboard_manager: *const c_void,
input_method_manager: *const c_void,
outputs: Wrapped<Outputs>,
seat: *const c_void,
input_method: InputMethod,
virtual_keyboard: ZwpVirtualKeyboardV1,
}
impl Wayland {
fn new(outputs_manager: Outputs) -> Self {
Wayland {
layer_shell: ptr::null(),
virtual_keyboard_manager: ptr::null(),
input_method_manager: ptr::null(),
outputs: Wrapped::new(outputs_manager),
seat: ptr::null(),
input_method: InputMethod::null(),
virtual_keyboard: ZwpVirtualKeyboardV1::null(),
}
}
}
extern "C" {
#[allow(improper_ctypes)]
fn init_wayland(wayland: *mut Wayland);
#[allow(improper_ctypes)]
fn eekboard_context_service_set_layout(service: HintManager, name: *const c_char, layout: *const layout::Layout, timestamp: u32);
fn dbus_handler_set_visible(dbus: *const DBusHandler, visible: u8);
}
#[no_mangle]
pub extern "C"
fn squeek_init() -> RsObjects {
let (sender, receiver) = MainContext::channel(Priority::default());
let now = Instant::now();
let state_manager = driver::Threaded::new(sender, state::Application::new(now));
debug::init(state_manager.clone());
let outputs = Outputs::new(state_manager.clone());
let mut wayland = Box::new(Wayland::new(outputs));
let wayland_raw = &mut *wayland as *mut _;
unsafe { init_wayland(wayland_raw); }
let vk = wayland.virtual_keyboard;
let imservice = if wayland.input_method.is_null() {
None
} else {
Some(IMService::new(wayland.input_method, state_manager.clone()))
};
let submission = Submission::new(vk, imservice);
let popover = ArcWrapped::new(actors::popover::State::new(true));
#[cfg(feature = "zbus_v1_5")]
crate::actors::external::screensaver::init(popover.clone_ref());
RsObjects {
submission: Wrapped::new(submission),
state_manager: Wrapped::new(state_manager),
receiver: Wrapped::new(receiver),
wayland: Box::into_raw(wayland),
popover,
}
}
#[no_mangle]
pub extern "C"
fn register_ui_loop_handler(
receiver: Wrapped<Receiver<Commands>>,
panel_manager: panel::c::PanelManager,
popover: actors::popover::c::Actor,
hint_manager: HintManager,
dbus_handler: *const DBusHandler,
) {
let receiver = unsafe { receiver.unwrap() };
let receiver = Rc::try_unwrap(receiver).expect("References still present");
let receiver = receiver.into_inner();
let panel_manager = Wrapped::new(panel::Manager::new(panel_manager));
let ctx = MainContext::default();
let _acqu = ctx.acquire();
receiver.attach(
Some(&ctx),
move |msg| {
main_loop_handle_message(
msg,
panel_manager.clone(),
&popover.clone_ref(),
hint_manager,
dbus_handler,
);
ControlFlow::Continue
},
);
}
fn main_loop_handle_message(
msg: Commands,
panel_manager: Wrapped<panel::Manager>,
popover: &actors::popover::Destination,
hint_manager: HintManager,
dbus_handler: *const DBusHandler,
) {
if let Some(visibility) = msg.panel_visibility {
panel::Manager::update(panel_manager, visibility);
}
if let Some(visible) = msg.dbus_visible_set {
if dbus_handler != std::ptr::null() {
unsafe { dbus_handler_set_visible(dbus_handler, visible as u8) };
}
}
if let Some(commands::SetLayout { description }) = msg.layout_selection {
let animation::Contents {
name,
kind,
overlay_name,
purpose,
} = description;
popover.send(popover::Event::Overlay(overlay_name.clone()));
let layout = loading::load_layout(&name, kind, purpose, &overlay_name);
let layout = Box::into_raw(Box::new(layout));
let name = overlay_name.unwrap_or(name).replace('+', "_");
let name = CString::new(name).unwrap_or(
CString::new("").unwrap()
);
unsafe {
let name = name.as_ptr();
eekboard_context_service_set_layout(hint_manager, name, layout, 0);
}
}
}
use crate::logging;
use crate::state::{Event, Presence};
use crate::state::LayoutChoice;
use crate::state::visibility;
use crate::util;
use crate::logging::Warn;
#[no_mangle]
pub extern "C"
fn squeek_state_send_force_visible(mgr: Wrapped<EventLoop>) {
let sender = mgr.clone_ref();
let sender = sender.borrow();
sender.send(Event::Visibility(visibility::Event::ForceVisible))
.or_warn(&mut logging::Print, logging::Problem::Warning, "Can't send to state manager");
}
#[no_mangle]
pub extern "C"
fn squeek_state_send_force_hidden(sender: Wrapped<EventLoop>) {
let sender = sender.clone_ref();
let sender = sender.borrow();
sender.send(Event::Visibility(visibility::Event::ForceHidden))
.or_warn(&mut logging::Print, logging::Problem::Warning, "Can't send to state manager");
}
#[no_mangle]
pub extern "C"
fn squeek_state_send_keyboard_present(sender: Wrapped<EventLoop>, present: u32) {
let sender = sender.clone_ref();
let sender = sender.borrow();
let state =
if present == 0 { Presence::Missing }
else { Presence::Present };
sender.send(Event::PhysicalKeyboard(state))
.or_warn(&mut logging::Print, logging::Problem::Warning, "Can't send to state manager");
}
#[no_mangle]
pub extern "C"
fn squeek_state_send_layout_set(
sender: Wrapped<EventLoop>,
name: *const c_char,
source: *const c_char,
_timestamp: u32,
) {
let sender = sender.clone_ref();
let sender = sender.borrow();
let string_or_empty = |v| String::from(
util::c::as_str(v)
.unwrap_or(Some(""))
.unwrap_or("")
);
sender
.send(Event::LayoutChoice(LayoutChoice {
name: string_or_empty(&name),
source: string_or_empty(&source).into(),
}))
.or_warn(&mut logging::Print, logging::Problem::Warning, "Can't send to state manager");
}
}
pub type EventLoop = event_loop::driver::Threaded<state::Application>;
pub mod commands {
use crate::animation;
#[derive(Clone, Debug)]
pub struct SetLayout {
pub description: animation::Contents,
}
}
#[derive(Clone)]
pub struct Commands {
pub panel_visibility: Option<panel::Command>,
pub dbus_visible_set: Option<bool>,
pub layout_selection: Option<commands::SetLayout>,
}