Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add background_color APIs #995

Merged
merged 7 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
6 changes: 6 additions & 0 deletions .changes/background_color.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"tao": "patch"
---

Add `WindowAttributes::background_color`, `WindowBuilder::with_background_color`, and `Window::set_background_colr` APIs to set and change window background colors.
lucasfernog marked this conversation as resolved.
Show resolved Hide resolved

2 changes: 2 additions & 0 deletions src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,8 @@ impl Window {
))
}

pub fn set_background_color(&self, _color: Option<crate::window::RGBA>) {}

pub fn set_ignore_cursor_events(&self, _ignore: bool) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported(
error::NotSupportedError::new(),
Expand Down
2 changes: 2 additions & 0 deletions src/platform_impl/ios/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,8 @@ impl Inner {
warn!("`Window::request_user_attention` is ignored on iOS")
}

pub fn set_background_color(&self, _color: Option<crate::window::RGBA>) {}

// Allow directly accessing the current monitor internally without unwrapping.
fn current_monitor_inner(&self) -> RootMonitorHandle {
unsafe {
Expand Down
49 changes: 46 additions & 3 deletions src/platform_impl/linux/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,28 @@ impl<T: 'static> EventLoop<T> {
window.set_skip_taskbar_hint(skip);
window.set_skip_pager_hint(skip)
}
WindowRequest::BackgroundColor(css_provider, color) => {
unsafe { window.set_data("background_color", color) };

let style_context = window.style_context();
style_context.remove_provider(&css_provider);

if let Some(color) = color {
let theme = format!(
r#"
window {{
background-color: rgba({},{},{},{});
}}
"#,
color.0,
color.1,
color.2,
color.3 as f64 / 255.0
);
let _ = css_provider.load_from_data(theme.as_bytes());
style_context.add_provider(&css_provider, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION);
};
}
WindowRequest::SetVisibleOnAllWorkspaces(visible) => {
if visible {
window.stick();
Expand Down Expand Up @@ -854,15 +876,36 @@ impl<T: 'static> EventLoop<T> {

// Receive draw events of the window.
let draw_clone = draw_tx.clone();
window.connect_draw(move |_, cr| {
window.connect_draw(move |window, cr| {
if let Err(e) = draw_clone.send(id) {
log::warn!("Failed to send redraw event to event channel: {}", e);
}

if transparent {
cr.set_source_rgba(0., 0., 0., 0.);
let background_color = unsafe {
window
.data::<Option<crate::window::RGBA>>("background_color")
.and_then(|c| c.as_ref().clone())
};

let rgba = background_color
.map(|(r, g, b, a)| (r as f64, g as f64, b as f64, a as f64 / 255.0))
.unwrap_or((0., 0., 0., 0.));

let rect = window
.child()
.map(|c| c.allocation())
.unwrap_or_else(|| window.allocation());

cr.rectangle(
rect.x() as _,
rect.y() as _,
rect.width() as _,
rect.height() as _,
);
cr.set_source_rgba(rgba.0, rgba.1, rgba.2, rgba.3);
cr.set_operator(cairo::Operator::Source);
let _ = cr.paint();
let _ = cr.fill();
cr.set_operator(cairo::Operator::Over);
}

Expand Down
20 changes: 17 additions & 3 deletions src/platform_impl/linux/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use gtk::{
gdk::WindowState,
glib::{self, translate::ToGlibPtr},
prelude::*,
Settings,
CssProvider, Settings,
};

use crate::{
Expand All @@ -27,7 +27,7 @@ use crate::{
platform_impl::wayland::header::WlHeader,
window::{
CursorIcon, Fullscreen, ProgressBarState, ResizeDirection, Theme, UserAttentionType,
WindowAttributes, WindowSizeConstraints,
WindowAttributes, WindowSizeConstraints, RGBA,
},
};

Expand Down Expand Up @@ -69,6 +69,7 @@ pub struct Window {
/// Draw event Sender
draw_tx: crossbeam_channel::Sender<WindowId>,
preferred_theme: RefCell<Option<Theme>>,
css_provider: CssProvider,
}

impl Window {
Expand Down Expand Up @@ -324,9 +325,11 @@ impl Window {
fullscreen: RefCell::new(attributes.fullscreen),
inner_size_constraints: RefCell::new(attributes.inner_size_constraints),
preferred_theme: RefCell::new(preferred_theme),
css_provider: CssProvider::new(),
};

win.set_skip_taskbar(pl_attribs.skip_taskbar);
let _ = win.set_skip_taskbar(pl_attribs.skip_taskbar);
win.set_background_color(attributes.background_color);

Ok(win)
}
Expand Down Expand Up @@ -407,6 +410,7 @@ impl Window {
fullscreen: RefCell::new(None),
inner_size_constraints: RefCell::new(WindowSizeConstraints::default()),
preferred_theme: RefCell::new(None),
css_provider: CssProvider::new(),
};

Ok(win)
Expand Down Expand Up @@ -456,6 +460,15 @@ impl Window {
}
}

pub fn set_background_color(&self, color: Option<RGBA>) {
if let Err(e) = self.window_requests_tx.send((
self.window_id,
WindowRequest::BackgroundColor(self.css_provider.clone(), color),
)) {
log::warn!("Fail to send size request: {}", e);
}
}

pub fn inner_size(&self) -> PhysicalSize<u32> {
let (width, height) = &*self.size;

Expand Down Expand Up @@ -1029,6 +1042,7 @@ pub enum WindowRequest {
SetVisibleOnAllWorkspaces(bool),
ProgressBarState(ProgressBarState),
SetTheme(Option<Theme>),
BackgroundColor(CssProvider, Option<RGBA>),
}

impl Drop for Window {
Expand Down
44 changes: 43 additions & 1 deletion src/platform_impl/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ pub struct UnownedWindow {
pub shared_state: Arc<Mutex<SharedState>>,
decorations: AtomicBool,
cursor_state: Weak<Mutex<CursorState>>,
transparent: bool,
pub inner_rect: Option<PhysicalSize<u32>>,
}

Expand Down Expand Up @@ -499,7 +500,22 @@ impl UnownedWindow {

unsafe {
if win_attribs.transparent {
ns_window.setOpaque_(NO);
let color = ns_window.setOpaque_(NO);
}

if win_attribs.transparent || win_attribs.background_color.is_some() {
let color = win_attribs
.background_color
.map(|(r, g, b, a)| {
NSColor::colorWithRed_green_blue_alpha_(
nil,
r as f64,
g as f64,
b as f64,
a as f64 / 255.0,
)
})
.unwrap_or_else(|| NSColor::clearColor(nil));
ns_window.setBackgroundColor_(NSColor::clearColor(nil));
}

Expand Down Expand Up @@ -530,6 +546,7 @@ impl UnownedWindow {
// `WindowDelegate` to update the state.
let fullscreen = win_attribs.fullscreen.take();
let maximized = win_attribs.maximized;
let transparent = win_attribs.transparent;
let visible = win_attribs.visible;
let focused = win_attribs.focused;
let decorations = win_attribs.decorations;
Expand All @@ -548,6 +565,7 @@ impl UnownedWindow {
decorations: AtomicBool::new(decorations),
cursor_state,
inner_rect,
transparent,
});

match cloned_preferred_theme {
Expand Down Expand Up @@ -848,6 +866,30 @@ impl UnownedWindow {
Ok(())
}

#[inline]
pub fn set_background_color(&self, color: Option<crate::window::RGBA>) {
unsafe {
let color = color
.map(|(r, g, b, a)| {
NSColor::colorWithRed_green_blue_alpha_(
nil,
r as f64,
g as f64,
b as f64,
a as f64 / 255.0,
)
})
.unwrap_or_else(|| {
if self.transparent {
NSColor::clearColor(nil)
} else {
nil
}
});
self.ns_window.setBackgroundColor_(color);
}
}

#[inline]
pub fn drag_window(&self) -> Result<(), ExternalError> {
unsafe {
Expand Down
19 changes: 19 additions & 0 deletions src/platform_impl/windows/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,25 @@ unsafe fn public_window_callback_inner<T: 'static>(
}
}

win32wm::WM_ERASEBKGND => {
let w = subclass_input.window_state.lock();
if let Some(color) = w.background_color {
let hdc = HDC(wparam.0 as *mut _);
let mut rc = RECT::default();
if GetClientRect(window, &mut rc).is_ok() {
let brush = CreateSolidBrush(util::RGB(color.0, color.1, color.2));
FillRect(hdc, &rc, brush);
let _ = DeleteObject(brush);

result = ProcResult::Value(LRESULT(1));
} else {
result = ProcResult::DefSubclassProc;
}
} else {
result = ProcResult::DefSubclassProc;
}
}

win32wm::WM_WINDOWPOSCHANGING => {
let mut window_state = subclass_input.window_state.lock();

Expand Down
9 changes: 8 additions & 1 deletion src/platform_impl/windows/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::{
use windows::{
core::{HRESULT, PCSTR, PCWSTR},
Win32::{
Foundation::{BOOL, FARPROC, HWND, LPARAM, LRESULT, POINT, RECT, WPARAM},
Foundation::{BOOL, COLORREF, FARPROC, HWND, LPARAM, LRESULT, POINT, RECT, WPARAM},
Globalization::lstrlenW,
Graphics::Gdi::{ClientToScreen, InvalidateRgn, HMONITOR, HRGN},
System::LibraryLoader::*,
Expand Down Expand Up @@ -393,6 +393,13 @@ pub fn PRIMARYLANGID(hkl: HKL) -> u32 {
((hkl.0 as usize) & 0x3FF) as u32
}

/// Implementation of the `RGB` macro.
#[allow(non_snake_case)]
#[inline]
pub fn RGB<T: Into<u32>>(r: T, g: T, b: T) -> COLORREF {
COLORREF(r.into() | g.into() << 8 | b.into() << 16)
}

pub unsafe extern "system" fn call_default_window_proc(
hwnd: HWND,
msg: u32,
Expand Down
13 changes: 12 additions & 1 deletion src/platform_impl/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ use crate::{
},
window::{
CursorIcon, Fullscreen, ProgressBarState, ProgressState, ResizeDirection, Theme,
UserAttentionType, WindowAttributes, WindowSizeConstraints,
UserAttentionType, WindowAttributes, WindowSizeConstraints, RGBA,
},
};

Expand Down Expand Up @@ -982,6 +982,16 @@ impl Window {
unsafe { set_skip_taskbar(self.hwnd(), skip) }
}

#[inline]
pub fn set_background_color(&self, color: Option<RGBA>) {
self.window_state.lock().background_color = color;

unsafe {
let _ = InvalidateRect(self.hwnd(), None, true);
let _ = UpdateWindow(self.hwnd());
}
}

#[inline]
pub fn set_progress_bar(&self, progress: ProgressBarState) {
unsafe {
Expand Down Expand Up @@ -1176,6 +1186,7 @@ unsafe fn init<T: 'static>(
scale_factor,
current_theme,
attributes.preferred_theme,
attributes.background_color,
);
let window_state = Arc::new(Mutex::new(window_state));
WindowState::set_window_flags(window_state.lock(), real_window.0, |f| *f = window_flags);
Expand Down
7 changes: 6 additions & 1 deletion src/platform_impl/windows/window_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
icon::Icon,
keyboard::ModifiersState,
platform_impl::platform::{event_loop, minimal_ime::MinimalIme, util},
window::{CursorIcon, Fullscreen, Theme, WindowAttributes, WindowSizeConstraints},
window::{CursorIcon, Fullscreen, Theme, WindowAttributes, WindowSizeConstraints, RGBA},
};
use parking_lot::MutexGuard;
use std::io;
Expand Down Expand Up @@ -46,6 +46,8 @@ pub struct WindowState {
// Used by WM_NCACTIVATE, WM_SETFOCUS and WM_KILLFOCUS
pub is_active: bool,
pub is_focused: bool,

pub background_color: Option<RGBA>,
}

unsafe impl Send for WindowState {}
Expand Down Expand Up @@ -126,6 +128,7 @@ impl WindowState {
scale_factor: f64,
current_theme: Theme,
preferred_theme: Option<Theme>,
background_color: Option<RGBA>,
) -> WindowState {
WindowState {
mouse: MouseProperties {
Expand Down Expand Up @@ -155,6 +158,8 @@ impl WindowState {
window_flags: WindowFlags::empty(),
is_active: false,
is_focused: false,

background_color,
}
}

Expand Down
Loading
Loading