Quick settings panel for the gardesk desktop
gartray is a quick settings panel that provides easy access to system controls including volume, screen brightness, WiFi networks, Bluetooth devices, battery status, and power options. Designed for the gardesk ecosystem, it integrates with system services via D-Bus and provides a polished UI built on gartk. Note: System tray functionality has been moved to garbar.
gartray is available as an RPM package for Fedora and RHEL-compatible distributions.
Runtime dependencies for all features:
wpctl - WirePlumber CLI for volume control (wireplumber package)NetworkManager - WiFi managementBlueZ - Bluetooth supportUPower - Battery statussystemd - Power actions via login1brightnessctl - Brightness control fallback (optional)dunstctl - DND integration (optional, for dunst users)Start the gartray daemon and show the quick settings panel:
Add gartray to your gar window manager startup:
-- ~/.config/gar/init.lua
gar.spawn("gartray daemon")
-- Bind to a key (e.g., Super+S)
gar.bind("super+s", function()
-- Show panel at cursor position or fixed location
gar.spawn("gartrayctl toggle 1200 50")
end) The quick settings panel provides intuitive controls for common system settings:
Slider for system volume, mute toggle, real-time updates via WirePlumber/PipeWire.
Slider for backlight control, auto-detects laptop displays, uses sysfs or brightnessctl.
Toggle WiFi, scan for networks, connect with saved or new passwords, 802.1X enterprise support.
Toggle Bluetooth, view paired devices, connect/disconnect, start discovery for new devices.
Display battery percentage, charging status, and estimated time remaining.
Shutdown, reboot, suspend, hibernate, and logout via systemd-logind.
gartray is configured via a TOML file at ~/.config/gartray/config.toml.
All settings have sensible defaults - you only need to create a config file to customize behavior.
A minimal config to change panel width and disable unused modules:
# ~/.config/gartray/config.toml
[panel]
width = 400
modules = ["volume", "brightness", "network", "power"] # ~/.config/gartray/config.toml
[panel]
enabled = true
width = 360
modules = ["volume", "brightness", "network", "bluetooth", "battery", "power"]
[panel.volume]
show_per_app = false
show_input = false
[panel.network]
show_vpn = true
show_ethernet = true
[panel.bluetooth]
show_battery = true
[theme]
preset = "dark" | Option | Type | Default | Description |
|---|---|---|---|
enabled | bool | true | Enable the quick settings panel |
width | u32 | 360 | Panel width in pixels |
modules | string[] | ["volume", "brightness", "network", "bluetooth", "battery", "power"] | Enabled modules in display order |
| Option | Type | Default | Description |
|---|---|---|---|
show_per_app | bool | false | Show per-application volume controls |
show_input | bool | false | Show microphone/input controls |
| Option | Type | Default | Description |
|---|---|---|---|
show_vpn | bool | false | Show VPN connection status |
show_ethernet | bool | false | Show wired ethernet connections |
| Option | Type | Default | Description |
|---|---|---|---|
show_battery | bool | false | Show battery level for connected Bluetooth devices |
| Option | Type | Default | Description |
|---|---|---|---|
preset | string | "dark" | Theme preset: dark, light, or custom |
Reload configuration without restarting the daemon:
gartray is a quick settings panel designed for the gardesk desktop environment. It provides a centralized interface for controlling common system settings without opening full-featured settings applications. The panel integrates with standard Linux desktop services via D-Bus to provide native functionality.
Key design principles:
Note: System tray (StatusNotifierItem/SNI) functionality has been moved to garbar where it appears in the status bar alongside other indicators.
gartray uses a daemon architecture where the main process maintains connections to system services and renders the panel when requested.
The gartray daemon runs continuously in the background, maintaining D-Bus connections to system services. This allows the panel to open instantly without connection delays.
Daemon Lifecycle:
┌─────────────────────────────────────────────────────────┐
│ 1. Start daemon │
│ ├── Load configuration │
│ ├── Initialize module connections │
│ │ ├── Volume: connect to wpctl │
│ │ ├── Brightness: probe /sys/class/backlight │
│ │ ├── Network: connect to NetworkManager D-Bus │
│ │ ├── Bluetooth: connect to BlueZ D-Bus │
│ │ ├── Battery: connect to UPower D-Bus │
│ │ ├── Power: connect to login1 D-Bus │
│ │ └── DND: check for dunstctl │
│ └── Listen for IPC commands │
│ │
│ 2. Handle IPC commands (show/hide/toggle/reload/quit) │
│ │
│ 3. When shown: render panel, handle user interaction │
│ │
│ 4. When hidden: return to idle, maintain connections │
└─────────────────────────────────────────────────────────┘ The panel is a popup window rendered using gartk. Each module contributes a section to the panel UI. Modules are displayed in the order specified in the configuration.
Panel Layout:
┌────────────────────────────────────────┐
│ 🔊 Volume ──────────────────○──── 75% │
│ ☐ Mute │
├────────────────────────────────────────┤
│ 🔆 Brightness ──────────────○──── 50% │
├────────────────────────────────────────┤
│ 📶 WiFi: MyNetwork [Toggle ☑] │
├────────────────────────────────────────┤
│ 🔵 Bluetooth [Toggle ☑] │
├────────────────────────────────────────┤
│ 🔋 Battery: 85% ⚡ 3h 20m │
├────────────────────────────────────────┤
│ ⏻ Shutdown 🔄 Restart 💤 Suspend │
└────────────────────────────────────────┘ Each module implements a common interface for initialization and state updates. Modules gracefully handle unavailable services (e.g., no battery on a desktop).
// Module trait interface
pub trait PanelModule {
/// Module name for configuration
fn name(&self) -> &'static str;
/// Update module state
fn update(&mut self);
} Modules are initialized at daemon startup and maintain their service connections for the daemon's lifetime. State is refreshed when the panel is shown to ensure current values.
gartray integrates with standard Linux desktop services via D-Bus for native control of system settings.
WiFi control uses the NetworkManager D-Bus interface on the system bus. This provides:
D-Bus Service: org.freedesktop.NetworkManager
Object: /org/freedesktop/NetworkManager
Key Methods:
GetDevices() -> ao # Get device paths
ActivateConnection(o, o, o) # Activate a saved connection
AddAndActivateConnection(a{sa{sv}}, o, o) # Create and connect
Device.Wireless Methods:
RequestScan(a{sv}) # Trigger network scan
GetAccessPoints() -> ao # Get available networks Bluetooth control uses the BlueZ D-Bus interface. The module uses ObjectManager to discover adapters and devices dynamically.
D-Bus Service: org.bluez
Object: / (for ObjectManager), /org/bluez/hci0 (adapter)
Adapter1 Interface:
Powered (bool) # Read/write power state
StartDiscovery() # Start scanning for devices
StopDiscovery() # Stop scanning
Device1 Interface:
Connect() # Connect to device
Disconnect() # Disconnect from device
Name, Address, Paired, Connected, Icon (properties) Battery information comes from UPower's DisplayDevice, which aggregates information from all power sources into a single logical battery.
D-Bus Service: org.freedesktop.UPower
Object: /org/freedesktop/UPower/devices/DisplayDevice
Device Properties:
Percentage (d) # 0-100 battery level
State (u) # 1=Charging, 2=Discharging, 4=FullyCharged
TimeToEmpty (x) # Seconds until empty (when discharging)
TimeToFull (x) # Seconds until full (when charging)
IsPresent (b) # Whether battery is physically present
Type (u) # 2 = Battery
State Constants:
0 = Unknown
1 = Charging
2 = Discharging
3 = Empty
4 = Fully Charged
5 = Pending Charge
6 = Pending Discharge Power actions use the systemd-logind D-Bus interface with systemctl fallback for environments where D-Bus calls may be restricted.
D-Bus Service: org.freedesktop.login1
Object: /org/freedesktop/login1
Manager Methods:
PowerOff(b) # Shutdown (interactive: bool)
Reboot(b) # Restart
Suspend(b) # Sleep
Hibernate(b) # Hibernate to disk
TerminateSession(s) # Logout (session id)
CanPowerOff() -> s # Check if action is allowed
CanReboot() -> s # Returns "yes", "no", or "challenge"
CanSuspend() -> s
CanHibernate() -> s gartray uses gartk for all rendering, providing consistent visuals with other gardesk components.
The panel is rendered using gartk's rendering primitives:
Modules are laid out vertically with configurable spacing. Each module renders its own section with:
gartray is organized into independent modules, each providing a specific quick setting. Modules can be enabled or disabled via configuration, and their display order is configurable.
Controls audio output via wpctl, the WirePlumber command-line tool for PipeWire.
# Get current volume
wpctl get-volume @DEFAULT_AUDIO_SINK@
# Output: "Volume: 0.75" or "Volume: 0.50 [MUTED]"
# Set volume to 80%
wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.80
# Toggle mute
wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle Controls screen brightness via the Linux backlight interface.
# Direct sysfs access (requires permissions)
cat /sys/class/backlight/intel_backlight/brightness
cat /sys/class/backlight/intel_backlight/max_brightness
echo 500 > /sys/class/backlight/intel_backlight/brightness
# Fallback via brightnessctl
brightnessctl set 500 The module first attempts direct sysfs writes, which may require udev rules or group membership. If that fails, it uses brightnessctl which typically has the necessary permissions via polkit.
WiFi control via NetworkManager D-Bus interface.
For 802.1X enterprise networks, gartray prompts for EAP credentials:
Bluetooth control via BlueZ D-Bus interface.
For each device, the module shows:
Battery status via UPower D-Bus interface.
Discharging:
80-100% → battery-full
50-79% → battery-good
20-49% → battery-low
5-19% → battery-caution
0-4% → battery-empty
Charging:
80-100% → battery-full-charging
50-79% → battery-good-charging
20-49% → battery-low-charging
0-19% → battery-caution-charging
Fully Charged → battery-full-charged
Missing/No battery → battery-missing Power actions via systemd-logind D-Bus interface.
If D-Bus calls fail (e.g., due to polkit restrictions), the module falls back to:
systemctl poweroff for shutdownsystemctl reboot for restartsystemctl suspend for sleeppkill -TERM -x gar for logout (kills window manager)Toggle notifications on/off, with optional dunst integration.
# Check current state
dunstctl is-paused
# Output: "true" or "false"
# Enable DND (pause notifications)
dunstctl set-paused true
# Disable DND (resume notifications)
dunstctl set-paused false
The gartrayctl command-line tool controls the gartray daemon
via IPC. It's the primary way to show/hide the panel and manage the daemon.
| Command | Description |
|---|---|
show [X] [Y] | Show the quick settings panel at position X,Y (defaults to 0,0) |
hide | Hide the quick settings panel |
toggle [X] [Y] | Toggle panel visibility at position X,Y |
reload | Reload configuration from disk |
status | Show daemon status and module states |
quit | Stop the gartray daemon |
Bind to a key in your window manager for quick access:
-- gar config (~/.config/gar/init.lua)
gar.bind("super+s", function()
gar.spawn("gartrayctl toggle 1200 50")
end)
-- Or position near the mouse cursor
gar.bind("super+s", function()
local mouse = gar.get_cursor_pos()
gar.spawn("gartrayctl toggle " .. mouse.x .. " " .. mouse.y)
end)
gartray uses a Unix domain socket for IPC. The socket is created at
$XDG_RUNTIME_DIR/gartray.sock.
| Command | Description |
|---|---|
show | Show panel at position (x: i32, y: i32) |
hide | Hide the panel |
toggle | Toggle panel visibility (x: i32, y: i32) |
reload | Reload configuration |
status | Get daemon and module status |
quit | Stop the daemon |
gartray is commonly triggered from garbar status bar clicks. Add a widget to your garbar configuration:
-- garbar config
modules = {
-- ... other modules ...
{
type = "button",
icon = "settings",
on_click = "gartrayctl toggle", -- Opens at click position
},
} If the volume module shows as unavailable:
If this fails, ensure PipeWire and WirePlumber are installed and running:
Direct sysfs writes require appropriate permissions. Solutions:
# /etc/udev/rules.d/90-backlight.rules
ACTION=="add", SUBSYSTEM=="backlight", RUN+="/bin/chgrp video $sys$devpath/brightness"
ACTION=="add", SUBSYSTEM=="backlight", RUN+="/bin/chmod g+w $sys$devpath/brightness" The network module requires NetworkManager:
Ensure BlueZ is running:
If you have a Bluetooth adapter but it's not detected:
The battery module is automatically hidden on systems without batteries. Verify UPower detects your battery:
If shutdown/reboot prompts for authentication, this is a polkit policy. You can:
gartray automatically falls back to systemctl, which typically works without prompts.
/* /etc/polkit-1/rules.d/85-allow-shutdown.rules */
polkit.addRule(function(action, subject) {
if (action.id.indexOf("org.freedesktop.login1.") == 0 &&
subject.isInGroup("wheel")) {
return polkit.Result.YES;
}
}); The position is passed via gartrayctl. Make sure you're providing the correct coordinates:
Run the daemon in foreground with verbose logging:
For further assistance:
gartrayctl status