diff --git a/.github/actions/web/action.yaml b/.github/actions/web/action.yaml index 5ccce0646..2e0e41162 100644 --- a/.github/actions/web/action.yaml +++ b/.github/actions/web/action.yaml @@ -27,11 +27,11 @@ runs: - name: Build website shell: bash run: cd web && make prod - - name: Generate liboxide docs - shell: bash - run: | - cd shared/liboxide && make prod - name: Generate libblight docs shell: bash run: | cd shared/libblight && make prod + - name: Generate liboxide docs + shell: bash + run: | + cd shared/liboxide && make prod diff --git a/shared/libblight/Doxyfile b/shared/libblight/Doxyfile index c9ff02f50..b551592dd 100644 --- a/shared/libblight/Doxyfile +++ b/shared/libblight/Doxyfile @@ -13,8 +13,13 @@ HTML_EXTRA_FILES = ../doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js \ ../doxygen-awesome-css/doxygen-awesome-fragment-copy-button.js \ ../doxygen-awesome-css/doxygen-awesome-paragraph-link.js HTML_HEADER = ../doxygen-header.html -PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS +PREDEFINED += DOXYGEN_SHOULD_SKIP_THIS +PREDEFINED += IN_DOXYGEN HIDE_UNDOC_MEMBERS = YES HIDE_UNDOC_CLASSES = YES MACRO_EXPANSION = YES EXAMPLE_PATH = examples +GENERATE_TAGFILE = html/libblight.tag +ALLEXTERNALS = Yes +ALIASES = "accessors=\par Accessors:^^" +ALIASES += "notifier=\par Notifier signal:^^" diff --git a/shared/libblight/connection.h b/shared/libblight/connection.h index 5d92941b0..c55ff2e33 100644 --- a/shared/libblight/connection.h +++ b/shared/libblight/connection.h @@ -100,6 +100,7 @@ namespace Blight { * \param type Type of message * \param data Data to send * \param size Size of data + * \param __ackid Unique identifier to use, will automatically generate if set to 0 * \return ack_ptr_t if the message was sent */ maybe_ackid_ptr_t send(MessageType type, data_t data, size_t size, unsigned int __ackid = 0); diff --git a/shared/libblight/libblight.h b/shared/libblight/libblight.h index 3f1fe41d9..e025fdacb 100644 --- a/shared/libblight/libblight.h +++ b/shared/libblight/libblight.h @@ -9,6 +9,9 @@ #include "connection.h" #include +/*! + * \brief Blight namespace + */ namespace Blight{ /*! * \brief Connect to DBus diff --git a/shared/libblight/libblight.pro b/shared/libblight/libblight.pro index f38b042d4..b2143e4e2 100644 --- a/shared/libblight/libblight.pro +++ b/shared/libblight/libblight.pro @@ -75,3 +75,6 @@ QMAKE_PKGCONFIG_PREFIX = /opt QMAKE_PKGCONFIG_LIBDIR = /opt/lib QMAKE_PKGCONFIG_INCDIR = /opt/include QMAKE_PKGCONFIG_DESTDIR = pkgconfig + +DISTFILES += \ + Doxyfile diff --git a/shared/liboxide/Doxyfile b/shared/liboxide/Doxyfile index 6fd055461..fec86e929 100644 --- a/shared/liboxide/Doxyfile +++ b/shared/liboxide/Doxyfile @@ -13,8 +13,14 @@ HTML_EXTRA_FILES = ../doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js \ ../doxygen-awesome-css/doxygen-awesome-fragment-copy-button.js \ ../doxygen-awesome-css/doxygen-awesome-paragraph-link.js HTML_HEADER = ../doxygen-header.html -PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS +PREDEFINED += DOXYGEN_SHOULD_SKIP_THIS +PREDEFINED += IN_DOXYGEN HIDE_UNDOC_MEMBERS = YES HIDE_UNDOC_CLASSES = YES MACRO_EXPANSION = YES EXAMPLE_PATH = examples +GENERATE_TAGFILE = html/liboxide.tag +ALLEXTERNALS = Yes +TAGFILES = ../libblight/html/libblight.tag=../libblight/ +ALIASES += "accessors=\par Accessors:^^" +ALIASES += "notifier=\par Notifier signal:^^" diff --git a/shared/liboxide/dbus.h b/shared/liboxide/dbus.h index 8eb82e757..6ffaa2aab 100644 --- a/shared/liboxide/dbus.h +++ b/shared/liboxide/dbus.h @@ -10,7 +10,61 @@ // This must be here to make precompiled headers happy #ifndef LIBOXIDE_DBUS_H #define LIBOXIDE_DBUS_H - +#ifdef IN_DOXYGEN +/*! + * \brief System service DBus interfaces + */ +namespace codes::eeems::oxide1{ + /*! + * \brief General API interface + */ + class General : public QDBusAbstractInterface{}; + /*! + * \brief The Power class + */ + class Power : public QDBusAbstractInterface{}; + /*! + * \brief The Wifi class + */ + class Wifi : public QDBusAbstractInterface{}; + /*! + * \brief The Network class + */ + class Network : public QDBusAbstractInterface{}; + /*! + * \brief The BSS class + */ + class BSS : public QDBusAbstractInterface{}; + /*! + * \brief The Apps class + */ + class Apps : public QDBusAbstractInterface{}; + /*! + * \brief The Application class + */ + class Application : public QDBusAbstractInterface{}; + /*! + * \brief The System class + */ + class System : public QDBusAbstractInterface{}; + /*! + * \brief The Screen class + */ + class Screen : public QDBusAbstractInterface{}; + /*! + * \brief The Screenshot class + */ + class Screenshot : public QDBusAbstractInterface{}; + /*! + * \brief The Notifications class + */ + class Notifications : public QDBusAbstractInterface{}; + /*! + * \brief The Notification class + */ + class Notification : public QDBusAbstractInterface{}; +} +#endif #include "dbusservice_interface.h" #include "powerapi_interface.h" #include "wifiapi_interface.h" @@ -23,8 +77,17 @@ #include "screenshot_interface.h" #include "notificationapi_interface.h" #include "notification_interface.h" - +#ifdef IN_DOXYGEN +/*! + * \brief Display server DBus interfaces + */ +namespace codes::eeems::blight1{ + /*! + * \brief Display server compositor API + */ + class Compositor : public QDBusAbstractInterface{}; +} +#endif #include "blight_interface.h" - #endif // LIBOXIDE_DBUS_H /*! @} */ diff --git a/shared/liboxide/debug.h b/shared/liboxide/debug.h index 5d0a6ad33..47be9a21d 100644 --- a/shared/liboxide/debug.h +++ b/shared/liboxide/debug.h @@ -23,7 +23,7 @@ /*! * \def __RIGHT_HERE__ * \brief Log the current file and line number - * \note This is only available if DEBUG is defined + * \note This will only do anything if DEBUG is defined */ #ifdef __RIGHT_HERE__ #undef __RIGHT_HERE__ @@ -95,9 +95,9 @@ namespace Oxide { /*! * \brief Get a formatted debug information string * \note this is automatically included in O_DEBUG, O_WARNING, O_INFO, and O_EVENT - * \param Name of file - * \param Line number in file - * \param Function information + * \param file Name of file + * \param line Line number in file + * \param function Function information * \return Formatted debug location string */ LIBOXIDE_EXPORT std::string getDebugLocation(const char* file, unsigned int line, const char* function); @@ -109,7 +109,7 @@ namespace Oxide { LIBOXIDE_EXPORT bool debugEnabled(); /*! * \brief Get the name of the application - * \param Don't use qApp's application name + * \param ignoreQApp Don't use qApp's application name * \return The name of the application */ LIBOXIDE_EXPORT std::string getAppName(bool ignoreQApp); diff --git a/shared/liboxide/devicesettings.h b/shared/liboxide/devicesettings.h index 3ebafa5db..e7ad2e833 100644 --- a/shared/liboxide/devicesettings.h +++ b/shared/liboxide/devicesettings.h @@ -101,7 +101,7 @@ namespace Oxide{ QString getTimezone(); /*! * \brief Set the current timezone - * \param locale Timezone to set + * \param timezone Timezone to set */ void setTimezone(const QString& timezone); /*! diff --git a/shared/liboxide/event_device.h b/shared/liboxide/event_device.h index d3955702a..cf4482bd2 100644 --- a/shared/liboxide/event_device.h +++ b/shared/liboxide/event_device.h @@ -17,74 +17,98 @@ using namespace std; namespace Oxide { /*! - * \brief The event_device class + * \brief A class to simplify managing a /dev/event* file */ class LIBOXIDE_EXPORT event_device { public: + /*! + * \brief Create an input_event + * \param type Input event type + * \param code Input event code + * \param value Input event value + * \return + */ static input_event create_event(ushort type, ushort code, int value); /*! - * \brief event_device - * \param path - * \param flags + * \brief Instantiate a new instance + * \param path Path to the event device + * \param flags Flags to use when opening the event device */ event_device(const string& path, int flags); + /*! + * \brief Create a copy of an event_device instance + * \param other Instance to copy + */ event_device(const event_device& other); ~event_device(); /*! - * \brief close + * \brief Close the event device + * \sa open() */ void close(); /*! - * \brief open + * \brief Open the event device + * \sa fd, error, close() */ void open(); /*! - * \brief lock - * \return + * \brief Grab all input from this device + * \return If grabbing was successful + * \retval 0 Successfully grabbed all input + * \retval EBUSY The event device is grabbed by another process + * \sa locked unlock() */ int lock(); /*! - * \brief unlock - * \return + * \brief Ungrab all input from this device + * \return If ungrabbing was successful + * \retval 0 Successfully ungrabbed all input + * \sa locked, lock() */ int unlock(); /*! - * \brief write - * \param ie + * \brief Write an input event to the event device + * \param ie Input event to write + * \sa write(ushort, ushort, int) */ void write(input_event ie); /*! - * \brief write_event - * \param device - * \param type - * \param code - * \param value + * \brief Write an input event to the event device + * \param type Input event type + * \param code Input event code + * \param value Input event value + * \sa write(input_event) */ void write(ushort type, ushort code, int value); /*! - * \brief ev_syn + * \brief Write an EV_SYN SYN_REPORT event to the event device */ void ev_syn(); /*! - * \brief ev_dropped + * \brief Write an EV_SYN SYN_DROPPED event to the event device */ void ev_dropped(); /*! - * \brief error + * \brief Errno reported when opening the event device + * \sa open() */ int error; /*! - * \brief fd + * \brief File descriptor returned when opening the event device + * \sa open(), close() */ int fd; /*! - * \brief device + * \brief Path to the event device + * \sa event_device(const string&, int) */ string device; /*! - * \brief locked + * \brief If input is currently grabbed + * \sa lock(), unlock() */ bool locked = false; + private: int flags; }; diff --git a/shared/liboxide/eventfilter.h b/shared/liboxide/eventfilter.h index 17260a799..f79f5817c 100644 --- a/shared/liboxide/eventfilter.h +++ b/shared/liboxide/eventfilter.h @@ -30,8 +30,7 @@ namespace Oxide{ * \param parent The parent object. Usually should be qApp */ explicit EventFilter(QObject* parent = nullptr); - signals: - void suspend(); + protected: bool eventFilter(QObject* obj, QEvent* ev); }; diff --git a/shared/liboxide/liboxide.pro b/shared/liboxide/liboxide.pro index e23eb24c4..fb772e5fa 100644 --- a/shared/liboxide/liboxide.pro +++ b/shared/liboxide/liboxide.pro @@ -137,5 +137,6 @@ RESOURCES += \ oxide.qrc DISTFILES += \ + Doxyfile \ OxideMenu.qml \ OxideWindow.qml diff --git a/shared/liboxide/liboxide_global.h b/shared/liboxide/liboxide_global.h index 6901768c3..e1b4f9167 100644 --- a/shared/liboxide/liboxide_global.h +++ b/shared/liboxide/liboxide_global.h @@ -1,8 +1,3 @@ -/*! - * \addtogroup Oxide - * @{ - * \file - */ #pragma once #include @@ -23,4 +18,3 @@ #else # define ATTRIBUTE_NO_SANITIZE_ADDRESS #endif -/*! @} */ diff --git a/shared/liboxide/oxideqml.h b/shared/liboxide/oxideqml.h index 491dc270f..83a5aa3eb 100644 --- a/shared/liboxide/oxideqml.h +++ b/shared/liboxide/oxideqml.h @@ -1,3 +1,9 @@ +/*! + * \addtogroup QML + * \brief The QML module + * @{ + * \file + */ #pragma once #include @@ -11,42 +17,160 @@ #include namespace Oxide { + /*! + * \brief The Oxide::QML namespace + */ namespace QML{ + /*! + * \brief An object available as Oxide in qml that provides useful properties and methods + * + * Example: + * + * ```qml + * Item { + * enabled: Oxide.landscape && Oxide.deviceName === "reMarkable 2" + * } + * ``` + */ class OxideQml : public QObject{ Q_OBJECT + /*! + * \brief If the device should be in landscape or not + * \accessors landscape() + * \notifier landscapeChanged(bool) + */ Q_PROPERTY(bool landscape READ landscape NOTIFY landscapeChanged) + /*! + * \brief The name of the device + * \accessors deviceName() + */ Q_PROPERTY(QString deviceName READ deviceName CONSTANT) QML_NAMED_ELEMENT(Oxide) QML_SINGLETON + public: explicit OxideQml(QObject *parent = nullptr); + /*! + * \brief Check if the device should be in landscape mode or not + * \return If the device should be in landscape or not + * \sa landscape, landscapeChanged(bool) + */ bool landscape(); + /*! + * \brief Get the name of the device + * \return The name of the device + * \retval "reMarkable 1" + * \retval "reMarkable 2" + * \retval "Unknown" + * \sa deviceName + */ QString deviceName(); + /*! + * \brief Get a QBrush for a colour + * \param color Colour + * \return QBrush for a colour + */ Q_INVOKABLE QBrush brushFromColor(const QColor& color); signals: + /*! + * \brief The value of landscape changed + * \sa landscape, landscape() + */ void landscapeChanged(bool); }; - + /*! + * \brief A canvas widget + * + * Example: + * ```qml + * import "qrc://codes.eeems.oxide" + * import codes.eeems.oxide 3.0 + * + * OxideWindow{ + * initialItem: Canvas{ + * anchors.fill: parent + * brush: Oxide.brushFromColor(Qt.black) + * penWidth: 12 + * } + * } + * ``` + */ class Canvas : public QQuickPaintedItem { Q_OBJECT + /*! + * \property brush + * \brief Current brush used when drawing + * \accessors brush(), setBrush(QBrush) + * \notifier brushChanged(const QBrush&) + */ Q_PROPERTY(QBrush brush READ brush WRITE setBrush NOTIFY brushChanged) + /*! + * \property penWidth + * \brief Current pen width used when drawing + * \accessors penWidth(), setPenWidth(qreal) + * \notifier penWidthChanged(qreal) + */ Q_PROPERTY(qreal penWidth READ penWidth WRITE setPenWidth NOTIFY penWidthChanged) QML_ELEMENT public: + /*! + * \brief Create a new canvas instance + * \param parent Parent widget + */ Canvas(QQuickItem* parent = nullptr); void paint(QPainter* painter) override; + /*! + * \brief Current brush used when drawing + * \return The current brush + * \sa brush, setBrush(QBrush), brushChanged(const QBrush&) + */ QBrush brush(); + /*! + * \brief Set the current brush that is used for drawing + * \param brush Brush to use + * \sa brush, brush(), brushChanged(const QBrush&) + */ void setBrush(QBrush brush); + /*! + * \brief Current pen width used when drawing + * \return The current pen with + * \sa penWidth, setPenWidth(QBrush), penWidthChanged(const QBrush&) + */ qreal penWidth(); + /*! + * \brief Set the current pen width used for drawing + * \param penWidth Pen width to use + * \sa penWidth, penWidth(), penWidthChanged(qreal) + */ void setPenWidth(qreal penWidth); + /*! + * \brief QImage instance of the current canvas + * \return QImage instanceof the current canvas + */ QImage* image(); signals: + /*! + * \brief The user has started drawing on the canvas + */ void drawStart(); + /*! + * \brief The user has finished drawing on the canvas + */ void drawDone(); + /*! + * \brief The current brush used for drawing has been changed + * \param brush New brush + * \sa brush, brush(), setBrush(QBrush) + */ void brushChanged(const QBrush& brush); + /*! + * \brief The current pen width used for drawing has been changed + * \param pendWidth New pen width + * \sa penWidth, penWidth(), setPenWidth(qreal) + */ void penWidthChanged(qreal pendWidth); protected: @@ -61,18 +185,53 @@ namespace Oxide { QBrush m_brush; qreal m_penWidth; }; - + /*! + * \brief Get the display server buffer that represents a surface for a QWindow + * \param window The Window to get the surface buffer for + * \return The buffer that represents the display server surface + */ Blight::shared_buf_t getSurfaceForWindow(QWindow* window); + /*! + * \brief Get the a QImage that can be used to manipulate a display server buffer + * \param buffer The buffer to create the QImage instance for + * \return A QImage instance that can be used to manipulate a display server buffer + */ QImage getImageForSurface(Blight::shared_buf_t buffer); + /*! + * \brief Get a QImage instance that can be used to manipulate a display server buffer for a QWindow + * \param window The QWindow instance + * \return A QImage instance that can be used to manipulate a display server buffer for the QWindow + */ QImage getImageForWindow(QWindow* window); + /*! + * \brief Repaint a surface for a QWindow on the display server + * \param window The QWindow instance to repaint + * \param rect The area of the QWindow to repaint + * \param waveform The waveform to use for repainting + * \param sync If the method should wait for the repaint to finish before continuing + */ void repaint( QWindow* window, QRectF rect, Blight::WaveformMode waveform = Blight::WaveformMode::HighQualityGrayscale, bool sync = false ); - + /*! + * \brief Get the OxideQML singleton instance + * \return The OxideQML singleton instance + * \sa OxideQML + */ OxideQml* getSingleton(); + /*! + * \brief Register the %QML extensions that liboxide provides + * \param engine The QQmlApplicationEngine instance that this application is using + * \sa OxideQml, Canvas + * + * This registers the OxideQML singleton so that it can be accessed via Oxide in QML. + * It also registers the built in QML classes that liboxide provides so that they can be imported with `import "qrc://codes.eeems.oxide"`. + * Other classes are available for import with `import codes.eeems.oxide 3.0` + */ void registerQML(QQmlApplicationEngine* engine); } } +/*! @} */ diff --git a/shared/liboxide/settingsfile.h b/shared/liboxide/settingsfile.h index 5de0183df..316dd0f89 100644 --- a/shared/liboxide/settingsfile.h +++ b/shared/liboxide/settingsfile.h @@ -92,30 +92,31 @@ O_SETTINGS_PROPERTY_BODY_2, \ O_SETTINGS_PROPERTY_BODY_1, \ ) +#ifdef IN_DOXYGEN /*! - * \def O_SETTINGS_PROPERTY * \brief Add a property to a SettingsFile derived class - * \param _type Type of property + * \param type Type of property * \param group Group name for property. This usually should be ``General`` * \param member Property name - * \param _default Optional default value + * \param default Optional default value * \sa O_SETTINGS, O_SETTINGS_PROPERTY_BODY, Oxide::SettingsFile */ -#define O_SETTINGS_PROPERTY(...) O_SETTINGS_PROPERTY_X(__VA_ARGS__)(__VA_ARGS__) +#define O_SETTINGS_PROPERTY(type, group, member, ...) O_SETTINGS_PROPERTY_X(type, group, member, __VA_ARGS__)(type, group, member, __VA_ARGS__) /*! - * \def O_SETTINGS_PROPERTY_BODY * \brief Add the body for a property on a SettingsFile derived class - * \param _class Class name - * \param _type Type of property + * \param class Class name + * \param type Type of property * \param group Group name for property. This usually should be ``General`` * \param member Property name - * \param _default Optional default value + * \param default Optional default value * \sa O_SETTINGS, O_SETTINGS_PROPERTY, Oxide::SettingsFile */ +#define O_SETTINGS_PROPERTY_BODY(class, type, group, member, ...) O_SETTINGS_PROPERTY_BODY_X(class, type, group, member, __VA_ARGS__)(class, type, group, member, __VA_ARGS__) +#else +#define O_SETTINGS_PROPERTY(...) O_SETTINGS_PROPERTY_X(__VA_ARGS__)(__VA_ARGS__) #define O_SETTINGS_PROPERTY_BODY(...) O_SETTINGS_PROPERTY_BODY_X(__VA_ARGS__)(__VA_ARGS__) - +#endif /*! - * \def O_SETTINGS * \brief Define the instance() and constructor methods for a SettingsFile derived class * \param _type Class name * \param path Path to file on disk that stores the settings @@ -143,7 +144,11 @@ namespace Oxide { */ class LIBOXIDE_EXPORT SettingsFile : public QSettings { Q_OBJECT + signals: + /*! + * \brief The settings file has changed + */ void changed(); private slots: diff --git a/shared/liboxide/socketpair.h b/shared/liboxide/socketpair.h index ee8ff7bbe..713c1590e 100644 --- a/shared/liboxide/socketpair.h +++ b/shared/liboxide/socketpair.h @@ -1,38 +1,128 @@ +/*! + * \addtogroup Oxide + * @{ + * \file + */ #pragma once #include "liboxide_global.h" #include namespace Oxide{ + /*! + * \brief A socket pair used for two way communication + */ class LIBOXIDE_EXPORT SocketPair : public QObject{ Q_OBJECT public: + /*! + * \brief Create a new socket pair + * \param allowWriteSocketRead Allow reading from the write socket, this allows messages to be sent by the other end of the socket + */ SocketPair(bool allowWriteSocketRead = false); ~SocketPair(); + /*! + * \brief Is this socket pair valid + * \return If this socket pair valid + */ bool isValid(); + /*! + * \brief Is this socket pair readable + * \return If this socket pair readable + */ bool isReadable(); + /*! + * \brief Is this socket pair open + * \return If this socket pair open + */ bool isOpen(); + /*! + * \brief The QLocalSocket instance of the read socket + * \return The QLocalSocket instance of the read socket + */ QLocalSocket* readSocket(); + /*! + * \brief The QLocalSocket instance of the write socket + * \return The QLocalSocket instance of the write socket + */ QLocalSocket* writeSocket(); + /*! + * \brief Enable or disable reading and writing to this socket pair + * \param enabled If reading and writing to this socket pair is enabled + */ void setEnabled(bool enabled); + /*! + * \brief Is reading and writing to this socket pair is enabled + * \return If reading and writing to this socket pair is enabled + */ bool enabled(); + /*! + * \brief Is there more data available to read from the read socket + * \return If there more data available to read from the read socket + */ bool atEnd(); + /*! + * \brief Read a line from the read socket + * \param maxlen Maxiumum amount of data to read + * \return The line of data + */ QByteArray readLine(qint64 maxlen = 0); + /*! + * \brief Read all available data on the read socket + * \return The data + */ QByteArray readAll(); + /*! + * \brief Read data from the read socket + * \param maxlen maximum amount of data to read + * \return The data + */ QByteArray read(qint64 maxlen = 0); + /*! + * \brief How many bytes are available to read from the read socket + * \return How many bytes that are available to read from the read socket + */ qint64 bytesAvailable(); qint64 _write(const char* data, qint64 size); + /*! + * \brief Write data to the write socket + * \param data Data to write + * \param size Size of data to write + * \return Amount of data written + */ qint64 write(const char* data, qint64 size); qint64 _write(QByteArray data); + /*! + * \brief Write data to the write socket + * \param data Data to write + * \return Amount of data written + */ qint64 write(QByteArray data); + /*! + * \brief Error string if the last operation on the write socket errored + * \return Error string if the last operation on the write socket errored + */ QString errorString(); signals: + /*! + * \brief The read socket has data available to read + */ void readyRead(); + /*! + * \brief Data was written to the write socket + * \param bytes Amount of data written + */ void bytesWritten(qint64 bytes); + /*! + * \brief The write socket has disconnected + */ void disconnected(); public slots: + /*! + * \brief Close both the read and write sockets + */ void close(); private slots: @@ -45,3 +135,4 @@ namespace Oxide{ bool m_allowWriteSocketRead; }; } +/*! @} */ diff --git a/shared/liboxide/threading.cpp b/shared/liboxide/threading.cpp index f4be2f11f..d0fc0b0e2 100644 --- a/shared/liboxide/threading.cpp +++ b/shared/liboxide/threading.cpp @@ -2,103 +2,103 @@ #include "debug.h" namespace Oxide{ -void startThreadWithPriority(QThread* thread, QThread::Priority priority){ - O_DEBUG(thread << "Starting thread"); -#ifndef QT_HAS_THREAD_PRIORITY_SCHEDULING - QObject::connect(thread, &QThread::started, thread, [priority]{ - switch(priority){ - case QThread::IdlePriority: - nice(19); // 19 is the max - break; - case QThread::LowestPriority: - nice(10); - break; - case QThread::LowPriority: - nice(5); - break; - case QThread::InheritPriority: - case QThread::NormalPriority: - nice(0); - break; - case QThread::HighPriority: - nice(-5); - break; - case QThread::HighestPriority: - nice(-10); - break; - case QThread::TimeCriticalPriority: - nice(-20); - break; - } - }, Qt::QueuedConnection); -#endif - thread->start(priority); -} - -void dispatchToMainThread(std::function callback){ - dispatchToMainThread([callback]{ - callback(); - return 0; - }); -} - -void dispatchToThread(QThread* thread, std::function callback){ - if(QThread::currentThread() == thread){ - // Already on the correct thread - return callback(); + void startThreadWithPriority(QThread* thread, QThread::Priority priority){ + O_DEBUG(thread << "Starting thread"); + #ifndef QT_HAS_THREAD_PRIORITY_SCHEDULING + QObject::connect(thread, &QThread::started, thread, [priority]{ + switch(priority){ + case QThread::IdlePriority: + nice(19); // 19 is the max + break; + case QThread::LowestPriority: + nice(10); + break; + case QThread::LowPriority: + nice(5); + break; + case QThread::InheritPriority: + case QThread::NormalPriority: + nice(0); + break; + case QThread::HighPriority: + nice(-5); + break; + case QThread::HighestPriority: + nice(-10); + break; + case QThread::TimeCriticalPriority: + nice(-20); + break; + } + }, Qt::QueuedConnection); + #endif + thread->start(priority); } - // We are on a different thread - Q_ASSERT(!QCoreApplication::startingUp()); - O_DEBUG("Dispatching to thread" << thread); - QTimer* timer = new QTimer(); - timer->setSingleShot(true); - timer->moveToThread(thread); - bool finished = false; - QObject::connect(timer, &QTimer::timeout, thread, [callback, thread, &finished]{ - Q_ASSERT(QThread::currentThread() == thread); - // This runs on the correct thread - callback(); - finished = true; - }); - QMetaObject::invokeMethod(timer, "start", Qt::BlockingQueuedConnection, Q_ARG(int, 0)); - // Don't use an event loop to avoid deadlocks - while(!finished){ - QCoreApplication::processEvents(QEventLoop::AllEvents, 10); + + void dispatchToMainThread(std::function callback){ + dispatchToMainThread([callback]{ + callback(); + return 0; + }); } - timer->deleteLater(); - O_DEBUG("Thread dispatch finished" << thread); -} -void runLater(QThread* thread, std::function callback){ - O_DEBUG("Run later on thread" << thread); - QTimer* timer = new QTimer(); - timer->moveToThread(thread); - timer->setSingleShot(true); - QObject::connect(timer, &QTimer::timeout, thread, [timer, callback, thread]{ - callback(); + void dispatchToThread(QThread* thread, std::function callback){ + if(QThread::currentThread() == thread){ + // Already on the correct thread + return callback(); + } + // We are on a different thread + Q_ASSERT(!QCoreApplication::startingUp()); + O_DEBUG("Dispatching to thread" << thread); + QTimer* timer = new QTimer(); + timer->setSingleShot(true); + timer->moveToThread(thread); + bool finished = false; + QObject::connect(timer, &QTimer::timeout, thread, [callback, thread, &finished]{ + Q_ASSERT(QThread::currentThread() == thread); + // This runs on the correct thread + callback(); + finished = true; + }); + QMetaObject::invokeMethod(timer, "start", Qt::BlockingQueuedConnection, Q_ARG(int, 0)); + // Don't use an event loop to avoid deadlocks + while(!finished){ + QCoreApplication::processEvents(QEventLoop::AllEvents, 10); + } timer->deleteLater(); - O_DEBUG("Ran on thread" << thread); - }); - QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0)); -} + O_DEBUG("Thread dispatch finished" << thread); + } -void runLaterInMainThread(std::function callback){ runLater(qApp->thread(), callback); } + void runLater(QThread* thread, std::function callback){ + O_DEBUG("Run later on thread" << thread); + QTimer* timer = new QTimer(); + timer->moveToThread(thread); + timer->setSingleShot(true); + QObject::connect(timer, &QTimer::timeout, thread, [timer, callback, thread]{ + callback(); + timer->deleteLater(); + O_DEBUG("Ran on thread" << thread); + }); + QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0)); + } -void runInEventLoop(std::function)> callback){ - QEventLoop loop; - QTimer timer; - O_DEBUG("Running in event loop"); - QObject::connect(&timer, &QTimer::timeout, qApp, [&loop, &timer, callback]{ - if(!loop.isRunning()){ - return; - } - timer.stop(); - callback([&loop]{ - loop.quit(); - O_DEBUG("Finished running in event loop"); + void runLaterInMainThread(std::function callback){ runLater(qApp->thread(), callback); } + + void runInEventLoop(std::function)> callback){ + QEventLoop loop; + QTimer timer; + O_DEBUG("Running in event loop"); + QObject::connect(&timer, &QTimer::timeout, qApp, [&loop, &timer, callback]{ + if(!loop.isRunning()){ + return; + } + timer.stop(); + callback([&loop]{ + loop.quit(); + O_DEBUG("Finished running in event loop"); + }); }); - }); - timer.start(0); - loop.exec(); -} + timer.start(0); + loop.exec(); + } } diff --git a/shared/liboxide/threading.h b/shared/liboxide/threading.h index 28de28ca7..81907399e 100644 --- a/shared/liboxide/threading.h +++ b/shared/liboxide/threading.h @@ -11,63 +11,64 @@ #include namespace Oxide { -/*! - * \brief startThreadWithPriority - * \param thread - * \param priority - */ -LIBOXIDE_EXPORT void startThreadWithPriority(QThread* thread, QThread::Priority priority); -/*! - * \brief Run code on the main Qt thread - * \param callback The code to run on the main thread - * * \snippet examples/oxide.cpp dispatchToMainThread - */ -LIBOXIDE_EXPORT void dispatchToMainThread(std::function callback); -/*! - * \brief Run code on the main Qt thread - * \param callback The code to run on the main thread - * \return Return value of callback - * * \snippet examples/oxide.cpp dispatchToMainThread - */ -template LIBOXIDE_EXPORT T dispatchToMainThread(std::function callback){ - return dispatchToThread(qApp->thread(), callback); -} -/*! - * \brief Run code on a specific thread - * \param thread The thread to run the callback in - * \param callback The code to run on the thread - */ -LIBOXIDE_EXPORT void dispatchToThread(QThread* thread, std::function callback); -/*! - * \brief Run code on a specific thread - * \param thread The thread to run the callback in - * \param callback The code to run on the thread - * \return Return value of callback - */ -template LIBOXIDE_EXPORT T dispatchToThread( - QThread* thread, - std::function callback -){ - T result; - dispatchToThread(thread, [callback, &result]{ - result = callback(); - }); - return result; -} -/*! - * \brief Run code on a specific thread at some point in the near future - * \param thread The thread to run the callback in - * \param callback The code to run on the thread - */ -LIBOXIDE_EXPORT void runLater(QThread* thread, std::function callback); -/*! - * \brief Run code on the main thread at some point in the near future - * \param callback The code to run on the thread - */ -LIBOXIDE_EXPORT void runLaterInMainThread(std::function callback); -/*! - * \brief runInEventLoop - * \param callback - */ -LIBOXIDE_EXPORT void runInEventLoop(std::function)> callback); + /*! + * \brief Start a QThread with a specific priority. This will work even if Qt doesn't support priority scheduling + * \param thread Thread to start + * \param priority Priority to start with + */ + LIBOXIDE_EXPORT void startThreadWithPriority(QThread* thread, QThread::Priority priority); + /*! + * \brief Run code on the main Qt thread + * \param callback The code to run on the main thread + * * \snippet examples/oxide.cpp dispatchToMainThread + */ + LIBOXIDE_EXPORT void dispatchToMainThread(std::function callback); + /*! + * \brief Run code on the main Qt thread + * \param callback The code to run on the main thread + * \return Return value of callback + * * \snippet examples/oxide.cpp dispatchToMainThread + */ + template LIBOXIDE_EXPORT T dispatchToMainThread(std::function callback){ + return dispatchToThread(qApp->thread(), callback); + } + /*! + * \brief Run code on a specific thread + * \param thread The thread to run the callback in + * \param callback The code to run on the thread + */ + LIBOXIDE_EXPORT void dispatchToThread(QThread* thread, std::function callback); + /*! + * \brief Run code on a specific thread + * \param thread The thread to run the callback in + * \param callback The code to run on the thread + * \return Return value of callback + */ + template LIBOXIDE_EXPORT T dispatchToThread( + QThread* thread, + std::function callback + ){ + T result; + dispatchToThread(thread, [callback, &result]{ + result = callback(); + }); + return result; + } + /*! + * \brief Run code on a specific thread at some point in the near future + * \param thread The thread to run the callback in + * \param callback The code to run on the thread + */ + LIBOXIDE_EXPORT void runLater(QThread* thread, std::function callback); + /*! + * \brief Run code on the main thread at some point in the near future + * \param callback The code to run on the thread + */ + LIBOXIDE_EXPORT void runLaterInMainThread(std::function callback); + /*! + * \brief Run code in a Qt event loop + * \param callback The code to run inside an event loop + */ + LIBOXIDE_EXPORT void runInEventLoop(std::function)> callback); } +/*! @} */