| @@ -189,6 +189,8 @@ endif | |||
| ifeq ($(HAVE_DGL),true) | |||
| DGL_FLAGS += -DHAVE_DGL | |||
| ifeq ($(MACOS),true) | |||
| DGL_LIBS = -framework OpenGL -framework Cocoa | |||
| endif | |||
| @@ -198,8 +200,8 @@ DGL_LIBS = -lopengl32 -lgdi32 | |||
| endif | |||
| ifneq ($(MACOS_OR_WIN32),true) | |||
| DGL_FLAGS = $(shell pkg-config --cflags gl x11) | |||
| DGL_LIBS = $(shell pkg-config --libs gl x11) | |||
| DGL_FLAGS += $(shell pkg-config --cflags gl x11) | |||
| DGL_LIBS += $(shell pkg-config --libs gl x11) | |||
| endif | |||
| endif # HAVE_DGL | |||
| @@ -73,6 +73,8 @@ | |||
| // ----------------------------------------------------------------------- | |||
| // OpenGL includes | |||
| #if defined(HAVE_DGL) | |||
| #ifdef DISTRHO_OS_MAC | |||
| # include <OpenGL/gl.h> | |||
| #else | |||
| @@ -83,9 +85,20 @@ | |||
| # include <GL/glext.h> | |||
| #endif | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // Cairo includes | |||
| #if defined(HAVE_DCAIRO) | |||
| # include <cairo/cairo.h> | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // Missing OpenGL defines | |||
| #if defined(HAVE_DGL) | |||
| #if defined(GL_BGR_EXT) && ! defined(GL_BGR) | |||
| # define GL_BGR GL_BGR_EXT | |||
| #endif | |||
| @@ -98,6 +111,8 @@ | |||
| # define GL_CLAMP_TO_BORDER 0x812D | |||
| #endif | |||
| #endif | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| // ----------------------------------------------------------------------- | |||
| // Fix OpenGL includes for Windows, based on glfw code | |||
| @@ -19,7 +19,9 @@ | |||
| #include "Base.hpp" | |||
| #if !defined(HAVE_DCAIRO) | |||
| struct NVGcolor; | |||
| #endif | |||
| START_NAMESPACE_DGL | |||
| @@ -95,12 +97,14 @@ struct Color { | |||
| */ | |||
| void fixBounds() noexcept; | |||
| #if !defined(HAVE_DCAIRO) | |||
| /** | |||
| @internal | |||
| Needed for NanoVG compatibility. | |||
| */ | |||
| Color(const NVGcolor&) noexcept; | |||
| operator NVGcolor() const noexcept; | |||
| #endif | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -346,10 +346,12 @@ public: | |||
| */ | |||
| void moveBy(const Point<T>& pos) noexcept; | |||
| #if defined(HAVE_DGL) | |||
| /** | |||
| Draw this line using the current OpenGL state. | |||
| */ | |||
| void draw(); | |||
| #endif | |||
| /** | |||
| Return true if line is null (start and end pos are equal). | |||
| @@ -460,6 +462,7 @@ public: | |||
| */ | |||
| void setNumSegments(const uint num); | |||
| #if defined(HAVE_DGL) | |||
| /** | |||
| Draw this circle using the current OpenGL state. | |||
| */ | |||
| @@ -469,6 +472,7 @@ public: | |||
| Draw lines (outline of this circle) using the current OpenGL state. | |||
| */ | |||
| void drawOutline(); | |||
| #endif | |||
| Circle<T>& operator=(const Circle<T>& cir) noexcept; | |||
| bool operator==(const Circle<T>& cir) const noexcept; | |||
| @@ -482,7 +486,9 @@ private: | |||
| // cached values | |||
| float fTheta, fCos, fSin; | |||
| #if defined(HAVE_DGL) | |||
| void _draw(const bool outline); | |||
| #endif | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -516,6 +522,7 @@ public: | |||
| */ | |||
| Triangle(const Triangle<T>& tri) noexcept; | |||
| #if defined(HAVE_DGL) | |||
| /** | |||
| Draw this triangle using the current OpenGL state. | |||
| */ | |||
| @@ -525,6 +532,7 @@ public: | |||
| Draw lines (outline of this triangle) using the current OpenGL state. | |||
| */ | |||
| void drawOutline(); | |||
| #endif | |||
| /** | |||
| Return true if triangle is null (all its points are equal). | |||
| @@ -556,7 +564,9 @@ public: | |||
| private: | |||
| Point<T> fPos1, fPos2, fPos3; | |||
| #if defined(HAVE_DGL) | |||
| void _draw(const bool outline); | |||
| #endif | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -720,6 +730,7 @@ public: | |||
| */ | |||
| bool containsY(const T& y) const noexcept; | |||
| #if defined(HAVE_DGL) | |||
| /** | |||
| Draw this rectangle using the current OpenGL state. | |||
| */ | |||
| @@ -729,6 +740,7 @@ public: | |||
| Draw lines (outline of this rectangle) using the current OpenGL state. | |||
| */ | |||
| void drawOutline(); | |||
| #endif | |||
| Rectangle<T>& operator=(const Rectangle<T>& rect) noexcept; | |||
| Rectangle<T>& operator*=(double m) noexcept; | |||
| @@ -740,7 +752,9 @@ private: | |||
| Point<T> fPos; | |||
| Size<T> fSize; | |||
| #if defined(HAVE_DGL) | |||
| void _draw(const bool outline); | |||
| #endif | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -312,6 +312,10 @@ public: | |||
| */ | |||
| Window& getParentWindow() const noexcept; | |||
| #if defined(HAVE_DCAIRO) | |||
| cairo_t* getGraphics() const noexcept; | |||
| #endif | |||
| /** | |||
| Check if this widget contains the point defined by @a x and @a y. | |||
| */ | |||
| @@ -119,6 +119,10 @@ public: | |||
| Application& getApp() const noexcept; | |||
| intptr_t getWindowId() const noexcept; | |||
| #if defined(HAVE_DCAIRO) | |||
| cairo_t* getGraphics() const noexcept; | |||
| #endif | |||
| void addIdleCallback(IdleCallback* const callback); | |||
| void removeIdleCallback(IdleCallback* const callback); | |||
| @@ -16,7 +16,9 @@ | |||
| #include "../Color.hpp" | |||
| #if !defined(HAVE_DCAIRO) | |||
| #include "nanovg/nanovg.h" | |||
| #endif | |||
| START_NAMESPACE_DGL | |||
| @@ -105,7 +107,36 @@ Color::Color(const Color& color1, const Color& color2, float u) noexcept | |||
| Color Color::fromHSL(float hue, float saturation, float lightness, float alpha) | |||
| { | |||
| #if defined(HAVE_DGL) | |||
| return nvgHSLA(hue, saturation, lightness, static_cast<uchar>(getFixedRange(alpha)*255.0f)); | |||
| #else | |||
| float m1, m2; | |||
| Color col; | |||
| hue = fmodf(hue, 1.0f); | |||
| if (hue < 0.0f) hue += 1.0f; | |||
| fixRange(saturation); | |||
| fixRange(lightness); | |||
| m2 = lightness <= 0.5f ? (lightness * (1 + saturation)) : (lightness + saturation - lightness * saturation); | |||
| m1 = 2 * lightness - m2; | |||
| auto hue_ = [](float h, float m1, float m2) -> float | |||
| { | |||
| if (h < 0) h += 1; | |||
| if (h > 1) h -= 1; | |||
| if (h < 1.0f/6.0f) | |||
| return m1 + (m2 - m1) * h * 6.0f; | |||
| else if (h < 3.0f/6.0f) | |||
| return m2; | |||
| else if (h < 4.0f/6.0f) | |||
| return m1 + (m2 - m1) * (2.0f/3.0f - h) * 6.0f; | |||
| return m1; | |||
| }; | |||
| col.red = hue_(hue + 1.0f/3.0f, m1, m2); | |||
| col.green = hue_(hue, m1, m2); | |||
| col.blue = hue_(hue - 1.0f/3.0f, m1, m2); | |||
| col.alpha = alpha; | |||
| col.fixBounds(); | |||
| return col; | |||
| #endif | |||
| } | |||
| Color Color::fromHTML(const char* rgb, float alpha) | |||
| @@ -224,6 +255,7 @@ void Color::fixBounds() noexcept | |||
| // ----------------------------------------------------------------------- | |||
| #if !defined(HAVE_DCAIRO) | |||
| Color::Color(const NVGcolor& c) noexcept | |||
| : red(c.r), green(c.g), blue(c.b), alpha(c.a) | |||
| { | |||
| @@ -239,6 +271,7 @@ Color::operator NVGcolor() const noexcept | |||
| nc.a = alpha; | |||
| return nc; | |||
| } | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| @@ -441,6 +441,7 @@ void Line<T>::moveBy(const Point<T>& pos) noexcept | |||
| fPosEnd.moveBy(pos); | |||
| } | |||
| #if defined(HAVE_DGL) | |||
| template<typename T> | |||
| void Line<T>::draw() | |||
| { | |||
| @@ -455,6 +456,7 @@ void Line<T>::draw() | |||
| glEnd(); | |||
| } | |||
| #endif | |||
| template<typename T> | |||
| bool Line<T>::isNull() const noexcept | |||
| @@ -614,6 +616,7 @@ void Circle<T>::setNumSegments(const uint num) | |||
| fSin = std::sin(fTheta); | |||
| } | |||
| #if defined(HAVE_DGL) | |||
| template<typename T> | |||
| void Circle<T>::draw() | |||
| { | |||
| @@ -625,6 +628,7 @@ void Circle<T>::drawOutline() | |||
| { | |||
| _draw(true); | |||
| } | |||
| #endif | |||
| template<typename T> | |||
| Circle<T>& Circle<T>::operator=(const Circle<T>& cir) noexcept | |||
| @@ -650,6 +654,7 @@ bool Circle<T>::operator!=(const Circle<T>& cir) const noexcept | |||
| return (fPos != cir.fPos || d_isNotEqual(fSize, cir.fSize) || fNumSegments != cir.fNumSegments); | |||
| } | |||
| #if defined(HAVE_DGL) | |||
| template<typename T> | |||
| void Circle<T>::_draw(const bool outline) | |||
| { | |||
| @@ -670,6 +675,7 @@ void Circle<T>::_draw(const bool outline) | |||
| glEnd(); | |||
| } | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // Triangle | |||
| @@ -698,6 +704,7 @@ Triangle<T>::Triangle(const Triangle<T>& tri) noexcept | |||
| fPos2(tri.fPos2), | |||
| fPos3(tri.fPos3) {} | |||
| #if defined(HAVE_DGL) | |||
| template<typename T> | |||
| void Triangle<T>::draw() | |||
| { | |||
| @@ -709,6 +716,7 @@ void Triangle<T>::drawOutline() | |||
| { | |||
| _draw(true); | |||
| } | |||
| #endif | |||
| template<typename T> | |||
| bool Triangle<T>::isNull() const noexcept | |||
| @@ -755,6 +763,7 @@ bool Triangle<T>::operator!=(const Triangle<T>& tri) const noexcept | |||
| return (fPos1 != tri.fPos1 || fPos2 != tri.fPos2 || fPos3 != tri.fPos3); | |||
| } | |||
| #if defined(HAVE_DGL) | |||
| template<typename T> | |||
| void Triangle<T>::_draw(const bool outline) | |||
| { | |||
| @@ -770,6 +779,7 @@ void Triangle<T>::_draw(const bool outline) | |||
| glEnd(); | |||
| } | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // Rectangle | |||
| @@ -952,6 +962,7 @@ bool Rectangle<T>::containsY(const T& y) const noexcept | |||
| return (y >= fPos.fY && y <= fPos.fY + fSize.fHeight); | |||
| } | |||
| #if defined(HAVE_DGL) | |||
| template<typename T> | |||
| void Rectangle<T>::draw() | |||
| { | |||
| @@ -963,6 +974,7 @@ void Rectangle<T>::drawOutline() | |||
| { | |||
| _draw(true); | |||
| } | |||
| #endif | |||
| template<typename T> | |||
| Rectangle<T>& Rectangle<T>::operator=(const Rectangle<T>& rect) noexcept | |||
| @@ -998,6 +1010,7 @@ bool Rectangle<T>::operator!=(const Rectangle<T>& rect) const noexcept | |||
| return (fPos != rect.fPos || fSize != rect.fSize); | |||
| } | |||
| #if defined(HAVE_DGL) | |||
| template<typename T> | |||
| void Rectangle<T>::_draw(const bool outline) | |||
| { | |||
| @@ -1021,6 +1034,7 @@ void Rectangle<T>::_draw(const bool outline) | |||
| glEnd(); | |||
| } | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // Possible template data types | |||
| @@ -189,6 +189,13 @@ Window& Widget::getParentWindow() const noexcept | |||
| return pData->parent; | |||
| } | |||
| #if defined(HAVE_DCAIRO) | |||
| cairo_t* Widget::getGraphics() const noexcept | |||
| { | |||
| return pData->parent.getGraphics(); | |||
| } | |||
| #endif | |||
| bool Widget::contains(int x, int y) const noexcept | |||
| { | |||
| return (x >= 0 && y >= 0 && static_cast<uint>(x) < pData->size.getWidth() && static_cast<uint>(y) < pData->size.getHeight()); | |||
| @@ -68,6 +68,7 @@ struct Widget::PrivateData { | |||
| if ((skipDisplay && ! renderingSubWidget) || size.isInvalid() || ! visible) | |||
| return; | |||
| #if defined(HAVE_DGL) | |||
| bool needsDisableScissor = false; | |||
| // reset color | |||
| @@ -106,15 +107,18 @@ struct Widget::PrivateData { | |||
| glEnable(GL_SCISSOR_TEST); | |||
| needsDisableScissor = true; | |||
| } | |||
| #endif | |||
| // display widget | |||
| self->onDisplay(); | |||
| #if defined(HAVE_DGL) | |||
| if (needsDisableScissor) | |||
| { | |||
| glDisable(GL_SCISSOR_TEST); | |||
| needsDisableScissor = false; | |||
| } | |||
| #endif | |||
| displaySubWidgets(width, height, scaling); | |||
| } | |||
| @@ -19,6 +19,16 @@ | |||
| #include "../Base.hpp" | |||
| #undef PUGL_HAVE_CAIRO | |||
| #undef PUGL_HAVE_GL | |||
| #if defined(HAVE_DGL) | |||
| #define PUGL_HAVE_GL 1 | |||
| #endif | |||
| #if defined(HAVE_DCAIRO) | |||
| #define PUGL_HAVE_CAIRO 1 | |||
| #endif | |||
| #include "pugl/pugl.h" | |||
| #if defined(__GNUC__) && (__GNUC__ >= 7) | |||
| @@ -203,6 +213,14 @@ struct Window::PrivateData { | |||
| return; | |||
| } | |||
| #if defined(HAVE_DGL) | |||
| PuglContextType contextType = PUGL_GL; | |||
| #endif | |||
| #if defined(HAVE_DCAIRO) | |||
| PuglContextType contextType = PUGL_CAIRO; | |||
| #endif | |||
| puglInitContextType(fView, contextType); | |||
| puglInitUserResizable(fView, fResizable); | |||
| puglInitWindowSize(fView, static_cast<int>(fWidth), static_cast<int>(fHeight)); | |||
| @@ -222,11 +240,12 @@ struct Window::PrivateData { | |||
| puglCreateWindow(fView, nullptr); | |||
| PuglInternals* impl = fView->impl; | |||
| #if defined(DISTRHO_OS_WINDOWS) | |||
| hwnd = impl->hwnd; | |||
| DISTRHO_SAFE_ASSERT(hwnd != 0); | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| mView = impl->glview; | |||
| mView = impl->view; | |||
| mWindow = impl->window; | |||
| DISTRHO_SAFE_ASSERT(mView != nullptr); | |||
| if (fUsingEmbed) { | |||
| @@ -1081,7 +1100,7 @@ struct Window::PrivateData { | |||
| HWND hwndParent; | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| bool fNeedsIdle; | |||
| PuglOpenGLView* mView; | |||
| NSView<PuglGenericView>* mView; | |||
| id mWindow; | |||
| id mParentWindow; | |||
| #else | |||
| @@ -1365,6 +1384,13 @@ intptr_t Window::getWindowId() const noexcept | |||
| return puglGetNativeWindow(pData->fView); | |||
| } | |||
| #if defined(HAVE_DCAIRO) | |||
| cairo_t* Window::getGraphics() const noexcept | |||
| { | |||
| return (cairo_t*)puglGetContext(pData->fView); | |||
| } | |||
| #endif | |||
| void Window::_addWidget(Widget* const widget) | |||
| { | |||
| pData->addWidget(widget); | |||
| @@ -1400,8 +1426,10 @@ void Window::removeIdleCallback(IdleCallback* const callback) | |||
| void Window::onDisplayBefore() | |||
| { | |||
| #if defined(HAVE_DGL) | |||
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |||
| glLoadIdentity(); | |||
| #endif | |||
| } | |||
| void Window::onDisplayAfter() | |||
| @@ -1410,6 +1438,7 @@ void Window::onDisplayAfter() | |||
| void Window::onReshape(uint width, uint height) | |||
| { | |||
| #if defined(HAVE_DGL) | |||
| glEnable(GL_BLEND); | |||
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||
| glMatrixMode(GL_PROJECTION); | |||
| @@ -1418,6 +1447,7 @@ void Window::onReshape(uint width, uint height) | |||
| glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height)); | |||
| glMatrixMode(GL_MODELVIEW); | |||
| glLoadIdentity(); | |||
| #endif | |||
| } | |||
| void Window::onClose() | |||
| @@ -273,6 +273,20 @@ puglInitUserResizable(PuglView* view, bool resizable); | |||
| PUGL_API void | |||
| puglInitTransientFor(PuglView* view, uintptr_t parent); | |||
| /** | |||
| Drawing context type. | |||
| */ | |||
| typedef enum { | |||
| PUGL_GL, | |||
| PUGL_CAIRO | |||
| } PuglContextType; | |||
| /** | |||
| Set the context type before creating a window. | |||
| */ | |||
| PUGL_API void | |||
| puglInitContextType(PuglView* view, PuglContextType type); | |||
| /** | |||
| @} | |||
| */ | |||
| @@ -349,6 +363,14 @@ puglSetHandle(PuglView* view, PuglHandle handle); | |||
| PUGL_API PuglHandle | |||
| puglGetHandle(PuglView* view); | |||
| /** | |||
| Get the drawing context. | |||
| For PUGL_GL contexts, this is unused and returns NULL. | |||
| For PUGL_CAIRO contexts, this returns a pointer to a cairo_t. | |||
| */ | |||
| PUGL_API void* | |||
| puglGetContext(PuglView* view); | |||
| /** | |||
| Return the timestamp (if any) of the currently-processing event. | |||
| */ | |||
| @@ -41,6 +41,7 @@ struct PuglViewImpl { | |||
| PuglInternals* impl; | |||
| PuglNativeWindow parent; | |||
| PuglContextType ctx_type; | |||
| uintptr_t transient_parent; | |||
| int width; | |||
| @@ -140,6 +141,12 @@ puglCreate(PuglNativeWindow parent, | |||
| return view; | |||
| } | |||
| void | |||
| puglInitContextType(PuglView* view, PuglContextType type) | |||
| { | |||
| view->ctx_type = type; | |||
| } | |||
| void | |||
| puglSetHandle(PuglView* view, PuglHandle handle) | |||
| { | |||
| @@ -239,6 +246,7 @@ puglLeaveContext(PuglView* view, bool flush); | |||
| static void | |||
| puglDefaultReshape(int width, int height) | |||
| { | |||
| #ifdef PUGL_HAVE_GL | |||
| #ifdef ROBTK_HERE | |||
| glViewport(0, 0, width, height); | |||
| glMatrixMode(GL_PROJECTION); | |||
| @@ -257,4 +265,5 @@ puglDefaultReshape(int width, int height) | |||
| glMatrixMode(GL_MODELVIEW); | |||
| glLoadIdentity(); | |||
| #endif | |||
| #endif | |||
| } | |||
| @@ -21,6 +21,10 @@ | |||
| #include <stdlib.h> | |||
| #import <Cocoa/Cocoa.h> | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| #import <cairo.h> | |||
| #import <cairo-quartz.h> | |||
| #endif | |||
| #include "pugl_internal.h" | |||
| @@ -93,7 +97,40 @@ puglDisplay(PuglView* view) | |||
| } | |||
| } | |||
| @interface PuglOpenGLView : NSOpenGLView | |||
| @protocol PuglGenericView | |||
| @required | |||
| - (PuglView *) puglView; | |||
| - (void) setPuglview:(PuglView *)pv; | |||
| @end | |||
| static unsigned | |||
| getModifiers(PuglView* view, NSEvent* ev) | |||
| { | |||
| const unsigned modifierFlags = [ev modifierFlags]; | |||
| view->event_timestamp_ms = fmod([ev timestamp] * 1000.0, UINT32_MAX); | |||
| unsigned 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; | |||
| } | |||
| static int | |||
| getFixedAppKitButton(NSInteger button) | |||
| { | |||
| switch (button) { | |||
| case 0: return 1; | |||
| case 1: return 3; | |||
| case 2: return 2; | |||
| default: return button; | |||
| } | |||
| } | |||
| #ifdef PUGL_HAVE_GL | |||
| @interface PuglOpenGLView : NSOpenGLView<PuglGenericView> | |||
| { | |||
| @public | |||
| PuglView* puglview; | |||
| @@ -101,6 +138,9 @@ puglDisplay(PuglView* view) | |||
| bool doubleBuffered; | |||
| } | |||
| - (PuglView *) puglView; | |||
| - (void) setPuglview:(PuglView *)pv; | |||
| - (BOOL) acceptsFirstMouse:(NSEvent*)e; | |||
| - (BOOL) acceptsFirstResponder; | |||
| - (BOOL) isFlipped; | |||
| @@ -130,6 +170,13 @@ puglDisplay(PuglView* view) | |||
| @end | |||
| @implementation PuglOpenGLView | |||
| - (PuglView *) puglView { | |||
| return self->puglview; | |||
| } | |||
| - (void) setPuglview:(PuglView *)pv { | |||
| self->puglview = pv; | |||
| } | |||
| - (BOOL) acceptsFirstMouse:(NSEvent*)e | |||
| { | |||
| @@ -277,32 +324,296 @@ puglDisplay(PuglView* view) | |||
| [super viewWillMoveToWindow:newWindow]; | |||
| } | |||
| static unsigned | |||
| getModifiers(PuglView* view, NSEvent* ev) | |||
| - (void) mouseMoved:(NSEvent*)event | |||
| { | |||
| const unsigned modifierFlags = [ev modifierFlags]; | |||
| if (puglview->motionFunc) { | |||
| NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; | |||
| puglview->mods = getModifiers(puglview, event); | |||
| puglview->motionFunc(puglview, loc.x, loc.y); | |||
| } | |||
| } | |||
| view->event_timestamp_ms = fmod([ev timestamp] * 1000.0, UINT32_MAX); | |||
| - (void) mouseDragged:(NSEvent*)event | |||
| { | |||
| [self mouseMoved:event]; | |||
| } | |||
| unsigned 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) rightMouseDragged:(NSEvent*)event | |||
| { | |||
| [self mouseDragged:event]; | |||
| } | |||
| static int | |||
| getFixedAppKitButton(NSInteger button) | |||
| - (void) otherMouseDragged:(NSEvent*)event | |||
| { | |||
| switch (button) { | |||
| case 0: return 1; | |||
| case 1: return 3; | |||
| case 2: return 2; | |||
| default: return button; | |||
| [self mouseDragged:event]; | |||
| } | |||
| - (void) mouseDown:(NSEvent*)event | |||
| { | |||
| if (puglview->mouseFunc) { | |||
| NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; | |||
| puglview->mods = getModifiers(puglview, event); | |||
| puglview->mouseFunc(puglview, getFixedAppKitButton([event buttonNumber]), true, loc.x, loc.y); | |||
| } | |||
| } | |||
| - (void) rightMouseDown:(NSEvent*)event | |||
| { | |||
| [self mouseDown:event]; | |||
| } | |||
| - (void) otherMouseDown:(NSEvent*)event | |||
| { | |||
| [self mouseDown:event]; | |||
| } | |||
| - (void) mouseUp:(NSEvent*)event | |||
| { | |||
| if (puglview->mouseFunc) { | |||
| NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; | |||
| puglview->mods = getModifiers(puglview, event); | |||
| puglview->mouseFunc(puglview, getFixedAppKitButton([event buttonNumber]), false, loc.x, loc.y); | |||
| } | |||
| } | |||
| - (void) rightMouseUp:(NSEvent*)event | |||
| { | |||
| [self mouseUp:event]; | |||
| } | |||
| - (void) otherMouseUp:(NSEvent*)event | |||
| { | |||
| [self mouseUp:event]; | |||
| } | |||
| - (void) scrollWheel:(NSEvent*)event | |||
| { | |||
| if (puglview->scrollFunc) { | |||
| NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; | |||
| puglview->mods = getModifiers(puglview, event); | |||
| puglview->scrollFunc(puglview, | |||
| loc.x, loc.y, | |||
| [event deltaX], [event deltaY]); | |||
| } | |||
| } | |||
| - (void) keyDown:(NSEvent*)event | |||
| { | |||
| if (puglview->keyboardFunc && !(puglview->ignoreKeyRepeat && [event isARepeat])) { | |||
| NSString* chars = [event characters]; | |||
| puglview->mods = getModifiers(puglview, event); | |||
| puglview->keyboardFunc(puglview, true, [chars characterAtIndex:0]); | |||
| } | |||
| } | |||
| - (void) keyUp:(NSEvent*)event | |||
| { | |||
| if (puglview->keyboardFunc) { | |||
| NSString* chars = [event characters]; | |||
| puglview->mods = getModifiers(puglview, event); | |||
| puglview->keyboardFunc(puglview, false, [chars characterAtIndex:0]); | |||
| } | |||
| } | |||
| - (void) flagsChanged:(NSEvent*)event | |||
| { | |||
| if (puglview->specialFunc) { | |||
| const unsigned mods = getModifiers(puglview, event); | |||
| if ((mods & PUGL_MOD_SHIFT) != (puglview->mods & PUGL_MOD_SHIFT)) { | |||
| puglview->specialFunc(puglview, mods & PUGL_MOD_SHIFT, PUGL_KEY_SHIFT); | |||
| } else if ((mods & PUGL_MOD_CTRL) != (puglview->mods & PUGL_MOD_CTRL)) { | |||
| puglview->specialFunc(puglview, mods & PUGL_MOD_CTRL, PUGL_KEY_CTRL); | |||
| } else if ((mods & PUGL_MOD_ALT) != (puglview->mods & PUGL_MOD_ALT)) { | |||
| puglview->specialFunc(puglview, mods & PUGL_MOD_ALT, PUGL_KEY_ALT); | |||
| } else if ((mods & PUGL_MOD_SUPER) != (puglview->mods & PUGL_MOD_SUPER)) { | |||
| puglview->specialFunc(puglview, mods & PUGL_MOD_SUPER, PUGL_KEY_SUPER); | |||
| } | |||
| puglview->mods = mods; | |||
| } | |||
| } | |||
| @end | |||
| #endif | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| @interface PuglCairoView : NSView<PuglGenericView> | |||
| { | |||
| PuglView* puglview; | |||
| cairo_t* cr; | |||
| NSTrackingArea* trackingArea; | |||
| } | |||
| - (PuglView *) puglView; | |||
| - (void) setPuglview:(PuglView *)pv; | |||
| - (cairo_t *) cairoContext; | |||
| - (BOOL) acceptsFirstMouse:(NSEvent*)e; | |||
| - (BOOL) acceptsFirstResponder; | |||
| - (BOOL) isFlipped; | |||
| - (BOOL) isOpaque; | |||
| - (BOOL) preservesContentInLiveResize; | |||
| - (id) initWithFrame:(NSRect)frame; | |||
| - (void) reshape; | |||
| - (void) drawRect:(NSRect)r; | |||
| /* TODO: duplication of code from PuglOpenGLView */ | |||
| - (void) cursorUpdate:(NSEvent*)e; | |||
| - (void) updateTrackingAreas; | |||
| - (void) viewWillMoveToWindow:(NSWindow*)newWindow; | |||
| - (void) mouseMoved:(NSEvent*)event; | |||
| - (void) mouseDragged:(NSEvent*)event; | |||
| - (void) rightMouseDragged:(NSEvent*)event; | |||
| - (void) otherMouseDragged:(NSEvent*)event; | |||
| - (void) mouseDown:(NSEvent*)event; | |||
| - (void) rightMouseDown:(NSEvent*)event; | |||
| - (void) otherMouseDown:(NSEvent*)event; | |||
| - (void) mouseUp:(NSEvent*)event; | |||
| - (void) rightMouseUp:(NSEvent*)event; | |||
| - (void) otherMouseUp:(NSEvent*)event; | |||
| - (void) scrollWheel:(NSEvent*)event; | |||
| - (void) keyDown:(NSEvent*)event; | |||
| - (void) keyUp:(NSEvent*)event; | |||
| - (void) flagsChanged:(NSEvent*)event; | |||
| @end | |||
| @implementation PuglCairoView | |||
| - (PuglView *) puglView { | |||
| return self->puglview; | |||
| } | |||
| - (void) setPuglview:(PuglView *)pv { | |||
| self->puglview = pv; | |||
| } | |||
| - (cairo_t *) cairoContext { | |||
| return cr; | |||
| } | |||
| - (BOOL) acceptsFirstMouse:(NSEvent*)e | |||
| { | |||
| return YES; | |||
| // unused | |||
| (void)e; | |||
| } | |||
| - (BOOL) acceptsFirstResponder | |||
| { | |||
| return YES; | |||
| } | |||
| - (BOOL) isFlipped | |||
| { | |||
| return YES; | |||
| } | |||
| - (BOOL) isOpaque | |||
| { | |||
| return YES; | |||
| } | |||
| - (BOOL) preservesContentInLiveResize | |||
| { | |||
| return NO; | |||
| } | |||
| - (id) initWithFrame:(NSRect)frame { | |||
| puglview = nil; | |||
| cr = NULL; | |||
| trackingArea = nil; | |||
| [super initWithFrame:frame]; | |||
| return self; | |||
| } | |||
| - (void) reshape | |||
| { | |||
| if (!puglview) { | |||
| /* NOTE: Apparently reshape gets called when the GC gets around to | |||
| deleting the view (?), so we must have reset puglview to NULL when | |||
| this comes around. | |||
| */ | |||
| return; | |||
| } | |||
| NSRect bounds = [self bounds]; | |||
| int width = bounds.size.width; | |||
| int height = bounds.size.height; | |||
| puglEnterContext(puglview); | |||
| if (puglview->reshapeFunc) { | |||
| puglview->reshapeFunc(puglview, width, height); | |||
| } else { | |||
| puglDefaultReshape(width, height); | |||
| } | |||
| puglLeaveContext(puglview, false); | |||
| puglview->width = width; | |||
| puglview->height = height; | |||
| } | |||
| - (void) drawRect:(NSRect)r { | |||
| CGContextRef ctx = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; | |||
| NSRect bounds = [self bounds]; | |||
| cairo_surface_t* surface; | |||
| cairo_t* cairo; | |||
| surface = cairo_quartz_surface_create_for_cg_context(ctx, bounds.size.width, bounds.size.height); | |||
| if (surface) { | |||
| cairo = cairo_create(surface); | |||
| if (cairo) { | |||
| self->cr = cairo; | |||
| puglEnterContext(puglview); | |||
| puglDisplay(puglview); | |||
| puglLeaveContext(puglview, true); | |||
| self->cr = NULL; | |||
| cairo_destroy(cairo); | |||
| } | |||
| cairo_surface_destroy(surface); | |||
| } | |||
| } | |||
| - (void) cursorUpdate:(NSEvent*)e | |||
| { | |||
| [[NSCursor arrowCursor] set]; | |||
| // unused | |||
| return; (void)e; | |||
| } | |||
| - (void) updateTrackingAreas | |||
| { | |||
| static const int opts = NSTrackingMouseEnteredAndExited | |||
| | NSTrackingMouseMoved | |||
| | NSTrackingEnabledDuringMouseDrag | |||
| | NSTrackingInVisibleRect | |||
| | NSTrackingActiveAlways | |||
| | NSTrackingCursorUpdate; | |||
| if (trackingArea != nil) { | |||
| [self removeTrackingArea:trackingArea]; | |||
| [trackingArea release]; | |||
| } | |||
| trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] | |||
| options:opts | |||
| owner:self | |||
| userInfo:nil]; | |||
| [self addTrackingArea:trackingArea]; | |||
| [super updateTrackingAreas]; | |||
| } | |||
| - (void) viewWillMoveToWindow:(NSWindow*)newWindow | |||
| { | |||
| if (newWindow != nil) { | |||
| [newWindow setAcceptsMouseMovedEvents:YES]; | |||
| [newWindow makeFirstResponder:self]; | |||
| } | |||
| [super viewWillMoveToWindow:newWindow]; | |||
| } | |||
| - (void) mouseMoved:(NSEvent*)event | |||
| { | |||
| if (puglview->motionFunc) { | |||
| @@ -410,11 +721,19 @@ getFixedAppKitButton(NSInteger button) | |||
| puglview->mods = mods; | |||
| } | |||
| } | |||
| @end | |||
| #endif | |||
| struct PuglInternalsImpl { | |||
| PuglOpenGLView* glview; | |||
| union { | |||
| NSView<PuglGenericView>* view; | |||
| #ifdef PUGL_HAVE_GL | |||
| PuglOpenGLView* glview; | |||
| #endif | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| PuglCairoView* cairoview; | |||
| #endif | |||
| }; | |||
| id window; | |||
| }; | |||
| @@ -427,13 +746,18 @@ puglInitInternals() | |||
| void | |||
| puglEnterContext(PuglView* view) | |||
| { | |||
| [[view->impl->glview openGLContext] makeCurrentContext]; | |||
| #ifdef PUGL_HAVE_GL | |||
| if (view->ctx_type == PUGL_GL) { | |||
| [[view->impl->glview openGLContext] makeCurrentContext]; | |||
| } | |||
| #endif | |||
| } | |||
| void | |||
| puglLeaveContext(PuglView* view, bool flush) | |||
| { | |||
| if (flush) { | |||
| #ifdef PUGL_HAVE_GL | |||
| if (view->ctx_type == PUGL_GL && flush) { | |||
| if (view->impl->glview->doubleBuffered) { | |||
| [[view->impl->glview openGLContext] flushBuffer]; | |||
| } else { | |||
| @@ -441,6 +765,7 @@ puglLeaveContext(PuglView* view, bool flush) | |||
| } | |||
| //[NSOpenGLContext clearCurrentContext]; | |||
| } | |||
| #endif | |||
| } | |||
| int | |||
| @@ -451,22 +776,31 @@ puglCreateWindow(PuglView* view, const char* title) | |||
| [NSAutoreleasePool new]; | |||
| [NSApplication sharedApplication]; | |||
| impl->glview = [PuglOpenGLView new]; | |||
| #ifdef PUGL_HAVE_GL | |||
| if (view->ctx_type == PUGL_GL) { | |||
| impl->glview = [PuglOpenGLView new]; | |||
| } | |||
| #endif | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| if (view->ctx_type == PUGL_CAIRO) { | |||
| impl->cairoview = [PuglCairoView new]; | |||
| } | |||
| #endif | |||
| if (!impl->glview) { | |||
| if (!impl->view) { | |||
| return 1; | |||
| } | |||
| impl->glview->puglview = view; | |||
| [impl->view setPuglview:view]; | |||
| if (view->user_resizable) { | |||
| [impl->glview setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; | |||
| [impl->view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; | |||
| } | |||
| if (view->parent) { | |||
| [impl->glview retain]; | |||
| [impl->view retain]; | |||
| NSView* pview = (NSView*)view->parent; | |||
| [pview addSubview:impl->glview]; | |||
| [pview addSubview:impl->view]; | |||
| return 0; | |||
| } | |||
| @@ -482,8 +816,8 @@ puglCreateWindow(PuglView* view, const char* title) | |||
| } | |||
| [window setPuglview:view]; | |||
| [window setContentView:impl->glview]; | |||
| [window makeFirstResponder:impl->glview]; | |||
| [window setContentView:impl->view]; | |||
| [window makeFirstResponder:impl->view]; | |||
| [window makeKeyAndOrderFront:window]; | |||
| // wait for first puglShowWindow | |||
| @@ -505,7 +839,7 @@ puglShowWindow(PuglView* view) | |||
| if (impl->window) { | |||
| [impl->window setIsVisible:YES]; | |||
| } else { | |||
| [view->impl->glview setHidden:NO]; | |||
| [view->impl->view setHidden:NO]; | |||
| } | |||
| } | |||
| @@ -517,21 +851,21 @@ puglHideWindow(PuglView* view) | |||
| if (impl->window) { | |||
| [impl->window setIsVisible:NO]; | |||
| } else { | |||
| [impl->glview setHidden:YES]; | |||
| [impl->view setHidden:YES]; | |||
| } | |||
| } | |||
| void | |||
| puglDestroy(PuglView* view) | |||
| { | |||
| view->impl->glview->puglview = NULL; | |||
| [view->impl->view setPuglview:NULL]; | |||
| if (view->impl->window) { | |||
| [view->impl->window close]; | |||
| [view->impl->glview release]; | |||
| [view->impl->view release]; | |||
| [view->impl->window release]; | |||
| } else { | |||
| [view->impl->glview release]; | |||
| [view->impl->view release]; | |||
| } | |||
| free(view->impl); | |||
| @@ -551,13 +885,27 @@ void | |||
| puglPostRedisplay(PuglView* view) | |||
| { | |||
| view->redisplay = true; | |||
| [view->impl->glview setNeedsDisplay:YES]; | |||
| [view->impl->view setNeedsDisplay:YES]; | |||
| } | |||
| PuglNativeWindow | |||
| puglGetNativeWindow(PuglView* view) | |||
| { | |||
| return (PuglNativeWindow)view->impl->glview; | |||
| return (PuglNativeWindow)view->impl->view; | |||
| } | |||
| void* | |||
| puglGetContext(PuglView* view) | |||
| { | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| if (view->ctx_type == PUGL_CAIRO) { | |||
| return [view->impl->cairoview cairoContext]; | |||
| } | |||
| #endif | |||
| return NULL; | |||
| // may be unused | |||
| (void)view; | |||
| } | |||
| int | |||
| @@ -21,7 +21,13 @@ | |||
| #include <winsock2.h> | |||
| #include <windows.h> | |||
| #include <windowsx.h> | |||
| #ifdef PUGL_HAVE_GL | |||
| #include <GL/gl.h> | |||
| #endif | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| #include <cairo/cairo.h> | |||
| #include <cairo/cairo-win32.h> | |||
| #endif | |||
| #include <ctime> | |||
| #include <cstdio> | |||
| @@ -48,8 +54,13 @@ HINSTANCE hInstance = NULL; | |||
| struct PuglInternalsImpl { | |||
| HWND hwnd; | |||
| #ifdef PUGL_HAVE_GL | |||
| HDC hdc; | |||
| HGLRC hglrc; | |||
| #endif | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| cairo_t* cr; | |||
| #endif | |||
| WNDCLASS wc; | |||
| }; | |||
| @@ -76,17 +87,25 @@ puglInitInternals() | |||
| void | |||
| puglEnterContext(PuglView* view) | |||
| { | |||
| wglMakeCurrent(view->impl->hdc, view->impl->hglrc); | |||
| #ifdef PUGL_HAVE_GL | |||
| if (view->ctx_type == PUGL_GL) { | |||
| wglMakeCurrent(view->impl->hdc, view->impl->hglrc); | |||
| } | |||
| #endif | |||
| } | |||
| void | |||
| puglLeaveContext(PuglView* view, bool flush) | |||
| { | |||
| if (flush) { | |||
| glFlush(); | |||
| SwapBuffers(view->impl->hdc); | |||
| #ifdef PUGL_HAVE_GL | |||
| if (view->ctx_type == PUGL_GL) { | |||
| if (flush) { | |||
| glFlush(); | |||
| SwapBuffers(view->impl->hdc); | |||
| } | |||
| wglMakeCurrent(NULL, NULL); | |||
| } | |||
| wglMakeCurrent(NULL, NULL); | |||
| #endif | |||
| } | |||
| int | |||
| @@ -124,7 +143,6 @@ puglCreateWindow(PuglView* view, const char* title) | |||
| if (!RegisterClass(&impl->wc)) { | |||
| free((void*)impl->wc.lpszClassName); | |||
| free(impl); | |||
| free(view); | |||
| return 1; | |||
| } | |||
| @@ -155,37 +173,39 @@ puglCreateWindow(PuglView* view, const char* title) | |||
| UnregisterClass(impl->wc.lpszClassName, NULL); | |||
| free((void*)impl->wc.lpszClassName); | |||
| free(impl); | |||
| free(view); | |||
| return 1; | |||
| } | |||
| SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)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); | |||
| if (!impl->hglrc) { | |||
| ReleaseDC (impl->hwnd, impl->hdc); | |||
| DestroyWindow (impl->hwnd); | |||
| UnregisterClass (impl->wc.lpszClassName, NULL); | |||
| free((void*)impl->wc.lpszClassName); | |||
| free(impl); | |||
| free(view); | |||
| return 1; | |||
| #ifdef PUGL_HAVE_GL | |||
| if (view->ctx_type == PUGL_GL) { | |||
| 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); | |||
| if (!impl->hglrc) { | |||
| ReleaseDC (impl->hwnd, impl->hdc); | |||
| DestroyWindow (impl->hwnd); | |||
| UnregisterClass (impl->wc.lpszClassName, NULL); | |||
| free((void*)impl->wc.lpszClassName); | |||
| free(impl); | |||
| return 1; | |||
| } | |||
| } | |||
| #endif | |||
| return PUGL_SUCCESS; | |||
| } | |||
| @@ -205,13 +225,23 @@ puglHideWindow(PuglView* view) | |||
| void | |||
| puglDestroy(PuglView* view) | |||
| { | |||
| wglMakeCurrent(NULL, NULL); | |||
| wglDeleteContext(view->impl->hglrc); | |||
| ReleaseDC(view->impl->hwnd, view->impl->hdc); | |||
| DestroyWindow(view->impl->hwnd); | |||
| UnregisterClass(view->impl->wc.lpszClassName, NULL); | |||
| free((void*)view->impl->wc.lpszClassName); | |||
| free(view->impl); | |||
| if (!view) { | |||
| return; | |||
| } | |||
| PuglInternals* const impl = view->impl; | |||
| #ifdef PUGL_HAVE_GL | |||
| if (view->ctx_type == PUGL_GL) { | |||
| wglMakeCurrent(NULL, NULL); | |||
| wglDeleteContext(impl->hglrc); | |||
| } | |||
| ReleaseDC(impl->hwnd, impl->hdc); | |||
| #endif | |||
| DestroyWindow(impl->hwnd); | |||
| UnregisterClass(impl->wc.lpszClassName, NULL); | |||
| free((void*)impl->wc.lpszClassName); | |||
| free(impl); | |||
| free(view); | |||
| } | |||
| @@ -329,9 +359,32 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) | |||
| mmi->ptMinTrackSize.y = view->min_height; | |||
| break; | |||
| case WM_PAINT: | |||
| BeginPaint(view->impl->hwnd, &ps); | |||
| puglDisplay(view); | |||
| EndPaint(view->impl->hwnd, &ps); | |||
| #ifdef PUGL_HAVE_GL | |||
| if (view->ctx_type == PUGL_GL) { | |||
| BeginPaint(view->impl->hwnd, &ps); | |||
| puglDisplay(view); | |||
| EndPaint(view->impl->hwnd, &ps); | |||
| } | |||
| #endif | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| if (view->ctx_type == PUGL_CAIRO) { | |||
| HDC hdc = BeginPaint(view->impl->hwnd, &ps); | |||
| if (hdc == NULL) | |||
| break; | |||
| cairo_surface_t *surface = cairo_win32_surface_create(hdc); | |||
| if (surface) { | |||
| cairo_t *cr = cairo_create(surface); | |||
| if (cr) { | |||
| view->impl->cr = cr; | |||
| puglDisplay(view); | |||
| view->impl->cr = NULL; | |||
| cairo_destroy(cr); | |||
| } | |||
| cairo_surface_destroy(surface); | |||
| } | |||
| EndPaint(view->impl->hwnd, &ps); | |||
| } | |||
| #endif | |||
| break; | |||
| case WM_MOUSEMOVE: | |||
| if (view->motionFunc) { | |||
| @@ -469,6 +522,20 @@ puglGetNativeWindow(PuglView* view) | |||
| return (PuglNativeWindow)view->impl->hwnd; | |||
| } | |||
| void* | |||
| puglGetContext(PuglView* view) | |||
| { | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| if (view->ctx_type == PUGL_CAIRO) { | |||
| return view->impl->cr; | |||
| } | |||
| #endif | |||
| return NULL; | |||
| // may be unused | |||
| (void)view; | |||
| } | |||
| int | |||
| puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect) | |||
| { | |||
| @@ -24,8 +24,14 @@ | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #ifdef PUGL_HAVE_GL | |||
| #include <GL/gl.h> | |||
| #include <GL/glx.h> | |||
| #endif | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| #include <cairo/cairo.h> | |||
| #include <cairo/cairo-xlib.h> | |||
| #endif | |||
| #include <X11/Xatom.h> | |||
| #include <X11/Xlib.h> | |||
| #include <X11/Xutil.h> | |||
| @@ -53,10 +59,17 @@ struct PuglInternalsImpl { | |||
| Display* display; | |||
| int screen; | |||
| Window win; | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| cairo_t* cr; | |||
| cairo_surface_t* surface; | |||
| #endif | |||
| #ifdef PUGL_HAVE_GL | |||
| GLXContext ctx; | |||
| Bool doubleBuffered; | |||
| #endif | |||
| }; | |||
| #ifdef PUGL_HAVE_GL | |||
| /** | |||
| Attributes for single-buffered RGBA with at least | |||
| 4 bits per color and a 16 bit depth buffer. | |||
| @@ -102,6 +115,7 @@ static int attrListDblMS[] = { | |||
| GLX_SAMPLES, 4, | |||
| None | |||
| }; | |||
| #endif | |||
| PuglInternals* | |||
| puglInitInternals(void) | |||
| @@ -112,25 +126,33 @@ puglInitInternals(void) | |||
| void | |||
| puglEnterContext(PuglView* view) | |||
| { | |||
| glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||
| #ifdef PUGL_HAVE_GL | |||
| if (view->ctx_type == PUGL_GL) { | |||
| glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||
| } | |||
| #endif | |||
| } | |||
| void | |||
| puglLeaveContext(PuglView* view, bool flush) | |||
| { | |||
| if (flush) { | |||
| glFlush(); | |||
| if (view->impl->doubleBuffered) { | |||
| glXSwapBuffers(view->impl->display, view->impl->win); | |||
| #ifdef PUGL_HAVE_GL | |||
| if (view->ctx_type == PUGL_GL) { | |||
| if (flush) { | |||
| glFlush(); | |||
| if (view->impl->doubleBuffered) { | |||
| glXSwapBuffers(view->impl->display, view->impl->win); | |||
| } | |||
| } | |||
| glXMakeCurrent(view->impl->display, None, NULL); | |||
| } | |||
| glXMakeCurrent(view->impl->display, None, NULL); | |||
| #endif | |||
| } | |||
| int | |||
| puglCreateWindow(PuglView* view, const char* title) | |||
| { | |||
| PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||
| PuglInternals* impl = view->impl; | |||
| if (!impl) { | |||
| return 1; | |||
| } | |||
| @@ -142,21 +164,35 @@ puglCreateWindow(PuglView* view, const char* title) | |||
| return 1; | |||
| } | |||
| impl->screen = DefaultScreen(impl->display); | |||
| impl->doubleBuffered = True; | |||
| XVisualInfo* vi = glXChooseVisual(impl->display, impl->screen, attrListDblMS); | |||
| XVisualInfo* vi = NULL; | |||
| if (!vi) { | |||
| vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); | |||
| #ifdef PUGL_HAVE_GL | |||
| if (view->ctx_type == PUGL_GL) { | |||
| impl->doubleBuffered = True; | |||
| vi = glXChooseVisual(impl->display, impl->screen, attrListDblMS); | |||
| if (!vi) { | |||
| vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); | |||
| #ifdef PUGL_VERBOSE | |||
| printf("puGL: multisampling (antialiasing) is not available\n"); | |||
| printf("puGL: multisampling (antialiasing) is not available\n"); | |||
| #endif | |||
| } | |||
| } | |||
| if (!vi) { | |||
| vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | |||
| impl->doubleBuffered = False; | |||
| if (!vi) { | |||
| vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | |||
| impl->doubleBuffered = False; | |||
| } | |||
| } | |||
| #endif | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| if (view->ctx_type == PUGL_CAIRO) { | |||
| XVisualInfo pat; | |||
| int n; | |||
| pat.screen = impl->screen; | |||
| vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n); | |||
| } | |||
| #endif | |||
| if (!vi) { | |||
| XCloseDisplay(impl->display); | |||
| @@ -165,18 +201,25 @@ puglCreateWindow(PuglView* view, const char* title) | |||
| } | |||
| #ifdef PUGL_VERBOSE | |||
| #ifdef PUGL_HAVE_GL | |||
| int glxMajor, glxMinor; | |||
| glXQueryVersion(impl->display, &glxMajor, &glxMinor); | |||
| printf("puGL: GLX-Version : %d.%d\n", glxMajor, glxMinor); | |||
| #endif | |||
| #endif | |||
| impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | |||
| #ifdef PUGL_HAVE_GL | |||
| if (view->ctx_type == PUGL_GL) { | |||
| impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | |||
| if (!impl->ctx) { | |||
| XCloseDisplay(impl->display); | |||
| free(impl); | |||
| return 1; | |||
| if (!impl->ctx) { | |||
| XFree(vi); | |||
| XCloseDisplay(impl->display); | |||
| free(impl); | |||
| return 1; | |||
| } | |||
| } | |||
| #endif | |||
| Window xParent = view->parent | |||
| ? (Window)view->parent | |||
| @@ -201,11 +244,40 @@ puglCreateWindow(PuglView* view, const char* title) | |||
| CWBorderPixel | CWColormap | CWEventMask, &attr); | |||
| if (!impl->win) { | |||
| #ifdef PUGL_HAVE_GL | |||
| if (view->ctx_type == PUGL_GL) { | |||
| glXDestroyContext(impl->display, impl->ctx); | |||
| } | |||
| #endif | |||
| XFree(vi); | |||
| XCloseDisplay(impl->display); | |||
| free(impl); | |||
| return 1; | |||
| } | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| if (view->ctx_type == PUGL_CAIRO) { | |||
| impl->surface = cairo_xlib_surface_create( | |||
| impl->display, impl->win, vi->visual, view->width, view->height); | |||
| if (impl->surface == NULL || cairo_surface_status(impl->surface) != CAIRO_STATUS_SUCCESS) { | |||
| printf("puGL: failed to create cairo surface\n"); | |||
| } | |||
| else { | |||
| impl->cr = cairo_create(impl->surface); | |||
| } | |||
| if (impl->cr == NULL || cairo_status(impl->cr) != CAIRO_STATUS_SUCCESS) { | |||
| cairo_destroy(impl->cr); | |||
| cairo_surface_destroy(impl->surface); | |||
| XDestroyWindow(impl->display, impl->win); | |||
| XFree(vi); | |||
| XCloseDisplay(impl->display); | |||
| free(impl); | |||
| printf("puGL: failed to create cairo context\n"); | |||
| return 1; | |||
| } | |||
| } | |||
| #endif | |||
| if (view->width > 1 || view->height > 1) { | |||
| puglUpdateGeometryConstraints(view, view->min_width, view->min_height, view->min_width != view->width); | |||
| XResizeWindow(view->impl->display, view->impl->win, view->width, view->height); | |||
| @@ -227,11 +299,13 @@ puglCreateWindow(PuglView* view, const char* title) | |||
| } | |||
| #ifdef PUGL_VERBOSE | |||
| #ifdef PUGL_HAVE_GL | |||
| if (glXIsDirect(impl->display, impl->ctx)) { | |||
| printf("puGL: DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n"); | |||
| } else { | |||
| printf("puGL: No DRI available\n"); | |||
| } | |||
| #endif | |||
| #endif | |||
| XFree(vi); | |||
| @@ -244,14 +318,27 @@ puglDestroy(PuglView* view) | |||
| if (!view) { | |||
| return; | |||
| } | |||
| PuglInternals* const impl = view->impl; | |||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||
| x_fib_close(view->impl->display); | |||
| x_fib_close(impl->display); | |||
| #endif | |||
| glXDestroyContext(view->impl->display, view->impl->ctx); | |||
| XDestroyWindow(view->impl->display, view->impl->win); | |||
| XCloseDisplay(view->impl->display); | |||
| free(view->impl); | |||
| #ifdef PUGL_HAVE_GL | |||
| if (view->ctx_type == PUGL_GL) { | |||
| glXDestroyContext(impl->display, impl->ctx); | |||
| } | |||
| #endif | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| if (view->ctx_type == PUGL_CAIRO) { | |||
| cairo_destroy(impl->cr); | |||
| cairo_surface_destroy(impl->surface); | |||
| } | |||
| #endif | |||
| XDestroyWindow(impl->display, impl->win); | |||
| XCloseDisplay(impl->display); | |||
| free(impl); | |||
| free(view); | |||
| } | |||
| @@ -554,6 +641,14 @@ puglProcessEvents(PuglView* view) | |||
| } | |||
| if (conf_width != -1) { | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| if (view->ctx_type == PUGL_CAIRO) { | |||
| // Resize surfaces/contexts before dispatching | |||
| view->redisplay = true; | |||
| cairo_xlib_surface_set_size(view->impl->surface, | |||
| conf_width, conf_height); | |||
| } | |||
| #endif | |||
| puglReshape(view, conf_width, conf_height); | |||
| } | |||
| @@ -586,6 +681,20 @@ puglGetNativeWindow(PuglView* view) | |||
| return view->impl->win; | |||
| } | |||
| void* | |||
| puglGetContext(PuglView* view) | |||
| { | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| if (view->ctx_type == PUGL_CAIRO) { | |||
| return view->impl->cr; | |||
| } | |||
| #endif | |||
| return NULL; | |||
| // may be unused | |||
| (void)view; | |||
| } | |||
| int | |||
| puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect) | |||
| { | |||
| @@ -93,7 +93,7 @@ | |||
| // Define DISTRHO_PLUGIN_HAS_EMBED_UI if needed | |||
| #ifndef DISTRHO_PLUGIN_HAS_EMBED_UI | |||
| # ifdef HAVE_DGL | |||
| # if defined(HAVE_DGL) || defined(HAVE_DCAIRO) | |||
| # define DISTRHO_PLUGIN_HAS_EMBED_UI 1 | |||
| # else | |||
| # define DISTRHO_PLUGIN_HAS_EMBED_UI 0 | |||
| @@ -135,7 +135,7 @@ | |||
| // ----------------------------------------------------------------------- | |||
| // Disable UI if DGL or External UI is not available | |||
| #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI && ! defined(HAVE_DGL) | |||
| #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI && ! defined(HAVE_DGL) && ! defined(HAVE_DCAIRO) | |||
| # undef DISTRHO_PLUGIN_HAS_UI | |||
| # define DISTRHO_PLUGIN_HAS_UI 0 | |||
| #endif | |||
| @@ -152,6 +152,7 @@ void UI::uiFileBrowserSelected(const char*) | |||
| void UI::uiReshape(uint width, uint height) | |||
| { | |||
| #if defined(HAVE_DGL) | |||
| glEnable(GL_BLEND); | |||
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||
| glMatrixMode(GL_PROJECTION); | |||
| @@ -160,6 +161,7 @@ void UI::uiReshape(uint width, uint height) | |||
| glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height)); | |||
| glMatrixMode(GL_MODELVIEW); | |||
| glLoadIdentity(); | |||
| #endif | |||
| } | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||