Feat/linux pr 525#582
Conversation
Ten standalone bug fixes that are correct on all platforms. Each was a
latent bug on macOS masked by libc++/GLUT/Metal; they surface as hard
errors on Linux/libstdc++/Vulkan.
- Common/SmartPtr.h: guard _LIBCPP_INLINE_VISIBILITY — libstdc++ does
not define _LIBCPP_HIDE_FROM_ABI, so the macro expansion failed to
compile on GCC.
- Common/BlockingQueue.h: condition_variable::wait() requires a lock
object, not a raw mutex. Three call sites passed m_mutex directly
(undefined behaviour). Also mark condition var members mutable so
const methods can legally call wait().
- Common/XTimer.h: remove unused <X11/Xlib.h> / <X11/Xutil.h> —
these headers define the None macro (0L) which clashes with
enum class TransitionType { None }. Also make Time() const to
satisfy the ITimer pure-virtual signature.
- Client/FrameDisplay.h: guard <CoreVideo/CVPixelBuffer.h> inside
#ifdef MAC — CoreVideo does not exist on Linux.
- Client/StringFormat.cpp: add missing #include <cstdarg> for
va_list / va_start / va_end.
- Client/client.h: wrap SHAREDIR in std::string() when calling
Set("settings.app.InstallDir", ...). SHAREDIR is const char*; without
the cast, overload resolution picks Set(string_view, bool) (non-null
pointer → true) instead of Set(string_view, string_view), storing a
boolean in JSON and crashing later at as_string().
- ContentDecoder/ContentDecoder.cpp: avcodec_close() was removed in
FFmpeg 6.x. Replace with avcodec_free_context() which also nulls the
pointer.
- ContentDownloader/PlaylistManager.h: add missing <condition_variable>
and <mutex> for the std::condition_variable / std::mutex members.
- DisplayOutput/Renderer/TextureFlat.h: wrap FFmpeg headers in
extern "C". Without it, sws_getContext gets C++ name mangling and
fails to link even with -lswscale present.
- Networking/EDreamClient.h: add missing SetQuota() declaration.
The method is defined in EDreamClient.cpp and called from a free
function, but was absent from the header, causing a compile error
on strict-conformance builds.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Modify existing files to route Linux through Vulkan instead of falling through to Metal (which only exists on macOS). No Mac code paths are changed — all additions are inside new #elif defined(LINUX_GNU) or #else branches that were previously absent or broken. - Client/Player.cpp: change bare #else after WIN32 guard to #elif defined(MAC) for Metal includes, add new #else block that includes DisplayVulkan.h / RendererVulkan.h. AddDisplay() gains a matching Linux branch that constructs CDisplayVulkan + CRendererVulkan. Remove dead EndFrameUpdate() FPS-capping code (spFD / m_PlayerFps undefined on Linux; the block was never reachable on Mac either due to the surrounding #ifndef USE_METAL guard). - Client/main.cpp: remove <GL/gl.h> / <GL/glut.h> includes from the Linux branch (Vulkan does not use GLUT). Guard glutInit() inside #if defined(MAC) so it is not called on Linux. - Client/client_linux.h: remove #include "lua_playlist.h" (file does not exist). Add #include "PlatformUtils.h". Fix m_AppData path to ~/.config/infinidream/. Derive m_WorkingDir from PlatformUtils::GetWorkingDir() rather than the autotools SHAREDIR macro. Fix g_Player().AddDisplay() missing nullptr second argument. Remove g_Player().Framerate() call (method no longer exists). Fix CElectricSheep::Update() call to pass required int argument. Replace invalid static_cast<spCKeyEvent> with std::static_pointer_cast. Remove entire stale voting block (m_pVoter, GetCurrentPlayingID, RepeatSheep, m_spSplashPos/Neg — all removed from current codebase). - Client/cpu_usage_linux.h: replace glibtop (GNOME library, requires libgtop2 which is not a standard dependency) with direct /proc/stat parsing. ReadProcStat() uses fscanf with a format string that matches the literal "cpu" prefix — no throwaway variables, no string allocation, returns matched == 4 on success. GetNumCores() uses sysconf(_SC_NPROCESSORS_ONLN) instead of parsing /proc/cpuinfo. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Everything needed to configure and compile the project on Linux.
No existing Mac build files are touched.
LinuxBuild/CMakeLists.txt
Standalone CMake build for Linux (mirrors MacBuild structure).
Targets: Vulkan, X11, Boost (filesystem/thread/log/log_setup/json),
FFmpeg (via pkg-config), OpenSSL, libcurl, libpng, pthreads.
Compiles GLSL shaders to SPIR-V via glslc (from Vulkan SDK or PATH)
and copies them next to the binary at POST_BUILD. Defines LINUX_GNU,
BOOST_FILESYSTEM_VERSION=3, SHAREDIR=".".
LinuxBuild/PlatformUtils_Linux.cpp
Implements the PlatformUtils static interface for Linux:
IsInternetReachable (connect to 8.8.8.8:53), GetWorkingDir / GetAppPath
(/proc/self/exe), OpenURLExternally (xdg-open), SetThreadName
(pthread_setname_np), SetCursorHidden (X11 blank cursor),
SetOnMouseMovedCallback, DispatchOnMainThread (thread-safe queue
drained on the main thread), NotifyError (stderr), CalculateFileMD5
(OpenSSL EVP — same logic as the Mac version).
LinuxBuild/PlatformUtils_Internal.h
Internal helpers shared between DisplayVulkan and PlatformUtils_Linux:
DrainMainThreadQueue(), GetMouseCallback(), GetCursorHidden().
socket.io-client-cpp/lib/linux/libsioclient{,_tls}.a
Linux ELF builds of socket.io-client-cpp. The vendored .a files in
lib/ are Mach-O universal binaries used by the Xcode project and are
left untouched. Linux links against the lib/linux/ variants via CMake.
To rebuild: clone socket.io-client-cpp, cmake -DUSE_TLS=1, make.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
New DisplayOutput/Vulkan/ directory implements the CDisplayOutput and
CRenderer interfaces for Linux using Vulkan + X11. The Metal backend
(DisplayOutput/Metal/) is untouched.
DisplayVulkan (.h/.cpp)
Creates an X11 Window and a VkSurfaceKHR via VK_KHR_xlib_surface.
Manages VkInstance, VkDevice (picks first discrete GPU, falls back to
integrated), VkSwapchainKHR, render pass, framebuffers, and per-frame
sync primitives (semaphores + fence). Fullscreen via EWMH
_NET_WM_STATE_FULLSCREEN. Handles ConfigureNotify resize by
recreating the swapchain. XScreensaver mode: if XSCREENSAVER_WINDOW
env var is set the window is reparented into it rather than created
standalone. Implements CDisplayOutput: Initialize, Resize, SetTitle,
SetFullScreen, Present, SwapBuffers, ProcessEvents.
RendererVulkan (.h/.cpp)
Implements CRenderer. Allocates a VkDescriptorPool, descriptor set
layout, and a graphics pipeline backed by the compiled quad shaders.
Per-frame: acquires swapchain image, begins render pass, binds
pipeline + descriptor set, draws the fullscreen quad, ends pass,
submits, presents. BeginFrame/EndFrame bracket each rendered frame.
NewTextureFlat() returns a CTextureFlatVulkan.
TextureFlatVulkan (.h/.cpp)
Implements CTextureFlat. Allocates a VkImage + VkImageView + VkSampler
and a host-visible VkDeviceMemory staging buffer. Upload(spCImage)
copies RGBA pixel data via vkMapMemory then transitions the image to
SHADER_READ_ONLY_OPTIMAL. BindFrame(spCVideoFrame) maps decoded AVFrame
data directly into the staging buffer each frame for zero-copy video
upload. The descriptor set is updated with vkUpdateDescriptorSets so
the fragment shader samples the current frame.
ShaderVulkan (.h/.cpp)
Loads SPIR-V bytecode (compiled from shaders/quad.vert / quad.frag at
build time by glslc). Creates VkShaderModule.
FontVulkan (.h/.cpp)
Stub implementing CFont. Text rendering is not yet wired up on Linux;
the stub satisfies the interface so the binary links and runs.
shaders/quad.vert
Fullscreen triangle-pair. Passes UV coordinates to the fragment stage.
shaders/quad.frag
Samples a combined image sampler (the current video frame texture)
and writes to the swapchain image. YUV→RGB conversion is handled
upstream by FFmpeg swscale (frames arrive as RGBA); the shader is a
straight passthrough blit.
Verified on Arch Linux, RTX 4090, Vulkan 1.4.341, driver 575.57.08:
cmake -B build -DCMAKE_BUILD_TYPE=Debug && cmake --build build
./build/infinidream → window opens, content decoder and downloader
initialise, video playback begins.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
At runtime, if WAYLAND_DISPLAY is set and XSCREENSAVER_WINDOW is not, DisplayVulkan connects natively to the Wayland compositor using VK_KHR_wayland_surface instead of VK_KHR_xlib_surface. XScreensaver embed mode always uses X11 (that protocol is inherently X11). On X11-only systems or if wayland-client is absent at build time, behaviour is identical to before. CMakeLists.txt: Optionally find wayland-client, wayland-protocols, and wayland-scanner via pkg-config. When all three are present, generates xdg-shell protocol bindings (xdg-shell-protocol.c / xdg-shell-client-protocol.h) at configure time via wayland-scanner, adds HAVE_WAYLAND compile definition, and links wayland-client. Graceful fallback to X11-only if any piece is missing. DisplayVulkan.h / .cpp: createVulkanInstance() picks VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME or VK_KHR_XLIB_SURFACE_EXTENSION_NAME based on m_bWayland. initWayland() — connects to wl_display, binds wl_compositor and xdg_wm_base from the registry, creates wl_surface, xdg_surface, and xdg_toplevel, handles ping/configure/close via static listener callbacks (onXdgWmBasePing, onXdgSurfaceConfigure, onXdgToplevelConfigure, onXdgToplevelClose), sets fullscreen if requested, and does two wl_display_roundtrips to complete the initial configure handshake before returning. checkEvents() dispatches Wayland events with wl_display_flush() + wl_display_dispatch_pending() instead of XPending/XNextEvent. setFullScreen() calls xdg_toplevel_set_fullscreen / _unset_fullscreen on Wayland; EWMH ClientMessage on X11. Title() calls xdg_toplevel_set_title on Wayland; XStoreName on X11. destroyWayland() tears down xdg_toplevel → xdg_surface → wl_surface → xdg_wm_base → wl_compositor → wl_display in dependency order, after Vulkan surface/instance are already destroyed. client_linux.h: Replace CElectricSheep::Update(0) (now requires two boost::barrier refs) with the equivalent direct calls: BeginFrameUpdate(), DoRealFrameUpdate(0), EndFrameUpdate(). Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
EDreamClient::ParsePlaylist line 1631 passed a std::string_view to a %s variadic argument. On Apple Clang/libc++ this accidentally works because the ABI passes the pointer field first and it happens to be null-terminated; on GCC/libstdc++ vsnprintf reads the struct bytes differently and segfaults. Fix: uuid.empty() ? "default playlist" : uuid.data() uuid.data() is safe here — callers always pass a std::string-backed view so the data pointer is null-terminated. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
- Frame.h: set m_pFrame->format/width/height in first constructor (was left as AV_PIX_FMT_NONE=-1, causing sws_getContext to crash) - Clip.cpp: use AV_PIX_FMT_RGBA on Linux so ContentDecoder pre-converts decoded frames; call BindFrame via USE_HW_ACCELERATION||LINUX_GNU guard - TextureFlatVulkan: add Bind() override to set descriptor set on renderer; add dirty flag so Apply() re-binds after each BindFrame upload; fast-path RGBA upload without redundant swscale pass - RendererVulkan: Apply() was a no-op stub — delegate to base class so texture Bind()/Dirty() logic actually runs - quad.vert: input coords are normalized [0,1], not pixels — remove division by screenWidth/Height that squashed quad to a 1px strip - websocketpp/constants.hpp: bump max_header_size 16KB→64KB for Heroku large set-cookie response headers - libsioclient_tls.a: rebuild with patched websocketpp header - client.h: fix Run() loop and add virtual Update() base - EDreamClient.cpp: fix string_view passed to %s (UB on GCC) Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…ipts The Mac build (primary platform) uses Xcode/CMake and is unaffected. These files were remnants of the original Electric Sheep Linux autotools era: - electricsheep-saver, electricsheep-saver-gnome: wrapper scripts pointing at an 'electricsheep' binary that no longer exists. Linux xscreensaver integration already works via the XSCREENSAVER_WINDOW env var in DisplayVulkan — no wrapper script needed. - Makefile.am (root, Client/, MSVC/SettingsGUI/), configure.ac, Makefile.in: dead autotools scaffolding superseded by LinuxBuild/CMakeLists.txt. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Two targeted fixes for the high CPU usage observed on Linux (~57% CPU for simple video playback). RendererVulkan: switch swapchain from MAILBOX to FIFO present mode. MAILBOX never blocks — vkQueuePresentKHR returns immediately and the render loop spins at uncapped speed consuming a full CPU core. FIFO is guaranteed supported by the Vulkan spec and blocks on each present until the next vblank, giving vsync-throttled output for free with zero extra code. Mac is unaffected (Vulkan backend is Linux-only). client.h / Player.h: call FpsCap(m_PerceptualFPS) in the Run() loop after each frame. FpsCap() already existed in Player.cpp (complete with its own wall-clock timer) but was unreachable — it was buried inside a WIN32-only private section. Move it to public and call it from Run(), which caps frame delivery to the configured perceptual FPS (default 20 fps) and sleeps away any remaining frame budget. Run() is only entered from main.cpp on Linux; the Mac Cocoa/display- link loop never calls it, so Mac behaviour is unchanged. Together these changes eliminate the busy-spin that was burning ~30-40% of a CPU core between frames and the uncapped GPU submission loop on top. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
The existing auth flow only knew how to refresh a WorkOS sealed session
(wos-session cookie). On Linux there is no UI to obtain one, so a fresh
install could never authenticate.
The backend middleware already accepts an Api-Key <key> header as an
alternative to the session cookie on all protected endpoints, so no
server changes are needed.
Changes:
EDreamClient: AppendAuthHeader()
Centralises all request auth in one place. Previously every call site
duplicated three lines of get-setting / build-header / append-header.
Now: sealed session present → Cookie: wos-session=<session> (existing
behaviour); no session but api_key present → Api-Key <key>; neither →
no auth header (request will 401, existing error handling applies).
All ~15 call sites replaced with AppendAuthHeader(spDownload).
EDreamClient: SignInWithApiKey()
Persists the API key to settings.content.api_key and returns true.
No round-trip to the server needed — the key is used directly on each
subsequent request.
EDreamClient: Authenticate() fallback
After sealed-session refresh fails, checks the INFINIDREAM_API_KEY
environment variable. If set, calls SignInWithApiKey() and persists
the key for future runs. Falls back to a key already stored in
settings. This means Linux users can authenticate with:
export INFINIDREAM_API_KEY=<key> ./infinidream
or by adding settings.content.api_key to ~/.electricsheep/settings.json.
WebSocket connection
ConnectRemoteControlSocket() now passes Api-Key in the query map when
no sealed session is available, matching the HTTP auth fallback.
Mac is unaffected: EDreamClient is shared but the Mac flow always
obtains a sealed session via the first-time setup UI before reaching
any of these paths.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
The streaming-load lambda (detached thread that fetches a download link and starts a clip) declared a bool return type via an early 'return false' on the no-display-units error path, but fell off the end without returning on the success path. Add 'return true' after the clip-start block. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Three related issues with the startup/loading screen on Linux: client.h: startup screen invisible during buffering The render block was gated on (drawNoSheepIntro || drawn). When a clip is in buffering mode g_Player().Update() returns false (drawn=false), and if the user is logged in HasStarted() is true so drawNoSheepIntro is also false. Result: nothing rendered at all — pure black screen while waiting for the first frames to decode. Fix: hoist the startup-screen visibility check into a 'showStartup' bool and include it in the outer gate condition so the startup screen renders independently of whether the player has a frame ready to draw. StartupScreen.h: white square when logo.png not found CImage::Create() initialises the 256×256 buffer to white. If Load() fails (file not found) the blank white image was still uploaded as a texture and rendered as a white square in the centre of the screen. Fix: check the return value of Load() and set m_spImageRef = nullptr on failure. The existing if (m_spImageRef) guard around the DrawQuad then cleanly skips the logo without affecting the text rendering below it. CMakeLists.txt: deploy logo.png next to the binary at build time The startup screen looks for logo.png relative to the working directory (settings.app.InstallDir). On Linux this is the build output directory, but the asset was never copied there. Add a POST_BUILD custom command that copies Runtime/logo.png next to the infinidream binary so it is found on first launch without manual installation steps. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
HasStarted() returns true as soon as the playlist is set in the startup thread, which happens before the first render frame. This meant drawNoSheepIntro=false and m_StartupScreen was never created, so showStartup=false and drawn=false → pure black screen. Fix: include !drawn in the showStartup condition so the startup screen is shown whenever there is no video frame available yet (buffering, quota exhausted, no content downloaded, etc.) regardless of whether HasStarted() returned true. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
On Wayland, vkAcquireNextImageKHR returns VK_ERROR_OUT_OF_DATE_KHR after the first few frames during initial surface configuration. Previously BeginFrame() returned false without recreating the swapchain, causing BeginDisplayFrame() to return false every subsequent frame. Since Player::Update() is gated on BeginDisplayFrame(), it was never called, so Clip::Update() never ran, the buffering threshold was never checked, the frame queue filled to max (25 frames), and the decoder thread blocked on push() — meaning video never played. Fix: store the VkSurfaceKHR in Initialize(), implement recreateSwapchain() (wait idle → destroy framebuffers/imageviews/swapchain → recreate), and call it from both BeginFrame() and EndFrame() on OUT_OF_DATE or SUBOPTIMAL. Also: - Return bool from RenderFrame() so Update() can report whether it drew - Fix SHAREDIR path suffix (\"./\" instead of \".\") in CMakeLists.txt Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…isc fixes
Fullscreen / windowed toggle (Wayland):
- Add F key binding to toggle fullscreen (replaces Ctrl+F) in client_linux.h
- Add key-release guard (m_bPressed check) to prevent double-fire on toggle actions
- Add ToggleFullscreen() virtual to DisplayOutput base; override in CDisplayVulkan
- Set m_bFullScreen = bFullscreen in initWayland before the initial roundtrip so
the configure-event filter correctly accepts the startup fullscreen configure
- Parse XDG_TOPLEVEL_STATE_FULLSCREEN from the wl_array in onXdgToplevelConfigure
and ignore stale fullscreen configures when we have already requested windowed mode
- Set m_Width/m_Height = 1280x720 in setFullScreen(false) before unset_fullscreen
so RendererVulkan recreates the swapchain at the correct windowed size
- Re-assert ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE on windowed transition
- Add proactive swapchain recreation in BeginFrame when display dimensions change
(Wayland compositors do not always send VK_ERROR_OUT_OF_DATE_KHR for client-driven
resizes)
- Add xdg-decoration-unstable-v1 protocol support (server-side window borders);
falls back gracefully when the compositor does not advertise the interface (GNOME)
- Log all Wayland registry globals at startup for diagnostics
- Update CMakeLists.txt to generate xdg-decoration protocol bindings via
wayland-scanner alongside the existing xdg-shell bindings
VAAPI / video decoder fixes:
- Fix VAAPI PTS loss: av_hwframe_transfer_data copies only pixel data; manually
copy pts, pkt_dts, and best_effort_timestamp to sw_frame before av_frame_move_ref
- Guard against corrupted/wrapped last_played_frame resume values (e.g. uint32_t
wrap from a previous VAAPI PTS bug) by clamping seekFrame to a sane range
Font / HUD rendering (FontVulkan):
- Implement FreeType-based glyph atlas for Vulkan (CFontVulkan)
- Wire up TextureFlatVulkan for font atlas texture upload
Startup / display:
- Fix startup screen visibility: show logo until the first video frame is ready
- Silence spurious PNG warnings for Mac-only OSD assets missing on Linux by
removing the Warning log from the file-not-found path in LoadPNG.cpp
HUD / help text (client.h):
- Capitalise all F1 help text entries ("A: Slower playback" not "a: slower…")
- Show "F: Toggle full screen" on Linux instead of "Ctrl+F: Toggle full screen"
README: update Linux build and feature documentation
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
- client.h: make BK() macro a no-op on non-Linux builds; the \x01/\x02 inline-bold markers are only handled by the Linux HUD renderer — on Mac they would appear as raw control characters in the F1 help overlay - ContentDecoder.cpp: change #ifndef WIN32 guards to #ifdef LINUX_GNU so the VAAPI code (vaapi_get_format, hw device init, hw frame transfer) is only compiled on Linux; Mac retains its VideoToolbox path via the existing USE_HW_ACCELERATION / USE_METAL logic in base.h Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Remove the FreeType-based CFontVulkan/CTextVulkan implementation and replace it with ImGui-backed CFontImGui/CTextImGui, using ImGui's embedded ProggyForever font (MIT licensed, no external font files required). New build dependency: Dear ImGui added as a git submodule at client_generic/imgui (pinned to v1.92.6, the latest stable release). Its source files are compiled directly into the Linux build — no system package or vcpkg entry needed. - Drop FreeType dependency from LinuxBuild/CMakeLists.txt - CFontImGui: registers font with ImGui atlas via AddFontDefaultVector() - CTextImGui: GetExtent() measures via CalcTextSizeA() - RendererVulkan: integrate ImGui frame lifecycle (NewFrame/Render/RenderDrawData) - DrawText: segment-based renderer handles \n (newlines) and \t (tab stops at 4×space width); \x01/\x02 bold markers are stripped — ProggyForever has no bold variant so bold text support is removed for now pending a future decision on font strategy - Remove Lato-Regular.ttf from the build (was missing its license) - Update README: remove freetype2 from prereqs, note ImGui submodule init No Mac files were modified. The Metal renderer, Mac CMakeLists, OSD, and CI workflow are all unchanged. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
X11 fullscreen / window management: - Create window at requested size and apply _NET_WM_STATE_FULLSCREEN as a window *property* before mapping (not a client message), so the WM resizes it to the correct monitor dimensions on startup. - MapNotify wait loop now captures ConfigureNotify events so the initial fullscreen size is known before creating the Vulkan surface/swapchain. - Add 500 ms fallback poll if ConfigureNotify arrives after MapNotify. - Fix EWMH setFullScreen message: data.l[0] must be 0/1, not an Atom value; set data.l[2]=0, data.l[3]=1 (source: normal application). - checkEvents(): update m_Width/m_Height on ConfigureNotify so HUD coordinates stay in sync with WM-driven window resizes at runtime. - Add IsWayland() accessor to CDisplayVulkan. Swapchain / HUD aspect ratio: - createSwapchain(): use std::clamp(requested, min, max) instead of caps.currentExtent, which can lag behind ConfigureNotify on X11. - BeginFrame(): trigger swapchain recreation when Display()->Width/Height() differs from m_swapExtent, replacing the surface-caps query that had the same lag problem. - Set io.DisplaySize from Display()->Width/Height() so ImGui always reflects the true window dimensions. - Remove max(1.0f, ...) floor from font scaling in DrawText, GetExtent, StatsConsole, and StartupScreen; use proportional screenH/1080 scaling. - Compute startup logo aspect ratio dynamically each frame rather than baking it in the constructor, fixing logo squash after fullscreen toggle. F1 help overlay: - Remove inline bold markers (\x01/\x02) from BK macro — ProggyForever does not support bold; simplify DrawText and GetExtent accordingly. - Fix tab stop counts so all right-column key bindings align correctly. Auth: - On InvalidSession refresh failure, probe the QUOTA endpoint before wiping the session; HTTP 200 means the token is still live and the client proceeds logged in rather than forcing an unnecessary re-login. - Companion backend change: e-dream-ai/backend#407 Misc: remove unused boost::bind include from Player.cpp. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…efactor Upstream added richer result types (SendCodeResult, ValidateCodeResult, HelloResult) and a retry loop in GetCurrentServerPlaylist(). Conflict was in HelloDetailed(): kept our AppendAuthHeader() call (which handles both wos-session cookie and Api-Key header for Linux/headless) in place of the sealed-session-only block from upstream. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
CRendererVulkan::Reset() was a complete no-op, so calling it with eTexture never cleared m_aspSelectedTextures[]. Apply() then re-bound the stale video/startup texture, causing DrawSoftQuad to sample it instead of the white descriptor set — manifesting as a ghost ellipse behind the F1 help and F2 status overlays. Fix: delegate to CRenderer::Reset(_flags) so the base class clears m_aspSelectedTextures, then explicitly reset m_currentDescSet to m_whiteDescSet when eTexture is requested. Inspired by upstream commit 29a5da8 (e-dream-ai/client), which fixed the same class of stale-texture bug on Metal by clearing stale bindings between draw calls that share a single render encoder. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…g path
- Add LoginWithMagicLinkCode(): on first run prompts for email (saved to
settings.generator.nickname), sends a one-time code, reads it from stdin,
and exchanges it for a sealed session before the window opens. Subsequent
runs auto-refresh the session; re-prompts interactively if it expires.
- Add --cached flag: skips auth entirely and plays locally cached videos in
offline mode, reporting count and size ("cycling through N (X.X GB) of
cached videos"). Exits with a clear message if the cache is empty.
- Pre-check auth state before the display window opens: if no sealed session
and no API key, attempt magic link login or abort with actionable guidance
rather than opening a window that cannot download any content.
- Store api_key and user email in settings.json (settings.content.api_key /
settings.generator.nickname) rather than a separate credentials file.
- Fix Linux settings path: remove hardcoded ~/.electricsheep/ in InitStorage()
so settings, logs, and content all live under ~/.config/infinidream/ as
client_linux.h always intended.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
The Linux client was doing too much synchronous work on the main/render loop for what should be a mostly idle video screensaver workload. In particular, the shared client frame path was repeatedly probing internet reachability, rebuilding cache statistics, polling download/network status, and updating large HUD/stat blocks every frame. On Linux that showed up as excessive CPU usage even when hardware video decode was active, and it also created extra event-pump churn because the Linux wrapper called Display()->Update() a second time each frame. This change introduces a cached RuntimeDiagnostics layer inside CElectricSheep so the expensive shared-loop diagnostics are sampled on coarse timers instead of per frame. Fast-changing values such as CPU, GPU, and transfer status are refreshed at a short interval, while slower values such as internet reachability, disk/update status, and cache size are refreshed at longer intervals. The dream stats and credits HUD updates are also gated on HUD visibility so hidden overlays no longer pay the full per-frame formatting and data collection cost. An optional INFINIDREAM_PERF_LOG path remains available for coarse runtime measurements. On Linux specifically, the extra Display()->Update() call in CElectricSheep_Linux::Update() is removed so window events are pumped once per frame through the shared render path instead of twice. That reduces unnecessary X11/Wayland work without changing presentation semantics. This is intentionally safe for macOS because it does not change the Metal renderer, macOS display update path, swap/present behavior, or decode pipeline. The shared-code changes only reduce how often diagnostic state is recomputed and how often hidden HUDs are updated. Visible HUD behavior remains intact, user-triggered network checks still force a fresh connectivity probe, and the Linux-only event-pump change is isolated to client_linux.h.
Wayland windowed mode previously relied entirely on xdg-decoration server-side decorations. On compositors that do not provide that protocol, the Linux client came up undecorated, which left the window difficult to move and resize compared with the existing X11 path. Add an optional libdecor-0 fallback in the Vulkan display backend and Linux build. When xdg-decoration is unavailable, the Wayland path now creates a libdecor frame, routes title/fullscreen updates through it, dispatches libdecor events during the frame loop, and tears it down safely without affecting the X11 path. Also add Wayland cursor-theme handling for the content surface so the app restores a normal arrow when re-entered from another application, reports a distro-correct warning when libdecor decorations cannot be provided, and exposes a content-side resize hotzone near the window edges and corners to make resizing practical even when the decoration backend's own hit targets are narrow. This change is Linux-only. macOS is unaffected because the code paths are guarded behind the Wayland/Linux build configuration and do not alter the shared Metal or Cocoa client behavior.
…text After merging upstream/master, resolve several issues introduced during conflict resolution: - Guard POSIX-only code in EDreamClient.cpp (#include <unistd.h>, LoginWithMagicLinkCode body) so Windows builds are not broken - Guard the Linux headless auth block in CElectricSheep::Startup() with #ifdef LINUX_GNU so Mac/Windows first-run startup is not short-circuited before the GUI auth flow can run - Restore null guards on g_Player().Renderer() and g_Player().Display() in StartupScreen constructor and CElectricSheep::Run() - Remove DrawSoftQuad override keyword from RendererVulkan (upstream removed the base class virtual in commit 1b4735d) - Fix Frame.h constructor assigning _width/_height to AVFrame fields - Fix duplicate ToggleFullscreen in DisplayOutput.h (bool vs void return) - Restore startup screen text rendering: draw "Connecting to infinidream.ai..." centered at top of screen via GetExtent() + DrawText Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Our earlier work replaced the upstream `if (USE_HW_ACCELERATION)` block with a `#ifdef LINUX_GNU` VAAPI block, which inadvertently deleted the Mac VideoToolbox initialisation. Without it, FFmpeg outputs software YUV frames. TextureFlatMetal::GetPixelBuffer() casts data[3] directly to CVPixelBufferRef; for software frames data[3] is null, causing an immediate crash the moment the first video starts playing. Once the app crashes the main loop stops running and ProcessCommandQueue() is never called, which is why remote-control commands also appeared broken. Fix: - Add a vt_get_format() callback (MAC-only, mirrors the existing vaapi_get_format for Linux) so the codec negotiates AV_PIX_FMT_VIDEOTOOLBOX rather than falling back to software YUV. - Restore VideoToolbox hw-device creation in ContentDecoder::Open() using av_hwdevice_ctx_create() (the correct one-step API, replacing the upstream's fragile alloc+init pattern) guarded with #elif defined(MAC). The Linux VAAPI path is untouched; Windows gets neither block and continues with software decoding as before. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
PR #541 bumped the vcpkg submodule past upstream commit b94ab47c99 ("[ffmpeg] Remove deprecated securetransport"), which silently dropped the implicit --enable-securetransport on macOS/iOS. The Apr 16 rebuild produced libavformat.a with no TLS backend (no ff_openssl, ff_securetransport, or ff_gnutls symbols), breaking the Player::PlayDreamNow uncached-streaming path with: FFmpeg warning: https or dtls protocol not found Failed to open URL https://... Enable the openssl feature for ffmpeg on !windows (Mac reads /etc/ssl/cert.pem, Linux reads the distro bundle; OpenSSL 3.6.1 is already linked for libcurl since 823d072). Leave Windows on the portfile's default --enable-schannel, which reads the Windows cert store natively; vcpkg's curl[ssl] port already defaults to sspi on Windows for the same reason. Also document the runtime log path (/Users/Shared/infinidream.ai/Logs/) in AGENTS.md. Related: #556 will eventually supersede this by removing ffmpeg's TLS dependency entirely (use libcurl for all network). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
on the previous PR i said
turns out this was a bug that i had just created, not from this branch. fixed now. |
Timecode already refreshed per-frame but server/download status was on the 0.5s RefreshFastDiagnostics cache. Moved both into the dreamStatsVisible block so they tick at frame rate when the overlay is visible and not at all when it isn't. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Post-merge audit: macOS-affecting changes from PR #525 (Linux port)Reviewing all 29 commits brought in through the Linux PR #525 merge ( CATEGORY A — Already fixed1.
|
|
@scottdraves — thanks for the thorough audit, that's a genuinely useful write-up. Confirming your conclusions: CATEGORY A — F2 overlay already fixed, agreed. CATEGORY B — all intentional:
CATEGORY C/D — confirmed, all good. While going through the PR comments I also spotted two real bugs that were reported by wolfwood/zquestz during testing, now fixed in da3a790:
|
Resolve merge conflicts with master: - AGENTS.md: take master's multi-platform log paths + add Linux path - client.h: incorporate settings keybind from master, keep Linux diagnostics struct - ContentDecoder.cpp: unify HW accel under USE_HW_ACCELERATION with D3D11VA (Windows), VAAPI (Linux), and VideoToolbox (macOS)
The cache/univ-osx artifacts committed in a5ac6b3 predate the ffmpeg openssl feature added in 1d998a4, so the universal libs shipped without TLS-dependent protocols (tls, dtls, https, rtmps, gophers, rtmp[e|s|te|ts], ffrtmpcrypt). Streaming uncached dreams on Mac failed with "https or dtls protocol not found". Re-run lipo_dir_merge.py against the per-triplet vcpkg trees to pick up the openssl-enabled ffmpeg. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
tested on mac, looked good, just had to cherry pick the https streaming fix. |
- EDreamClient: fix malformed Api-Key HTTP header (missing colon). curl_slist_append expects "Name: Value" — the missing colon meant the header was never delivered, causing all API-key-only logins to silently fail and return a black screen. - client_linux.h: honour Ctrl modifier on KEY_R and KEY_B. Ctrl+R opens the remote control URL and Ctrl+B opens the playlists page in the browser (mirroring the Mac NSMenu handlers in ESWindow.mm). Without this check both keys triggered their unmodified actions (Repeat / Report) regardless of Ctrl state. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
|
looking good on mac but breaks windows. |
|
@scottdraves - apols, will aim to get that fixed up shortly. |
…y signature - Add DisplayOutput:: namespace to CDisplayDX11 construction/cast sites (Player.cpp, RendererDX11.cpp) - Change ToggleFullscreen() from bool to void; callers now check IsFullscreen() before/after - Update AddDisplay() call sites in client_win32.h to pass nullptr for new middle parameter - Add cachedOnlyMode=false stub in WinMain (--cached flag is Linux-only for now) - Bump generated build version header to 0.1.0 / 6fe1bb1 Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
… feat/linux-pr-525
|
@scottdraves - windows build fixed in commit f1d85f8 |
Commit e0a87d5 added FpsCap(m_PerceptualFPS) to the Run() loop to fix Linux CPU usage, claiming "Run() is only entered from main.cpp on Linux." That is incorrect: WinMain in main.cpp also calls client.Run(), so the cap was throttling the Windows render loop to the perceptual FPS, slowing it down and producing visibly choppy motion. Guard the FpsCap call with #ifdef LINUX_GNU. Windows is paced by DXGI Present and does not need an explicit cap; Mac never enters Run() (uses the Cocoa/display-link loop) and is unaffected either way. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
awesome that works except i got choppy video performance, but it was easy to fix. will continue testing... |
Drop the "Connecting to infinidream.ai..." message and all the font/text plumbing it required. The text was invisible on macOS anyway (CATextLayer starts hidden and nothing unhid it), and it adds nothing useful on the platforms where it did render. Also clean up dead members (m_LogoSize, m_TextureUploaded, m_MoveMessageCounter) and the orphaned m_bServerMessageStartTimer block, plus the dead drawNoSheepIntro branch in client.h. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Force live connectivity probes until the first websocket connection, and tighten the cache interval from 3s to 0.5s. The diagnostics-caching commit widened the auth-done -> websocket-up gap from sub-frame to up to 3 seconds, triggering the "initial connection not yet established" branch before the cache caught up. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
ld --as-needed dropped libssl before the socket.io static archive could reference it, failing with "DSO missing from command line". Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
moved from #525