Browse Source

Add back modal windows related functionality

Signed-off-by: falkTX <falktx@falktx.com>
pull/272/head
falkTX 4 years ago
parent
commit
635e5cede4
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
4 changed files with 190 additions and 153 deletions
  1. +15
    -4
      dgl/Window.hpp
  2. +9
    -14
      dgl/src/Window.cpp
  3. +130
    -33
      dgl/src/WindowPrivateData.cpp
  4. +36
    -102
      dgl/src/WindowPrivateData.hpp

+ 15
- 4
dgl/Window.hpp View File

@@ -55,6 +55,12 @@ public:
*/ */
explicit Window(Application& app); 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, Constructor for an embed Window without known size,
typically used in modules or plugins that run inside another host. typically used in modules or plugins that run inside another host.
@@ -224,6 +230,13 @@ public:
*/ */
void repaint(const Rectangle<uint>& rect) noexcept; 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. Set geometry constraints for the Window when resized by the user, and optionally scale contents automatically.
*/ */
@@ -239,6 +252,7 @@ public:
// TODO deprecated // TODO deprecated
inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); } inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); }
inline double getScaling() const noexcept { return getScaling(); } inline double getScaling() const noexcept { return getScaling(); }
inline void exec(bool blockWait = false) { runAsModal(blockWait); }


protected: protected:
/** /**
@@ -257,6 +271,7 @@ protected:
/** /**
A function called when the window is resized. 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. 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); virtual void onReshape(uint width, uint height);


@@ -318,10 +333,6 @@ END_NAMESPACE_DGL
}; };
#endif // DGL_FILE_BROWSER_DISABLED #endif // DGL_FILE_BROWSER_DISABLED


static Window& withTransientParentWindow(Window& transientParentWindow);

void exec(bool lockWait = false);

void addIdleCallback(IdleCallback* const callback); void addIdleCallback(IdleCallback* const callback);
void removeIdleCallback(IdleCallback* const callback); void removeIdleCallback(IdleCallback* const callback);




+ 9
- 14
dgl/src/Window.cpp View File

@@ -23,12 +23,12 @@ START_NAMESPACE_DGL
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Window // Window


// Window::Window(Window& transientParentWindow)
// : pData(new PrivateData(transientParentWindow.pData->fAppData, this, transientParentWindow)) {}

Window::Window(Application& app) Window::Window(Application& app)
: pData(new PrivateData(app, this)) {} : pData(new PrivateData(app, this)) {}


Window::Window(Application& app, Window& parent)
: pData(new PrivateData(app, this, parent.pData)) {}

Window::Window(Application& app, Window::Window(Application& app,
const uintptr_t parentWindowHandle, const uintptr_t parentWindowHandle,
const double scaleFactor, const double scaleFactor,
@@ -170,10 +170,7 @@ double Window::getScaleFactor() const noexcept


void Window::focus() void Window::focus()
{ {
if (! pData->isEmbed)
puglRaiseWindow(pData->view);

puglGrabFocus(pData->view);
pData->focus();
} }


void Window::repaint() noexcept void Window::repaint() noexcept
@@ -192,6 +189,11 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept
puglPostRedisplayRect(pData->view, prect); puglPostRedisplayRect(pData->view, prect);
} }


void Window::runAsModal(bool blockWait)
{
pData->runAsModal(blockWait);
}

void Window::setGeometryConstraints(const uint minimumWidth, void Window::setGeometryConstraints(const uint minimumWidth,
const uint minimumHeight, const uint minimumHeight,
const bool keepAspectRatio, const bool keepAspectRatio,
@@ -242,13 +244,6 @@ void Window::onReshape(uint, uint)
} }


#if 0 #if 0
#if 0
void Window::exec(bool lockWait)
{
pData->exec(lockWait);
}
#endif

void Window::setTransientWinId(const uintptr_t winId) void Window::setTransientWinId(const uintptr_t winId)
{ {
puglSetTransientFor(pData->fView, winId); puglSetTransientFor(pData->fView, winId);


+ 130
- 33
dgl/src/WindowPrivateData.cpp View File

@@ -63,12 +63,13 @@ Window::PrivateData::PrivateData(Application& a, Window* const s)
autoScaling(false), autoScaling(false),
autoScaleFactor(1.0), autoScaleFactor(1.0),
minWidth(0), minWidth(0),
minHeight(0)
minHeight(0),
modal(this)
{ {
init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); 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), : app(a),
appData(a.pData), appData(a.pData),
self(s), self(s),
@@ -77,15 +78,16 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, Window& transi
isClosed(true), isClosed(true),
isVisible(false), isVisible(false),
isEmbed(false), isEmbed(false),
scaleFactor(getDesktopScaleFactor()),
scaleFactor(ppData->scaleFactor),
autoScaling(false), autoScaling(false),
autoScaleFactor(1.0), autoScaleFactor(1.0),
minWidth(0), minWidth(0),
minHeight(0)
minHeight(0),
modal(this, ppData)
{ {
init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false);


puglSetTransientFor(view, transientWindow.getNativeWindowHandle());
puglSetTransientFor(view, puglGetNativeWindow(ppData->view));
} }


Window::PrivateData::PrivateData(Application& a, Window* const s, Window::PrivateData::PrivateData(Application& a, Window* const s,
@@ -103,7 +105,8 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
autoScaling(false), autoScaling(false),
autoScaleFactor(1.0), autoScaleFactor(1.0),
minWidth(0), minWidth(0),
minHeight(0)
minHeight(0),
modal(this)
{ {
if (isEmbed) if (isEmbed)
{ {
@@ -136,7 +139,8 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
autoScaling(false), autoScaling(false),
autoScaleFactor(1.0), autoScaleFactor(1.0),
minWidth(0), minWidth(0),
minHeight(0)
minHeight(0),
modal(this)
{ {
if (isEmbed) if (isEmbed)
{ {
@@ -279,16 +283,26 @@ void Window::PrivateData::hide()
// } // }
#endif #endif


puglHide(view);
if (modal.enabled)
stopModal();


// if (fModal.enabled)
// exec_fini();
puglHide(view);


isVisible = false; isVisible = false;
} }


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------


void Window::PrivateData::focus()
{
if (! isEmbed)
puglRaiseWindow(view);

puglGrabFocus(view);
}

// -----------------------------------------------------------------------

void Window::PrivateData::close() void Window::PrivateData::close()
{ {
DGL_DBG("Window close\n"); DGL_DBG("Window close\n");
@@ -327,13 +341,91 @@ void Window::PrivateData::idleCallback()
// std::free(buffer); // std::free(buffer);
// } // }
// #endif // #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) void Window::PrivateData::onPuglConfigure(const int width, const int height)
{ {
@@ -372,14 +464,19 @@ void Window::PrivateData::onPuglClose()
{ {
DGL_DBG("PUGL: onClose\n"); DGL_DBG("PUGL: onClose\n");


// if (fModal.enabled)
// exec_fini();

if (! self->onClose()) if (! self->onClose())
return; 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(); close();
} }
@@ -388,8 +485,8 @@ void Window::PrivateData::onPuglFocus(const bool focus, const CrossingMode mode)
{ {
DGL_DBGp("onPuglFocus : %i %i\n", focus, 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 #ifndef DPF_TEST_WINDOW_CPP
self->onFocus(focus, mode); 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); 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 #ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr) 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); 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 #ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr) 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); 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 #ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr) 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()); 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 #ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr) 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()); 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 #ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr) 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()); 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 #ifndef DPF_TEST_WINDOW_CPP
if (topLevelWidget != nullptr) if (topLevelWidget != nullptr)


+ 36
- 102
dgl/src/WindowPrivateData.hpp View File

@@ -68,11 +68,40 @@ struct Window::PrivateData : IdleCallback {
/** Pugl minWidth, minHeight access. */ /** Pugl minWidth, minHeight access. */
uint minWidth, minHeight; 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. */ /** Constructor for a regular, standalone window. */
explicit PrivateData(Application& app, Window* self); 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. */ /** 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. */ /** 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); explicit PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle, double scaling, bool resizable);
@@ -89,6 +118,7 @@ struct Window::PrivateData : IdleCallback {


void show(); void show();
void hide(); void hide();
void focus();


/** Hide window and notify application of a window close event. /** Hide window and notify application of a window close event.
* Does nothing if window is embed (that is, not standalone). * Does nothing if window is embed (that is, not standalone).
@@ -105,6 +135,11 @@ struct Window::PrivateData : IdleCallback {


void idleCallback() override; void idleCallback() override;


// modal handling
void startModal();
void stopModal();
void runAsModal(bool blockWait);

// pugl events // pugl events
void onPuglConfigure(int width, int height); void onPuglConfigure(int width, int height);
void onPuglExpose(); void onPuglExpose();
@@ -128,39 +163,6 @@ struct Window::PrivateData : IdleCallback {
END_NAMESPACE_DGL END_NAMESPACE_DGL


#if 0 #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) // #if defined(DISTRHO_OS_HAIKU)
// BApplication* bApplication; // BApplication* bApplication;
// BView* bView; // BView* bView;
@@ -189,74 +191,6 @@ END_NAMESPACE_DGL
struct Window::PrivateData { 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) bool handlePluginSpecial(const bool press, const Key key)
{ {
DBGp("PUGL: handlePluginSpecial : %i %i\n", press, key); DBGp("PUGL: handlePluginSpecial : %i %i\n", press, key);


Loading…
Cancel
Save