fix(gui-client): use Wayland rendering backend on Linux (#10849)

Previously, we opted into the X11 GTK backend when rendering the GUI
Client's window. This is causing issues on newer Linux distributions
such as Fedora 43 where Wayland is now the only available compositor.

Removing the X11 GTK requires us to draw our own CSDs such as titlebars
and a close button. This PR does exactly that by adding a minimalistic
title bar. To make better use of the space, we move the section headers
into there.

|Before|After|
|---|---|
|<img width="1900" height="1174" alt="Screenshot From 2025-11-11
11-14-11"
src="https://github.com/user-attachments/assets/9439a69b-65ba-41d6-b1f8-4448e0f80728"
/>|<img width="1800" height="1000" alt="Screenshot From 2025-11-11
11-40-55"
src="https://github.com/user-attachments/assets/7884b2cc-3d9c-4b47-9a1e-c6462aef36ab"
/>|
|<img width="1900" height="1174" alt="Screenshot From 2025-11-11
11-14-16"
src="https://github.com/user-attachments/assets/2cfea825-5c08-45a5-873c-5afcbc1dbf16"
/>|<img width="1800" height="1000" alt="Screenshot From 2025-11-11
11-40-58"
src="https://github.com/user-attachments/assets/43ddd7c9-ce65-42f7-b972-28c6b172b70d"
/>|
|<img width="1900" height="1174" alt="Screenshot From 2025-11-11
11-14-19"
src="https://github.com/user-attachments/assets/446873a7-9023-4266-9377-ea7b8b4353ee"
/>|<img width="1800" height="1000" alt="Screenshot From 2025-11-11
11-41-01"
src="https://github.com/user-attachments/assets/64439383-f33f-461d-9b4a-6b4138bd675b"
/>|
|<img width="1900" height="1174" alt="Screenshot From 2025-11-11
11-14-22"
src="https://github.com/user-attachments/assets/6c39e06c-1d77-471f-91f1-32a78b90a21c"
/>|<img width="1800" height="1000" alt="Screenshot From 2025-11-11
11-41-04"
src="https://github.com/user-attachments/assets/b56912cb-9c85-4b5a-9295-dae6139b25c6"
/>|
|<img width="1900" height="1174" alt="Screenshot From 2025-11-11
11-14-26"
src="https://github.com/user-attachments/assets/5a5d638c-15bf-4523-8466-2e0977a03e22"
/>|<img width="1800" height="1000" alt="Screenshot From 2025-11-11
11-41-06"
src="https://github.com/user-attachments/assets/ed169b52-ef86-4dc4-8f25-852da622eaa1"
/>|
This commit is contained in:
Thomas Eizinger
2025-11-11 16:51:08 +11:00
committed by GitHub
parent 0008539b65
commit 3e849ae852
10 changed files with 166 additions and 102 deletions

View File

@@ -45,10 +45,6 @@ export default function AdvancedSettingsPage({
return (
<div className="container p-4">
<div className="pb-2">
<h2 className="text-xl font-semibold">Advanced Settings</h2>
</div>
<p className="text-neutral-900 mb-6">
<strong>WARNING</strong>: These settings are intended for internal debug
purposes <strong>only</strong>. Changing these is not supported and will

View File

@@ -30,6 +30,7 @@ import {
GeneralSettingsViewModel,
SessionViewModel,
} from "../generated/bindings";
import Titlebar from "./Titlebar";
export default function App() {
const [session, setSession] = useState<SessionViewModel | null>(null);
@@ -83,92 +84,120 @@ export default function App() {
const isDev = import.meta.env.DEV;
return (
<div className="h-screen bg-neutral-50 flex flex-row">
<Sidebar
aria-label="Sidebar"
className="w-52 flex-shrink-0 border-r border-neutral-200"
>
<SidebarItems>
<SidebarItemGroup>
<ReactRouterSidebarItem icon={HomeIcon} href="/overview">
Overview
</ReactRouterSidebarItem>
<SidebarCollapse label="Settings" open={true} icon={Bars3Icon}>
<ReactRouterSidebarItem icon={CogIcon} href="/general-settings">
General
<div className="h-screen flex flex-col rounded-lg border border-neutral-300 overflow-hidden">
<Routes>
<Route path="/overview" element={<Titlebar title={"Firezone"} />} />
<Route
path="/general-settings"
element={<Titlebar title={"General Settings"} />}
/>
<Route
path="/advanced-settings"
element={<Titlebar title={"Advanced Settings"} />}
/>
<Route
path="/diagnostics"
element={<Titlebar title={"Diagnostics"} />}
/>
<Route path="/about" element={<Titlebar title={"About"} />} />
<Route
path="/colour-palette"
element={<Titlebar title={"Colour Palette"} />}
/>
</Routes>
<div className="flex-1 bg-neutral-50 flex flex-row">
<Sidebar
aria-label="Sidebar"
className="w-52 flex-shrink-0 border-r border-neutral-200"
>
<SidebarItems>
<SidebarItemGroup>
<ReactRouterSidebarItem icon={HomeIcon} href="/overview">
Overview
</ReactRouterSidebarItem>
<SidebarCollapse label="Settings" open={true} icon={Bars3Icon}>
<ReactRouterSidebarItem icon={CogIcon} href="/general-settings">
General
</ReactRouterSidebarItem>
<ReactRouterSidebarItem
icon={WrenchScrewdriverIcon}
href="/advanced-settings"
>
Advanced
</ReactRouterSidebarItem>
</SidebarCollapse>
<ReactRouterSidebarItem
icon={DocumentMagnifyingGlassIcon}
href="/diagnostics"
>
Diagnostics
</ReactRouterSidebarItem>
<ReactRouterSidebarItem
icon={WrenchScrewdriverIcon}
href="/advanced-settings"
icon={InformationCircleIcon}
href="/about"
>
Advanced
</ReactRouterSidebarItem>
</SidebarCollapse>
<ReactRouterSidebarItem
icon={DocumentMagnifyingGlassIcon}
href="/diagnostics"
>
Diagnostics
</ReactRouterSidebarItem>
<ReactRouterSidebarItem icon={InformationCircleIcon} href="/about">
About
</ReactRouterSidebarItem>
</SidebarItemGroup>
{isDev && (
<SidebarItemGroup>
<ReactRouterSidebarItem icon={SwatchIcon} href="/colour-palette">
Color Palette
About
</ReactRouterSidebarItem>
</SidebarItemGroup>
)}
</SidebarItems>
</Sidebar>
<main className="flex-grow overflow-auto">
<Routes>
<Route
path="/overview"
element={
<Overview
session={session}
signIn={commands.signIn}
signOut={commands.signOut}
/>
}
/>
<Route
path="/general-settings"
element={
<GeneralSettingsPage
settings={generalSettings}
saveSettings={commands.applyGeneralSettings}
resetSettings={commands.resetGeneralSettings}
/>
}
/>
<Route
path="/advanced-settings"
element={
<AdvancedSettingsPage
settings={advancedSettings}
saveSettings={commands.applyAdvancedSettings}
resetSettings={commands.resetAdvancedSettings}
/>
}
/>
<Route
path="/diagnostics"
element={
<Diagnostics
logCount={logCount}
exportLogs={commands.exportLogs}
clearLogs={commands.clearLogs}
/>
}
/>
<Route path="/about" element={<About />} />
<Route path="/colour-palette" element={<ColorPalette />} />
</Routes>
</main>
{isDev && (
<SidebarItemGroup>
<ReactRouterSidebarItem
icon={SwatchIcon}
href="/colour-palette"
>
Color Palette
</ReactRouterSidebarItem>
</SidebarItemGroup>
)}
</SidebarItems>
</Sidebar>
<main className="flex-grow overflow-auto">
<Routes>
<Route
path="/overview"
element={
<Overview
session={session}
signIn={commands.signIn}
signOut={commands.signOut}
/>
}
/>
<Route
path="/general-settings"
element={
<GeneralSettingsPage
settings={generalSettings}
saveSettings={commands.applyGeneralSettings}
resetSettings={commands.resetGeneralSettings}
/>
}
/>
<Route
path="/advanced-settings"
element={
<AdvancedSettingsPage
settings={advancedSettings}
saveSettings={commands.applyAdvancedSettings}
resetSettings={commands.resetAdvancedSettings}
/>
}
/>
<Route
path="/diagnostics"
element={
<Diagnostics
logCount={logCount}
exportLogs={commands.exportLogs}
clearLogs={commands.clearLogs}
/>
}
/>
<Route path="/about" element={<About />} />
<Route path="/colour-palette" element={<ColorPalette />} />
</Routes>
</main>
</div>
</div>
);
}

View File

@@ -21,10 +21,6 @@ export default function Diagnostics({
return (
<div className="container mx-auto p-4">
<div className="mb-4 pb-2">
<h2 className="text-xl font-semibold mb-4">Diagnostic Logs</h2>
</div>
<div className="p-4 rounded-lg">
<div className="mt-8 flex justify-center">
<p className="mr-1">Log directory size:</p>

View File

@@ -43,13 +43,8 @@ export default function GeneralSettingsPage({
const startMinimizedInputId = useId();
const startOnLoginInputId = useId();
const connectOnStartInputId = useId();
return (
<div className="container p-4">
<div className="pb-2">
<h2 className="text-xl font-semibold">General settings</h2>
</div>
<form
onSubmit={(e) => {
e.preventDefault();

View File

@@ -11,7 +11,7 @@ interface OverviewPageProps {
export default function Overview(props: OverviewPageProps) {
return (
<div className="flex flex-col items-center justify-center gap-4 min-h-screen">
<div className="flex flex-col items-center justify-center gap-4">
<img src={logo} alt="Firezone Logo" className="w-40 h-40" />
<h1 className="text-6xl font-bold">Firezone</h1>

View File

@@ -0,0 +1,45 @@
import { XMarkIcon } from "@heroicons/react/16/solid";
import { getCurrentWindow } from "@tauri-apps/api/window";
import { Navbar } from "flowbite-react";
import React from "react";
export interface TitlebarProps {
title?: string;
}
export default function Titlebar({ title }: TitlebarProps) {
const handleMouseDown = (e: React.MouseEvent) => {
if (e.buttons === 1) {
getCurrentWindow().startDragging();
}
};
return (
<div onMouseDown={handleMouseDown} className="select-none">
<Navbar
clearTheme={{
root: {
base: true,
},
}}
theme={{
root: {
base: "py-1 px-2 bg-gray-100 flex flex-row space-between",
inner: {
base: "max-w-full",
},
},
}}
>
<h2 className="text-xl font-semibold">{title}</h2>
<div
className="justify-self-end"
onMouseDown={(e) => e.stopPropagation()}
onClick={() => getCurrentWindow().close()}
>
<XMarkIcon className="h-6 p-1 rounded-full hover:text-gray-700 hover:bg-gray-200" />
</div>
</Navbar>
</div>
);
}

View File

@@ -7,6 +7,8 @@
"core:path:default",
"core:event:default",
"core:window:default",
"core:window:allow-start-dragging",
"core:window:allow-close",
"core:app:default",
"core:resources:default",
"core:menu:default",

View File

@@ -20,12 +20,6 @@ fn main() -> ExitCode {
let mut bootstrap_log_guard =
Some(firezone_logging::setup_bootstrap().expect("Failed to setup bootstrap logger"));
// Mitigates a bug in Ubuntu 22.04 - Under Wayland, some features of the window decorations like minimizing, closing the windows, etc., doesn't work unless you double-click the titlebar first.
// SAFETY: No other thread is running yet
unsafe {
std::env::set_var("GDK_BACKEND", "x11");
}
let cli = Cli::parse();
let mut telemetry = if cli.is_telemetry_allowed() {

View File

@@ -64,6 +64,7 @@
},
"windows": [
{
"decorations": false,
"label": "main",
"title": "Firezone",
"url": "index.html",
@@ -71,7 +72,8 @@
"resizable": false,
"width": 900,
"height": 500,
"visible": false
"visible": false,
"transparent": true
}
]
}

View File

@@ -21,6 +21,11 @@ export default function GUI({ os }: { os: OS }) {
Fixes an issue where the order of upstream / system DNS resolvers was
not respected.
</ChangeItem>
{os == OS.Linux && (
<ChangeItem pull="10849">
Fixes some rendering issues on Wayland-only systems.
</ChangeItem>
)}
</Unreleased>
<Entry version="1.5.8" date={new Date("2025-10-16")}>
<ChangeItem pull="10509">