diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1076aa56..10eabd8f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,7 @@ jobs: env: RUST_BACKTRACE: 1 CARGO_INCREMENTAL: 0 + PKG_CONFIG_ALLOW_CROSS: 1 RUSTFLAGS: "-C debuginfo=0 --deny warnings" OPTIONS: ${{ matrix.platform.options }} FEATURES: ${{ format(',{0}', matrix.platform.features ) }} @@ -62,9 +63,12 @@ jobs: rust-version: ${{ matrix.rust_version }}${{ matrix.platform.host }} targets: ${{ matrix.platform.target }} + - name: Install Linux dependencies + if: (matrix.platform.os == 'ubuntu-latest') + run: sudo apt-get update && sudo apt-get install pkg-config cmake libfreetype6-dev libfontconfig1-dev - name: Install GCC Multilib if: (matrix.platform.os == 'ubuntu-latest') && contains(matrix.platform.target, 'i686') - run: sudo apt-get update && sudo apt-get install gcc-multilib + run: sudo dpkg --add-architecture i386 && sudo apt-get update && sudo apt-get install g++-multilib gcc-multilib libfreetype6-dev:i386 libfontconfig1-dev:i386 - name: Install cargo-apk if: contains(matrix.platform.target, 'android') run: cargo install cargo-apk diff --git a/CHANGELOG.md b/CHANGELOG.md index aa457108..5a2216e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,12 @@ And please only add new entries to the top of this list, right below the `# Unre sent a cancel or frame event. - On iOS, send `RedrawEventsCleared` even if there are no redraw events, consistent with other platforms. - **Breaking:** Replaced `Window::with_app_id` and `Window::with_class` with `Window::with_name` on `WindowBuilderExtUnix`. +- On Wayland, fallback CSD was replaced with proper one: + - `WindowBuilderExtUnix::with_wayland_csd_theme` to set color theme in builder. + - `WindowExtUnix::wayland_set_csd_theme` to set color theme when creating a window. + - `WINIT_WAYLAND_CSD_THEME` env variable was added, it can be used to set "dark"/"light" theme in apps that don't expose theme setting. + - `wayland-csd-adwaita` feature that enables proper CSD with title rendering using FreeType system library. + - `wayland-csd-adwaita-notitle` feature that enables CSD but without title rendering. - On Wayland and X11, fix window not resizing with `Window::set_inner_size` after calling `Window:set_resizable(false)`. - On Windows, fix wrong fullscreen monitors being recognized when handling WM_WINDOWPOSCHANGING messages - **Breaking:** Added new `WindowEvent::Ime` supported on desktop platforms. diff --git a/Cargo.toml b/Cargo.toml index d6ee8b53..3f5acfb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,10 +17,12 @@ default-target = "x86_64-unknown-linux-gnu" targets = ["i686-pc-windows-msvc", "x86_64-pc-windows-msvc", "i686-unknown-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-apple-darwin", "wasm32-unknown-unknown"] [features] -default = ["x11", "wayland", "wayland-dlopen"] +default = ["x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"] x11 = ["x11-dl", "mio", "percent-encoding", "parking_lot"] wayland = ["wayland-client", "wayland-protocols", "sctk"] wayland-dlopen = ["sctk/dlopen", "wayland-client/dlopen"] +wayland-csd-adwaita = ["sctk-adwaita", "sctk-adwaita/title"] +wayland-csd-adwaita-notitle = ["sctk-adwaita"] [dependencies] instant = { version = "0.1", features = ["wasm-bindgen"] } @@ -90,6 +92,7 @@ features = [ wayland-client = { version = "0.29.4", default_features = false, features = ["use_system_lib"], optional = true } wayland-protocols = { version = "0.29.4", features = [ "staging_protocols"], optional = true } sctk = { package = "smithay-client-toolkit", version = "0.15.4", default_features = false, features = ["calloop"], optional = true } +sctk-adwaita = { version = "0.3.5", optional = true } mio = { version = "0.8", features = ["os-ext"], optional = true } x11-dl = { version = "2.18.5", optional = true } percent-encoding = { version = "2.0", optional = true } diff --git a/FEATURES.md b/FEATURES.md index 15aacb6b..02625f06 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -173,7 +173,7 @@ Legend: |Window initialization |✔️ |✔️ |▢[#5] |✔️ |▢[#33]|▢[#33] |✔️ | |Providing pointer to init OpenGL |✔️ |✔️ |✔️ |✔️ |✔️ |✔️ |**N/A**| |Providing pointer to init Vulkan |✔️ |✔️ |✔️ |✔️ |✔️ |❓ |**N/A**| -|Window decorations |✔️ |✔️ |✔️ |▢[#306] |**N/A**|**N/A**|**N/A**| +|Window decorations |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**| |Window decorations toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**| |Window resizing |✔️ |▢[#219]|✔️ |▢[#306] |**N/A**|**N/A**|✔️ | |Window resize increments |❌ |❌ |❌ |❌ |❌ |❌ |**N/A**| diff --git a/src/platform/unix.rs b/src/platform/unix.rs index 508cafb5..81b06ad0 100644 --- a/src/platform/unix.rs +++ b/src/platform/unix.rs @@ -32,6 +32,9 @@ pub use crate::platform_impl::x11; #[cfg(feature = "x11")] pub use crate::platform_impl::{x11::util::WindowType as XWindowType, XNotSupported}; +#[cfg(feature = "wayland")] +pub use crate::window::Theme; + /// Additional methods on `EventLoopWindowTarget` that are specific to Unix. pub trait EventLoopWindowTargetExtUnix { /// True if the `EventLoopWindowTarget` uses Wayland. @@ -70,7 +73,6 @@ impl EventLoopWindowTargetExtUnix for EventLoopWindowTarget { } #[inline] - #[doc(hidden)] #[cfg(feature = "x11")] fn xlib_xconnection(&self) -> Option> { match self.p { @@ -179,6 +181,13 @@ pub trait WindowExtUnix { #[cfg(feature = "wayland")] fn wayland_display(&self) -> Option<*mut raw::c_void>; + /// Updates [`Theme`] of window decorations. + /// + /// You can also use `WINIT_WAYLAND_CSD_THEME` env variable to set the theme. + /// Possible values for env variable are: "dark" and light" + #[cfg(feature = "wayland")] + fn wayland_set_csd_theme(&self, config: Theme); + /// Check if the window is ready for drawing /// /// It is a remnant of a previous implementation detail for the @@ -221,7 +230,6 @@ impl WindowExtUnix for Window { } #[inline] - #[doc(hidden)] #[cfg(feature = "x11")] fn xlib_xconnection(&self) -> Option> { match self.window { @@ -261,6 +269,16 @@ impl WindowExtUnix for Window { } } + #[inline] + #[cfg(feature = "wayland")] + fn wayland_set_csd_theme(&self, theme: Theme) { + match self.window { + LinuxWindow::Wayland(ref w) => w.set_csd_theme(theme), + #[cfg(feature = "x11")] + _ => {} + } + } + #[inline] fn is_ready(&self) -> bool { true @@ -299,6 +317,13 @@ pub trait WindowBuilderExtUnix { #[cfg(feature = "x11")] fn with_gtk_theme_variant(self, variant: String) -> Self; + /// Build window with certain decoration [`Theme`] + /// + /// You can also use `WINIT_WAYLAND_CSD_THEME` env variable to set the theme. + /// Possible values for env variable are: "dark" and light" + #[cfg(feature = "wayland")] + fn with_wayland_csd_theme(self, theme: Theme) -> Self; + /// Build window with resize increment hint. Only implemented on X11. /// /// ``` @@ -375,6 +400,13 @@ impl WindowBuilderExtUnix for WindowBuilder { self } + #[inline] + #[cfg(feature = "wayland")] + fn with_wayland_csd_theme(mut self, theme: Theme) -> Self { + self.platform_specific.csd_theme = Some(theme); + self + } + #[inline] #[cfg(feature = "x11")] fn with_resize_increments>(mut self, increments: S) -> Self { diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index cee7f94d..6552a822 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -9,8 +9,11 @@ #[cfg(all(not(feature = "x11"), not(feature = "wayland")))] compile_error!("Please select a feature to build for unix: `x11`, `wayland`"); +#[cfg(feature = "wayland")] +use crate::window::Theme; #[cfg(feature = "wayland")] use std::error::Error; + use std::{collections::VecDeque, env, fmt}; #[cfg(feature = "x11")] use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Arc}; @@ -101,6 +104,8 @@ pub struct PlatformSpecificWindowBuilderAttributes { pub x11_window_types: Vec, #[cfg(feature = "x11")] pub gtk_theme_variant: Option, + #[cfg(feature = "wayland")] + pub csd_theme: Option, } impl Default for PlatformSpecificWindowBuilderAttributes { @@ -121,6 +126,8 @@ impl Default for PlatformSpecificWindowBuilderAttributes { x11_window_types: vec![XWindowType::Normal], #[cfg(feature = "x11")] gtk_theme_variant: None, + #[cfg(feature = "wayland")] + csd_theme: None, } } } diff --git a/src/platform_impl/linux/wayland/seat/pointer/mod.rs b/src/platform_impl/linux/wayland/seat/pointer/mod.rs index 0542ba2f..7ec11640 100644 --- a/src/platform_impl/linux/wayland/seat/pointer/mod.rs +++ b/src/platform_impl/linux/wayland/seat/pointer/mod.rs @@ -13,10 +13,11 @@ use sctk::reexports::protocols::unstable::pointer_constraints::v1::client::zwp_p use sctk::reexports::protocols::unstable::pointer_constraints::v1::client::zwp_confined_pointer_v1::ZwpConfinedPointerV1; use sctk::seat::pointer::{ThemeManager, ThemedPointer}; -use sctk::window::{FallbackFrame, Window}; +use sctk::window::Window; use crate::event::ModifiersState; use crate::platform_impl::wayland::event_loop::WinitState; +use crate::platform_impl::wayland::window::WinitFrame; use crate::window::CursorIcon; mod data; @@ -156,7 +157,7 @@ impl WinitPointer { } } - pub fn drag_window(&self, window: &Window) { + pub fn drag_window(&self, window: &Window) { // WlPointer::setart_interactive_move() expects the last serial of *any* // pointer event (compare to set_cursor()). window.start_interactive_move(&self.seat, self.latest_serial.get()); diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index 04ca0189..6cb3daed 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -8,7 +8,7 @@ use sctk::reexports::client::Display; use sctk::reexports::calloop; use raw_window_handle::WaylandHandle; -use sctk::window::{Decorations, FallbackFrame}; +use sctk::window::Decorations; use crate::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError}; @@ -17,7 +17,7 @@ use crate::platform_impl::{ MonitorHandle as PlatformMonitorHandle, OsError, PlatformSpecificWindowBuilderAttributes as PlatformAttributes, }; -use crate::window::{CursorIcon, Fullscreen, UserAttentionType, WindowAttributes}; +use crate::window::{CursorIcon, Fullscreen, Theme, UserAttentionType, WindowAttributes}; use super::env::WindowingFeatures; use super::event_loop::WinitState; @@ -28,6 +28,14 @@ pub mod shim; use shim::{WindowHandle, WindowRequest, WindowUpdate}; +#[cfg(feature = "sctk-adwaita")] +pub type WinitFrame = sctk_adwaita::AdwaitaFrame; +#[cfg(not(feature = "sctk-adwaita"))] +pub type WinitFrame = sctk::window::FallbackFrame; + +#[cfg(feature = "sctk-adwaita")] +const WAYLAND_CSD_THEME_ENV_VAR: &str = "WINIT_WAYLAND_CSD_THEME"; + pub struct Window { /// Window id. window_id: WindowId, @@ -105,7 +113,7 @@ impl Window { let theme_manager = event_loop_window_target.theme_manager.clone(); let mut window = event_loop_window_target .env - .create_window::( + .create_window::( surface.clone(), Some(theme_manager), (width, height), @@ -139,6 +147,20 @@ impl Window { ) .map_err(|_| os_error!(OsError::WaylandMisc("failed to create window.")))?; + // Set CSD frame config + #[cfg(feature = "sctk-adwaita")] + { + let theme = platform_attributes.csd_theme.unwrap_or_else(|| { + let env = std::env::var(WAYLAND_CSD_THEME_ENV_VAR).unwrap_or_default(); + match env.to_lowercase().as_str() { + "dark" => Theme::Dark, + _ => Theme::Light, + } + }); + + window.set_frame_config(theme.into()); + } + // Set decorations. if attributes.decorations { window.set_decorate(Decorations::FollowServer); @@ -380,6 +402,11 @@ impl Window { self.decorated.load(Ordering::Relaxed) } + #[inline] + pub fn set_csd_theme(&self, theme: Theme) { + self.send_request(WindowRequest::CsdThemeVariant(theme)); + } + #[inline] pub fn set_minimized(&self, minimized: bool) { // You can't unminimize the window on Wayland. @@ -550,3 +577,13 @@ impl Drop for Window { self.send_request(WindowRequest::Close); } } + +#[cfg(feature = "sctk-adwaita")] +impl From for sctk_adwaita::FrameConfig { + fn from(theme: Theme) -> Self { + match theme { + Theme::Light => sctk_adwaita::FrameConfig::light(), + Theme::Dark => sctk_adwaita::FrameConfig::dark(), + } + } +} diff --git a/src/platform_impl/linux/wayland/window/shim.rs b/src/platform_impl/linux/wayland/window/shim.rs index 7359a300..9789d5db 100644 --- a/src/platform_impl/linux/wayland/window/shim.rs +++ b/src/platform_impl/linux/wayland/window/shim.rs @@ -8,7 +8,7 @@ use sctk::reexports::protocols::staging::xdg_activation::v1::client::xdg_activat use sctk::reexports::protocols::staging::xdg_activation::v1::client::xdg_activation_v1::XdgActivationV1; use sctk::environment::Environment; -use sctk::window::{Decorations, FallbackFrame, Window}; +use sctk::window::{Decorations, Window}; use crate::dpi::{LogicalPosition, LogicalSize}; @@ -19,7 +19,9 @@ use crate::platform_impl::wayland::event_loop::{EventSink, WinitState}; use crate::platform_impl::wayland::seat::pointer::WinitPointer; use crate::platform_impl::wayland::seat::text_input::TextInputHandler; use crate::platform_impl::wayland::WindowId; -use crate::window::{CursorIcon, UserAttentionType}; +use crate::window::{CursorIcon, Theme, UserAttentionType}; + +use super::WinitFrame; /// A request to SCTK window from Winit window. #[derive(Debug, Clone)] @@ -53,6 +55,9 @@ pub enum WindowRequest { /// Request decorations change. Decorate(bool), + /// Request decorations change. + CsdThemeVariant(Theme), + /// Make the window resizeable. Resizeable(bool), @@ -146,7 +151,7 @@ impl WindowUpdate { /// and react to events. pub struct WindowHandle { /// An actual window. - pub window: Window, + pub window: Window, /// The current size of the window. pub size: Arc>>, @@ -188,7 +193,7 @@ pub struct WindowHandle { impl WindowHandle { pub fn new( env: &Environment, - window: Window, + window: Window, size: Arc>>, pending_window_requests: Arc>>, ) -> Self { @@ -450,6 +455,15 @@ pub fn handle_window_requests(winit_state: &mut WinitState) { let window_update = window_updates.get_mut(window_id).unwrap(); window_update.refresh_frame = true; } + #[cfg(feature = "sctk-adwaita")] + WindowRequest::CsdThemeVariant(theme) => { + window_handle.window.set_frame_config(theme.into()); + + let window_update = window_updates.get_mut(window_id).unwrap(); + window_update.refresh_frame = true; + } + #[cfg(not(feature = "sctk-adwaita"))] + WindowRequest::CsdThemeVariant(_) => {} WindowRequest::Resizeable(resizeable) => { window_handle.window.set_resizable(resizeable);