wayland: Listen to output changes
This commit is contained in:
@ -12,6 +12,7 @@ pub mod float_ord;
|
|||||||
pub mod imservice;
|
pub mod imservice;
|
||||||
mod keyboard;
|
mod keyboard;
|
||||||
mod layout;
|
mod layout;
|
||||||
|
mod outputs;
|
||||||
mod resources;
|
mod resources;
|
||||||
mod submission;
|
mod submission;
|
||||||
mod util;
|
mod util;
|
||||||
|
|||||||
13
src/outputs.h
Normal file
13
src/outputs.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef __OUTPUTS_H
|
||||||
|
#define __OUTPUTS_H
|
||||||
|
|
||||||
|
#include "wayland-client-protocol.h"
|
||||||
|
|
||||||
|
struct squeek_outputs;
|
||||||
|
|
||||||
|
struct squeek_outputs *squeek_outputs_new();
|
||||||
|
void squeek_outputs_free(struct squeek_outputs*);
|
||||||
|
void squeek_outputs_register(struct squeek_outputs*, struct wl_output *output);
|
||||||
|
struct wl_output *squeek_outputs_get_current(struct squeek_outputs*);
|
||||||
|
|
||||||
|
#endif
|
||||||
227
src/outputs.rs
Normal file
227
src/outputs.rs
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
/*! Managing Wayland outputs */
|
||||||
|
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
|
||||||
|
/// Gathers stuff defined in C or called by C
|
||||||
|
pub mod c {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use std::os::raw::{ c_char, c_void };
|
||||||
|
|
||||||
|
use ::util::c::COpaquePtr;
|
||||||
|
|
||||||
|
// Defined in C
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub struct WlOutput(*const c_void);
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct WlOutputListener<T: COpaquePtr> {
|
||||||
|
geometry: extern fn(
|
||||||
|
T, // data
|
||||||
|
WlOutput,
|
||||||
|
i32, // x
|
||||||
|
i32, // y
|
||||||
|
i32, // physical_width
|
||||||
|
i32, // physical_height
|
||||||
|
i32, // subpixel
|
||||||
|
*const c_char, // make
|
||||||
|
*const c_char, // model
|
||||||
|
i32, // transform
|
||||||
|
),
|
||||||
|
mode: extern fn(
|
||||||
|
T, // data
|
||||||
|
WlOutput,
|
||||||
|
u32, // flags
|
||||||
|
i32, // width
|
||||||
|
i32, // height
|
||||||
|
i32, // refresh
|
||||||
|
),
|
||||||
|
done: extern fn(
|
||||||
|
T, // data
|
||||||
|
WlOutput,
|
||||||
|
),
|
||||||
|
scale: extern fn(
|
||||||
|
T, // data
|
||||||
|
WlOutput,
|
||||||
|
i32, // factor
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags!{
|
||||||
|
/// Map to `wl_output.mode` values
|
||||||
|
pub struct Mode: u32 {
|
||||||
|
const NONE = 0x0;
|
||||||
|
const CURRENT = 0x1;
|
||||||
|
const PREFERRED = 0x2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
// Rustc wrongly assumes
|
||||||
|
// that COutputs allows C direct access to the underlying RefCell
|
||||||
|
#[allow(improper_ctypes)]
|
||||||
|
fn squeek_output_add_listener(
|
||||||
|
wl_output: WlOutput,
|
||||||
|
listener: *const WlOutputListener<COutputs>,
|
||||||
|
data: COutputs,
|
||||||
|
) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
type COutputs = ::util::c::Wrapped<Outputs>;
|
||||||
|
|
||||||
|
// Defined in Rust
|
||||||
|
|
||||||
|
extern fn outputs_handle_geometry(
|
||||||
|
_outputs: COutputs,
|
||||||
|
_wl_output: WlOutput,
|
||||||
|
_x: i32, _y: i32,
|
||||||
|
_phys_width: i32, _phys_height: i32,
|
||||||
|
_subpixel: i32,
|
||||||
|
_make: *const c_char, _model: *const c_char,
|
||||||
|
_transform: i32,
|
||||||
|
) {
|
||||||
|
//println!("geometry handled {},{}", x, y);
|
||||||
|
// Totally unused
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn outputs_handle_mode(
|
||||||
|
outputs: COutputs,
|
||||||
|
wl_output: WlOutput,
|
||||||
|
flags: u32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
_refresh: i32,
|
||||||
|
) {
|
||||||
|
let flags = Mode::from_bits(flags).unwrap_or_else(|| {
|
||||||
|
eprintln!("Warning: received invalid wl_output.mode flags");
|
||||||
|
Mode::NONE
|
||||||
|
});
|
||||||
|
let outputs = outputs.clone_ref();
|
||||||
|
let mut outputs = outputs.borrow_mut();
|
||||||
|
let mut output_state: Option<&mut OutputState> = outputs.outputs
|
||||||
|
.iter_mut()
|
||||||
|
.find_map(|o|
|
||||||
|
if o.output == wl_output { Some(&mut o.pending) } else { None }
|
||||||
|
);
|
||||||
|
match output_state {
|
||||||
|
Some(ref mut state) => {
|
||||||
|
if flags.contains(Mode::CURRENT) {
|
||||||
|
state.current_mode = Some(super::Mode { width, height});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => eprintln!("Wayland error: Got mode on unknown output"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn outputs_handle_done(
|
||||||
|
outputs: COutputs,
|
||||||
|
wl_output: WlOutput,
|
||||||
|
) {
|
||||||
|
let outputs = outputs.clone_ref();
|
||||||
|
let mut outputs = outputs.borrow_mut();
|
||||||
|
let mut output = outputs.outputs
|
||||||
|
.iter_mut()
|
||||||
|
.find(|o| o.output == wl_output);
|
||||||
|
match output {
|
||||||
|
Some(ref mut output) => { output.current = output.pending.clone(); }
|
||||||
|
None => eprintln!("Wayland error: Got done on unknown output"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn outputs_handle_scale(
|
||||||
|
outputs: COutputs,
|
||||||
|
wl_output: WlOutput,
|
||||||
|
factor: i32,
|
||||||
|
) {
|
||||||
|
let outputs = outputs.clone_ref();
|
||||||
|
let mut outputs = outputs.borrow_mut();
|
||||||
|
let output_state = outputs.outputs
|
||||||
|
.iter_mut()
|
||||||
|
.find_map(|o|
|
||||||
|
if o.output == wl_output { Some(&mut o.pending) } else { None }
|
||||||
|
);
|
||||||
|
match output_state {
|
||||||
|
Some(state) => { state.scale = factor; }
|
||||||
|
None => eprintln!("Wayland error: Got done on unknown output"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C"
|
||||||
|
fn squeek_outputs_new() -> COutputs {
|
||||||
|
COutputs::new(Outputs { outputs: Vec::new() })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C"
|
||||||
|
fn squeek_outputs_free(outputs: COutputs) {
|
||||||
|
unsafe { outputs.unwrap() }; // gets dropped
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C"
|
||||||
|
fn squeek_outputs_register(raw_collection: COutputs, output: WlOutput) {
|
||||||
|
let collection = raw_collection.clone_ref();
|
||||||
|
let mut collection = collection.borrow_mut();
|
||||||
|
collection.outputs.push(Output {
|
||||||
|
output: output.clone(),
|
||||||
|
pending: OutputState::uninitialized(),
|
||||||
|
current: OutputState::uninitialized(),
|
||||||
|
});
|
||||||
|
|
||||||
|
unsafe { squeek_output_add_listener(
|
||||||
|
output,
|
||||||
|
&WlOutputListener {
|
||||||
|
geometry: outputs_handle_geometry,
|
||||||
|
mode: outputs_handle_mode,
|
||||||
|
done: outputs_handle_done,
|
||||||
|
scale: outputs_handle_scale,
|
||||||
|
} as *const WlOutputListener<COutputs>,
|
||||||
|
raw_collection,
|
||||||
|
)};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C"
|
||||||
|
fn squeek_outputs_get_current(raw_collection: COutputs) -> WlOutput {
|
||||||
|
let collection = raw_collection.clone_ref();
|
||||||
|
let collection = collection.borrow();
|
||||||
|
collection.outputs[0].output.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle unregistration
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Mode {
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct OutputState {
|
||||||
|
current_mode: Option<Mode>,
|
||||||
|
scale: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutputState {
|
||||||
|
fn uninitialized() -> OutputState {
|
||||||
|
OutputState {
|
||||||
|
current_mode: None,
|
||||||
|
scale: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Output {
|
||||||
|
output: c::WlOutput,
|
||||||
|
pending: OutputState,
|
||||||
|
current: OutputState,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Outputs {
|
||||||
|
outputs: Vec<Output>,
|
||||||
|
}
|
||||||
@ -120,10 +120,12 @@ make_window (ServerContextService *context)
|
|||||||
if (context->window)
|
if (context->window)
|
||||||
g_error("Window already present");
|
g_error("Window already present");
|
||||||
|
|
||||||
|
struct wl_output *output = squeek_outputs_get_current(squeek_wayland->outputs);
|
||||||
|
|
||||||
context->window = g_object_new (
|
context->window = g_object_new (
|
||||||
PHOSH_TYPE_LAYER_SURFACE,
|
PHOSH_TYPE_LAYER_SURFACE,
|
||||||
"layer-shell", squeek_wayland->layer_shell,
|
"layer-shell", squeek_wayland->layer_shell,
|
||||||
"wl-output", g_ptr_array_index(squeek_wayland->outputs, 0), // TODO: select output as needed,
|
"wl-output", output,
|
||||||
"height", KEYBOARD_HEIGHT,
|
"height", KEYBOARD_HEIGHT,
|
||||||
"anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
|
"anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
|
||||||
| ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
|
| ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
|
||||||
|
|||||||
@ -28,6 +28,7 @@
|
|||||||
#include "eekboard/eekboard-service.h"
|
#include "eekboard/eekboard-service.h"
|
||||||
#include "eek/eek.h"
|
#include "eek/eek.h"
|
||||||
#include "imservice.h"
|
#include "imservice.h"
|
||||||
|
#include "outputs.h"
|
||||||
#include "server-context-service.h"
|
#include "server-context-service.h"
|
||||||
#include "wayland.h"
|
#include "wayland.h"
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ registry_handle_global (void *data,
|
|||||||
} else if (!strcmp (interface, "wl_output")) {
|
} else if (!strcmp (interface, "wl_output")) {
|
||||||
struct wl_output *output = wl_registry_bind (registry, name,
|
struct wl_output *output = wl_registry_bind (registry, name,
|
||||||
&wl_output_interface, 2);
|
&wl_output_interface, 2);
|
||||||
g_ptr_array_add (instance->wayland.outputs, output);
|
squeek_outputs_register(instance->wayland.outputs, output);
|
||||||
} else if (!strcmp(interface, "wl_seat")) {
|
} else if (!strcmp(interface, "wl_seat")) {
|
||||||
instance->wayland.seat = wl_registry_bind(registry, name,
|
instance->wayland.seat = wl_registry_bind(registry, name,
|
||||||
&wl_seat_interface, 1);
|
&wl_seat_interface, 1);
|
||||||
|
|||||||
@ -62,6 +62,10 @@ pub mod c {
|
|||||||
assert_eq!(as_str(&ptr::null()), Ok(None))
|
assert_eq!(as_str(&ptr::null()), Ok(None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Marker trait for values that can be transferred to/received from C.
|
||||||
|
/// They must be either *const or *mut or repr(transparent).
|
||||||
|
pub trait COpaquePtr {}
|
||||||
|
|
||||||
/// Wraps structures to pass them safely to/from C
|
/// Wraps structures to pass them safely to/from C
|
||||||
/// Since C doesn't respect borrowing rules,
|
/// Since C doesn't respect borrowing rules,
|
||||||
@ -79,6 +83,9 @@ pub mod c {
|
|||||||
// which is a bit too complex for now.
|
// which is a bit too complex for now.
|
||||||
|
|
||||||
impl<T> Wrapped<T> {
|
impl<T> Wrapped<T> {
|
||||||
|
pub fn new(value: T) -> Wrapped<T> {
|
||||||
|
Wrapped::wrap(Rc::new(RefCell::new(value)))
|
||||||
|
}
|
||||||
pub fn wrap(state: Rc<RefCell<T>>) -> Wrapped<T> {
|
pub fn wrap(state: Rc<RefCell<T>>) -> Wrapped<T> {
|
||||||
Wrapped(Rc::into_raw(state))
|
Wrapped(Rc::into_raw(state))
|
||||||
}
|
}
|
||||||
@ -116,6 +123,8 @@ pub mod c {
|
|||||||
r.to_owned()
|
r.to_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> COpaquePtr for Wrapped<T> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CloneOwned {
|
pub trait CloneOwned {
|
||||||
|
|||||||
@ -10,3 +10,8 @@ void
|
|||||||
eek_virtual_keyboard_v1_key(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, uint32_t time, uint32_t key, uint32_t state) {
|
eek_virtual_keyboard_v1_key(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, uint32_t time, uint32_t key, uint32_t state) {
|
||||||
zwp_virtual_keyboard_v1_key(zwp_virtual_keyboard_v1, time, key, state);
|
zwp_virtual_keyboard_v1_key(zwp_virtual_keyboard_v1, time, key, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int squeek_output_add_listener(struct wl_output *wl_output,
|
||||||
|
const struct wl_output_listener *listener, void *data) {
|
||||||
|
return wl_output_add_listener(wl_output, listener, data);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
#ifndef WAYLAND_H
|
#ifndef WAYLAND_H
|
||||||
#define WAYLAND_H
|
#define WAYLAND_H
|
||||||
|
|
||||||
|
#include <gmodule.h>
|
||||||
|
|
||||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||||
#include "virtual-keyboard-unstable-v1-client-protocol.h"
|
#include "virtual-keyboard-unstable-v1-client-protocol.h"
|
||||||
#include "input-method-unstable-v2-client-protocol.h"
|
#include "input-method-unstable-v2-client-protocol.h"
|
||||||
|
|
||||||
#include <gmodule.h>
|
#include "outputs.h"
|
||||||
|
|
||||||
|
|
||||||
struct squeek_wayland {
|
struct squeek_wayland {
|
||||||
struct zwlr_layer_shell_v1 *layer_shell;
|
struct zwlr_layer_shell_v1 *layer_shell;
|
||||||
struct zwp_virtual_keyboard_manager_v1 *virtual_keyboard_manager;
|
struct zwp_virtual_keyboard_manager_v1 *virtual_keyboard_manager;
|
||||||
struct zwp_input_method_manager_v2 *input_method_manager;
|
struct zwp_input_method_manager_v2 *input_method_manager;
|
||||||
GPtrArray *outputs; // *wl_output
|
struct squeek_outputs *outputs;
|
||||||
struct wl_seat *seat;
|
struct wl_seat *seat;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ extern struct squeek_wayland *squeek_wayland;
|
|||||||
|
|
||||||
|
|
||||||
static inline void squeek_wayland_init(struct squeek_wayland *wayland) {
|
static inline void squeek_wayland_init(struct squeek_wayland *wayland) {
|
||||||
wayland->outputs = g_ptr_array_new();
|
wayland->outputs = squeek_outputs_new();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void squeek_wayland_set_global(struct squeek_wayland *wayland) {
|
static inline void squeek_wayland_set_global(struct squeek_wayland *wayland) {
|
||||||
@ -29,7 +30,7 @@ static inline void squeek_wayland_set_global(struct squeek_wayland *wayland) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void squeek_wayland_deinit(struct squeek_wayland *wayland) {
|
static inline void squeek_wayland_deinit(struct squeek_wayland *wayland) {
|
||||||
g_ptr_array_free(wayland->outputs, TRUE);
|
squeek_outputs_free(wayland->outputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // WAYLAND_H
|
#endif // WAYLAND_H
|
||||||
|
|||||||
Reference in New Issue
Block a user