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(macos): title_bar_style and hidden_title window options, closes #2663 #3965

Merged
merged 10 commits into from
Sep 30, 2022
6 changes: 6 additions & 0 deletions .changes/hidden-title-macos.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'tauri': minor
"tauri-runtime-wry": minor
---

Add `hidden_title` option for macOS windows.
6 changes: 6 additions & 0 deletions .changes/transparent-titlebar-macos.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'tauri': minor
"tauri-runtime-wry": minor
---

Add `title_bar_style` option for macOS windows.
39 changes: 35 additions & 4 deletions core/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ use wry::application::platform::unix::{WindowBuilderExtUnix, WindowExtUnix};
#[cfg(windows)]
use wry::application::platform::windows::{WindowBuilderExtWindows, WindowExtWindows};

#[cfg(target_os = "macos")]
use tauri_utils::TitleBarStyle;
use tauri_utils::{config::WindowConfig, debug_eprintln, Theme};
use uuid::Uuid;
use wry::{
Expand Down Expand Up @@ -739,6 +741,13 @@ impl WindowBuilder for WindowBuilderWrapper {
.skip_taskbar(config.skip_taskbar)
.theme(config.theme);

#[cfg(target_os = "macos")]
{
window = window
.hidden_title(config.hidden_title)
.title_bar_style(config.title_bar_style);
}

#[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
{
window = window.transparent(config.transparent);
Expand Down Expand Up @@ -879,6 +888,32 @@ impl WindowBuilder for WindowBuilderWrapper {
self
}

#[cfg(target_os = "macos")]
fn title_bar_style(mut self, style: TitleBarStyle) -> Self {
match style {
TitleBarStyle::Visible => {
self.inner = self.inner.with_titlebar_transparent(false);
// Fixes rendering issue when resizing window with devtools open (https://github.com/tauri-apps/tauri/issues/3914)
self.inner = self.inner.with_fullsize_content_view(true);
}
TitleBarStyle::Transparent => {
self.inner = self.inner.with_titlebar_transparent(true);
self.inner = self.inner.with_fullsize_content_view(false);
}
TitleBarStyle::Overlay => {
self.inner = self.inner.with_titlebar_transparent(true);
self.inner = self.inner.with_fullsize_content_view(true);
}
}
self
}

#[cfg(target_os = "macos")]
fn hidden_title(mut self, hidden: bool) -> Self {
self.inner = self.inner.with_title_hidden(hidden);
self
}

fn icon(mut self, icon: Icon) -> Result<Self> {
self.inner = self
.inner
Expand Down Expand Up @@ -2870,10 +2905,6 @@ fn create_webview<T: UserEvent>(

let window_event_listeners = WindowEventListeners::default();

#[cfg(target_os = "macos")]
{
window_builder.inner = window_builder.inner.with_fullsize_content_view(true);
}
#[cfg(windows)]
{
window_builder.inner = window_builder
Expand Down
12 changes: 12 additions & 0 deletions core/tauri-runtime/src/webview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

use crate::{menu::Menu, window::DetachedWindow, Icon};

#[cfg(target_os = "macos")]
use tauri_utils::TitleBarStyle;
use tauri_utils::{
config::{WindowConfig, WindowUrl},
Theme,
Expand Down Expand Up @@ -189,6 +191,16 @@ pub trait WindowBuilder: WindowBuilderBase {
#[must_use]
fn owner_window(self, owner: HWND) -> Self;

/// Hide the titlebar. Titlebar buttons will still be visible.
#[cfg(target_os = "macos")]
#[must_use]
fn title_bar_style(self, style: TitleBarStyle) -> Self;

/// Hide the window title.
#[cfg(target_os = "macos")]
#[must_use]
fn hidden_title(self, hidden: bool) -> Self;

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

Expand Down
28 changes: 27 additions & 1 deletion core/tauri-utils/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ use std::{
/// Items to help with parsing content into a [`Config`].
pub mod parse;

use crate::TitleBarStyle;

pub use self::parse::parse;

/// An URL to open on a Tauri webview window.
Expand Down Expand Up @@ -859,6 +861,12 @@ pub struct WindowConfig {
pub skip_taskbar: bool,
/// The initial window theme. Defaults to the system theme. Only implemented on Windows and macOS 10.14+.
pub theme: Option<crate::Theme>,
/// The style of the macOS title bar.
#[serde(default, alias = "title-bar-style")]
pub title_bar_style: TitleBarStyle,
/// If `true`, sets the window title to be hidden on macOS.
#[serde(default, alias = "hidden-title")]
pub hidden_title: bool,
}

impl Default for WindowConfig {
Expand Down Expand Up @@ -887,6 +895,8 @@ impl Default for WindowConfig {
always_on_top: false,
skip_taskbar: false,
theme: None,
title_bar_style: Default::default(),
hidden_title: false,
}
}
}
Expand Down Expand Up @@ -2932,6 +2942,18 @@ mod build {
}
}

impl ToTokens for crate::TitleBarStyle {
fn to_tokens(&self, tokens: &mut TokenStream) {
let prefix = quote! { ::tauri::utils::TitleBarStyle };

tokens.append_all(match self {
Self::Visible => quote! { #prefix::Visible },
Self::Transparent => quote! { #prefix::Transparent },
Self::Overlay => quote! { #prefix::Overlay },
})
}
}

impl ToTokens for WindowConfig {
fn to_tokens(&self, tokens: &mut TokenStream) {
let label = str_lit(&self.label);
Expand All @@ -2957,6 +2979,8 @@ mod build {
let always_on_top = self.always_on_top;
let skip_taskbar = self.skip_taskbar;
let theme = opt_lit(self.theme.as_ref());
let title_bar_style = &self.title_bar_style;
let hidden_title = self.hidden_title;

literal_struct!(
tokens,
Expand All @@ -2983,7 +3007,9 @@ mod build {
decorations,
always_on_top,
skip_taskbar,
theme
theme,
title_bar_style,
hidden_title
);
}
}
Expand Down
62 changes: 62 additions & 0 deletions core/tauri-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,68 @@ impl PackageInfo {
}
}

/// How the window title bar should be displayed.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub enum TitleBarStyle {
/// A normal title bar.
Visible,
/// Makes the title bar transparent, so the window background color is shown instead.
///
/// Useful if you don't need to have actual HTML under the title bar. This lets you avoid the caveats of using `TitleBarStyle::Overlay`. Will be more useful when Tauri lets you set a custom window background color.
Transparent,
/// Shows the title bar as a transparent overlay over the window's content.
///
/// Keep in mind:
/// - The height of the title bar is different on different OS versions, which can lead to window the controls and title not being where you don't expect.
/// - You need to define a custom drag region to make your window draggable, however due to a limitation you can't drag the window when it's not in focus (https://github.com/tauri-apps/tauri/issues/4316).
/// - The color of the window title depends on the system theme.
Overlay,
}

impl Default for TitleBarStyle {
fn default() -> Self {
Self::Visible
}
}

impl Serialize for TitleBarStyle {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.to_string().as_ref())
}
}

impl<'de> Deserialize<'de> for TitleBarStyle {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(match s.to_lowercase().as_str() {
"transparent" => Self::Transparent,
"overlay" => Self::Overlay,
_ => Self::Visible,
})
}
}

impl Display for TitleBarStyle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::Visible => "Visible",
Self::Transparent => "Transparent",
Self::Overlay => "Overlay",
}
)
}
}

/// System theme.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
Expand Down
2 changes: 2 additions & 0 deletions core/tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ pub use runtime::http;
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
pub use runtime::{menu::NativeImage, ActivationPolicy};

#[cfg(target_os = "macos")]
pub use self::utils::TitleBarStyle;
#[cfg(all(desktop, feature = "system-tray"))]
#[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))]
pub use {
Expand Down
12 changes: 12 additions & 0 deletions core/tauri/src/test/mock_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ use tauri_runtime::{
menu::{SystemTrayMenu, TrayHandle},
SystemTray, SystemTrayEvent, TrayId,
};
#[cfg(target_os = "macos")]
use tauri_utils::TitleBarStyle;
use tauri_utils::{config::WindowConfig, Theme};
use uuid::Uuid;

Expand Down Expand Up @@ -259,6 +261,16 @@ impl WindowBuilder for MockWindowBuilder {
self
}

#[cfg(target_os = "macos")]
fn title_bar_style(self, style: TitleBarStyle) -> Self {
self
}

#[cfg(target_os = "macos")]
fn hidden_title(self, transparent: bool) -> Self {
self
}

fn theme(self, theme: Option<Theme>) -> Self {
self
}
Expand Down
18 changes: 18 additions & 0 deletions core/tauri/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub(crate) mod menu;

pub use menu::{MenuEvent, MenuHandle};

#[cfg(target_os = "macos")]
use crate::TitleBarStyle;
use crate::{
app::AppHandle,
command::{CommandArg, CommandItem},
Expand Down Expand Up @@ -433,6 +435,22 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
self
}

/// Sets the [`TitleBarStyle`].
#[cfg(target_os = "macos")]
#[must_use]
pub fn title_bar_style(mut self, style: TitleBarStyle) -> Self {
self.window_builder = self.window_builder.title_bar_style(style);
self
}

/// Hide the window title.
#[cfg(target_os = "macos")]
#[must_use]
pub fn hidden_title(mut self, hidden: bool) -> Self {
self.window_builder = self.window_builder.hidden_title(hidden);
self
}

// ------------------------------------------- Webview attributes -------------------------------------------

/// Adds the provided JavaScript to a list of scripts that should be run after the global object has been created,
Expand Down
9 changes: 9 additions & 0 deletions tooling/api/src/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import { emit, Event, listen, once } from './helpers/event'
import { TauriEvent } from './event'

type Theme = 'light' | 'dark'
type TitleBarStyle = 'visible' | 'transparent' | 'overlay'

/**
* Allows you to retrieve information about a given monitor.
Expand Down Expand Up @@ -2033,6 +2034,14 @@ interface WindowOptions {
* Only implemented on Windows and macOS 10.14+.
*/
theme?: Theme
/**
* The style of the macOS title bar.
*/
titleBarStyle?: TitleBarStyle
/**
* If `true`, sets the window title to be hidden on macOS.
*/
hiddenTitle?: boolean
}

/**
Expand Down
23 changes: 23 additions & 0 deletions tooling/cli/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,20 @@
"type": "null"
}
]
},
"titleBarStyle": {
"description": "The style of the macOS title bar.",
"default": "Visible",
"allOf": [
{
"$ref": "#/definitions/TitleBarStyle"
}
]
},
"hiddenTitle": {
"description": "Sets the window title to be hidden on macOS.",
"default": false,
"type": "boolean"
}
},
"additionalProperties": false
Expand All @@ -665,6 +679,15 @@
"Dark"
]
},
"TitleBarStyle": {
"description": "How the window title bar should be displayed.",
"type": "string",
"enum": [
"Visible",
"Transparent",
"Overlay"
]
},
"CliConfig": {
"description": "describes a CLI configuration",
"type": "object",
Expand Down