Overall Architecture | vasak-desktop

Overview of the Vasak Desktop architecture and how its components are laid out.

What is Vasak Desktop?#

Vasak Desktop is NOT a full desktop environment (like GNOME or KDE). It is a lightweight desktop interface that has no WM of its own but that provides:

  • Top Panel - Taskbar with system applets
  • Desktop View - Wallpaper with optional widgets
  • Control Center - Quick access to settings
  • Application Menu - Search and launch apps
  • File Manager - Tool for browsing files
  • Search Launcher - Fast search tool
  • Config Manager - Tool for configuring the operating system

It runs as several independent Tauri windows that talk to each other over IPC.

The rest of the VasakOS tools that do not share the desktop backend follow a similar architecture and can be integrated the same way with the desktop settings.

High-level Architecture#

graph TD User["πŸ‘€ END USER"] Panel["πŸͺŸ PANEL Window
(Top Bar)"] Desktop["πŸ–₯️ DESKTOP Window
(Background)"] Frontend["🎨 Vue.js Frontend
(TypeScript + CSS)"] IPC["πŸ”— Tauri IPC Bridge
(Frontend ↔ Backend)"] Backend["βš™οΈ Rust Backend
- System commands
- D-Bus integration
- Window management"] DBus["πŸ”Œ D-Bus
(IPC)"] GTK["🎭 GTK
(Theme)"] System["πŸ“ System
(FS/IO)"] Services["πŸ”§ System Services
(PulseAudio, NetworkManager,
BlueZ, MPRIS, gsettings...)"] User --> Panel User --> Desktop Panel --> Frontend Desktop --> Frontend Frontend --> IPC IPC --> Backend Backend --> DBus Backend --> GTK Backend --> System DBus --> Services style User fill:#e1f5ff style Panel fill:#fff3e0 style Desktop fill:#fff3e0 style Frontend fill:#f3e5f5 style IPC fill:#ffe0b2 style Backend fill:#c8e6c9 style DBus fill:#ffccbc style GTK fill:#ffccbc style System fill:#ffccbc style Services fill:#b3e5fc

Application Windows#

Vasak Desktop is made up of 2 independent windows:

Window 1: Panel (Top Bar)#

1
2
3
4
5
6
7
8
9
{
  "label": "panel",
  "title": "Vasak Panel",
  "width": [screen width],
  "height": 40,
  "y": 0,
  "decorations": false,
  "alwaysOnTop": true
}

It shows:

  • Application menu
  • Widgets (clock, music)
  • System applets (audio, network, bluetooth, battery)
  • Control center

Window 2: Desktop (Background)#

1
2
3
4
5
6
7
8
{
  "label": "desktop",
  "title": "Vasak Desktop",
  "fullscreen": true,
  "decorations": false,
  "alwaysOnBottom": true,
  "skipTaskbar": true
}

It shows:

  • Desktop wallpaper
  • Optional widgets (weather, clock)

Application Layers#

1. Presentation Layer (Frontend)#

Technology: Vue.js 3.5.18, TypeScript, Tailwind CSS 4.1

graph LR Frontend["🎨 Vue.js Frontend
src/"] Frontend --> App["πŸ“„ App.vue
Root component"] Frontend --> Main["πŸ“„ main.ts
Entry point"] Frontend --> Style["πŸ“„ style.css
Global styles"] Frontend --> Views["πŸ“ views/
Main pages"] Frontend --> Components["πŸ“ components/
Reusable components"] Frontend --> Routes["πŸ“ routes/
Route configuration"] Frontend --> Tools["πŸ“ tools/
Controllers"] Views --> ViewPanel["πŸ“„ PanelView.vue
Top panel window"] Views --> ViewDesktop["πŸ“„ DesktopView.vue
Desktop background window"] Views --> ViewMenu["πŸ“„ MenuView.vue
App menu view"] Views --> ViewCC["πŸ“„ ControlCenterView.vue
Control center"] Components --> CompBtns["πŸ“ buttons/
Interface buttons"] Components --> CompCards["πŸ“ cards/
Information cards"] Components --> CompCtrl["πŸ“ controls/
Interactive controls"] Components --> CompAreas["πŸ“ areas/
Full areas"] CompAreas --> AreaPanel["πŸ“ panel/"] CompAreas --> AreaCC["πŸ“ control-center/"] CompAreas --> AreaMenu["πŸ“ menu/"] Tools --> ToolBat["πŸ“„ battery.controller.ts"] Tools --> ToolNet["πŸ“„ network.controller.ts"] Tools --> ToolBT["πŸ“„ bluetooth.controller.ts"] Tools --> ToolTray["πŸ“„ tray.controller.ts"] Routes --> RouteIdx["πŸ“„ index.ts"] style Frontend fill:#667eea,stroke:#764ba2,color:#fff style App fill:#f3e5f5,stroke:#ce93d8,color:#000 style Views fill:#4facfe,stroke:#00f2fe,color:#fff style Components fill:#43e97b,stroke:#38f9d7,color:#fff style Routes fill:#feca57,stroke:#ff9a56,color:#fff style Tools fill:#fa709a,stroke:#f5576c,color:#fff style ViewPanel fill:#f3e5f5,stroke:#ce93d8,color:#000 style ViewDesktop fill:#f3e5f5,stroke:#ce93d8,color:#000 style ViewMenu fill:#f3e5f5,stroke:#ce93d8,color:#000 style ViewCC fill:#f3e5f5,stroke:#ce93d8,color:#000

Data flow:

  • Components β†’ invoke('command') β†’ Backend
  • Backend β†’ emit('event') β†’ Components update

2. Communication Layer (IPC)#

Technology: Tauri IPC Bridge

sequenceDiagram participant VueComp as Vue
Component participant Invoke as invoke() participant IPCBridge as IPC Bridge participant BackendCmd as Backend
Command participant DBusService as D-Bus /
System Call participant Result as Result VueComp->>Invoke: invoke('get_audio_volume') activate Invoke Invoke->>IPCBridge: sends the serialized command deactivate Invoke activate IPCBridge IPCBridge->>BackendCmd: #64 (Backend Handler) deactivate IPCBridge activate BackendCmd BackendCmd->>DBusService: D-Bus query / system call deactivate BackendCmd activate DBusService DBusService->>Result: gets the value (e.g. 50%) deactivate DBusService activate Result Result->>IPCBridge: returns the response deactivate Result activate IPCBridge IPCBridge->>VueComp: resolves the Promise with the result deactivate IPCBridge activate VueComp VueComp->>VueComp: updates local state deactivate VueComp Note over VueComp,Result: Only explicitly registered commands can be invoked

Security: Only explicitly registered commands can be invoked.

3. Logic Layer (Backend)#

Technology: Rust 1.70+, Tauri 2.x

graph LR Backend["βš™οΈ Rust Backend
src-tauri/src/"] Backend --> Main["πŸ“„ main.rs
Entry point
window setup
"] Backend --> Lib["πŸ“„ lib.rs
Command and
module registration
"] Backend --> Structs["πŸ“„ structs.rs
Shared structures"] Backend --> Commands["πŸ“ commands/
IPC handlers"] Backend --> WindowMgr["πŸ“ window_manager/
Window management"] Backend --> MonitorMgr["πŸ“„ monitor_manager.rs
Monitor management"] Backend --> DBusService["πŸ“„ dbus_service.rs
D-Bus integration"] Backend --> Tray["πŸ“ tray/
System tray"] Backend --> Utils["πŸ“ utils/
Utility functions"] Commands --> AudioCmd["πŸ“„ audio.rs
Audio control"] Commands --> BluetoothCmd["πŸ“„ bluetooth.rs
Bluetooth control"] Commands --> NetworkCmd["πŸ“„ network.rs
Network control"] Commands --> BrightnessCmd["πŸ“„ brightness.rs
Brightness control"] Commands --> NotificationsCmd["πŸ“„ notifications.rs
Notification system"] Commands --> ShortcutsCmd["πŸ“„ shortcuts.rs
Shortcut management"] Commands --> SearchCmd["πŸ“„ search.rs
App search"] Commands --> SystemConfigCmd["πŸ“„ system_config.rs
OS configuration"] Commands --> ThemeCmd["πŸ“„ theme.rs
GTK themes, icons"] Commands --> SessionCmd["πŸ“„ session.rs
Logout, shutdown, suspend"] WindowMgr --> WinMod["πŸ“„ window_controller.rs"] Utils --> UtilShortcuts["πŸ“ shortcuts/"] Utils --> UtilSearch["πŸ“ search/"] style Backend fill:#667eea,stroke:#764ba2,color:#fff style Main fill:#4facfe,stroke:#00f2fe,color:#fff style Lib fill:#4facfe,stroke:#00f2fe,color:#fff style Structs fill:#4facfe,stroke:#00f2fe,color:#fff style Commands fill:#feca57,stroke:#ff9a56,color:#fff style WindowMgr fill:#43e97b,stroke:#38f9d7,color:#fff style MonitorMgr fill:#43e97b,stroke:#38f9d7,color:#fff style DBusService fill:#f093fb,stroke:#f5576c,color:#fff style Tray fill:#fa709a,stroke:#f5576c,color:#fff style Utils fill:#4facfe,stroke:#00f2fe,color:#fff style AudioCmd fill:#43e97b,stroke:#38f9d7,color:#fff style BluetoothCmd fill:#f093fb,stroke:#f5576c,color:#fff style NetworkCmd fill:#fa709a,stroke:#f5576c,color:#fff style BrightnessCmd fill:#feca57,stroke:#ff9a56,color:#fff style NotificationsCmd fill:#43e97b,stroke:#38f9d7,color:#fff style ShortcutsCmd fill:#feca57,stroke:#ff9a56,color:#fff style SearchCmd fill:#feca57,stroke:#ff9a56,color:#fff style SystemConfigCmd fill:#4facfe,stroke:#00f2fe,color:#fff style ThemeCmd fill:#feca57,stroke:#ff9a56,color:#fff style SessionCmd fill:#f093fb,stroke:#f5576c,color:#fff

Backend responsibilities:

  • Run system commands via shell or native APIs
  • Talk to system services over D-Bus
  • Handle hardware events and notifications
  • Apply system settings (gsettings, config files)
  • Manage the Tauri windows

4. System Integration Layer (D-Bus)#

Technology: Zbus (Rust) + D-Bus

The standard Linux interface for:

  • Audio control (PulseAudio/PipeWire)
  • Bluetooth (BlueZ)
  • Network (NetworkManager)
  • Notifications (Freedesktop)
  • Power (UPower)

See   D-Bus for more details.

5. Hardware/OS Layer#

System components:

  • PulseAudio / PipeWire (Audio)
  • BlueZ (Bluetooth)
  • NetworkManager (Network)
  • X11 / Wayland (Windows)
  • Compositor (Visual effects)

Current Wayland support is EXPERIMENTAL

Typical Data Flow#

Example: Changing the Volume#

sequenceDiagram participant User participant VueComponent as Vue Component participant PiniaStore as Pinia Store participant BackendHandler as Backend Handler participant IPCBridge as IPC Bridge participant BackendRust as Rust Backend participant SystemOS as OS System participant DBusEvent as D-Bus Event User->>VueComponent: Moves the volume slider activate VueComponent VueComponent->>PiniaStore: emit('volume-changed', newValue) activate PiniaStore PiniaStore->>PiniaStore: updates local state deactivate PiniaStore VueComponent->>BackendHandler: invoke('set_audio_volume', {level: 50}) deactivate VueComponent activate BackendHandler BackendHandler->>IPCBridge: sends the command deactivate BackendHandler activate IPCBridge IPCBridge->>BackendRust: runs set_audio_volume deactivate IPCBridge activate BackendRust BackendRust->>SystemOS: pactl set-sink-volume @DEFAULT_SINK@ 50% activate SystemOS SystemOS->>SystemOS: Changes the actual volume deactivate SystemOS SystemOS->>DBusEvent: Emits a change event activate DBusEvent DBusEvent->>BackendRust: Receives the confirmation deactivate DBusEvent deactivate BackendRust BackendRust->>VueComponent: event('audio_volume_changed', newValue) activate VueComponent VueComponent->>User: Reflects the visual change deactivate VueComponent

Directory Structure#

Frontend (src/)#

graph LR Src["πŸ“ src/
Vue.js frontend"] Src --> AppVue["πŸ“„ App.vue
Root component"] Src --> MainTs["πŸ“„ main.ts
Entry point"] Src --> StyleCss["πŸ“„ style.css
Global styles"] Src --> VieDts["πŸ“„ vite-env.d.ts
Vite types"] Src --> Assets["πŸ“ assets/
Static assets"] Src --> Components["πŸ“ components/
Reusable"] Src --> Interfaces["πŸ“ interfaces/
TypeScript types"] Src --> Layouts["πŸ“ layouts/
Templates"] Src --> Routes["πŸ“ routes/
Routing"] Src --> Tools["πŸ“ tools/
Controllers"] Src --> Types["πŸ“ types/
Definitions"] Src --> Views["πŸ“ views/
Main pages"] Assets --> AssetsImg["πŸ“ img/"] Assets --> AssetsVec["πŸ“ vectors/"] Components --> CompMenu["πŸ“„ SearchMenuComponent.vue"] Components --> CompAreas["πŸ“ areas/"] Components --> CompBtns["πŸ“ buttons/"] Components --> CompCards["πŸ“ cards/"] Components --> CompCtrl["πŸ“ controls/"] Components --> CompIcon["πŸ“ icon/"] Components --> CompWdg["πŸ“ widgets/"] CompAreas --> AreaPanel["πŸ“ panel/"] CompAreas --> AreaCC["πŸ“ control-center/"] CompAreas --> AreaMenu["πŸ“ menu/"] Interfaces --> IfBat["πŸ“„ battery.ts"] Interfaces --> IfNot["πŸ“„ notifications.ts"] Interfaces --> IfTray["πŸ“„ tray.ts"] Layouts --> LayConfig["πŸ“„ ConfigAppLayout.vue"] Routes --> RouteIdx["πŸ“„ index.ts"] Tools --> ToolBat["πŸ“„ battery.controller.ts"] Tools --> ToolBT["πŸ“„ bluetooth.controller.ts"] Tools --> ToolNet["πŸ“„ network.controller.ts"] Tools --> ToolTray["πŸ“„ tray.controller.ts"] Types --> TypeVue["πŸ“„ vue-libvasak.d.ts"] Views --> ViewCC["πŸ“„ ControlCenterView.vue"] Views --> ViewDsk["πŸ“„ DesktopView.vue"] Views --> ViewMnu["πŸ“„ MenuView.vue"] Views --> ViewPnl["πŸ“„ PanelView.vue"] Views --> ViewApp["πŸ“ applets/"] Views --> ViewApps["πŸ“ apps/"] style Src fill:#667eea,stroke:#764ba2,color:#fff style Components fill:#4facfe,stroke:#00f2fe,color:#fff style Assets fill:#4facfe,stroke:#00f2fe,color:#fff style Interfaces fill:#43e97b,stroke:#38f9d7,color:#fff style Layouts fill:#43e97b,stroke:#38f9d7,color:#fff style Routes fill:#43e97b,stroke:#38f9d7,color:#fff style Tools fill:#feca57,stroke:#ff9a56,color:#fff style Types fill:#fa709a,stroke:#f5576c,color:#fff style Views fill:#f093fb,stroke:#f5576c,color:#fff

Backend (src-tauri/src/)#

graph LR SrcTauri["πŸ“ src-tauri/src/
Rust backend"] SrcTauri --> LibRs["πŸ“„ lib.rs
Main modules"] SrcTauri --> MainRs["πŸ“„ main.rs
Entry point"] SrcTauri --> ErrorRs["πŸ“„ error.rs
Error handling"] SrcTauri --> StructRs["πŸ“„ structs.rs
Shared structures"] SrcTauri --> ConstRs["πŸ“„ constants.rs
Constants"] SrcTauri --> Commands["πŸ“ commands/
IPC commands"] SrcTauri --> WinMgr["πŸ“ window_manager/
Window management"] SrcTauri --> AudioRs["πŸ“„ audio.rs
Audio control"] SrcTauri --> BrightRs["πŸ“„ brightness.rs
Brightness control"] SrcTauri --> BTRs["πŸ“„ bluetooth.rs
Bluetooth control"] SrcTauri --> NetRs["πŸ“„ network.rs
Network control"] SrcTauri --> NotifRs["πŸ“„ notifications.rs
Notification system"] SrcTauri --> DBusRs["πŸ“„ dbus_service.rs
D-Bus integration"] SrcTauri --> EventsRs["πŸ“„ eventloops.rs
Event loops"] SrcTauri --> ShortcutsRs["πŸ“„ platform_shortcuts.rs
Keyboard shortcuts"] SrcTauri --> MenuRs["πŸ“„ menu_manager.rs
Menu management"] SrcTauri --> Tray["πŸ“ tray/
System tray"] SrcTauri --> Applets["πŸ“ applets/
Mini-applications"] SrcTauri --> Utils["πŸ“ utils/
Utility functions"] SrcTauri --> WinApps["πŸ“ windows_apps/
Application handling"] Commands --> AudioCmd["πŸ“„ audio_commands.rs"] Commands --> BTCmd["πŸ“„ bluetooth_commands.rs"] Commands --> NetCmd["πŸ“„ network_commands.rs"] WinMgr --> ModWin["πŸ“„ mod.rs"] WinMgr --> WinCtrl["πŸ“„ window_controller.rs"] WinMgr --> MonMgr["πŸ“„ monitor_handler.rs"] Tray --> ModTray["πŸ“„ mod.rs"] Tray --> TrayIcon["πŸ“„ tray_icon.rs"] style SrcTauri fill:#667eea,stroke:#764ba2,color:#fff style Commands fill:#4facfe,stroke:#00f2fe,color:#fff style WinMgr fill:#4facfe,stroke:#00f2fe,color:#fff style Tray fill:#4facfe,stroke:#00f2fe,color:#fff style Utils fill:#4facfe,stroke:#00f2fe,color:#fff style Applets fill:#4facfe,stroke:#00f2fe,color:#fff style WinApps fill:#4facfe,stroke:#00f2fe,color:#fff style AudioRs fill:#43e97b,stroke:#38f9d7,color:#fff style BrightRs fill:#feca57,stroke:#ff9a56,color:#fff style BTRs fill:#f093fb,stroke:#f5576c,color:#fff style NetRs fill:#fa709a,stroke:#f5576c,color:#fff style NotifRs fill:#43e97b,stroke:#38f9d7,color:#fff style DBusRs fill:#f093fb,stroke:#f5576c,color:#fff

Design Patterns#

1. MVC (Model-View-Controller)#

Frontend:

  • Model: Pinia stores
  • View: Vue components
  • Controller: Methods in components

Backend:

  • Model: Structures in structs.rs
  • Controller: Functions in commands/
  • Business Logic: Specialized modules

2. Pub-Sub (Publish-Subscribe)#

For system events:

1
2
// Backend: emit the event
window.emit("audio_volume_changed", {level: 50})?;
1
2
3
4
5
6
// Frontend: listen for the event
onMounted(() => {
  listen('audio_volume_changed', (event) => {
    state.volume = event.payload.level;
  });
});

3. Service Layer#

Every feature has its own service layer:

  • audio.rs - Audio service
  • network.rs - Network service
  • bluetooth.rs - Bluetooth service

Information Flows#

Command (Frontend β†’ Backend)#

1
2
3
4
5
6
// Frontend
import { invoke } from '@tauri-apps/api/tauri';

const result = await invoke('set_brightness', { 
  level: 75 
});
1
2
3
4
5
6
// Backend
#[tauri::command]
pub fn set_brightness(level: u32) -> Result<(), String> {
    brightness::set_level(level)?;
    Ok(())
}

Event (Backend β†’ Frontend)#

1
2
3
4
// Backend
window.emit("brightness_changed", json!({
    "level": 75
}))?;
1
2
3
4
5
6
// Frontend
import { listen } from '@tauri-apps/api/event';

listen('brightness_changed', (event) => {
  console.log('Brightness:', event.payload.level);
});

Configuration and Manifests#

tauri.conf.json#

Defines Tauri permissions and configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  "build": {
    "beforeDevCommand": "bun run dev",
    "devUrl": "http://localhost:5173"
  },
  "app": {
    "windows": [
      {
        "title": "Vasak Desktop",
        "label": "main",
        "width": 1024,
        "height": 768
      }
    ]
  }
}

Cargo.toml#

Rust dependencies and configuration.

tsconfig.json#

TypeScript configuration.

vite.config.ts#

Frontend build configuration.