GNOME Settings Architecture
Detailed overview of the GNOME settings stack in Pulsar OS.
The Stack
+-----------------------------------------------+
| gnome-control-center (UI) |
| Each panel = plugin, talks backends |
+----------------------+------------------------+
| D-Bus: org.gnome.Mutter.DisplayConfig
| (monitors)
| GSettings API (everything else)
|
+----------------------+------------------------+
| Two backends: |
| |
| 1. MUTTER -- owns display/monitor config |
| MetaMonitorManager -> monitors.xml |
| Hotplug: kernel DRM -> udev -> mutter |
| |
| 2. DCONF -- owns all other settings |
| ~/.config/dconf/user (binary DB) |
| Layered system DBs from /etc/dconf/db/ |
| Schema-enforced via .gschema.xml |
+-----------------------------------------------+
Key GNOME Components
| Component | Role |
|---|---|
| mutter | Wayland compositor / X11 WM. Owns display stack. Exposes org.gnome.Mutter.DisplayConfig D-Bus interface. Stores layout in ~/.config/monitors.xml. |
| gnome-shell | Desktop shell. Hosts mutter, provides panel, overview, activities, window switching. |
| gnome-settings-daemon (gsd) | Session daemon translating settings changes into actions. Plugins for power, media-keys, xsettings, color. Watches GSettings and acts. |
| gnome-control-center | Settings UI. Each panel is a plugin. Display panel talks to mutter over D-Bus. |
| GDM | Login manager. Runs its own mutter/gnome-shell instance. Separate dconf profile and monitor config. |
| dconf-service | D-Bus activated daemon writing to binary dconf database. Stateless, crashes freely. |
Settings Storage: dconf + GSettings
| Layer | What it does |
|---|---|
| GSettings (GLib API) | Type-safe schema-enforced wrapper. Every key has a type, default, path defined in .gschema.xml files compiled by glib-compile-schemas. This is what apps call. |
| dconf (backend) | Raw key/value binary store. Optimized for reads (mmap’d hashtable, zero syscalls). Writes through dconf-service over D-Bus, fsync latency hidden by fast-path cache. |
Schema Path Convention
Dotted IDs map to dconf paths. Schema org.gnome.desktop.interface lives at dconf path /org/gnome/desktop/interface/.
Key Files
~/.config/dconf/user– per-user binary database (the actual storage)/etc/dconf/db/<name>/– system-wide override databases (compiled from keyfiles)/etc/dconf/profile/user– profile listing the database layers consulted in order~/.config/monitors.xml– display configuration (separate from dconf)
Write Flow
gsettings_set("org.gnome.desktop.interface", "gtk-theme", "'Adwaita'")
-> GSettings API validates type against schema
-> dconf backend calls dconf_engine_change_fast()
-> local fast-path records change immediately (readable instantly)
-> D-Bus call to dconf-service
-> dconf-service renames new DB file over old one
-> fsync() (up to 100ms latency)
-> D-Bus signal notifies watchers of change
Layering
dconf consults databases in profile order. User DB always wins. System databases (for admin policy/defaults) come from /etc/dconf/db/. Lock-down supported – system admins can lock keys so users cannot override them.
Key Schema Files
gsettings-desktop-schemas:org.gnome.desktop.interface,org.gnome.desktop.background,org.gnome.desktop.screensaver, etc.gnome-settings-daemon:org.gnome.settings-daemon.plugins.*mutter:org.gnome.mutter.*
Display/Monitor Management
Key insight: mutter owns display configuration. Not gnome-settings-daemon, not XRandR directly.
Core Classes in Mutter
MetaMonitorManager (abstract)
|
+-- MetaMonitorManagerKms (Wayland/native backend, KMS/DRM)
+-- MetaMonitorManagerXrandr (X11 backend, XRandR)
+-- MetaMonitorManagerDummy (testing)
|
Provides: org.gnome.Mutter.DisplayConfig D-Bus service
MetaMonitorConfigManager
|-- Manages MetaMonitorsConfig (in-memory representation)
|-- Uses MetaMonitorConfigStore (reads/writes monitors.xml)
MetaMonitorConfigStore
|-- Reads: ~/.config/monitors.xml (user)
|-- Reads: /etc/xdg/monitors.xml (system-wide default)
|-- Writes: ~/.config/monitors.xml (when persistent config applied)
|-- Format: XML with <monitors version="2"> root
MetaMonitor, MetaLogicalMonitor, MetaCrtc, MetaOutput, MetaGpu
|-- Hardware abstraction objects
monitors.xml Format
<monitors version="2">
<configuration>
<logicalmonitor>
<x>0</x><y>0</y>
<monitor>
<connector>HDMI-1</connector>
<vendor>ABC</vendor>
<product>Display</product>
<serial>123</serial>
<mode>
<width>1920</width>
<height>1080</height>
<rate>60.0</rate>
</mode>
</monitor>
<scale>1</scale>
<primary>yes</primary>
</logicalmonitor>
</configuration>
</monitors>
Monitor Hotplug Detection (Wayland)
Kernel DRM subsystem
-> udev uevent ("drm" subsystem, HOTPLUG property)
-> GUdevClient signal "uevent"
-> MetaUdev emits "hotplug" signal
-> MetaMonitorManagerKms::on_udev_hotplug()
-> handle_hotplug_event()
-> meta_monitor_manager_read_current_state() // re-read hardware
-> meta_monitor_manager_on_hotplug()
-> meta_monitor_manager_notify_monitors_changed()
-> emits "monitors-changed" signal
-> D-Bus MonitorsChanged signal emitted
-> gnome-control-center reacts
Hotplug flow in detail:
- Monitor plugged in. Kernel DRM driver emits uevent.
gudevpicks it up in mutter’sMetaMonitorManagerKms. Device must haveHOTPLUGproperty.- Mutter calls
meta_monitor_manager_read_current_state()– re-enumerates all GPU connectors, modes, CRTCs. meta_monitor_manager_on_hotplug()triggersmeta_monitor_manager_ensure_configured():- Tries stored config from
monitors.xml(matching by connector/vendor/product/serial) - Falls back to current config if still works
- Falls back to “suggested” config
- Falls back to “linear” layout (side by side)
- Falls back to single-monitor fallback
- Tries stored config from
- Config applied,
MonitorsChangedD-Bus signal fires. - gsd-xsettings plugin reads new state, updates X11 properties (DPI, scaling).
- gnome-control-center display panel receives signal, rebuilds UI.
GPU hotplug (e.g., eGPU): udev “add” events for DRM devices trigger handle_gpu_hotplug(), creating a new MetaGpuKms object.
D-Bus Interfaces
org.gnome.Mutter.DisplayConfig
Bus name: org.gnome.Mutter.DisplayConfig
Object path: /org/gnome/Mutter/DisplayConfig
This is THE central interface.
| Method | Purpose |
|---|---|
GetResources() |
Legacy: returns CRTCs, outputs, modes with serial. Older clients. |
GetCurrentState() |
Modern: returns serial, monitors list (connector/vendor/product/serial/modes with scales), logical monitors (position/scale/transform/primary/monitor-list), properties. |
ApplyMonitorsConfig(serial, method, logical_monitors, properties) |
Apply new layout. method: 0=verify, 1=temporary, 2=persistent. |
ApplyConfiguration(serial, persistent, crtcs, outputs) |
Legacy apply (older API). |
SetOutputCTM(serial, output, ctm) |
Set color transform matrix on output. |
Properties:
PowerSaveMode(read/write)PanelOrientationManaged(read-only)ApplyMonitorsConfigAllowed(read-only, controlled by policy)
Signal:
MonitorsChanged– emitted when hardware config changes; clients should re-read viaGetCurrentState().
org.gnome.SettingsDaemon.XRANDR (deprecated)
Formerly used by gnome-control-center. Methods: ApplyConfiguration, VideoModeSwitch, Rotate. Now deprecated – mutter’s DisplayConfig is the only supported path.
Settings Flow: UI to Storage
Display Setting Change (resolution, position, scale)
gnome-control-center (Display panel)
-> CcDisplayConfigManagerDBus
-> CcDisplayConfigDBus::config_apply()
-> g_dbus_connection_call_sync("org.gnome.Mutter.DisplayConfig",
"ApplyMonitorsConfig", ...)
-> mutter's MetaMonitorManager handles the call
-> meta_monitor_manager_apply_monitors_config()
-> validates, applies to hardware
-> if method == PERSISTENT:
meta_monitor_config_manager_set_current()
-> MetaMonitorConfigStore saves to ~/.config/monitors.xml
-> emits MonitorsChanged signal
General Desktop Setting (theme, font, etc.)
gnome-control-center (Appearance panel)
-> g_settings_set("org.gnome.desktop.interface", "gtk-theme", "'Yaru'")
-> GSettings API validates type
-> dconf backend writes to ~/.config/dconf/user
-> dconf-service commits via D-Bus
-> gsd-xsettings plugin watches the key
-> applies theme to running GTK apps
The gsd-xsettings plugin is a critical bridge: watches GSettings changes and applies them as X properties or GTK settings to the running session. On Wayland, many applied differently (through gnome-shell’s own CSS theming).
GDM’s Relationship
GDM runs its own GNOME session (mutter + gnome-shell) as the gdm user.
- Separate dconf profile:
/etc/dconf/profile/gdmwithsystem-db:gdmandfile-db:/usr/share/gdm/greeter-dconf-defaults - Separate monitor config:
/etc/xdg/monitors.xml(system-wide) or~gdm/.config/monitors.xml(per greeter user) - D-Bus: GDM’s session bus is separate from user session bus. Its mutter instance exposes its own
org.gnome.Mutter.DisplayConfigon the system session bus.
The greeter’s display config is independent of user session. To apply user display settings to GDM, copy ~/.config/monitors.xml to the gdm user or /etc/xdg/monitors.xml.
PulsarOS Modifications
pulsaros-gnome
Default settings layer for Pulsar OS:
90_pulsaros.gschema.override– GSettings defaults (theme, extensions, keybindings, dock, blur, power)etc/dconf/db/local.d/00-pulsaros-theme– dconf system DB (same + XKB swaps, Liquid Glass params, mutter overlay-key)etc/dconf/db/local.d/locks/00-pulsaros-theme– Locksbutton-layoutandextension-version-validation
pulsaros-control-center
Replaces gnome-control-center with:
- macOS-style user banner at top (Apple ID & Accounts)
- Reordered sidebar (network first, system last)
- Custom squircle panel icons
- Heavily modified Background panel -> “Appearance” panel:
- Light/Dark style toggle
- macOS Keyboard Remap switch (XKB
ctrl:swap_lwin_lctl) - macOS Fullscreen Spaces switch
- Liquid Glass switch
- Accent color picker
- Live Wallpaper launcher
- Spotlight vs Overview toggle
- Cursor theme picker
- Display panel is upstream mutter’s – no PulsarOS override
pulsaros-effects-settings
Python GTK3 app for toggling desktop visual effects:
- Two modes: “Blur my Shell (Recommended)” and “Liquid Glass (Glassmorphism)”
- Directly writes
org.gnome.shell enabled-extensionsstrv - Sets dock opacity, blur parameters via GSettings
- Chains multiple extension schema directories into custom
SettingsSchemaSource
What’s NOT Customized
Monitor/display config uses upstream mutter. No PulsarOS override for:
monitors.xmlhandlingorg.gnome.Mutter.DisplayConfigD-Bus interface- Hotplug detection
- Multi-monitor layout logic
Architecture Diagram
GNOME Shell Runtime Subsystems
Notifications
Architecture
Three APIs exist. GNOME Shell is the notification server for all of them:
| API | Who uses it | How it reaches the shell |
|---|---|---|
| org.freedesktop.Notifications (Fdo spec) | Any Linux app via libnotify or raw D-Bus | D-Bus Notify() method call |
| Gio.Notification (GLib/GIO) | GNOME/GTK apps | GIO sends to org.freedesktop.Notifications or the XDG Notification Portal |
XDG Desktop Notification Portal (org.freedesktop.portal.Notification) |
Flatpak/sandboxed apps | Portal daemon forwards to shell |
GNOME 46+ migrates toward the portal as the canonical path.
D-Bus Interface
GNOME Shell owns org.freedesktop.Notifications on the session bus via a separate proxy daemon:
- Bus name:
org.freedesktop.Notifications - Object path:
/org/freedesktop/Notifications - Interface:
org.freedesktop.Notifications
| Method | Signature |
|---|---|
Notify |
(sasa{sv}) → u – app_name, replaces_id, app_icon, summary, body, actions, hints, expire_timeout |
CloseNotification |
(u) – id |
GetCapabilities |
→ as – supported features |
GetServerInformation |
→ (ssss) – name, vendor, version, spec_version |
| Signal | Signature |
|---|---|
NotificationClosed |
(uu) – id, reason |
ActionInvoked |
(us) – id, action_key |
Notification Flow
1. App calls Gio.Notification / libnotify / raw D-Bus Notify()
|
v
2. org.freedesktop.Notifications D-Bus name
(owned by gnome-shell-notification-daemon process)
|
v
3. NotificationDaemon.js proxies to org.gnome.Shell
js/ui/notificationDaemon.js
|
v
4. Shell creates MessageTray.Source + MessageTray.Notification
js/ui/messageTray.js
|
+---> Banner popup (temporary overlay at screen top)
|
+---> Message Tray (notification center, revealed from bottom)
Notifications persist until dismissed, expired, or source closed
Key Source Files
| File | Role |
|---|---|
js/ui/notificationDaemon.js |
NotificationDaemon – D-Bus handler, creates Source objects per app |
js/ui/messageTray.js |
MessageTray, Source, Notification, NotificationPolicy – notification center UI and data model |
js/ui/calendar.js |
CalendarMessageList – notification list inside the date menu |
src/dbusServices/notifications/notificationDaemon.js |
Out-of-process proxy daemon |
Key Classes
NotificationDaemon– D-Bus interface handler, maps Fdo notifications to MessageTray sourcesMessageTray.Source– groups notifications by app; owns icon, title, policyMessageTray.Notification– single notification with title, body, actions, urgencyNotificationPolicy/NotificationGenericPolicy– controls banners, sounds, lock screen behaviorUrgency–LOW(0),NORMAL(1),HIGH(2),CRITICAL(3)
Persistence
Fdo spec advertises "persistence" capability. GNOME Shell keeps dismissed notifications in the Message Tray until the source is destroyed. Gio.Notification notifications can survive app exit only when routed through the shell’s private API.
Calendar / Date Menu
Architecture
Calendar events load out-of-process because Evolution Data Server (EDS) libraries can block and are not thread-safe. A dedicated gnome-shell-calendar-server C binary talks to EDS and exposes a private D-Bus interface.
Data Flow
Evolution Data Server (e-cal-client, e-source-registry)
|
v
gnome-shell-calendar-server (C binary)
bus name: org.gnome.Shell.CalendarServer
object path: /org/gnome/Shell/CalendarServer
interface: org.gnome.Shell.CalendarServer
|
v
gnome-shell JS process
js/ui/dateMenu.js -- DateMenuButton
js/ui/calendar.js -- Calendar, DBusEventSource
D-Bus Interface: org.gnome.Shell.CalendarServer
| Method | Args | Purpose |
|---|---|---|
SetTimeRange |
(xxb) since, until, force_reload |
Request events in a time window |
| Signal | Args | Purpose |
|---|---|---|
EventsAdded |
a(ssbxxa{sv}) events |
Event tuple: (id, summary, all_day, start_time, end_time, extras) |
EventsRemoved |
as ids |
Removed event IDs |
ClientDisappeared |
s source_uid |
EDS source went away |
| Property | Type | Purpose |
|---|---|---|
HasCalendars |
b |
Whether any calendar sources exist |
Since / Until |
x |
Current time range bounds |
Calendar Server Internals
gnome-shell-calendar-server.c– GApplication, owns the bus namecalendar-sources.c– wrapsESourceRegistry, managesECalClientconnections per source- Creates
ECalClientViewlive queries with iCal RDATE/expansion - Emits
EventsAddedOrUpdated/EventsRemovedwhen EDS view fires - Handles timezone via
e_cal_system_timezone_get_location() - Integrates
EReminderWatcherfor alarm/reminder notifications
Key Source Files
| File | Role |
|---|---|
src/calendar-server/gnome-shell-calendar-server.c |
Out-of-process calendar server |
src/calendar-server/calendar-sources.c |
EDS source registry + ECalClient management |
src/calendar-server/reminder-watcher.c |
Calendar reminder/alarm handling |
js/ui/dateMenu.js |
DateMenuButton – clock+calendar dropdown in top bar |
js/ui/calendar.js |
Calendar widget, DBusEventSource, EventsSection, CalendarMessageList |
Key Classes
DateMenuButton–PanelMenu.Buttonsubclass; owns clock display, calendar widget, events section, world clocks, weatherCalendar– monthly calendar grid widgetDBusEventSource– JS proxy toorg.gnome.Shell.CalendarServer; callsSetTimeRange, listens for eventsEventsSection– shows upcoming events below the calendarWorldClocksSection,WeatherSection– additional displays in the date dropdown
Top Bar / System Status
Panel Layout
+---------------------------------------------------------------+
| [leftBox] [centerBox] [rightBox] |
| Activities Date/Time/Clock QuickSettings |
| workspace indicators MessagesIndicator indicators |
| (wifi, vol, bat) |
+---------------------------------------------------------------+
Panel Item Registry
// js/ui/panel.js
const PANEL_ITEM_IMPLEMENTATIONS = {
'activities': ActivitiesButton,
'quickSettings': QuickSettings,
'dateMenu': DateMenuButton,
'a11y': ATIndicator,
'keyboard': InputSourceIndicator,
'dwellClick': DwellClickIndicator,
'screenRecording': ScreenRecordingIndicator,
'screenSharing': ScreenSharingIndicator,
};
QuickSettings Menu
QuickSettings (PanelMenu.Button)
+-- indicators box (wifi icon, volume icon, battery icon...)
+-- QuickSettingsItems grid (toggles):
| +-- Wi-Fi toggle
| +-- Bluetooth toggle
| +-- Night Light toggle
| +-- Dark Style toggle
| +-- Do Not Disturb toggle
+-- Sliders:
| +-- Volume slider (QuickSlider)
| +-- Brightness slider
| +-- Microphone slider
+-- SystemItem (bottom row):
+-- Settings button
+-- Lock button
+-- Power Off button (Restart, Log Out, Switch User sub-menu)
D-Bus Services Consumed by Status Indicators
| Indicator | D-Bus Service | Bus Name |
|---|---|---|
| Network (Wi-Fi, wired) | NetworkManager | org.freedesktop.NetworkManager |
| Volume | PulseAudio / PipeWire | org.pulseaudio.Server (via Gvc/MixerControl) |
| Bluetooth | BlueZ | org.bluez |
| Battery/Power | UPower | org.freedesktop.UPower |
| System (shutdown/lock) | systemd-logind | org.freedesktop.login1 |
| Screen Sharing | Mutter ScreenCast | PipeWire-based screencast |
| Remote Access | GNOME RemoteDesktop | RDP/VNC |
Key Source Files
| File | Role |
|---|---|
js/ui/panel.js |
Panel – top bar widget, ActivitiesButton, panel layout |
js/ui/panelMenu.js |
PanelMenu.Button – base class for all panel indicators |
js/ui/quickSettings.js |
QuickSettingsMenu, SystemIndicator, QuickSettingsItem, QuickSlider |
js/ui/status/system.js |
ShutdownItem, LockItem, SettingsItem |
js/ui/status/network.js |
Network indicator, NMApplet |
js/ui/status/volume.js |
Volume indicator |
js/ui/status/power.js |
Battery indicator, UPower proxy |
js/ui/status/bluetooth.js |
Bluetooth indicator |
js/ui/status/keyboard.js |
Input source indicator |
js/ui/status/accessibility.js |
Accessibility indicators |
js/ui/status/remoteAccess.js |
Screen sharing/recording indicators |
Extension API for Quick Settings
Extensions add indicators via:
Main.panel.statusArea.quickSettings.addExternalIndicator(this._indicator);
Where _indicator is a SystemIndicator subclass with quickSettingsItems array.
Shell Extensions
Loading Mechanism
- Discovery:
ExtensionManagerscans$XDG_DATA_HOME/gnome-shell/extensions/(user) and$XDG_DATA_DIRS/gnome-shell/extensions/(system) for directories withmetadata.json. - Registration: Each extension gets an entry in
ExtensionManager._extensions[uuid]. - Enable/Disable:
org.gnome.shellGSettings keyenabled-extensions(typeas) lists enabled UUIDs.ExtensionManagerwatches this key. - Loading:
extension.jsimported as ES module. Must export a subclass ofExtension(or legacyinit()/enable()/disable()functions).
Extension Lifecycle
constructor(metadata) <- once, when module is loaded
enable() <- when extension is enabled
disable() <- when extension is disabled
D-Bus Interface
| Method | Return | Purpose |
|---|---|---|
ListExtensions |
a{sa{sv}} |
All discovered extensions |
GetExtensionInfo |
a{sv} |
Extension metadata |
EnableExtension |
b |
Enable by UUID |
DisableExtension |
b |
Disable by UUID |
LaunchExtensionPrefs |
Open prefs window | |
InstallExtension |
Install from zip | |
UninstallExtension |
Remove extension | |
ReloadExtension |
Reload from disk | |
CheckForUpdates |
Check extensions.gnome.org |
| Signal | Purpose |
|---|---|
ExtensionStateChanged |
(s, a{sv}) – UUID, state info |
Settings Storage
Extensions use GSettings backed by dconf:
- Schema ID:
org.gnome.shell.extensions.<uuid> - Schema path:
/org/gnome/shell/extensions/<uuid>/ - Schema files:
schemas/org.gnome.shell.extensions.<uuid>.gschema.xml - Compiled with
glib-compile-schemasintoschemas/gschemas.compiled settings-schemakey inmetadata.jsonenablesthis.getSettings()auto-resolution
Key Source Files
| File | Role |
|---|---|
js/ui/extensionSystem.js |
ExtensionManager – discovery, loading, enable/disable |
js/ui/shellDBus.js |
GnomeShellExtensions – D-Bus interface |
js/misc/extensionUtils.js |
ExtensionFinder, getSettings(), extension type constants |
js/ui/extensionDownloader.js |
Download/install from extensions.gnome.org |
App Grid / Overview
Overview State Machine
var ControlsState = {
HIDDEN: 0, // desktop, no overview
WINDOW_PICKER: 1, // activities overview -- workspaces visible
APP_GRID: 2, // application grid visible
};
Transitions animated via OverviewAdjustment (an St.Adjustment) interpolating between states.
Actor Hierarchy
Overview (js/ui/overview.js)
+-- ControlsManager (js/ui/overviewControls.js)
+-- SearchEntry (St.Entry, "Type to search")
+-- AppDisplay (js/ui/appDisplay.js)
| +-- St.ScrollView
| | +-- AppGrid (IconGrid subclass)
| | +-- AppIcon items, FolderIcon items
| +-- PageIndicators
+-- Dash (js/ui/dash.js)
| +-- AppFavorites
| +-- DashItemContainer items
+-- SearchController
+-- ThumbnailsBox (workspace thumbnails sidebar)
+-- WorkspacesDisplay (js/ui/workspacesView.js)
+-- Workspace views
ControlsManagerLayout
The ControlsManagerLayout (a Clutter.BoxLayout) computes positions based on ControlsState:
- HIDDEN: Everything offscreen
- WINDOW_PICKER: Search at top, workspace thumbnails on left, workspaces in center, dash at bottom, app display hidden
- APP_GRID: Search at top, app grid fills remaining space (workspaces shrink), dash at bottom
Layout respects the work area (excludes panels, docks) for proper sizing.
App Grid Internals
AppDisplayextendsBaseAppView– paginated icon grid, folder dialogs, drag-and-dropAppGridextendsIconGrid–IconGridLayoutmanages page/column/row computationPageManager– reads/writesglobal.settingskeyapp-picker-layout(GVarianta{sa{sv}})AppIcon– individual app launcher iconFolderIcon– represents a folder; opensFolderDialogoverlay- App ordering: saved positions from
app-picker-layouttake priority; unplaced apps sort alphabetically - DnD: apps dragged between pages and into/out of folders.
SwipeTrackerhandles touchpad page switching.
Key Source Files
| File | Role |
|---|---|
js/ui/overview.js |
Overview – top-level widget, show/hide/toggle logic |
js/ui/overviewControls.js |
ControlsManager, ControlsManagerLayout, OverviewAdjustment |
js/ui/appDisplay.js |
AppDisplay, AppGrid, AppIcon, FolderIcon, FolderDialog, PageManager |
js/ui/iconGrid.js |
IconGrid, IconGridLayout – paginated grid layout |
js/ui/dash.js |
Dash – favorites dock at bottom of overview |
js/ui/appFavorites.js |
AppFavorites – reads/writes org.gnome.shell key favorite-apps |
js/ui/workspacesView.js |
WorkspacesDisplay – workspace thumbnails and primary workspace |
js/ui/workspaceThumbnail.js |
ThumbnailsBox – workspace thumbnail sidebar |
js/ui/pageIndicators.js |
PageIndicators – dots showing current page |
js/ui/search.js |
SearchResultsView – search providers integration |
D-Bus Interfaces Summary
| Subsystem | Bus Name | Object Path | Interface |
|---|---|---|---|
| Display Config | org.gnome.Mutter.DisplayConfig |
/org/gnome/Mutter/DisplayConfig |
org.gnome.Mutter.DisplayConfig |
| Notifications | org.freedesktop.Notifications |
/org/freedesktop/Notifications |
org.freedesktop.Notifications |
| Calendar | org.gnome.Shell.CalendarServer |
/org/gnome/Shell/CalendarServer |
org.gnome.Shell.CalendarServer |
| Shell Extensions | org.gnome.Shell |
/org/gnome/Shell |
org.gnome.Shell.Extensions |
| Network | org.freedesktop.NetworkManager |
/org/freedesktop/NetworkManager |
Various NM interfaces |
| Power/Battery | org.freedesktop.UPower |
/org/freedesktop/UPower |
org.freedesktop.UPower.Device |
| Bluetooth | org.bluez |
Varies | org.bluez.Adapter1, org.bluez.Device1 |
| Login/Session | org.freedesktop.login1 |
/org/freedesktop/login1 |
org.freedesktop.login1.Manager |
| AppIndicator | org.kde.StatusNotifierWatcher |
/StatusNotifierWatcher |
org.kde.StatusNotifierWatcher |
Additional GNOME Subsystems
Power Management
Architecture
+-----------------------------------------------+
| GNOME Settings / Shell / Control Center | session bus clients
+-----------------------------------------------+
| gnome-settings-daemon / gsd-power | session bus: org.gnome.SettingsDaemon.Power
| gsd-power-manager.c (core logic) |
| gsd-backlight.c (display/kbd brightness) |
+-----------------------------------------------+
| power-profiles-daemon | system bus: net.hadess.PowerProfiles
+-----------------------------------------------+
| UPower | system bus: org.freedesktop.UPower
| /org/freedesktop/UPower |
| /org/freedesktop/UPower/devices/* |
| /org/freedesktop/UPower/KbdBacklight |
+-----------------------------------------------+
| systemd-logind | system bus: org.freedesktop.login1
| HandleLidSwitch, Inhibit |
+-----------------------------------------------+
| Kernel (sysfs, udev, /dev/input/*) |
+-----------------------------------------------+
Key D-Bus Interfaces
org.freedesktop.UPower (system bus):
| Method/Property | Purpose |
|---|---|
EnumerateDevices() |
List all power devices |
OnBattery (prop) |
Whether running on battery |
LidIsClosed (prop) |
Lid switch state |
org.freedesktop.UPower.Device (per-device):
| Property | Purpose |
|---|---|
Type |
1=line-power, 2=battery, 6=keyboard, etc. |
State |
0=unknown, 1=charging, 2=discharging, 4=full |
Percentage |
Battery percentage |
TimeToEmpty / TimeToFull |
Estimated seconds |
ChargeStartThreshold / ChargeEndThreshold |
Battery charge limits |
ChargeThresholdSupported |
Whether thresholds are supported |
org.freedesktop.UPower.KbdBacklight (system bus):
| Method | Purpose |
|---|---|
GetMaxBrightness() |
Maximum keyboard backlight level |
GetBrightness() |
Current level |
SetBrightness(value) |
Set level |
net.hadess.PowerProfiles (system bus):
| Property | Purpose |
|---|---|
ActiveProfile |
“power-saver”, “balanced”, or “performance” |
Profiles |
Available profiles with degradation info |
Suspend/Hibernate Flow
1. Idle timeout fires (gnome_idle_monitor_add_idle_watch)
-> idle_set_mode(GSD_POWER_IDLE_MODE_SLEEP)
2. do_power_action_type() reads setting:
- On battery: sleep-inactive-battery-type
- On AC: sleep-inactive-ac-type
3. For suspend: gnome_session_shutdown_type("Suspend")
-> org.freedesktop.login1.Manager.Suspend via systemd-logind
4. Inhibitors: gsd-power acquires logind inhibitor locks
(delay type for sleep/idle) to prevent premature suspend
Lid Switch Flow
1. systemd-logind detects lid switch via /dev/input or ACPI
-> emits LidClosed signal
2. gsd-power monitors UPower's LidIsClosed property
OR receives logind's PrepareForSleep signal
3. gsd-power checks gsettings:
- lid-close-ac-action (default: "suspend")
- lid-close-battery-action (default: "suspend")
4. External monitor check: if multiple displays attached,
gsd-power acquires inhibitor lock "Multiple displays attached"
-> blocks logind's HandleLidSwitch
5. Action dispatched via do_power_action_type()
Idle Dimming Flow
idle_configure() in gsd-power-manager.c:
1. Checks idle-dim setting and idle-delay timeout
2. Sets up gnome_idle_monitor_add_idle_watch for DIM
3. On DIM trigger:
- Reads idle-brightness percentage
- display_backlight_dim(): saves current, sets dim level
- kbd_backlight_dim(): dims keyboard
4. Sets up BLANK watch (next stage)
5. On BLANK: backlight_disable(), toggle kbd off
6. Sets up SLEEP watch (final stage)
7. On SLEEP: do_power_action_type()
8. On NORMAL (user active): restore saved brightness
Key GSettings Keys
| Schema | Key | Purpose |
|---|---|---|
org.gnome.settings-daemon.plugins.power |
sleep-inactive-ac-type |
Action on AC idle (suspend/hibernate/nothing) |
org.gnome.settings-daemon.plugins.power |
sleep-inactive-battery-type |
Action on battery idle |
org.gnome.settings-daemon.plugins.power |
lid-close-ac-action |
Lid close on AC |
org.gnome.settings-daemon.plugins.power |
lid-close-battery-action |
Lid close on battery |
org.gnome.settings-daemon.plugins.power |
idle-dim |
Whether to dim display before blank |
org.gnome.settings-daemon.plugins.power |
idle-brightness |
Dim brightness percentage |
Key Source Files
| File | Role |
|---|---|
plugins/power/gsd-power-manager.c |
Core: idle handling, lid switch, suspend/hibernate, battery warnings |
plugins/power/gsd-backlight.c |
Display backlight abstraction |
power-profiles-daemon/src/ppd-main.c |
Power profiles daemon |
upower/src/up-main.c |
UPower daemon |
upower/src/up-device.c |
UPower device implementation |
upower/src/up-kbd-backlight.c |
Keyboard backlight LED interface |
Screen Locking
Architecture
Since GNOME 3.5.5 (2012), screen locking is handled natively by GNOME Shell. The standalone gnome-screensaver is deprecated.
+-----------------------------------------------+
| Triggers |
| - Ctrl+Alt+L (gsd-media-keys) |
| - System menu Lock button |
| - Idle timeout (gsd-power -> screenShield) |
+-----------------------------------------------+
| GNOME Shell |
| js/ui/screenShield.js (lock screen UI) |
| org.gnome.ScreenSaver D-Bus interface |
+-----------------------------------------------+
| GDM (for unlock authentication) |
| org.gnome.DisplayManager D-Bus (system bus) |
| PAM authentication |
+-----------------------------------------------+
| systemd-logind |
| org.freedesktop.login1.Session.Lock/Unlock |
+-----------------------------------------------+
D-Bus Interfaces
org.gnome.ScreenSaver (session bus, gnome-shell):
| Method | Purpose |
|---|---|
Lock() |
Immediately lock screen |
GetActive() |
Whether screensaver is active |
GetActiveTime() |
Seconds since activation |
SetActive(active) |
Enable/disable screensaver |
| Signal | Purpose |
|---|---|
ActiveChanged(boolean) |
true = locked, false = unlocked |
org.freedesktop.ScreenSaver (freedesktop standard, also implemented by gnome-shell):
| Method | Purpose |
|---|---|
Lock() |
Lock screen |
SimulateUserActivity() |
Prevent screensaver activation |
Lock Flow
1. Idle detected by gnome_idle_monitor
OR manual lock via Ctrl+Alt+L / system menu
2. screenShield.deactivate() called
-> Creates lock screen group with clock, notification box
-> Slides curtain overlay down (1.2s animation)
-> Grabs keyboard/pointer input
-> Emits ActiveChanged(true)
3. User presses key/moves mouse -> unlock dialog appears
-> PAM authentication via org.gnome.DisplayManager (GDM)
-> On success: curtain slides up
-> Emits ActiveChanged(false)
Key GSettings Keys (org.gnome.desktop.screensaver)
| Key | Default | Purpose |
|---|---|---|
idle-delay |
300 | Seconds before blanking |
lock-enabled |
true | Lock when screen blanks |
lock-delay |
0 | Seconds after blanking before lock |
show-notifications |
true | Show notifications on lock screen |
Key Source Files
| File | Role |
|---|---|
js/ui/screenShield.js |
Core lock screen: curtain, clock, notifications, unlock dialog |
js/ui/shellDBus.js |
Registers org.gnome.ScreenSaver D-Bus interface |
src/shell-screen-saver-dbus.c |
C D-Bus skeleton |
plugins/media-keys/gsd-media-keys-manager.c |
Ctrl+Alt+L shortcut handler |
gdm/daemon/gdm-manager.c |
GDM session management, PAM verification |
Screenshots / Recording
Architecture
+-----------------------------------------------+
| Applications |
| gnome-screenshot (legacy) |
| Sandboxed apps (Flatpak) |
+-----------------------------------------------+
| XDG Desktop Portal (session bus) |
| org.freedesktop.portal.Screenshot |
| org.freedesktop.portal.ScreenCast |
+-----------------------------------------------+
| xdg-desktop-portal-gnome (backend) |
| Bridges portal to gnome-shell APIs |
+-----------------------------------------------+
| GNOME Shell (session bus) |
| org.gnome.Shell.Screenshot |
| org.gnome.Shell.Screencast |
+-----------------------------------------------+
| PipeWire |
| pw_stream, pipewiresrc (GStreamer) |
+-----------------------------------------------+
org.gnome.Shell.Screenshot (session bus)
| Method | Purpose |
|---|---|
Screenshot(flash, filename) |
Full screen capture |
ScreenshotWindow(frame, cursor, flash, filename) |
Window capture |
ScreenshotArea(x, y, w, h, flash, filename) |
Area capture |
InteractiveScreenshot() |
Interactive overlay mode |
PickColor() |
Color picker |
SelectArea() |
User selects region |
org.freedesktop.portal.Screenshot (session bus)
| Method | Purpose |
|---|---|
Screenshot(parent_window, options) |
Capture with options (modal, interactive, target) |
PickColor(parent_window, options) |
Color picker |
Options target bitmask: 1=Screen, 2=Window, 4=Area, 8=ActiveWindow
org.freedesktop.portal.ScreenCast (session bus)
| Method | Purpose |
|---|---|
CreateSession(options) |
Create screencast session |
SelectSources(session, options) |
Select monitors/windows, cursor mode |
Start(session, parent_window, options) |
Start capture, returns PipeWire node IDs |
OpenPipeWireRemote(session, options) |
Returns PipeWire fd for stream connection |
Options: types(u) (1=MONITOR, 2=WINDOW), cursor_mode(u) (1=Hidden, 2=Embedded, 4=Metadata), persist_mode(u)
PipeWire Screencast Flow
1. App calls CreateSession()
2. App calls SelectSources(types=MONITOR, cursor_mode=EMBEDDED)
3. App calls Start()
-> Portal shows source selection dialog
-> Mutter creates PipeWire stream node
-> Returns: streams = [{node_id, properties: {position, size}}]
4. App calls OpenPipeWireRemote()
-> Returns fd -> app connects: pw_context_connect_fd(fd)
-> Frames arrive as DMA-BUF or video format buffers
5. App closes Session -> PipeWire stream destroyed
Screen Recording Indicator
When recording active (Ctrl+Shift+Alt+R or D-Bus):
Shell.Recordercreates GStreamer pipeline:pipewiresrc -> vp8enc -> webmmux -> filesink- Red circle indicator with elapsed time appears in top bar
- Clicking indicator stops recording
- Default max: 30s (configurable via
org.gnome.settings-daemon.plugins.media-keys max-screencast-length)
Key Source Files
| File | Role |
|---|---|
js/ui/screenshot.js |
Interactive screenshot overlay, Print Screen handler |
src/shell-screenshot.c |
C: pixel capture via stage_paint_to_buffer() |
src/shell-recorder.c |
C: screen recording, GStreamer pipeline |
js/dbusServices/screencast/screencastService.js |
Screencast D-Bus service |
xdg-desktop-portal-gnome/src/screenshot.c |
Portal screenshot backend |
xdg-desktop-portal-gnome/src/screencast.c |
Portal screencast backend |
Input Methods
Overview
GNOME integrates IBus (Intelligent Input Bus) as its default input method framework. The system provides a unified UI for keyboard layouts (XKB) and input methods (IBus engines) via “input sources.”
GSettings Schema (org.gnome.desktop.input-sources)
| Key | Type | Purpose |
|---|---|---|
sources |
a(ss) |
Input sources: ("xkb","us") or ("ibus","anthy") |
mru-sources |
a(ss) |
Most recently used sources |
xkb-options |
as |
XKB options (e.g. compose:ralt) |
per-window |
b |
Different sources per window |
show-all-sources |
b |
Show all installed sources |
Data Flow (Wayland – Composer Mode)
User types -> GTK4 app -> Wayland text-input protocol -> Mutter
-> org.freedesktop.IBus.InputContext D-Bus -> ibus-daemon
-> IBus engine (e.g. ibus-libpinyin) processes input
-> commit signal back through Mutter -> GTK4 app
Data Flow (X11)
User types -> GTK app -> GtkIMContext -> IBus (GTK_IM_MODULE=ibus)
-> ibus-daemon -> engine -> commit signal -> GTK app
Input Source Switching
- Triggered via
Super+Space(default) ororg.gnome.desktop.wm.keybindings switch-input-source gsd-keyboard-manager.cwatchescurrentkey changes- For IBus: calls
org.freedesktop.IBus.InputContext.SetEngine() - For XKB: applies new layout via XKB API
fcitx5 Support
Users set GTK_IM_MODULE=fcitx, XMODIFIERS=@im=fcitx5, QT_IM_MODULE=fcitx5. GNOME’s sources list doesn’t have a native “fcitx” type – users typically use fcitx5’s IBus compatibility layer or manage it externally.
Key Source Files
| File | Role |
|---|---|
plugins/keyboard/gsd-keyboard-manager.c |
Applies XKB config, switches IBus engines |
src/wayland/meta-wayland-text-input.c |
Wayland text-input protocol handling |
src/wayland/meta-wayland-input-method.c |
Wayland input-method protocol |
bus/inputcontext.c |
IBus InputContext D-Bus implementation |
Accessibility
Architecture (Two-Layer Bus)
GNOME accessibility uses a separate D-Bus bus (not the session bus) for the chatty AT-SPI protocol.
Session Bus: Accessibility Bus (separate daemon):
org.a11y.Bus org.a11y.atspi.Registry
| |
GetAddress() returns address --> Registry.RegisterEvent()
org.a11y.atspi.Accessible.*
org.a11y.atspi.Action.*
org.a11y.atspi.Event.*
The accessibility bus runs at /run/user/UID/at-spi/bus_0.
D-Bus Interfaces
| Interface | Bus | Purpose |
|---|---|---|
org.a11y.Bus |
Session | Entry point: GetAddress() |
org.a11y.Status |
Session | IsEnabled, ScreenReaderEnabled properties |
org.a11y.atspi.Registry |
A11y Bus | Event registration |
org.a11y.atspi.Accessible |
A11y Bus | Base: Name, Description, Role, Children |
org.a11y.atspi.Action |
A11y Bus | GetNActions(), DoAction() |
org.a11y.atspi.Event |
A11y Bus | Focus, state-changed, window events |
GSettings Schemas
org.gnome.desktop.a11y.applications:
| Key | Purpose |
|---|---|
screen-reader-enabled |
Launches Orca |
screen-magnifier-enabled |
Launches gnome-mag |
org.gnome.desktop.a11y.keyboard:
| Key | Purpose |
|---|---|
slowkeys-delay |
Hold time before key registers (ms) |
bouncekeys-delay |
Ignore period after keypress (ms) |
stickykeys-enable |
Modifier sequences without holding |
org.gnome.desktop.a11y.interface:
| Key | Purpose |
|---|---|
high-contrast |
High contrast theme |
large-text |
Large text mode |
text-scaling-factor |
Fine-grained text scaling |
Data Flow
Application (GTK3) -> ATK API -> atk-adaptor (in-process)
-> D-Bus -> accessibility bus -> libatspi -> pyatspi2 -> Orca
-> Speech Dispatcher / liblouis (braille) -> User
Application (GTK4) -> D-Bus directly (no ATK intermediary)
-> accessibility bus -> libatspi -> Orca
Key Source Files
| File | Role |
|---|---|
plugins/a11y-settings/gsd-a11y-settings-manager.c |
Enables toolkit-accessibility when a11y active |
plugins/a11y-keyboard/ |
Applies slow/bounce/sticky keys to XKB |
registryd/ |
at-spi2-registryd – app registry, event routing |
bus/at-spi-bus-launcher.c |
Launches accessibility bus |
atk-adaptor/ |
Translates ATK API to AT-SPI D-Bus |
src/orca/ |
Orca screen reader |
Color Management
Architecture
Color management spans three layers: colord (system daemon, device/profile registry), gsd-color (night light tracking), and Mutter (owns color device management and profile application).
D-Bus Interfaces (colord, system bus)
| Interface | Purpose |
|---|---|
org.freedesktop.ColorManager |
Top-level: GetDevices(), GetProfiles() |
org.freedesktop.ColorManager.Device |
Per-device: GetProfiles(), SetProfile() |
org.freedesktop.ColorManager.Profile |
Per-profile: GetFilename(), GetMetadata() |
org.freedesktop.ColorManager.Sensor |
Calibration device |
Persistent Storage
| Path | Purpose |
|---|---|
/var/lib/colord/mapping.db |
Device-to-profile mappings |
/var/lib/colord/storage.db |
Profile metadata |
/var/lib/colord/icc/ |
System-wide ICC profiles |
~/.local/share/icc/ |
Per-user ICC profiles |
Data Flow
Monitor connected -> Mutter (MetaMonitorManager) detects via KMS/udev
-> MetaColorManager creates MetaColorDevice
-> MetaColorDevice creates colord Device (D-Bus)
-> MetaColorStore resolves ICC profile:
1. Check colord for assigned profile
2. Check ~/.local/share/icc/ for user profiles
3. Generate from EDID as fallback
-> MetaColorDevice applies profile:
- X11: set _ICC_PROFILE atom, load VCGT gamma LUT
- Wayland: apply color transform matrix to compositor
-> Night light: mutter reads temperature from gsd-color D-Bus
Mutter Color Classes
MetaColorManager– singleton, createsMetaColorDeviceper monitorMetaColorManagerX11– X11: sets_ICC_PROFILEatoms, loads VCGTMetaColorDevice– per-monitor, creates colord device, applies profileMetaColorProfile– ICC profile abstraction (EDID-generated, standard, calibration)MetaColorStore– caches profiles, watches~/.local/share/icc/
gsd-color Current Role
After mutter integration, gsd-color is reduced to:
- Tracking night light state (on/off, temperature)
- Exposing via
org.gnome.SettingsDaemon.Power.ScreenD-Bus - Mutter reads this and applies warm color temperature filter
Key Source Files
| File | Role |
|---|---|
plugins/color/gsd-color-manager.c |
Night light tracking |
src/backends/meta-color-manager.c |
Main color management object |
src/backends/meta-color-manager-x11.c |
X11 ICC atom, VCGT |
src/backends/meta-color-device.c |
Per-monitor colord device |
src/backends/meta-color-profile.c |
ICC profile abstraction |
src/backends/meta-color-store.c |
Profile cache, watches user ICC dir |
Window Management
Overview
Mutter is both a Wayland compositor and window manager library. It handles keybindings, workspaces, tiling, focus, and compositing.
Keybinding Schemas
| Schema | Purpose |
|---|---|
org.gnome.desktop.wm.keybindings |
Shared WM keybindings (legacy metacity port) |
org.gnome.mutter.keybindings |
Mutter-specific keybindings |
org.gnome.mutter.wayland.keybindings |
Wayland-specific keybindings |
org.gnome.shell.keybindings |
Shell keybindings (override wm.keybindings when both define same action) |
Keybinding Data Flow
Input event (libinput)
-> Clutter event processing
-> process_event() in keybindings.c
-> lookup in key_bindings hash table (combo + layout index)
-> invoke_handler() -> MetaKeyHandler.func()
-> handle_switch_to_workspace(), handle_toggle_tiled(), etc.
Window Tiling
MetaTileMode:
META_TILE_NONE, META_TILE_LEFT, META_TILE_RIGHT, META_TILE_MAXIMIZED
MetaTileZone (constraint-based, WIP):
MAXIMIZED_HORZ, MAXIMIZED_VERT, MAXIMIZED,
W (left), E (right), N (top), S (bottom),
NW, NE, SW, SE (quarters)
Tiling flow:
- Keybinding triggers
handle_toggle_tiled() - Sets
window->tile_monitor_number - Calls
meta_window_tile(window, mode) - Computes target rectangle via
get_tile_zone_area() - Constraint engine applies tile zone constraints
Tile matching: meta_window_compute_tile_match() finds complementary window (LEFT<->RIGHT). Resizing one auto-resizes the sibling.
Mutter Plugin API
Plugins are shared libraries. GnomeShellPlugin is the concrete implementation.
Plugin virtual methods:
start, minimize, unminimize, size_changed, size_change, map, destroy,
switch_workspace, show_tile_preview, hide_tile_preview,
show_window_menu, keybinding_filter, confirm_display_change,
create_close_dialog, locate_pointer
Each effect must call meta_plugin_*_completed() when done.
Key Source Files
| File | Role |
|---|---|
src/core/keybindings.c |
Keybinding manager, grab/ungrab, dispatch |
src/core/meta-accel-parse.c |
Accelerator string parser |
src/core/display.c |
MetaDisplay – central singleton |
src/core/window.c |
MetaWindow – tiling, maximize, minimize |
src/core/constraints.c |
Constraint engine (tile zones, placement) |
src/core/place.c |
Window placement algorithm |
src/meta/meta-workspace-manager.h |
Workspace management API |
src/meta/meta-plugin.h |
Plugin abstract class |
src/gnome-shell-plugin.c |
GNOME Shell’s plugin implementation |
Wayland / Portals
Architecture
The portal system provides sandboxed apps access to desktop features through D-Bus.
+-----------------------------------------------+
| Sandboxed Apps (Flatpak/snap) |
+-----------------------------------------------+
| xdg-desktop-portal (frontend) |
| Bus: org.freedesktop.portal.Desktop |
| Routes to backend based on XDG_CURRENT_DESKTOP|
+-----------------------------------------------+
| xdg-desktop-portal-gnome (backend) |
| Implements org.freedesktop.impl.portal.* |
| Bridges to GNOME-specific D-Bus APIs |
+-----------------------------------------------+
| GNOME Shell / Mutter / other daemons |
+-----------------------------------------------+
Key Portal Interfaces
| Interface | Purpose |
|---|---|
org.freedesktop.portal.FileChooser |
File open/save dialogs |
org.freedesktop.portal.ScreenCast |
Screen capture via PipeWire |
org.freedesktop.portal.RemoteDesktop |
Remote desktop (input + capture) |
org.freedesktop.portal.Screenshot |
Screenshot capture |
org.freedesktop.portal.Settings |
Desktop settings (font, theme) |
org.freedesktop.portal.Notification |
Desktop notifications |
org.freedesktop.portal.Inhibit |
Inhibit screensaver/logout |
org.freedesktop.portal.Background |
Background activity management |
org.freedesktop.portal.Wallpaper |
Wallpaper setting |
org.freedesktop.portal.Clipboard |
Clipboard access |
org.freedesktop.portal.InputCapture |
Input capture for remote desktop |
Backend Selection
-
Backend declares in
/usr/share/xdg-desktop-portal/portals/gnome.portal:[portal] Interfaces=org.freedesktop.impl.portal.FileChooser;... UseIn=gnome -
xdg-desktop-portalreads$XDG_CURRENT_DESKTOP -
For each interface, selects backend via
.portalfiles -
Frontend creates proxy to backend’s
org.freedesktop.impl.portal.*
Portal vs Direct D-Bus
| Aspect | Portal | Direct D-Bus |
|---|---|---|
| Sandboxing | Works in Flatpak/snap | Only outside sandbox |
| UI | Native desktop dialogs | No UI, direct call |
| Security | Permission store, user consent | Trusts caller |
| File access | FUSE filesystem / document IDs | Direct paths |
| Portability | Desktop-agnostic | Desktop-specific |
Key Source Files
| File | Role |
|---|---|
src/xdg-desktop-portal.c |
Frontend: owns bus name, routes to backends |
src/portal-impl.c |
Backend discovery |
src/request.c |
Request lifecycle |
src/file-chooser.c |
FileChooser frontend |
src/screen-cast.c |
ScreenCast frontend |
xdg-desktop-portal-gnome/src/filechooser.c |
GTK4 file chooser dialog |
xdg-desktop-portal-gnome/src/screencast.c |
Screencast via gnome-shell |
xdg-desktop-portal-gnome/src/screenshot.c |
Screenshot via gnome-shell |
xdg-desktop-portal-gnome/src/remotedesktop.c |
Remote desktop |
Search Providers
Architecture
GNOME Shell’s overview search uses a search provider architecture. Text input is dispatched to registered providers, which return results asynchronously.
D-Bus Interface: org.gnome.Shell.SearchProvider2
| Method | Args | Purpose |
|---|---|---|
GetInitialResultSet |
(as) terms |
First search results |
GetSubsearchResultSet |
(as) previous, (as) terms |
Refined results |
GetResultMetas |
(as) identifiers |
Result metadata (name, icon, description) |
ActivateResult |
(s) id, (as) terms, (u) timestamp |
Open selected result |
LaunchSearch |
(as) terms, (u) timestamp |
Open full search view |
Registration (Application Providers)
.ini file in $(datadir)/gnome-shell/search-providers/:
[Shell Search Provider]
DesktopId=org.gnome.Nautilus.desktop
BusName=org.gnome.Nautilus
ObjectPath=/org/gnome/Nautilus/SearchProvider
Version=2
Registration (Extension Providers)
class MySearchProvider {
getInitialResultSet(terms, cancellation) { /* return string[] */ }
getSubsearchResultSet(previousResults, terms, cancellation) { /* ... */ }
getResultMetas(ids, cancellation) { /* return ResultMeta[] */ }
activateResult(id, terms, timestamp) { /* open result */ }
}
Main.overview.searchController.addProvider(provider);
ResultMeta Properties
| Property | Type | Purpose |
|---|---|---|
id |
s |
Unique identifier |
name |
s |
Display name |
icon / gicon / icon-data |
various | App icon |
description |
s |
Optional description |
clipboardText |
s |
Text for clipboard on activation |
Built-in Providers
- Application Search –
.desktopapps, Flatpak apps (always active) - Calculator – arithmetic expressions
- Terminal commands – suggests CLI commands
- Settings – GNOME Settings panels
- File search – via Localsearch/Tracker (TinySPARQL)
Data Flow
User types "foo" in overview search
-> SearchController dispatches to all providers:
1. AppSearchProvider: fuzzy match apps
2. External providers (D-Bus): GetInitialResultSet(["foo"])
3. Extension providers (in-process)
-> GetResultMetas for top results
-> SearchResults renders grouped results (max 3 per provider)
-> Click result: ActivateResult()
-> Click provider icon: LaunchSearch()
Localsearch (Tracker) Integration
- TinySPARQL (
tsparql): RDF triple store, SQLite backend - Localsearch: Miner daemon, crawls filesystem, extracts metadata
- D-Bus:
org.freedesktop.Tracker3.Miner– pause, resume, status - gnome-shell queries Localsearch via TinySPARQL (built into shell’s C code)
Key Source Files
| File | Role |
|---|---|
js/ui/search.js |
SearchController, SearchProviderManager |
js/ui/searchResults.js |
Renders search results, groups by provider |
src/app-search-provider.c |
Built-in app/flatpak search |
src/shell-search-provider.c |
D-Bus proxy to external SearchProvider2 |
src/shell-app-system.c |
App registry |
