Signed-off-by: falkTX <falktx@falktx.com>pull/272/head
@@ -1,3 +1,3 @@ | |||
[submodule "dgl/src/pugl-upstream"] | |||
path = dgl/src/pugl-upstream | |||
url = https://github.com/lv2/pugl.git | |||
url = https://github.com/DISTRHO/pugl.git |
@@ -63,6 +63,26 @@ public: | |||
*/ | |||
virtual ~Window(); | |||
/** | |||
Whether this Window is embed into another (usually not DGL-controlled) Window. | |||
*/ | |||
bool isEmbed() const noexcept; | |||
bool isVisible() const noexcept; | |||
void setVisible(bool visible); | |||
inline void show() { setVisible(true); } | |||
inline void hide() { setVisible(true); } | |||
/** | |||
Hide window and notify application of a window close event. | |||
The application event-loop will stop when all windows have been closed. | |||
For standalone windows only, has no effect if window is embed. | |||
@see isEmbed() | |||
@note It is possible to hide the window while not stopping the event-loop. | |||
A closed window is always hidden, but the reverse is not always true. | |||
*/ | |||
void close(); | |||
/** | |||
@@ -144,8 +164,6 @@ END_NAMESPACE_DGL | |||
static Window& withTransientParentWindow(Window& transientParentWindow); | |||
void show(); | |||
void hide(); | |||
void exec(bool lockWait = false); | |||
void focus(); | |||
@@ -156,11 +174,6 @@ END_NAMESPACE_DGL | |||
bool openFileBrowser(const FileBrowserOptions& options); | |||
#endif | |||
bool isEmbed() const noexcept; | |||
bool isVisible() const noexcept; | |||
void setVisible(bool visible); | |||
bool isResizable() const noexcept; | |||
void setResizable(bool resizable); | |||
@@ -28,6 +28,7 @@ Application::PrivateData::PrivateData(const bool standalone) | |||
standalone ? PUGL_WORLD_THREADS : 0x0)), | |||
isStandalone(standalone), | |||
isQuitting(false), | |||
isStarting(true), | |||
visibleWindows(0), | |||
windows(), | |||
idleCallbacks() | |||
@@ -36,14 +37,11 @@ Application::PrivateData::PrivateData(const bool standalone) | |||
puglSetWorldHandle(world, this); | |||
puglSetClassName(world, DISTRHO_MACRO_AS_STRING(DGL_NAMESPACE)); | |||
// puglSetLogLevel(world, PUGL_LOG_LEVEL_DEBUG); | |||
} | |||
Application::PrivateData::~PrivateData() | |||
{ | |||
DISTRHO_SAFE_ASSERT(isQuitting); | |||
DISTRHO_SAFE_ASSERT(isStarting || isQuitting); | |||
DISTRHO_SAFE_ASSERT(visibleWindows == 0); | |||
windows.clear(); | |||
@@ -57,21 +55,23 @@ Application::PrivateData::~PrivateData() | |||
void Application::PrivateData::oneWindowShown() noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(isStandalone,); | |||
if (++visibleWindows == 1) | |||
{ | |||
isQuitting = false; | |||
isStarting = false; | |||
} | |||
} | |||
void Application::PrivateData::oneWindowHidden() noexcept | |||
void Application::PrivateData::oneWindowClosed() noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(isStandalone,); | |||
DISTRHO_SAFE_ASSERT_RETURN(visibleWindows != 0,); | |||
if (--visibleWindows == 0) | |||
isQuitting = true; | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
void Application::PrivateData::idle(const uint timeoutInMs) | |||
{ | |||
if (world != nullptr) | |||
@@ -92,6 +92,8 @@ void Application::PrivateData::idle(const uint timeoutInMs) | |||
void Application::PrivateData::quit() | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(isStandalone,); | |||
isQuitting = true; | |||
#ifndef DPF_TEST_APPLICATION_CPP | |||
@@ -39,31 +39,38 @@ struct Application::PrivateData { | |||
/** Whether the applicating is about to quit, or already stopped. Defaults to false. */ | |||
bool isQuitting; | |||
/** Whether the applicating is starting up, that is, no windows have been made visible yet. Defaults to true. */ | |||
bool isStarting; | |||
/** Counter of visible windows, only used in standalone mode. | |||
If 0->1, application is starting. If 1->0, application is quitting/stopping. */ | |||
uint visibleWindows; | |||
/** List of windows for this application. Used as a way to call each window `idle`. */ | |||
/** List of windows for this application. Only used during `close`. */ | |||
std::list<Window*> windows; | |||
/** List of idle callbacks for this application. Run after all windows `idle`. */ | |||
/** List of idle callbacks for this application. */ | |||
std::list<IdleCallback*> idleCallbacks; | |||
/** Constructor and destructor */ | |||
PrivateData(const bool standalone); | |||
~PrivateData(); | |||
/** Flag one window shown or hidden status, which modifies @a visibleWindows. | |||
For standalone mode only. | |||
Modifies @a isQuitting under certain conditions */ | |||
/** Flag one window as shown, which increments @a visibleWindows. | |||
Sets @a isQuitting and @a isStarting as false if this is the first window. | |||
For standalone mode only. */ | |||
void oneWindowShown() noexcept; | |||
void oneWindowHidden() noexcept; | |||
/** Run Pugl world update for @a timeoutInMs, and then the idle functions for each window and idle callback, | |||
in order of registration. */ | |||
/** Flag one window as closed, which decrements @a visibleWindows. | |||
Sets @a isQuitting as true if this is the last window. | |||
For standalone mode only. */ | |||
void oneWindowClosed() noexcept; | |||
/** Run Pugl world update for @a timeoutInMs, and then each idle callback in order of registration. */ | |||
void idle(const uint timeoutInMs); | |||
/** Set flag indicating application is quitting, and closes all windows in reverse order of registration. */ | |||
/** Set flag indicating application is quitting, and close all windows in reverse order of registration. | |||
For standalone mode only. */ | |||
void quit(); | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) | |||
@@ -37,27 +37,32 @@ Window::~Window() | |||
delete pData; | |||
} | |||
void Window::close() | |||
bool Window::isEmbed() const noexcept | |||
{ | |||
pData->close(); | |||
return pData->isEmbed; | |||
} | |||
uintptr_t Window::getNativeWindowHandle() const noexcept | |||
bool Window::isVisible() const noexcept | |||
{ | |||
return puglGetNativeWindow(pData->view); | |||
return pData->isVisible; | |||
} | |||
#if 0 | |||
void Window::show() | |||
void Window::setVisible(const bool visible) | |||
{ | |||
pData->setVisible(true); | |||
pData->setVisible(visible); | |||
} | |||
void Window::hide() | |||
void Window::close() | |||
{ | |||
pData->close(); | |||
} | |||
uintptr_t Window::getNativeWindowHandle() const noexcept | |||
{ | |||
pData->setVisible(false); | |||
return puglGetNativeWindow(pData->view); | |||
} | |||
#if 0 | |||
#if 0 | |||
void Window::exec(bool lockWait) | |||
{ | |||
@@ -89,21 +94,6 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept | |||
puglPostRedisplayRect(pData->fView, prect); | |||
} | |||
bool Window::isEmbed() const noexcept | |||
{ | |||
return pData->fUsingEmbed; | |||
} | |||
bool Window::isVisible() const noexcept | |||
{ | |||
return pData->fVisible; | |||
} | |||
void Window::setVisible(const bool visible) | |||
{ | |||
pData->setVisible(visible); | |||
} | |||
bool Window::isResizable() const noexcept | |||
{ | |||
return puglGetViewHint(pData->fView, PUGL_RESIZABLE) == PUGL_TRUE; | |||
@@ -26,32 +26,56 @@ START_NAMESPACE_DGL | |||
Window::PrivateData::PrivateData(Application::PrivateData* const a, Window* const s) | |||
: appData(a), | |||
self(s), | |||
view(puglNewView(appData->world)) | |||
view(puglNewView(appData->world)), | |||
isClosed(true), | |||
isVisible(false), | |||
isEmbed(false) | |||
{ | |||
init(true); | |||
init(false); | |||
} | |||
Window::PrivateData::PrivateData(Application::PrivateData* const a, Window* const s, Window& transientWindow) | |||
: appData(a), | |||
self(s), | |||
view(puglNewView(appData->world)) | |||
view(puglNewView(appData->world)), | |||
isClosed(true), | |||
isVisible(false), | |||
isEmbed(false) | |||
{ | |||
init(false); | |||
puglSetTransientFor(view, transientWindow.getNativeWindowHandle()); | |||
init(true); | |||
} | |||
Window::PrivateData::PrivateData(Application::PrivateData* const a, Window* const s, | |||
const uintptr_t parentWindowHandle, const double scaling, const bool resizable) | |||
: appData(a), | |||
self(s), | |||
view(puglNewView(appData->world)) | |||
view(puglNewView(appData->world)), | |||
isClosed(parentWindowHandle == 0), | |||
isVisible(parentWindowHandle != 0), | |||
isEmbed(parentWindowHandle != 0) | |||
{ | |||
// TODO view parent | |||
init(resizable); | |||
if (isEmbed) | |||
{ | |||
appData->oneWindowShown(); | |||
puglSetParentWindow(view, parentWindowHandle); | |||
puglShow(view); | |||
} | |||
} | |||
Window::PrivateData::~PrivateData() | |||
{ | |||
if (isEmbed) | |||
{ | |||
puglHide(view); | |||
appData->oneWindowClosed(); | |||
isClosed = true; | |||
isVisible = false; | |||
} | |||
appData->idleCallbacks.remove(this); | |||
appData->windows.remove(self); | |||
@@ -95,28 +119,102 @@ void Window::PrivateData::init(const bool resizable) | |||
// DGL_DBG("Success!\n"); | |||
} | |||
// ----------------------------------------------------------------------- | |||
void Window::PrivateData::close() | |||
{ | |||
/* | |||
DGL_DBG("Window close\n"); | |||
// DGL_DBG("Window close\n"); | |||
if (fUsingEmbed) | |||
if (isEmbed || isClosed) | |||
return; | |||
isClosed = true; | |||
setVisible(false); | |||
appData->oneWindowClosed(); | |||
} | |||
// ----------------------------------------------------------------------- | |||
void Window::PrivateData::setVisible(const bool visible) | |||
{ | |||
if (isVisible == visible) | |||
{ | |||
// DGL_DBG("Window setVisible matches current state, ignoring request\n"); | |||
return; | |||
} | |||
if (isEmbed) | |||
{ | |||
// DGL_DBG("Window setVisible cannot be called when embedded\n"); | |||
return; | |||
} | |||
// DGL_DBG("Window setVisible called\n"); | |||
isVisible = visible; | |||
if (visible) | |||
{ | |||
// #if 0 && defined(DISTRHO_OS_MAC) | |||
// if (mWindow != nullptr) | |||
// { | |||
// if (mParentWindow != nullptr) | |||
// [mParentWindow addChildWindow:mWindow | |||
// ordered:NSWindowAbove]; | |||
// } | |||
// #endif | |||
if (! fFirstInit) | |||
if (isClosed) | |||
{ | |||
puglRealize(view); | |||
#ifdef DISTRHO_OS_WINDOWS | |||
puglWin32ShowWindowCentered(view); | |||
#else | |||
puglShow(view); | |||
#endif | |||
appData->oneWindowShown(); | |||
isClosed = false; | |||
} | |||
else | |||
{ | |||
#ifdef DISTRHO_OS_WINDOWS | |||
puglWin32RestoreWindow(view); | |||
#else | |||
puglShow(view); | |||
#endif | |||
} | |||
} | |||
else | |||
{ | |||
fAppData->oneWindowHidden(); | |||
fFirstInit = true; | |||
// #if 0 && defined(DISTRHO_OS_MAC) | |||
// if (mWindow != nullptr) | |||
// { | |||
// if (mParentWindow != nullptr) | |||
// [mParentWindow removeChildWindow:mWindow]; | |||
// } | |||
// #endif | |||
puglHide(view); | |||
// if (fModal.enabled) | |||
// exec_fini(); | |||
} | |||
*/ | |||
} | |||
// ----------------------------------------------------------------------- | |||
void Window::PrivateData::idleCallback() | |||
{ | |||
// #if defined(DISTRHO_OS_WINDOWS) && !defined(DGL_FILE_BROWSER_DISABLED) | |||
// if (fSelectedFile.isNotEmpty()) | |||
// { | |||
// char* const buffer = fSelectedFile.getAndReleaseBuffer(); | |||
// fView->fileSelectedFunc(fView, buffer); | |||
// std::free(buffer); | |||
// } | |||
// #endif | |||
// | |||
// if (fModal.enabled && fModal.parent != nullptr) | |||
// fModal.parent->windowSpecificIdle(); | |||
} | |||
// ----------------------------------------------------------------------- | |||
@@ -156,8 +254,6 @@ extern "C" { | |||
# define DGL_DEBUG_EVENTS | |||
# include "pugl-upstream/src/haiku.cpp" | |||
#elif defined(DISTRHO_OS_MAC) | |||
# define PuglWindow DISTRHO_JOIN_MACRO(PuglWindow, DGL_NAMESPACE) | |||
# define PuglOpenGLView DISTRHO_JOIN_MACRO(PuglOpenGLView, DGL_NAMESPACE) | |||
# include "pugl-upstream/src/mac.m" | |||
#elif defined(DISTRHO_OS_WINDOWS) | |||
# include "ppugl-upstream/src/win.c" | |||
@@ -214,189 +310,6 @@ struct Fallback { | |||
// ----------------------------------------------------------------------- | |||
Window::PrivateData::PrivateData(Application::PrivateData* const appData, Window* const self) | |||
: fAppData(appData), | |||
fSelf(self), | |||
fView(puglNewView(appData->world)), | |||
fFirstInit(true), | |||
fVisible(false), | |||
fUsingEmbed(false), | |||
fScaling(1.0), | |||
fAutoScaling(1.0), | |||
fWidgets(), | |||
fModal() | |||
{ | |||
DGL_DBG("Creating window without parent..."); DGL_DBGF; | |||
init(); | |||
} | |||
#ifndef DPF_TEST_WINDOW_CPP | |||
Window::PrivateData::PrivateData(Application::PrivateData* const appData, Window* const self, Window& transientWindow) | |||
: fAppData(appData), | |||
fSelf(self), | |||
fView(puglNewView(appData->world)), | |||
fFirstInit(true), | |||
fVisible(false), | |||
fUsingEmbed(false), | |||
fScaling(1.0), | |||
fAutoScaling(1.0), | |||
fWidgets(), | |||
fModal(transientWindow.pData) | |||
{ | |||
DGL_DBG("Creating window with parent..."); DGL_DBGF; | |||
init(); | |||
puglSetTransientFor(fView, transientWindow.getNativeWindowHandle()); | |||
} | |||
#endif | |||
Window::PrivateData::PrivateData(Application::PrivateData* const appData, Window* const self, | |||
const uintptr_t parentWindowHandle, | |||
const double scaling, | |||
const bool resizable) | |||
: fAppData(appData), | |||
fSelf(self), | |||
fView(puglNewView(appData->world)), | |||
fFirstInit(true), | |||
fVisible(parentWindowHandle != 0), | |||
fUsingEmbed(parentWindowHandle != 0), | |||
fScaling(scaling), | |||
fAutoScaling(1.0), | |||
fWidgets(), | |||
fModal() | |||
{ | |||
if (fUsingEmbed) | |||
{ | |||
DGL_DBG("Creating embedded window..."); DGL_DBGF; | |||
puglSetParentWindow(fView, parentWindowHandle); | |||
} | |||
else | |||
{ | |||
DGL_DBG("Creating window without parent..."); DGL_DBGF; | |||
} | |||
init(resizable); | |||
if (fUsingEmbed) | |||
{ | |||
DGL_DBG("NOTE: Embed window is always visible and non-resizable\n"); | |||
// puglShowWindow(fView); | |||
// fAppData->oneWindowShown(); | |||
// fFirstInit = false; | |||
} | |||
} | |||
Window::PrivateData::~PrivateData() | |||
{ | |||
DGL_DBG("Destroying window..."); DGL_DBGF; | |||
#if 0 | |||
if (fModal.enabled) | |||
{ | |||
exec_fini(); | |||
close(); | |||
} | |||
#endif | |||
fWidgets.clear(); | |||
if (fUsingEmbed) | |||
{ | |||
// puglHideWindow(fView); | |||
// fAppData->oneWindowHidden(); | |||
} | |||
if (fSelf != nullptr) | |||
fAppData->windows.remove(fSelf); | |||
#if defined(DISTRHO_OS_MAC) && !defined(DGL_FILE_BROWSER_DISABLED) | |||
if (fOpenFilePanel) | |||
{ | |||
[fOpenFilePanel release]; | |||
fOpenFilePanel = nullptr; | |||
} | |||
if (fFilePanelDelegate) | |||
{ | |||
[fFilePanelDelegate release]; | |||
fFilePanelDelegate = nullptr; | |||
} | |||
#endif | |||
if (fView != nullptr) | |||
puglFreeView(fView); | |||
DGL_DBG("Success!\n"); | |||
} | |||
// ----------------------------------------------------------------------- | |||
void Window::PrivateData::setVisible(const bool visible) | |||
{ | |||
if (fVisible == visible) | |||
{ | |||
DGL_DBG("Window setVisible matches current state, ignoring request\n"); | |||
return; | |||
} | |||
if (fUsingEmbed) | |||
{ | |||
DGL_DBG("Window setVisible cannot be called when embedded\n"); | |||
return; | |||
} | |||
DGL_DBG("Window setVisible called\n"); | |||
fVisible = visible; | |||
if (visible) | |||
{ | |||
#if 0 && defined(DISTRHO_OS_MAC) | |||
if (mWindow != nullptr) | |||
{ | |||
if (mParentWindow != nullptr) | |||
[mParentWindow addChildWindow:mWindow | |||
ordered:NSWindowAbove]; | |||
} | |||
#endif | |||
if (fFirstInit) | |||
{ | |||
puglRealize(fView); | |||
#ifdef DISTRHO_OS_WINDOWS | |||
puglShowWindowCentered(fView); | |||
#else | |||
puglShow(fView); | |||
#endif | |||
fAppData->oneWindowShown(); | |||
fFirstInit = false; | |||
} | |||
else | |||
{ | |||
#ifdef DISTRHO_OS_WINDOWS | |||
puglWin32RestoreWindow(fView); | |||
#else | |||
puglShow(fView); | |||
#endif | |||
} | |||
} | |||
else | |||
{ | |||
#if 0 && defined(DISTRHO_OS_MAC) | |||
if (mWindow != nullptr) | |||
{ | |||
if (mParentWindow != nullptr) | |||
[mParentWindow removeChildWindow:mWindow]; | |||
} | |||
#endif | |||
puglHide(fView); | |||
// if (fModal.enabled) | |||
// exec_fini(); | |||
} | |||
} | |||
// ----------------------------------------------------------------------- | |||
void Window::PrivateData::addWidget(Widget* const widget) | |||
{ | |||
fWidgets.push_back(widget); | |||
@@ -486,23 +399,6 @@ void Window::PrivateData::onPuglMouse(const Widget::MouseEvent& ev) | |||
// ----------------------------------------------------------------------- | |||
void Window::PrivateData::windowSpecificIdle() | |||
{ | |||
#if defined(DISTRHO_OS_WINDOWS) && !defined(DGL_FILE_BROWSER_DISABLED) | |||
if (fSelectedFile.isNotEmpty()) | |||
{ | |||
char* const buffer = fSelectedFile.getAndReleaseBuffer(); | |||
fView->fileSelectedFunc(fView, buffer); | |||
std::free(buffer); | |||
} | |||
#endif | |||
if (fModal.enabled && fModal.parent != nullptr) | |||
fModal.parent->windowSpecificIdle(); | |||
} | |||
// ----------------------------------------------------------------------- | |||
static inline int | |||
printModifiers(const uint32_t mods) | |||
{ | |||
@@ -18,7 +18,6 @@ | |||
#define DGL_WINDOW_PRIVATE_DATA_HPP_INCLUDED | |||
#include "../Window.hpp" | |||
// #include "ApplicationPrivateData.hpp" | |||
#include "pugl.hpp" | |||
@@ -41,6 +40,16 @@ struct Window::PrivateData : IdleCallback { | |||
/** Pugl view instance. */ | |||
PuglView* const view; | |||
/** Whether this Window is closed (not visible or counted in the Application it is tied to). | |||
Defaults to true unless embed (embed windows are never closed). */ | |||
bool isClosed; | |||
/** Whether this Window is currently visible/mapped. Defaults to false. */ | |||
bool isVisible; | |||
/** Whether this Window is embed into another (usually not DGL-controlled) Window. */ | |||
const bool isEmbed; | |||
/** Constructor for a regular, standalone window. */ | |||
PrivateData(AppData* appData, Window* self); | |||
@@ -58,13 +67,15 @@ struct Window::PrivateData : IdleCallback { | |||
/** Hide window and notify application of a window close event. | |||
* Does nothing if window is embed (that is, not standalone). | |||
* The application event-loop will stop if all windows have been closed. | |||
* The application event-loop will stop when all windows have been closed. | |||
* | |||
* @note It is possible to hide the window while not stopping event-loop. | |||
* @note It is possible to hide the window while not stopping the event-loop. | |||
* A closed window is always hidden, but the reverse is not always true. | |||
*/ | |||
void close(); | |||
void setVisible(bool visible); | |||
void idleCallback() override; | |||
static PuglStatus puglEventCallback(PuglView* view, const PuglEvent* event); | |||
@@ -1 +1 @@ | |||
Subproject commit 2d3100e47eee6a8bf2209ee19157de6d23dd1c55 | |||
Subproject commit 5a3a1309ad6432d72cdb7f37e3e36383dd6ba372 |
@@ -67,6 +67,8 @@ START_NAMESPACE_DGL | |||
#if defined(DISTRHO_OS_HAIKU) | |||
#elif defined(DISTRHO_OS_MAC) | |||
# define PuglWindow DISTRHO_JOIN_MACRO(PuglWindow, DGL_NAMESPACE) | |||
# define PuglOpenGLView DISTRHO_JOIN_MACRO(PuglOpenGLView, DGL_NAMESPACE) | |||
#elif defined(DISTRHO_OS_WINDOWS) | |||
#else | |||
# include "pugl-upstream/src/x11.c" | |||
@@ -35,7 +35,7 @@ TARGETS = $(TESTS:%=../build/tests/%) | |||
TARGETS += $(WTESTS:Window.%=../build/tests/Window.%) | |||
OBJS = $(TESTS:%=../build/tests/%.cpp.o) | |||
OBJS += $(WTESTS:Window.%=../build/tests/Window.%.cpp.o) | |||
OBJS += $(WTESTS:Window.%=../build/tests/Window.cpp.%.o) | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
@@ -68,8 +68,7 @@ all: $(TARGETS) | |||
@echo "Linking $*" | |||
$(SILENT)$(CXX) $< $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ | |||
@echo "Running test for $*" | |||
# $(SILENT) | |||
$@ | |||
$(SILENT) $@ | |||
# gdb -ex run | |||
../build/tests/%.vulkan: ../build/tests/%.cpp.vulkan.o | |||
@@ -39,6 +39,7 @@ int main() | |||
{ | |||
Application app(true); | |||
Window win(app); | |||
app.idle(); | |||
} | |||
// TODO | |||