|
- /*
- * DISTRHO Plugin Toolkit (DPT)
- * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * For a full copy of the license see the LGPL.txt file
- */
-
- #include "AppPrivate.hpp"
-
- #include "../Widget.hpp"
- #include "../Window.hpp"
-
- #include "pugl/pugl.h"
-
- #if DGL_OS_WINDOWS
- # include "pugl/pugl_win.cpp"
- #elif DGL_OS_MAC
- extern "C" {
- # include "pugl/pugl_osx_extended.h"
- }
- #elif DGL_OS_LINUX
- extern "C" {
- # include "pugl/pugl_x11.c"
- }
- #else
- # error Unsupported platform!
- #endif
-
- #include <cassert>
-
- #define FOR_EACH_WIDGET(it) \
- for (std::list<Widget*>::iterator it = fWidgets.begin(); it != fWidgets.end(); ++it)
-
- #define FOR_EACH_WIDGET_INV(rit) \
- for (std::list<Widget*>::reverse_iterator rit = fWidgets.rbegin(); rit != fWidgets.rend(); ++rit)
-
- START_NAMESPACE_DGL
-
- Window* dgl_lastUiParent = nullptr;
-
- // -------------------------------------------------
- // Window Private
-
- class Window::Private
- {
- public:
- Private(Window* self, App* app, App::Private* appPriv, Private* parent, intptr_t parentId = 0)
- : kApp(app),
- kAppPriv(appPriv),
- kSelf(self),
- kView(puglCreate(parentId, "Window", 100, 100, false, (parentId != 0))),
- fParent(parent),
- fChildFocus(nullptr),
- fVisible((parentId != 0)),
- fOnModal(false),
- fResizable(false),
- #if DGL_OS_WINDOWS
- hwnd(0)
- #elif DGL_OS_LINUX
- xDisplay(nullptr),
- xWindow(0)
- #else
- _dummy(0)
- #endif
- {
- if (kView == nullptr)
- return;
-
- // we can't have both
- if (parent != nullptr)
- {
- assert(parentId == 0);
- }
-
- puglSetHandle(kView, this);
- puglSetDisplayFunc(kView, onDisplayCallback);
- puglSetKeyboardFunc(kView, onKeyboardCallback);
- puglSetMotionFunc(kView, onMotionCallback);
- puglSetMouseFunc(kView, onMouseCallback);
- puglSetScrollFunc(kView, onScrollCallback);
- puglSetSpecialFunc(kView, onSpecialCallback);
- puglSetReshapeFunc(kView, onReshapeCallback);
- puglSetCloseFunc(kView, onCloseCallback);
-
- #if DGL_OS_WINDOWS
- PuglInternals* impl = kView->impl;
- hwnd = impl->hwnd;
- #elif DGL_OS_LINUX
- PuglInternals* impl = kView->impl;
- xDisplay = impl->display;
- xWindow = impl->win;
-
- if (parent != nullptr && parentId == 0)
- {
- PuglInternals* parentImpl = parent->kView->impl;
-
- XSetTransientForHint(xDisplay, xWindow, parentImpl->win);
- XFlush(xDisplay);
- }
- #endif
-
- kAppPriv->addWindow(kSelf);
- }
-
- ~Private()
- {
- fOnModal = false;
- fWidgets.clear();
-
- if (kView != nullptr)
- {
- kAppPriv->removeWindow(kSelf);
- puglDestroy(kView);
- }
- }
-
- void exec_init()
- {
- fOnModal = true;
- assert(fParent != nullptr);
-
- if (fParent != nullptr)
- {
- fParent->fChildFocus = this;
-
- #if DGL_OS_WINDOWS
- // Center this window
- PuglInternals* parentImpl = fParent->kView->impl;
-
- RECT curRect;
- RECT parentRect;
- GetWindowRect(hwnd, &curRect);
- GetWindowRect(parentImpl->hwnd, &parentRect);
-
- int x = parentRect.left+(parentRect.right-curRect.right)/2;
- int y = parentRect.top+(parentRect.bottom-curRect.bottom)/2;
-
- SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
- UpdateWindow(hwnd);
- #endif
-
- fParent->show();
- }
-
- show();
- }
-
- void exec_fini()
- {
- fOnModal = false;
-
- if (fParent != nullptr)
- fParent->fChildFocus = nullptr;
- }
-
- void exec(bool block)
- {
- exec_init();
-
- if (block)
- {
- while (fVisible && fOnModal)
- {
- // idle()
- puglProcessEvents(kView);
-
- if (fParent != nullptr)
- fParent->idle();
-
- dgl_msleep(10);
- }
-
- exec_fini();
- }
- else
- {
- idle();
- }
- }
-
- void focus()
- {
- #if DGL_OS_WINDOWS
- SetForegroundWindow(hwnd);
- SetActiveWindow(hwnd);
- SetFocus(hwnd);
- #elif DGL_OS_MAC
- puglImplFocus(kView);
- #elif DGL_OS_LINUX
- XRaiseWindow(xDisplay, xWindow);
- XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime);
- XFlush(xDisplay);
- #endif
- }
-
- void idle()
- {
- puglProcessEvents(kView);
-
- if (fVisible && fOnModal && fParent != nullptr)
- fParent->idle();
- }
-
- void repaint()
- {
- puglPostRedisplay(kView);
- }
-
- void show()
- {
- setVisible(true);
- }
-
- void hide()
- {
- setVisible(false);
- }
-
- void close()
- {
- setVisible(false, true);
- }
-
- bool isVisible()
- {
- return fVisible;
- }
-
- void setResizable(bool yesNo)
- {
- if (fResizable == yesNo)
- return;
-
- fResizable = yesNo;
-
- //setSize();
- }
-
- void setVisible(bool yesNo, bool closed = false)
- {
- if (fVisible == yesNo)
- return;
-
- fVisible = yesNo;
-
- #if DGL_OS_WINDOWS
- if (yesNo)
- {
- ShowWindow(hwnd, WS_VISIBLE);
- ShowWindow(hwnd, SW_RESTORE);
- //SetForegroundWindow(hwnd);
- }
- else
- {
- ShowWindow(hwnd, SW_HIDE);
- }
-
- UpdateWindow(hwnd);
- #elif DGL_OS_MAC
- puglImplSetVisible(kView, yesNo);
- #elif DGL_OS_LINUX
- if (yesNo)
- XMapRaised(xDisplay, xWindow);
- else
- XUnmapWindow(xDisplay, xWindow);
-
- XFlush(xDisplay);
- #endif
-
- if (yesNo)
- {
- kAppPriv->oneShown();
- }
- else
- {
- if (fOnModal)
- exec_fini();
-
- if (closed)
- kAppPriv->oneHidden();
- }
- }
-
- void setSize(unsigned int width, unsigned int height)
- {
- kView->width = width;
- kView->height = height;
-
- #if DGL_OS_WINDOWS
- int winFlags = WS_POPUPWINDOW | WS_CAPTION;
-
- if (fResizable)
- winFlags |= WS_SIZEBOX;
-
- RECT wr = { 0, 0, (long)width, (long)height };
- AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST);
-
- SetWindowPos(hwnd, 0, 0, 0, wr.right-wr.left, wr.bottom-wr.top, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER);
- UpdateWindow(hwnd);
- #elif DGL_OS_MAC
- puglImplSetSize(kView, width, height);
- #elif DGL_OS_LINUX
- XResizeWindow(xDisplay, xWindow, width, height);
-
- if (! fResizable)
- {
- XSizeHints sizeHints;
- memset(&sizeHints, 0, sizeof(sizeHints));
-
- sizeHints.flags = PMinSize|PMaxSize;
- sizeHints.min_width = width;
- sizeHints.min_height = height;
- sizeHints.max_width = width;
- sizeHints.max_height = height;
-
- XSetNormalHints(xDisplay, xWindow, &sizeHints);
- }
-
- XFlush(xDisplay);
- #endif
-
- repaint();
- }
-
- void setWindowTitle(const char* title)
- {
- #if DGL_OS_WINDOWS
- SetWindowTextA(hwnd, title);
- #elif DGL_OS_MAC
- puglImplSetTitle(kView, title);
- #elif DGL_OS_LINUX
- XStoreName(xDisplay, xWindow, title);
- XFlush(xDisplay);
- #endif
- }
-
- App* getApp() const
- {
- return kApp;
- }
-
- int getModifiers() const
- {
- return puglGetModifiers(kView);
- }
-
- intptr_t getWindowId() const
- {
- return puglGetNativeWindow(kView);
- }
-
- void addWidget(Widget* widget)
- {
- fWidgets.push_back(widget);
- }
-
- void removeWidget(Widget* widget)
- {
- fWidgets.remove(widget);
- }
-
- protected:
- void onDisplay()
- {
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- FOR_EACH_WIDGET(it)
- {
- Widget* const widget(*it);
- if (widget->isVisible())
- widget->onDisplay();
- }
- }
-
- void onKeyboard(bool press, uint32_t key)
- {
- if (fChildFocus != nullptr)
- return fChildFocus->focus();
-
- FOR_EACH_WIDGET_INV(rit)
- {
- Widget* const widget(*rit);
- if (widget->isVisible())
- {
- if (widget->onKeyboard(press, key))
- break;
- }
- }
- }
-
- void onMouse(int button, bool press, int x, int y)
- {
- if (fChildFocus != nullptr)
- return fChildFocus->focus();
-
- FOR_EACH_WIDGET_INV(rit)
- {
- Widget* const widget(*rit);
- if (widget->isVisible())
- {
- if (widget->onMouse(button, press, x, y))
- break;
- }
- }
- }
-
- void onMotion(int x, int y)
- {
- if (fChildFocus != nullptr)
- return;
-
- FOR_EACH_WIDGET_INV(rit)
- {
- Widget* const widget(*rit);
- if (widget->isVisible())
- {
- if (widget->onMotion(x, y))
- break;
- }
- }
- }
-
- void onScroll(float dx, float dy)
- {
- if (fChildFocus != nullptr)
- return;
-
- FOR_EACH_WIDGET_INV(rit)
- {
- Widget* const widget(*rit);
- if (widget->isVisible())
- {
- if (widget->onScroll(dx, dy))
- break;
- }
- }
- }
-
- void onSpecial(bool press, Key key)
- {
- if (fChildFocus != nullptr)
- return;
-
- FOR_EACH_WIDGET_INV(rit)
- {
- Widget* const widget(*rit);
- if (widget->isVisible())
- {
- if (widget->onSpecial(press, key))
- break;
- }
- }
- }
-
- void onReshape(int width, int height)
- {
- FOR_EACH_WIDGET(it)
- {
- Widget* const widget(*it);
- widget->onReshape(width, height);
- }
- }
-
- void onClose()
- {
- fOnModal = false;
-
- if (fChildFocus != nullptr)
- fChildFocus->onClose();
-
- FOR_EACH_WIDGET(it)
- {
- Widget* const widget(*it);
- widget->onClose();
- }
-
- close();
- }
-
- private:
- App* const kApp;
- App::Private* const kAppPriv;
- Window* const kSelf;
- PuglView* const kView;
-
- Private* fParent;
- Private* fChildFocus;
- bool fVisible;
- bool fOnModal;
- bool fResizable;
-
- std::list<Widget*> fWidgets;
-
- #if DGL_OS_WINDOWS
- HWND hwnd;
- #elif DGL_OS_LINUX
- Display* xDisplay;
- ::Window xWindow;
- #else
- int _dummy;
- #endif
-
- // Callbacks
- #define handlePtr ((Private*)puglGetHandle(view))
-
- static void onDisplayCallback(PuglView* view)
- {
- handlePtr->onDisplay();
- }
-
- static void onKeyboardCallback(PuglView* view, bool press, uint32_t key)
- {
- handlePtr->onKeyboard(press, key);
- }
-
- static void onMouseCallback(PuglView* view, int button, bool press, int x, int y)
- {
- handlePtr->onMouse(button, press, x, y);
- }
-
- static void onMotionCallback(PuglView* view, int x, int y)
- {
- handlePtr->onMotion(x, y);
- }
-
- static void onScrollCallback(PuglView* view, float dx, float dy)
- {
- handlePtr->onScroll(dx, dy);
- }
-
- static void onSpecialCallback(PuglView* view, bool press, PuglKey key)
- {
- handlePtr->onSpecial(press, static_cast<Key>(key));
- }
-
- static void onReshapeCallback(PuglView* view, int width, int height)
- {
- handlePtr->onReshape(width, height);
- }
-
- static void onCloseCallback(PuglView* view)
- {
- handlePtr->onClose();
- }
-
- #undef handlePtr
- };
-
- // -------------------------------------------------
- // Window
-
- Window::Window(App* app, Window* parent)
- : kPrivate(new Private(this, app, app->kPrivate, (parent != nullptr) ? parent->kPrivate : nullptr))
- {
- dgl_lastUiParent = this;
- }
-
- Window::Window(App* app, intptr_t parentId)
- : kPrivate(new Private(this, app, app->kPrivate, nullptr, parentId))
- {
- dgl_lastUiParent = this;
- }
-
- Window::~Window()
- {
- delete kPrivate;
- }
-
- void Window::exec(bool lock)
- {
- kPrivate->exec(lock);
- }
-
- void Window::focus()
- {
- kPrivate->focus();
- }
-
- void Window::idle()
- {
- kPrivate->idle();
- }
-
- void Window::repaint()
- {
- kPrivate->repaint();
- }
-
- bool Window::isVisible()
- {
- return kPrivate->isVisible();
- }
-
- void Window::setResizable(bool yesNo)
- {
- kPrivate->setResizable(yesNo);
- }
-
- void Window::setVisible(bool yesNo)
- {
- kPrivate->setVisible(yesNo);
- }
-
- void Window::setSize(unsigned int width, unsigned int height)
- {
- kPrivate->setSize(width, height);
- }
-
- void Window::setWindowTitle(const char* title)
- {
- kPrivate->setWindowTitle(title);
- }
-
- App* Window::getApp() const
- {
- return kPrivate->getApp();
- }
-
- int Window::getModifiers() const
- {
- return kPrivate->getModifiers();
- }
-
- intptr_t Window::getWindowId() const
- {
- return kPrivate->getWindowId();
- }
-
- void Window::addWidget(Widget* widget)
- {
- kPrivate->addWidget(widget);
- }
-
- void Window::removeWidget(Widget* widget)
- {
- kPrivate->removeWidget(widget);
- }
-
- void Window::show()
- {
- setVisible(true);
- }
-
- void Window::hide()
- {
- setVisible(false);
- }
-
- void Window::close()
- {
- kPrivate->close();
- }
-
- // -------------------------------------------------
-
- END_NAMESPACE_DGL
|