Move Wayland backend to winit-wayland (#4252)
This commit is contained in:
parent
927af44aa4
commit
1126e9ea2f
29 changed files with 181 additions and 138 deletions
67
winit-wayland/src/types/cursor.rs
Normal file
67
winit-wayland/src/types/cursor.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
use cursor_icon::CursorIcon;
|
||||
use sctk::reexports::client::protocol::wl_shm::Format;
|
||||
use sctk::shm::slot::{Buffer, SlotPool};
|
||||
use winit_core::cursor::{CursorImage, CustomCursorProvider};
|
||||
|
||||
// Wrap in our own type to not impl trait on global type.
|
||||
#[derive(Debug)]
|
||||
pub struct WaylandCustomCursor(pub(crate) CursorImage);
|
||||
impl CustomCursorProvider for WaylandCustomCursor {
|
||||
fn is_animated(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SelectedCursor {
|
||||
Named(CursorIcon),
|
||||
Custom(CustomCursor),
|
||||
}
|
||||
|
||||
impl Default for SelectedCursor {
|
||||
fn default() -> Self {
|
||||
Self::Named(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CustomCursor {
|
||||
pub buffer: Buffer,
|
||||
pub w: i32,
|
||||
pub h: i32,
|
||||
pub hotspot_x: i32,
|
||||
pub hotspot_y: i32,
|
||||
}
|
||||
|
||||
impl CustomCursor {
|
||||
pub(crate) fn new(pool: &mut SlotPool, image: &WaylandCustomCursor) -> Self {
|
||||
let image = &image.0;
|
||||
let (buffer, canvas) = pool
|
||||
.create_buffer(
|
||||
image.width() as i32,
|
||||
image.height() as i32,
|
||||
4 * (image.width() as i32),
|
||||
Format::Argb8888,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
for (canvas_chunk, rgba) in canvas.chunks_exact_mut(4).zip(image.buffer().chunks_exact(4)) {
|
||||
// Alpha in buffer is premultiplied.
|
||||
let alpha = rgba[3] as f32 / 255.;
|
||||
let r = (rgba[0] as f32 * alpha) as u32;
|
||||
let g = (rgba[1] as f32 * alpha) as u32;
|
||||
let b = (rgba[2] as f32 * alpha) as u32;
|
||||
let color = ((rgba[3] as u32) << 24) + (r << 16) + (g << 8) + b;
|
||||
let array: &mut [u8; 4] = canvas_chunk.try_into().unwrap();
|
||||
*array = color.to_le_bytes();
|
||||
}
|
||||
|
||||
CustomCursor {
|
||||
buffer,
|
||||
w: image.width() as i32,
|
||||
h: image.height() as i32,
|
||||
hotspot_x: image.hotspot_x() as i32,
|
||||
hotspot_y: image.hotspot_y() as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
67
winit-wayland/src/types/kwin_blur.rs
Normal file
67
winit-wayland/src/types/kwin_blur.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
//! Handling of KDE-compatible blur.
|
||||
|
||||
use sctk::globals::GlobalData;
|
||||
use sctk::reexports::client::globals::{BindError, GlobalList};
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::{delegate_dispatch, Connection, Dispatch, Proxy, QueueHandle};
|
||||
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;
|
||||
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur_manager::OrgKdeKwinBlurManager;
|
||||
|
||||
use crate::state::WinitState;
|
||||
|
||||
/// KWin blur manager.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct KWinBlurManager {
|
||||
manager: OrgKdeKwinBlurManager,
|
||||
}
|
||||
|
||||
impl KWinBlurManager {
|
||||
pub fn new(
|
||||
globals: &GlobalList,
|
||||
queue_handle: &QueueHandle<WinitState>,
|
||||
) -> Result<Self, BindError> {
|
||||
let manager = globals.bind(queue_handle, 1..=1, GlobalData)?;
|
||||
Ok(Self { manager })
|
||||
}
|
||||
|
||||
pub fn blur(
|
||||
&self,
|
||||
surface: &WlSurface,
|
||||
queue_handle: &QueueHandle<WinitState>,
|
||||
) -> OrgKdeKwinBlur {
|
||||
self.manager.create(surface, queue_handle, ())
|
||||
}
|
||||
|
||||
pub fn unset(&self, surface: &WlSurface) {
|
||||
self.manager.unset(surface)
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<OrgKdeKwinBlurManager, GlobalData, WinitState> for KWinBlurManager {
|
||||
fn event(
|
||||
_: &mut WinitState,
|
||||
_: &OrgKdeKwinBlurManager,
|
||||
_: <OrgKdeKwinBlurManager as Proxy>::Event,
|
||||
_: &GlobalData,
|
||||
_: &Connection,
|
||||
_: &QueueHandle<WinitState>,
|
||||
) {
|
||||
unreachable!("no events defined for org_kde_kwin_blur_manager");
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<OrgKdeKwinBlur, (), WinitState> for KWinBlurManager {
|
||||
fn event(
|
||||
_: &mut WinitState,
|
||||
_: &OrgKdeKwinBlur,
|
||||
_: <OrgKdeKwinBlur as Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<WinitState>,
|
||||
) {
|
||||
unreachable!("no events defined for org_kde_kwin_blur");
|
||||
}
|
||||
}
|
||||
|
||||
delegate_dispatch!(WinitState: [OrgKdeKwinBlurManager: GlobalData] => KWinBlurManager);
|
||||
delegate_dispatch!(WinitState: [OrgKdeKwinBlur: ()] => KWinBlurManager);
|
||||
7
winit-wayland/src/types/mod.rs
Normal file
7
winit-wayland/src/types/mod.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
//! Wayland protocol implementation boilerplate.
|
||||
|
||||
pub mod cursor;
|
||||
pub mod kwin_blur;
|
||||
pub mod wp_fractional_scaling;
|
||||
pub mod wp_viewporter;
|
||||
pub mod xdg_activation;
|
||||
77
winit-wayland/src/types/wp_fractional_scaling.rs
Normal file
77
winit-wayland/src/types/wp_fractional_scaling.rs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
//! Handling of the fractional scaling.
|
||||
|
||||
use sctk::globals::GlobalData;
|
||||
use sctk::reexports::client::globals::{BindError, GlobalList};
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::{delegate_dispatch, Connection, Dispatch, Proxy, QueueHandle};
|
||||
use sctk::reexports::protocols::wp::fractional_scale::v1::client::wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1;
|
||||
use sctk::reexports::protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::{
|
||||
Event as FractionalScalingEvent, WpFractionalScaleV1,
|
||||
};
|
||||
|
||||
use crate::state::WinitState;
|
||||
|
||||
/// The scaling factor denominator.
|
||||
const SCALE_DENOMINATOR: f64 = 120.;
|
||||
|
||||
/// Fractional scaling manager.
|
||||
#[derive(Debug)]
|
||||
pub struct FractionalScalingManager {
|
||||
manager: WpFractionalScaleManagerV1,
|
||||
}
|
||||
|
||||
pub struct FractionalScaling {
|
||||
/// The surface used for scaling.
|
||||
surface: WlSurface,
|
||||
}
|
||||
|
||||
impl FractionalScalingManager {
|
||||
/// Create new viewporter.
|
||||
pub fn new(
|
||||
globals: &GlobalList,
|
||||
queue_handle: &QueueHandle<WinitState>,
|
||||
) -> Result<Self, BindError> {
|
||||
let manager = globals.bind(queue_handle, 1..=1, GlobalData)?;
|
||||
Ok(Self { manager })
|
||||
}
|
||||
|
||||
pub fn fractional_scaling(
|
||||
&self,
|
||||
surface: &WlSurface,
|
||||
queue_handle: &QueueHandle<WinitState>,
|
||||
) -> WpFractionalScaleV1 {
|
||||
let data = FractionalScaling { surface: surface.clone() };
|
||||
self.manager.get_fractional_scale(surface, queue_handle, data)
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<WpFractionalScaleManagerV1, GlobalData, WinitState> for FractionalScalingManager {
|
||||
fn event(
|
||||
_: &mut WinitState,
|
||||
_: &WpFractionalScaleManagerV1,
|
||||
_: <WpFractionalScaleManagerV1 as Proxy>::Event,
|
||||
_: &GlobalData,
|
||||
_: &Connection,
|
||||
_: &QueueHandle<WinitState>,
|
||||
) {
|
||||
// No events.
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<WpFractionalScaleV1, FractionalScaling, WinitState> for FractionalScalingManager {
|
||||
fn event(
|
||||
state: &mut WinitState,
|
||||
_: &WpFractionalScaleV1,
|
||||
event: <WpFractionalScaleV1 as Proxy>::Event,
|
||||
data: &FractionalScaling,
|
||||
_: &Connection,
|
||||
_: &QueueHandle<WinitState>,
|
||||
) {
|
||||
if let FractionalScalingEvent::PreferredScale { scale } = event {
|
||||
state.scale_factor_changed(&data.surface, scale as f64 / SCALE_DENOMINATOR, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delegate_dispatch!(WinitState: [WpFractionalScaleManagerV1: GlobalData] => FractionalScalingManager);
|
||||
delegate_dispatch!(WinitState: [WpFractionalScaleV1: FractionalScaling] => FractionalScalingManager);
|
||||
64
winit-wayland/src/types/wp_viewporter.rs
Normal file
64
winit-wayland/src/types/wp_viewporter.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
//! Handling of the wp-viewporter.
|
||||
|
||||
use sctk::globals::GlobalData;
|
||||
use sctk::reexports::client::globals::{BindError, GlobalList};
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::{delegate_dispatch, Connection, Dispatch, Proxy, QueueHandle};
|
||||
use sctk::reexports::protocols::wp::viewporter::client::wp_viewport::WpViewport;
|
||||
use sctk::reexports::protocols::wp::viewporter::client::wp_viewporter::WpViewporter;
|
||||
|
||||
use crate::state::WinitState;
|
||||
|
||||
/// Viewporter.
|
||||
#[derive(Debug)]
|
||||
pub struct ViewporterState {
|
||||
viewporter: WpViewporter,
|
||||
}
|
||||
|
||||
impl ViewporterState {
|
||||
/// Create new viewporter.
|
||||
pub fn new(
|
||||
globals: &GlobalList,
|
||||
queue_handle: &QueueHandle<WinitState>,
|
||||
) -> Result<Self, BindError> {
|
||||
let viewporter = globals.bind(queue_handle, 1..=1, GlobalData)?;
|
||||
Ok(Self { viewporter })
|
||||
}
|
||||
|
||||
/// Get the viewport for the given object.
|
||||
pub fn get_viewport(
|
||||
&self,
|
||||
surface: &WlSurface,
|
||||
queue_handle: &QueueHandle<WinitState>,
|
||||
) -> WpViewport {
|
||||
self.viewporter.get_viewport(surface, queue_handle, GlobalData)
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<WpViewporter, GlobalData, WinitState> for ViewporterState {
|
||||
fn event(
|
||||
_: &mut WinitState,
|
||||
_: &WpViewporter,
|
||||
_: <WpViewporter as Proxy>::Event,
|
||||
_: &GlobalData,
|
||||
_: &Connection,
|
||||
_: &QueueHandle<WinitState>,
|
||||
) {
|
||||
// No events.
|
||||
}
|
||||
}
|
||||
impl Dispatch<WpViewport, GlobalData, WinitState> for ViewporterState {
|
||||
fn event(
|
||||
_: &mut WinitState,
|
||||
_: &WpViewport,
|
||||
_: <WpViewport as Proxy>::Event,
|
||||
_: &GlobalData,
|
||||
_: &Connection,
|
||||
_: &QueueHandle<WinitState>,
|
||||
) {
|
||||
// No events.
|
||||
}
|
||||
}
|
||||
|
||||
delegate_dispatch!(WinitState: [WpViewporter: GlobalData] => ViewporterState);
|
||||
delegate_dispatch!(WinitState: [WpViewport: GlobalData] => ViewporterState);
|
||||
102
winit-wayland/src/types/xdg_activation.rs
Normal file
102
winit-wayland/src/types/xdg_activation.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
//! Handling of xdg activation, which is used for user attention requests.
|
||||
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Weak;
|
||||
|
||||
use sctk::globals::GlobalData;
|
||||
use sctk::reexports::client::globals::{BindError, GlobalList};
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::{delegate_dispatch, Connection, Dispatch, Proxy, QueueHandle};
|
||||
use sctk::reexports::protocols::xdg::activation::v1::client::xdg_activation_token_v1::{
|
||||
Event as ActivationTokenEvent, XdgActivationTokenV1,
|
||||
};
|
||||
use sctk::reexports::protocols::xdg::activation::v1::client::xdg_activation_v1::XdgActivationV1;
|
||||
use winit_core::event_loop::AsyncRequestSerial;
|
||||
use winit_core::window::{ActivationToken, WindowId};
|
||||
|
||||
use crate::state::WinitState;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XdgActivationState {
|
||||
xdg_activation: XdgActivationV1,
|
||||
}
|
||||
|
||||
impl XdgActivationState {
|
||||
pub fn bind(
|
||||
globals: &GlobalList,
|
||||
queue_handle: &QueueHandle<WinitState>,
|
||||
) -> Result<Self, BindError> {
|
||||
let xdg_activation = globals.bind(queue_handle, 1..=1, GlobalData)?;
|
||||
Ok(Self { xdg_activation })
|
||||
}
|
||||
|
||||
pub fn global(&self) -> &XdgActivationV1 {
|
||||
&self.xdg_activation
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<XdgActivationV1, GlobalData, WinitState> for XdgActivationState {
|
||||
fn event(
|
||||
_state: &mut WinitState,
|
||||
_proxy: &XdgActivationV1,
|
||||
_event: <XdgActivationV1 as Proxy>::Event,
|
||||
_data: &GlobalData,
|
||||
_conn: &Connection,
|
||||
_qhandle: &QueueHandle<WinitState>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<XdgActivationTokenV1, XdgActivationTokenData, WinitState> for XdgActivationState {
|
||||
fn event(
|
||||
state: &mut WinitState,
|
||||
proxy: &XdgActivationTokenV1,
|
||||
event: <XdgActivationTokenV1 as Proxy>::Event,
|
||||
data: &XdgActivationTokenData,
|
||||
_: &Connection,
|
||||
_: &QueueHandle<WinitState>,
|
||||
) {
|
||||
let token = match event {
|
||||
ActivationTokenEvent::Done { token } => token,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let global = state
|
||||
.xdg_activation
|
||||
.as_ref()
|
||||
.expect("got xdg_activation event without global.")
|
||||
.global();
|
||||
|
||||
match data {
|
||||
XdgActivationTokenData::Attention((surface, fence)) => {
|
||||
global.activate(token, surface);
|
||||
// Mark that no request attention is in process.
|
||||
if let Some(attention_requested) = fence.upgrade() {
|
||||
attention_requested.store(false, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
},
|
||||
XdgActivationTokenData::Obtain((window_id, serial)) => {
|
||||
state.events_sink.push_window_event(
|
||||
winit_core::event::WindowEvent::ActivationTokenDone {
|
||||
serial: *serial,
|
||||
token: ActivationToken::from_raw(token),
|
||||
},
|
||||
*window_id,
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
proxy.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/// The data associated with the activation request.
|
||||
pub enum XdgActivationTokenData {
|
||||
/// Request user attention for the given surface.
|
||||
Attention((WlSurface, Weak<AtomicBool>)),
|
||||
/// Get a token to be passed outside of the winit.
|
||||
Obtain((WindowId, AsyncRequestSerial)),
|
||||
}
|
||||
|
||||
delegate_dispatch!(WinitState: [ XdgActivationV1: GlobalData] => XdgActivationState);
|
||||
delegate_dispatch!(WinitState: [ XdgActivationTokenV1: XdgActivationTokenData] => XdgActivationState);
|
||||
Loading…
Add table
Add a link
Reference in a new issue