WallpaperApplication.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. #pragma once
  2. #include <atomic>
  3. #include <chrono>
  4. #include <random>
  5. #include "WallpaperEngine/Application/ApplicationContext.h"
  6. #include "WallpaperEngine/Assets/AssetLocator.h"
  7. #include "WallpaperEngine/Render/CWallpaper.h"
  8. #include "WallpaperEngine/Render/Drivers/Detectors/FullScreenDetector.h"
  9. #include "WallpaperEngine/Render/Drivers/GLFWOpenGLDriver.h"
  10. #include "WallpaperEngine/Render/Drivers/Output/GLFWWindowOutput.h"
  11. #include "WallpaperEngine/Render/RenderContext.h"
  12. #include "WallpaperEngine/Audio/Drivers/SDLAudioDriver.h"
  13. #include "WallpaperEngine/Input/InputContext.h"
  14. #include "WallpaperEngine/WebBrowser/WebBrowserContext.h"
  15. #include "WallpaperEngine/Data/JSON.h"
  16. #include "WallpaperEngine/Data/Model/Types.h"
  17. #include "WallpaperEngine/Media/MediaSource.h"
  18. #include <set>
  19. namespace WallpaperEngine::Application {
  20. using namespace WallpaperEngine::Assets;
  21. using namespace WallpaperEngine::Data::Model;
  22. class WallpaperApplication {
  23. public:
  24. explicit WallpaperApplication (ApplicationContext& context);
  25. void setup ();
  26. void render ();
  27. static void cleanup ();
  28. void show ();
  29. void signal (int signal);
  30. /**
  31. * Entry point for a disposable CEF host child process (settings.general.webHost) instead of
  32. * embedding CEF in the main engine process. Never touches Wayland/GL/audio. Runs until the
  33. * main process signals quit through shared memory (or this process is killed).
  34. */
  35. void runWebHost ();
  36. [[nodiscard]] const std::map<std::string, ProjectUniquePtr>& getBackgrounds () const;
  37. [[nodiscard]] ApplicationContext& getContext () const;
  38. void update (Render::Drivers::Output::OutputViewport* viewport);
  39. [[nodiscard]] const WallpaperEngine::Render::Drivers::Output::Output& getOutput () const;
  40. /** If not called, the default framebuffer will be used */
  41. void setDestinationFramebuffer (GLuint framebuffer);
  42. /** Returns 0 (the default framebuffer) if setDestinationFramebuffer() was never called */
  43. [[nodiscard]] GLuint getDestinationFramebuffer () const;
  44. private:
  45. /** A project.json ready to be parsed. For presets, json is the base wallpaper's and preset holds the overrides */
  46. struct ProjectSource {
  47. AssetLocatorUniquePtr container;
  48. WallpaperEngine::Data::JSON::JSON json;
  49. std::optional<WallpaperEngine::Data::JSON::JSON> preset;
  50. };
  51. /** overlay is an extra folder mounted after bg, used for preset-owned files (e.g. splat data) */
  52. AssetLocatorUniquePtr setupAssetLocator (const std::string& bg, const std::filesystem::path& overlay = {}) const;
  53. ProjectSource openProjectSource (const std::string& path) const;
  54. static void applyPreset (
  55. const Project& project, const WallpaperEngine::Data::JSON::JSON& preset, const std::filesystem::path& presetDir
  56. );
  57. void initializeSubsystems ();
  58. void loadBackgrounds ();
  59. [[nodiscard]] ProjectUniquePtr loadBackground (const std::string& bg);
  60. void setupProperties ();
  61. void setupPropertiesForProject (const Project& project);
  62. /** Prints objects/layers for every loaded background, triggered by --list-objects */
  63. void listObjects () const;
  64. void listObjectsForProject (const std::string& background, const Project& project) const;
  65. /** Prints per-object effects (bloom, blur, glow, etc) for every loaded background, triggered by --list-effects */
  66. void listEffects () const;
  67. void listEffectsForProject (const std::string& background, const Project& project) const;
  68. /** Applies --audio-sensitivity overrides for every loaded background */
  69. void setupAudioSensitivity ();
  70. void setupAudioSensitivityForProject (const Project& project) const;
  71. /** Prints audio-reactive objects/properties for every loaded background, triggered by --list-audio-objects */
  72. void listAudioObjects () const;
  73. void listAudioObjectsForProject (const std::string& background, const Project& project) const;
  74. /** Applies --sound-volume overrides for every loaded background */
  75. void setupSoundVolume ();
  76. void setupSoundVolumeForProject (const Project& project) const;
  77. void setupBrowser ();
  78. void setupOutput ();
  79. void setupAudio ();
  80. /** Starts audio capture for a wallpaper loaded after startup, setupAudio() only saw the first ones */
  81. void ensureAudioCapture (const Project& project);
  82. void prepareOutputs ();
  83. void setupOpenGLDebugging ();
  84. void takeScreenshot (const std::filesystem::path& filename) const;
  85. struct ActivePlaylist {
  86. ApplicationContext::PlaylistDefinition definition;
  87. std::vector<std::size_t> order;
  88. std::size_t orderIndex = 0;
  89. std::chrono::steady_clock::time_point nextSwitch;
  90. std::chrono::steady_clock::time_point lastUpdate;
  91. std::set<std::size_t> failedIndices;
  92. };
  93. void initializePlaylists ();
  94. void updatePlaylists ();
  95. void checkHotswapRequest ();
  96. void advancePlaylist (
  97. const std::string& screen, ActivePlaylist& playlist, const std::chrono::steady_clock::time_point& now
  98. );
  99. bool selectNextCandidate (ActivePlaylist& playlist, std::size_t& outOrderIndex);
  100. bool preflightWallpaper (const std::string& path);
  101. std::vector<std::size_t> buildPlaylistOrder (const ApplicationContext::PlaylistDefinition& definition);
  102. bool makeAnyViewportCurrent () const;
  103. /** True if this process was re-exec'd by CEF as a subprocess helper (--type=renderer/gpu-process/...) */
  104. bool isCefSubprocess () const;
  105. /**
  106. * Pushes a volume change live to already-running video players and the SDL audio mixer,
  107. * without touching the loaded projects. volume is 0-128, matching --volume.
  108. */
  109. void applyVolumeHotswap (int volume);
  110. void applyFpsHotswap (int fps);
  111. /**
  112. * Pushes a full-xray toggle live to the renderer, without touching the loaded projects.
  113. * value is "on"/"off"/"toggle" (also accepts "1"/"0"/"true"/"false" for on/off).
  114. */
  115. void applyXrayHotswap (const std::string& value);
  116. /**
  117. * Pushes a scaling mode change ("stretch"/"fit"/"fill"/"center"/"default") live to every
  118. * currently rendered wallpaper, without reloading the loaded projects. Applies to all screens,
  119. * same as the other hotswap setters below.
  120. */
  121. void applyScalingHotswap (const std::string& value);
  122. /** Pushes a manual zoom factor (e.g. "1.5") live to every currently rendered wallpaper */
  123. void applyZoomHotswap (const std::string& value);
  124. /** Pushes an offset re-center (e.g. "0.5,-1") live to every currently rendered wallpaper */
  125. void applyOffsetHotswap (const std::string& value);
  126. /**
  127. * Pushes a force-disable-parallax toggle live. This is a straight passthrough to
  128. * settings.mouse.disableparallax, which every parallax-capable object (CImage/CText/CParticle) and
  129. * CScene's mouse-follow logic already reads directly every frame, so no reload or per-wallpaper
  130. * plumbing is needed at all. value is "on"/"off"/"toggle" (also "1"/"0"/"true"/"false").
  131. */
  132. void applyParallaxHotswap (const std::string& value);
  133. /**
  134. * Pushes a corner color change (hex RGB/RGBA, e.g. "000000" or "#1a1a1aff") live to every
  135. * currently rendered wallpaper. Only visible where clamp mode is border.
  136. */
  137. void applyCornerColorHotswap (const std::string& value);
  138. /**
  139. * Pushes a playback speed multiplier (e.g. "0.5") live. Straight passthrough to
  140. * settings.render.playbackSpeed, which render() reads directly every frame to scale the
  141. * dt fed into g_Time, so no reload or per-wallpaper plumbing is needed at all.
  142. */
  143. void applySpeedHotswap (const std::string& value);
  144. /**
  145. * Pushes a new --audio-screen restriction live (empty value clears it back to "no
  146. * restriction"), then re-applies audio policy to every currently rendered wallpaper.
  147. */
  148. void applyAudioScreenHotswap (const std::string& value);
  149. /** Pushes a new --ambient-volume (0-128) live, then re-applies audio policy to every currently rendered wallpaper */
  150. void applyAmbientVolumeHotswap (const std::string& value);
  151. /**
  152. * Pushes --sound-volume overrides (id-or-name -> 0-1 volume) live to every Sound object in the
  153. * currently loaded projects, without reloading - unlike --set-property/--audio-sensitivity,
  154. * Sound objects already re-read their own volume every frame (see CSound::render()), so this
  155. * is a pure live setter.
  156. */
  157. void applySoundVolumeHotswap (const std::map<std::string, std::string>& targets);
  158. /**
  159. * Recomputes and pushes CWallpaper::setAudioPolicy() to every currently rendered wallpaper
  160. * based on settings.audio.audioScreen/ambientVolume. Span-group screens share a single
  161. * CWallpaper instance across several screen names, so this groups by instance first and
  162. * only mutes one if none of its screens match audioScreen.
  163. */
  164. void applyAudioPolicy ();
  165. /**
  166. * Figures out what background a given screen is currently showing, so a layers-only
  167. * hotswap can reload it without the caller having to resend the path
  168. */
  169. [[nodiscard]] std::string resolveScreenBackgroundPath (const std::string& screen) const;
  170. [[nodiscard]] float resolveScreenZoom (const std::string& screen) const;
  171. [[nodiscard]] glm::vec2 resolveScreenOffset (const std::string& screen) const;
  172. [[nodiscard]] glm::vec4 resolveScreenCornerColor (const std::string& screen) const;
  173. // The resolution a Web wallpaper on this screen will actually be rendered at - falls back to
  174. // the combined bounding box of every active screen if this one isn't registered yet.
  175. [[nodiscard]] glm::ivec2 resolveScreenRenderSize (const std::string& screen) const;
  176. ApplicationContext& m_context;
  177. std::map<std::string, ProjectUniquePtr> m_backgrounds {};
  178. std::map<std::string, ActivePlaylist> m_activePlaylists {};
  179. std::unique_ptr<WallpaperEngine::Audio::Drivers::Detectors::AudioPlayingDetector> m_audioDetector = nullptr;
  180. std::unique_ptr<WallpaperEngine::Audio::AudioContext> m_audioContext = nullptr;
  181. std::unique_ptr<WallpaperEngine::Audio::Drivers::SDLAudioDriver> m_audioDriver = nullptr;
  182. std::unique_ptr<WallpaperEngine::Audio::Drivers::Recorders::PlaybackRecorder> m_audioRecorder = nullptr;
  183. // the recorder replaced by ensureAudioCapture(), the outgoing wallpaper's passes still point into it
  184. std::unique_ptr<WallpaperEngine::Audio::Drivers::Recorders::PlaybackRecorder> m_previousAudioRecorder = nullptr;
  185. bool m_audioCapturing = false;
  186. std::unique_ptr<WallpaperEngine::Render::RenderContext> m_renderContext = nullptr;
  187. std::unique_ptr<WallpaperEngine::Render::Drivers::VideoDriver> m_videoDriver = nullptr;
  188. std::unique_ptr<WallpaperEngine::Render::Drivers::Detectors::FullScreenDetector> m_fullScreenDetector = nullptr;
  189. std::unique_ptr<WallpaperEngine::WebBrowser::WebBrowserContext> m_browserContext = nullptr;
  190. std::unique_ptr<WallpaperEngine::Media::MediaSource> m_mediaSource = nullptr;
  191. std::mt19937 m_playlistRng { std::random_device {}() };
  192. std::atomic<bool> m_hotswapRequested { false };
  193. bool m_isPaused = false;
  194. bool m_screenShotTaken = false;
  195. uint32_t m_nextFrameScreenshot = 0;
  196. std::chrono::steady_clock::time_point m_pauseStart {};
  197. GLuint m_destinationFramebuffer = 0;
  198. };
  199. } // namespace WallpaperEngine::Application