#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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) public: explicit WallpaperService(QObject* parent = nullptr); ~WallpaperService() override; [[nodiscard]] QString path() const; void setPath(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); signals: void pathChanged(); void cropsChanged(); 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 stopVideo(); void teardownMpv(); void initMpvRender(); void renderMpvToSurface(const QSize& size); void pumpMpvEvents(); static void* getMpvProcAddress(void* ctx, const char* name); static void mpvUpdate(void* ctx); 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); bool decode(const QString& path); bool ensureDecodeSize(); [[nodiscard]] QSize largestBufferSize(); void queue(WallpaperSurface* surface); void queueAll(); void startDrawing(); 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; 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_sourceSize; QSize m_decodeSize; 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; QImage m_previousImage; QVariantMap m_previousCrops; uint32_t m_previousTexture = 0; 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