#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef ZHAVE_VIDEO #include "videoplayer.hpp" #endif #include #include #include "wallpapersurface.hpp" struct mpv_handle; struct mpv_render_context; class QProcess; namespace ZShell::internal { class WallpaperSurface; class WallpaperService : public QObject { Q_OBJECT QML_ELEMENT Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged REQUIRED) Q_PROPERTY(QVariantMap crops READ crops WRITE setCrops NOTIFY cropsChanged) Q_PROPERTY(QString dbPath READ dbPath WRITE setDbPath NOTIFY dbPathChanged) Q_PROPERTY( QSize largestBufferSize READ largestBufferSize NOTIFY largestBufferSizeChanged) public: explicit WallpaperService(QObject* parent = nullptr); ~WallpaperService() override; [[nodiscard]] QString path() const; void setPath(const QString& path); [[nodiscard]] QSize largestBufferSize() const; [[nodiscard]] QString dbPath() const; void setDbPath(const QString& path); void addScreen(const QString& screen); void removeScreen(const QString& screen); [[nodiscard]] const QVariantMap& crops() const; void setCrops(const QVariantMap& crops); Q_INVOKABLE void redraw(); Q_INVOKABLE void setCrop(const QString& screen, const QVariantMap& crop); Q_INVOKABLE void invalidateCache(); signals: void pathChanged(); void cropsChanged(); void dbPathChanged(); void largestBufferSizeChanged(); private: friend class WallpaperSurface; static bool isVideoPath(const QString& path); static bool isHardwareCodec(const QString& codec); [[nodiscard]] QString codecName(const QString& path) const; [[nodiscard]] QString cacheDir() const; [[nodiscard]] QString transcodeTarget(const QString& path) const; [[nodiscard]] bool needsTranscode(const QString& path) const; void transcodeVideo(const QString& src, const QString& dst); void applyPath(const QString& path); void startVideo(const QString& path); void teardownMpv(); void initMpvRender(); void renderMpvToSurface(const QSize& size); void pumpMpvEvents(); static void* getMpvProcAddress(void* ctx, const char* name); static void mpvUpdate(void* ctx); #ifdef ZHAVE_VIDEO bool startPlayerVideo(const QString& path); void stopPlayerVideo(); [[nodiscard]] uint32_t createVideoProgram(); void drawVideoTexture( uint32_t lumaTex, uint32_t chromaTex, int matrix, int range, const QRectF& rect, float sizeW, float sizeH, float srcW, float srcH, float alpha); #endif void bindGlobals(); static void registryGlobal( void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version); void storeGlobal(const char* interface, void* proxy); [[nodiscard]] bool setupGl(); [[nodiscard]] uint32_t createProgram(); void uploadTexture(uint32_t& texture, const QImage& image); void uploadImage(); void createBlackTexture(uint32_t& texture); void drawTexture( uint32_t texture, const QRectF& rect, float sizeW, float sizeH, float alpha); [[nodiscard]] QImage decodeImage( const QString& path, const QSize& decodeSize) const; [[nodiscard]] QByteArray cachedBlob(const QString& path) const; void ensureImage(); void notifyBufferSizes(); void queue(WallpaperSurface* surface); void queueAll(); void loop(); void present(); void drawSurface(WallpaperSurface* surface); void wake(); [[nodiscard]] wl_event_queue* eventQueue() const { return m_queue; } [[nodiscard]] QRectF sourceRect( const QVariantMap& crops, const QString& screen, const QSize& size, const QSize& image) const; void start(); void addSurfaces(); void addSurface(const QString& screen); QString m_path; QString m_dbPath; QStringList m_screens; QVariantMap m_crops; QImage m_image; bool m_isVideo = false; bool m_videoReload = false; bool m_previousVideo = false; mpv_handle* m_mpv = nullptr; mpv_render_context* m_mpvRender = nullptr; uint32_t m_blackTex = 0; std::atomic m_mpvFrameReady{false}; std::atomic m_videoReady{false}; std::atomic m_videoLoaded{false}; QProcess* m_transcode = nullptr; QSize m_decodeSize; QImage m_stagedImage; QString m_stagedPath; bool m_stagedReady = false; bool m_decoding = false; QString m_decodePath; bool m_replacementReady = false; wl_display* m_display = nullptr; wl_registry* m_registry = nullptr; wl_compositor* m_compositor = nullptr; QtWayland::zwlr_layer_shell_v1* m_layerShell = nullptr; QtWayland::wp_viewporter* m_viewporter = nullptr; QtWayland::wp_fractional_scale_manager_v1* m_scaleManager = nullptr; EGLDisplay m_eglDisplay = EGL_NO_DISPLAY; EGLConfig m_config = nullptr; EGLContext m_context = EGL_NO_CONTEXT; uint32_t m_texture = 0; uint32_t m_program = 0; int m_sizeUniform = -1; int m_cropUniform = -1; int m_alphaUniform = -1; int m_sourceUniform = -1; uint32_t m_videoProgram = 0; uint32_t m_vao = 0; int m_videoSizeUniform = -1; int m_videoSrcSizeUniform = -1; int m_videoCropUniform = -1; int m_videoAlphaUniform = -1; int m_videoLumaUniform = -1; int m_videoChromaUniform = -1; int m_videoMatrixUniform = -1; int m_videoRangeUniform = -1; int m_videoChromaOffUniform = -1; #ifdef ZHAVE_VIDEO std::unique_ptr m_player; bool m_usePlayer = true; #endif QImage m_previousImage; QVariantMap m_previousCrops; uint32_t m_previousTexture = 0; std::vector m_orphanTextures; bool m_fading = false; bool m_fadeClockStarted = false; bool m_firstFadeDone = false; QElapsedTimer m_fadeTimer; QList m_surfaces; std::thread m_thread; mutable std::recursive_mutex m_mutex; wl_event_queue* m_queue = nullptr; int m_wake[2] = {-1, -1}; bool m_stop = false; bool m_drawing = false; bool started = false; bool m_forceDecode = false; bool m_imageChanged = false; }; } // namespace ZShell::internal