feat(desktop): add XDG portals module for in-app screen sharing (task 0030)
Add modules.desktop.portals, enabled by the desktop aggregator, pinning the XDG desktop portal routing explicitly: the three interfaces the Hyprland portal implements (screencast, screenshot, global shortcuts) go to Hyprland, and GTK is the default for file dialogs and appearance. The backend packages already arrive with the Hyprland compositor integration, so this module owns only the routing, which was previously empty and rode on the config file the Hyprland package happens to ship. Making it a first-class module so in-app screen sharing does not depend on that incidental default.
This commit was merged in pull request #22.
This commit is contained in:
@@ -12,7 +12,24 @@ In-app screen sharing depends on these regardless of whether the recorder is pre
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] A portals module exists in the desktop group and is enabled by the aggregator.
|
||||
- [ ] The Hyprland desktop portal (screencast, screenshot, global shortcuts) and the GTK portal (file dialogs, appearance) are both configured.
|
||||
- [ ] In-app screen sharing is available independent of the screen recorder.
|
||||
- [ ] neogaia builds green under `nix flake check`.
|
||||
- [x] A portals module exists in the desktop group and is enabled by the aggregator.
|
||||
- [x] The Hyprland desktop portal (screencast, screenshot, global shortcuts) and the GTK portal (file dialogs, appearance) are both configured.
|
||||
- [x] In-app screen sharing is available independent of the screen recorder.
|
||||
- [x] neogaia builds green under `nix flake check`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- **The module owns routing, not the backend packages.**
|
||||
The Hyprland compositor integration (`programs.hyprland`) already forces both portal backends into `xdg.portal.extraPortals` — `xdg-desktop-portal-hyprland` through its `portalPackage`, and `xdg-desktop-portal-gtk` through nixpkgs' `wayland-session.nix` (`enableGtkPortal` defaults on) — and turns `xdg.portal.enable` on.
|
||||
A portal backend only answers while its compositor runs, so those packages belong with the compositor and cannot be removed there; re-declaring them here would only duplicate them.
|
||||
The genuinely-missing, first-class piece was the routing: `xdg.portal.config` was empty, and which backend answered each request rode on a config file the Hyprland package happens to ship (`hyprland-portals.conf`, `default=hyprland;gtk`).
|
||||
This module makes that routing explicit and declarative.
|
||||
|
||||
- **Per-interface routing, not a preference list.**
|
||||
Rather than `default = [ "hyprland" "gtk" ]` (which tries Hyprland first for every interface and falls through to GTK), the three interfaces the Hyprland portal actually implements — `ScreenCast`, `Screenshot`, `GlobalShortcuts`, confirmed from its `hyprland.portal` file — are routed to Hyprland explicitly, and GTK is the default for everything else.
|
||||
This directly encodes the spec's split (Hyprland for the screen-facing requests, GTK for file dialogs and appearance) and keeps appearance on GTK even if a future Hyprland portal starts implementing `org.freedesktop.impl.portal.Settings`.
|
||||
|
||||
- **Already functional, now first-class.**
|
||||
Because the compositor integration already supplied both backends and a working shipped route, in-app screen sharing was effectively working before this task as an implicit side-effect.
|
||||
The deliverable is the explicit, aggregator-enabled `modules.desktop.portals` module, so the desktop's checklist reads completely and screen sharing no longer depends on a package's incidental default.
|
||||
Verified: the built config emits `/etc/xdg/xdg-desktop-portal/portals.conf` with `default=gtk` plus the three Hyprland routes, and neogaia's toplevel builds green.
|
||||
|
||||
@@ -15,6 +15,7 @@ in
|
||||
modules.desktop.hypridle.enable = lib.mkDefault true;
|
||||
modules.desktop.login.enable = lib.mkDefault true;
|
||||
modules.desktop.mako.enable = lib.mkDefault true;
|
||||
modules.desktop.portals.enable = lib.mkDefault true;
|
||||
modules.desktop.recording.enable = lib.mkDefault true;
|
||||
modules.desktop.rofi.enable = lib.mkDefault true;
|
||||
modules.desktop.screenshot.enable = lib.mkDefault true;
|
||||
|
||||
22
modules/desktop/portals.nix
Normal file
22
modules/desktop/portals.nix
Normal file
@@ -0,0 +1,22 @@
|
||||
{ config, lib, ... }:
|
||||
# XDG desktop portal routing for in-app screen sharing and file dialogs.
|
||||
let
|
||||
cfg = config.modules.desktop.portals;
|
||||
in
|
||||
{
|
||||
options.modules.desktop.portals.enable =
|
||||
lib.mkEnableOption "XDG desktop portals for in-app screen sharing and file dialogs";
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
# The backend packages arrive with the compositor, so only the routing is set
|
||||
# here.
|
||||
# GTK is the default backend, and the three compositor-native requests go to
|
||||
# Hyprland.
|
||||
xdg.portal.config.common = {
|
||||
default = [ "gtk" ];
|
||||
"org.freedesktop.impl.portal.ScreenCast" = [ "hyprland" ];
|
||||
"org.freedesktop.impl.portal.Screenshot" = [ "hyprland" ];
|
||||
"org.freedesktop.impl.portal.GlobalShortcuts" = [ "hyprland" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user