commit 635e5cede4756bd22fe75dab76758e47778072f2
parent bdcdd576a42c8525d2e69dc1683d3f5fe62c671f
Author: falkTX <falktx@falktx.com>
Date: Sun, 16 May 2021 14:03:00 +0100
Add back modal windows related functionality
Signed-off-by: falkTX <falktx@falktx.com>
Diffstat:
4 files changed, 190 insertions(+), 153 deletions(-)
diff --git a/dgl/Window.hpp b/dgl/Window.hpp
@@ -56,6 +56,12 @@ public:
explicit Window(Application& app);
/**
+ Constructor for a modal window, by having another window as its parent.
+ The Application instance must be the same between the 2 windows.
+ */
+ explicit Window(Application& app, Window& parent);
+
+ /**
Constructor for an embed Window without known size,
typically used in modules or plugins that run inside another host.
*/
@@ -225,6 +231,13 @@ public:
void repaint(const Rectangle<uint>& rect) noexcept;
/**
+ Run this window as a modal, blocking input events from the parent.
+ Only valid for windows that have been created with another window as parent (as passed in the constructor).
+ Can optionally block-wait, but such option is only available if the application is running as standalone.
+ */
+ void runAsModal(bool blockWait = false);
+
+ /**
Set geometry constraints for the Window when resized by the user, and optionally scale contents automatically.
*/
void setGeometryConstraints(uint minimumWidth,
@@ -239,6 +252,7 @@ public:
// TODO deprecated
inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); }
inline double getScaling() const noexcept { return getScaling(); }
+ inline void exec(bool blockWait = false) { runAsModal(blockWait); }
protected:
/**
@@ -257,6 +271,7 @@ protected:
/**
A function called when the window is resized.
If there is a top-level widget associated with this window, its size will be set right after this function.
+ TODO this seems wrong, top-level widget should be resized here
*/
virtual void onReshape(uint width, uint height);
@@ -318,10 +333,6 @@ END_NAMESPACE_DGL
};
#endif // DGL_FILE_BROWSER_DISABLED
- static Window& withTransientParentWindow(Window& transientParentWindow);
-
- void exec(bool lockWait = false);
-
void addIdleCallback(IdleCallback* const callback);
void removeIdleCallback(IdleCallback* const callback);
diff --git a/dgl/src/Window.cpp b/dgl/src/Window.cpp
@@ -23,12 +23,12 @@ START_NAMESPACE_DGL
// -----------------------------------------------------------------------
// Window
-// Window::Window(Window& transientParentWindow)
-// : pData(new PrivateData(transientParentWindow.pData->fAppData, this, transientParentWindow)) {}
-
Window::Window(Application& app)
: pData(new PrivateData(app, this)) {}
+Window::Window(Application& app, Window& parent)
+ : pData(new PrivateData(app, this, parent.pData)) {}
+
Window::Window(Application& app,
const uintptr_t parentWindowHandle,
const double scaleFactor,
@@ -170,10 +170,7 @@ double Window::getScaleFactor() const noexcept
void Window::focus()
{
- if (! pData->isEmbed)
- puglRaiseWindow(pData->view);
-
- puglGrabFocus(pData->view);
+ pData->focus();
}
void Window::repaint() noexcept
@@ -192,6 +189,11 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept
puglPostRedisplayRect(pData->view, prect);
}
+void Window::runAsModal(bool blockWait)
+{
+ pData->runAsModal(blockWait);
+}
+
void Window::setGeometryConstraints(const uint minimumWidth,
const uint minimumHeight,
const bool keepAspectRatio,
@@ -242,13 +244,6 @@ void Window::onReshape(uint, uint)
}
#if 0
-#if 0
-void Window::exec(bool lockWait)
-{
- pData->exec(lockWait);
-}
-#endif
-
void Window::setTransientWinId(const uintptr_t winId)
{
puglSetTransientFor(pData->fView, winId);
diff --git a/dgl/src/WindowPrivateData.cpp b/dgl/src/WindowPrivateData.cpp
@@ -63,12 +63,13 @@ Window::PrivateData::PrivateData(Application& a, Window* const s)
autoScaling(false),
autoScaleFactor(1.0),
minWidth(0),
- minHeight(0)
+ minHeight(0),
+ modal(this)
{
init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false);
}
-Window::PrivateData::PrivateData(Application& a, Window* const s, Window& transientWindow)
+Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* const ppData)
: app(a),
appData(a.pData),
self(s),
@@ -77,15 +78,16 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, Window& transi
isClosed(true),
isVisible(false),
isEmbed(false),
- scaleFactor(getDesktopScaleFactor()),
+ scaleFactor(ppData->scaleFactor),
autoScaling(false),
autoScaleFactor(1.0),
minWidth(0),
- minHeight(0)
+ minHeight(0),
+ modal(this, ppData)
{
init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false);
- puglSetTransientFor(view, transientWindow.getNativeWindowHandle());
+ puglSetTransientFor(view, puglGetNativeWindow(ppData->view));
}
Window::PrivateData::PrivateData(Application& a, Window* const s,
@@ -103,7 +105,8 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
autoScaling(false),
autoScaleFactor(1.0),
minWidth(0),
- minHeight(0)
+ minHeight(0),
+ modal(this)
{
if (isEmbed)
{
@@ -136,7 +139,8 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
autoScaling(false),
autoScaleFactor(1.0),
minWidth(0),
- minHeight(0)
+ minHeight(0),
+ modal(this)
{
if (isEmbed)
{
@@ -279,16 +283,26 @@ void Window::PrivateData::hide()
// }
#endif
- puglHide(view);
+ if (modal.enabled)
+ stopModal();
-// if (fModal.enabled)
-// exec_fini();
+ puglHide(view);
isVisible = false;
}
// -----------------------------------------------------------------------
+void Window::PrivateData::focus()
+{
+ if (! isEmbed)
+ puglRaiseWindow(view);
+
+ puglGrabFocus(view);
+}
+
+// -----------------------------------------------------------------------
+
void Window::PrivateData::close()
{
DGL_DBG("Window close\n");
@@ -327,13 +341,91 @@ void Window::PrivateData::idleCallback()
// std::free(buffer);
// }
// #endif
-//
-// if (fModal.enabled && fModal.parent != nullptr)
-// fModal.parent->windowSpecificIdle();
-// self->repaint();
+
+// if (modal.enabled && modal.parent != nullptr)
+// modal.parent->idleCallback();
}
// -----------------------------------------------------------------------
+// modal handling
+
+void Window::PrivateData::startModal()
+{
+ DGL_DBG("Window modal loop starting..."); DGL_DBGF;
+ DISTRHO_SAFE_ASSERT_RETURN(modal.parent != nullptr, show());
+
+ // activate modal mode for this window
+ modal.enabled = true;
+
+ // make parent give focus to us
+ modal.parent->modal.child = this;
+
+ // make sure both parent and ourselves are visible
+ modal.parent->show();
+ show();
+
+ DGL_DBG("Ok\n");
+}
+
+void Window::PrivateData::stopModal()
+{
+ DGL_DBG("Window modal loop stopping..."); DGL_DBGF;
+
+ // deactivate modal mode
+ modal.enabled = false;
+
+ // safety checks, make sure we have a parent and we are currently active as the child to give focus to
+ if (modal.parent == nullptr)
+ return;
+ if (modal.parent->modal.child != this)
+ return;
+
+ // stop parent from giving focus to us, so it behaves like normal
+ modal.parent->modal.child = nullptr;
+
+ // the mouse position probably changed since the modal appeared,
+ // so send a mouse motion event to the modal's parent window
+#if 0
+#if defined(DISTRHO_OS_HAIKU)
+ // TODO
+#elif defined(DISTRHO_OS_MAC)
+ // TODO
+#elif defined(DISTRHO_OS_WINDOWS)
+ // TODO
+#else
+ int i, wx, wy;
+ uint u;
+ ::Window w;
+ if (XQueryPointer(fModal.parent->xDisplay, fModal.parent->xWindow, &w, &w, &i, &i, &wx, &wy, &u) == True)
+ fModal.parent->onPuglMotion(wx, wy);
+#endif
+#endif
+
+ DGL_DBG("Ok\n");
+}
+
+void Window::PrivateData::runAsModal(const bool blockWait)
+{
+ DGL_DBGp("Window::PrivateData::runAsModal %i\n", blockWait);
+ startModal();
+
+ if (blockWait)
+ {
+ DISTRHO_SAFE_ASSERT_RETURN(appData->isStandalone,);
+
+ while (isVisible && modal.enabled)
+ appData->idle(10);
+
+ stopModal();
+ }
+ else
+ {
+ appData->idle(0);
+ }
+}
+
+// -----------------------------------------------------------------------
+// pugl events
void Window::PrivateData::onPuglConfigure(const int width, const int height)
{
@@ -372,14 +464,19 @@ void Window::PrivateData::onPuglClose()
{
DGL_DBG("PUGL: onClose\n");
-// if (fModal.enabled)
-// exec_fini();
-
if (! self->onClose())
return;
-// if (fModal.childFocus != nullptr)
-// fModal.childFocus->fSelf->onClose();
+ if (modal.enabled)
+ stopModal();
+
+ if (modal.child != nullptr)
+ {
+ if (modal.child->modal.enabled)
+ modal.child->stopModal();
+
+ modal.child->close();
+ }
close();
}
@@ -388,8 +485,8 @@ void Window::PrivateData::onPuglFocus(const bool focus, const CrossingMode mode)
{
DGL_DBGp("onPuglFocus : %i %i\n", focus, mode);
-// if (fModal.childFocus != nullptr)
-// return fModal.childFocus->focus();
+ if (modal.child != nullptr)
+ return modal.child->focus();
#ifndef DPF_TEST_WINDOW_CPP
self->onFocus(focus, mode);
@@ -400,8 +497,8 @@ void Window::PrivateData::onPuglKey(const Events::KeyboardEvent& ev)
{
DGL_DBGp("onPuglKey : %i %u %u\n", ev.press, ev.key, ev.keycode);
-// if (fModal.childFocus != nullptr)
-// return fModal.childFocus->focus();
+ if (modal.child != nullptr)
+ return modal.child->focus();
#ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr)
@@ -413,8 +510,8 @@ void Window::PrivateData::onPuglSpecial(const Events::SpecialEvent& ev)
{
DGL_DBGp("onPuglSpecial : %i %u\n", ev.press, ev.key);
-// if (fModal.childFocus != nullptr)
-// return fModal.childFocus->focus();
+ if (modal.child != nullptr)
+ return modal.child->focus();
#ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr)
@@ -426,8 +523,8 @@ void Window::PrivateData::onPuglText(const Events::CharacterInputEvent& ev)
{
DGL_DBGp("onPuglText : %u %u %s\n", ev.keycode, ev.character, ev.string);
-// if (fModal.childFocus != nullptr)
-// return fModal.childFocus->focus();
+ if (modal.child != nullptr)
+ return modal.child->focus();
#ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr)
@@ -439,8 +536,8 @@ void Window::PrivateData::onPuglMouse(const Events::MouseEvent& ev)
{
DGL_DBGp("onPuglMouse : %i %i %f %f\n", ev.button, ev.press, ev.pos.getX(), ev.pos.getY());
-// if (fModal.childFocus != nullptr)
-// return fModal.childFocus->focus();
+ if (modal.child != nullptr)
+ return modal.child->focus();
#ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr)
@@ -452,8 +549,8 @@ void Window::PrivateData::onPuglMotion(const Events::MotionEvent& ev)
{
DGL_DBGp("onPuglMotion : %f %f\n", ev.pos.getX(), ev.pos.getY());
-// if (fModal.childFocus != nullptr)
-// return fModal.childFocus->focus();
+ if (modal.child != nullptr)
+ return modal.child->focus();
#ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr)
@@ -465,8 +562,8 @@ void Window::PrivateData::onPuglScroll(const Events::ScrollEvent& ev)
{
DGL_DBGp("onPuglScroll : %f %f %f %f\n", ev.pos.getX(), ev.pos.getY(), ev.delta.getX(), ev.delta.getY());
-// if (fModal.childFocus != nullptr)
-// return fModal.childFocus->focus();
+ if (modal.child != nullptr)
+ return modal.child->focus();
#ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr)
diff --git a/dgl/src/WindowPrivateData.hpp b/dgl/src/WindowPrivateData.hpp
@@ -68,11 +68,40 @@ struct Window::PrivateData : IdleCallback {
/** Pugl minWidth, minHeight access. */
uint minWidth, minHeight;
+ /** Modal window setup. */
+ struct Modal {
+// PrivateData* self; // pointer to PrivateData this Modal class belongs to
+ PrivateData* parent; // parent of this window (so we can become modal)
+ PrivateData* child; // child window to give focus to when modal mode is enabled
+ bool enabled; // wherever modal mode is enabled (only possible if parent != null)
+
+ /** Constructor for a non-modal window. */
+ Modal(PrivateData* const s) noexcept
+ : parent(nullptr),
+ child(nullptr),
+ enabled(false) {}
+
+ /** Constructor for a modal window (with a parent). */
+ Modal(PrivateData* const s, PrivateData* const p) noexcept
+ : parent(p),
+ child(nullptr),
+ enabled(false) {}
+
+ /** Destructor. */
+ ~Modal() noexcept
+ {
+ DISTRHO_SAFE_ASSERT(! enabled);
+ }
+ } modal;
+
/** Constructor for a regular, standalone window. */
explicit PrivateData(Application& app, Window* self);
+ /** Constructor for a modal window. */
+ explicit PrivateData(Application& app, Window* self, PrivateData* ppData);
+
/** Constructor for a regular, standalone window with a transient parent. */
- explicit PrivateData(Application& app, Window* self, Window& transientWindow);
+// explicit PrivateData(Application& app, Window* self, Window& transientWindow);
/** Constructor for an embed Window, with a few extra hints from the host side. */
explicit PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle, double scaling, bool resizable);
@@ -89,6 +118,7 @@ struct Window::PrivateData : IdleCallback {
void show();
void hide();
+ void focus();
/** Hide window and notify application of a window close event.
* Does nothing if window is embed (that is, not standalone).
@@ -105,6 +135,11 @@ struct Window::PrivateData : IdleCallback {
void idleCallback() override;
+ // modal handling
+ void startModal();
+ void stopModal();
+ void runAsModal(bool blockWait);
+
// pugl events
void onPuglConfigure(int width, int height);
void onPuglExpose();
@@ -128,39 +163,6 @@ struct Window::PrivateData : IdleCallback {
END_NAMESPACE_DGL
#if 0
- // this one depends on build type
- // GraphicsContext fContext;
-
- bool fFirstInit;
- bool fVisible;
- bool fUsingEmbed;
- double fScaling;
- double fAutoScaling;
-
- struct Modal {
- bool enabled;
- PrivateData* parent;
- PrivateData* childFocus;
-
- Modal()
- : enabled(false),
- parent(nullptr),
- childFocus(nullptr) {}
-
- Modal(PrivateData* const p)
- : enabled(false),
- parent(p),
- childFocus(nullptr) {}
-
- ~Modal()
- {
- DISTRHO_SAFE_ASSERT(! enabled);
- DISTRHO_SAFE_ASSERT(childFocus == nullptr);
- }
-
- DISTRHO_DECLARE_NON_COPY_STRUCT(Modal)
- } fModal;
-
// #if defined(DISTRHO_OS_HAIKU)
// BApplication* bApplication;
// BView* bView;
@@ -189,74 +191,6 @@ END_NAMESPACE_DGL
struct Window::PrivateData {
// -------------------------------------------------------------------
- void exec(const bool lockWait)
- {
- DBG("Window exec\n");
- exec_init();
-
- if (lockWait)
- {
- for (; fVisible && fModal.enabled;)
- {
- idle();
- d_msleep(10);
- }
-
- exec_fini();
- }
- else
- {
- idle();
- }
- }
-
- // -------------------------------------------------------------------
-
- void exec_init()
- {
- DBG("Window modal loop starting..."); DBGF;
- DISTRHO_SAFE_ASSERT_RETURN(fModal.parent != nullptr, setVisible(true));
-
- fModal.enabled = true;
- fModal.parent->fModal.childFocus = this;
-
- fModal.parent->setVisible(true);
- setVisible(true);
-
- DBG("Ok\n");
- }
-
- void exec_fini()
- {
- DBG("Window modal loop stopping..."); DBGF;
- fModal.enabled = false;
-
- if (fModal.parent != nullptr)
- {
- fModal.parent->fModal.childFocus = nullptr;
-
- // the mouse position probably changed since the modal appeared,
- // so send a mouse motion event to the modal's parent window
-#if defined(DISTRHO_OS_HAIKU)
- // TODO
-#elif defined(DISTRHO_OS_MAC)
- // TODO
-#elif defined(DISTRHO_OS_WINDOWS)
- // TODO
-#else
- int i, wx, wy;
- uint u;
- ::Window w;
- if (XQueryPointer(fModal.parent->xDisplay, fModal.parent->xWindow, &w, &w, &i, &i, &wx, &wy, &u) == True)
- fModal.parent->onPuglMotion(wx, wy);
-#endif
- }
-
- DBG("Ok\n");
- }
-
- // -------------------------------------------------------------------
-
bool handlePluginSpecial(const bool press, const Key key)
{
DBGp("PUGL: handlePluginSpecial : %i %i\n", press, key);