Skip to content

Commit

Permalink
feat(core): add a new function to set theme dynamically (#10210)
Browse files Browse the repository at this point in the history
closes #5279
  • Loading branch information
Legend-Master authored Sep 24, 2024
1 parent 8d22c0c commit 11db7be
Show file tree
Hide file tree
Showing 21 changed files with 281 additions and 8 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/tauri-runtime-wry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ wry = { version = "0.44.0", default-features = false, features = [
"os-webview",
"linux-body",
] }
tao = { version = "0.30", default-features = false, features = ["rwh_06"] }
tao = { version = "0.30.2", default-features = false, features = ["rwh_06"] }
tauri-runtime = { version = "2.0.0-rc.12", path = "../tauri-runtime" }
tauri-utils = { version = "2.0.0-rc.12", path = "../tauri-utils" }
raw-window-handle = "0.6"
Expand Down
35 changes: 35 additions & 0 deletions crates/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1204,6 +1204,7 @@ pub enum WindowMessage {
SetIgnoreCursorEvents(bool),
SetProgressBar(ProgressBarState),
SetTitleBarStyle(tauri_utils::TitleBarStyle),
SetTheme(Option<Theme>),
DragWindow,
ResizeDragWindow(tauri_runtime::ResizeDirection),
RequestRedraw,
Expand Down Expand Up @@ -2026,6 +2027,13 @@ impl<T: UserEvent> WindowDispatch<T> for WryWindowDispatcher<T> {
Message::Window(self.window_id, WindowMessage::SetTitleBarStyle(style)),
)
}

fn set_theme(&self, theme: Option<Theme>) -> Result<()> {
send_user_message(
&self.context,
Message::Window(self.window_id, WindowMessage::SetTheme(theme)),
)
}
}

#[derive(Clone)]
Expand Down Expand Up @@ -2286,6 +2294,18 @@ impl<T: UserEvent> RuntimeHandle<T> for WryHandle<T> {
.map_err(|_| Error::FailedToGetCursorPosition)
}

fn set_theme(&self, theme: Option<Theme>) {
self
.context
.main_thread
.window_target
.set_theme(match theme {
Some(Theme::Light) => Some(TaoTheme::Light),
Some(Theme::Dark) => Some(TaoTheme::Dark),
_ => None,
});
}

#[cfg(target_os = "macos")]
fn show(&self) -> tauri_runtime::Result<()> {
send_user_message(
Expand Down Expand Up @@ -2564,6 +2584,14 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
.map_err(|_| Error::FailedToGetCursorPosition)
}

fn set_theme(&self, theme: Option<Theme>) {
self.event_loop.set_theme(match theme {
Some(Theme::Light) => Some(TaoTheme::Light),
Some(Theme::Dark) => Some(TaoTheme::Dark),
_ => None,
});
}

#[cfg(target_os = "macos")]
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
self
Expand Down Expand Up @@ -2996,6 +3024,13 @@ fn handle_user_message<T: UserEvent>(
}
};
}
WindowMessage::SetTheme(theme) => {
window.set_theme(match theme {
Some(Theme::Light) => Some(TaoTheme::Light),
Some(Theme::Dark) => Some(TaoTheme::Dark),
_ => None,
});
}
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions crates/tauri-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@ pub trait RuntimeHandle<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'st

fn cursor_position(&self) -> Result<PhysicalPosition<f64>>;

fn set_theme(&self, theme: Option<Theme>);

/// Shows the application, but does not automatically focus it.
#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
Expand Down Expand Up @@ -402,6 +404,8 @@ pub trait Runtime<T: UserEvent>: Debug + Sized + 'static {

fn cursor_position(&self) -> Result<PhysicalPosition<f64>>;

fn set_theme(&self, theme: Option<Theme>);

/// Sets the activation policy for the application.
#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
Expand Down Expand Up @@ -802,4 +806,12 @@ pub trait WindowDispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 's
///
/// - **Linux / Windows / iOS / Android:** Unsupported.
fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> Result<()>;

/// Sets the theme for this window.
///
/// ## Platform-specific
///
/// - **Linux / macOS**: Theme is app-wide and not specific to this window.
/// - **iOS / Android:** Unsupported.
fn set_theme(&self, theme: Option<Theme>) -> Result<()>;
}
2 changes: 2 additions & 0 deletions crates/tauri/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
("set_progress_bar", false),
("set_icon", false),
("set_title_bar_style", false),
("set_theme", false),
("toggle_maximize", false),
// internal
("internal_toggle_maximize", true),
Expand Down Expand Up @@ -141,6 +142,7 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
("app_show", false),
("app_hide", false),
("default_window_icon", false),
("set_app_theme", false),
],
),
(
Expand Down
26 changes: 26 additions & 0 deletions crates/tauri/permissions/app/autogenerated/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,32 @@ Denies the name command without any pre-configured scope.
<tr>
<td>

`core:app:allow-set-app-theme`

</td>
<td>

Enables the set_app_theme command without any pre-configured scope.

</td>
</tr>

<tr>
<td>

`core:app:deny-set-app-theme`

</td>
<td>

Denies the set_app_theme command without any pre-configured scope.

</td>
</tr>

<tr>
<td>

`core:app:allow-tauri-version`

</td>
Expand Down
26 changes: 26 additions & 0 deletions crates/tauri/permissions/window/autogenerated/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1469,6 +1469,32 @@ Denies the set_skip_taskbar command without any pre-configured scope.
<tr>
<td>

`core:window:allow-set-theme`

</td>
<td>

Enables the set_theme command without any pre-configured scope.

</td>
</tr>

<tr>
<td>

`core:window:deny-set-theme`

</td>
<td>

Denies the set_theme command without any pre-configured scope.

</td>
</tr>

<tr>
<td>

`core:window:allow-set-title`

</td>
Expand Down
2 changes: 1 addition & 1 deletion crates/tauri/scripts/bundle.global.js

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions crates/tauri/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,31 @@ macro_rules! shared_app_impl {
})
}

/// Set the app theme.
pub fn set_theme(&self, theme: Option<Theme>) {
#[cfg(windows)]
for window in self.manager.windows().values() {
if let (Some(menu), Ok(hwnd)) = (window.menu(), window.hwnd()) {
let raw_hwnd = hwnd.0 as isize;
let _ = self.run_on_main_thread(move || {
let _ = unsafe {
menu.inner().set_theme_for_hwnd(
raw_hwnd,
theme
.map(crate::menu::map_to_menu_theme)
.unwrap_or(muda::MenuTheme::Auto),
)
};
});
};
}
match self.runtime() {
RuntimeOrDispatch::Runtime(h) => h.set_theme(theme),
RuntimeOrDispatch::RuntimeHandle(h) => h.set_theme(theme),
_ => unreachable!(),
}
}

/// Returns the default window icon.
pub fn default_window_icon(&self) -> Option<&Image<'_>> {
self.manager.window.default_icon.as_ref()
Expand Down
8 changes: 8 additions & 0 deletions crates/tauri/src/app/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use tauri_utils::Theme;

use crate::{
command,
plugin::{Builder, TauriPlugin},
Expand Down Expand Up @@ -50,6 +52,11 @@ pub fn default_window_icon<R: Runtime>(
})
}

#[command(root = "crate")]
pub async fn set_app_theme<R: Runtime>(app: AppHandle<R>, theme: Option<Theme>) {
app.set_theme(theme);
}

pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("app")
.invoke_handler(crate::generate_handler![
Expand All @@ -59,6 +66,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
app_show,
app_hide,
default_window_icon,
set_app_theme,
])
.build()
}
12 changes: 12 additions & 0 deletions crates/tauri/src/test/mock_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ impl<T: UserEvent> RuntimeHandle<T> for MockRuntimeHandle {
unimplemented!()
}

fn set_theme(&self, theme: Option<Theme>) {
unimplemented!()
}

/// Shows the application, but does not automatically focus it.
#[cfg(target_os = "macos")]
fn show(&self) -> Result<()> {
Expand Down Expand Up @@ -955,6 +959,10 @@ impl<T: UserEvent> WindowDispatch<T> for MockWindowDispatcher {
) -> Result<()> {
Ok(())
}

fn set_theme(&self, theme: Option<Theme>) -> Result<()> {
Ok(())
}
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -1096,6 +1104,10 @@ impl<T: UserEvent> Runtime<T> for MockRuntime {
unimplemented!()
}

fn set_theme(&self, theme: Option<Theme>) {
unimplemented!()
}

#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
fn set_activation_policy(&mut self, activation_policy: tauri_runtime::ActivationPolicy) {}
Expand Down
10 changes: 9 additions & 1 deletion crates/tauri/src/webview/webview_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ use crate::{
},
};
use serde::Serialize;
use tauri_utils::config::{WebviewUrl, WindowConfig};
use tauri_utils::{
config::{WebviewUrl, WindowConfig},
Theme,
};
use url::Url;

use crate::{
Expand Down Expand Up @@ -1582,6 +1585,11 @@ impl<R: Runtime> WebviewWindow<R> {
pub fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> crate::Result<()> {
self.webview.window().set_title_bar_style(style)
}

/// Set the window theme.
pub fn set_theme(&self, theme: Option<Theme>) -> crate::Result<()> {
self.webview.window().set_theme(theme)
}
}

/// Desktop webview setters and actions.
Expand Down
30 changes: 30 additions & 0 deletions crates/tauri/src/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1981,6 +1981,7 @@ tauri::Builder::default()
})
.map_err(Into::into)
}

/// Sets the title bar style. **macOS only**.
pub fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> crate::Result<()> {
self
Expand All @@ -1989,6 +1990,35 @@ tauri::Builder::default()
.set_title_bar_style(style)
.map_err(Into::into)
}

/// Sets the theme for this window.
///
/// ## Platform-specific
///
/// - **Linux / macOS**: Theme is app-wide and not specific to this window.
/// - **iOS / Android:** Unsupported.
pub fn set_theme(&self, theme: Option<Theme>) -> crate::Result<()> {
self
.window
.dispatcher
.set_theme(theme)
.map_err(Into::<crate::Error>::into)?;
#[cfg(windows)]
if let (Some(menu), Ok(hwnd)) = (self.menu(), self.hwnd()) {
let raw_hwnd = hwnd.0 as isize;
self.run_on_main_thread(move || {
let _ = unsafe {
menu.inner().set_theme_for_hwnd(
raw_hwnd,
theme
.map(crate::menu::map_to_menu_theme)
.unwrap_or(muda::MenuTheme::Auto),
)
};
})?;
};
Ok(())
}
}

/// Progress bar state.
Expand Down
2 changes: 2 additions & 0 deletions crates/tauri/src/window/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ mod desktop_commands {
setter!(set_visible_on_all_workspaces, bool);
setter!(set_title_bar_style, TitleBarStyle);
setter!(set_size_constraints, WindowSizeConstraints);
setter!(set_theme, Option<Theme>);

#[command(root = "crate")]
pub async fn set_icon<R: Runtime>(
Expand Down Expand Up @@ -287,6 +288,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
desktop_commands::set_icon,
desktop_commands::set_visible_on_all_workspaces,
desktop_commands::set_title_bar_style,
desktop_commands::set_theme,
desktop_commands::toggle_maximize,
desktop_commands::internal_toggle_maximize,
]);
Expand Down
2 changes: 2 additions & 0 deletions examples/api/src-tauri/capabilities/run-app.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"core:default",
"core:app:allow-app-hide",
"core:app:allow-app-show",
"core:app:allow-set-app-theme",
"core:window:allow-set-theme",
"core:window:allow-center",
"core:window:allow-request-user-attention",
"core:window:allow-set-resizable",
Expand Down
Loading

0 comments on commit 11db7be

Please sign in to comment.