Commit Graph
623 Commits
Author SHA1 Message Date
Ashish Ajin c875ceda4d Hide the touchpad cursor when switching to direct touch (#424) 2026-10-10 15:02:38 -04:00
The412Banner 666abd134f Windows components: a recommended component is listed once, not again under All (#537)
The full list left out only the 'installed for this game' rows, never the recommendations, so
every recommended component appeared twice (DirectX 9 on Final Fantasy Resonance, both rows
switched on).
2026-10-10 14:54:28 -04:00
Muaz Kadan c115916962 Read the phone's motion sensors only while Steam asks for them (#534)
perf: only read the phone's motion sensors when Steam wants them

The gyro and accelerometer ran at 4 ms for the whole session, even in games without gyro, costing about 6% of a core. Steam already tells the Deck pad when it wants motion (setting 48), so libfakeinput now passes that on and PadMotion follows it, with a short delay to ride out Steam's brief toggles.
2026-10-10 14:44:05 -04:00
0579e688ba fix: preserve keyboard input on composite devices (#435)
* fix: preserve keyboard input on composite devices

* Fix composite input merge noteDevice call

---------

Co-authored-by: Jammo <[email protected]>
Co-authored-by: xXJsonDeruloXx <[email protected]>
2026-10-10 14:40:53 -04:00
ArthurandJames Yeung 6489232598 Fix NativeAOT GC region range defaults (#385)
Use the bare hex value accepted by older NativeAOT runtimes and CoreCLR. Cover the default and shared and per-game overrides.

Co-authored-by: James Yeung <[email protected]>
2026-10-10 14:38:47 -04:00
0x142857andxXJsonDeruloXx c23c436502 Controller: optional Select button that opens the Steam menu (#384)
* Controller: optional Select button that opens the Steam menu

* Controller: translate the Select-opens-Steam-menu option

* Controller: clearer wording for the Select-opens-Steam-menu option

* docs: evidence for the Select-opens-Steam-menu option

---------

Co-authored-by: xXJsonDeruloXx <[email protected]>
2026-10-10 14:38:07 -04:00
abduznik fad52ec125 Terminal: release createSubprocess's JNI local references, and the cwd chars against cwd (#527)
Fix JNI local reference leak in createSubprocess

The argv and envp loops took one local reference per element from
GetObjectArrayElement and never released it, so the references piled up
until the native call returned. ART aborts the process at 512 local
references ("local reference table overflow"), and both loops share the
table, so a long argument list plus a large environment could hit it.

Delete each element's local reference once its chars are copied and
released, after ReleaseStringUTFChars since the chars depend on the string.

Also release the cwd chars against cwd rather than cmd; the call passed
the wrong jstring.

Adds a host-side test that runs termux.c against a mock JNIEnv that counts
local references and checks release pairing. It needs a jni.h (JNI_INCLUDE,
JAVA_HOME or the NDK) and skips without one.

Fixes #507
2026-10-10 14:29:51 -04:00
Nicolás Gómez Solano d22e458d64 fix(audio): avoid InputStream.readAllBytes() for Android 12 compatibility (#531) 2026-10-10 14:29:46 -04:00
The412Banner 1b7cb4179d Windows components: leave out WebView2, which only Microsoft's installer can lay out (#532)
Its files sit in a container no extractor opens and may not be hosted, so a recording cannot
source them; installing it means running the installer in the prefix, which no runtime here
does. With it gone the waiting section is empty.
2026-10-10 14:03:04 -04:00
MaxsTechReviewandxXJsonDeruloXx c1c22dfd37 Launch the executable a Store package declares (#400)
Store and GDK folders name their game in MicrosoftGame.config or
appxmanifest.xml. Picking the top-level Unreal bootstrap instead failed
with "CreateProcess() returned 2" when the Store had renamed the
shipping exe.

Co-authored-by: xXJsonDeruloXx <[email protected]>
2026-10-10 13:46:03 -04:00
kmnkv1 0043cefab5 Rumble: don't restart the vibrator on every force-feedback packet (#514)
fix: stop restarting the vibrator on every force-feedback packet
2026-10-10 13:34:19 -04:00
kaosjammoandJammo 41f68ef1a1 Fix launcher fullscreen around display cutouts (#432)
Co-authored-by: Jammo <[email protected]>
2026-10-10 13:33:59 -04:00
The412Banner 9743ac3abc Windows components: leave out the OpenAL setup program, a twin of the DLL copy that installs here (#528) 2026-10-10 13:32:12 -04:00
SG3xHERO ca6cfcd193 Unfolded deck controls (#407) 2026-10-10 17:24:23 +00:00
Willie Yao d41424170a Controller editor: snap controls into line while dragging (#490) 2026-10-10 15:11:50 +00:00
kmnkv1 f4678935c4 Odin 3: skip the low-latency Wi-Fi lock, whose WLAN firmware hang reboots the device (#512) 2026-10-10 11:06:29 -04:00
Kurt Himebauch 416eb41d8d feat(desktop): add desktop uninstall and legacy LXQt cleanup (#493) 2026-10-10 10:59:32 -04:00
Kurt Himebauch 6e0d456dd7 fix(amazon): sync library with nile's headers and registered serial (#500) 2026-10-10 10:58:18 -04:00
The412Banner 8ac555664a Windows components: Access 2000 runtime installs here (an MSI inside a 7-Zip-openable wrapper) (#505)
art2kmin.exe is Setup.exe + Data1.msi in a wrapper 7-Zip opens, so the MSI engine lays it out
like any other package; it was on the setup-program list by assumption.
2026-10-10 01:31:23 -04:00
The412Banner 4bf4e53ecf Build: verify the runtime inputs only after the session scripts are staged (#504)
With parallel task execution, verifyRuntimeInputs and stageSessionScripts could run at the
same time; main's build at 3d50e6b1 hashed droiddeck-netmanager mid-copy and failed with
'Missing or changed runtime input'. The check now runs after the staging tasks.
2026-10-10 00:38:23 -04:00
The412Banner 3d50e6b1ae Windows components: hide Vulkan RT and the IE8 update; honest captions for the waiting section (#502)
* Windows components: hide Vulkan RT, whose loader every Proton here ships

vulkan-1.dll is in lib/wine/x86_64-windows and i386-windows of Proton Experimental (ARM64),
GE-Proton and proton-cachyos alike, so the catalog's VulkanRT entry would only shadow it. It
joins the list the page leaves out.

* Windows components: the waiting section says what is really missing (a recording), not 'coming next'

* Windows components: leave out the IE8 security update, which patches a browser no prefix has

* Windows components: the waiting caption without an apostrophe the resource compiler rejects
2026-10-10 00:24:14 -04:00
The412Banner 61bfc04704 Windows components: hide the CJK fonts and PowerShell, which every Proton here ships (#496)
Proton Experimental (ARM64), GE-Proton and proton-cachyos all carry Malgun, MS Gothic, YaHei
and SimSun in share/fonts and Wine's PowerShell wrapper, so the catalog's cjkfonts and
powershell entries would only shadow what is already there. They join gecko and mono in the
list the page leaves out.
2026-10-09 23:13:53 -04:00
The412Banner 9b90386e73 Windows components: install from a recording of the installer's result (#495)
* Windows components: install from a recording of the installer's result

A catalog entry may name a 'snapshot': what its own setup program leaves in a prefix,
recorded once in Wine by winlator-contents' tools/snapshot/record.py (the files it places and
the registry values it writes, the self-registering DLLs' CLSID entries included). With one,
the setup program never runs here: the files come from the archive beside the recording, or
out of the vendor's installer by the paths the recording maps (small generated ones inline),
and the registry values go to registry.json for droiddeck-wincomponents to write at launch.
The steps a recording makes redundant are skipped; DLL overrides still apply. A component
with a recording counts as installable; its prerequisites must still be.

* droiddeck-msi-install --unpack: open archives nested inside an installer

QuickTime's cabinets and an NSIS pack's payloads sit inside the unpacked installer; they are
opened in place into '<name>.nested' folders, two levels deep, the same layout the component
recordings map their file sources to, so a recording's paths resolve on the device (QuickTime:
593 of 593).
2026-10-09 22:56:18 -04:00
Kurt Himebauchandmaxjivi05 ddc4c18faf Steam's touch controller as on-screen controls (beta) (#431)
* feat: Steam's touch controller as on-screen controls (beta)

* fix: Steam touch controls appear once the session makes the device; tidier default layout

* fix: Steam touch layout decoding, saved layouts and new sessions

* docs: Steam's touch controls

* feat: Steam's touch icons, labels and colours on the touch controls; pick and save them like Steam

* feat: Steam touch icon picker as in-session panels; layout colour; docs

* Give each physical controller its own player slot

Every controller fed the one exported pad, so two pads played as one.
The first controller keeps slot 0 (the Deck in a Steam session); further
ones get slots 1-3 as separate Xbox 360 pads, created on first input and
removed on disconnect. In Deck mode only the Steam client sees those
pads and hands them to games through Steam Input. Rumble follows the
slot it names.

* feat: Steam Link's touch menu, per-game input modes, action set editing, add/copy/paste, oval controls, paste control

* feat: Steam touch controls drawn as Steam Link draws them; Steam Link's touch menu and layout tray

* feat: Steam touch controls in DroidDeck's style, D-mark guide button, shake to hide

* refactor: Steam touch controls become an On-screen controls choice instead of a second dropdown

---------

Co-authored-by: maxjivi05 <[email protected]>
2026-10-09 21:12:46 -04:00
MaxsTechReview fb8361b197 Expanded Fastpaths for proot and increased performance up to 57% (#494)
* perf: fast path resolves links, /proc and glue as proot does, and answers uname, isatty and passwd

The fast path handed back to proot whatever crossed a symlink, /proc or a directory proot
only shows as glue, which is most of what Steam and Wine ask. It now walks a path the way
proot's canonicalize() does, so those calls stay in-process:

- links are followed in guest terms and their text detranslated as detranslate_path() does,
  including readlink into a buffer the kernel cut short and /proc's exe, cwd and fd links;
- a binding proot dropped at start is dropped here too, glue above a binding is ENOENT, and a
  last component proot cannot stat is left to the kernel;
- pipe and socket dirfds are ENOTDIR, rmdir("dir/") removes dir, and "." and ".." go to proot;
- a blocking accept() with a connection already waiting no longer goes to proot.

Also answered: uname() and gethostname() (proot's utsname never changes), isatty() (glibc
2.43 asks with TCGETS2, which proot rewrites) and getpwnam/getpwuid when nsswitch.conf
sends passwd to files first and the entry is there (Xwayland asks for every client).

equiv.py, equiv2.py and equiv3.py match line for line with and without the fast path
(222, 507 and 924 lines). Per call on the RedMagic: realpath 240 us -> 1.0 us,
realpath /proc/self/fd/N 408 -> 9.9, getpwuid 41.5 -> 4.6, uname 28 -> 0.006.

* perf: LD_AUDIT module skips library lookups proot would fail

ld.so looks each library up along the game's search path, and Proton puts the game's
directory, Steam's runtime and video directories and its own library directories ahead of
/usr/lib: 72% of ld.so's opens in an Among Us launch failed, each a round trip to proot.

libblaudit.so answers la_objsearch() for a candidate proot would certainly fail with ENOENT
(its directory walked as canonicalize() walks it, the name or a directory on the way missing).
It has no libc and maps the fast path's trampoline itself. Each lookup's first candidate is
still opened, since a skipped one fails with ld.so's errno as it stands, and the default
directories are never skipped, so dlerror() reads the same. droiddeck-proton and the extra
wrapper add it to LD_AUDIT when the fast path is on.

* perf: droiddeck-proton checks a tool's components with one sha256sum

Each program the launcher starts pays a dozen traced library lookups under the game's search
path before it does anything. One sha256sum over every listed file replaces one per file;
the check itself is unchanged.

* perf: build a locale archive for C.UTF-8

Every program loads the locale LANG names before main(). glibc ships C.UTF-8 as a directory
it looks for once per category under two spellings, before reading gconv's module lists:
about 30 opens, each a stop in proot, in every process of the session. droiddeck-session
builds /usr/lib/locale/locale-archive (and gconv's cache) once per glibc package, so that is
one open.

localedef names a finished archive by hard link, which Android refuses; with
DROIDDECK_LINK_RENAME=1 libblsession turns a refused link into a rename that will not replace
an existing name.

* perf: library beat starts its helpers only when what they read changed

Every 15 s the session ran droiddeck-seed-redists (some forty programs under proot) and, when
a library directory had changed, steam-compatibility: a burst of thousands of proot stops each
quarter minute, game loads included. The seeder now runs when a library changed or a prefix
(or Proton's template for them) is unmarked, the compat pass when a manifest, depot, tool or
config.vdf changed, both checked from bash without starting anything, and each every five
minutes regardless. The seeder reads its stamp and the time without a subshell each.

* perf: fakeinput opens pad.log on its first line

Every process the library is loaded in opened the session's pad.log at start, a stop in proot
on shared storage, and most never write to it. The file is now opened when there is a line to
write.

* docs: the fast path as it ships, the audit module and measured launch times

* fix: a game the app launches after an idle spell comes to the front

The Steam client brings a game it launched forward only while it counts someone as present,
which it reads from gamescope's input counter. A game the app launched after four or more
minutes without a touch started, mapped its window, and stayed behind the library page until
the next input (device: Palworld, Stardew Valley, Fallout: New Vegas, Mortal Kombat X; the same
on main). The session now watches a requested launch, and when the game's window is focusable
but the interface keeps focus for two polls, counts one input on gamescope's counter, as a key
would. Nothing changes for a launch the client already brings forward.
2026-10-09 20:55:18 -04:00
The412Banner a5fd64f9f2 Games: revamped add games feature (#492)
Adding and managing your own (non-Steam) games moves out of the Steam
settings into the Games tab, and works like Steam's own non-Steam
Properties.

- A + beside "Games N" opens a compact in-app picker: the storage first,
  then that storage's root, every folder, .exe files only. Picking an exe
  adds the game with its name, art, Custom badge and Steam shortcut.
- "Add all games in this folder" adds every game folder inside at once.
  A summary opens immediately and fills in as each game is found, with a
  "?" where the exe was a close call and a red X to remove a game.
- An edit button on each Custom game opens its editor: Name, Target
  (ranked exes, Other exe…), Start in, Launch options, the four pieces of
  art with thumbnails, and Remove. Edits go through the same Steam
  shortcut, so the appid never changes and nothing duplicates.
- Art chooser per piece: images in the game folder, Steam's official art,
  SteamGridDB alternatives, your own image, or back to automatic.
- Finding the exe: up to five folders deep, every exe scored (name match,
  Unreal -Shipping builds, bin folders and size up; launchers, crash
  reporters, installers, redistributables and depth down).
- Real titles from the game's files (Steam manifest, GOG info, the exe's
  version info), keeping the folder's spacing when both spell the same
  title, underscores read as spaces.
- Art: the exact Steam appid when the game names one, strict name
  matches otherwise, Steam's hashed asset paths for newer games,
  SteamGridDB as a fallback (built-in key from the SGDB_API_KEY secret,
  optional own key in Setup, sealed with the Keystore), and a cover made
  from the exe's icon when nothing else has one.
- Removing a game is instant and keeps its files; adding it again brings
  it back. Steam's shortcut list is rewritten once, in the background.
- The Games section is gone from Steam settings; folders added before
  keep listing their games. Artwork switch and SteamGridDB key are in
  Setup.
2026-10-09 19:50:03 -04:00
Kurt Himebauch e0a7ce4f88 fix(desktop): address KDE feedback and keep local builds in sync with CI (#488) 2026-10-09 21:35:37 +00:00
Kurt Himebauch b213ae77b4 feat(stores): bring the launcher's motion to the stores pages (#482)
* refactor(ui): share End session's step-out as StepOut

* feat(ui): let PageFlood carry a tile's art

* feat(stores): bring the launcher's motion to the stores pages

* fix(stores): lay out the pane's rows in a column

* fix(stores): a game page no longer leaves the pad's focus on a dead card and crashes the next press

* perf(stores): GOG remembers its non-games and the library cache loads off the main thread

* fix(ui): a step-out's backdrop never takes the pad's focus

* feat(stores): modes step out of the store chip, each store in its own colour, search in the header

* feat(stores): sign-in pages in the Steam tab's style and an are-you-sure for sign out

* style(stores): drop the sign-in page's store eyebrow, which the title already names

* style(stores): the sign-in page is the store's name and Sign in

* fix(ui): the focus ring follows a control until it stops and meets one still rising into place

* feat(stores): the store a pad's focus is on shows without A, and a press never lands on where it sent focus

* perf(stores): keep chip motion responsive while libraries change
2026-10-09 14:55:03 -04:00
The412Banner 6e5932cb68 Stores: seal the GOG, Epic and Amazon sign-in files with an Android Keystore key (#486)
The stores' sign-ins (files/stores/<store>/credentials.json: access and refresh
tokens, account id and name) were plain JSON. Other apps could not read them, but
every program in the Linux session runs as the app and could. They are now sealed
with AES-256-GCM under a non-exportable AndroidKeyStore key (StrongBox when the
device has one), so the session only ever sees ciphertext.

- Format: a versioned envelope {v, alg, iv, ct}, written atomically and readable
  only by the app. No new dependencies (javax.crypto and KeyStore).
- Migration: an existing plaintext file is sealed at the next start, checked by
  decrypting it, then the plaintext is removed; users stay signed in.
- No Keystore on the device: the file stays plain and the log says so once per
  start.
- A sealed file that can never be opened (tampered, key gone or invalidated,
  broken envelope) is removed and that store asks for sign-in again. A transient
  Keystore error keeps the file and retries.
2026-10-09 14:42:23 -04:00
The412Banner 38e3fa2a33 Logs: every log in app-private storage, shared as one scrubbed zip (#484)
Session folders, tool and installer logs and the stores' log now all live under the
app's private files/logs instead of Download/DroidDeck, and every existing "Share
logs" action bundles them into one zip that goes through a final scrub.

- Where: LinuxRuntime.logDir() = files/logs; sessions keep their dated folders and
  30-session pruning, tools/ and stores/ beside them. The "Logs" setting keeps its
  meaning. Game save backups stay in Download/DroidDeck/Saves.
- Migration: at first start the old session folders, tools/ and loose logs move from
  Download/DroidDeck into files/logs (Saves untouched), and every moved folder is
  scrubbed under the current rules.
- Scrubbing: one rule set (SecretScrub) for the stores' log and the zip. The scrub
  marker carries the rules version, so a rules change re-scrubs every folder at the
  next start (in the background, a few at a time). Steam login account names and
  emails, account-name fields, OAuth codes, tokens in URLs and private LAN
  addresses are removed; Windows exception codes and server addresses are kept.
- Share: one zip of the current session folder plus the last 7 days of stores/ and
  tools/, written to cache/share and handed to the share sheet.
2026-10-09 13:28:03 -04:00
The412Banner 8e1a676f19 Windows components: lay out installer .exe wrappers without running them (#480)
* Windows components: lay out installer .exe wrappers without running them

The components page could only take .msi packages apart; most catalog entries ship an
installer .exe, so VC++ runtimes, .NET Framework 4.0-4.8 and the .NET Core/5+ runtimes sat
under 'Need a Windows installer'. droiddeck-msi-install now opens those wrappers and lays
out the packages inside the same way:

- WiX bundles (Visual C++ 2012-2022, .NET Core/5+ desktop runtimes): the .wixburn section
  names the containers, each a cabinet found by its header (signing moves them); payloads
  get the names the bundle manifest lists, so each package finds its cab1.cab beside it.
  ARM64 packages are skipped, x86 and x64 both laid out.
- Self-extracting cabinets (Visual C++ 2005-2010): cabextract, external cabinet beside the
  package (vc_red.cab).
- Self-extracting 7-Zip archives (.NET Framework 4.0-4.8): 7-Zip, now bundled with the
  msitools (Arch Linux ARM 7zip 26.04: 7z + its 7z.so plugin, licences beside the others).
  The complete product (netfx_Full_*) wins over the 4.0 parts and the per-Windows copies.
- An .exe that is its own setup program (NSIS, InnoSetup) reports that it holds no package.
- --unpack opens an archive for the app: DirectX's redistributable for XACT's cabinet picks.

The app executes the remaining catalog steps offline: set_windows (HKCU\Software\Wine
Version), set_register_key, get_from_cab (through --unpack) and 'uninstall Wine Mono' (the
mscoree override beside it is what matters), and reads url/file_name the catalog nests under
'environment' on a few .NET entries. Setup-program installers stay in the waiting section
with a note that says what they are.

Verified on this branch's engine with msitools, cabextract and 7z: VC++ 2010 x64 (19 files,
61 values), VC++ 2022 x64 bundle (26 files, 66 values), .NET 4.0 (1053 files, 6056 values,
Framework64\v4.0.30319 with clr.dll and mscorlib.dll, NDP\v4 keys) and .NET 4.8 (1633
files, 522 GAC assemblies, 6495 values). Not yet run on a device.

* Windows components: the pressed row greys out and shows its own two-step progress bar

Pressing a switch now greys that row at once and runs a thin bar across it: the download
0..100, then the install 0..100, with a caption naming the file or the stage (a dependency's
name in front while that installs first). Turning a component off greys the row the same way
until the pick is saved. The page-wide bar at the bottom is gone; Done waits on the busy row.

droiddeck-msi-install reports how far along it is ('progress 37% placing files'): reading,
each cabinet, every 5% of files placed, the registry, done - and a wrapper maps each package
into its share, so a bundle's two packages run 10..55 and 55..100. The app parses the percent
and passes a typed Progress (component, stage, phase, percent) up to the editor.

* Windows components: the ones turned on sort to the top of the list

In 'All components' the picks for this game come first, in their usual alphabetical order
among themselves; turning one off returns it to its place. The row moves once the install has
finished and the pick is saved, not while its progress bar is running.

* Windows components: an 'Installed for this game' section under the recommendations

What is turned on for this game gets its own section between Recommended and All components,
alphabetical; the recommendations stay where they are (a recommended pick stays there). A
component in the section leaves All components, and goes back to its place when turned off.
LB/RB jump through the new section too.
2026-10-09 12:36:05 -04:00
The412Banner 7c946db440 Stores: GOG, Epic Games and Amazon Games libraries, installs and cloud saves (#476)
A Stores section (rail, under Games; Setup › Stores gate) with each store's sign-in,
library, storefront shelves and a download queue. Each store has two tabs, Store and
Library, and Library filters to All or Installed; libraries open from a saved copy
and refresh in the background, with install sizes on every card. Games install to internal storage,
or a card chosen at Install time, and are registered in the Steam client as non-Steam
games, so they launch through Steam and droiddeck-proton from either the front end or
the client.

- Downloads: GOG, Epic and Amazon engines in Rust (app/src/main/rust/stores, built by
  cargo-ndk, nothing compiled in the tree). One adaptive fetch core with a latency
  brake, stalled-host handoff and every CDN a store offers. Per-stage progress,
  pause/resume, two-step cancel that deletes, failed downloads kept for retry, a
  foreground service with Wi-Fi and wake locks and notification controls.
- Games tab: store source chips (Steam, GOG, Epic, Amazon, Custom) and store art.
- Epic: per-launch exchange code from the app and from Steam's Play button,
  "Epic sign-in (EOS)", "Launch offline", and a game's web links opened in Android's
  browser for EOS consent. The EOS overlay crashed games and is left out.
- Cloud saves (GOG, Epic): pulled before launch, pushed after the game or the session
  ends, no upload before a first download, conflicts never overwritten, backups both
  ways.
- Logs: every store line redacted; the engine log goes to daily files.
2026-10-09 11:08:17 -04:00
Kurt Himebauch eaf26c8a20 feat: replace the LXQt desktop with SteamOS-style KDE Plasma (#473)
* feat: replace the LXQt desktop with SteamOS-style KDE Plasma

* feat: leaving the KDE desktop logs out through Plasma and returns to gaming mode

* feat: DroidDeck logo wallpaper as the KDE desktop default

* feat: build the KDE wallpaper from the DroidDeck mark artwork

* ci: keep the built desktop package as a short-lived artifact for device testing

* fix: the desktop loading screen no longer promises Steam on the desktop

* docs: the output resize comments name the desktop's KWin

* fix: the desktop package verifies every package's Arch Linux ARM signature and never replaces a published tag

* fix: programs sent to the GPU from the desktop drop its software rendering overrides

* fix: an interrupted desktop install no longer counts as installed

* feat: pin the desktop package to its DroidDeck-Components release instead of the catalog
2026-10-09 10:39:50 -04:00
SG3xHERO 32054e156e Add a Follow screen resolution for foldables (#403) 2026-10-09 07:13:06 -04:00
Kurt Himebauch c101a451e3 perf: fast path answers Steam's pre-2.33 stat calls and stays off without the patched proot (#466) 2026-10-09 03:14:29 +00:00
Kurt Himebauch a76ba69217 fix: runtime removal never strands an undeletable leftover (#463) 2026-10-08 21:39:00 -04:00
Kurt Himebauch 134fa167fe feat: install Flatpak apps from a .flatpak file (#446) 2026-10-08 14:13:32 -04:00
The412BannerandThe412Banner da42a5d7a7 DirectAudio from its own release: driver set per Proton interface (CachyOS fix), the Steam client's own DirectAudio sink, binaries out of tree (#439)
DirectAudio from its own release: driver set per Proton audio interface (CachyOS fix), the Steam client's own DirectAudio sink, binaries out of tree

Games
- Two driver sets ship from the pinned DirectAudio release (tools/directaudio/release.env =
  directaudio-linux-v1.1.0, sha256-checked by tools/directaudio/fetch.sh in CI and
  build_local.sh): linux-wine11 for Valve Proton 11 / Experimental / GE-Proton, and
  linux-wine11-systhread for Proton-CachyOS, whose Wine carries the system-thread mmdevapi
  interface. steam-compatibility picks by whether the Proton's own winepulse.so imports
  PsCreateSystemThread, never by the version string (both say wine-11.0; the wrong set is
  silence). No matching set: DirectAudio off, Proton's audio runs, logged.
- Proton-CachyOS's launcher pre-sets WINE_AUDIO_DRIVER=pulse,alsa and its mmdevapi reads that
  before the registry (Valve's and GE's do not read it): the wrapper exports
  WINE_AUDIO_DRIVER=directaudio,pulse as well as writing the registry. On CachyOS this also
  makes DirectAudio engage on a game's first launch.
- A wineserver from an earlier Steam verb can save its in-memory registry over the appended
  Audio value; the wrapper says so when one is live. Writing through it (wine reg add) and
  creating a missing prefix first (proton run wineboot) were tried on the device and withdrawn:
  a second Proton/Wine run inside Steam's launch sequence got launches aborted.
- Tests: both sets, no set, no prefix (34 pass).

Steam client audio
- DirectAudio = module-directaudio-native-sink, the game driver's AAudio engine inside the
  PulseAudio daemon, one step from Android (adaptive buffer, two-burst floor, primed ring with
  fades, reopen on route change, watchdog, limiter). Default. Shared output = the previous relay
  route, kept. New pref clientAudioRoute; the old boolean is not read. If the native sink cannot
  open its stream the daemon keeps running (.nofail) and ensureClientSink loads the plain AAudio
  sink instead, logged to audio.log. Audio bundle stamp bumped.

Out of tree
- app/src/main/assets/directaudio/ is generated and ignored; tools/directaudio-relay/ and the
  vendored module-directaudio-sink.c + da_relay_proto.h are gone; tools/aaudio-sink keeps only
  module-aaudio-sink (the fallback). The release carries the relay and sink field fixes by
  MaxsTechReview (#338), credited there and in its AUTHORS.

Device-proven on an AYANEO Pocket FIT: client sink 12 ms / 4 ms bursts, 0 underruns; FEZ on
cachyos-11.0-20261005-slr on DirectAudio (took pulse before); FEZ on Proton Experimental
unchanged; Curse of the Dead Gods on CachyOS from a cold prefix, DirectAudio on first launch.

Co-authored-by: The412Banner <[email protected]>
2026-10-08 12:35:00 -04:00
MaxsTechReview b6c1d3c09c Land taps and the pointer on what is drawn under them (#389)
The compositor takes touch and pointer positions over its whole output and
removes the letterbox bars itself, but the session sent them already
measured from the picture's edge, so the bars were taken off twice. Any
session whose output is a different shape from the panel (16:9 on a 16:10
tablet or a foldable, a fixed resolution on a wide phone) had taps and the
touchpad pointer pulled away from the centre, by up to a bar's height at
the edges: on a 2400x1504 panel showing 1280x720, a tap near the top
reached the first row and one near the bottom landed 32 rows low. Stretch
to panel hid it because that output has no bars.

Direct touch, the touchpad and mouse pointer, and the second-screen pointer
now send positions over the whole view, so the compositor's own mapping
puts them on the pixel under the finger.
2026-10-08 11:52:45 -04:00
Kurt Himebauch a58b0ac3e0 chore: bump version to 0.3.2 (12) (#437) 2026-10-08 10:49:33 -04:00
Tak-attackandxXJsonDeruloXx 1304809240 Improvements to the Japanese Translation (#314)
Update strings.xml

Improvements to the Japanese Translation
I have rewritten the translation to make it sound more natural in Japanese.

Also, since “Loader” in “Decky Loader” is a proper noun, I believe it does not need to be translated.

Co-authored-by: xXJsonDeruloXx <[email protected]>
2026-10-08 04:11:52 +00:00
kmnkv1andxXJsonDeruloXx 343a516e1a Update Russian translation (#324)
Translate the 103 missing strings (screen effects, scaling, Wine sync
backends, FEX for AppImages, Steam repair, device info) and fix existing
ones: inverted meaning in mode_suspend_note, content_add_roms and
wadb_connect_address, double space in the update/install buttons,
outdated AppImage/Proton hints, "1 приложений"-style counts, gender
agreement with substituted names, lowercase fragments that are joined
into sentences, and inconsistent terms (Setup, Developer options, Stop
session, Button mapping).

Co-authored-by: xXJsonDeruloXx <[email protected]>
2026-10-08 04:06:56 +00:00
0x142857andxXJsonDeruloXx 7c08cb58ae Share font defaults across runtime sessions (#252)
* Support CJK text with the device's own fonts

The Linux runtime's rootfs ships DejaVu alone, which has no CJK
glyphs, so Chinese, Japanese and Korean text in Steam Big Picture and
on the LXQt desktop draws as tofu boxes (issues #118, #206, #249).

Bind the device's own CJK fonts - Android's world-readable Noto CJK
.ttc, or DroidSansFallback / Source Han - into the guest under
/usr/share/fonts/droiddeck-cjk, so nothing is added to the ~790 MB
runtime image and the coverage follows the device. A new
droiddeck-fonts script, run by droiddeck-session before any program
that queries fontconfig, links the default rules, writes local.conf
with DejaVu first and the CJK families after it, and rebuilds the
fontconfig cache once per set of font files. The desktop's own
fontconfig block moves there, so every mode gets it.

* Fix CJK and Thai: bind the device font directory, not one file at a time

The first cut bound each device font with its own proot -b host:guest. A
per-file binding into a plain directory is not applied here: the guest sees a
zero-byte placeholder where the font should be (stat size=0, fc-scan empty),
so Chinese stayed tofu even though the app had "bound" the font. A directory
binding is what the rest of the runtime relies on, so bind /system/fonts as a
whole under /usr/share/fonts/droiddeck-device. That also brings Thai, Arabic,
Devanagari and the emoji fonts, which the runtime did not have either.

Verified on the AYN Thor: the session's fontconfig probe reports
sans=DejaVu Sans, zh=Noto Sans CJK SC, th=Noto Serif Thai, and Steam Big
Picture in Simplified Chinese renders without tofu (screenshot under
docs/development/evidence/).

---------

Co-authored-by: xXJsonDeruloXx <[email protected]>
2026-10-08 04:06:23 +00:00
7e81668de2 Polish Spanish translation (#234)
* i18n: complete Spanish

Spanish gets the strings added since it landed and the ones that are only a format or a brand name, so it has the same keys as English, in the same order. Each English term keeps one Spanish word across the file, and a few existing strings are reworded to read right with the values they are filled with.

* i18n: use compilación for build in Spanish

* i18n: translate new strings to Spanish

---------

Co-authored-by: Kurt Himebauch <[email protected]>
Co-authored-by: xXJsonDeruloXx <[email protected]>
2026-10-08 04:05:09 +00:00
Kurt Himebauch d231564f8e feat: agent bridge wayland and gamescope coverage (#406)
* feat: run a guest agent in every session for commands, focus and the Steam client's DevTools

* feat: give the agent bridge game, input, UI and experiment commands behind a Setup toggle

* feat: droiddeckctl commands for the new bridge, a scenario runner and contract tests

* feat: run cleanup steps after every scenario run so a failure cannot leak into the next

* feat: restart a session that died between scenario runs with start --reuse

* fix: give droiddeckctl stop its own, longer wait for the session's logs

* fix: harden debugging tools access and output
2026-10-08 03:50:58 +00:00
Kurt Himebauch 37e89c5b4d harden logging (#414) 2026-10-08 02:10:06 +00:00
The412Banner e070bd72e0 fix: read droiddeck-env from ps (#413) 2026-10-07 21:38:33 -04:00
Kurt Himebauch 4454a6d39a fix: keep Updates channels and status side by side (#397) 2026-10-07 13:48:02 -04:00
MaxsTechReview 453f6f5180 Keep the shortcut settings changed in Steam (#393)
Steam saves a shortcut's Properties to shortcuts.vdf as soon as they
change and keeps its appid. The session rewrote every added game's entry
from the app's list before and after each client run, keeping only the
launch options, so a Target or Start In set in Steam, a new name or icon,
the hidden and overlay switches, the last played time and Steam's sort
name were all put back at the next exit.

droiddeck-steam-shortcuts now merges instead: an entry keeps every field
Steam has, and the app's exe is written only where the app changed it.
What the app last asked for and what Steam then had are recorded beside
shortcuts.vdf (.droiddeck-shortcuts.json). A Target changed in Steam to a
file inside the game's folder becomes the exe chosen in Steam > Settings >
Games, and a later pick there replaces it in Steam, so both show the same
exe. The appid now stays with the folder, so changing the exe no longer
turns the game into a new one with a new prefix, playtime and launch
options. A game whose folder is missing is set aside with its settings
and comes back with them. The exit-time merge runs before Steam's logs
are copied.
2026-10-07 09:32:15 -04:00
MaxsTechReview 6d0484941e Make Games folders Steam libraries and skip the zero-filled reservation (#388)
With Second library on Automatic, every writable Games folder is now a
Steam library: it gets the same private prefix and tool binds as the card,
the app hands the session the list (BL_STEAM_LIBRARIES), and
droiddeck-steam-library registers, relabels and forgets entries from it.
Steam offers them in the install dialog as "<folder> (<volume>)", and
Proton mapping, esync, the redist seeder, desktop entries and the compat
beat read every registered library instead of only the card. Games folder
libraries stop at the fast path's bind budget.

Steam's preallocation on Android's FUSE storage either failed outright
(NTFS answers EPERM, so installs were cancelled as "not enough disk
space") or zero-filled the whole download first (exFAT, minutes for a
small game). After fallocate is refused, the Steam client's ftruncate
extension of its own staging files is reported as done; the writes that
follow fill the file. A 76 MB install to a USB SSD now preallocates
instantly instead of taking about 3.5 minutes.

A library that is not there is left out of the list and forgotten until
it returns, imports whose folder is missing are set aside rather than
offered as broken installs, and the front end refreshes when storage is
mounted or removed.
2026-10-07 09:31:33 -04:00