Skip to content
This repository was archived by the owner on Jul 15, 2024. It is now read-only.
Draft
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
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ categories = [
exclude = ["/.github/"]
publish = false # Until it's ready

[workspace]
members = ["v2"]

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
Expand All @@ -24,7 +27,7 @@ default-target = "x86_64-pc-windows-msvc"
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]

[features]
default = ["x11"]
default = ["x11", "wayland"]
x11 = ["ashpd", "bindgen", "futures", "nix", "pkg-config", "x11rb"]
wayland = [
# Required for XKBCommon
Expand Down
68 changes: 68 additions & 0 deletions v2/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
[package]
name = "v2"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
default = ["wayland"]
wayland = [
# Required for XKBCommon
"pkg-config",
"bindgen",
"nix",
"smithay-client-toolkit",
"wayland-backend",
]


[dependencies]
kurbo = "0.10.4"
# glazier = { path = "../" }
cfg-if = "1.0.0"

tracing = { version = "0.1.22", features = ["log"] }
raw-window-handle = { version = "0.5.0", default_features = false }

keyboard-types = { version = "0.7", default_features = false }
instant = { version = "0.1.6", features = ["wasm-bindgen"] }
thiserror = "1.0.51"

[dev-dependencies]
static_assertions = "1.1.0"

[target.'cfg(any(target_os = "freebsd", target_os="linux", target_os="openbsd"))'.dependencies]
ashpd = { version = "0.6.7", optional = true }
futures = { version = "0.3.24", optional = true, features = ["executor"] }

nix = { version = "0.27.0", optional = true }

x11rb = { version = "0.13", features = [
"allow-unsafe-code",
"present",
"render",
"randr",
"xfixes",
"xkb",
"resource_manager",
"cursor",
"xinput",
], optional = true }

rand = { version = "0.8.0", optional = true }
log = { version = "0.4.14", optional = true }

smithay-client-toolkit = { version = "0.18.0", optional = true, default-features = false, features = [
# Don't use the built-in xkb handling
"calloop",
] }
# Wayland dependencies
# Needed for supporting RawWindowHandle
wayland-backend = { version = "0.3.2", default_features = false, features = [
"client_system",
], optional = true }

[target.'cfg(any(target_os = "freebsd", target_os="linux", target_os="openbsd"))'.build-dependencies]
bindgen = { version = "0.66", optional = true }
pkg-config = { version = "0.3.25", optional = true }
68 changes: 68 additions & 0 deletions v2/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#[cfg(not(all(
any(feature = "x11", feature = "wayland"),
any(target_os = "freebsd", target_os = "linux", target_os = "openbsd")
)))]
fn main() {}

#[cfg(all(
any(feature = "x11", feature = "wayland"),
any(target_os = "freebsd", target_os = "linux", target_os = "openbsd")
))]
fn main() {
use pkg_config::probe_library;
use std::env;
use std::path::PathBuf;

let xkbcommon = probe_library("xkbcommon").unwrap();

#[cfg(feature = "x11")]
probe_library("xkbcommon-x11").unwrap();

let mut header = "\
#include <xkbcommon/xkbcommon-compose.h>
#include <xkbcommon/xkbcommon-names.h>
#include <xkbcommon/xkbcommon.h>"
.to_string();

if cfg!(feature = "x11") {
header += "
#include <xkbcommon/xkbcommon-x11.h>";
}

let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header_contents("wrapper.h", &header)
.clang_args(
xkbcommon
.include_paths
.iter()
.filter_map(|path| path.to_str().map(|s| format!("-I{s}"))),
)
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.prepend_enum_name(false)
.size_t_is_usize(true)
.allowlist_function("xkb_.*")
.allowlist_type("xkb_.*")
.allowlist_var("XKB_.*")
.allowlist_type("xcb_connection_t")
// this needs var args
.blocklist_function("xkb_context_set_log_fn")
// we use FILE from libc
.blocklist_type("FILE")
.blocklist_type("va_list")
.default_enum_style(bindgen::EnumVariation::NewType {
is_bitfield: true,
is_global: false,
})
.generate()
.expect("Unable to generate bindings");

// Write the bindings to the $OUT_DIR/xkbcommon.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("xkbcommon_sys.rs"))
.expect("Couldn't write bindings!");
}
4 changes: 4 additions & 0 deletions v2/src/backend/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod new_wayland;
mod shared;

pub(crate) use new_wayland::*;
60 changes: 60 additions & 0 deletions v2/src/backend/new_wayland/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2020 The Druid Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Wayland errors

use std::fmt;

use smithay_client_toolkit::reexports::{
calloop,
client::{globals::BindError, ConnectError},
};

// TODO: Work out error handling
#[derive(Debug)]
pub enum Error {
Connect(ConnectError),
Bind(BindError),
Calloop(calloop::Error),
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self {
Error::Connect(e) => write!(f, "could not connect to the wayland server: {e:}"),
Error::Bind(e) => write!(f, "could not bind a wayland global: {e:}"),
Error::Calloop(e) => write!(f, "calloop failed: {e:}"),
}
}
}

impl std::error::Error for Error {}

impl From<ConnectError> for Error {
fn from(value: ConnectError) -> Self {
Self::Connect(value)
}
}

impl From<BindError> for Error {
fn from(value: BindError) -> Self {
Self::Bind(value)
}
}

impl From<calloop::Error> for Error {
fn from(value: calloop::Error) -> Self {
Self::Calloop(value)
}
}
137 changes: 137 additions & 0 deletions v2/src/backend/new_wayland/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Copyright 2019 The Druid Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! wayland platform support

use std::{any::TypeId, fmt::Debug, marker::PhantomData};

use smithay_client_toolkit::{
delegate_registry,
reexports::{
calloop::{self, LoopHandle, LoopSignal},
client::{Proxy, QueueHandle},
protocols::wp::text_input::zv3::client::zwp_text_input_manager_v3::ZwpTextInputManagerV3,
},
registry::{ProvidesRegistryState, RegistryState},
registry_handlers,
};
use thiserror::Error;

use self::{outputs::Outputs, windows::Windowing};
use super::shared::xkb::Context;

use crate::{handler::PlatformHandler, window::IdleToken, Glazier};

pub(crate) mod error;
mod outputs;
mod run_loop;
mod windows;

#[derive(Error, Debug)]
pub enum BackendWindowCreationError {}

pub(crate) use run_loop::{launch, LoopHandle as LoopHandle2};

pub(crate) type GlazierImpl<'a> = &'a mut WaylandState;

/// The main state type of the event loop. Implements dispatching for all supported
/// wayland events
struct WaylandPlatform {
// Drop the handler as early as possible, in case there are any Wgpu surfaces owned by it
pub(self) handler: Box<dyn PlatformHandler>,
pub(self) state: WaylandState,
}

pub(crate) struct WaylandState {
// Meta
/// The type of the user's [PlatformHandler]. Used to allow
/// [Glazier::handle] to have eager error handling
pub(self) handler_type: TypeId,

// Event loop management
/// The queue used to communicate with the platform
pub(self) wayland_queue: QueueHandle<WaylandPlatform>,
/// Used to stop the event loop
pub(self) loop_signal: LoopSignal,
/// Used to add new items into the loop. Primarily used for timers and keyboard repeats
pub(self) loop_handle: LoopHandle<'static, WaylandPlatform>,

// Callbacks and other delayed actions
/// The actions which the application has requested to occur on the next opportunity
pub(self) idle_actions: Vec<IdleAction>,
/// Actions which the application has requested to happen, but which require access to the handler
// pub(self) actions: VecDeque<ActiveAction>,
/// The sender used to access the event loop from other threads
pub(self) loop_sender: calloop::channel::Sender<LoopCallback>,

// Subsytem state
/// Monitors, not currently used
pub(self) monitors: Outputs,

// State of the windowing subsystem
pub(self) windows: Windowing,

// Input. Wayland splits input into seats, and doesn't provide much
// help in implementing cases where there are multiple of these
/// The sctk manager for seats
// pub(self) seats: SeatState,
/// The data
// pub(self) input_states: Vec<SeatInfo>,
/// Global used for IME. Optional because the compositor might not implement text input
pub(self) text_input: Option<ZwpTextInputManagerV3>,
/// The xkb context object
pub(self) xkb_context: Context,
// Other wayland state
pub(self) registry_state: RegistryState,
}

delegate_registry!(WaylandPlatform);

impl ProvidesRegistryState for WaylandPlatform {
fn registry(&mut self) -> &mut RegistryState {
&mut self.state.registry_state
}
registry_handlers![Outputs];
}

// We *could* implement `Deref<Target=WaylandState>` for `WaylandPlatform`, but
// that causes borrow checking issues, because the borrow checker doesn't know
// that the derefs don't make unrelated fields alias in a horrible but safe way.
// To enable greater consistency, we therefore force using `plat.state`

impl WaylandPlatform {
fn with_glz<R>(&mut self, f: impl FnOnce(&mut dyn PlatformHandler, Glazier) -> R) -> R {
f(&mut *self.handler, Glazier(&mut self.state, PhantomData))
// TODO: Is now the time to drain `self.actions`?
}
}

enum IdleAction {
Callback(LoopCallback),
Token(IdleToken),
}

type LoopCallback = Box<dyn FnOnce(&mut WaylandPlatform) + Send>;

fn on_unknown_event<P: Proxy>(proxy: &P, event: P::Event)
where
P::Event: Debug,
{
let name = P::interface().name;
tracing::warn!(
proxy = ?proxy,
event = ?event,
issues_url = "https://github.com/linebender/glazier/issues",
"Got an unknown event for interface {name}, got event: {event:?}. Please report this to Glazier on GitHub");
}
Loading