@@ -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 | |||
} | |||
/* ------------------------------------------------------------------------------------------------------------ | |||