@@ -82,11 +82,6 @@ protected: | |||
private: | |||
UIPrivateData* const pData; | |||
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 | |||
virtual void d_uiIdle(); | |||
virtual void d_uiIdle() {} | |||
private: | |||
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 | |||
#ifdef DISTRHO_UI_QT4 | |||
pData->widget = (Qt4UI*)this; | |||
pData->ui = (Qt4UI*)this; | |||
#else | |||
pData->ui = (OpenGLUI*)this; | |||
#endif | |||
} | |||
@@ -19,13 +19,11 @@ | |||
#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 <QtGui/QMouseEvent> | |||
# include <QtGui/QResizeEvent> | |||
@@ -34,30 +32,26 @@ | |||
# ifdef Q_WS_X11 | |||
# include <QtGui/QX11EmbedWidget> | |||
# endif | |||
//#endif | |||
#endif | |||
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 (*setParamFunc) (void* ptr, uint32_t index, float 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 (*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 | |||
class QEmbedWidget : public QX11EmbedWidget | |||
# else | |||
@@ -71,7 +65,7 @@ public: | |||
void embedInto(WId id); | |||
WId containerWinId() const; | |||
}; | |||
//#endif | |||
#endif | |||
// ------------------------------------------------- | |||
@@ -80,27 +74,23 @@ struct UIPrivateData { | |||
double sampleRate; | |||
uint32_t parameterOffset; | |||
// UI | |||
void* ptr; | |||
NativeWidget* widget; | |||
// Callbacks | |||
editParamFunc editParamCallbackFunc; | |||
setParamFunc setParamCallbackFunc; | |||
setStateFunc setStateCallbackFunc; | |||
sendNoteFunc sendNoteCallbackFunc; | |||
uiResizeFunc uiResizeCallbackFunc; | |||
void* ptr; | |||
UIPrivateData() | |||
: sampleRate(d_lastUiSampleRate), | |||
parameterOffset(0), | |||
ptr(nullptr), | |||
widget(nullptr), | |||
editParamCallbackFunc(nullptr), | |||
setParamCallbackFunc(nullptr), | |||
setStateCallbackFunc(nullptr), | |||
sendNoteCallbackFunc(nullptr), | |||
uiResizeCallbackFunc(nullptr) | |||
uiResizeCallbackFunc(nullptr), | |||
ptr(nullptr) | |||
{ | |||
assert(d_lastUiSampleRate != 0.0); | |||
} | |||
@@ -150,15 +140,14 @@ class UIInternal | |||
{ | |||
public: | |||
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 | |||
qtMouseDown(false), | |||
qtGrip(nullptr), | |||
qtWidget(nullptr) | |||
: qtGrip(nullptr), | |||
qtWidget(nullptr), | |||
#else | |||
glInitiated(false) | |||
: glWindow(createWindow(winId)), | |||
#endif | |||
kUi(createUI()), | |||
kData((kUi != nullptr) ? kUi->pData : nullptr) | |||
{ | |||
assert(kUi != nullptr); | |||
assert(winId != 0); | |||
@@ -173,7 +162,11 @@ public: | |||
kData->sendNoteCallbackFunc = sendNoteCall; | |||
kData->uiResizeCallbackFunc = uiResizeCall; | |||
#ifdef DISTRHO_UI_QT4 | |||
createWindow(winId); | |||
#else | |||
d_lastUiParent = nullptr; | |||
#endif | |||
} | |||
~UIInternal() | |||
@@ -255,20 +248,22 @@ public: | |||
kUi->d_uiIdle(); | |||
} | |||
intptr_t getWindowId() | |||
intptr_t getWinId() | |||
{ | |||
#ifdef DISTRHO_UI_QT4 | |||
assert(qtWidget != nullptr); | |||
return (qtWidget != nullptr) ? qtWidget->winId() : 0; | |||
#else | |||
assert(glWindow != nullptr); | |||
return (glWindow != nullptr) ? glWindow->getWindowId() : 0; | |||
#endif | |||
} | |||
// --------------------------------------------- | |||
#ifdef DISTRHO_UI_QT4 | |||
void createWindow(intptr_t parent) | |||
{ | |||
#ifdef DISTRHO_UI_QT4 | |||
assert(kUi != nullptr); | |||
assert(kData != nullptr); | |||
assert(kData->widget != nullptr); | |||
@@ -279,14 +274,12 @@ public: | |||
return; | |||
if (kData == nullptr) | |||
return; | |||
if (kData->widget == nullptr) | |||
return; | |||
if (qtGrip != nullptr) | |||
return; | |||
if (qtWidget != nullptr) | |||
return; | |||
qtMouseDown = false; | |||
Qt4UI* qt4Ui = (Qt4UI*)kUi; | |||
// create embedable widget | |||
qtWidget = new QEmbedWidget; | |||
@@ -298,10 +291,10 @@ public: | |||
qtWidget->setFixedSize(kUi->d_width(), kUi->d_height()); | |||
// set resize grip | |||
if (((Qt4UI*)kUi)->d_resizable()) | |||
if (qt4Ui->d_resizable()) | |||
{ | |||
// listen for resize on the plugin widget | |||
kData->widget->installEventFilter(this); | |||
qt4Ui->installEventFilter(this); | |||
// create resize grip on bottom-right | |||
qtGrip = new QSizeGrip(qtWidget); | |||
@@ -318,9 +311,15 @@ public: | |||
// show it | |||
qtWidget->show(); | |||
} | |||
#else | |||
#endif | |||
Window* createWindow(intptr_t parent) | |||
{ | |||
Window* window = new Window(&glApp, parent); | |||
d_lastParent = window; | |||
return window; | |||
} | |||
#endif | |||
void destroyWindow() | |||
{ | |||
@@ -331,16 +330,16 @@ public: | |||
if (kData == nullptr) | |||
return; | |||
if (kData->widget == nullptr) | |||
return; | |||
if (qtWidget == nullptr) | |||
return; | |||
Qt4UI* qt4Ui = (Qt4UI*)kUi; | |||
// 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->removeEventFilter(this); | |||
@@ -355,17 +354,36 @@ public: | |||
delete qtWidget; | |||
qtWidget = nullptr; | |||
#else | |||
assert(kData != nullptr); | |||
assert(glWindow != nullptr); | |||
if (kData == nullptr) | |||
return; | |||
if (glWindow == nullptr) | |||
return; | |||
glWindow->hide(); | |||
delete glWindow; | |||
glWindow = nullptr; | |||
#endif | |||
} | |||
// --------------------------------------------- | |||
private: | |||
#ifdef DISTRHO_UI_QT4 | |||
QSizeGrip* qtGrip; | |||
QEmbedWidget* qtWidget; | |||
#else | |||
App glApp; | |||
Window* glWindow; | |||
#endif | |||
protected: | |||
UI* const kUi; | |||
UIPrivateData* const kData; | |||
#ifdef DISTRHO_UI_QT4 | |||
// FIXME - remove qtMouseDown usage | |||
bool eventFilter(QObject* obj, QEvent* event) | |||
{ | |||
assert(kUi != nullptr); | |||
@@ -378,52 +396,40 @@ protected: | |||
return false; | |||
if (kData == nullptr) | |||
return false; | |||
if (kData->widget == nullptr) | |||
return false; | |||
if (qtGrip == nullptr) | |||
return false; | |||
if (qtWidget == nullptr) | |||
return false; | |||
Qt4UI* qt4Ui = (Qt4UI*)kUi; | |||
if (obj == nullptr) | |||
{ | |||
// nothing | |||
} | |||
else if (obj == qtGrip) | |||
{ | |||
if (event->type() == QEvent::MouseButtonPress) | |||
if (event->type() == QEvent::MouseMove) | |||
{ | |||
QMouseEvent* mEvent = (QMouseEvent*)event; | |||
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; | |||
} | |||
} | |||
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; | |||
const QSize& size = rEvent->size(); | |||
@@ -437,15 +443,6 @@ protected: | |||
return QObject::eventFilter(obj, event); | |||
} | |||
#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 | |||