Skip to content

Commit

Permalink
feat: add theme feature on Linux (#468)
Browse files Browse the repository at this point in the history
  • Loading branch information
keiya01 committed Jul 10, 2022
1 parent 2ad9126 commit 74425e8
Show file tree
Hide file tree
Showing 11 changed files with 91 additions and 61 deletions.
5 changes: 5 additions & 0 deletions .changes/impl-theme-linux.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": patch
---

Add theme feature on Linux.
19 changes: 0 additions & 19 deletions examples/theme.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0

#[cfg(any(target_os = "windows", target_os = "macos"))]
#[allow(clippy::single_match)]
fn main() {
use tao::{
Expand All @@ -10,11 +9,6 @@ fn main() {
window::WindowBuilder,
};

#[cfg(any(target_os = "macos"))]
use tao::platform::macos::{WindowBuilderExtMacOS, WindowExtMacOS};
#[cfg(target_os = "windows")]
use tao::platform::windows::{WindowBuilderExtWindows, WindowExtWindows};

env_logger::init();
let event_loop = EventLoop::new();

Expand Down Expand Up @@ -45,16 +39,3 @@ fn main() {
}
});
}

#[cfg(any(
target_os = "ios",
target_os = "android",
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
fn main() {
println!("This platform doesn't support theme.");
}
4 changes: 3 additions & 1 deletion src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,9 @@ pub enum WindowEvent<'a> {
/// Applications might wish to react to this to change the theme of the content of the window
/// when the system changes the window theme.
///
/// At the moment this is only supported on Windows.
/// ## Platform-specific
///
/// - **Linux / Android / iOS:** Unsupported
ThemeChanged(Theme),

/// The window decorations has been clicked.
Expand Down
18 changes: 1 addition & 17 deletions src/platform/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
menu::CustomMenuItem,
monitor::MonitorHandle,
platform_impl::{get_aux_state_mut, Parent},
window::{Icon, Theme, Window, WindowBuilder},
window::{Icon, Window, WindowBuilder},
};

#[cfg(feature = "tray")]
Expand Down Expand Up @@ -54,9 +54,6 @@ pub trait WindowExtMacOS {

/// Sets whether or not the window has shadow.
fn set_has_shadow(&self, has_shadow: bool);

/// Returns the current window theme.
fn theme(&self) -> Theme;
}

impl WindowExtMacOS for Window {
Expand Down Expand Up @@ -89,11 +86,6 @@ impl WindowExtMacOS for Window {
fn set_has_shadow(&self, has_shadow: bool) {
self.window.set_has_shadow(has_shadow)
}

#[inline]
fn theme(&self) -> Theme {
self.window.theme()
}
}

/// Corresponds to `NSApplicationActivationPolicy`.
Expand Down Expand Up @@ -346,8 +338,6 @@ pub trait WindowBuilderExtMacOS {
fn with_resize_increments(self, increments: LogicalSize<f64>) -> WindowBuilder;
fn with_disallow_hidpi(self, disallow_hidpi: bool) -> WindowBuilder;
fn with_has_shadow(self, has_shadow: bool) -> WindowBuilder;
/// Forces a theme or uses the system settings if `None` was provided.
fn with_theme(self, theme: Option<Theme>) -> WindowBuilder;
}

impl WindowBuilderExtMacOS for WindowBuilder {
Expand Down Expand Up @@ -413,12 +403,6 @@ impl WindowBuilderExtMacOS for WindowBuilder {
self.platform_specific.has_shadow = has_shadow;
self
}

#[inline]
fn with_theme(mut self, theme: Option<Theme>) -> WindowBuilder {
self.platform_specific.preferred_theme = theme;
self
}
}

pub trait EventLoopExtMacOS {
Expand Down
9 changes: 0 additions & 9 deletions src/platform/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,6 @@ pub trait WindowBuilderExtWindows {
/// See <https://docs.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize#remarks> for more information.
fn with_drag_and_drop(self, flag: bool) -> WindowBuilder;

/// Forces a theme or uses the system settings if `None` was provided.
fn with_theme(self, theme: Option<Theme>) -> WindowBuilder;

/// Whether to create the window icon with the taskbar icon or not.
fn with_skip_taskbar(self, skip: bool) -> WindowBuilder;
}
Expand Down Expand Up @@ -251,12 +248,6 @@ impl WindowBuilderExtWindows for WindowBuilder {
self
}

#[inline]
fn with_theme(mut self, theme: Option<Theme>) -> WindowBuilder {
self.platform_specific.preferred_theme = theme;
self
}

#[inline]
fn with_skip_taskbar(mut self, skip: bool) -> WindowBuilder {
self.platform_specific.skip_taskbar = skip;
Expand Down
7 changes: 6 additions & 1 deletion src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use crate::{
icon::Icon,
keyboard::{Key, KeyCode, KeyLocation, NativeKeyCode},
menu::{CustomMenuItem, MenuId, MenuItem, MenuType},
monitor, window,
monitor,
window::{self, Theme},
};
use ndk::{
configuration::Configuration,
Expand Down Expand Up @@ -689,6 +690,10 @@ impl Window {
pub fn content_rect(&self) -> Rect {
ndk_glue::content_rect()
}

pub fn theme(&self) -> Theme {
Theme::Light
}
}

#[derive(Default, Clone, Debug)]
Expand Down
8 changes: 7 additions & 1 deletion src/platform_impl/ios/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ use crate::{
},
monitor, view, EventLoopWindowTarget, Menu, MonitorHandle,
},
window::{CursorIcon, Fullscreen, UserAttentionType, WindowAttributes, WindowId as RootWindowId},
window::{
CursorIcon, Fullscreen, Theme, UserAttentionType, WindowAttributes, WindowId as RootWindowId,
},
};

pub struct Inner {
Expand Down Expand Up @@ -351,6 +353,10 @@ impl Inner {
handle.ui_view_controller = self.view_controller as _;
RawWindowHandle::UiKit(handle)
}

pub fn theme(&self) -> Theme {
Theme::Light
}
}

pub struct Window {
Expand Down
40 changes: 38 additions & 2 deletions src/platform_impl/linux/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::{
};

use gdk::{WindowEdge, WindowState};
use gtk::{prelude::*, AccelGroup, Orientation};
use gtk::{prelude::*, traits::SettingsExt, AccelGroup, Orientation, Settings};
use raw_window_handle::{RawWindowHandle, XlibHandle};

use crate::{
Expand All @@ -18,7 +18,9 @@ use crate::{
icon::Icon,
menu::{MenuId, MenuItem},
monitor::MonitorHandle as RootMonitorHandle,
window::{CursorIcon, Fullscreen, UserAttentionType, WindowAttributes, BORDERLESS_RESIZE_INSET},
window::{
CursorIcon, Fullscreen, Theme, UserAttentionType, WindowAttributes, BORDERLESS_RESIZE_INSET,
},
};

use super::{
Expand Down Expand Up @@ -192,6 +194,26 @@ impl Window {
window.set_icon(Some(&icon.inner.into()));
}

let settings = Settings::default();

if let Some(settings) = settings {
if let Some(preferred_theme) = attributes.preferred_theme {
match preferred_theme {
Theme::Dark => settings.set_gtk_application_prefer_dark_theme(true),
Theme::Light => {
let theme_name = settings.gtk_theme_name().map(|t| t.as_str().to_owned());
if let Some(theme) = theme_name {
// Remove dark variant.
match (theme.strip_suffix("-dark"), theme.strip_suffix("-Dark")) {
(theme, None) | (None, theme) => settings.set_gtk_theme_name(theme),
_ => {}
}
}
}
}
}
}

if attributes.visible {
window.show_all();
} else {
Expand Down Expand Up @@ -647,6 +669,20 @@ impl Window {
log::warn!("Fail to send skip taskbar request: {}", e);
}
}

pub fn theme(&self) -> Theme {
if let Some(settings) = Settings::default() {
let theme_name = settings.gtk_theme_name().map(|s| s.as_str().to_owned());
if let Some(theme) = theme_name {
// Currently GTK doesn't provide feature for detect theme, so we need to check theme manually.
// ref: https://github.com/WebKit/WebKit/blob/e44ffaa0d999a9807f76f1805943eea204cfdfbc/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp#L587
if theme.ends_with("-dark") || theme.ends_with("-Dark") {
return Theme::Dark;
}
}
}
return Theme::Light;
}
}

// We need GtkWindow to initialize WebView, so we have to keep it in the field.
Expand Down
20 changes: 10 additions & 10 deletions src/platform_impl/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ pub struct PlatformSpecificWindowBuilderAttributes {
pub resize_increments: Option<LogicalSize<f64>>,
pub disallow_hidpi: bool,
pub has_shadow: bool,
pub preferred_theme: Option<Theme>,
}

impl Default for PlatformSpecificWindowBuilderAttributes {
Expand All @@ -104,7 +103,6 @@ impl Default for PlatformSpecificWindowBuilderAttributes {
resize_increments: None,
disallow_hidpi: false,
has_shadow: true,
preferred_theme: None,
}
}
}
Expand Down Expand Up @@ -484,6 +482,8 @@ impl UnownedWindow {
.inner_size
.map(|size| size.to_physical(scale_factor));

let cloned_preferred_theme = win_attribs.preferred_theme.clone();

let window = Arc::new(UnownedWindow {
ns_view,
ns_window,
Expand All @@ -494,11 +494,11 @@ impl UnownedWindow {
inner_rect,
});

match pl_attribs.preferred_theme {
match cloned_preferred_theme {
Some(theme) => {
set_ns_theme(theme);
let mut state = window.shared_state.lock().unwrap();
state.current_theme = theme;
state.current_theme = theme.clone();
}
None => {
let mut state = window.shared_state.lock().unwrap();
Expand Down Expand Up @@ -1208,6 +1208,12 @@ impl UnownedWindow {
handle.ns_view = *self.ns_view as *mut _;
RawWindowHandle::AppKit(handle)
}

#[inline]
pub fn theme(&self) -> Theme {
let state = self.shared_state.lock().unwrap();
state.current_theme
}
}

impl WindowExtMacOS for UnownedWindow {
Expand Down Expand Up @@ -1323,12 +1329,6 @@ impl WindowExtMacOS for UnownedWindow {
.setHasShadow_(if has_shadow { YES } else { NO })
}
}

#[inline]
fn theme(&self) -> Theme {
let state = self.shared_state.lock().unwrap();
state.current_theme
}
}

impl Drop for UnownedWindow {
Expand Down
2 changes: 1 addition & 1 deletion src/platform_impl/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,7 @@ unsafe fn init<T: 'static>(
// If the system theme is dark, we need to set the window theme now
// before we update the window flags (and possibly show the
// window for the first time).
let current_theme = try_theme(real_window.0, pl_attribs.preferred_theme);
let current_theme = try_theme(real_window.0, attributes.preferred_theme);

let window_state = {
let window_state = WindowState::new(
Expand Down
20 changes: 20 additions & 0 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ pub struct WindowAttributes {
///
/// The default is `None`.
pub window_menu: Option<platform_impl::Menu>,

pub preferred_theme: Option<Theme>,
}

impl Default for WindowAttributes {
Expand All @@ -217,6 +219,7 @@ impl Default for WindowAttributes {
always_on_top: false,
window_icon: None,
window_menu: None,
preferred_theme: None,
}
}
}
Expand Down Expand Up @@ -378,6 +381,13 @@ impl WindowBuilder {
self
}

/// Forces a theme or uses the system settings if `None` was provided.
#[inline]
pub fn with_theme(mut self, theme: Option<Theme>) -> WindowBuilder {
self.window.preferred_theme = theme;
self
}

/// Builds the window.
///
/// Possible causes of error include denied permission, incompatible system, and lack of memory.
Expand Down Expand Up @@ -832,6 +842,16 @@ impl Window {
pub fn is_menu_visible(&self) -> bool {
self.window.is_menu_visible()
}

/// Returns the current window theme.
///
/// ## Platform-specific
///
/// - **iOS / Android:** Unsupported.
#[inline]
pub fn theme(&self) -> Theme {
self.window.theme()
}
}

/// Cursor functions.
Expand Down

0 comments on commit 74425e8

Please sign in to comment.