diff --git a/Makefile.base.mk b/Makefile.base.mk index 5eaea285..6568471e 100644 --- a/Makefile.base.mk +++ b/Makefile.base.mk @@ -225,7 +225,10 @@ HAVE_OPENGL = true else HAVE_OPENGL = $(shell $(PKG_CONFIG) --exists gl && echo true) ifneq ($(HAIKU),true) -HAVE_X11 = $(shell $(PKG_CONFIG) --exists x11 && echo true) +HAVE_X11 = $(shell $(PKG_CONFIG) --exists x11 && echo true) +HAVE_XCURSOR = $(shell $(PKG_CONFIG) --exists xcursor && echo true) +HAVE_XEXT = $(shell $(PKG_CONFIG) --exists xext && echo true) +HAVE_XRANDR = $(shell $(PKG_CONFIG) --exists xrandr && echo true) endif endif @@ -254,6 +257,19 @@ ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) ifeq ($(HAVE_X11),true) DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11) DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs x11) +ifeq ($(HAVE_XCURSOR),true) +# TODO -DHAVE_XCURSOR +DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xcursor) +DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs xcursor) +endif +ifeq ($(HAVE_XEXT),true) +DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xext) -DHAVE_XEXT -DHAVE_XSYNC +DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs xext) +endif +ifeq ($(HAVE_XRANDR),true) +DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xrandr) -DHAVE_XRANDR +DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs xrandr) +endif endif endif diff --git a/dgl/Application.hpp b/dgl/Application.hpp index 3d574ca0..2c166b8e 100644 --- a/dgl/Application.hpp +++ b/dgl/Application.hpp @@ -77,12 +77,12 @@ public: Idle callbacks trigger right after OS event handling and Window idle events (within the same cycle). There are no guarantees in terms of timing. */ - void addIdleCallback(IdleCallback* const callback); + void addIdleCallback(IdleCallback* callback); /** Remove an idle callback previously added via addIdleCallback(). */ - void removeIdleCallback(IdleCallback* const callback); + void removeIdleCallback(IdleCallback* callback); private: struct PrivateData; diff --git a/dgl/TopLevelWidget.hpp b/dgl/TopLevelWidget.hpp index fe859766..e7ac44d3 100644 --- a/dgl/TopLevelWidget.hpp +++ b/dgl/TopLevelWidget.hpp @@ -67,6 +67,8 @@ public: Window& getWindow() const noexcept; // TODO group stuff after here, convenience functions present in Window class + bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0); + bool removeIdleCallback(IdleCallback* callback); double getScaleFactor() const noexcept; void repaint() noexcept; void repaint(const Rectangle& rect) noexcept; diff --git a/dgl/Window.hpp b/dgl/Window.hpp index 6c27f84a..5defcf6b 100644 --- a/dgl/Window.hpp +++ b/dgl/Window.hpp @@ -190,6 +190,25 @@ public: */ void setIgnoringKeyRepeat(bool ignore) noexcept; + /** + Add a callback function to be triggered on every idle cycle or on a specific timer frequency. + You can add more than one, and remove them at anytime with removeIdleCallback(). + This can be used to perform some action at a regular interval with relatively low frequency. + + If providing a timer frequency, there are a few things to note: + 1. There is a platform-specific limit to the number of supported timers, and overhead associated with each, + so you should create only a few timers and perform several tasks in one if necessary. + 2. This timer frequency is not guaranteed to have a resolution better than 10ms + (the maximum timer resolution on Windows) and may be rounded up if it is too short. + On X11 and MacOS, a resolution of about 1ms can usually be relied on. + */ + bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0); + + /** + Remove an idle callback previously added via addIdleCallback(). + */ + bool removeIdleCallback(IdleCallback* callback); + /** Get the application associated with this window. */ diff --git a/dgl/src/TopLevelWidget.cpp b/dgl/src/TopLevelWidget.cpp index 9d553604..9f68360e 100644 --- a/dgl/src/TopLevelWidget.cpp +++ b/dgl/src/TopLevelWidget.cpp @@ -40,6 +40,16 @@ Window& TopLevelWidget::getWindow() const noexcept return pData->window; } +bool TopLevelWidget::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) +{ + return pData->window.addIdleCallback(callback, timerFrequencyInMs); +} + +bool TopLevelWidget::removeIdleCallback(IdleCallback* const callback) +{ + return pData->window.removeIdleCallback(callback); +} + double TopLevelWidget::getScaleFactor() const noexcept { return pData->window.getScaleFactor(); diff --git a/dgl/src/Window.cpp b/dgl/src/Window.cpp index b68302ef..800daab3 100644 --- a/dgl/src/Window.cpp +++ b/dgl/src/Window.cpp @@ -153,6 +153,20 @@ void Window::setIgnoringKeyRepeat(const bool ignore) noexcept puglSetViewHint(pData->view, PUGL_IGNORE_KEY_REPEAT, ignore); } +bool Window::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) +{ + DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr, false) + + return pData->addIdleCallback(callback, timerFrequencyInMs); +} + +bool Window::removeIdleCallback(IdleCallback* const callback) +{ + DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr, false) + + return pData->removeIdleCallback(callback); +} + Application& Window::getApp() const noexcept { return pData->app; diff --git a/dgl/src/WindowPrivateData.cpp b/dgl/src/WindowPrivateData.cpp index cadd93b9..9d962127 100644 --- a/dgl/src/WindowPrivateData.cpp +++ b/dgl/src/WindowPrivateData.cpp @@ -347,6 +347,31 @@ void Window::PrivateData::idleCallback() // modal.parent->idleCallback(); } +// ----------------------------------------------------------------------- + +bool Window::PrivateData::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) +{ + if (timerFrequencyInMs == 0) + { + appData->idleCallbacks.push_back(callback); + return true; + } + + return puglStartTimer(view, (uintptr_t)callback, static_cast(timerFrequencyInMs) / 1000.0) == PUGL_SUCCESS; +} + +bool Window::PrivateData::removeIdleCallback(IdleCallback* const callback) +{ + if (std::find(appData->idleCallbacks.begin(), + appData->idleCallbacks.end(), callback) != appData->idleCallbacks.end()) + { + appData->idleCallbacks.remove(callback); + return true; + } + + return puglStopTimer(view, (uintptr_t)callback) == PUGL_SUCCESS; +} + // ----------------------------------------------------------------------- // modal handling @@ -740,6 +765,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu ///< Timer triggered, a #PuglEventTimer case PUGL_TIMER: + if (IdleCallback* const idleCallback = reinterpret_cast(event->timer.id)) + idleCallback->idleCallback(); break; ///< Recursive loop entered, a #PuglEventLoopEnter diff --git a/dgl/src/WindowPrivateData.hpp b/dgl/src/WindowPrivateData.hpp index e00f97b7..fafbd0aa 100644 --- a/dgl/src/WindowPrivateData.hpp +++ b/dgl/src/WindowPrivateData.hpp @@ -136,6 +136,9 @@ struct Window::PrivateData : IdleCallback { void idleCallback() override; + bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs); + bool removeIdleCallback(IdleCallback* callback); + // modal handling void startModal(); void stopModal(); @@ -152,6 +155,7 @@ struct Window::PrivateData : IdleCallback { void onPuglMouse(const Events::MouseEvent& ev); void onPuglMotion(const Events::MotionEvent& ev); void onPuglScroll(const Events::ScrollEvent& ev); + void onPuglTimer(IdleCallback* idleCallback); // Pugl event handling entry point static PuglStatus puglEventCallback(PuglView* view, const PuglEvent* event);