-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathlib.rs
More file actions
180 lines (158 loc) · 6 KB
/
lib.rs
File metadata and controls
180 lines (158 loc) · 6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//! # Winit's Wayland backend.
//!
//! **Note:** Windows don't appear on Wayland until you draw/present to them.
//!
//! By default, Winit loads system libraries using `dlopen`. This can be
//! disabled by disabling the `"wayland-dlopen"` cargo feature.
//!
//! ## Client-side decorations
//!
//! Winit provides client-side decorations by default, but the behaviour can
//! be controlled with the following feature flags:
//!
//! * `wayland-csd-adwaita` (default).
//! * `wayland-csd-adwaita-crossfont`.
//! * `wayland-csd-adwaita-notitle`.
//! * `wayland-csd-adwaita-notitlebar`.
use std::ffi::c_void;
use std::ptr::NonNull;
use dpi::{LogicalSize, PhysicalSize};
use sctk::reexports::client::Proxy;
use sctk::reexports::client::protocol::wl_surface::WlSurface;
pub use sctk::shell::xdg::popup::Popup as SctkPopup;
pub use sctk::shell::xdg::window::Window as SctkWindow;
use sctk::shm::slot::{Buffer, CreateBufferError, SlotPool};
use wayland_client::protocol::wl_shm::Format;
use winit_core::event_loop::ActiveEventLoop as CoreActiveEventLoop;
use winit_core::window::{
ActivationToken, PlatformWindowAttributes, Window as CoreWindow, WindowId,
};
macro_rules! os_error {
($error:expr) => {{ winit_core::error::OsError::new(line!(), file!(), $error) }};
}
mod event_loop;
mod output;
mod seat;
mod state;
mod types;
mod window;
pub use self::event_loop::{ActiveEventLoop, EventLoop};
pub use self::window::Window;
/// Additional methods on [`ActiveEventLoop`] that are specific to Wayland.
pub trait ActiveEventLoopExtWayland {
/// True if the [`ActiveEventLoop`] uses Wayland.
fn is_wayland(&self) -> bool;
}
impl ActiveEventLoopExtWayland for dyn CoreActiveEventLoop + '_ {
#[inline]
fn is_wayland(&self) -> bool {
self.cast_ref::<ActiveEventLoop>().is_some()
}
}
/// Additional methods on [`EventLoop`] that are specific to Wayland.
pub trait EventLoopExtWayland {
/// True if the [`EventLoop`] uses Wayland.
fn is_wayland(&self) -> bool;
}
/// Additional methods when building event loop that are specific to Wayland.
pub trait EventLoopBuilderExtWayland {
/// Force using Wayland.
fn with_wayland(&mut self) -> &mut Self;
/// Whether to allow the event loop to be created off of the main thread.
///
/// By default, the window is only allowed to be created on the main
/// thread, to make platform compatibility easier.
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
}
/// Additional methods on [`Window`] that are specific to Wayland.
///
/// [`Window`]: crate::window::Window
pub trait WindowExtWayland {
/// Returns `xdg_toplevel` of the window or [`None`] if the window is X11 window.
fn xdg_toplevel(&self) -> Option<NonNull<c_void>>;
}
impl WindowExtWayland for dyn CoreWindow + '_ {
#[inline]
fn xdg_toplevel(&self) -> Option<NonNull<c_void>> {
self.cast_ref::<Window<SctkWindow>>()?.xdg_toplevel()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct ApplicationName {
pub(crate) general: String,
pub(crate) instance: String,
}
/// Window attributes methods specific to Wayland.
#[derive(Debug, Default, Clone)]
pub struct WindowAttributesWayland {
pub(crate) name: Option<ApplicationName>,
pub(crate) activation_token: Option<ActivationToken>,
pub(crate) prefer_csd: bool,
}
impl WindowAttributesWayland {
/// Build window with the given name.
///
/// The `general` name sets an application ID, which should match the `.desktop`
/// file distributed with your program. The `instance` is a `no-op`.
///
/// For details about application ID conventions, see the
/// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id)
#[inline]
pub fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self {
self.name = Some(ApplicationName { general: general.into(), instance: instance.into() });
self
}
#[inline]
pub fn with_activation_token(mut self, token: ActivationToken) -> Self {
self.activation_token = Some(token);
self
}
/// Builds the window with a given preference for client-side decorations.
///
/// When set to `true`, the window will tell the compositor that it prefers
/// client-side decorations, even if server-side decorations are available.
/// When set to `false` (the default), the window will indicate a preference
/// for server-side decorations.
#[inline]
pub fn with_prefer_csd(mut self, prefer_csd: bool) -> Self {
self.prefer_csd = prefer_csd;
self
}
}
impl PlatformWindowAttributes for WindowAttributesWayland {
fn box_clone(&self) -> Box<dyn PlatformWindowAttributes> {
Box::from(self.clone())
}
}
/// Get the WindowId out of the surface.
#[inline]
fn make_wid(surface: &WlSurface) -> WindowId {
WindowId::from_raw(surface.id().as_ptr() as usize)
}
/// The default routine does floor, but we need round on Wayland.
fn logical_to_physical_rounded(size: LogicalSize<u32>, scale_factor: f64) -> PhysicalSize<u32> {
let width = size.width as f64 * scale_factor;
let height = size.height as f64 * scale_factor;
(width.round(), height.round()).into()
}
/// Converts an image buffer to a Wayland buffer (`wl_buffer`)
fn image_to_buffer(
width: i32,
height: i32,
data: &[u8],
format: Format,
pool: &mut SlotPool,
) -> Result<Buffer, CreateBufferError> {
let (buffer, canvas) = pool.create_buffer(width, height, 4 * width, format)?;
for (canvas_chunk, rgba) in canvas.chunks_exact_mut(4).zip(data.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();
}
Ok(buffer)
}