blob: 1d6ef0c5579804a19bac1db45b274f5fe9e23399 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::cell::RefCell;
use std::os::unix::io::{AsRawFd, IntoRawFd};
use std::os::unix::net::UnixStream;
use std::os::unix::process::CommandExt;
use std::process::Command;
use std::rc::Rc;
use log::debug;
use nix::sys::signal::{sigprocmask, SigSet, SigmaskHow};
use crate::ffi;
use crate::Server;
#[derive(Debug)]
pub struct Compositor {
pub server: Server,
pub terminate: bool,
pub native: ffi::weston_compositor,
}
impl Compositor {
pub fn new(ctx: *mut ffi::weston_log_context) -> Rc<RefCell<Self>> {
let server = Server::new();
let display_native = server.native;
let rc = Rc::new(RefCell::new(Compositor {
server: server,
terminate: false,
native: ffi::weston_compositor {
destroy_signal: ffi::wl_signal::zeroed(),
wl_display: display_native,
event_loop: unsafe { ffi::wl_event_loop_create() },
create_surface_signal: ffi::wl_signal::zeroed(),
activate_signal: ffi::wl_signal::zeroed(),
transform_signal: ffi::wl_signal::zeroed(),
idle_signal: ffi::wl_signal::zeroed(),
wake_signal: ffi::wl_signal::zeroed(),
show_input_panel_signal: ffi::wl_signal::zeroed(),
hide_input_panel_signal: ffi::wl_signal::zeroed(),
update_input_panel_signal: ffi::wl_signal::zeroed(),
seat_created_signal: ffi::wl_signal::zeroed(),
output_created_signal: ffi::wl_signal::zeroed(),
output_destroyed_signal: ffi::wl_signal::zeroed(),
output_moved_signal: ffi::wl_signal::zeroed(),
output_resized_signal: ffi::wl_signal::zeroed(),
output_heads_changed_signal: ffi::wl_signal::zeroed(),
session_signal: ffi::wl_signal::zeroed(),
session_active: true,
fade_layer: ffi::weston_layer::zeroed(),
cursor_layer: ffi::weston_layer::zeroed(),
pending_output_list: ffi::wl_list::zeroed(),
output_list: ffi::wl_list::zeroed(),
head_list: ffi::wl_list::zeroed(),
seat_list: ffi::wl_list::zeroed(),
layer_list: ffi::wl_list::zeroed(),
view_list: ffi::wl_list::zeroed(),
plane_list: ffi::wl_list::zeroed(),
key_binding_list: ffi::wl_list::zeroed(),
modifier_binding_list: ffi::wl_list::zeroed(),
button_binding_list: ffi::wl_list::zeroed(),
touch_binding_list: ffi::wl_list::zeroed(),
axis_binding_list: ffi::wl_list::zeroed(),
debug_binding_list: ffi::wl_list::zeroed(),
state: ffi::WESTON_COMPOSITOR_IDLE as u32,
idle_source: std::ptr::null_mut(),
idle_inhibit: 0,
idle_time: 0,
repaint_timer: std::ptr::null_mut(),
default_pointer_grab: std::ptr::null_mut(),
primary_plane: unsafe { std::mem::zeroed() },
capabilities: 0,
renderer: std::ptr::null_mut(),
read_format: ffi::pixman_format_code_t::PIXMAN_r8g8b8a8,
backend: std::ptr::null_mut(),
launcher: std::ptr::null_mut(),
plugin_api_list: ffi::wl_list::zeroed(),
output_id_pool: 0,
xkb_names: ffi::xkb_rule_names {
rules: std::ptr::null_mut(),
model: std::ptr::null_mut(),
layout: std::ptr::null_mut(),
variant: std::ptr::null_mut(),
options: std::ptr::null_mut(),
},
xkb_context: std::ptr::null_mut(),
xkb_info: std::ptr::null_mut(),
kb_repeat_rate: 0,
kb_repeat_delay: 0,
vt_switching: false,
presentation_clock: 0,
repaint_msec: 7,
activate_serial: 1,
pointer_constraints: std::ptr::null_mut(),
exit_code: 0,
user_data: std::ptr::null_mut(),
exit: None,
require_input: true,
heads_changed_signal: ffi::wl_signal::zeroed(),
heads_changed_source: std::ptr::null_mut(),
touch_mode: ffi::weston_touch_mode::WESTON_TOUCH_MODE_NORMAL,
touch_calibration: std::ptr::null_mut(),
touch_calibration_save: None,
calibrator_layer: ffi::weston_layer::zeroed(),
touch_calibrator: std::ptr::null_mut(),
weston_log_ctx: ctx,
debug_scene: std::ptr::null_mut(),
timeline: std::ptr::null_mut(),
content_protection: std::ptr::null_mut(),
},
}));
let mut compositor = rc.borrow_mut();
compositor.init();
Rc::clone(&rc)
}
fn init(&mut self) {
self.native.destroy_signal.init();
self.native.create_surface_signal.init();
self.native.activate_signal.init();
self.native.transform_signal.init();
self.native.idle_signal.init();
self.native.wake_signal.init();
self.native.show_input_panel_signal.init();
self.native.hide_input_panel_signal.init();
self.native.update_input_panel_signal.init();
self.native.seat_created_signal.init();
self.native.output_created_signal.init();
self.native.output_destroyed_signal.init();
self.native.output_moved_signal.init();
self.native.output_resized_signal.init();
self.native.heads_changed_signal.init();
self.native.output_heads_changed_signal.init();
self.native.session_signal.init();
self.native.view_list.init();
self.native.plane_list.init();
self.native.layer_list.init();
self.native.seat_list.init();
self.native.pending_output_list.init();
self.native.output_list.init();
self.native.head_list.init();
self.native.key_binding_list.init();
self.native.modifier_binding_list.init();
self.native.button_binding_list.init();
self.native.touch_binding_list.init();
self.native.axis_binding_list.init();
self.native.debug_binding_list.init();
self.native.plugin_api_list.init();
let compositor = &mut self.native as *mut _;
self.native.fade_layer.init(compositor);
self.native
.fade_layer
.set_position(ffi::weston_layer_position::WESTON_LAYER_POSITION_FADE);
self.native.cursor_layer.init(compositor);
self.native
.cursor_layer
.set_position(ffi::weston_layer_position::WESTON_LAYER_POSITION_CURSOR);
unsafe { ffi::weston_compositor_init(&mut self.native) };
}
pub fn add_heads_changed_listener(&mut self, listener: &mut ffi::wl_listener) {
unsafe { ffi::weston_compositor_add_heads_changed_listener(&mut self.native, listener) }
}
pub fn bind_key<F>(&mut self, key: u32, modifier: ffi::weston_keyboard_modifier, f: F)
where
F: Fn(&mut ffi::weston_keyboard, *const ffi::timespec, u32),
{
extern "C" fn call_key_closure<F>(
keyboard: *mut ffi::weston_keyboard,
time: *const ffi::timespec,
key: u32,
data: *mut std::ffi::c_void,
) where
F: Fn(&mut ffi::weston_keyboard, *const ffi::timespec, u32),
{
let keyboard = unsafe { &mut *keyboard };
(unsafe { &mut *(data as *mut F) })(keyboard, time, key)
}
let handler = Box::new(f);
unsafe {
ffi::weston_compositor_add_key_binding(
&mut self.native,
key,
modifier,
Some(call_key_closure::<F>),
Box::into_raw(handler) as *mut _,
)
};
}
pub fn bind_button<F>(&mut self, button: u32, modifier: ffi::weston_keyboard_modifier, f: F)
where
F: Fn(&mut ffi::weston_pointer, *const ffi::timespec, u32),
{
extern "C" fn call_button_closure<F>(
pointer: *mut ffi::weston_pointer,
time: *const ffi::timespec,
button: u32,
data: *mut std::ffi::c_void,
) where
F: Fn(&mut ffi::weston_pointer, *const ffi::timespec, u32),
{
let pointer = unsafe { &mut *pointer };
(unsafe { &mut *(data as *mut F) })(pointer, time, button)
}
let handler = Box::new(f);
unsafe {
ffi::weston_compositor_add_button_binding(
&mut self.native,
button,
modifier,
Some(call_button_closure::<F>),
Box::into_raw(handler) as *mut _,
)
};
}
pub fn bind_touch<F>(&mut self, modifier: ffi::weston_keyboard_modifier, f: F)
where
F: Fn(&mut ffi::weston_touch, *const ffi::timespec),
{
extern "C" fn call_touch_closure<F>(
touch: *mut ffi::weston_touch,
time: *const ffi::timespec,
data: *mut std::ffi::c_void,
) where
F: Fn(&mut ffi::weston_touch, *const ffi::timespec),
{
let touch = unsafe { &mut *touch };
(unsafe { &mut *(data as *mut F) })(touch, time)
}
let handler = Box::new(f);
unsafe {
ffi::weston_compositor_add_touch_binding(
&mut self.native,
modifier,
Some(call_touch_closure::<F>),
Box::into_raw(handler) as *mut _,
)
};
}
pub fn create_client_stream(&mut self, path: &str) -> std::io::Result<UnixStream> {
let (client_stream, server_stream) = UnixStream::pair()?;
let fd = client_stream.as_raw_fd();
unsafe {
use nix::fcntl::{fcntl, FdFlag, F_GETFD, F_SETFD};
Command::new(path)
// TODO: figure out why socket doesn't work
.env("WAYLAND_SOCKET", fd.to_string())
.pre_exec(move || {
sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&SigSet::all()), None)
.expect("sigprocmask failed");
let mut flags = FdFlag::from_bits_truncate(fcntl(fd, F_GETFD).unwrap());
flags.remove(FdFlag::FD_CLOEXEC);
fcntl(fd, F_SETFD(flags)).unwrap();
Ok(())
})
.spawn()?;
}
Ok(server_stream)
}
pub fn launch_client(&mut self, path: &str) -> std::io::Result<*mut ffi::wl_client> {
let stream = self.create_client_stream(path);
Ok(self.server.create_client(stream.unwrap().into_raw_fd()))
}
pub fn wake(&mut self) {
unsafe { ffi::weston_compositor_wake(&mut self.native) }
}
pub fn flush_heads_changed(&mut self) {
unsafe { ffi::weston_compositor_flush_heads_changed(&mut self.native) }
}
pub fn set_xkb_rule_names(&mut self, names: &mut ffi::xkb_rule_names) {
unsafe {
ffi::weston_compositor_set_xkb_rule_names(&mut self.native, names);
}
}
pub fn head_iter(&self) -> ffi::WlListIter<ffi::weston_head> {
wl_list_iter!(&self.native.head_list, ffi::weston_head, compositor_link)
}
pub fn head_iter_mut(&mut self) -> ffi::WlListIterMut<ffi::weston_head> {
wl_list_iter_mut!(
&mut self.native.head_list,
ffi::weston_head,
compositor_link
)
}
pub fn output_iter_mut(&mut self) -> ffi::WlListIterMut<ffi::weston_output> {
wl_list_iter_mut!(&mut self.native.output_list, ffi::weston_output, link)
}
pub fn default_output(&mut self) -> Option<&mut ffi::weston_output> {
self.output_iter_mut().next()
}
pub fn create_surface(&self) -> *mut ffi::weston_surface {
unsafe { ffi::weston_surface_create(&self.native as *const _ as *mut _) }
}
}
impl Drop for Compositor {
fn drop(&mut self) {
debug!("drop compositor");
unsafe {
ffi::weston_compositor_deinit(&mut self.native);
ffi::wl_event_loop_destroy(self.native.event_loop);
}
}
}