mirror of
https://github.com/marcoallegretti/WEFT_OS.git
synced 2026-03-26 17:03:09 +00:00
feat(servo-embed): wire Servo deps and share Wayland surface with shell client
- Add servo/winit/softbuffer as optional deps in weft-servo-shell and weft-app-shell Cargo.toml, gated on servo-embed feature - Replace ShellClient::connect() and connect_as_app() with connect_with_display() and connect_as_app_with_display(), using Backend::from_foreign_display to share the winit wl_display connection - Move ShellClient construction into resumed() in both embedders after winit window and wl_surface are available - Pass actual wl_surface to create_window instead of None - Fix pre-existing field name bug: wayland-scanner generates _type for the reserved keyword arg name=type, not r#type
This commit is contained in:
parent
4edfa00e22
commit
34359acf3f
9 changed files with 7248 additions and 176 deletions
7231
Cargo.lock
generated
7231
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -9,11 +9,10 @@ name = "weft-app-shell"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# Enable actual Servo rendering. Requires manually adding the deps listed in
|
# Enable actual Servo rendering. Deps are declared as optional below and only
|
||||||
# weft-servo-shell/SERVO_PIN.md to this file before building; they are not
|
# fetched when this feature is active. The Servo monorepo (~1 GB) is not
|
||||||
# included here to avoid pulling the Servo monorepo (~1 GB) into every
|
# downloaded during a plain `cargo check` or `cargo build` without this feature.
|
||||||
# `cargo check` cycle.
|
servo-embed = ["dep:servo", "dep:winit", "dep:softbuffer", "dep:serde", "dep:toml"]
|
||||||
servo-embed = ["dep:serde", "dep:toml"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
|
@ -25,3 +24,18 @@ wayland-scanner = "0.31"
|
||||||
bitflags = "2"
|
bitflags = "2"
|
||||||
serde = { version = "1", features = ["derive"], optional = true }
|
serde = { version = "1", features = ["derive"], optional = true }
|
||||||
toml = { version = "0.8", optional = true }
|
toml = { version = "0.8", optional = true }
|
||||||
|
|
||||||
|
[dependencies.servo]
|
||||||
|
git = "https://github.com/marcoallegretti/servo"
|
||||||
|
branch = "servo-weft"
|
||||||
|
optional = true
|
||||||
|
default-features = false
|
||||||
|
|
||||||
|
[dependencies.winit]
|
||||||
|
version = "0.30"
|
||||||
|
optional = true
|
||||||
|
features = ["wayland"]
|
||||||
|
|
||||||
|
[dependencies.softbuffer]
|
||||||
|
version = "0.4"
|
||||||
|
optional = true
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ use winit::{
|
||||||
event::{ElementState, MouseButton, WindowEvent},
|
event::{ElementState, MouseButton, WindowEvent},
|
||||||
event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy},
|
event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy},
|
||||||
keyboard::ModifiersState,
|
keyboard::ModifiersState,
|
||||||
|
platform::wayland::{ActiveEventLoopExtWayland, WindowExtWayland},
|
||||||
window::{Window, WindowAttributes, WindowId},
|
window::{Window, WindowAttributes, WindowId},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -74,6 +75,7 @@ impl RenderingCtx {
|
||||||
|
|
||||||
struct App {
|
struct App {
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
|
app_id: String,
|
||||||
session_id: u64,
|
session_id: u64,
|
||||||
ws_port: u16,
|
ws_port: u16,
|
||||||
window: Option<Arc<Window>>,
|
window: Option<Arc<Window>>,
|
||||||
|
|
@ -92,13 +94,14 @@ struct App {
|
||||||
impl App {
|
impl App {
|
||||||
fn new(
|
fn new(
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
|
app_id: String,
|
||||||
session_id: u64,
|
session_id: u64,
|
||||||
ws_port: u16,
|
ws_port: u16,
|
||||||
waker: WeftEventLoopWaker,
|
waker: WeftEventLoopWaker,
|
||||||
shell_client: Option<crate::shell_client::ShellClient>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
url,
|
url,
|
||||||
|
app_id,
|
||||||
session_id,
|
session_id,
|
||||||
ws_port,
|
ws_port,
|
||||||
window: None,
|
window: None,
|
||||||
|
|
@ -111,7 +114,7 @@ impl App {
|
||||||
ready_signalled: false,
|
ready_signalled: false,
|
||||||
modifiers: ModifiersState::default(),
|
modifiers: ModifiersState::default(),
|
||||||
cursor_pos: servo::euclid::default::Point2D::zero(),
|
cursor_pos: servo::euclid::default::Point2D::zero(),
|
||||||
shell_client,
|
shell_client: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,6 +163,22 @@ impl ApplicationHandler<ServoWake> for App {
|
||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
self.window = Some(Arc::clone(&window));
|
self.window = Some(Arc::clone(&window));
|
||||||
|
|
||||||
|
if self.shell_client.is_none() {
|
||||||
|
if let (Some(disp), Some(surf)) =
|
||||||
|
(event_loop.wayland_display(), window.wayland_surface())
|
||||||
|
{
|
||||||
|
match crate::shell_client::ShellClient::connect_as_app_with_display(
|
||||||
|
&self.app_id,
|
||||||
|
self.session_id,
|
||||||
|
disp,
|
||||||
|
surf,
|
||||||
|
) {
|
||||||
|
Ok(sc) => self.shell_client = Some(sc),
|
||||||
|
Err(e) => tracing::warn!(error = %e, "shell protocol unavailable"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let servo = ServoBuilder::default()
|
let servo = ServoBuilder::default()
|
||||||
.event_loop_waker(Box::new(self.waker.clone()))
|
.event_loop_waker(Box::new(self.waker.clone()))
|
||||||
.build();
|
.build();
|
||||||
|
|
@ -421,7 +440,6 @@ pub fn run(
|
||||||
app_id: &str,
|
app_id: &str,
|
||||||
session_id: u64,
|
session_id: u64,
|
||||||
ws_port: u16,
|
ws_port: u16,
|
||||||
shell_client: Option<crate::shell_client::ShellClient>,
|
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let url = resolve_weft_app_url(app_id)
|
let url = resolve_weft_app_url(app_id)
|
||||||
.ok_or_else(|| anyhow::anyhow!("no ui/index.html found for app {app_id}"))?;
|
.ok_or_else(|| anyhow::anyhow!("no ui/index.html found for app {app_id}"))?;
|
||||||
|
|
@ -434,7 +452,7 @@ pub fn run(
|
||||||
proxy: Arc::new(Mutex::new(event_loop.create_proxy())),
|
proxy: Arc::new(Mutex::new(event_loop.create_proxy())),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut app = App::new(url, session_id, ws_port, waker, shell_client);
|
let mut app = App::new(url, app_id.to_owned(), session_id, ws_port, waker);
|
||||||
event_loop
|
event_loop
|
||||||
.run_app(&mut app)
|
.run_app(&mut app)
|
||||||
.map_err(|e| anyhow::anyhow!("event loop run: {e}"))
|
.map_err(|e| anyhow::anyhow!("event loop run: {e}"))
|
||||||
|
|
|
||||||
|
|
@ -28,18 +28,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
let ws_port = appd_ws_port();
|
let ws_port = appd_ws_port();
|
||||||
|
|
||||||
let shell = match shell_client::ShellClient::connect_as_app(&app_id, session_id) {
|
embed_app(&app_id, session_id, ws_port)
|
||||||
Ok(c) => {
|
|
||||||
tracing::info!("app shell window registered with compositor");
|
|
||||||
Some(c)
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
tracing::warn!(error = %e, "shell protocol unavailable; continuing without compositor registration");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
embed_app(&app_id, session_id, ws_port, shell)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn appd_ws_port() -> u16 {
|
fn appd_ws_port() -> u16 {
|
||||||
|
|
@ -63,14 +52,13 @@ fn embed_app(
|
||||||
app_id: &str,
|
app_id: &str,
|
||||||
session_id: u64,
|
session_id: u64,
|
||||||
ws_port: u16,
|
ws_port: u16,
|
||||||
shell_client: Option<shell_client::ShellClient>,
|
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
#[cfg(feature = "servo-embed")]
|
#[cfg(feature = "servo-embed")]
|
||||||
return embedder::run(app_id, session_id, ws_port, shell_client);
|
return embedder::run(app_id, session_id, ws_port);
|
||||||
|
|
||||||
#[cfg(not(feature = "servo-embed"))]
|
#[cfg(not(feature = "servo-embed"))]
|
||||||
{
|
{
|
||||||
let _ = (app_id, session_id, ws_port, shell_client);
|
let _ = (app_id, session_id, ws_port);
|
||||||
println!("READY");
|
println!("READY");
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
let _ = std::io::stdout().flush();
|
let _ = std::io::stdout().flush();
|
||||||
|
|
|
||||||
|
|
@ -129,9 +129,26 @@ pub struct ShellClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShellClient {
|
impl ShellClient {
|
||||||
pub fn connect_as_app(app_id: &str, session_id: u64) -> anyhow::Result<Self> {
|
/// Connect using winit's existing Wayland display handle.
|
||||||
let conn =
|
///
|
||||||
Connection::connect_to_env().context("failed to connect to Wayland compositor")?;
|
/// See `weft-servo-shell/src/shell_client.rs` for the rationale on
|
||||||
|
/// `Backend::from_foreign_display`. The `surface_ptr` is the `wl_surface*`
|
||||||
|
/// from the same winit connection, enabling the compositor to associate the
|
||||||
|
/// application window with the rendered surface.
|
||||||
|
#[cfg(feature = "servo-embed")]
|
||||||
|
pub fn connect_as_app_with_display(
|
||||||
|
app_id: &str,
|
||||||
|
session_id: u64,
|
||||||
|
display_ptr: *mut std::ffi::c_void,
|
||||||
|
surface_ptr: *mut std::ffi::c_void,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
use wayland_client::Proxy;
|
||||||
|
use wayland_client::backend::{Backend, ObjectId};
|
||||||
|
|
||||||
|
// Safety: display_ptr is winit's wl_display*, valid for the event loop lifetime.
|
||||||
|
let conn = unsafe {
|
||||||
|
Connection::from_backend(Backend::from_foreign_display(display_ptr as *mut _))
|
||||||
|
};
|
||||||
|
|
||||||
let mut event_queue = conn.new_event_queue::<AppData>();
|
let mut event_queue = conn.new_event_queue::<AppData>();
|
||||||
let qh = event_queue.handle();
|
let qh = event_queue.handle();
|
||||||
|
|
@ -148,13 +165,20 @@ impl ShellClient {
|
||||||
"zweft_shell_manager_v1 not advertised; WEFT compositor must be running"
|
"zweft_shell_manager_v1 not advertised; WEFT compositor must be running"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Safety: surface_ptr is winit's wl_surface* on the same wl_display connection.
|
||||||
|
let surface = unsafe {
|
||||||
|
let id = ObjectId::from_ptr(WlSurface::interface(), surface_ptr as *mut _)
|
||||||
|
.context("wl_surface ObjectId import")?;
|
||||||
|
WlSurface::from_id(&conn, id).context("wl_surface from_id")?
|
||||||
|
};
|
||||||
|
|
||||||
let manager = data.manager.as_ref().unwrap();
|
let manager = data.manager.as_ref().unwrap();
|
||||||
let title = format!("{app_id}/{session_id}");
|
let title = format!("{app_id}/{session_id}");
|
||||||
let window = manager.create_window(
|
let window = manager.create_window(
|
||||||
app_id.to_string(),
|
app_id.to_string(),
|
||||||
title,
|
title,
|
||||||
"application".to_string(),
|
"application".to_string(),
|
||||||
None::<&WlSurface>,
|
Some(&surface),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ name = "weft-servo-shell"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# Enable actual Servo rendering. Requires manually adding the deps listed in
|
# Enable actual Servo rendering. Deps are declared as optional below and only
|
||||||
# SERVO_PIN.md to this file before building; they are not included here to
|
# fetched when this feature is active. The Servo monorepo (~1 GB) is not
|
||||||
# avoid pulling the Servo monorepo (~1 GB) into every `cargo check` cycle.
|
# downloaded during a plain `cargo check` or `cargo build` without this feature.
|
||||||
servo-embed = []
|
servo-embed = ["dep:servo", "dep:winit", "dep:softbuffer"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
|
@ -24,3 +24,18 @@ wayland-scanner = "0.31"
|
||||||
bitflags = "2"
|
bitflags = "2"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
tungstenite = "0.24"
|
tungstenite = "0.24"
|
||||||
|
|
||||||
|
[dependencies.servo]
|
||||||
|
git = "https://github.com/marcoallegretti/servo"
|
||||||
|
branch = "servo-weft"
|
||||||
|
optional = true
|
||||||
|
default-features = false
|
||||||
|
|
||||||
|
[dependencies.winit]
|
||||||
|
version = "0.30"
|
||||||
|
optional = true
|
||||||
|
features = ["wayland"]
|
||||||
|
|
||||||
|
[dependencies.softbuffer]
|
||||||
|
version = "0.4"
|
||||||
|
optional = true
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ use winit::{
|
||||||
event::{ElementState, MouseButton, WindowEvent},
|
event::{ElementState, MouseButton, WindowEvent},
|
||||||
event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy},
|
event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy},
|
||||||
keyboard::ModifiersState,
|
keyboard::ModifiersState,
|
||||||
|
platform::wayland::{ActiveEventLoopExtWayland, WindowExtWayland},
|
||||||
window::{Window, WindowAttributes, WindowId},
|
window::{Window, WindowAttributes, WindowId},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -102,7 +103,6 @@ impl App {
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
waker: WeftEventLoopWaker,
|
waker: WeftEventLoopWaker,
|
||||||
ws_port: u16,
|
ws_port: u16,
|
||||||
shell_client: Option<crate::shell_client::ShellClient>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
url,
|
url,
|
||||||
|
|
@ -116,7 +116,7 @@ impl App {
|
||||||
shutting_down: false,
|
shutting_down: false,
|
||||||
modifiers: ModifiersState::default(),
|
modifiers: ModifiersState::default(),
|
||||||
cursor_pos: servo::euclid::default::Point2D::zero(),
|
cursor_pos: servo::euclid::default::Point2D::zero(),
|
||||||
shell_client,
|
shell_client: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,6 +164,17 @@ impl ApplicationHandler<ServoWake> for App {
|
||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
self.window = Some(Arc::clone(&window));
|
self.window = Some(Arc::clone(&window));
|
||||||
|
|
||||||
|
if self.shell_client.is_none() {
|
||||||
|
if let (Some(disp), Some(surf)) =
|
||||||
|
(event_loop.wayland_display(), window.wayland_surface())
|
||||||
|
{
|
||||||
|
match crate::shell_client::ShellClient::connect_with_display(disp, surf) {
|
||||||
|
Ok(sc) => self.shell_client = Some(sc),
|
||||||
|
Err(e) => tracing::warn!(error = %e, "shell protocol unavailable"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let servo = ServoBuilder::default()
|
let servo = ServoBuilder::default()
|
||||||
.event_loop_waker(Box::new(self.waker.clone()))
|
.event_loop_waker(Box::new(self.waker.clone()))
|
||||||
.build();
|
.build();
|
||||||
|
|
@ -380,7 +391,6 @@ fn app_store_roots() -> Vec<PathBuf> {
|
||||||
pub fn run(
|
pub fn run(
|
||||||
html_path: &Path,
|
html_path: &Path,
|
||||||
ws_port: u16,
|
ws_port: u16,
|
||||||
shell_client: Option<crate::shell_client::ShellClient>,
|
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let url_str = format!("file://{}", html_path.display());
|
let url_str = format!("file://{}", html_path.display());
|
||||||
let raw_url =
|
let raw_url =
|
||||||
|
|
@ -395,7 +405,7 @@ pub fn run(
|
||||||
proxy: Arc::new(Mutex::new(event_loop.create_proxy())),
|
proxy: Arc::new(Mutex::new(event_loop.create_proxy())),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut app = App::new(url, waker, ws_port, shell_client);
|
let mut app = App::new(url, waker, ws_port);
|
||||||
event_loop
|
event_loop
|
||||||
.run_app(&mut app)
|
.run_app(&mut app)
|
||||||
.map_err(|e| anyhow::anyhow!("event loop run: {e}"))
|
.map_err(|e| anyhow::anyhow!("event loop run: {e}"))
|
||||||
|
|
|
||||||
|
|
@ -32,18 +32,7 @@ fn run() -> anyhow::Result<()> {
|
||||||
let ws_port = appd_ws_port();
|
let ws_port = appd_ws_port();
|
||||||
tracing::info!(ws_port, "appd WebSocket port");
|
tracing::info!(ws_port, "appd WebSocket port");
|
||||||
|
|
||||||
let shell = match shell_client::ShellClient::connect() {
|
embed_servo(&wayland_display, &html_path, ws_port)
|
||||||
Ok(c) => {
|
|
||||||
tracing::info!("shell window registered with compositor");
|
|
||||||
Some(c)
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
tracing::warn!(error = %e, "shell protocol unavailable; continuing without compositor registration");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
embed_servo(&wayland_display, &html_path, ws_port, shell)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn system_ui_html_path() -> anyhow::Result<PathBuf> {
|
fn system_ui_html_path() -> anyhow::Result<PathBuf> {
|
||||||
|
|
@ -84,14 +73,12 @@ fn embed_servo(
|
||||||
_wayland_display: &str,
|
_wayland_display: &str,
|
||||||
html_path: &std::path::Path,
|
html_path: &std::path::Path,
|
||||||
ws_port: u16,
|
ws_port: u16,
|
||||||
shell_client: Option<shell_client::ShellClient>,
|
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
#[cfg(feature = "servo-embed")]
|
#[cfg(feature = "servo-embed")]
|
||||||
return embedder::run(html_path, ws_port, shell_client);
|
return embedder::run(html_path, ws_port);
|
||||||
|
|
||||||
#[cfg(not(feature = "servo-embed"))]
|
#[cfg(not(feature = "servo-embed"))]
|
||||||
{
|
{
|
||||||
let _ = shell_client;
|
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
path = %html_path.display(),
|
path = %html_path.display(),
|
||||||
ws_port,
|
ws_port,
|
||||||
|
|
|
||||||
|
|
@ -132,14 +132,14 @@ impl Dispatch<ZweftShellWindowV1, ()> for AppData {
|
||||||
tracing::trace!(tv_sec, tv_nsec, refresh, "shell presentation feedback");
|
tracing::trace!(tv_sec, tv_nsec, refresh, "shell presentation feedback");
|
||||||
}
|
}
|
||||||
zweft_shell_window_v1::Event::NavigationGesture {
|
zweft_shell_window_v1::Event::NavigationGesture {
|
||||||
r#type,
|
_type,
|
||||||
fingers,
|
fingers,
|
||||||
dx,
|
dx,
|
||||||
dy,
|
dy,
|
||||||
} => {
|
} => {
|
||||||
tracing::debug!(r#type, fingers, dx, dy, "navigation gesture from compositor");
|
tracing::debug!(_type, fingers, dx, dy, "navigation gesture from compositor");
|
||||||
state.pending_gestures.push(PendingGesture {
|
state.pending_gestures.push(PendingGesture {
|
||||||
gesture_type: r#type,
|
gesture_type: _type,
|
||||||
fingers,
|
fingers,
|
||||||
dx,
|
dx,
|
||||||
dy,
|
dy,
|
||||||
|
|
@ -157,9 +157,23 @@ pub struct ShellClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShellClient {
|
impl ShellClient {
|
||||||
pub fn connect() -> anyhow::Result<Self> {
|
/// Connect to the compositor using winit's existing Wayland display handle.
|
||||||
let conn =
|
///
|
||||||
Connection::connect_to_env().context("failed to connect to Wayland compositor")?;
|
/// Using `Backend::from_foreign_display` shares winit's `wl_display` connection so
|
||||||
|
/// that `surface_ptr` (a `wl_surface*` owned by winit) is a valid object on the same
|
||||||
|
/// client, enabling the compositor to link the shell window to the actual surface.
|
||||||
|
#[cfg(feature = "servo-embed")]
|
||||||
|
pub fn connect_with_display(
|
||||||
|
display_ptr: *mut std::ffi::c_void,
|
||||||
|
surface_ptr: *mut std::ffi::c_void,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
use wayland_client::Proxy;
|
||||||
|
use wayland_client::backend::{Backend, ObjectId};
|
||||||
|
|
||||||
|
// Safety: display_ptr is winit's wl_display*, valid for the event loop lifetime.
|
||||||
|
let conn = unsafe {
|
||||||
|
Connection::from_backend(Backend::from_foreign_display(display_ptr as *mut _))
|
||||||
|
};
|
||||||
|
|
||||||
let mut event_queue = conn.new_event_queue::<AppData>();
|
let mut event_queue = conn.new_event_queue::<AppData>();
|
||||||
let qh = event_queue.handle();
|
let qh = event_queue.handle();
|
||||||
|
|
@ -176,12 +190,19 @@ impl ShellClient {
|
||||||
"zweft_shell_manager_v1 not advertised; WEFT compositor must be running"
|
"zweft_shell_manager_v1 not advertised; WEFT compositor must be running"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Safety: surface_ptr is winit's wl_surface* on the same wl_display connection.
|
||||||
|
let surface = unsafe {
|
||||||
|
let id = ObjectId::from_ptr(WlSurface::interface(), surface_ptr as *mut _)
|
||||||
|
.context("wl_surface ObjectId import")?;
|
||||||
|
WlSurface::from_id(&conn, id).context("wl_surface from_id")?
|
||||||
|
};
|
||||||
|
|
||||||
let manager = data.manager.as_ref().unwrap();
|
let manager = data.manager.as_ref().unwrap();
|
||||||
let window = manager.create_window(
|
let window = manager.create_window(
|
||||||
"org.weft.system.shell".to_string(),
|
"org.weft.system.shell".to_string(),
|
||||||
"WEFT Shell".to_string(),
|
"WEFT Shell".to_string(),
|
||||||
"panel".to_string(),
|
"panel".to_string(),
|
||||||
None::<&WlSurface>,
|
Some(&surface),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue