Integrate native Rime and stabilize input, output, and rendering
- Add optional modifier-only Super binding whose tap is cancelled by other input, focus changes, grabs, locks, and session teardown. - Ship the native ferese-rime user service, Rime defaults, installer inventory, package dependencies, session environment, and docs. - Vendor Smithay 8a27023 with the SHM texture-cache format fix and add GPU regressions for format changes and resize snapshots. - Release reused CRTC owners before staging output modes, then restore changed outputs before former owners when a transaction fails. - Wait for resize-capture GPU completion, expand filtered surface damage, and preserve IME popup origin under fractional scaling. - Mark weekends like holidays in both calendar layouts.
This commit is contained in:
1 parent
a2be421974
commit
993bc0f88f
391 files changed
+130908
-76
No files matched your search
Vendored
+295
@@ -0,0 +1,295 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use ::winit::event_loop::pump_events::PumpStatus;
|
||||
use smithay::{
|
||||
backend::{
|
||||
input::{InputEvent, InputTime, KeyboardKeyEvent},
|
||||
renderer::{
|
||||
Color32F, Frame, Renderer,
|
||||
element::{
|
||||
Kind,
|
||||
surface::{WaylandSurfaceRenderElement, render_elements_from_surface_tree},
|
||||
},
|
||||
gles::GlesRenderer,
|
||||
utils::{draw_render_elements, on_commit_buffer_handler},
|
||||
},
|
||||
winit::{self, WinitEvent},
|
||||
},
|
||||
input::{Seat, SeatHandler, SeatState, keyboard::FilterResult},
|
||||
reexports::wayland_server::{Display, protocol::wl_seat},
|
||||
utils::{Rectangle, Serial, Transform},
|
||||
wayland::{
|
||||
buffer::BufferHandler,
|
||||
compositor::{
|
||||
CompositorClientState, CompositorHandler, CompositorState, SurfaceAttributes, TraversalAction,
|
||||
with_surface_tree_downward,
|
||||
},
|
||||
pointer_constraints::PointerConstraintsHandler,
|
||||
selection::{
|
||||
SelectionHandler,
|
||||
data_device::{DataDeviceHandler, DataDeviceState, WaylandDndGrabHandler},
|
||||
},
|
||||
shell::xdg::{PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState},
|
||||
shm::{ShmHandler, ShmState},
|
||||
},
|
||||
};
|
||||
use wayland_protocols::xdg::shell::server::xdg_toplevel;
|
||||
use wayland_server::{
|
||||
Client, ListeningSocket,
|
||||
backend::{ClientData, ClientId, DisconnectReason},
|
||||
protocol::{
|
||||
wl_buffer,
|
||||
wl_surface::{self, WlSurface},
|
||||
},
|
||||
};
|
||||
|
||||
impl BufferHandler for App {
|
||||
fn buffer_destroyed(&mut self, _buffer: &wl_buffer::WlBuffer) {}
|
||||
}
|
||||
|
||||
impl XdgShellHandler for App {
|
||||
fn xdg_shell_state(&mut self) -> &mut XdgShellState {
|
||||
&mut self.xdg_shell_state
|
||||
}
|
||||
|
||||
fn new_toplevel(&mut self, surface: ToplevelSurface) {
|
||||
surface.with_pending_state(|state| {
|
||||
state.states.set(xdg_toplevel::State::Activated);
|
||||
});
|
||||
surface.send_configure();
|
||||
}
|
||||
|
||||
fn new_popup(&mut self, _surface: PopupSurface, _positioner: PositionerState) {
|
||||
// Handle popup creation here
|
||||
}
|
||||
|
||||
fn grab(&mut self, _surface: PopupSurface, _seat: wl_seat::WlSeat, _serial: Serial) {
|
||||
// Handle popup grab here
|
||||
}
|
||||
|
||||
fn reposition_request(&mut self, _surface: PopupSurface, _positioner: PositionerState, _token: u32) {
|
||||
// Handle popup reposition here
|
||||
}
|
||||
}
|
||||
|
||||
impl SelectionHandler for App {
|
||||
type SelectionUserData = ();
|
||||
}
|
||||
|
||||
impl DataDeviceHandler for App {
|
||||
fn data_device_state(&mut self) -> &mut DataDeviceState {
|
||||
&mut self.data_device_state
|
||||
}
|
||||
}
|
||||
|
||||
impl WaylandDndGrabHandler for App {}
|
||||
|
||||
impl CompositorHandler for App {
|
||||
fn compositor_state(&mut self) -> &mut CompositorState {
|
||||
&mut self.compositor_state
|
||||
}
|
||||
|
||||
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
|
||||
&client.get_data::<ClientState>().unwrap().compositor_state
|
||||
}
|
||||
|
||||
fn commit(&mut self, surface: &WlSurface) {
|
||||
on_commit_buffer_handler::<Self>(surface);
|
||||
}
|
||||
}
|
||||
|
||||
impl ShmHandler for App {
|
||||
fn shm_state(&self) -> &ShmState {
|
||||
&self.shm_state
|
||||
}
|
||||
}
|
||||
|
||||
impl SeatHandler for App {
|
||||
type KeyboardFocus = WlSurface;
|
||||
type PointerFocus = WlSurface;
|
||||
type TouchFocus = WlSurface;
|
||||
|
||||
fn seat_state(&mut self) -> &mut SeatState<Self> {
|
||||
&mut self.seat_state
|
||||
}
|
||||
|
||||
fn focus_changed(&mut self, _seat: &Seat<Self>, _focused: Option<&WlSurface>) {}
|
||||
fn cursor_image(&mut self, _seat: &Seat<Self>, _image: smithay::input::pointer::CursorImageStatus) {}
|
||||
}
|
||||
|
||||
impl PointerConstraintsHandler for App {}
|
||||
|
||||
struct App {
|
||||
compositor_state: CompositorState,
|
||||
xdg_shell_state: XdgShellState,
|
||||
shm_state: ShmState,
|
||||
seat_state: SeatState<Self>,
|
||||
data_device_state: DataDeviceState,
|
||||
|
||||
seat: Seat<Self>,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
if let Ok(env_filter) = tracing_subscriber::EnvFilter::try_from_default_env() {
|
||||
tracing_subscriber::fmt().with_env_filter(env_filter).init();
|
||||
} else {
|
||||
tracing_subscriber::fmt().init();
|
||||
}
|
||||
|
||||
run_winit()
|
||||
}
|
||||
|
||||
pub fn run_winit() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut display: Display<App> = Display::new()?;
|
||||
let dh = display.handle();
|
||||
|
||||
let compositor_state = CompositorState::new::<App>(&dh);
|
||||
let shm_state = ShmState::new::<App>(&dh, vec![]);
|
||||
let mut seat_state = SeatState::new();
|
||||
let seat = seat_state.new_wl_seat(&dh, "winit");
|
||||
|
||||
let mut state = {
|
||||
App {
|
||||
compositor_state,
|
||||
xdg_shell_state: XdgShellState::new::<App>(&dh),
|
||||
shm_state,
|
||||
seat_state,
|
||||
data_device_state: DataDeviceState::new::<App>(&dh),
|
||||
seat,
|
||||
}
|
||||
};
|
||||
|
||||
let listener = ListeningSocket::bind("wayland-5").unwrap();
|
||||
let mut clients = Vec::new();
|
||||
|
||||
let (mut backend, mut winit) = winit::init::<GlesRenderer>()?;
|
||||
|
||||
let start_time = std::time::Instant::now();
|
||||
|
||||
let keyboard = state.seat.add_keyboard(Default::default(), 200, 200).unwrap();
|
||||
|
||||
unsafe { std::env::set_var("WAYLAND_DISPLAY", "wayland-5") };
|
||||
std::process::Command::new("weston-terminal").spawn().ok();
|
||||
|
||||
loop {
|
||||
let status = winit.dispatch_new_events(|event| match event {
|
||||
WinitEvent::Resized { .. } => {}
|
||||
WinitEvent::Input(event) => match event {
|
||||
InputEvent::Keyboard { event } => {
|
||||
keyboard.input::<(), _>(
|
||||
&mut state,
|
||||
event.key_code(),
|
||||
event.state(),
|
||||
0.into(),
|
||||
InputTime::now(),
|
||||
|_, _, _| {
|
||||
//
|
||||
FilterResult::Forward
|
||||
},
|
||||
);
|
||||
}
|
||||
InputEvent::PointerMotionAbsolute { .. } => {
|
||||
if let Some(surface) = state.xdg_shell_state.toplevel_surfaces().iter().next().cloned() {
|
||||
let surface = surface.wl_surface().clone();
|
||||
keyboard.set_focus(&mut state, Some(surface), 0.into());
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => (),
|
||||
});
|
||||
|
||||
match status {
|
||||
PumpStatus::Continue => (),
|
||||
PumpStatus::Exit(_) => return Ok(()),
|
||||
};
|
||||
|
||||
let size = backend.window_size();
|
||||
let damage = Rectangle::from_size(size);
|
||||
{
|
||||
let (renderer, mut framebuffer) = backend.bind().unwrap();
|
||||
let elements = state
|
||||
.xdg_shell_state
|
||||
.toplevel_surfaces()
|
||||
.iter()
|
||||
.flat_map(|surface| {
|
||||
render_elements_from_surface_tree(
|
||||
renderer,
|
||||
surface.wl_surface(),
|
||||
(0, 0),
|
||||
1.0,
|
||||
1.0,
|
||||
Kind::Unspecified,
|
||||
)
|
||||
})
|
||||
.collect::<Vec<WaylandSurfaceRenderElement<GlesRenderer>>>();
|
||||
|
||||
let mut frame = renderer
|
||||
.render(&mut framebuffer, size, Transform::Flipped180)
|
||||
.unwrap();
|
||||
frame.clear(Color32F::new(0.1, 0.0, 0.0, 1.0), &[damage]).unwrap();
|
||||
draw_render_elements(&mut frame, 1.0, &elements, &[damage]).unwrap();
|
||||
// We rely on the nested compositor to do the sync for us
|
||||
let _ = frame.finish().unwrap();
|
||||
|
||||
for surface in state.xdg_shell_state.toplevel_surfaces() {
|
||||
send_frames_surface_tree(surface.wl_surface(), start_time.elapsed().as_millis() as u32);
|
||||
}
|
||||
|
||||
if let Some(stream) = listener.accept()? {
|
||||
println!("Got a client: {:?}", stream);
|
||||
|
||||
let client = display
|
||||
.handle()
|
||||
.insert_client(stream, Arc::new(ClientState::default()))
|
||||
.unwrap();
|
||||
clients.push(client);
|
||||
}
|
||||
|
||||
display.dispatch_clients(&mut state)?;
|
||||
display.flush_clients()?;
|
||||
}
|
||||
|
||||
// It is important that all events on the display have been dispatched and flushed to clients before
|
||||
// swapping buffers because this operation may block.
|
||||
backend.submit(Some(&[damage])).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_frames_surface_tree(surface: &wl_surface::WlSurface, time: u32) {
|
||||
with_surface_tree_downward(
|
||||
surface,
|
||||
(),
|
||||
|_, _, &()| TraversalAction::DoChildren(()),
|
||||
|_surf, states, &()| {
|
||||
// the surface may not have any user_data if it is a subsurface and has not
|
||||
// yet been committed
|
||||
for callback in states
|
||||
.cached_state
|
||||
.get::<SurfaceAttributes>()
|
||||
.current()
|
||||
.frame_callbacks
|
||||
.drain(..)
|
||||
{
|
||||
callback.done(time);
|
||||
}
|
||||
},
|
||||
|_, _, &()| true,
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ClientState {
|
||||
compositor_state: CompositorClientState,
|
||||
}
|
||||
impl ClientData for ClientState {
|
||||
fn initialized(&self, _client_id: ClientId) {
|
||||
println!("initialized");
|
||||
}
|
||||
|
||||
fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) {
|
||||
println!("disconnected");
|
||||
}
|
||||
}
|
||||
|
||||
smithay::delegate_dispatch2!(App);
|
||||
Reference in new issue
Block a user