Skip to content

Commit 11db7be

Browse files
feat(core): add a new function to set theme dynamically (#10210)
closes #5279
1 parent 8d22c0c commit 11db7be

File tree

21 files changed

+281
-8
lines changed

21 files changed

+281
-8
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/tauri-runtime-wry/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ wry = { version = "0.44.0", default-features = false, features = [
2323
"os-webview",
2424
"linux-body",
2525
] }
26-
tao = { version = "0.30", default-features = false, features = ["rwh_06"] }
26+
tao = { version = "0.30.2", default-features = false, features = ["rwh_06"] }
2727
tauri-runtime = { version = "2.0.0-rc.12", path = "../tauri-runtime" }
2828
tauri-utils = { version = "2.0.0-rc.12", path = "../tauri-utils" }
2929
raw-window-handle = "0.6"

crates/tauri-runtime-wry/src/lib.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,6 +1204,7 @@ pub enum WindowMessage {
12041204
SetIgnoreCursorEvents(bool),
12051205
SetProgressBar(ProgressBarState),
12061206
SetTitleBarStyle(tauri_utils::TitleBarStyle),
1207+
SetTheme(Option<Theme>),
12071208
DragWindow,
12081209
ResizeDragWindow(tauri_runtime::ResizeDirection),
12091210
RequestRedraw,
@@ -2026,6 +2027,13 @@ impl<T: UserEvent> WindowDispatch<T> for WryWindowDispatcher<T> {
20262027
Message::Window(self.window_id, WindowMessage::SetTitleBarStyle(style)),
20272028
)
20282029
}
2030+
2031+
fn set_theme(&self, theme: Option<Theme>) -> Result<()> {
2032+
send_user_message(
2033+
&self.context,
2034+
Message::Window(self.window_id, WindowMessage::SetTheme(theme)),
2035+
)
2036+
}
20292037
}
20302038

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

2297+
fn set_theme(&self, theme: Option<Theme>) {
2298+
self
2299+
.context
2300+
.main_thread
2301+
.window_target
2302+
.set_theme(match theme {
2303+
Some(Theme::Light) => Some(TaoTheme::Light),
2304+
Some(Theme::Dark) => Some(TaoTheme::Dark),
2305+
_ => None,
2306+
});
2307+
}
2308+
22892309
#[cfg(target_os = "macos")]
22902310
fn show(&self) -> tauri_runtime::Result<()> {
22912311
send_user_message(
@@ -2564,6 +2584,14 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
25642584
.map_err(|_| Error::FailedToGetCursorPosition)
25652585
}
25662586

2587+
fn set_theme(&self, theme: Option<Theme>) {
2588+
self.event_loop.set_theme(match theme {
2589+
Some(Theme::Light) => Some(TaoTheme::Light),
2590+
Some(Theme::Dark) => Some(TaoTheme::Dark),
2591+
_ => None,
2592+
});
2593+
}
2594+
25672595
#[cfg(target_os = "macos")]
25682596
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
25692597
self
@@ -2996,6 +3024,13 @@ fn handle_user_message<T: UserEvent>(
29963024
}
29973025
};
29983026
}
3027+
WindowMessage::SetTheme(theme) => {
3028+
window.set_theme(match theme {
3029+
Some(Theme::Light) => Some(TaoTheme::Light),
3030+
Some(Theme::Dark) => Some(TaoTheme::Dark),
3031+
_ => None,
3032+
});
3033+
}
29993034
}
30003035
}
30013036
}

crates/tauri-runtime/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ pub trait RuntimeHandle<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'st
311311

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

314+
fn set_theme(&self, theme: Option<Theme>);
315+
314316
/// Shows the application, but does not automatically focus it.
315317
#[cfg(target_os = "macos")]
316318
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
@@ -402,6 +404,8 @@ pub trait Runtime<T: UserEvent>: Debug + Sized + 'static {
402404

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

407+
fn set_theme(&self, theme: Option<Theme>);
408+
405409
/// Sets the activation policy for the application.
406410
#[cfg(target_os = "macos")]
407411
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
@@ -802,4 +806,12 @@ pub trait WindowDispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 's
802806
///
803807
/// - **Linux / Windows / iOS / Android:** Unsupported.
804808
fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> Result<()>;
809+
810+
/// Sets the theme for this window.
811+
///
812+
/// ## Platform-specific
813+
///
814+
/// - **Linux / macOS**: Theme is app-wide and not specific to this window.
815+
/// - **iOS / Android:** Unsupported.
816+
fn set_theme(&self, theme: Option<Theme>) -> Result<()>;
805817
}

crates/tauri/build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
105105
("set_progress_bar", false),
106106
("set_icon", false),
107107
("set_title_bar_style", false),
108+
("set_theme", false),
108109
("toggle_maximize", false),
109110
// internal
110111
("internal_toggle_maximize", true),
@@ -141,6 +142,7 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
141142
("app_show", false),
142143
("app_hide", false),
143144
("default_window_icon", false),
145+
("set_app_theme", false),
144146
],
145147
),
146148
(

crates/tauri/permissions/app/autogenerated/reference.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,32 @@ Denies the name command without any pre-configured scope.
122122
<tr>
123123
<td>
124124

125+
`core:app:allow-set-app-theme`
126+
127+
</td>
128+
<td>
129+
130+
Enables the set_app_theme command without any pre-configured scope.
131+
132+
</td>
133+
</tr>
134+
135+
<tr>
136+
<td>
137+
138+
`core:app:deny-set-app-theme`
139+
140+
</td>
141+
<td>
142+
143+
Denies the set_app_theme command without any pre-configured scope.
144+
145+
</td>
146+
</tr>
147+
148+
<tr>
149+
<td>
150+
125151
`core:app:allow-tauri-version`
126152

127153
</td>

crates/tauri/permissions/window/autogenerated/reference.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,32 @@ Denies the set_skip_taskbar command without any pre-configured scope.
14691469
<tr>
14701470
<td>
14711471

1472+
`core:window:allow-set-theme`
1473+
1474+
</td>
1475+
<td>
1476+
1477+
Enables the set_theme command without any pre-configured scope.
1478+
1479+
</td>
1480+
</tr>
1481+
1482+
<tr>
1483+
<td>
1484+
1485+
`core:window:deny-set-theme`
1486+
1487+
</td>
1488+
<td>
1489+
1490+
Denies the set_theme command without any pre-configured scope.
1491+
1492+
</td>
1493+
</tr>
1494+
1495+
<tr>
1496+
<td>
1497+
14721498
`core:window:allow-set-title`
14731499

14741500
</td>

crates/tauri/scripts/bundle.global.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/tauri/src/app.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,31 @@ macro_rules! shared_app_impl {
685685
})
686686
}
687687

688+
/// Set the app theme.
689+
pub fn set_theme(&self, theme: Option<Theme>) {
690+
#[cfg(windows)]
691+
for window in self.manager.windows().values() {
692+
if let (Some(menu), Ok(hwnd)) = (window.menu(), window.hwnd()) {
693+
let raw_hwnd = hwnd.0 as isize;
694+
let _ = self.run_on_main_thread(move || {
695+
let _ = unsafe {
696+
menu.inner().set_theme_for_hwnd(
697+
raw_hwnd,
698+
theme
699+
.map(crate::menu::map_to_menu_theme)
700+
.unwrap_or(muda::MenuTheme::Auto),
701+
)
702+
};
703+
});
704+
};
705+
}
706+
match self.runtime() {
707+
RuntimeOrDispatch::Runtime(h) => h.set_theme(theme),
708+
RuntimeOrDispatch::RuntimeHandle(h) => h.set_theme(theme),
709+
_ => unreachable!(),
710+
}
711+
}
712+
688713
/// Returns the default window icon.
689714
pub fn default_window_icon(&self) -> Option<&Image<'_>> {
690715
self.manager.window.default_icon.as_ref()

crates/tauri/src/app/plugin.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// SPDX-License-Identifier: Apache-2.0
33
// SPDX-License-Identifier: MIT
44

5+
use tauri_utils::Theme;
6+
57
use crate::{
68
command,
79
plugin::{Builder, TauriPlugin},
@@ -50,6 +52,11 @@ pub fn default_window_icon<R: Runtime>(
5052
})
5153
}
5254

55+
#[command(root = "crate")]
56+
pub async fn set_app_theme<R: Runtime>(app: AppHandle<R>, theme: Option<Theme>) {
57+
app.set_theme(theme);
58+
}
59+
5360
pub fn init<R: Runtime>() -> TauriPlugin<R> {
5461
Builder::new("app")
5562
.invoke_handler(crate::generate_handler![
@@ -59,6 +66,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
5966
app_show,
6067
app_hide,
6168
default_window_icon,
69+
set_app_theme,
6270
])
6371
.build()
6472
}

0 commit comments

Comments
 (0)