| @@ -82,11 +82,6 @@ protected: | |||||
| private: | private: | ||||
| UIPrivateData* const pData; | UIPrivateData* const pData; | ||||
| friend class UIInternal; | friend class UIInternal; | ||||
| #ifdef DISTRHO_UI_QT4 | |||||
| friend class Qt4UI; | |||||
| #else | |||||
| friend class OpenGLUI; | |||||
| #endif | |||||
| }; | }; | ||||
| // ------------------------------------------------- | // ------------------------------------------------- | ||||
| @@ -0,0 +1,70 @@ | |||||
| /* | |||||
| * 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 | |||||
| */ | |||||
| #ifndef __DISTRHO_UI_OPENGL_HPP__ | |||||
| #define __DISTRHO_UI_OPENGL_HPP__ | |||||
| #include "DistrhoUI.hpp" | |||||
| #include "dgl/Widget.hpp" | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ------------------------------------------------- | |||||
| // OpenGL UI | |||||
| class OpenGLUI : public UI, | |||||
| public Widget | |||||
| { | |||||
| public: | |||||
| OpenGLUI(); | |||||
| virtual ~OpenGLUI(); | |||||
| protected: | |||||
| // --------------------------------------------- | |||||
| // Information | |||||
| virtual unsigned int d_width() const = 0; | |||||
| virtual unsigned int d_height() const = 0; | |||||
| // --------------------------------------------- | |||||
| // DSP Callbacks | |||||
| virtual void d_parameterChanged(uint32_t index, float value) = 0; | |||||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||||
| virtual void d_programChanged(uint32_t index) = 0; | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_WANT_STATE | |||||
| virtual void d_stateChanged(const char* key, const char* value) = 0; | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_IS_SYNTH | |||||
| virtual void d_noteReceived(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity) = 0; | |||||
| #endif | |||||
| // --------------------------------------------- | |||||
| // UI Callbacks | |||||
| virtual void d_uiIdle() = 0; | |||||
| private: | |||||
| friend class UIInternal; | |||||
| }; | |||||
| // ------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| #endif // __DISTRHO_UI_OPENGL_HPP__ | |||||
| @@ -58,7 +58,7 @@ protected: | |||||
| // --------------------------------------------- | // --------------------------------------------- | ||||
| // UI Callbacks | // UI Callbacks | ||||
| virtual void d_uiIdle(); | |||||
| virtual void d_uiIdle() {} | |||||
| private: | private: | ||||
| friend class UIInternal; | friend class UIInternal; | ||||
| @@ -0,0 +1,45 @@ | |||||
| /* | |||||
| * 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 | |||||
| */ | |||||
| #ifndef __DGL_APP_HPP__ | |||||
| #define __DGL_APP_HPP__ | |||||
| #include "Base.hpp" | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ------------------------------------------------- | |||||
| class App | |||||
| { | |||||
| public: | |||||
| App(); | |||||
| ~App(); | |||||
| void idle(); | |||||
| void exec(); | |||||
| private: | |||||
| class Private; | |||||
| Private* const kPrivate; | |||||
| friend class Window; | |||||
| }; | |||||
| // ------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| #endif // __DGL_APP_HPP__ | |||||
| @@ -0,0 +1,79 @@ | |||||
| /* | |||||
| * 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 | |||||
| */ | |||||
| #ifndef __DGL_BASE_HPP__ | |||||
| #define __DGL_BASE_HPP__ | |||||
| #include "../src/DistrhoDefines.h" | |||||
| #if DISTRHO_OS_MAC | |||||
| # include <OpenGL/glu.h> | |||||
| #else | |||||
| # include <GL/glu.h> | |||||
| #endif | |||||
| #if defined(GL_BGR_EXT) && ! defined(GL_BGR) | |||||
| # define GL_BGR GL_BGR_EXT | |||||
| #endif | |||||
| #if defined(GL_BGRA_EXT) && ! defined(GL_BGRA) | |||||
| # define GL_BGRA GL_BGRA_EXT | |||||
| #endif | |||||
| // ------------------------------------------------- | |||||
| enum Char { | |||||
| CHAR_BACKSPACE = 0x08, | |||||
| CHAR_ESCAPE = 0x1B, | |||||
| CHAR_DELETE = 0x7F | |||||
| }; | |||||
| enum Key { | |||||
| KEY_F1 = 1, | |||||
| KEY_F2, | |||||
| KEY_F3, | |||||
| KEY_F4, | |||||
| KEY_F5, | |||||
| KEY_F6, | |||||
| KEY_F7, | |||||
| KEY_F8, | |||||
| KEY_F9, | |||||
| KEY_F10, | |||||
| KEY_F11, | |||||
| KEY_F12, | |||||
| KEY_LEFT, | |||||
| KEY_UP, | |||||
| KEY_RIGHT, | |||||
| KEY_DOWN, | |||||
| KEY_PAGE_UP, | |||||
| KEY_PAGE_DOWN, | |||||
| KEY_HOME, | |||||
| KEY_END, | |||||
| KEY_INSERT, | |||||
| KEY_SHIFT, | |||||
| KEY_CTRL, | |||||
| KEY_ALT, | |||||
| KEY_SUPER | |||||
| }; | |||||
| enum Modifier { | |||||
| MODIFIER_SHIFT = 1 << 0, /**< Shift key */ | |||||
| MODIFIER_CTRL = 1 << 1, /**< Control key */ | |||||
| MODIFIER_ALT = 1 << 2, /**< Alt/Option key */ | |||||
| MODIFIER_SUPER = 1 << 3 /**< Mod4/Command/Windows key */ | |||||
| }; | |||||
| #endif // __DGL_BASE_HPP__ | |||||
| @@ -0,0 +1,131 @@ | |||||
| /* | |||||
| * 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 | |||||
| */ | |||||
| #ifndef __DGL_GEOMETRY_HPP__ | |||||
| #define __DGL_GEOMETRY_HPP__ | |||||
| #include "Base.hpp" | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ------------------------------------------------- | |||||
| template<typename T> | |||||
| class Point | |||||
| { | |||||
| public: | |||||
| Point(); | |||||
| Point(T x, T y); | |||||
| Point(const Point<T>& pos); | |||||
| T getX() const; | |||||
| T getY() const; | |||||
| void setX(T x); | |||||
| void setY(T y); | |||||
| void move(T x, T y); | |||||
| void move(const Point<T>& pos); | |||||
| Point<T>& operator=(const Point<T>& pos); | |||||
| Point<T>& operator+=(const Point<T>& pos); | |||||
| Point<T>& operator-=(const Point<T>& pos); | |||||
| bool operator==(const Point<T>& pos) const; | |||||
| bool operator!=(const Point<T>& pos) const; | |||||
| private: | |||||
| T fX, fY; | |||||
| template<typename> friend class Rectangle; | |||||
| }; | |||||
| // ------------------------------------------------- | |||||
| template<typename T> | |||||
| class Size | |||||
| { | |||||
| public: | |||||
| Size(); | |||||
| Size(T width, T height); | |||||
| Size(const Size<T>& size); | |||||
| T getWidth() const; | |||||
| T getHeight() const; | |||||
| void setWidth(T width); | |||||
| void setHeight(T height); | |||||
| Size<T>& operator=(const Size<T>& size); | |||||
| Size<T>& operator+=(const Size<T>& size); | |||||
| Size<T>& operator-=(const Size<T>& size); | |||||
| Size<T>& operator*=(T m); | |||||
| Size<T>& operator/=(T d); | |||||
| bool operator==(const Size<T>& size) const; | |||||
| bool operator!=(const Size<T>& size) const; | |||||
| private: | |||||
| T fWidth, fHeight; | |||||
| template<typename> friend class Rectangle; | |||||
| }; | |||||
| // ------------------------------------------------- | |||||
| template<typename T> | |||||
| class Rectangle | |||||
| { | |||||
| public: | |||||
| Rectangle(); | |||||
| Rectangle(T x, T y, T width, T height); | |||||
| Rectangle(T x, T y, const Size<T>& size); | |||||
| Rectangle(const Point<T>& pos, T width, T height); | |||||
| Rectangle(const Point<T>& pos, const Size<T>& size); | |||||
| Rectangle(const Rectangle<T>& rect); | |||||
| T getX() const; | |||||
| T getY() const; | |||||
| T getWidth() const; | |||||
| T getHeight() const; | |||||
| const Point<T>& getPos() const; | |||||
| const Size<T>& getSize() const; | |||||
| bool contains(T x, T y) const; | |||||
| bool contains(const Point<T>& pos) const; | |||||
| void setX(T x); | |||||
| void setY(T y); | |||||
| void setPos(T x, T y); | |||||
| void setPos(const Point<T>& pos); | |||||
| void move(T x, T y); | |||||
| void move(const Point<T>& pos); | |||||
| void setWidth(T width); | |||||
| void setHeight(T height); | |||||
| void setSize(T width, T height); | |||||
| void setSize(const Size<T>& size); | |||||
| Rectangle<T>& operator=(const Rectangle<T>& rect); | |||||
| private: | |||||
| Point<T> fPos; | |||||
| Size<T> fSize; | |||||
| }; | |||||
| // ------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| #endif // __DGL_GEOMETRY_HPP__ | |||||
| @@ -0,0 +1,56 @@ | |||||
| /* | |||||
| * 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 | |||||
| */ | |||||
| #ifndef __DGL_IMAGE_HPP__ | |||||
| #define __DGL_IMAGE_HPP__ | |||||
| #include "Geometry.hpp" | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ------------------------------------------------- | |||||
| class Image | |||||
| { | |||||
| public: | |||||
| Image(); | |||||
| Image(const char* data, const Size<int>& size, GLenum format = GL_BGRA, GLenum type = GL_UNSIGNED_BYTE); | |||||
| Image(const Image& image); | |||||
| void loadFromMemory(const char* data, const Size<int>& size, GLenum format = GL_BGRA, GLenum type = GL_UNSIGNED_BYTE); | |||||
| bool isValid() const; | |||||
| int getWidth() const; | |||||
| int getHeight() const; | |||||
| const Size<int>& getSize() const; | |||||
| const char* getData() const; | |||||
| GLenum getFormat() const; | |||||
| GLenum getType() const; | |||||
| private: | |||||
| const char* fData; | |||||
| Size<int> fSize; | |||||
| GLenum fFormat; | |||||
| GLenum fType; | |||||
| }; | |||||
| // ------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| #endif // __DGL_IMAGE_HPP__ | |||||
| @@ -0,0 +1,54 @@ | |||||
| /* | |||||
| * 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 | |||||
| */ | |||||
| #ifndef __DGL_WIDGET_HPP__ | |||||
| #define __DGL_WIDGET_HPP__ | |||||
| #include "Base.hpp" | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ------------------------------------------------- | |||||
| class Window; | |||||
| class Widget | |||||
| { | |||||
| public: | |||||
| Widget(Window* parent = nullptr); | |||||
| virtual ~Widget(); | |||||
| protected: | |||||
| void onDisplay(); | |||||
| void onKeyboard(bool press, uint32_t key); | |||||
| void onMouse(int button, bool press, int x, int y); | |||||
| void onMotion(int x, int y); | |||||
| void onScroll(float dx, float dy); | |||||
| void onSpecial(bool press, Key key); | |||||
| void onReshape(int width, int height); | |||||
| void onClose(); | |||||
| private: | |||||
| class Private; | |||||
| Private* const kPrivate; | |||||
| friend class Window; | |||||
| }; | |||||
| // ------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| #endif // __DGL_WIDGET_HPP__ | |||||
| @@ -0,0 +1,65 @@ | |||||
| /* | |||||
| * 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 | |||||
| */ | |||||
| #ifndef __DGL_WINDOW_HPP__ | |||||
| #define __DGL_WINDOW_HPP__ | |||||
| #include "Base.hpp" | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ------------------------------------------------- | |||||
| class App; | |||||
| class Window | |||||
| { | |||||
| public: | |||||
| Window(App* app, Window* parent = nullptr); | |||||
| Window(App* app, intptr_t parentId); | |||||
| virtual ~Window(); | |||||
| void exec(); | |||||
| void focus(); | |||||
| void idle(); | |||||
| void repaint(); | |||||
| bool isVisible(); | |||||
| void setVisible(bool yesNo); | |||||
| void setWindowTitle(const char* title); | |||||
| intptr_t getWindowId(); | |||||
| void show() | |||||
| { | |||||
| setVisible(true); | |||||
| } | |||||
| void hide() | |||||
| { | |||||
| setVisible(false); | |||||
| } | |||||
| private: | |||||
| class Private; | |||||
| Private* const kPrivate; | |||||
| }; | |||||
| // ------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| #endif // __DGL_WINDOW_HPP__ | |||||
| @@ -0,0 +1,56 @@ | |||||
| /* | |||||
| * 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 "../Window.hpp" | |||||
| #include "../../DistrhoUtils.hpp" | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ------------------------------------------------- | |||||
| App::App() | |||||
| : kPrivate(new Private) | |||||
| { | |||||
| } | |||||
| App::~App() | |||||
| { | |||||
| delete kPrivate; | |||||
| } | |||||
| void App::idle() | |||||
| { | |||||
| for (auto it = kPrivate->fWindows.begin(); it != kPrivate->fWindows.end(); it++) | |||||
| { | |||||
| Window* window = *it; | |||||
| window->idle(); | |||||
| } | |||||
| } | |||||
| void App::exec() | |||||
| { | |||||
| while (kPrivate->fDoLoop) | |||||
| { | |||||
| idle(); | |||||
| d_msleep(10); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| @@ -0,0 +1,82 @@ | |||||
| /* | |||||
| * 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 | |||||
| */ | |||||
| #ifndef __APP_PRIVATE_HPP__ | |||||
| #define __APP_PRIVATE_HPP__ | |||||
| #include "../App.hpp" | |||||
| #include <list> | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ------------------------------------------------- | |||||
| class Window; | |||||
| class App::Private | |||||
| { | |||||
| public: | |||||
| Private() | |||||
| : fDoLoop(true), | |||||
| fVisibleWindows(0) | |||||
| { | |||||
| } | |||||
| ~Private() | |||||
| { | |||||
| fWindows.clear(); | |||||
| } | |||||
| void addWindow(Window* window) | |||||
| { | |||||
| if (window != nullptr) | |||||
| fWindows.push_back(window); | |||||
| } | |||||
| void removeWindow(Window* window) | |||||
| { | |||||
| if (window != nullptr) | |||||
| fWindows.remove(window); | |||||
| } | |||||
| void oneShown() | |||||
| { | |||||
| fVisibleWindows++; | |||||
| } | |||||
| void oneHidden() | |||||
| { | |||||
| fVisibleWindows--; | |||||
| if (fVisibleWindows == 0) | |||||
| fDoLoop = false; | |||||
| } | |||||
| private: | |||||
| bool fDoLoop; | |||||
| unsigned fVisibleWindows; | |||||
| std::list<Window*> fWindows; | |||||
| friend class App; | |||||
| }; | |||||
| // ------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| #endif // __APP_PRIVATE_HPP__ | |||||
| @@ -0,0 +1,380 @@ | |||||
| /* | |||||
| * 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 "../Geometry.hpp" | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ------------------------------------------------- | |||||
| // Point | |||||
| template<typename T> | |||||
| Point<T>::Point() | |||||
| : fX(0), | |||||
| fY(0) | |||||
| { | |||||
| } | |||||
| template<typename T> | |||||
| Point<T>::Point(T x, T y) | |||||
| : fX(x), | |||||
| fY(y) | |||||
| { | |||||
| } | |||||
| template<typename T> | |||||
| Point<T>::Point(const Point& pos) | |||||
| : fX(pos.fX), | |||||
| fY(pos.fY) | |||||
| { | |||||
| } | |||||
| template<typename T> | |||||
| T Point<T>::getX() const | |||||
| { | |||||
| return fX; | |||||
| } | |||||
| template<typename T> | |||||
| T Point<T>::getY() const | |||||
| { | |||||
| return fY; | |||||
| } | |||||
| template<typename T> | |||||
| void Point<T>::setX(T x) | |||||
| { | |||||
| fX = x; | |||||
| } | |||||
| template<typename T> | |||||
| void Point<T>::setY(T y) | |||||
| { | |||||
| fY = y; | |||||
| } | |||||
| template<typename T> | |||||
| void Point<T>::move(T x, T y) | |||||
| { | |||||
| fX += x; | |||||
| fY += y; | |||||
| } | |||||
| template<typename T> | |||||
| void Point<T>::move(const Point& pos) | |||||
| { | |||||
| fX += pos.fX; | |||||
| fY += pos.fY; | |||||
| } | |||||
| template<typename T> | |||||
| Point<T>& Point<T>::operator=(const Point<T>& pos) | |||||
| { | |||||
| fX = pos.fX; | |||||
| fY = pos.fY; | |||||
| return *this; | |||||
| } | |||||
| template<typename T> | |||||
| Point<T>& Point<T>::operator+=(const Point<T>& pos) | |||||
| { | |||||
| fX += pos.fX; | |||||
| fY += pos.fY; | |||||
| return *this; | |||||
| } | |||||
| template<typename T> | |||||
| Point<T>& Point<T>::operator-=(const Point<T>& pos) | |||||
| { | |||||
| fX -= pos.fX; | |||||
| fY -= pos.fY; | |||||
| return *this; | |||||
| } | |||||
| template<typename T> | |||||
| bool Point<T>::operator==(const Point<T>& pos) const | |||||
| { | |||||
| return (fX == pos.fX && fY== pos.fY); | |||||
| } | |||||
| template<typename T> | |||||
| bool Point<T>::operator!=(const Point<T>& pos) const | |||||
| { | |||||
| return !operator==(pos); | |||||
| } | |||||
| // ------------------------------------------------- | |||||
| // Size | |||||
| template<typename T> | |||||
| Size<T>::Size() | |||||
| : fWidth(0), | |||||
| fHeight(0) | |||||
| { | |||||
| } | |||||
| template<typename T> | |||||
| Size<T>::Size(T width, T height) | |||||
| : fWidth(width), | |||||
| fHeight(height) | |||||
| { | |||||
| } | |||||
| template<typename T> | |||||
| Size<T>::Size(const Size<T>& size) | |||||
| : fWidth(size.fWidth), | |||||
| fHeight(size.fHeight) | |||||
| { | |||||
| } | |||||
| template<typename T> | |||||
| T Size<T>::getWidth() const | |||||
| { | |||||
| return fWidth; | |||||
| } | |||||
| template<typename T> | |||||
| T Size<T>::getHeight() const | |||||
| { | |||||
| return fHeight; | |||||
| } | |||||
| template<typename T> | |||||
| void Size<T>::setWidth(T width) | |||||
| { | |||||
| fWidth = width; | |||||
| } | |||||
| template<typename T> | |||||
| void Size<T>::setHeight(T height) | |||||
| { | |||||
| fHeight = height; | |||||
| } | |||||
| template<typename T> | |||||
| Size<T>& Size<T>::operator=(const Size<T>& size) | |||||
| { | |||||
| fWidth = size.fWidth; | |||||
| fHeight = size.fHeight; | |||||
| return *this; | |||||
| } | |||||
| template<typename T> | |||||
| Size<T>& Size<T>::operator+=(const Size<T>& size) | |||||
| { | |||||
| fWidth += size.fWidth; | |||||
| fHeight += size.fHeight; | |||||
| return *this; | |||||
| } | |||||
| template<typename T> | |||||
| Size<T>& Size<T>::operator-=(const Size<T>& size) | |||||
| { | |||||
| fWidth -= size.fWidth; | |||||
| fHeight -= size.fHeight; | |||||
| return *this; | |||||
| } | |||||
| template<typename T> | |||||
| Size<T>& Size<T>::operator*=(T m) | |||||
| { | |||||
| fWidth *= m; | |||||
| fHeight *= m; | |||||
| return *this; | |||||
| } | |||||
| template<typename T> | |||||
| Size<T>& Size<T>::operator/=(T d) | |||||
| { | |||||
| fWidth /= d; | |||||
| fHeight /= d; | |||||
| return *this; | |||||
| } | |||||
| template<typename T> | |||||
| bool Size<T>::operator==(const Size<T>& size) const | |||||
| { | |||||
| return (fWidth == size.fWidth && fHeight == size.fHeight); | |||||
| } | |||||
| template<typename T> | |||||
| bool Size<T>::operator!=(const Size<T>& size) const | |||||
| { | |||||
| return !operator==(size); | |||||
| } | |||||
| // ------------------------------------------------- | |||||
| // Rectangle | |||||
| template<typename T> | |||||
| Rectangle<T>::Rectangle() | |||||
| : fPos(0, 0), | |||||
| fSize(0, 0) | |||||
| { | |||||
| } | |||||
| template<typename T> | |||||
| Rectangle<T>::Rectangle(T x, T y, T width, T height) | |||||
| : fPos(x, y), | |||||
| fSize(width, height) | |||||
| { | |||||
| } | |||||
| template<typename T> | |||||
| Rectangle<T>::Rectangle(T x, T y, const Size<T>& size) | |||||
| : fPos(x, y), | |||||
| fSize(size) | |||||
| { | |||||
| } | |||||
| template<typename T> | |||||
| Rectangle<T>::Rectangle(const Point<T>& pos, T width, T height) | |||||
| : fPos(pos), | |||||
| fSize(width, height) | |||||
| { | |||||
| } | |||||
| template<typename T> | |||||
| Rectangle<T>::Rectangle(const Point<T>& pos, const Size<T>& size) | |||||
| : fPos(pos), | |||||
| fSize(size) | |||||
| { | |||||
| } | |||||
| template<typename T> | |||||
| Rectangle<T>::Rectangle(const Rectangle<T>& rect) | |||||
| : fPos(rect._pos), | |||||
| fSize(rect._size) | |||||
| { | |||||
| } | |||||
| template<typename T> | |||||
| T Rectangle<T>::getX() const | |||||
| { | |||||
| return fPos.fX; | |||||
| } | |||||
| template<typename T> | |||||
| T Rectangle<T>::getY() const | |||||
| { | |||||
| return fPos.fY; | |||||
| } | |||||
| template<typename T> | |||||
| T Rectangle<T>::getWidth() const | |||||
| { | |||||
| return fSize.fWidth; | |||||
| } | |||||
| template<typename T> | |||||
| T Rectangle<T>::getHeight() const | |||||
| { | |||||
| return fSize.fHeight; | |||||
| } | |||||
| template<typename T> | |||||
| const Point<T>& Rectangle<T>::getPos() const | |||||
| { | |||||
| return fPos; | |||||
| } | |||||
| template<typename T> | |||||
| const Size<T>& Rectangle<T>::getSize() const | |||||
| { | |||||
| return fSize; | |||||
| } | |||||
| template<typename T> | |||||
| bool Rectangle<T>::contains(T x, T y) const | |||||
| { | |||||
| return (x >= fPos.fX && y >= fPos.fY && x <= fPos.fX+fSize.fWidth && y <= fPos.fY+fSize.fHeight); | |||||
| } | |||||
| template<typename T> | |||||
| bool Rectangle<T>::contains(const Point<T>& pos) const | |||||
| { | |||||
| return contains(pos.fX, pos.fY); | |||||
| } | |||||
| #if 0 | |||||
| template<typename T> | |||||
| void Rectangle::setX(int x) | |||||
| { | |||||
| _pos._x = x; | |||||
| } | |||||
| template<typename T> | |||||
| void Rectangle::setY(int y) | |||||
| { | |||||
| _pos._y = y; | |||||
| } | |||||
| void Rectangle::setPos(int x, int y) | |||||
| { | |||||
| _pos._x = x; | |||||
| _pos._y = y; | |||||
| } | |||||
| void Rectangle::setPos(const Point& pos) | |||||
| { | |||||
| _pos = pos; | |||||
| } | |||||
| void Rectangle::move(int x, int y) | |||||
| { | |||||
| _pos._x += x; | |||||
| _pos._y += y; | |||||
| } | |||||
| void Rectangle::move(const Point& pos) | |||||
| { | |||||
| _pos += pos; | |||||
| } | |||||
| void Rectangle::setWidth(int width) | |||||
| { | |||||
| _size._width = width; | |||||
| } | |||||
| void Rectangle::setHeight(int height) | |||||
| { | |||||
| _size._height = height; | |||||
| } | |||||
| void Rectangle::setSize(int width, int height) | |||||
| { | |||||
| _size._width = width; | |||||
| _size._height = height; | |||||
| } | |||||
| void Rectangle::setSize(const Size& size) | |||||
| { | |||||
| _size = size; | |||||
| } | |||||
| Rectangle& Rectangle::operator=(const Rectangle& rect) | |||||
| { | |||||
| _pos = rect._pos; | |||||
| _size = rect._size; | |||||
| return *this; | |||||
| } | |||||
| #endif | |||||
| // ------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| @@ -0,0 +1,115 @@ | |||||
| /* | |||||
| * 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 "../App.hpp" | |||||
| #include "../Widget.hpp" | |||||
| #include "../Window.hpp" | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ------------------------------------------------- | |||||
| // Window Private | |||||
| class Widget::Private | |||||
| { | |||||
| public: | |||||
| Private(Window* parent) | |||||
| : fApp(nullptr), | |||||
| fWindow(nullptr) | |||||
| { | |||||
| if (parent == nullptr) | |||||
| { | |||||
| fApp = new App; | |||||
| fWindow = new Window(fApp); | |||||
| } | |||||
| } | |||||
| ~Private() | |||||
| { | |||||
| if (fWindow != nullptr) | |||||
| delete fWindow; | |||||
| if (fApp != nullptr) | |||||
| delete fApp; | |||||
| } | |||||
| private: | |||||
| App* fApp; | |||||
| Window* fWindow; | |||||
| }; | |||||
| // ------------------------------------------------- | |||||
| // Widget | |||||
| Widget::Widget(Window* parent) | |||||
| : kPrivate(new Private(parent)) | |||||
| { | |||||
| } | |||||
| Widget::~Widget() | |||||
| { | |||||
| } | |||||
| void Widget::onDisplay() | |||||
| { | |||||
| //if (fParent == nullptr) | |||||
| // glColor3f(0.0f, 1.0f, 0.0f); | |||||
| //else | |||||
| glColor3f(0.0f, 0.0f, 1.0f); | |||||
| glRectf(-0.75f, 0.75f, 0.75f, -0.75f); | |||||
| } | |||||
| void Widget::onKeyboard(bool, uint32_t) | |||||
| { | |||||
| } | |||||
| void Widget::onMouse(int, bool, int, int) | |||||
| { | |||||
| } | |||||
| void Widget::onMotion(int, int) | |||||
| { | |||||
| } | |||||
| void Widget::onScroll(float, float) | |||||
| { | |||||
| } | |||||
| void Widget::onSpecial(bool, Key) | |||||
| { | |||||
| } | |||||
| void Widget::onReshape(int width, int height) | |||||
| { | |||||
| glEnable(GL_BLEND); | |||||
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
| glMatrixMode(GL_PROJECTION); | |||||
| glLoadIdentity(); | |||||
| glOrtho(0, width, height, 0, 0, 1); | |||||
| glViewport(0, 0, width, height); | |||||
| glMatrixMode(GL_MODELVIEW); | |||||
| glLoadIdentity(); | |||||
| } | |||||
| void Widget::onClose() | |||||
| { | |||||
| } | |||||
| // ------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| @@ -0,0 +1,497 @@ | |||||
| /* | |||||
| * 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 "../../DistrhoUtils.hpp" | |||||
| #if DISTRHO_OS_WINDOWS | |||||
| # include "pugl/pugl_win.cpp" | |||||
| #elif DISTRHO_OS_MAC | |||||
| # include "pugl/pugl_osx.m" | |||||
| #elif DISTRHO_OS_LINUX | |||||
| # include "pugl/pugl_x11.c" | |||||
| #else | |||||
| # error Unsupported platform! | |||||
| #endif | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ------------------------------------------------- | |||||
| // Utils | |||||
| #if DISTRHO_OS_LINUX | |||||
| static Bool isMapNotify(Display*, XEvent* ev, XPointer win) | |||||
| { | |||||
| return (ev->type == MapNotify && ev->xmap.window == *((::Window*)win)); | |||||
| } | |||||
| static Bool isUnmapNotify(Display*, XEvent* ev, XPointer win) | |||||
| { | |||||
| return (ev->type == UnmapNotify && ev->xunmap.window == *((::Window*)win)); | |||||
| } | |||||
| #endif | |||||
| #define FOR_EACH_WIDGET(it) \ | |||||
| for (auto it = fWidgets.begin(); it != fWidgets.end(); it++) | |||||
| // ------------------------------------------------- | |||||
| // Window Private | |||||
| class Window::Private | |||||
| { | |||||
| public: | |||||
| Private(Window* self, App::Private* app, Private* parent, intptr_t parentId = 0) | |||||
| : kApp(app), | |||||
| kSelf(self), | |||||
| kView(puglCreate(parentId, "test", 300, 100, false, false)), | |||||
| fParent(parent), | |||||
| fChildFocus(nullptr), | |||||
| fVisible(false), | |||||
| fClosed(false), | |||||
| #if DISTRHO_OS_WINDOWS | |||||
| hwnd(0) | |||||
| #elif DISTRHO_OS_LINUX | |||||
| xDisplay(nullptr), | |||||
| xWindow(0) | |||||
| #else | |||||
| _dummy(0) | |||||
| #endif | |||||
| { | |||||
| if (kView == nullptr) | |||||
| return; | |||||
| 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); | |||||
| PuglInternals* impl = kView->impl; | |||||
| #if DISTRHO_OS_WINDOWS | |||||
| //hwnd = impl->hwnd; | |||||
| if (parent != nullptr) | |||||
| { | |||||
| //PuglInternals* parentImpl = parent->kView->impl; | |||||
| //SetParent(parentImpl->hwnd, hwnd); | |||||
| } | |||||
| #elif DISTRHO_OS_LINUX | |||||
| xDisplay = impl->display; | |||||
| xWindow = impl->win; | |||||
| if (parent != nullptr) | |||||
| { | |||||
| PuglInternals* parentImpl = parent->kView->impl; | |||||
| bool parentWasVisible = parent->isVisible(); | |||||
| if (parentWasVisible) | |||||
| { | |||||
| XEvent event; | |||||
| XUnmapWindow(xDisplay, xWindow); | |||||
| XIfEvent(xDisplay, &event, &isUnmapNotify, (XPointer)&xWindow); | |||||
| } | |||||
| XSetTransientForHint(xDisplay, xWindow, parentImpl->win); | |||||
| if (parentWasVisible) | |||||
| { | |||||
| XEvent event; | |||||
| XMapWindow(xDisplay, xWindow); | |||||
| XIfEvent(xDisplay, &event, &isMapNotify, (XPointer)&xWindow); | |||||
| } | |||||
| XFlush(xDisplay); | |||||
| } | |||||
| #endif | |||||
| kApp->addWindow(kSelf); | |||||
| } | |||||
| ~Private() | |||||
| { | |||||
| fWidgets.clear(); | |||||
| if (kView != nullptr) | |||||
| { | |||||
| kApp->removeWindow(kSelf); | |||||
| puglDestroy(kView); | |||||
| } | |||||
| } | |||||
| void exec() | |||||
| { | |||||
| fClosed = false; | |||||
| show(); | |||||
| if (fParent != nullptr) | |||||
| { | |||||
| #if DISTRHO_OS_WINDOWS | |||||
| EnableWindow(fParent->hwnd, FALSE); | |||||
| #endif | |||||
| fParent->fChildFocus = this; | |||||
| fParent->show(); | |||||
| } | |||||
| focus(); | |||||
| while (! fClosed) | |||||
| { | |||||
| idle(); | |||||
| if (fParent != nullptr) | |||||
| fParent->idle(); | |||||
| d_msleep(10); | |||||
| } | |||||
| if (fParent != nullptr) | |||||
| { | |||||
| fParent->fChildFocus = nullptr; | |||||
| #if DISTRHO_OS_WINDOWS | |||||
| EnableWindow(fParent->hwnd, TRUE); | |||||
| #endif | |||||
| } | |||||
| } | |||||
| void focus() | |||||
| { | |||||
| #if DISTRHO_OS_WINDOWS | |||||
| SetForegroundWindow(hwnd); | |||||
| SetActiveWindow(hwnd); | |||||
| SetFocus(hwnd); | |||||
| #elif DISTRHO_OS_LINUX | |||||
| XRaiseWindow(xDisplay, xWindow); | |||||
| XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime); | |||||
| XFlush(xDisplay); | |||||
| #endif | |||||
| } | |||||
| void idle() | |||||
| { | |||||
| puglProcessEvents(kView); | |||||
| } | |||||
| void repaint() | |||||
| { | |||||
| puglPostRedisplay(kView); | |||||
| } | |||||
| void show() | |||||
| { | |||||
| setVisible(true); | |||||
| } | |||||
| void hide() | |||||
| { | |||||
| setVisible(false); | |||||
| } | |||||
| bool isVisible() | |||||
| { | |||||
| return fVisible; | |||||
| } | |||||
| void setVisible(bool yesNo) | |||||
| { | |||||
| if (fVisible == yesNo) | |||||
| return; | |||||
| fVisible = yesNo; | |||||
| #if DISTRHO_OS_WINDOWS | |||||
| if (yesNo) | |||||
| { | |||||
| ShowWindow(hwnd, WS_VISIBLE); | |||||
| ShowWindow(hwnd, SW_RESTORE); | |||||
| //SetForegroundWindow(hwnd); | |||||
| } | |||||
| else | |||||
| { | |||||
| ShowWindow(hwnd, SW_HIDE); | |||||
| } | |||||
| UpdateWindow(hwnd); | |||||
| #elif DISTRHO_OS_LINUX | |||||
| XEvent event; | |||||
| if (yesNo) | |||||
| { | |||||
| XMapRaised(xDisplay, xWindow); | |||||
| XIfEvent(xDisplay, &event, &isMapNotify, (XPointer)&xWindow); | |||||
| } | |||||
| else | |||||
| { | |||||
| XUnmapWindow(xDisplay, xWindow); | |||||
| XIfEvent(xDisplay, &event, &isUnmapNotify, (XPointer)&xWindow); | |||||
| } | |||||
| XFlush(xDisplay); | |||||
| #endif | |||||
| if (yesNo) | |||||
| kApp->oneShown(); | |||||
| else | |||||
| kApp->oneHidden(); | |||||
| } | |||||
| void setWindowTitle(const char* title) | |||||
| { | |||||
| #if DISTRHO_OS_WINDOWS | |||||
| SetWindowTextA(hwnd, title); | |||||
| #elif DISTRHO_OS_LINUX | |||||
| XStoreName(xDisplay, xWindow, title); | |||||
| XFlush(xDisplay); | |||||
| #endif | |||||
| } | |||||
| intptr_t getWindowId() | |||||
| { | |||||
| return puglGetNativeWindow(kView); | |||||
| } | |||||
| protected: | |||||
| void onDisplay() | |||||
| { | |||||
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |||||
| FOR_EACH_WIDGET(it) | |||||
| { | |||||
| Widget* widget = *it; | |||||
| widget->onDisplay(); | |||||
| } | |||||
| } | |||||
| void onKeyboard(bool press, uint32_t key) | |||||
| { | |||||
| if (fChildFocus != nullptr) | |||||
| return fChildFocus->focus(); | |||||
| FOR_EACH_WIDGET(it) | |||||
| { | |||||
| Widget* widget = *it; | |||||
| widget->onKeyboard(press, key); | |||||
| } | |||||
| } | |||||
| void onMouse(int button, bool press, int x, int y) | |||||
| { | |||||
| if (fChildFocus != nullptr) | |||||
| return fChildFocus->focus(); | |||||
| FOR_EACH_WIDGET(it) | |||||
| { | |||||
| Widget* widget = *it; | |||||
| widget->onMouse(button, press, x, y); | |||||
| } | |||||
| } | |||||
| void onMotion(int x, int y) | |||||
| { | |||||
| if (fChildFocus != nullptr) | |||||
| return; | |||||
| FOR_EACH_WIDGET(it) | |||||
| { | |||||
| Widget* widget = *it; | |||||
| widget->onMotion(x, y); | |||||
| } | |||||
| } | |||||
| void onScroll(float dx, float dy) | |||||
| { | |||||
| if (fChildFocus != nullptr) | |||||
| return; | |||||
| FOR_EACH_WIDGET(it) | |||||
| { | |||||
| Widget* widget = *it; | |||||
| widget->onScroll(dx, dy); | |||||
| } | |||||
| } | |||||
| void onSpecial(bool press, Key key) | |||||
| { | |||||
| if (fChildFocus != nullptr) | |||||
| return; | |||||
| FOR_EACH_WIDGET(it) | |||||
| { | |||||
| Widget* widget = *it; | |||||
| widget->onSpecial(press, key); | |||||
| } | |||||
| } | |||||
| void onReshape(int width, int height) | |||||
| { | |||||
| FOR_EACH_WIDGET(it) | |||||
| { | |||||
| Widget* widget = *it; | |||||
| widget->onReshape(width, height); | |||||
| } | |||||
| } | |||||
| void onClose() | |||||
| { | |||||
| fClosed = true; | |||||
| if (fChildFocus != nullptr) | |||||
| fChildFocus->onClose(); | |||||
| FOR_EACH_WIDGET(it) | |||||
| { | |||||
| Widget* widget = *it; | |||||
| widget->onClose(); | |||||
| } | |||||
| hide(); | |||||
| } | |||||
| private: | |||||
| App::Private* const kApp; | |||||
| Window* const kSelf; | |||||
| PuglView* const kView; | |||||
| Private* fParent; | |||||
| Private* fChildFocus; | |||||
| bool fVisible; | |||||
| bool fClosed; | |||||
| std::list<Widget*> fWidgets; | |||||
| #if DISTRHO_OS_WINDOWS | |||||
| HWND hwnd; | |||||
| #elif DISTRHO_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->kPrivate, (parent != nullptr) ? parent->kPrivate : nullptr)) | |||||
| { | |||||
| } | |||||
| Window::Window(App* app, intptr_t parentId) | |||||
| : kPrivate(new Private(this, app->kPrivate, nullptr, parentId)) | |||||
| { | |||||
| } | |||||
| Window::~Window() | |||||
| { | |||||
| delete kPrivate; | |||||
| } | |||||
| void Window::exec() | |||||
| { | |||||
| kPrivate->exec(); | |||||
| } | |||||
| void Window::focus() | |||||
| { | |||||
| kPrivate->focus(); | |||||
| } | |||||
| void Window::idle() | |||||
| { | |||||
| kPrivate->idle(); | |||||
| } | |||||
| void Window::repaint() | |||||
| { | |||||
| kPrivate->repaint(); | |||||
| } | |||||
| bool Window::isVisible() | |||||
| { | |||||
| return kPrivate->isVisible(); | |||||
| } | |||||
| void Window::setVisible(bool yesNo) | |||||
| { | |||||
| kPrivate->setVisible(yesNo); | |||||
| } | |||||
| void Window::setWindowTitle(const char* title) | |||||
| { | |||||
| kPrivate->setWindowTitle(title); | |||||
| } | |||||
| intptr_t Window::getWindowId() | |||||
| { | |||||
| return kPrivate->getWindowId(); | |||||
| } | |||||
| // ------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| @@ -0,0 +1,341 @@ | |||||
| /* | |||||
| Copyright 2012 David Robillard <http://drobilla.net> | |||||
| Permission to use, copy, modify, and/or distribute this software for any | |||||
| purpose with or without fee is hereby granted, provided that the above | |||||
| copyright notice and this permission notice appear in all copies. | |||||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
| */ | |||||
| /** | |||||
| @file pugl.h API for Pugl, a minimal portable API for OpenGL. | |||||
| */ | |||||
| #ifndef PUGL_H_INCLUDED | |||||
| #define PUGL_H_INCLUDED | |||||
| #include <stdint.h> | |||||
| /* | |||||
| This API is pure portable C and contains no platform specific elements, or | |||||
| even a GL dependency. However, unfortunately GL includes vary across | |||||
| platforms so they are included here to allow for pure portable programs. | |||||
| */ | |||||
| #ifdef __APPLE__ | |||||
| # include "OpenGL/gl.h" | |||||
| #else | |||||
| # ifdef _WIN32 | |||||
| # include <windows.h> /* Broken Windows GL headers require this */ | |||||
| # endif | |||||
| # include "GL/gl.h" | |||||
| #endif | |||||
| #ifdef PUGL_SHARED | |||||
| # ifdef _WIN32 | |||||
| # define PUGL_LIB_IMPORT __declspec(dllimport) | |||||
| # define PUGL_LIB_EXPORT __declspec(dllexport) | |||||
| # else | |||||
| # define PUGL_LIB_IMPORT __attribute__((visibility("default"))) | |||||
| # define PUGL_LIB_EXPORT __attribute__((visibility("default"))) | |||||
| # endif | |||||
| # ifdef PUGL_INTERNAL | |||||
| # define PUGL_API PUGL_LIB_EXPORT | |||||
| # else | |||||
| # define PUGL_API PUGL_LIB_IMPORT | |||||
| # endif | |||||
| #else | |||||
| # define PUGL_API | |||||
| #endif | |||||
| #ifndef __cplusplus | |||||
| # include <stdbool.h> | |||||
| #endif | |||||
| /** | |||||
| @defgroup pugl Pugl | |||||
| A minimal portable API for OpenGL. | |||||
| @{ | |||||
| */ | |||||
| /** | |||||
| An OpenGL view. | |||||
| */ | |||||
| typedef struct PuglViewImpl PuglView; | |||||
| /** | |||||
| A native window handle. | |||||
| On X11, this is a Window. | |||||
| On OSX, this is an NSView*. | |||||
| On Windows, this is a HWND. | |||||
| */ | |||||
| typedef intptr_t PuglNativeWindow; | |||||
| /** | |||||
| Return status code. | |||||
| */ | |||||
| typedef enum { | |||||
| PUGL_SUCCESS = 0 | |||||
| } PuglStatus; | |||||
| /** | |||||
| Convenience symbols for ASCII control characters. | |||||
| */ | |||||
| typedef enum { | |||||
| PUGL_CHAR_BACKSPACE = 0x08, | |||||
| PUGL_CHAR_ESCAPE = 0x1B, | |||||
| PUGL_CHAR_DELETE = 0x7F | |||||
| } PuglChar; | |||||
| /** | |||||
| Special (non-Unicode) keyboard keys. | |||||
| */ | |||||
| typedef enum { | |||||
| PUGL_KEY_F1 = 1, | |||||
| PUGL_KEY_F2, | |||||
| PUGL_KEY_F3, | |||||
| PUGL_KEY_F4, | |||||
| PUGL_KEY_F5, | |||||
| PUGL_KEY_F6, | |||||
| PUGL_KEY_F7, | |||||
| PUGL_KEY_F8, | |||||
| PUGL_KEY_F9, | |||||
| PUGL_KEY_F10, | |||||
| PUGL_KEY_F11, | |||||
| PUGL_KEY_F12, | |||||
| PUGL_KEY_LEFT, | |||||
| PUGL_KEY_UP, | |||||
| PUGL_KEY_RIGHT, | |||||
| PUGL_KEY_DOWN, | |||||
| PUGL_KEY_PAGE_UP, | |||||
| PUGL_KEY_PAGE_DOWN, | |||||
| PUGL_KEY_HOME, | |||||
| PUGL_KEY_END, | |||||
| PUGL_KEY_INSERT, | |||||
| PUGL_KEY_SHIFT, | |||||
| PUGL_KEY_CTRL, | |||||
| PUGL_KEY_ALT, | |||||
| PUGL_KEY_SUPER | |||||
| } PuglKey; | |||||
| /** | |||||
| Keyboard modifier flags. | |||||
| */ | |||||
| typedef enum { | |||||
| PUGL_MOD_SHIFT = 1, /**< Shift key */ | |||||
| PUGL_MOD_CTRL = 1 << 1, /**< Control key */ | |||||
| PUGL_MOD_ALT = 1 << 2, /**< Alt/Option key */ | |||||
| PUGL_MOD_SUPER = 1 << 3 /**< Mod4/Command/Windows key */ | |||||
| } PuglMod; | |||||
| /** | |||||
| Handle for opaque user data. | |||||
| */ | |||||
| typedef void* PuglHandle; | |||||
| /** | |||||
| A function called when the window is closed. | |||||
| */ | |||||
| typedef void (*PuglCloseFunc)(PuglView* view); | |||||
| /** | |||||
| A function called to draw the view contents with OpenGL. | |||||
| */ | |||||
| typedef void (*PuglDisplayFunc)(PuglView* view); | |||||
| /** | |||||
| A function called when a key is pressed or released. | |||||
| @param view The view the event occured in. | |||||
| @param press True if the key was pressed, false if released. | |||||
| @param key Unicode point of the key pressed. | |||||
| */ | |||||
| typedef void (*PuglKeyboardFunc)(PuglView* view, bool press, uint32_t key); | |||||
| /** | |||||
| A function called when the pointer moves. | |||||
| @param view The view the event occured in. | |||||
| @param x The window-relative x coordinate of the pointer. | |||||
| @param y The window-relative y coordinate of the pointer. | |||||
| */ | |||||
| typedef void (*PuglMotionFunc)(PuglView* view, int x, int y); | |||||
| /** | |||||
| A function called when a mouse button is pressed or released. | |||||
| @param view The view the event occured in. | |||||
| @param button The button number (1 = left, 2 = middle, 3 = right). | |||||
| @param press True if the key was pressed, false if released. | |||||
| @param x The window-relative x coordinate of the pointer. | |||||
| @param y The window-relative y coordinate of the pointer. | |||||
| */ | |||||
| typedef void (*PuglMouseFunc)( | |||||
| PuglView* view, int button, bool press, int x, int y); | |||||
| /** | |||||
| A function called when the view is resized. | |||||
| @param view The view being resized. | |||||
| @param width The new view width. | |||||
| @param height The new view height. | |||||
| */ | |||||
| typedef void (*PuglReshapeFunc)(PuglView* view, int width, int height); | |||||
| /** | |||||
| A function called on scrolling (e.g. mouse wheel or track pad). | |||||
| The distances used here are in "lines", a single tick of a clicking mouse | |||||
| wheel. For example, @p dy = 1.0 scrolls 1 line up. Some systems and | |||||
| devices support finer resolution and/or higher values for fast scrolls, | |||||
| so programs should handle any value gracefully. | |||||
| @param view The view being scrolled. | |||||
| @param dx The scroll x distance. | |||||
| @param dx The scroll y distance. | |||||
| */ | |||||
| typedef void (*PuglScrollFunc)(PuglView* view, float dx, float dy); | |||||
| /** | |||||
| A function called when a special key is pressed or released. | |||||
| This callback allows the use of keys that do not have unicode points. Note | |||||
| that some non-printable keys | |||||
| @param view The view the event occured in. | |||||
| @param press True if the key was pressed, false if released. | |||||
| @param key The key pressed. | |||||
| */ | |||||
| typedef void (*PuglSpecialFunc)(PuglView* view, bool press, PuglKey key); | |||||
| /** | |||||
| Create a new GL window. | |||||
| @param parent Parent window, or 0 for top level. | |||||
| @param title Window title, or NULL. | |||||
| @param width Window width in pixels. | |||||
| @param height Window height in pixels. | |||||
| @param resizable Whether window should be user resizable. | |||||
| */ | |||||
| PUGL_API PuglView* | |||||
| puglCreate(PuglNativeWindow parent, | |||||
| const char* title, | |||||
| int width, | |||||
| int height, | |||||
| bool resizable, | |||||
| bool addToDesktop = true, | |||||
| const char* x11Display = nullptr); | |||||
| /** | |||||
| Set the handle to be passed to all callbacks. | |||||
| This is generally a pointer to a struct which contains all necessary state. | |||||
| Everything needed in callbacks should be here, not in static variables. | |||||
| Note the lack of this facility makes GLUT unsuitable for plugins or | |||||
| non-trivial programs; this mistake is largely why Pugl exists. | |||||
| */ | |||||
| PUGL_API void | |||||
| puglSetHandle(PuglView* view, PuglHandle handle); | |||||
| /** | |||||
| Get the handle to be passed to all callbacks. | |||||
| */ | |||||
| PUGL_API PuglHandle | |||||
| puglGetHandle(PuglView* view); | |||||
| /** | |||||
| Get the currently active modifiers (PuglMod flags). | |||||
| This should only be called from an event handler. | |||||
| */ | |||||
| PUGL_API int | |||||
| puglGetModifiers(PuglView* view); | |||||
| /** | |||||
| Ignore synthetic repeated key events. | |||||
| */ | |||||
| PUGL_API void | |||||
| puglIgnoreKeyRepeat(PuglView* view, bool ignore); | |||||
| /** | |||||
| Set the function to call when the window is closed. | |||||
| */ | |||||
| PUGL_API void | |||||
| puglSetCloseFunc(PuglView* view, PuglCloseFunc closeFunc); | |||||
| /** | |||||
| Set the display function which should draw the UI using GL. | |||||
| */ | |||||
| PUGL_API void | |||||
| puglSetDisplayFunc(PuglView* view, PuglDisplayFunc displayFunc); | |||||
| /** | |||||
| Set the function to call on keyboard events. | |||||
| */ | |||||
| PUGL_API void | |||||
| puglSetKeyboardFunc(PuglView* view, PuglKeyboardFunc keyboardFunc); | |||||
| /** | |||||
| Set the function to call on mouse motion. | |||||
| */ | |||||
| PUGL_API void | |||||
| puglSetMotionFunc(PuglView* view, PuglMotionFunc motionFunc); | |||||
| /** | |||||
| Set the function to call on mouse button events. | |||||
| */ | |||||
| PUGL_API void | |||||
| puglSetMouseFunc(PuglView* view, PuglMouseFunc mouseFunc); | |||||
| /** | |||||
| Set the function to call on scroll events. | |||||
| */ | |||||
| PUGL_API void | |||||
| puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc); | |||||
| /** | |||||
| Set the function to call on special events. | |||||
| */ | |||||
| PUGL_API void | |||||
| puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc); | |||||
| /** | |||||
| Set the function to call when the window size changes. | |||||
| */ | |||||
| PUGL_API void | |||||
| puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc); | |||||
| /** | |||||
| Return the native window handle. | |||||
| */ | |||||
| PUGL_API PuglNativeWindow | |||||
| puglGetNativeWindow(PuglView* view); | |||||
| /** | |||||
| Process all pending window events. | |||||
| This handles input events as well as rendering, so it should be called | |||||
| regularly and rapidly enough to keep the UI responsive. | |||||
| */ | |||||
| PUGL_API PuglStatus | |||||
| puglProcessEvents(PuglView* view); | |||||
| /** | |||||
| Request a redisplay on the next call to puglProcessEvents(). | |||||
| */ | |||||
| PUGL_API void | |||||
| puglPostRedisplay(PuglView* view); | |||||
| /** | |||||
| Destroy a GL window. | |||||
| */ | |||||
| PUGL_API void | |||||
| puglDestroy(PuglView* view); | |||||
| /** | |||||
| @} | |||||
| */ | |||||
| #endif /* PUGL_H_INCLUDED */ | |||||
| @@ -0,0 +1,135 @@ | |||||
| /* | |||||
| Copyright 2012 David Robillard <http://drobilla.net> | |||||
| Permission to use, copy, modify, and/or distribute this software for any | |||||
| purpose with or without fee is hereby granted, provided that the above | |||||
| copyright notice and this permission notice appear in all copies. | |||||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
| */ | |||||
| /** | |||||
| @file pugl_internal.h Private platform-independent definitions. | |||||
| Note this file contains function definitions, so it must be compiled into | |||||
| the final binary exactly once. Each platform specific implementation file | |||||
| including it once should achieve this. | |||||
| */ | |||||
| #include "pugl.h" | |||||
| typedef struct PuglInternalsImpl PuglInternals; | |||||
| struct PuglViewImpl { | |||||
| PuglHandle handle; | |||||
| PuglCloseFunc closeFunc; | |||||
| PuglDisplayFunc displayFunc; | |||||
| PuglKeyboardFunc keyboardFunc; | |||||
| PuglMotionFunc motionFunc; | |||||
| PuglMouseFunc mouseFunc; | |||||
| PuglReshapeFunc reshapeFunc; | |||||
| PuglScrollFunc scrollFunc; | |||||
| PuglSpecialFunc specialFunc; | |||||
| PuglInternals* impl; | |||||
| int width; | |||||
| int height; | |||||
| int mods; | |||||
| bool ignoreKeyRepeat; | |||||
| bool redisplay; | |||||
| }; | |||||
| void | |||||
| puglSetHandle(PuglView* view, PuglHandle handle) | |||||
| { | |||||
| view->handle = handle; | |||||
| } | |||||
| PuglHandle | |||||
| puglGetHandle(PuglView* view) | |||||
| { | |||||
| return view->handle; | |||||
| } | |||||
| int | |||||
| puglGetModifiers(PuglView* view) | |||||
| { | |||||
| return view->mods; | |||||
| } | |||||
| static inline void | |||||
| puglDefaultReshape(PuglView* view, int width, int height) | |||||
| { | |||||
| glMatrixMode(GL_PROJECTION); | |||||
| glLoadIdentity(); | |||||
| glOrtho(0, width, height, 0, 0, 1); | |||||
| glViewport(0, 0, width, height); | |||||
| glMatrixMode(GL_MODELVIEW); | |||||
| glLoadIdentity(); | |||||
| return; | |||||
| // unused | |||||
| (void)view; | |||||
| } | |||||
| void | |||||
| puglIgnoreKeyRepeat(PuglView* view, bool ignore) | |||||
| { | |||||
| view->ignoreKeyRepeat = ignore; | |||||
| } | |||||
| void | |||||
| puglSetCloseFunc(PuglView* view, PuglCloseFunc closeFunc) | |||||
| { | |||||
| view->closeFunc = closeFunc; | |||||
| } | |||||
| void | |||||
| puglSetDisplayFunc(PuglView* view, PuglDisplayFunc displayFunc) | |||||
| { | |||||
| view->displayFunc = displayFunc; | |||||
| } | |||||
| void | |||||
| puglSetKeyboardFunc(PuglView* view, PuglKeyboardFunc keyboardFunc) | |||||
| { | |||||
| view->keyboardFunc = keyboardFunc; | |||||
| } | |||||
| void | |||||
| puglSetMotionFunc(PuglView* view, PuglMotionFunc motionFunc) | |||||
| { | |||||
| view->motionFunc = motionFunc; | |||||
| } | |||||
| void | |||||
| puglSetMouseFunc(PuglView* view, PuglMouseFunc mouseFunc) | |||||
| { | |||||
| view->mouseFunc = mouseFunc; | |||||
| } | |||||
| void | |||||
| puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc) | |||||
| { | |||||
| view->reshapeFunc = reshapeFunc; | |||||
| } | |||||
| void | |||||
| puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc) | |||||
| { | |||||
| view->scrollFunc = scrollFunc; | |||||
| } | |||||
| void | |||||
| puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc) | |||||
| { | |||||
| view->specialFunc = specialFunc; | |||||
| } | |||||
| @@ -0,0 +1,331 @@ | |||||
| /* | |||||
| Copyright 2012 David Robillard <http://drobilla.net> | |||||
| Permission to use, copy, modify, and/or distribute this software for any | |||||
| purpose with or without fee is hereby granted, provided that the above | |||||
| copyright notice and this permission notice appear in all copies. | |||||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
| */ | |||||
| /** | |||||
| @file pugl_osx.m OSX/Cocoa Pugl Implementation. | |||||
| */ | |||||
| #include <stdlib.h> | |||||
| #import <Cocoa/Cocoa.h> | |||||
| #include "pugl_internal.h" | |||||
| @interface PuglOpenGLView : NSOpenGLView | |||||
| { | |||||
| int colorBits; | |||||
| int depthBits; | |||||
| @public | |||||
| PuglView* view; | |||||
| } | |||||
| - (id) initWithFrame:(NSRect)frame | |||||
| colorBits:(int)numColorBits | |||||
| depthBits:(int)numDepthBits; | |||||
| - (void) reshape; | |||||
| - (void) drawRect:(NSRect)rect; | |||||
| - (void) mouseMoved:(NSEvent*)event; | |||||
| - (void) mouseDown:(NSEvent*)event; | |||||
| - (void) mouseUp:(NSEvent*)event; | |||||
| - (void) rightMouseDown:(NSEvent*)event; | |||||
| - (void) rightMouseUp:(NSEvent*)event; | |||||
| - (void) keyDown:(NSEvent*)event; | |||||
| - (void) keyUp:(NSEvent*)event; | |||||
| - (void) flagsChanged:(NSEvent*)event; | |||||
| @end | |||||
| @implementation PuglOpenGLView | |||||
| - (id) initWithFrame:(NSRect)frame | |||||
| colorBits:(int)numColorBits | |||||
| depthBits:(int)numDepthBits | |||||
| { | |||||
| colorBits = numColorBits; | |||||
| depthBits = numDepthBits; | |||||
| NSOpenGLPixelFormatAttribute pixelAttribs[16] = { | |||||
| NSOpenGLPFADoubleBuffer, | |||||
| NSOpenGLPFAAccelerated, | |||||
| NSOpenGLPFAColorSize, | |||||
| colorBits, | |||||
| NSOpenGLPFADepthSize, | |||||
| depthBits, | |||||
| 0 | |||||
| }; | |||||
| NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] | |||||
| initWithAttributes:pixelAttribs]; | |||||
| if (pixelFormat) { | |||||
| self = [super initWithFrame:frame pixelFormat:pixelFormat]; | |||||
| [pixelFormat release]; | |||||
| if (self) { | |||||
| [[self openGLContext] makeCurrentContext]; | |||||
| [self reshape]; | |||||
| } | |||||
| } else { | |||||
| self = nil; | |||||
| } | |||||
| return self; | |||||
| } | |||||
| - (void) reshape | |||||
| { | |||||
| [[self openGLContext] update]; | |||||
| NSRect bounds = [self bounds]; | |||||
| int width = bounds.size.width; | |||||
| int height = bounds.size.height; | |||||
| if (view->reshapeFunc) { | |||||
| view->reshapeFunc(view, width, height); | |||||
| } else { | |||||
| puglDefaultReshape(view, width, height); | |||||
| } | |||||
| view->width = width; | |||||
| view->height = height; | |||||
| } | |||||
| - (void) drawRect:(NSRect)rect | |||||
| { | |||||
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |||||
| glLoadIdentity(); | |||||
| if (self->view->displayFunc) { | |||||
| self->view->displayFunc(self->view); | |||||
| } | |||||
| glFlush(); | |||||
| glSwapAPPLE(); | |||||
| } | |||||
| static int | |||||
| getModifiers(unsigned modifierFlags) | |||||
| { | |||||
| int mods = 0; | |||||
| mods |= (modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0; | |||||
| mods |= (modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0; | |||||
| mods |= (modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0; | |||||
| mods |= (modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0; | |||||
| return mods; | |||||
| } | |||||
| - (void) mouseMoved:(NSEvent*)event | |||||
| { | |||||
| if (view->motionFunc) { | |||||
| NSPoint loc = [event locationInWindow]; | |||||
| view->mods = getModifiers([event modifierFlags]); | |||||
| view->motionFunc(view, loc.x, loc.y); | |||||
| } | |||||
| } | |||||
| - (void) mouseDown:(NSEvent*)event | |||||
| { | |||||
| if (view->mouseFunc) { | |||||
| NSPoint loc = [event locationInWindow]; | |||||
| view->mods = getModifiers([event modifierFlags]); | |||||
| view->mouseFunc(view, 1, true, loc.x, loc.y); | |||||
| } | |||||
| } | |||||
| - (void) mouseUp:(NSEvent*)event | |||||
| { | |||||
| if (view->mouseFunc) { | |||||
| NSPoint loc = [event locationInWindow]; | |||||
| view->mods = getModifiers([event modifierFlags]); | |||||
| view->mouseFunc(view, 1, false, loc.x, loc.y); | |||||
| } | |||||
| } | |||||
| - (void) rightMouseDown:(NSEvent*)event | |||||
| { | |||||
| if (view->mouseFunc) { | |||||
| NSPoint loc = [event locationInWindow]; | |||||
| view->mods = getModifiers([event modifierFlags]); | |||||
| view->mouseFunc(view, 3, true, loc.x, loc.y); | |||||
| } | |||||
| } | |||||
| - (void) rightMouseUp:(NSEvent*)event | |||||
| { | |||||
| if (view->mouseFunc) { | |||||
| NSPoint loc = [event locationInWindow]; | |||||
| view->mods = getModifiers([event modifierFlags]); | |||||
| view->mouseFunc(view, 3, false, loc.x, loc.y); | |||||
| } | |||||
| } | |||||
| - (void) scrollWheel:(NSEvent*)event | |||||
| { | |||||
| if (view->scrollFunc) { | |||||
| view->mods = getModifiers([event modifierFlags]); | |||||
| view->scrollFunc(view, [event deltaX], [event deltaY]); | |||||
| } | |||||
| } | |||||
| - (void) keyDown:(NSEvent*)event | |||||
| { | |||||
| if (view->keyboardFunc && !(view->ignoreKeyRepeat && [event isARepeat])) { | |||||
| NSString* chars = [event characters]; | |||||
| view->mods = getModifiers([event modifierFlags]); | |||||
| view->keyboardFunc(view, true, [chars characterAtIndex:0]); | |||||
| } | |||||
| } | |||||
| - (void) keyUp:(NSEvent*)event | |||||
| { | |||||
| if (view->keyboardFunc) { | |||||
| NSString* chars = [event characters]; | |||||
| view->mods = getModifiers([event modifierFlags]); | |||||
| view->keyboardFunc(view, false, [chars characterAtIndex:0]); | |||||
| } | |||||
| } | |||||
| - (void) flagsChanged:(NSEvent*)event | |||||
| { | |||||
| if (view->specialFunc) { | |||||
| int mods = getModifiers([event modifierFlags]); | |||||
| if ((mods & PUGL_MOD_SHIFT) != (view->mods & PUGL_MOD_SHIFT)) { | |||||
| view->specialFunc(view, mods & PUGL_MOD_SHIFT, PUGL_KEY_SHIFT); | |||||
| } else if ((mods & PUGL_MOD_CTRL) != (view->mods & PUGL_MOD_CTRL)) { | |||||
| view->specialFunc(view, mods & PUGL_MOD_CTRL, PUGL_KEY_CTRL); | |||||
| } else if ((mods & PUGL_MOD_ALT) != (view->mods & PUGL_MOD_ALT)) { | |||||
| view->specialFunc(view, mods & PUGL_MOD_ALT, PUGL_KEY_ALT); | |||||
| } else if ((mods & PUGL_MOD_SUPER) != (view->mods & PUGL_MOD_SUPER)) { | |||||
| view->specialFunc(view, mods & PUGL_MOD_SUPER, PUGL_KEY_SUPER); | |||||
| } | |||||
| view->mods = mods; | |||||
| } | |||||
| } | |||||
| @end | |||||
| struct PuglInternalsImpl { | |||||
| PuglOpenGLView* view; | |||||
| NSModalSession session; | |||||
| id window; | |||||
| }; | |||||
| PuglView* | |||||
| puglCreate(PuglNativeWindow parent, | |||||
| const char* title, | |||||
| int width, | |||||
| int height, | |||||
| bool resizable, | |||||
| bool addToDesktop, | |||||
| const char* x11Display) | |||||
| { | |||||
| PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); | |||||
| PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||||
| if (!view || !impl) { | |||||
| return NULL; | |||||
| } | |||||
| view->impl = impl; | |||||
| view->width = width; | |||||
| view->height = height; | |||||
| [NSAutoreleasePool new]; | |||||
| [NSApplication sharedApplication]; | |||||
| [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; | |||||
| NSString* titleString = [[NSString alloc] | |||||
| initWithBytes:title | |||||
| length:strlen(title) | |||||
| encoding:NSUTF8StringEncoding]; | |||||
| id window = [[[NSWindow alloc] | |||||
| initWithContentRect:NSMakeRect(0, 0, 512, 512) | |||||
| styleMask:NSTitledWindowMask | |||||
| backing:NSBackingStoreBuffered | |||||
| defer:NO] | |||||
| autorelease]; | |||||
| [window cascadeTopLeftFromPoint:NSMakePoint(20, 20)]; | |||||
| [window setTitle:titleString]; | |||||
| [window setAcceptsMouseMovedEvents:YES]; | |||||
| impl->view = [PuglOpenGLView new]; | |||||
| impl->window = window; | |||||
| impl->view->view = view; | |||||
| [window setContentView:impl->view]; | |||||
| [NSApp activateIgnoringOtherApps:YES]; | |||||
| [window makeFirstResponder:impl->view]; | |||||
| impl->session = [NSApp beginModalSessionForWindow:view->impl->window]; | |||||
| return view; | |||||
| // unused | |||||
| (void)addToDesktop; | |||||
| (void)x11Display; | |||||
| } | |||||
| void | |||||
| puglDestroy(PuglView* view) | |||||
| { | |||||
| [NSApp endModalSession:view->impl->session]; | |||||
| [view->impl->view release]; | |||||
| free(view->impl); | |||||
| free(view); | |||||
| } | |||||
| void | |||||
| puglDisplay(PuglView* view) | |||||
| { | |||||
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |||||
| glLoadIdentity(); | |||||
| if (view->displayFunc) { | |||||
| view->displayFunc(view); | |||||
| } | |||||
| glFlush(); | |||||
| view->redisplay = false; | |||||
| } | |||||
| PuglStatus | |||||
| puglProcessEvents(PuglView* view) | |||||
| { | |||||
| NSInteger response = [NSApp runModalSession:view->impl->session]; | |||||
| if (response != NSRunContinuesResponse) { | |||||
| if (view->closeFunc) { | |||||
| view->closeFunc(view); | |||||
| } | |||||
| } | |||||
| if (view->redisplay) { | |||||
| puglDisplay(view); | |||||
| } | |||||
| return PUGL_SUCCESS; | |||||
| } | |||||
| void | |||||
| puglPostRedisplay(PuglView* view) | |||||
| { | |||||
| view->redisplay = true; | |||||
| } | |||||
| PuglNativeWindow | |||||
| puglGetNativeWindow(PuglView* view) | |||||
| { | |||||
| return (PuglNativeWindow)view->impl->view; | |||||
| } | |||||
| @@ -0,0 +1,344 @@ | |||||
| /* | |||||
| Copyright 2012 David Robillard <http://drobilla.net> | |||||
| Permission to use, copy, modify, and/or distribute this software for any | |||||
| purpose with or without fee is hereby granted, provided that the above | |||||
| copyright notice and this permission notice appear in all copies. | |||||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
| */ | |||||
| /** | |||||
| @file pugl_win.cpp Windows/WGL Pugl Implementation. | |||||
| */ | |||||
| #include <windows.h> | |||||
| #include <windowsx.h> | |||||
| #include <GL/gl.h> | |||||
| #include "pugl_internal.h" | |||||
| #ifndef WM_MOUSEWHEEL | |||||
| # define WM_MOUSEWHEEL 0x020A | |||||
| #endif | |||||
| #ifndef WM_MOUSEHWHEEL | |||||
| # define WM_MOUSEHWHEEL 0x020E | |||||
| #endif | |||||
| struct PuglInternalsImpl { | |||||
| HWND hwnd; | |||||
| HDC hdc; | |||||
| HGLRC hglrc; | |||||
| }; | |||||
| LRESULT CALLBACK | |||||
| wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); | |||||
| PuglView* | |||||
| puglCreate(PuglNativeWindow parent, | |||||
| const char* title, | |||||
| int width, | |||||
| int height, | |||||
| bool resizable, | |||||
| bool addToDesktop, | |||||
| const char* x11Display) | |||||
| { | |||||
| PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); | |||||
| PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||||
| if (!view || !impl) { | |||||
| return NULL; | |||||
| } | |||||
| view->impl = impl; | |||||
| view->width = width; | |||||
| view->height = height; | |||||
| WNDCLASS wc; | |||||
| wc.style = CS_OWNDC; | |||||
| wc.lpfnWndProc = wndProc; | |||||
| wc.cbClsExtra = 0; | |||||
| wc.cbWndExtra = 0; | |||||
| wc.hInstance = 0; | |||||
| wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); | |||||
| wc.hCursor = LoadCursor(NULL, IDC_ARROW); | |||||
| wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); | |||||
| wc.lpszMenuName = NULL; | |||||
| wc.lpszClassName = "Pugl"; | |||||
| RegisterClass(&wc); | |||||
| impl->hwnd = CreateWindow( | |||||
| "Pugl", title, | |||||
| (addToDesktop ? WS_VISIBLE : 0) | (parent ? WS_CHILD : (WS_POPUPWINDOW | WS_CAPTION)), | |||||
| 0, 0, width, height, | |||||
| (HWND)parent, NULL, NULL, NULL); | |||||
| if (!impl->hwnd) { | |||||
| free(impl); | |||||
| free(view); | |||||
| return NULL; | |||||
| } | |||||
| SetWindowLongPtr(impl->hwnd, GWL_USERDATA, (LONG)view); | |||||
| impl->hdc = GetDC(impl->hwnd); | |||||
| PIXELFORMATDESCRIPTOR pfd; | |||||
| ZeroMemory(&pfd, sizeof(pfd)); | |||||
| pfd.nSize = sizeof(pfd); | |||||
| pfd.nVersion = 1; | |||||
| pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; | |||||
| pfd.iPixelType = PFD_TYPE_RGBA; | |||||
| pfd.cColorBits = 24; | |||||
| pfd.cDepthBits = 16; | |||||
| pfd.iLayerType = PFD_MAIN_PLANE; | |||||
| int format = ChoosePixelFormat(impl->hdc, &pfd); | |||||
| SetPixelFormat(impl->hdc, format, &pfd); | |||||
| impl->hglrc = wglCreateContext(impl->hdc); | |||||
| wglMakeCurrent(impl->hdc, impl->hglrc); | |||||
| view->width = width; | |||||
| view->height = height; | |||||
| return view; | |||||
| // unused | |||||
| (void)resizable; | |||||
| (void)x11Display; | |||||
| } | |||||
| void | |||||
| puglDestroy(PuglView* view) | |||||
| { | |||||
| wglMakeCurrent(NULL, NULL); | |||||
| wglDeleteContext(view->impl->hglrc); | |||||
| ReleaseDC(view->impl->hwnd, view->impl->hdc); | |||||
| DestroyWindow(view->impl->hwnd); | |||||
| free(view->impl); | |||||
| free(view); | |||||
| } | |||||
| void | |||||
| puglReshape(PuglView* view, int width, int height) | |||||
| { | |||||
| wglMakeCurrent(view->impl->hdc, view->impl->hglrc); | |||||
| if (view->reshapeFunc) { | |||||
| view->reshapeFunc(view, width, height); | |||||
| } else { | |||||
| puglDefaultReshape(view, width, height); | |||||
| } | |||||
| view->width = width; | |||||
| view->height = height; | |||||
| } | |||||
| void | |||||
| puglDisplay(PuglView* view) | |||||
| { | |||||
| wglMakeCurrent(view->impl->hdc, view->impl->hglrc); | |||||
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |||||
| glLoadIdentity(); | |||||
| if (view->displayFunc) { | |||||
| view->displayFunc(view); | |||||
| } | |||||
| glFlush(); | |||||
| SwapBuffers(view->impl->hdc); | |||||
| view->redisplay = false; | |||||
| } | |||||
| static PuglKey | |||||
| keySymToSpecial(int sym) | |||||
| { | |||||
| switch (sym) { | |||||
| case VK_F1: return PUGL_KEY_F1; | |||||
| case VK_F2: return PUGL_KEY_F2; | |||||
| case VK_F3: return PUGL_KEY_F3; | |||||
| case VK_F4: return PUGL_KEY_F4; | |||||
| case VK_F5: return PUGL_KEY_F5; | |||||
| case VK_F6: return PUGL_KEY_F6; | |||||
| case VK_F7: return PUGL_KEY_F7; | |||||
| case VK_F8: return PUGL_KEY_F8; | |||||
| case VK_F9: return PUGL_KEY_F9; | |||||
| case VK_F10: return PUGL_KEY_F10; | |||||
| case VK_F11: return PUGL_KEY_F11; | |||||
| case VK_F12: return PUGL_KEY_F12; | |||||
| case VK_LEFT: return PUGL_KEY_LEFT; | |||||
| case VK_UP: return PUGL_KEY_UP; | |||||
| case VK_RIGHT: return PUGL_KEY_RIGHT; | |||||
| case VK_DOWN: return PUGL_KEY_DOWN; | |||||
| case VK_PRIOR: return PUGL_KEY_PAGE_UP; | |||||
| case VK_NEXT: return PUGL_KEY_PAGE_DOWN; | |||||
| case VK_HOME: return PUGL_KEY_HOME; | |||||
| case VK_END: return PUGL_KEY_END; | |||||
| case VK_INSERT: return PUGL_KEY_INSERT; | |||||
| case VK_SHIFT: return PUGL_KEY_SHIFT; | |||||
| case VK_CONTROL: return PUGL_KEY_CTRL; | |||||
| case VK_MENU: return PUGL_KEY_ALT; | |||||
| case VK_LWIN: return PUGL_KEY_SUPER; | |||||
| case VK_RWIN: return PUGL_KEY_SUPER; | |||||
| } | |||||
| return (PuglKey)0; | |||||
| } | |||||
| static void | |||||
| processMouseEvent(PuglView* view, int button, bool press, LPARAM lParam) | |||||
| { | |||||
| if (view->mouseFunc) { | |||||
| view->mouseFunc(view, button, press, | |||||
| GET_X_LPARAM(lParam), | |||||
| GET_Y_LPARAM(lParam)); | |||||
| } | |||||
| } | |||||
| static void | |||||
| setModifiers(PuglView* view) | |||||
| { | |||||
| view->mods = 0; | |||||
| view->mods |= (GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0; | |||||
| view->mods |= (GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0; | |||||
| view->mods |= (GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0; | |||||
| view->mods |= (GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0; | |||||
| view->mods |= (GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0; | |||||
| } | |||||
| static LRESULT | |||||
| handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) | |||||
| { | |||||
| PAINTSTRUCT ps; | |||||
| PuglKey key; | |||||
| setModifiers(view); | |||||
| switch (message) { | |||||
| case WM_CREATE: | |||||
| case WM_SHOWWINDOW: | |||||
| case WM_SIZE: | |||||
| puglReshape(view, view->width, view->height); | |||||
| break; | |||||
| case WM_PAINT: | |||||
| BeginPaint(view->impl->hwnd, &ps); | |||||
| puglDisplay(view); | |||||
| EndPaint(view->impl->hwnd, &ps); | |||||
| break; | |||||
| case WM_MOUSEMOVE: | |||||
| if (view->motionFunc) { | |||||
| view->motionFunc( | |||||
| view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); | |||||
| } | |||||
| break; | |||||
| case WM_LBUTTONDOWN: | |||||
| processMouseEvent(view, 1, true, lParam); | |||||
| break; | |||||
| case WM_MBUTTONDOWN: | |||||
| processMouseEvent(view, 2, true, lParam); | |||||
| break; | |||||
| case WM_RBUTTONDOWN: | |||||
| processMouseEvent(view, 3, true, lParam); | |||||
| break; | |||||
| case WM_LBUTTONUP: | |||||
| processMouseEvent(view, 1, false, lParam); | |||||
| break; | |||||
| case WM_MBUTTONUP: | |||||
| processMouseEvent(view, 2, false, lParam); | |||||
| break; | |||||
| case WM_RBUTTONUP: | |||||
| processMouseEvent(view, 3, false, lParam); | |||||
| break; | |||||
| case WM_MOUSEWHEEL: | |||||
| if (view->scrollFunc) { | |||||
| view->scrollFunc( | |||||
| view, 0, (int16_t)HIWORD(wParam) / (float)WHEEL_DELTA); | |||||
| } | |||||
| break; | |||||
| case WM_MOUSEHWHEEL: | |||||
| if (view->scrollFunc) { | |||||
| view->scrollFunc( | |||||
| view, (int16_t)HIWORD(wParam) / float(WHEEL_DELTA), 0); | |||||
| } | |||||
| break; | |||||
| case WM_KEYDOWN: | |||||
| if (view->ignoreKeyRepeat && (lParam & (1 << 30))) { | |||||
| break; | |||||
| } // else nobreak | |||||
| case WM_KEYUP: | |||||
| if ((key = keySymToSpecial(wParam))) { | |||||
| if (view->specialFunc) { | |||||
| view->specialFunc(view, message == WM_KEYDOWN, key); | |||||
| } | |||||
| } else if (view->keyboardFunc) { | |||||
| view->keyboardFunc(view, message == WM_KEYDOWN, wParam); | |||||
| } | |||||
| break; | |||||
| case WM_QUIT: | |||||
| if (view->closeFunc) { | |||||
| view->closeFunc(view); | |||||
| } | |||||
| break; | |||||
| default: | |||||
| return DefWindowProc( | |||||
| view->impl->hwnd, message, wParam, lParam); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| PuglStatus | |||||
| puglProcessEvents(PuglView* view) | |||||
| { | |||||
| MSG msg; | |||||
| while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) { | |||||
| handleMessage(view, msg.message, msg.wParam, msg.lParam); | |||||
| } | |||||
| if (view->redisplay) { | |||||
| puglDisplay(view); | |||||
| } | |||||
| return PUGL_SUCCESS; | |||||
| } | |||||
| LRESULT CALLBACK | |||||
| wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | |||||
| { | |||||
| PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWL_USERDATA); | |||||
| switch (message) { | |||||
| case WM_CREATE: | |||||
| PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0); | |||||
| return 0; | |||||
| case WM_CLOSE: | |||||
| PostQuitMessage(0); | |||||
| return 0; | |||||
| case WM_DESTROY: | |||||
| return 0; | |||||
| case WM_MOUSEWHEEL: | |||||
| case WM_MOUSEHWHEEL: | |||||
| PostMessage(hwnd, message, wParam, lParam); | |||||
| return 0; | |||||
| default: | |||||
| if (view) { | |||||
| return handleMessage(view, message, wParam, lParam); | |||||
| } else { | |||||
| return DefWindowProc(hwnd, message, wParam, lParam); | |||||
| } | |||||
| } | |||||
| } | |||||
| void | |||||
| puglPostRedisplay(PuglView* view) | |||||
| { | |||||
| view->redisplay = true; | |||||
| } | |||||
| PuglNativeWindow | |||||
| puglGetNativeWindow(PuglView* view) | |||||
| { | |||||
| return (PuglNativeWindow)view->impl->hwnd; | |||||
| } | |||||
| @@ -0,0 +1,379 @@ | |||||
| /* | |||||
| Copyright 2012 David Robillard <http://drobilla.net> | |||||
| Copyright 2011-2012 Ben Loftis, Harrison Consoles | |||||
| Permission to use, copy, modify, and/or distribute this software for any | |||||
| purpose with or without fee is hereby granted, provided that the above | |||||
| copyright notice and this permission notice appear in all copies. | |||||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
| */ | |||||
| /** | |||||
| @file pugl_x11.c X11 Pugl Implementation. | |||||
| */ | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include "pugl_x11.h" | |||||
| #include "pugl_internal.h" | |||||
| /** | |||||
| Attributes for single-buffered RGBA with at least | |||||
| 4 bits per color and a 16 bit depth buffer. | |||||
| */ | |||||
| static int attrListSgl[] = { | |||||
| GLX_RGBA, | |||||
| GLX_RED_SIZE, 4, | |||||
| GLX_GREEN_SIZE, 4, | |||||
| GLX_BLUE_SIZE, 4, | |||||
| GLX_DEPTH_SIZE, 16, | |||||
| None | |||||
| }; | |||||
| /** | |||||
| Attributes for double-buffered RGBA with at least | |||||
| 4 bits per color and a 16 bit depth buffer. | |||||
| */ | |||||
| static int attrListDbl[] = { | |||||
| GLX_RGBA, GLX_DOUBLEBUFFER, | |||||
| GLX_RED_SIZE, 4, | |||||
| GLX_GREEN_SIZE, 4, | |||||
| GLX_BLUE_SIZE, 4, | |||||
| GLX_DEPTH_SIZE, 16, | |||||
| None | |||||
| }; | |||||
| PuglView* | |||||
| puglCreate(PuglNativeWindow parent, | |||||
| const char* title, | |||||
| int width, | |||||
| int height, | |||||
| bool resizable, | |||||
| bool addToDesktop, | |||||
| const char* x11Display) | |||||
| { | |||||
| PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); | |||||
| PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||||
| if (!view || !impl) { | |||||
| return nullptr; | |||||
| } | |||||
| view->impl = impl; | |||||
| view->width = width; | |||||
| view->height = height; | |||||
| impl->display = XOpenDisplay(x11Display); | |||||
| impl->screen = DefaultScreen(impl->display); | |||||
| XVisualInfo* vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); | |||||
| if (!vi) { | |||||
| vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | |||||
| impl->doubleBuffered = False; | |||||
| printf("singlebuffered rendering will be used, no doublebuffering available\n"); | |||||
| } else { | |||||
| impl->doubleBuffered = True; | |||||
| printf("doublebuffered rendering available\n"); | |||||
| } | |||||
| int glxMajor, glxMinor; | |||||
| glXQueryVersion(impl->display, &glxMajor, &glxMinor); | |||||
| printf("GLX-Version %d.%d\n", glxMajor, glxMinor); | |||||
| impl->ctx = glXCreateContext(impl->display, vi, nullptr, GL_TRUE); | |||||
| Window xParent = parent | |||||
| ? (Window)parent | |||||
| : RootWindow(impl->display, impl->screen); | |||||
| Colormap cmap = XCreateColormap( | |||||
| impl->display, xParent, vi->visual, AllocNone); | |||||
| XSetWindowAttributes attr; | |||||
| memset(&attr, 0, sizeof(XSetWindowAttributes)); | |||||
| attr.colormap = cmap; | |||||
| attr.border_pixel = 0; | |||||
| attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | |||||
| | ButtonPressMask | ButtonReleaseMask | |||||
| | PointerMotionMask | StructureNotifyMask; | |||||
| impl->win = XCreateWindow( | |||||
| impl->display, xParent, | |||||
| 0, 0, (unsigned int)view->width, (unsigned int)view->height, 0, vi->depth, InputOutput, vi->visual, | |||||
| CWBorderPixel | CWColormap | CWEventMask, &attr); | |||||
| XSizeHints sizeHints; | |||||
| memset(&sizeHints, 0, sizeof(sizeHints)); | |||||
| if (!resizable) { | |||||
| sizeHints.flags = PMinSize|PMaxSize; | |||||
| sizeHints.min_width = width; | |||||
| sizeHints.min_height = height; | |||||
| sizeHints.max_width = width; | |||||
| sizeHints.max_height = height; | |||||
| XSetNormalHints(impl->display, impl->win, &sizeHints); | |||||
| } | |||||
| if (title) { | |||||
| XStoreName(impl->display, impl->win, title); | |||||
| } | |||||
| if (!parent) { | |||||
| Atom wmDelete = XInternAtom(impl->display, "WM_DELETE_WINDOW", True); | |||||
| XSetWMProtocols(impl->display, impl->win, &wmDelete, 1); | |||||
| } | |||||
| if (addToDesktop) { | |||||
| XMapRaised(impl->display, impl->win); | |||||
| } | |||||
| if (glXIsDirect(impl->display, impl->ctx)) { | |||||
| printf("DRI enabled\n"); | |||||
| } else { | |||||
| printf("no DRI available\n"); | |||||
| } | |||||
| XFree(vi); | |||||
| return view; | |||||
| } | |||||
| void | |||||
| puglDestroy(PuglView* view) | |||||
| { | |||||
| if (!view) { | |||||
| return; | |||||
| } | |||||
| glXDestroyContext(view->impl->display, view->impl->ctx); | |||||
| XDestroyWindow(view->impl->display, view->impl->win); | |||||
| XCloseDisplay(view->impl->display); | |||||
| free(view->impl); | |||||
| free(view); | |||||
| } | |||||
| static void | |||||
| puglReshape(PuglView* view, int width, int height) | |||||
| { | |||||
| glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||||
| if (view->reshapeFunc) { | |||||
| view->reshapeFunc(view, width, height); | |||||
| } else { | |||||
| puglDefaultReshape(view, width, height); | |||||
| } | |||||
| view->width = width; | |||||
| view->height = height; | |||||
| } | |||||
| static void | |||||
| puglDisplay(PuglView* view) | |||||
| { | |||||
| glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||||
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |||||
| glLoadIdentity(); | |||||
| if (view->displayFunc) { | |||||
| view->displayFunc(view); | |||||
| } | |||||
| glFlush(); | |||||
| if (view->impl->doubleBuffered) { | |||||
| glXSwapBuffers(view->impl->display, view->impl->win); | |||||
| } | |||||
| view->redisplay = false; | |||||
| } | |||||
| static PuglKey | |||||
| keySymToSpecial(KeySym sym) | |||||
| { | |||||
| switch (sym) { | |||||
| case XK_F1: return PUGL_KEY_F1; | |||||
| case XK_F2: return PUGL_KEY_F2; | |||||
| case XK_F3: return PUGL_KEY_F3; | |||||
| case XK_F4: return PUGL_KEY_F4; | |||||
| case XK_F5: return PUGL_KEY_F5; | |||||
| case XK_F6: return PUGL_KEY_F6; | |||||
| case XK_F7: return PUGL_KEY_F7; | |||||
| case XK_F8: return PUGL_KEY_F8; | |||||
| case XK_F9: return PUGL_KEY_F9; | |||||
| case XK_F10: return PUGL_KEY_F10; | |||||
| case XK_F11: return PUGL_KEY_F11; | |||||
| case XK_F12: return PUGL_KEY_F12; | |||||
| case XK_Left: return PUGL_KEY_LEFT; | |||||
| case XK_Up: return PUGL_KEY_UP; | |||||
| case XK_Right: return PUGL_KEY_RIGHT; | |||||
| case XK_Down: return PUGL_KEY_DOWN; | |||||
| case XK_Page_Up: return PUGL_KEY_PAGE_UP; | |||||
| case XK_Page_Down: return PUGL_KEY_PAGE_DOWN; | |||||
| case XK_Home: return PUGL_KEY_HOME; | |||||
| case XK_End: return PUGL_KEY_END; | |||||
| case XK_Insert: return PUGL_KEY_INSERT; | |||||
| case XK_Shift_L: return PUGL_KEY_SHIFT; | |||||
| case XK_Shift_R: return PUGL_KEY_SHIFT; | |||||
| case XK_Control_L: return PUGL_KEY_CTRL; | |||||
| case XK_Control_R: return PUGL_KEY_CTRL; | |||||
| case XK_Alt_L: return PUGL_KEY_ALT; | |||||
| case XK_Alt_R: return PUGL_KEY_ALT; | |||||
| case XK_Super_L: return PUGL_KEY_SUPER; | |||||
| case XK_Super_R: return PUGL_KEY_SUPER; | |||||
| } | |||||
| return (PuglKey)0; | |||||
| } | |||||
| static void | |||||
| setModifiers(PuglView* view, int xstate) | |||||
| { | |||||
| view->mods = 0; | |||||
| view->mods |= (xstate & ShiftMask) ? PUGL_MOD_SHIFT : 0; | |||||
| view->mods |= (xstate & ControlMask) ? PUGL_MOD_CTRL : 0; | |||||
| view->mods |= (xstate & Mod1Mask) ? PUGL_MOD_ALT : 0; | |||||
| view->mods |= (xstate & Mod4Mask) ? PUGL_MOD_SUPER : 0; | |||||
| } | |||||
| PuglStatus | |||||
| puglProcessEvents(PuglView* view) | |||||
| { | |||||
| XEvent event; | |||||
| while (XPending(view->impl->display) > 0) { | |||||
| XNextEvent(view->impl->display, &event); | |||||
| switch (event.type) { | |||||
| case MapNotify: | |||||
| puglReshape(view, view->width, view->height); | |||||
| break; | |||||
| case ConfigureNotify: | |||||
| if ((event.xconfigure.width != view->width) || | |||||
| (event.xconfigure.height != view->height)) { | |||||
| puglReshape(view, | |||||
| event.xconfigure.width, | |||||
| event.xconfigure.height); | |||||
| } | |||||
| break; | |||||
| case Expose: | |||||
| if (event.xexpose.count != 0) { | |||||
| break; | |||||
| } | |||||
| puglDisplay(view); | |||||
| view->redisplay = false; | |||||
| break; | |||||
| case MotionNotify: | |||||
| setModifiers(view, (int)event.xmotion.state); | |||||
| if (view->motionFunc) { | |||||
| view->motionFunc(view, event.xmotion.x, event.xmotion.y); | |||||
| } | |||||
| break; | |||||
| case ButtonPress: | |||||
| setModifiers(view, (int)event.xbutton.state); | |||||
| if (event.xbutton.button >= 4 && event.xbutton.button <= 7) { | |||||
| if (view->scrollFunc) { | |||||
| float dx = 0, dy = 0; | |||||
| switch (event.xbutton.button) { | |||||
| case 4: dy = 1.0f; break; | |||||
| case 5: dy = -1.0f; break; | |||||
| case 6: dx = -1.0f; break; | |||||
| case 7: dx = 1.0f; break; | |||||
| } | |||||
| view->scrollFunc(view, dx, dy); | |||||
| } | |||||
| break; | |||||
| } | |||||
| // nobreak | |||||
| case ButtonRelease: | |||||
| setModifiers(view, (int)event.xbutton.state); | |||||
| if (view->mouseFunc && | |||||
| (event.xbutton.button < 4 || event.xbutton.button > 7)) { | |||||
| view->mouseFunc(view, | |||||
| (int)event.xbutton.button, event.type == ButtonPress, | |||||
| event.xbutton.x, event.xbutton.y); | |||||
| } | |||||
| break; | |||||
| case KeyPress: { | |||||
| setModifiers(view, (int)event.xkey.state); | |||||
| KeySym sym; | |||||
| char str[5]; | |||||
| int n = XLookupString(&event.xkey, str, 4, &sym, nullptr); | |||||
| PuglKey key = keySymToSpecial(sym); | |||||
| if (!key && view->keyboardFunc) { | |||||
| if (n == 1) { | |||||
| view->keyboardFunc(view, true, (uint32_t)str[0]); | |||||
| } else { | |||||
| fprintf(stderr, "warning: Unknown key %X\n", (int)sym); | |||||
| } | |||||
| } else if (view->specialFunc) { | |||||
| view->specialFunc(view, true, key); | |||||
| } | |||||
| } break; | |||||
| case KeyRelease: { | |||||
| setModifiers(view, (int)event.xkey.state); | |||||
| bool repeated = false; | |||||
| if (view->ignoreKeyRepeat && | |||||
| XEventsQueued(view->impl->display, QueuedAfterReading)) { | |||||
| XEvent next; | |||||
| XPeekEvent(view->impl->display, &next); | |||||
| if (next.type == KeyPress && | |||||
| next.xkey.time == event.xkey.time && | |||||
| next.xkey.keycode == event.xkey.keycode) { | |||||
| XNextEvent(view->impl->display, &event); | |||||
| repeated = true; | |||||
| } | |||||
| } | |||||
| if (!repeated && view->keyboardFunc) { | |||||
| KeySym sym = XKeycodeToKeysym( | |||||
| view->impl->display, (KeyCode)event.xkey.keycode, 0); | |||||
| PuglKey special = keySymToSpecial(sym); | |||||
| if (!special) { | |||||
| view->keyboardFunc(view, false, (uint32_t)sym); | |||||
| } else if (view->specialFunc) { | |||||
| view->specialFunc(view, false, special); | |||||
| } | |||||
| } | |||||
| } break; | |||||
| case ClientMessage: | |||||
| if (!strcmp(XGetAtomName(view->impl->display, | |||||
| event.xclient.message_type), | |||||
| "WM_PROTOCOLS")) { | |||||
| if (view->closeFunc) { | |||||
| view->closeFunc(view); | |||||
| } | |||||
| } | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (view->redisplay) { | |||||
| puglDisplay(view); | |||||
| } | |||||
| return PUGL_SUCCESS; | |||||
| } | |||||
| void | |||||
| puglPostRedisplay(PuglView* view) | |||||
| { | |||||
| view->redisplay = true; | |||||
| } | |||||
| PuglNativeWindow | |||||
| puglGetNativeWindow(PuglView* view) | |||||
| { | |||||
| return static_cast<PuglNativeWindow>(view->impl->win); | |||||
| } | |||||
| PuglInternals* | |||||
| puglGetInternalsImpl(PuglView* view) | |||||
| { | |||||
| return view->impl; | |||||
| } | |||||
| @@ -0,0 +1,46 @@ | |||||
| /* | |||||
| Copyright 2012 David Robillard <http://drobilla.net> | |||||
| Copyright 2011-2012 Ben Loftis, Harrison Consoles | |||||
| Permission to use, copy, modify, and/or distribute this software for any | |||||
| purpose with or without fee is hereby granted, provided that the above | |||||
| copyright notice and this permission notice appear in all copies. | |||||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
| */ | |||||
| /** | |||||
| @file pugl_x11.h X11 Pugl Implementation (PuglInternalsImpl only). | |||||
| */ | |||||
| #ifndef PUGL_X11_H_INCLUDED | |||||
| #define PUGL_X11_H_INCLUDED | |||||
| #include "pugl.h" | |||||
| #include <GL/gl.h> | |||||
| #include <GL/glx.h> | |||||
| #include <X11/Xatom.h> | |||||
| #include <X11/Xlib.h> | |||||
| #include <X11/keysym.h> | |||||
| struct PuglInternalsImpl { | |||||
| Display* display; | |||||
| int screen; | |||||
| Window win; | |||||
| GLXContext ctx; | |||||
| Bool doubleBuffered; | |||||
| }; | |||||
| typedef struct PuglInternalsImpl PuglInternals; | |||||
| PuglInternals* | |||||
| puglGetInternalsImpl(PuglView* view); | |||||
| #endif /* PUGL_X11_H_INCLUDED */ | |||||
| @@ -38,7 +38,9 @@ UI::UI() | |||||
| #endif | #endif | ||||
| #ifdef DISTRHO_UI_QT4 | #ifdef DISTRHO_UI_QT4 | ||||
| pData->widget = (Qt4UI*)this; | |||||
| pData->ui = (Qt4UI*)this; | |||||
| #else | |||||
| pData->ui = (OpenGLUI*)this; | |||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -19,13 +19,11 @@ | |||||
| #include "DistrhoDefines.h" | #include "DistrhoDefines.h" | ||||
| //#ifdef DISTRHO_UI_OPENGL | |||||
| //# include "DistrhoUIOpenGL.h" | |||||
| // START_NAMESPACE_DISTRHO | |||||
| //# include "pugl/pugl.h" | |||||
| // END_NAMESPACE_DISTRHO | |||||
| //#else | |||||
| #ifdef DISTRHO_UI_OPENGL | |||||
| # include "../DistrhoUIOpenGL.hpp" | |||||
| # include "../dgl/App.hpp" | |||||
| # include "../dgl/Window.hpp" | |||||
| #else | |||||
| # include "../DistrhoUIQt4.hpp" | # include "../DistrhoUIQt4.hpp" | ||||
| # include <QtGui/QMouseEvent> | # include <QtGui/QMouseEvent> | ||||
| # include <QtGui/QResizeEvent> | # include <QtGui/QResizeEvent> | ||||
| @@ -34,30 +32,26 @@ | |||||
| # ifdef Q_WS_X11 | # ifdef Q_WS_X11 | ||||
| # include <QtGui/QX11EmbedWidget> | # include <QtGui/QX11EmbedWidget> | ||||
| # endif | # endif | ||||
| //#endif | |||||
| #endif | |||||
| START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
| // ------------------------------------------------- | // ------------------------------------------------- | ||||
| //#ifdef DISTRHO_UI_OPENGL | |||||
| //typedef PuglView NativeWidget; | |||||
| //#else | |||||
| typedef QWidget NativeWidget; | |||||
| //#endif | |||||
| typedef void (*editParamFunc) (void* ptr, uint32_t index, bool started); | typedef void (*editParamFunc) (void* ptr, uint32_t index, bool started); | ||||
| typedef void (*setParamFunc) (void* ptr, uint32_t index, float value); | typedef void (*setParamFunc) (void* ptr, uint32_t index, float value); | ||||
| typedef void (*setStateFunc) (void* ptr, const char* key, const char* value); | typedef void (*setStateFunc) (void* ptr, const char* key, const char* value); | ||||
| typedef void (*sendNoteFunc) (void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velo); | typedef void (*sendNoteFunc) (void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velo); | ||||
| typedef void (*uiResizeFunc) (void* ptr, unsigned int width, unsigned int height); | typedef void (*uiResizeFunc) (void* ptr, unsigned int width, unsigned int height); | ||||
| extern double d_lastUiSampleRate; | |||||
| extern double d_lastUiSampleRate; | |||||
| #ifdef DISTRHO_UI_OPENGL | |||||
| extern Window* d_lastUiParent; | |||||
| #endif | |||||
| // ------------------------------------------------- | // ------------------------------------------------- | ||||
| //#ifdef DISTRHO_UI_QT4 | |||||
| #ifdef DISTRHO_UI_QT4 | |||||
| # ifdef Q_WS_X11 | # ifdef Q_WS_X11 | ||||
| class QEmbedWidget : public QX11EmbedWidget | class QEmbedWidget : public QX11EmbedWidget | ||||
| # else | # else | ||||
| @@ -71,7 +65,7 @@ public: | |||||
| void embedInto(WId id); | void embedInto(WId id); | ||||
| WId containerWinId() const; | WId containerWinId() const; | ||||
| }; | }; | ||||
| //#endif | |||||
| #endif | |||||
| // ------------------------------------------------- | // ------------------------------------------------- | ||||
| @@ -80,27 +74,23 @@ struct UIPrivateData { | |||||
| double sampleRate; | double sampleRate; | ||||
| uint32_t parameterOffset; | uint32_t parameterOffset; | ||||
| // UI | |||||
| void* ptr; | |||||
| NativeWidget* widget; | |||||
| // Callbacks | // Callbacks | ||||
| editParamFunc editParamCallbackFunc; | editParamFunc editParamCallbackFunc; | ||||
| setParamFunc setParamCallbackFunc; | setParamFunc setParamCallbackFunc; | ||||
| setStateFunc setStateCallbackFunc; | setStateFunc setStateCallbackFunc; | ||||
| sendNoteFunc sendNoteCallbackFunc; | sendNoteFunc sendNoteCallbackFunc; | ||||
| uiResizeFunc uiResizeCallbackFunc; | uiResizeFunc uiResizeCallbackFunc; | ||||
| void* ptr; | |||||
| UIPrivateData() | UIPrivateData() | ||||
| : sampleRate(d_lastUiSampleRate), | : sampleRate(d_lastUiSampleRate), | ||||
| parameterOffset(0), | parameterOffset(0), | ||||
| ptr(nullptr), | |||||
| widget(nullptr), | |||||
| editParamCallbackFunc(nullptr), | editParamCallbackFunc(nullptr), | ||||
| setParamCallbackFunc(nullptr), | setParamCallbackFunc(nullptr), | ||||
| setStateCallbackFunc(nullptr), | setStateCallbackFunc(nullptr), | ||||
| sendNoteCallbackFunc(nullptr), | sendNoteCallbackFunc(nullptr), | ||||
| uiResizeCallbackFunc(nullptr) | |||||
| uiResizeCallbackFunc(nullptr), | |||||
| ptr(nullptr) | |||||
| { | { | ||||
| assert(d_lastUiSampleRate != 0.0); | assert(d_lastUiSampleRate != 0.0); | ||||
| } | } | ||||
| @@ -150,15 +140,14 @@ class UIInternal | |||||
| { | { | ||||
| public: | public: | ||||
| UIInternal(void* ptr, intptr_t winId, editParamFunc editParamCall, setParamFunc setParamCall, setStateFunc setStateCall, sendNoteFunc sendNoteCall, uiResizeFunc uiResizeCall) | UIInternal(void* ptr, intptr_t winId, editParamFunc editParamCall, setParamFunc setParamCall, setStateFunc setStateCall, sendNoteFunc sendNoteCall, uiResizeFunc uiResizeCall) | ||||
| : kUi(createUI()), | |||||
| kData((kUi != nullptr) ? kUi->pData : nullptr), | |||||
| #ifdef DISTRHO_UI_QT4 | #ifdef DISTRHO_UI_QT4 | ||||
| qtMouseDown(false), | |||||
| qtGrip(nullptr), | |||||
| qtWidget(nullptr) | |||||
| : qtGrip(nullptr), | |||||
| qtWidget(nullptr), | |||||
| #else | #else | ||||
| glInitiated(false) | |||||
| : glWindow(createWindow(winId)), | |||||
| #endif | #endif | ||||
| kUi(createUI()), | |||||
| kData((kUi != nullptr) ? kUi->pData : nullptr) | |||||
| { | { | ||||
| assert(kUi != nullptr); | assert(kUi != nullptr); | ||||
| assert(winId != 0); | assert(winId != 0); | ||||
| @@ -173,7 +162,11 @@ public: | |||||
| kData->sendNoteCallbackFunc = sendNoteCall; | kData->sendNoteCallbackFunc = sendNoteCall; | ||||
| kData->uiResizeCallbackFunc = uiResizeCall; | kData->uiResizeCallbackFunc = uiResizeCall; | ||||
| #ifdef DISTRHO_UI_QT4 | |||||
| createWindow(winId); | createWindow(winId); | ||||
| #else | |||||
| d_lastUiParent = nullptr; | |||||
| #endif | |||||
| } | } | ||||
| ~UIInternal() | ~UIInternal() | ||||
| @@ -255,20 +248,22 @@ public: | |||||
| kUi->d_uiIdle(); | kUi->d_uiIdle(); | ||||
| } | } | ||||
| intptr_t getWindowId() | |||||
| intptr_t getWinId() | |||||
| { | { | ||||
| #ifdef DISTRHO_UI_QT4 | #ifdef DISTRHO_UI_QT4 | ||||
| assert(qtWidget != nullptr); | assert(qtWidget != nullptr); | ||||
| return (qtWidget != nullptr) ? qtWidget->winId() : 0; | return (qtWidget != nullptr) ? qtWidget->winId() : 0; | ||||
| #else | #else | ||||
| assert(glWindow != nullptr); | |||||
| return (glWindow != nullptr) ? glWindow->getWindowId() : 0; | |||||
| #endif | #endif | ||||
| } | } | ||||
| // --------------------------------------------- | // --------------------------------------------- | ||||
| #ifdef DISTRHO_UI_QT4 | |||||
| void createWindow(intptr_t parent) | void createWindow(intptr_t parent) | ||||
| { | { | ||||
| #ifdef DISTRHO_UI_QT4 | |||||
| assert(kUi != nullptr); | assert(kUi != nullptr); | ||||
| assert(kData != nullptr); | assert(kData != nullptr); | ||||
| assert(kData->widget != nullptr); | assert(kData->widget != nullptr); | ||||
| @@ -279,14 +274,12 @@ public: | |||||
| return; | return; | ||||
| if (kData == nullptr) | if (kData == nullptr) | ||||
| return; | return; | ||||
| if (kData->widget == nullptr) | |||||
| return; | |||||
| if (qtGrip != nullptr) | if (qtGrip != nullptr) | ||||
| return; | return; | ||||
| if (qtWidget != nullptr) | if (qtWidget != nullptr) | ||||
| return; | return; | ||||
| qtMouseDown = false; | |||||
| Qt4UI* qt4Ui = (Qt4UI*)kUi; | |||||
| // create embedable widget | // create embedable widget | ||||
| qtWidget = new QEmbedWidget; | qtWidget = new QEmbedWidget; | ||||
| @@ -298,10 +291,10 @@ public: | |||||
| qtWidget->setFixedSize(kUi->d_width(), kUi->d_height()); | qtWidget->setFixedSize(kUi->d_width(), kUi->d_height()); | ||||
| // set resize grip | // set resize grip | ||||
| if (((Qt4UI*)kUi)->d_resizable()) | |||||
| if (qt4Ui->d_resizable()) | |||||
| { | { | ||||
| // listen for resize on the plugin widget | // listen for resize on the plugin widget | ||||
| kData->widget->installEventFilter(this); | |||||
| qt4Ui->installEventFilter(this); | |||||
| // create resize grip on bottom-right | // create resize grip on bottom-right | ||||
| qtGrip = new QSizeGrip(qtWidget); | qtGrip = new QSizeGrip(qtWidget); | ||||
| @@ -318,9 +311,15 @@ public: | |||||
| // show it | // show it | ||||
| qtWidget->show(); | qtWidget->show(); | ||||
| } | |||||
| #else | #else | ||||
| #endif | |||||
| Window* createWindow(intptr_t parent) | |||||
| { | |||||
| Window* window = new Window(&glApp, parent); | |||||
| d_lastParent = window; | |||||
| return window; | |||||
| } | } | ||||
| #endif | |||||
| void destroyWindow() | void destroyWindow() | ||||
| { | { | ||||
| @@ -331,16 +330,16 @@ public: | |||||
| if (kData == nullptr) | if (kData == nullptr) | ||||
| return; | return; | ||||
| if (kData->widget == nullptr) | |||||
| return; | |||||
| if (qtWidget == nullptr) | if (qtWidget == nullptr) | ||||
| return; | return; | ||||
| Qt4UI* qt4Ui = (Qt4UI*)kUi; | |||||
| // remove main widget, to prevent it from being auto-deleted | // remove main widget, to prevent it from being auto-deleted | ||||
| kData->widget->hide(); | |||||
| qtWidget->layout()->removeWidget(kData->widget); | |||||
| kData->widget->setParent(nullptr); | |||||
| kData->widget->close(); | |||||
| qt4Ui->hide(); | |||||
| qtWidget->layout()->removeWidget(qt4Ui); | |||||
| qt4Ui->setParent(nullptr); | |||||
| qt4Ui->close(); | |||||
| qtWidget->close(); | qtWidget->close(); | ||||
| qtWidget->removeEventFilter(this); | qtWidget->removeEventFilter(this); | ||||
| @@ -355,17 +354,36 @@ public: | |||||
| delete qtWidget; | delete qtWidget; | ||||
| qtWidget = nullptr; | qtWidget = nullptr; | ||||
| #else | #else | ||||
| assert(kData != nullptr); | |||||
| assert(glWindow != nullptr); | |||||
| if (kData == nullptr) | |||||
| return; | |||||
| if (glWindow == nullptr) | |||||
| return; | |||||
| glWindow->hide(); | |||||
| delete glWindow; | |||||
| glWindow = nullptr; | |||||
| #endif | #endif | ||||
| } | } | ||||
| // --------------------------------------------- | // --------------------------------------------- | ||||
| private: | |||||
| #ifdef DISTRHO_UI_QT4 | |||||
| QSizeGrip* qtGrip; | |||||
| QEmbedWidget* qtWidget; | |||||
| #else | |||||
| App glApp; | |||||
| Window* glWindow; | |||||
| #endif | |||||
| protected: | protected: | ||||
| UI* const kUi; | UI* const kUi; | ||||
| UIPrivateData* const kData; | UIPrivateData* const kData; | ||||
| #ifdef DISTRHO_UI_QT4 | #ifdef DISTRHO_UI_QT4 | ||||
| // FIXME - remove qtMouseDown usage | |||||
| bool eventFilter(QObject* obj, QEvent* event) | bool eventFilter(QObject* obj, QEvent* event) | ||||
| { | { | ||||
| assert(kUi != nullptr); | assert(kUi != nullptr); | ||||
| @@ -378,52 +396,40 @@ protected: | |||||
| return false; | return false; | ||||
| if (kData == nullptr) | if (kData == nullptr) | ||||
| return false; | return false; | ||||
| if (kData->widget == nullptr) | |||||
| return false; | |||||
| if (qtGrip == nullptr) | if (qtGrip == nullptr) | ||||
| return false; | return false; | ||||
| if (qtWidget == nullptr) | if (qtWidget == nullptr) | ||||
| return false; | return false; | ||||
| Qt4UI* qt4Ui = (Qt4UI*)kUi; | |||||
| if (obj == nullptr) | if (obj == nullptr) | ||||
| { | { | ||||
| // nothing | // nothing | ||||
| } | } | ||||
| else if (obj == qtGrip) | else if (obj == qtGrip) | ||||
| { | { | ||||
| if (event->type() == QEvent::MouseButtonPress) | |||||
| if (event->type() == QEvent::MouseMove) | |||||
| { | { | ||||
| QMouseEvent* mEvent = (QMouseEvent*)event; | QMouseEvent* mEvent = (QMouseEvent*)event; | ||||
| if (mEvent->button() == Qt::LeftButton) | if (mEvent->button() == Qt::LeftButton) | ||||
| qtMouseDown = true; | |||||
| } | |||||
| else if (event->type() == QEvent::MouseMove) | |||||
| { | |||||
| if (qtMouseDown) | |||||
| { | { | ||||
| Qt4UI* qtUi = (Qt4UI*)kUi; | |||||
| QMouseEvent* mEvent = (QMouseEvent*)event; | |||||
| unsigned int width = qtUi->d_width() + mEvent->x() - qtGrip->width(); | |||||
| unsigned int height = qtUi->d_height() + mEvent->y() - qtGrip->height(); | |||||
| unsigned int width = qt4Ui->d_width() + mEvent->x() - qtGrip->width(); | |||||
| unsigned int height = qt4Ui->d_height() + mEvent->y() - qtGrip->height(); | |||||
| if (width < qtUi->d_minimumWidth()) | |||||
| width = qtUi->d_minimumWidth(); | |||||
| if (height < qtUi->d_minimumHeight()) | |||||
| height = qtUi->d_minimumHeight(); | |||||
| if (width < qt4Ui->d_minimumWidth()) | |||||
| width = qt4Ui->d_minimumWidth(); | |||||
| if (height < qt4Ui->d_minimumHeight()) | |||||
| height = qt4Ui->d_minimumHeight(); | |||||
| kData->widget->setFixedSize(width, height); | |||||
| qt4Ui->setFixedSize(width, height); | |||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| else if (event->type() == QEvent::MouseButtonRelease) | |||||
| { | |||||
| QMouseEvent* mEvent = (QMouseEvent*)event; | |||||
| if (mEvent->button() == Qt::LeftButton) | |||||
| qtMouseDown = false; | |||||
| } | |||||
| } | } | ||||
| else if (obj == kData->widget && event->type() == QEvent::Resize) | |||||
| else if (obj == qt4Ui && event->type() == QEvent::Resize) | |||||
| { | { | ||||
| QResizeEvent* rEvent = (QResizeEvent*)event; | QResizeEvent* rEvent = (QResizeEvent*)event; | ||||
| const QSize& size = rEvent->size(); | const QSize& size = rEvent->size(); | ||||
| @@ -437,15 +443,6 @@ protected: | |||||
| return QObject::eventFilter(obj, event); | return QObject::eventFilter(obj, event); | ||||
| } | } | ||||
| #endif | #endif | ||||
| private: | |||||
| #ifdef DISTRHO_UI_QT4 | |||||
| bool qtMouseDown; | |||||
| QSizeGrip* qtGrip; | |||||
| QEmbedWidget* qtWidget; | |||||
| #else | |||||
| bool glInitiated; | |||||
| #endif | |||||
| }; | }; | ||||
| // ------------------------------------------------- | // ------------------------------------------------- | ||||
| @@ -0,0 +1,41 @@ | |||||
| /* | |||||
| * 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 "DistrhoUIInternal.hpp" | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ------------------------------------------------- | |||||
| // Static data | |||||
| Window* d_lastParent = nullptr; | |||||
| // ------------------------------------------------- | |||||
| // OpenGLUI | |||||
| OpenGLUI::OpenGLUI() | |||||
| : UI(), | |||||
| Widget(d_lastParent) | |||||
| { | |||||
| } | |||||
| OpenGLUI::~OpenGLUI() | |||||
| { | |||||
| } | |||||
| // ------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| @@ -58,13 +58,6 @@ Qt4UI::~Qt4UI() | |||||
| { | { | ||||
| } | } | ||||
| // ------------------------------------------------- | |||||
| // UI Callbacks | |||||
| void Qt4UI::d_uiIdle() | |||||
| { | |||||
| } | |||||
| // ------------------------------------------------- | // ------------------------------------------------- | ||||
| // Implement resize internally | // Implement resize internally | ||||