Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions src/server/frontend_wayland/wayland_rs/build_script/cpp_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,48 @@ impl CppBuilder {
}
}

if !class.protected_constructor_args.is_empty()
|| !class.protected_members.is_empty()
{
result.push_str("protected:\n");

if !class.protected_constructor_args.is_empty() {
let ctor_args_str: Vec<String> = class
.protected_constructor_args
.iter()
.map(|arg| {
format!(
"{} {}",
cpp_arg_type_to_cpp_source(&arg.cpp_type, true),
arg.name
Comment on lines +162 to +165
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I've seen this pattern before while reviewing related code. Might be worth refactoring out at some point (not urgent)

)
})
.collect();
let initialiser_list: Vec<String> = class
.protected_constructor_args
.iter()
.map(|arg| format!("{} ( std::move({}) )", arg.name, arg.name))
.collect();
result.push_str(&format!(
" {}({}) : {} {{}}\n",
class.name,
ctor_args_str.join(", "),
initialiser_list.join(", ")
));
result.push_str("\n");
}

for member in &class.protected_members {
result.push_str(&format!(
" {} {};\n",
cpp_arg_type_to_cpp_source(&member.cpp_type, true),
member.name
));
}

result.push_str("\n");
}

result.push_str("private:\n");
for member in &class.private_members {
if member.optional {
Expand Down Expand Up @@ -338,6 +380,8 @@ pub struct CppClass {
pub name: String,
pub methods: Vec<CppMethod>,
pub enums: Vec<CppEnum>,
pub protected_constructor_args: Vec<CppArg>,
pub protected_members: Vec<CppArg>,
pub private_members: Vec<CppArg>,
}

Expand All @@ -347,6 +391,8 @@ impl CppClass {
name: sanitize_identifier(&name.into()),
methods: vec![],
enums: vec![],
protected_constructor_args: vec![],
protected_members: vec![],
private_members: vec![],
}
}
Expand All @@ -365,6 +411,20 @@ impl CppClass {
.expect("enums cannot be empty after push")
}

pub fn add_protected_constructor_arg(&mut self, arg: CppArg) -> &mut CppArg {
self.protected_constructor_args.push(arg);
self.protected_constructor_args
.last_mut()
.expect("protected_constructor_args cannot be empty after push")
Comment on lines +416 to +418
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kinda redundant to check right after pushing. What is this trying to assert?

}

pub fn add_protected_member(&mut self, member: CppArg) -> &mut CppArg {
self.protected_members.push(member);
self.protected_members
.last_mut()
.expect("members cannot be empty after push")
}

pub fn add_private_member(&mut self, member: CppArg) -> &mut CppArg {
self.private_members.push(member);
self.private_members
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ pub fn generate_ffi(protocols: &Vec<WaylandProtocol>, builders: &Vec<CppBuilder>
fn uid(self: &WaylandClient) -> Result<u32>;
fn gid(self: &WaylandClient) -> Result<u32>;
fn equals(self: &WaylandClient, id: &WaylandClientId) -> bool;
fn id(self: &WaylandClient) -> Box<WaylandClientId>;
fn clone_box(self: &WaylandClient) -> Box<WaylandClient>;

type WaylandClientId;

Expand Down
32 changes: 27 additions & 5 deletions src/server/frontend_wayland/wayland_rs/build_script/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,8 @@ fn generate_global_dispatch_impl(
{
fn bind(
_state: &mut Self,
_handle: &wayland_server::DisplayHandle,
_client: &wayland_server::Client,
handle: &wayland_server::DisplayHandle,
client: &wayland_server::Client,
resource: New<#namespace_name::#interface_name::#interface_struct_name>,
// The global data is an Arc<Mutex<...>> instead of just a UniquePtr because it
// has to be accessed mutability in order to call methods across the Rust -> C++
Expand All @@ -215,11 +215,12 @@ fn generate_global_dispatch_impl(
data_init: &mut wayland_server::DataInit<'_, Self>,
) {
use crate::ffi;
let wayland_client = Box::new(WaylandClient::new(client.clone(), handle.clone()));
let mut guard = global_data.lock().unwrap();

// Methods on C++ classes must operate on Pin<&mut X> because those are the
// only ones that can cross the FFI boundary from Rust -> C++.
let global = (&mut *guard).pin_mut().#create_global_method();
let global = (&mut *guard).pin_mut().#create_global_method(wayland_client);
let arc = Arc::new(Mutex::new(global));

// The initialization strategy here requires a "double initialization". First,
Expand Down Expand Up @@ -590,7 +591,7 @@ fn write_dispatch_rs(protocols: &Vec<WaylandProtocol>) {
use crate::protocols;
use crate::wayland_server_core::ServerState;
use crate::ffi;
use crate::wayland_client::WaylandClientId;
use crate::wayland_client::{WaylandClient, WaylandClientId};
use std::os::fd::{AsRawFd, RawFd};
use std::sync::{Arc, LazyLock, Mutex, RwLock};
use std::collections::HashMap;
Expand Down Expand Up @@ -642,6 +643,7 @@ fn create_global_factory(protocols: &Vec<WaylandProtocol>) -> CppBuilder {
builder.add_header_include("<rust/cxx.h>");
let mut namespace = CppNamespace::new(vec!["mir", "wayland_rs"]);
let mut class = CppClass::new("GlobalFactory");
namespace.add_forward_declaration_class("WaylandClient");
protocols.iter().for_each(|protocol| {
protocol
.interfaces
Expand All @@ -652,14 +654,19 @@ fn create_global_factory(protocols: &Vec<WaylandProtocol>) -> CppBuilder {
let class_name = format_wayland_interface_to_cpp_class(&global_interface.name);
namespace.add_forward_declaration_class(&class_name);

let method = CppMethod::new(
let mut method = CppMethod::new(
format!("create_{}", global_interface.name),
Some(CppType::Object(class_name)),
true,
false,
true,
true,
);
method.add_arg(CppArg::new(
CppType::Box("WaylandClient".to_string()),
"client",
false,
));
class.add_method(method);
})
});
Expand Down Expand Up @@ -770,6 +777,8 @@ fn create_ffi_fwd_builder(protocols: &Vec<WaylandProtocol>) -> CppBuilder {
// WaylandServer is declared in ffi.rs but used nowhere in the protocol headers;
// include it for completeness so all Rust types are forward-declared.
namespace.add_forward_declaration_class("WaylandServer");
// WaylandClient is used in the protected constructor of every generated XxxImpl.
namespace.add_forward_declaration_class("WaylandClient");

for protocol in protocols {
for interface in &protocol.interfaces {
Expand Down Expand Up @@ -914,6 +923,19 @@ fn wayland_interface_to_cpp_class(interface: &WaylandInterface) -> CppClass {
);
class.add_method(get_box_method);

// Add a protected constructor and member so that subclasses know which client
// they are serving and can interact with it as they please.
class.add_protected_constructor_arg(CppArg::new(
CppType::Box("WaylandClient".to_string()),
"client",
false,
));
class.add_protected_member(CppArg::new(
CppType::Box("WaylandClient".to_string()),
"client",
false,
));

for method in methods {
class.add_method(method);
}
Expand Down
11 changes: 11 additions & 0 deletions src/server/frontend_wayland/wayland_rs/src/wayland_client.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use wayland_server::{backend::ClientId, Client, DisplayHandle};

/// A C++ friendly wrapper around a wayland [Client] object.
#[derive(Clone)]
pub struct WaylandClient {
client: Client,
handle: DisplayHandle,
Expand Down Expand Up @@ -38,10 +39,20 @@ impl WaylandClient {
.gid)
}

/// Retrieve the [WaylandClientId] for this client.
pub fn id(&self) -> Box<WaylandClientId> {
Box::new(WaylandClientId::new(self.client.id()))
}

/// Check if this client is wrapping the provided [WaylandClientId].
pub fn equals(&self, id: &WaylandClientId) -> bool {
self.client.id() == id.id
}

/// Clone this client into a new [Box].
pub fn clone_box(&self) -> Box<WaylandClient> {
Box::new(self.clone())
}
}

/// An opaque ID for the WaylandClient.
Expand Down
Loading