Browse Source

Update to latest pugl; fix more win32 api issues

tags/1.9.4
falkTX 11 years ago
parent
commit
196061f83b
16 changed files with 322 additions and 1836 deletions
  1. +0
    -4
      source/libs/distrho/dgl/Window.hpp
  2. +1
    -2
      source/libs/distrho/dgl/src/ImageAboutWindow.cpp
  3. +0
    -9
      source/libs/distrho/dgl/src/Widget.cpp
  4. +29
    -32
      source/libs/distrho/dgl/src/Window.cpp
  5. +14
    -3
      source/libs/distrho/dgl/src/pugl/pugl.h
  6. +14
    -6
      source/libs/distrho/dgl/src/pugl/pugl_internal.h
  7. +162
    -94
      source/libs/distrho/dgl/src/pugl/pugl_osx.m
  8. +68
    -37
      source/libs/distrho/dgl/src/pugl/pugl_win.cpp
  9. +34
    -27
      source/libs/distrho/dgl/src/pugl/pugl_x11.c
  10. +0
    -46
      source/libs/distrho/dgl/src/pugl/pugl_x11.h
  11. +0
    -341
      source/libs/pugl/pugl.h
  12. +0
    -135
      source/libs/pugl/pugl_internal.h
  13. +0
    -331
      source/libs/pugl/pugl_osx.m
  14. +0
    -344
      source/libs/pugl/pugl_win.cpp
  15. +0
    -379
      source/libs/pugl/pugl_x11.c
  16. +0
    -46
      source/libs/pugl/pugl_x11.h

+ 0
- 4
source/libs/distrho/dgl/Window.hpp View File

@@ -61,10 +61,6 @@ public:
setVisible(false);
}

#if DISTRHO_OS_WINDOWS
Rectangle<int> getBounds();
#endif

private:
class Private;
Private* const kPrivate;


+ 1
- 2
source/libs/distrho/dgl/src/ImageAboutWindow.cpp View File

@@ -27,13 +27,12 @@ ImageAboutWindow::ImageAboutWindow(App* app, Window* parent, const Image& image)
{
#if DISTRHO_OS_WINDOWS
// FIXME
Window::setSize(image.getWidth()+1, image.getHeight()+1);
Window::setSize(image.getWidth(), image.getHeight()+1);
#else
Window::setSize(image.getWidth(), image.getHeight());
#endif

Window::setWindowTitle("About");
Window::show();
}

void ImageAboutWindow::onDisplay()


+ 0
- 9
source/libs/distrho/dgl/src/Widget.cpp View File

@@ -214,19 +214,10 @@ void Widget::onReshape(int width, int height)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

#if DISTRHO_OS_WINDOWS
Rectangle<int> r(fParent->getBounds());
glOrtho(r.getX(), r.getWidth(), r.getHeight(), r.getY(), -1.0f, 1.0f);
glViewport(0, 0, r.getWidth() - r.getX(), r.getHeight() - r.getY());
#else
glOrtho(0, width, height, 0, 0.0f, 1.0f);
glViewport(0, 0, width, height);
#endif

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}


+ 29
- 32
source/libs/distrho/dgl/src/Window.cpp View File

@@ -53,6 +53,7 @@ public:
fChildFocus(nullptr),
fVisible(false),
fClosed(false),
fResizable(false),
#if DISTRHO_OS_WINDOWS
hwnd(0)
#elif DISTRHO_OS_LINUX
@@ -85,7 +86,6 @@ public:

#if DISTRHO_OS_WINDOWS
hwnd = impl->hwnd;

#elif DISTRHO_OS_LINUX
xDisplay = impl->display;
xWindow = impl->win;
@@ -116,17 +116,32 @@ public:
void exec()
{
fClosed = false;
show();

if (fParent != nullptr)
{
fParent->fChildFocus = this;

#if DISTRHO_OS_WINDOWS
EnableWindow(fParent->hwnd, FALSE);
// Center this window
PuglInternals* parentImpl = fParent->kView->impl;

RECT curRect;
RECT parentRect;
GetWindowRect(hwnd, &curRect);
GetWindowRect(parentImpl->hwnd, &parentRect);

int x = parentRect.left+(parentRect.right-curRect.right)/2;
int y = parentRect.top+(parentRect.bottom-curRect.bottom)/2;

SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
UpdateWindow(hwnd);
#endif
fParent->fChildFocus = this;
fParent->show();
}

show();

while (isVisible() && ! fClosed)
{
idle();
@@ -142,9 +157,6 @@ public:
if (fParent != nullptr)
{
fParent->fChildFocus = nullptr;
#if DISTRHO_OS_WINDOWS
EnableWindow(fParent->hwnd, TRUE);
#endif
}
}

@@ -224,14 +236,15 @@ public:
void setSize(unsigned int width, unsigned int height)
{
#if DISTRHO_OS_WINDOWS
RECT rcClient;
RECT rcWindow;
POINT ptDiff;
GetClientRect(hwnd, &rcClient);
GetWindowRect(hwnd, &rcWindow);
ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
SetWindowPos(hwnd, 0, 0, 0, width + ptDiff.x, height + ptDiff.y, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER);
int winFlags = WS_POPUPWINDOW | WS_CAPTION;

if (fResizable)
winFlags |= WS_SIZEBOX;

RECT wr = { 0, 0, (long)width, (long)height };
AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST);

SetWindowPos(hwnd, 0, 0, 0, wr.right-wr.left, wr.bottom-wr.top, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER);
UpdateWindow(hwnd);
#elif DISTRHO_OS_LINUX
XSizeHints sizeHints;
@@ -284,16 +297,6 @@ public:
fWidgets.remove(widget);
}

#if DISTRHO_OS_WINDOWS
Rectangle<int> getBounds()
{
RECT rcClient;
GetClientRect(hwnd, &rcClient);

return Rectangle<int>(rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
}
#endif

protected:
void onDisplay()
{
@@ -422,6 +425,7 @@ private:
Private* fChildFocus;
bool fVisible;
bool fClosed;
bool fResizable;

std::list<Widget*> fWidgets;

@@ -563,13 +567,6 @@ void Window::removeWidget(Widget* widget)
kPrivate->removeWidget(widget);
}

#if DISTRHO_OS_WINDOWS
Rectangle<int> Window::getBounds()
{
return kPrivate->getBounds();
}
#endif

// -------------------------------------------------

END_NAMESPACE_DISTRHO

+ 14
- 3
source/libs/distrho/dgl/src/pugl/pugl.h View File

@@ -54,7 +54,9 @@
# define PUGL_API
#endif

#ifndef __cplusplus
#ifdef __cplusplus
extern "C" {
#else
# include <stdbool.h>
#endif

@@ -224,8 +226,7 @@ puglCreate(PuglNativeWindow parent,
int width,
int height,
bool resizable,
bool addToDesktop = true,
const char* x11Display = nullptr);
bool addToDesktop = true);

/**
Set the handle to be passed to all callbacks.
@@ -245,6 +246,12 @@ puglSetHandle(PuglView* view, PuglHandle handle);
PUGL_API PuglHandle
puglGetHandle(PuglView* view);

/**
Return the timestamp (if any) of the currently-processing event.
*/
PUGL_API uint32_t
puglGetEventTimestamp(PuglView* view);

/**
Get the currently active modifiers (PuglMod flags).

@@ -338,4 +345,8 @@ puglDestroy(PuglView* view);
@}
*/

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* PUGL_H_INCLUDED */

+ 14
- 6
source/libs/distrho/dgl/src/pugl/pugl_internal.h View File

@@ -39,11 +39,13 @@ struct PuglViewImpl {

PuglInternals* impl;

int width;
int height;
int mods;
bool ignoreKeyRepeat;
bool redisplay;
int width;
int height;
int mods;
bool mouse_in_view;
bool ignoreKeyRepeat;
bool redisplay;
uint32_t event_timestamp_ms;
};

void
@@ -58,13 +60,19 @@ puglGetHandle(PuglView* view)
return view->handle;
}

uint32_t
puglGetEventTimestamp(PuglView* view)
{
return view->event_timestamp_ms;
}

int
puglGetModifiers(PuglView* view)
{
return view->mods;
}

static inline void
void
puglDefaultReshape(PuglView* view, int width, int height)
{
glMatrixMode(GL_PROJECTION);


+ 162
- 94
source/libs/distrho/dgl/src/pugl/pugl_osx.m View File

@@ -24,12 +24,64 @@

#include "pugl_internal.h"

@interface PuglWindow : NSWindow
{
@public
PuglView* puglview;
}

- (id) initWithContentRect:(NSRect)contentRect
styleMask:(unsigned int)aStyle
backing:(NSBackingStoreType)bufferingType
defer:(BOOL)flag;
- (void) setPuglview:(PuglView*)view;
- (BOOL) windowShouldClose:(id)sender;
- (void) becomeKeyWindow:(id)sender;
- (BOOL) canBecomeKeyWindow:(id)sender;
@end

@implementation PuglWindow

- (id)initWithContentRect:(NSRect)contentRect
styleMask:(unsigned int)aStyle
backing:(NSBackingStoreType)bufferingType
defer:(BOOL)flag
{
NSWindow* result = [super initWithContentRect:contentRect
styleMask:(NSClosableWindowMask |
NSTitledWindowMask |
NSResizableWindowMask)
backing:NSBackingStoreBuffered defer:NO];

[result setAcceptsMouseMovedEvents:YES];
[result setLevel: CGShieldingWindowLevel() + 1];

return result;
}

- (void)setPuglview:(PuglView*)view
{
puglview = view;
[self setContentSize:NSMakeSize(view->width, view->height) ];
}

- (BOOL)windowShouldClose:(id)sender
{
if (puglview->closeFunc)
puglview->closeFunc(puglview);
return YES;
}

@end

@interface PuglOpenGLView : NSOpenGLView
{
int colorBits;
int depthBits;
@public
PuglView* view;
PuglView* puglview;

NSTrackingArea* trackingArea;
}

- (id) initWithFrame:(NSRect)frame
@@ -38,6 +90,7 @@
- (void) reshape;
- (void) drawRect:(NSRect)rect;
- (void) mouseMoved:(NSEvent*)event;
- (void) mouseDragged:(NSEvent*)event;
- (void) mouseDown:(NSEvent*)event;
- (void) mouseUp:(NSEvent*)event;
- (void) rightMouseDown:(NSEvent*)event;
@@ -92,33 +145,37 @@
int width = bounds.size.width;
int height = bounds.size.height;

if (view->reshapeFunc) {
view->reshapeFunc(view, width, height);
} else {
puglDefaultReshape(view, width, height);
}
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.
*/
if (puglview->reshapeFunc) {
puglview->reshapeFunc(puglview, width, height);
} else {
puglDefaultReshape(puglview, width, height);
}

view->width = width;
view->height = height;
puglview->width = width;
puglview->height = height;
}
}

- (void) drawRect:(NSRect)rect
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

if (self->view->displayFunc) {
self->view->displayFunc(self->view);
}

puglDisplay(puglview);
glFlush();
glSwapAPPLE();
}

static int
getModifiers(unsigned modifierFlags)
static unsigned
getModifiers(PuglView* view, NSevent* ev)
{
int mods = 0;
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;
@@ -126,99 +183,135 @@ getModifiers(unsigned modifierFlags)
return mods;
}

-(void)updateTrackingAreas
{
if (trackingArea != nil) {
[self removeTrackingArea:trackingArea];
[trackingArea release];
}

const int opts = (NSTrackingMouseEnteredAndExited |
NSTrackingMouseMoved |
NSTrackingActiveAlways);
trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
options:opts
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
}

- (void)mouseEntered:(NSEvent*)theEvent
{
[self updateTrackingAreas];
}

- (void)mouseExited:(NSEvent*)theEvent
{
}

- (void) mouseMoved:(NSEvent*)event
{
if (view->motionFunc) {
if (puglview->motionFunc) {
NSPoint loc = [event locationInWindow];
view->mods = getModifiers([event modifierFlags]);
view->motionFunc(view, loc.x, loc.y);
puglview->mods = getModifiers(puglview, event);
puglview->motionFunc(puglview, loc.x, puglview->height - loc.y);
}
}

- (void) mouseDragged:(NSEvent*)event
{
if (puglview->motionFunc) {
NSPoint loc = [event locationInWindow];
puglview->mods = getModifiers(puglview, event);
puglview->motionFunc(puglview, loc.x, puglview->height - loc.y);
}
}

- (void) mouseDown:(NSEvent*)event
{
if (view->mouseFunc) {
if (puglview->mouseFunc) {
NSPoint loc = [event locationInWindow];
view->mods = getModifiers([event modifierFlags]);
view->mouseFunc(view, 1, true, loc.x, loc.y);
puglview->mods = getModifiers(puglview, event);
puglview->mouseFunc(puglview, 1, true, loc.x, puglview->height - loc.y);
}
}

- (void) mouseUp:(NSEvent*)event
{
if (view->mouseFunc) {
if (puglview->mouseFunc) {
NSPoint loc = [event locationInWindow];
view->mods = getModifiers([event modifierFlags]);
view->mouseFunc(view, 1, false, loc.x, loc.y);
puglview->mods = getModifiers(puglview, event);
puglview->mouseFunc(puglview, 1, false, loc.x, puglview->height - loc.y);
}
[self updateTrackingAreas];
}

- (void) rightMouseDown:(NSEvent*)event
{
if (view->mouseFunc) {
if (puglview->mouseFunc) {
NSPoint loc = [event locationInWindow];
view->mods = getModifiers([event modifierFlags]);
view->mouseFunc(view, 3, true, loc.x, loc.y);
puglview->mods = getModifiers(puglview, event);
puglview->mouseFunc(puglview, 3, true, loc.x, puglview->height - loc.y);
}
}

- (void) rightMouseUp:(NSEvent*)event
{
if (view->mouseFunc) {
if (puglview->mouseFunc) {
NSPoint loc = [event locationInWindow];
view->mods = getModifiers([event modifierFlags]);
view->mouseFunc(view, 3, false, loc.x, loc.y);
puglview->mods = getModifiers(puglview, event);
puglview->mouseFunc(puglview, 3, false, loc.x, puglview->height - loc.y);
}
}

- (void) scrollWheel:(NSEvent*)event
{
if (view->scrollFunc) {
view->mods = getModifiers([event modifierFlags]);
view->scrollFunc(view, [event deltaX], [event deltaY]);
if (puglview->scrollFunc) {
puglview->mods = getModifiers(puglview, event);
puglview->scrollFunc(puglview, [event deltaX], [event deltaY]);
}
[self updateTrackingAreas];
}

- (void) keyDown:(NSEvent*)event
{
if (view->keyboardFunc && !(view->ignoreKeyRepeat && [event isARepeat])) {
if (puglview->keyboardFunc && !(puglview->ignoreKeyRepeat && [event isARepeat])) {
NSString* chars = [event characters];
view->mods = getModifiers([event modifierFlags]);
view->keyboardFunc(view, true, [chars characterAtIndex:0]);
puglview->mods = getModifiers(puglview, event);
puglview->keyboardFunc(puglview, true, [chars characterAtIndex:0]);
}
}

- (void) keyUp:(NSEvent*)event
{
if (view->keyboardFunc) {
if (puglview->keyboardFunc) {
NSString* chars = [event characters];
view->mods = getModifiers([event modifierFlags]);
view->keyboardFunc(view, false, [chars characterAtIndex:0]);
puglview->mods = getModifiers(puglview, event);
puglview->keyboardFunc(puglview, false, [chars characterAtIndex:0]);
}
}

- (void) flagsChanged:(NSEvent*)event
{
if (view->specialFunc) {
int mods = getModifiers([event modifierFlags]);
if ((mods & PUGL_MOD_SHIFT) != (view->mods & PUGL_MOD_SHIFT)) {
view->specialFunc(view, mods & PUGL_MOD_SHIFT, PUGL_KEY_SHIFT);
} else if ((mods & PUGL_MOD_CTRL) != (view->mods & PUGL_MOD_CTRL)) {
view->specialFunc(view, mods & PUGL_MOD_CTRL, PUGL_KEY_CTRL);
} else if ((mods & PUGL_MOD_ALT) != (view->mods & PUGL_MOD_ALT)) {
view->specialFunc(view, mods & PUGL_MOD_ALT, PUGL_KEY_ALT);
} else if ((mods & PUGL_MOD_SUPER) != (view->mods & PUGL_MOD_SUPER)) {
view->specialFunc(view, mods & PUGL_MOD_SUPER, PUGL_KEY_SUPER);
if (puglview->specialFunc) {
const unsigned mods = getModifiers(puglview, [event modifierFlags]);
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);
}
view->mods = mods;
puglview->mods = mods;
}
}

@end

struct PuglInternalsImpl {
PuglOpenGLView* view;
NSModalSession session;
PuglOpenGLView* glview;
id window;
};

@@ -228,8 +321,7 @@ puglCreate(PuglNativeWindow parent,
int width,
int height,
bool resizable,
bool addToDesktop,
const char* x11Display)
bool addToDesktop)
{
PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
@@ -243,46 +335,37 @@ puglCreate(PuglNativeWindow parent,

[NSAutoreleasePool new];
[NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];

NSString* titleString = [[NSString alloc]
initWithBytes:title
length:strlen(title)
encoding:NSUTF8StringEncoding];

id window = [[[NSWindow alloc]
initWithContentRect:NSMakeRect(0, 0, 512, 512)
styleMask:NSTitledWindowMask
backing:NSBackingStoreBuffered
defer:NO]
autorelease];
id window = [[PuglWindow new]retain];

[window cascadeTopLeftFromPoint:NSMakePoint(20, 20)];
[window setPuglview:view];
[window setTitle:titleString];
[window setAcceptsMouseMovedEvents:YES];

impl->view = [PuglOpenGLView new];
impl->glview = [PuglOpenGLView new];
impl->window = window;
impl->view->view = view;
impl->glview->puglview = view;

[window setContentView:impl->view];
[window setContentView:impl->glview];
[NSApp activateIgnoringOtherApps:YES];
[window makeFirstResponder:impl->view];
[window makeFirstResponder:impl->glview];

impl->session = [NSApp beginModalSessionForWindow:view->impl->window];
[window makeKeyAndOrderFront:window];

return view;

// unused
(void)addToDesktop;
(void)x11Display;
}

void
puglDestroy(PuglView* view)
{
[NSApp endModalSession:view->impl->session];
[view->impl->view release];
view->impl->glview->puglview = NULL;
[view->impl->window close];
[view->impl->glview release];
[view->impl->window release];
free(view->impl);
free(view);
}
@@ -290,30 +373,15 @@ puglDestroy(PuglView* view)
void
puglDisplay(PuglView* view)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

if (view->displayFunc) {
view->displayFunc(view);
}

glFlush();
view->redisplay = false;
}

PuglStatus
puglProcessEvents(PuglView* view)
{
NSInteger response = [NSApp runModalSession:view->impl->session];
if (response != NSRunContinuesResponse) {
if (view->closeFunc) {
view->closeFunc(view);
}
}

if (view->redisplay) {
puglDisplay(view);
}
[view->impl->glview setNeedsDisplay: YES];

return PUGL_SUCCESS;
}
@@ -327,5 +395,5 @@ puglPostRedisplay(PuglView* view)
PuglNativeWindow
puglGetNativeWindow(PuglView* view)
{
return (PuglNativeWindow)view->impl->view;
return (PuglNativeWindow)view->impl->glview;
}

+ 68
- 37
source/libs/distrho/dgl/src/pugl/pugl_win.cpp View File

@@ -22,6 +22,9 @@
#include <windowsx.h>
#include <GL/gl.h>

#include <stdio.h>
#include <stdlib.h>

#include "pugl_internal.h"

#ifndef WM_MOUSEWHEEL
@@ -30,11 +33,17 @@
#ifndef WM_MOUSEHWHEEL
# define WM_MOUSEHWHEEL 0x020E
#endif
#ifndef WHEEL_DELTA
# define WHEEL_DELTA 120
#endif

const int LOCAL_CLOSE_MSG = WM_USER + 50;

struct PuglInternalsImpl {
HWND hwnd;
HDC hdc;
HGLRC hglrc;
HWND hwnd;
HDC hdc;
HGLRC hglrc;
WNDCLASS wc;
};

LRESULT CALLBACK
@@ -46,8 +55,7 @@ puglCreate(PuglNativeWindow parent,
int width,
int height,
bool resizable,
bool addToDesktop,
const char* x11Display)
bool addToDesktop)
{
PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
@@ -59,30 +67,47 @@ puglCreate(PuglNativeWindow parent,
view->width = width;
view->height = height;

WNDCLASS wc;
wc.style = CS_OWNDC;
wc.lpfnWndProc = wndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = 0;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "Pugl";
RegisterClass(&wc);

impl->hwnd = CreateWindow(
"Pugl", title,
(addToDesktop ? WS_VISIBLE : 0) | (parent ? WS_CHILD : (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX)),
CW_USEDEFAULT, CW_USEDEFAULT, width, height,
// FIXME: This is nasty, and pugl should not have static anything.
// Should class be a parameter? Does this make sense on other platforms?
static int wc_count = 0;
char classNameBuf[256];
_snprintf(classNameBuf, sizeof(classNameBuf), "%s_%d\n", title, wc_count++);

impl->wc.style = CS_OWNDC;
impl->wc.lpfnWndProc = wndProc;
impl->wc.cbClsExtra = 0;
impl->wc.cbWndExtra = 0;
impl->wc.hInstance = 0;
impl->wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
impl->wc.hCursor = LoadCursor(NULL, IDC_ARROW);
impl->wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
impl->wc.lpszMenuName = NULL;
impl->wc.lpszClassName = classNameBuf;
RegisterClass(&impl->wc);

int winFlags = WS_POPUPWINDOW | WS_CAPTION;
if (resizable) {
winFlags |= WS_SIZEBOX;
}

// Adjust the overall window size to accomodate our requested client size
RECT wr = { 0, 0, width, height };
AdjustWindowRectEx(
&wr, winFlags, FALSE, WS_EX_TOPMOST);

impl->hwnd = CreateWindowEx(
WS_EX_TOPMOST,
classNameBuf, title,
(addToDesktop ? WS_VISIBLE : 0) | (parent ? WS_CHILD : winFlags),
0, 0, wr.right-wr.left, wr.bottom-wr.top,
(HWND)parent, NULL, NULL, NULL);

if (!impl->hwnd) {
free(impl);
free(view);
return NULL;
}
SetWindowLongPtr(impl->hwnd, GWL_USERDATA, (LONG)view);

impl->hdc = GetDC(impl->hwnd);
@@ -107,10 +132,6 @@ puglCreate(PuglNativeWindow parent,
view->height = height;

return view;

// unused
(void)resizable;
(void)x11Display;
}

void
@@ -120,11 +141,12 @@ puglDestroy(PuglView* view)
wglDeleteContext(view->impl->hglrc);
ReleaseDC(view->impl->hwnd, view->impl->hdc);
DestroyWindow(view->impl->hwnd);
UnregisterClass(view->impl->wc.lpszClassName, NULL);
free(view->impl);
free(view);
}

void
static void
puglReshape(PuglView* view, int width, int height)
{
wglMakeCurrent(view->impl->hdc, view->impl->hglrc);
@@ -192,6 +214,13 @@ keySymToSpecial(int sym)
static void
processMouseEvent(PuglView* view, int button, bool press, LPARAM lParam)
{
view->event_timestamp_ms = GetMessageTime();
if (press) {
SetCapture(view->impl->hwnd);
} else {
ReleaseCapture();
}
if (view->mouseFunc) {
view->mouseFunc(view, button, press,
GET_X_LPARAM(lParam),
@@ -221,7 +250,11 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
case WM_CREATE:
case WM_SHOWWINDOW:
case WM_SIZE:
puglReshape(view, view->width, view->height);
RECT rect;
GetClientRect(view->impl->hwnd, &rect);
puglReshape(view, rect.right, rect.bottom);
view->width = rect.right;
view->height = rect.bottom;
break;
case WM_PAINT:
BeginPaint(view->impl->hwnd, &ps);
@@ -230,8 +263,7 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
break;
case WM_MOUSEMOVE:
if (view->motionFunc) {
view->motionFunc(
view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
view->motionFunc(view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
}
break;
case WM_LBUTTONDOWN:
@@ -265,6 +297,7 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
}
break;
case WM_KEYDOWN:
view->event_timestamp_ms = (GetMessageTime());
if (view->ignoreKeyRepeat && (lParam & (1 << 30))) {
break;
} // else nobreak
@@ -278,6 +311,7 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
}
break;
case WM_QUIT:
case LOCAL_CLOSE_MSG:
if (view->closeFunc) {
view->closeFunc(view);
}
@@ -298,8 +332,9 @@ puglProcessEvents(PuglView* view)
handleMessage(view, msg.message, msg.wParam, msg.lParam);
}


if (view->redisplay) {
puglDisplay(view);
InvalidateRect(view->impl->hwnd, NULL, FALSE);
}

return PUGL_SUCCESS;
@@ -314,14 +349,10 @@ wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0);
return 0;
case WM_CLOSE:
PostQuitMessage(0);
PostMessage(hwnd, LOCAL_CLOSE_MSG, wParam, lParam);
return 0;
case WM_DESTROY:
return 0;
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
PostMessage(hwnd, message, wParam, lParam);
return 0;
default:
if (view) {
return handleMessage(view, message, wParam, lParam);


+ 34
- 27
source/libs/distrho/dgl/src/pugl/pugl_x11.c View File

@@ -23,9 +23,22 @@
#include <stdlib.h>
#include <string.h>

#include "pugl_x11.h"
#include <GL/gl.h>
#include <GL/glx.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>

#include "pugl_internal.h"

struct PuglInternalsImpl {
Display* display;
int screen;
Window win;
GLXContext ctx;
Bool doubleBuffered;
};

/**
Attributes for single-buffered RGBA with at least
4 bits per color and a 16 bit depth buffer.
@@ -58,20 +71,19 @@ puglCreate(PuglNativeWindow parent,
int width,
int height,
bool resizable,
bool addToDesktop,
const char* x11Display)
bool addToDesktop)
{
PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
if (!view || !impl) {
return nullptr;
return NULL;
}

view->impl = impl;
view->width = width;
view->height = height;

impl->display = XOpenDisplay(x11Display);
impl->display = XOpenDisplay(0);
impl->screen = DefaultScreen(impl->display);

XVisualInfo* vi = glXChooseVisual(impl->display, impl->screen, attrListDbl);
@@ -88,7 +100,7 @@ puglCreate(PuglNativeWindow parent,
glXQueryVersion(impl->display, &glxMajor, &glxMinor);
printf("GLX-Version %d.%d\n", glxMajor, glxMinor);

impl->ctx = glXCreateContext(impl->display, vi, nullptr, GL_TRUE);
impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE);

Window xParent = parent
? (Window)parent
@@ -108,7 +120,7 @@ puglCreate(PuglNativeWindow parent,

impl->win = XCreateWindow(
impl->display, xParent,
0, 0, (unsigned int)view->width, (unsigned int)view->height, 0, vi->depth, InputOutput, vi->visual,
0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual,
CWBorderPixel | CWColormap | CWEventMask, &attr);

XSizeHints sizeHints;
@@ -138,7 +150,7 @@ puglCreate(PuglNativeWindow parent,
if (glXIsDirect(impl->display, impl->ctx)) {
printf("DRI enabled\n");
} else {
printf("no DRI available\n");
printf("No DRI available\n");
}

XFree(vi);
@@ -232,8 +244,10 @@ keySymToSpecial(KeySym sym)
}

static void
setModifiers(PuglView* view, int xstate)
setModifiers(PuglView* view, unsigned xstate, unsigned xtime)
{
view->event_timestamp_ms = xtime;

view->mods = 0;
view->mods |= (xstate & ShiftMask) ? PUGL_MOD_SHIFT : 0;
view->mods |= (xstate & ControlMask) ? PUGL_MOD_CTRL : 0;
@@ -264,16 +278,15 @@ puglProcessEvents(PuglView* view)
break;
}
puglDisplay(view);
view->redisplay = false;
break;
case MotionNotify:
setModifiers(view, (int)event.xmotion.state);
setModifiers(view, event.xmotion.state, event.xmotion.time);
if (view->motionFunc) {
view->motionFunc(view, event.xmotion.x, event.xmotion.y);
}
break;
case ButtonPress:
setModifiers(view, (int)event.xbutton.state);
setModifiers(view, event.xbutton.state, event.xbutton.time);
if (event.xbutton.button >= 4 && event.xbutton.button <= 7) {
if (view->scrollFunc) {
float dx = 0, dy = 0;
@@ -289,23 +302,23 @@ puglProcessEvents(PuglView* view)
}
// nobreak
case ButtonRelease:
setModifiers(view, (int)event.xbutton.state);
setModifiers(view, event.xbutton.state, event.xbutton.time);
if (view->mouseFunc &&
(event.xbutton.button < 4 || event.xbutton.button > 7)) {
view->mouseFunc(view,
(int)event.xbutton.button, event.type == ButtonPress,
event.xbutton.button, event.type == ButtonPress,
event.xbutton.x, event.xbutton.y);
}
break;
case KeyPress: {
setModifiers(view, (int)event.xkey.state);
setModifiers(view, event.xkey.state, event.xkey.time);
KeySym sym;
char str[5];
int n = XLookupString(&event.xkey, str, 4, &sym, nullptr);
int n = XLookupString(&event.xkey, str, 4, &sym, NULL);
PuglKey key = keySymToSpecial(sym);
if (!key && view->keyboardFunc) {
if (n == 1) {
view->keyboardFunc(view, true, (uint32_t)str[0]);
view->keyboardFunc(view, true, str[0]);
} else {
fprintf(stderr, "warning: Unknown key %X\n", (int)sym);
}
@@ -314,7 +327,7 @@ puglProcessEvents(PuglView* view)
}
} break;
case KeyRelease: {
setModifiers(view, (int)event.xkey.state);
setModifiers(view, event.xkey.state, event.xkey.time);
bool repeated = false;
if (view->ignoreKeyRepeat &&
XEventsQueued(view->impl->display, QueuedAfterReading)) {
@@ -330,10 +343,10 @@ puglProcessEvents(PuglView* view)

if (!repeated && view->keyboardFunc) {
KeySym sym = XKeycodeToKeysym(
view->impl->display, (KeyCode)event.xkey.keycode, 0);
view->impl->display, event.xkey.keycode, 0);
PuglKey special = keySymToSpecial(sym);
if (!special) {
view->keyboardFunc(view, false, (uint32_t)sym);
view->keyboardFunc(view, false, sym);
} else if (view->specialFunc) {
view->specialFunc(view, false, special);
}
@@ -369,11 +382,5 @@ puglPostRedisplay(PuglView* view)
PuglNativeWindow
puglGetNativeWindow(PuglView* view)
{
return static_cast<PuglNativeWindow>(view->impl->win);
}

PuglInternals*
puglGetInternalsImpl(PuglView* view)
{
return view->impl;
return view->impl->win;
}

+ 0
- 46
source/libs/distrho/dgl/src/pugl/pugl_x11.h View File

@@ -1,46 +0,0 @@
/*
Copyright 2012 David Robillard <http://drobilla.net>
Copyright 2011-2012 Ben Loftis, Harrison Consoles

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/**
@file pugl_x11.h X11 Pugl Implementation (PuglInternalsImpl only).
*/

#ifndef PUGL_X11_H_INCLUDED
#define PUGL_X11_H_INCLUDED

#include "pugl.h"

#include <GL/gl.h>
#include <GL/glx.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>

struct PuglInternalsImpl {
Display* display;
int screen;
Window win;
GLXContext ctx;
Bool doubleBuffered;
};

typedef struct PuglInternalsImpl PuglInternals;

PuglInternals*
puglGetInternalsImpl(PuglView* view);

#endif /* PUGL_X11_H_INCLUDED */

+ 0
- 341
source/libs/pugl/pugl.h View File

@@ -1,341 +0,0 @@
/*
Copyright 2012 David Robillard <http://drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/**
@file pugl.h API for Pugl, a minimal portable API for OpenGL.
*/

#ifndef PUGL_H_INCLUDED
#define PUGL_H_INCLUDED

#include <stdint.h>

/*
This API is pure portable C and contains no platform specific elements, or
even a GL dependency. However, unfortunately GL includes vary across
platforms so they are included here to allow for pure portable programs.
*/
#ifdef __APPLE__
# include "OpenGL/gl.h"
#else
# ifdef _WIN32
# include <windows.h> /* Broken Windows GL headers require this */
# endif
# include "GL/gl.h"
#endif

#ifdef PUGL_SHARED
# ifdef _WIN32
# define PUGL_LIB_IMPORT __declspec(dllimport)
# define PUGL_LIB_EXPORT __declspec(dllexport)
# else
# define PUGL_LIB_IMPORT __attribute__((visibility("default")))
# define PUGL_LIB_EXPORT __attribute__((visibility("default")))
# endif
# ifdef PUGL_INTERNAL
# define PUGL_API PUGL_LIB_EXPORT
# else
# define PUGL_API PUGL_LIB_IMPORT
# endif
#else
# define PUGL_API
#endif

#ifndef __cplusplus
# include <stdbool.h>
#endif

/**
@defgroup pugl Pugl
A minimal portable API for OpenGL.
@{
*/

/**
An OpenGL view.
*/
typedef struct PuglViewImpl PuglView;

/**
A native window handle.

On X11, this is a Window.
On OSX, this is an NSView*.
On Windows, this is a HWND.
*/
typedef intptr_t PuglNativeWindow;

/**
Return status code.
*/
typedef enum {
PUGL_SUCCESS = 0
} PuglStatus;

/**
Convenience symbols for ASCII control characters.
*/
typedef enum {
PUGL_CHAR_BACKSPACE = 0x08,
PUGL_CHAR_ESCAPE = 0x1B,
PUGL_CHAR_DELETE = 0x7F
} PuglChar;

/**
Special (non-Unicode) keyboard keys.
*/
typedef enum {
PUGL_KEY_F1 = 1,
PUGL_KEY_F2,
PUGL_KEY_F3,
PUGL_KEY_F4,
PUGL_KEY_F5,
PUGL_KEY_F6,
PUGL_KEY_F7,
PUGL_KEY_F8,
PUGL_KEY_F9,
PUGL_KEY_F10,
PUGL_KEY_F11,
PUGL_KEY_F12,
PUGL_KEY_LEFT,
PUGL_KEY_UP,
PUGL_KEY_RIGHT,
PUGL_KEY_DOWN,
PUGL_KEY_PAGE_UP,
PUGL_KEY_PAGE_DOWN,
PUGL_KEY_HOME,
PUGL_KEY_END,
PUGL_KEY_INSERT,
PUGL_KEY_SHIFT,
PUGL_KEY_CTRL,
PUGL_KEY_ALT,
PUGL_KEY_SUPER
} PuglKey;

/**
Keyboard modifier flags.
*/
typedef enum {
PUGL_MOD_SHIFT = 1, /**< Shift key */
PUGL_MOD_CTRL = 1 << 1, /**< Control key */
PUGL_MOD_ALT = 1 << 2, /**< Alt/Option key */
PUGL_MOD_SUPER = 1 << 3 /**< Mod4/Command/Windows key */
} PuglMod;

/**
Handle for opaque user data.
*/
typedef void* PuglHandle;

/**
A function called when the window is closed.
*/
typedef void (*PuglCloseFunc)(PuglView* view);

/**
A function called to draw the view contents with OpenGL.
*/
typedef void (*PuglDisplayFunc)(PuglView* view);

/**
A function called when a key is pressed or released.
@param view The view the event occured in.
@param press True if the key was pressed, false if released.
@param key Unicode point of the key pressed.
*/
typedef void (*PuglKeyboardFunc)(PuglView* view, bool press, uint32_t key);

/**
A function called when the pointer moves.
@param view The view the event occured in.
@param x The window-relative x coordinate of the pointer.
@param y The window-relative y coordinate of the pointer.
*/
typedef void (*PuglMotionFunc)(PuglView* view, int x, int y);

/**
A function called when a mouse button is pressed or released.
@param view The view the event occured in.
@param button The button number (1 = left, 2 = middle, 3 = right).
@param press True if the key was pressed, false if released.
@param x The window-relative x coordinate of the pointer.
@param y The window-relative y coordinate of the pointer.
*/
typedef void (*PuglMouseFunc)(
PuglView* view, int button, bool press, int x, int y);

/**
A function called when the view is resized.
@param view The view being resized.
@param width The new view width.
@param height The new view height.
*/
typedef void (*PuglReshapeFunc)(PuglView* view, int width, int height);

/**
A function called on scrolling (e.g. mouse wheel or track pad).

The distances used here are in "lines", a single tick of a clicking mouse
wheel. For example, @p dy = 1.0 scrolls 1 line up. Some systems and
devices support finer resolution and/or higher values for fast scrolls,
so programs should handle any value gracefully.

@param view The view being scrolled.
@param dx The scroll x distance.
@param dx The scroll y distance.
*/
typedef void (*PuglScrollFunc)(PuglView* view, float dx, float dy);

/**
A function called when a special key is pressed or released.

This callback allows the use of keys that do not have unicode points. Note
that some non-printable keys
@param view The view the event occured in.
@param press True if the key was pressed, false if released.
@param key The key pressed.
*/
typedef void (*PuglSpecialFunc)(PuglView* view, bool press, PuglKey key);

/**
Create a new GL window.
@param parent Parent window, or 0 for top level.
@param title Window title, or NULL.
@param width Window width in pixels.
@param height Window height in pixels.
@param resizable Whether window should be user resizable.
*/
PUGL_API PuglView*
puglCreate(PuglNativeWindow parent,
const char* title,
int width,
int height,
bool resizable,
bool addToDesktop = true,
const char* x11Display = nullptr);

/**
Set the handle to be passed to all callbacks.

This is generally a pointer to a struct which contains all necessary state.
Everything needed in callbacks should be here, not in static variables.

Note the lack of this facility makes GLUT unsuitable for plugins or
non-trivial programs; this mistake is largely why Pugl exists.
*/
PUGL_API void
puglSetHandle(PuglView* view, PuglHandle handle);

/**
Get the handle to be passed to all callbacks.
*/
PUGL_API PuglHandle
puglGetHandle(PuglView* view);

/**
Get the currently active modifiers (PuglMod flags).

This should only be called from an event handler.
*/
PUGL_API int
puglGetModifiers(PuglView* view);

/**
Ignore synthetic repeated key events.
*/
PUGL_API void
puglIgnoreKeyRepeat(PuglView* view, bool ignore);

/**
Set the function to call when the window is closed.
*/
PUGL_API void
puglSetCloseFunc(PuglView* view, PuglCloseFunc closeFunc);

/**
Set the display function which should draw the UI using GL.
*/
PUGL_API void
puglSetDisplayFunc(PuglView* view, PuglDisplayFunc displayFunc);

/**
Set the function to call on keyboard events.
*/
PUGL_API void
puglSetKeyboardFunc(PuglView* view, PuglKeyboardFunc keyboardFunc);

/**
Set the function to call on mouse motion.
*/
PUGL_API void
puglSetMotionFunc(PuglView* view, PuglMotionFunc motionFunc);

/**
Set the function to call on mouse button events.
*/
PUGL_API void
puglSetMouseFunc(PuglView* view, PuglMouseFunc mouseFunc);

/**
Set the function to call on scroll events.
*/
PUGL_API void
puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc);

/**
Set the function to call on special events.
*/
PUGL_API void
puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc);

/**
Set the function to call when the window size changes.
*/
PUGL_API void
puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc);

/**
Return the native window handle.
*/
PUGL_API PuglNativeWindow
puglGetNativeWindow(PuglView* view);

/**
Process all pending window events.

This handles input events as well as rendering, so it should be called
regularly and rapidly enough to keep the UI responsive.
*/
PUGL_API PuglStatus
puglProcessEvents(PuglView* view);

/**
Request a redisplay on the next call to puglProcessEvents().
*/
PUGL_API void
puglPostRedisplay(PuglView* view);

/**
Destroy a GL window.
*/
PUGL_API void
puglDestroy(PuglView* view);

/**
@}
*/

#endif /* PUGL_H_INCLUDED */

+ 0
- 135
source/libs/pugl/pugl_internal.h View File

@@ -1,135 +0,0 @@
/*
Copyright 2012 David Robillard <http://drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/**
@file pugl_internal.h Private platform-independent definitions.

Note this file contains function definitions, so it must be compiled into
the final binary exactly once. Each platform specific implementation file
including it once should achieve this.
*/

#include "pugl.h"

typedef struct PuglInternalsImpl PuglInternals;

struct PuglViewImpl {
PuglHandle handle;
PuglCloseFunc closeFunc;
PuglDisplayFunc displayFunc;
PuglKeyboardFunc keyboardFunc;
PuglMotionFunc motionFunc;
PuglMouseFunc mouseFunc;
PuglReshapeFunc reshapeFunc;
PuglScrollFunc scrollFunc;
PuglSpecialFunc specialFunc;

PuglInternals* impl;

int width;
int height;
int mods;
bool ignoreKeyRepeat;
bool redisplay;
};

void
puglSetHandle(PuglView* view, PuglHandle handle)
{
view->handle = handle;
}

PuglHandle
puglGetHandle(PuglView* view)
{
return view->handle;
}

int
puglGetModifiers(PuglView* view)
{
return view->mods;
}

static inline void
puglDefaultReshape(PuglView* view, int width, int height)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, height, 0, 0, 1);
glViewport(0, 0, width, height);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
return;

// unused
(void)view;
}

void
puglIgnoreKeyRepeat(PuglView* view, bool ignore)
{
view->ignoreKeyRepeat = ignore;
}

void
puglSetCloseFunc(PuglView* view, PuglCloseFunc closeFunc)
{
view->closeFunc = closeFunc;
}

void
puglSetDisplayFunc(PuglView* view, PuglDisplayFunc displayFunc)
{
view->displayFunc = displayFunc;
}

void
puglSetKeyboardFunc(PuglView* view, PuglKeyboardFunc keyboardFunc)
{
view->keyboardFunc = keyboardFunc;
}

void
puglSetMotionFunc(PuglView* view, PuglMotionFunc motionFunc)
{
view->motionFunc = motionFunc;
}

void
puglSetMouseFunc(PuglView* view, PuglMouseFunc mouseFunc)
{
view->mouseFunc = mouseFunc;
}

void
puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc)
{
view->reshapeFunc = reshapeFunc;
}

void
puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc)
{
view->scrollFunc = scrollFunc;
}

void
puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc)
{
view->specialFunc = specialFunc;
}

+ 0
- 331
source/libs/pugl/pugl_osx.m View File

@@ -1,331 +0,0 @@
/*
Copyright 2012 David Robillard <http://drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/**
@file pugl_osx.m OSX/Cocoa Pugl Implementation.
*/

#include <stdlib.h>

#import <Cocoa/Cocoa.h>

#include "pugl_internal.h"

@interface PuglOpenGLView : NSOpenGLView
{
int colorBits;
int depthBits;
@public
PuglView* view;
}

- (id) initWithFrame:(NSRect)frame
colorBits:(int)numColorBits
depthBits:(int)numDepthBits;
- (void) reshape;
- (void) drawRect:(NSRect)rect;
- (void) mouseMoved:(NSEvent*)event;
- (void) mouseDown:(NSEvent*)event;
- (void) mouseUp:(NSEvent*)event;
- (void) rightMouseDown:(NSEvent*)event;
- (void) rightMouseUp:(NSEvent*)event;
- (void) keyDown:(NSEvent*)event;
- (void) keyUp:(NSEvent*)event;
- (void) flagsChanged:(NSEvent*)event;

@end

@implementation PuglOpenGLView

- (id) initWithFrame:(NSRect)frame
colorBits:(int)numColorBits
depthBits:(int)numDepthBits
{
colorBits = numColorBits;
depthBits = numDepthBits;

NSOpenGLPixelFormatAttribute pixelAttribs[16] = {
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAAccelerated,
NSOpenGLPFAColorSize,
colorBits,
NSOpenGLPFADepthSize,
depthBits,
0
};

NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc]
initWithAttributes:pixelAttribs];

if (pixelFormat) {
self = [super initWithFrame:frame pixelFormat:pixelFormat];
[pixelFormat release];
if (self) {
[[self openGLContext] makeCurrentContext];
[self reshape];
}
} else {
self = nil;
}

return self;
}

- (void) reshape
{
[[self openGLContext] update];

NSRect bounds = [self bounds];
int width = bounds.size.width;
int height = bounds.size.height;

if (view->reshapeFunc) {
view->reshapeFunc(view, width, height);
} else {
puglDefaultReshape(view, width, height);
}

view->width = width;
view->height = height;
}

- (void) drawRect:(NSRect)rect
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

if (self->view->displayFunc) {
self->view->displayFunc(self->view);
}

glFlush();
glSwapAPPLE();
}

static int
getModifiers(unsigned modifierFlags)
{
int mods = 0;
mods |= (modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0;
mods |= (modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0;
mods |= (modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0;
mods |= (modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0;
return mods;
}

- (void) mouseMoved:(NSEvent*)event
{
if (view->motionFunc) {
NSPoint loc = [event locationInWindow];
view->mods = getModifiers([event modifierFlags]);
view->motionFunc(view, loc.x, loc.y);
}
}

- (void) mouseDown:(NSEvent*)event
{
if (view->mouseFunc) {
NSPoint loc = [event locationInWindow];
view->mods = getModifiers([event modifierFlags]);
view->mouseFunc(view, 1, true, loc.x, loc.y);
}
}

- (void) mouseUp:(NSEvent*)event
{
if (view->mouseFunc) {
NSPoint loc = [event locationInWindow];
view->mods = getModifiers([event modifierFlags]);
view->mouseFunc(view, 1, false, loc.x, loc.y);
}
}

- (void) rightMouseDown:(NSEvent*)event
{
if (view->mouseFunc) {
NSPoint loc = [event locationInWindow];
view->mods = getModifiers([event modifierFlags]);
view->mouseFunc(view, 3, true, loc.x, loc.y);
}
}

- (void) rightMouseUp:(NSEvent*)event
{
if (view->mouseFunc) {
NSPoint loc = [event locationInWindow];
view->mods = getModifiers([event modifierFlags]);
view->mouseFunc(view, 3, false, loc.x, loc.y);
}
}

- (void) scrollWheel:(NSEvent*)event
{
if (view->scrollFunc) {
view->mods = getModifiers([event modifierFlags]);
view->scrollFunc(view, [event deltaX], [event deltaY]);
}
}

- (void) keyDown:(NSEvent*)event
{
if (view->keyboardFunc && !(view->ignoreKeyRepeat && [event isARepeat])) {
NSString* chars = [event characters];
view->mods = getModifiers([event modifierFlags]);
view->keyboardFunc(view, true, [chars characterAtIndex:0]);
}
}

- (void) keyUp:(NSEvent*)event
{
if (view->keyboardFunc) {
NSString* chars = [event characters];
view->mods = getModifiers([event modifierFlags]);
view->keyboardFunc(view, false, [chars characterAtIndex:0]);
}
}

- (void) flagsChanged:(NSEvent*)event
{
if (view->specialFunc) {
int mods = getModifiers([event modifierFlags]);
if ((mods & PUGL_MOD_SHIFT) != (view->mods & PUGL_MOD_SHIFT)) {
view->specialFunc(view, mods & PUGL_MOD_SHIFT, PUGL_KEY_SHIFT);
} else if ((mods & PUGL_MOD_CTRL) != (view->mods & PUGL_MOD_CTRL)) {
view->specialFunc(view, mods & PUGL_MOD_CTRL, PUGL_KEY_CTRL);
} else if ((mods & PUGL_MOD_ALT) != (view->mods & PUGL_MOD_ALT)) {
view->specialFunc(view, mods & PUGL_MOD_ALT, PUGL_KEY_ALT);
} else if ((mods & PUGL_MOD_SUPER) != (view->mods & PUGL_MOD_SUPER)) {
view->specialFunc(view, mods & PUGL_MOD_SUPER, PUGL_KEY_SUPER);
}
view->mods = mods;
}
}

@end

struct PuglInternalsImpl {
PuglOpenGLView* view;
NSModalSession session;
id window;
};

PuglView*
puglCreate(PuglNativeWindow parent,
const char* title,
int width,
int height,
bool resizable,
bool addToDesktop,
const char* x11Display)
{
PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
if (!view || !impl) {
return NULL;
}

view->impl = impl;
view->width = width;
view->height = height;

[NSAutoreleasePool new];
[NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];

NSString* titleString = [[NSString alloc]
initWithBytes:title
length:strlen(title)
encoding:NSUTF8StringEncoding];

id window = [[[NSWindow alloc]
initWithContentRect:NSMakeRect(0, 0, 512, 512)
styleMask:NSTitledWindowMask
backing:NSBackingStoreBuffered
defer:NO]
autorelease];

[window cascadeTopLeftFromPoint:NSMakePoint(20, 20)];
[window setTitle:titleString];
[window setAcceptsMouseMovedEvents:YES];

impl->view = [PuglOpenGLView new];
impl->window = window;
impl->view->view = view;

[window setContentView:impl->view];
[NSApp activateIgnoringOtherApps:YES];
[window makeFirstResponder:impl->view];

impl->session = [NSApp beginModalSessionForWindow:view->impl->window];

return view;

// unused
(void)addToDesktop;
(void)x11Display;
}

void
puglDestroy(PuglView* view)
{
[NSApp endModalSession:view->impl->session];
[view->impl->view release];
free(view->impl);
free(view);
}

void
puglDisplay(PuglView* view)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

if (view->displayFunc) {
view->displayFunc(view);
}

glFlush();
view->redisplay = false;
}

PuglStatus
puglProcessEvents(PuglView* view)
{
NSInteger response = [NSApp runModalSession:view->impl->session];
if (response != NSRunContinuesResponse) {
if (view->closeFunc) {
view->closeFunc(view);
}
}

if (view->redisplay) {
puglDisplay(view);
}

return PUGL_SUCCESS;
}

void
puglPostRedisplay(PuglView* view)
{
view->redisplay = true;
}

PuglNativeWindow
puglGetNativeWindow(PuglView* view)
{
return (PuglNativeWindow)view->impl->view;
}

+ 0
- 344
source/libs/pugl/pugl_win.cpp View File

@@ -1,344 +0,0 @@
/*
Copyright 2012 David Robillard <http://drobilla.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/**
@file pugl_win.cpp Windows/WGL Pugl Implementation.
*/

#include <windows.h>
#include <windowsx.h>
#include <GL/gl.h>

#include "pugl_internal.h"

#ifndef WM_MOUSEWHEEL
# define WM_MOUSEWHEEL 0x020A
#endif
#ifndef WM_MOUSEHWHEEL
# define WM_MOUSEHWHEEL 0x020E
#endif

struct PuglInternalsImpl {
HWND hwnd;
HDC hdc;
HGLRC hglrc;
};

LRESULT CALLBACK
wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

PuglView*
puglCreate(PuglNativeWindow parent,
const char* title,
int width,
int height,
bool resizable,
bool addToDesktop,
const char* x11Display)
{
PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
if (!view || !impl) {
return NULL;
}

view->impl = impl;
view->width = width;
view->height = height;

WNDCLASS wc;
wc.style = CS_OWNDC;
wc.lpfnWndProc = wndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = 0;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "Pugl";
RegisterClass(&wc);

impl->hwnd = CreateWindow(
"Pugl", title,
(addToDesktop ? WS_VISIBLE : 0) | (parent ? WS_CHILD : (WS_POPUPWINDOW | WS_CAPTION)),
0, 0, width, height,
(HWND)parent, NULL, NULL, NULL);
if (!impl->hwnd) {
free(impl);
free(view);
return NULL;
}
SetWindowLongPtr(impl->hwnd, GWL_USERDATA, (LONG)view);

impl->hdc = GetDC(impl->hwnd);

PIXELFORMATDESCRIPTOR pfd;
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;

int format = ChoosePixelFormat(impl->hdc, &pfd);
SetPixelFormat(impl->hdc, format, &pfd);

impl->hglrc = wglCreateContext(impl->hdc);
wglMakeCurrent(impl->hdc, impl->hglrc);

view->width = width;
view->height = height;

return view;

// unused
(void)resizable;
(void)x11Display;
}

void
puglDestroy(PuglView* view)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(view->impl->hglrc);
ReleaseDC(view->impl->hwnd, view->impl->hdc);
DestroyWindow(view->impl->hwnd);
free(view->impl);
free(view);
}

void
puglReshape(PuglView* view, int width, int height)
{
wglMakeCurrent(view->impl->hdc, view->impl->hglrc);

if (view->reshapeFunc) {
view->reshapeFunc(view, width, height);
} else {
puglDefaultReshape(view, width, height);
}

view->width = width;
view->height = height;
}

void
puglDisplay(PuglView* view)
{
wglMakeCurrent(view->impl->hdc, view->impl->hglrc);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

if (view->displayFunc) {
view->displayFunc(view);
}

glFlush();
SwapBuffers(view->impl->hdc);
view->redisplay = false;
}

static PuglKey
keySymToSpecial(int sym)
{
switch (sym) {
case VK_F1: return PUGL_KEY_F1;
case VK_F2: return PUGL_KEY_F2;
case VK_F3: return PUGL_KEY_F3;
case VK_F4: return PUGL_KEY_F4;
case VK_F5: return PUGL_KEY_F5;
case VK_F6: return PUGL_KEY_F6;
case VK_F7: return PUGL_KEY_F7;
case VK_F8: return PUGL_KEY_F8;
case VK_F9: return PUGL_KEY_F9;
case VK_F10: return PUGL_KEY_F10;
case VK_F11: return PUGL_KEY_F11;
case VK_F12: return PUGL_KEY_F12;
case VK_LEFT: return PUGL_KEY_LEFT;
case VK_UP: return PUGL_KEY_UP;
case VK_RIGHT: return PUGL_KEY_RIGHT;
case VK_DOWN: return PUGL_KEY_DOWN;
case VK_PRIOR: return PUGL_KEY_PAGE_UP;
case VK_NEXT: return PUGL_KEY_PAGE_DOWN;
case VK_HOME: return PUGL_KEY_HOME;
case VK_END: return PUGL_KEY_END;
case VK_INSERT: return PUGL_KEY_INSERT;
case VK_SHIFT: return PUGL_KEY_SHIFT;
case VK_CONTROL: return PUGL_KEY_CTRL;
case VK_MENU: return PUGL_KEY_ALT;
case VK_LWIN: return PUGL_KEY_SUPER;
case VK_RWIN: return PUGL_KEY_SUPER;
}
return (PuglKey)0;
}

static void
processMouseEvent(PuglView* view, int button, bool press, LPARAM lParam)
{
if (view->mouseFunc) {
view->mouseFunc(view, button, press,
GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam));
}
}

static void
setModifiers(PuglView* view)
{
view->mods = 0;
view->mods |= (GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0;
view->mods |= (GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0;
view->mods |= (GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0;
view->mods |= (GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0;
view->mods |= (GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0;
}

static LRESULT
handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
PuglKey key;

setModifiers(view);
switch (message) {
case WM_CREATE:
case WM_SHOWWINDOW:
case WM_SIZE:
puglReshape(view, view->width, view->height);
break;
case WM_PAINT:
BeginPaint(view->impl->hwnd, &ps);
puglDisplay(view);
EndPaint(view->impl->hwnd, &ps);
break;
case WM_MOUSEMOVE:
if (view->motionFunc) {
view->motionFunc(
view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
}
break;
case WM_LBUTTONDOWN:
processMouseEvent(view, 1, true, lParam);
break;
case WM_MBUTTONDOWN:
processMouseEvent(view, 2, true, lParam);
break;
case WM_RBUTTONDOWN:
processMouseEvent(view, 3, true, lParam);
break;
case WM_LBUTTONUP:
processMouseEvent(view, 1, false, lParam);
break;
case WM_MBUTTONUP:
processMouseEvent(view, 2, false, lParam);
break;
case WM_RBUTTONUP:
processMouseEvent(view, 3, false, lParam);
break;
case WM_MOUSEWHEEL:
if (view->scrollFunc) {
view->scrollFunc(
view, 0, (int16_t)HIWORD(wParam) / (float)WHEEL_DELTA);
}
break;
case WM_MOUSEHWHEEL:
if (view->scrollFunc) {
view->scrollFunc(
view, (int16_t)HIWORD(wParam) / float(WHEEL_DELTA), 0);
}
break;
case WM_KEYDOWN:
if (view->ignoreKeyRepeat && (lParam & (1 << 30))) {
break;
} // else nobreak
case WM_KEYUP:
if ((key = keySymToSpecial(wParam))) {
if (view->specialFunc) {
view->specialFunc(view, message == WM_KEYDOWN, key);
}
} else if (view->keyboardFunc) {
view->keyboardFunc(view, message == WM_KEYDOWN, wParam);
}
break;
case WM_QUIT:
if (view->closeFunc) {
view->closeFunc(view);
}
break;
default:
return DefWindowProc(
view->impl->hwnd, message, wParam, lParam);
}

return 0;
}

PuglStatus
puglProcessEvents(PuglView* view)
{
MSG msg;
while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) {
handleMessage(view, msg.message, msg.wParam, msg.lParam);
}

if (view->redisplay) {
puglDisplay(view);
}

return PUGL_SUCCESS;
}

LRESULT CALLBACK
wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWL_USERDATA);
switch (message) {
case WM_CREATE:
PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0);
return 0;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
case WM_DESTROY:
return 0;
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
PostMessage(hwnd, message, wParam, lParam);
return 0;
default:
if (view) {
return handleMessage(view, message, wParam, lParam);
} else {
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
}

void
puglPostRedisplay(PuglView* view)
{
view->redisplay = true;
}

PuglNativeWindow
puglGetNativeWindow(PuglView* view)
{
return (PuglNativeWindow)view->impl->hwnd;
}

+ 0
- 379
source/libs/pugl/pugl_x11.c View File

@@ -1,379 +0,0 @@
/*
Copyright 2012 David Robillard <http://drobilla.net>
Copyright 2011-2012 Ben Loftis, Harrison Consoles

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/**
@file pugl_x11.c X11 Pugl Implementation.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "pugl_x11.h"
#include "pugl_internal.h"

/**
Attributes for single-buffered RGBA with at least
4 bits per color and a 16 bit depth buffer.
*/
static int attrListSgl[] = {
GLX_RGBA,
GLX_RED_SIZE, 4,
GLX_GREEN_SIZE, 4,
GLX_BLUE_SIZE, 4,
GLX_DEPTH_SIZE, 16,
None
};

/**
Attributes for double-buffered RGBA with at least
4 bits per color and a 16 bit depth buffer.
*/
static int attrListDbl[] = {
GLX_RGBA, GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 4,
GLX_GREEN_SIZE, 4,
GLX_BLUE_SIZE, 4,
GLX_DEPTH_SIZE, 16,
None
};

PuglView*
puglCreate(PuglNativeWindow parent,
const char* title,
int width,
int height,
bool resizable,
bool addToDesktop,
const char* x11Display)
{
PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
if (!view || !impl) {
return nullptr;
}

view->impl = impl;
view->width = width;
view->height = height;

impl->display = XOpenDisplay(x11Display);
impl->screen = DefaultScreen(impl->display);

XVisualInfo* vi = glXChooseVisual(impl->display, impl->screen, attrListDbl);
if (!vi) {
vi = glXChooseVisual(impl->display, impl->screen, attrListSgl);
impl->doubleBuffered = False;
printf("singlebuffered rendering will be used, no doublebuffering available\n");
} else {
impl->doubleBuffered = True;
printf("doublebuffered rendering available\n");
}

int glxMajor, glxMinor;
glXQueryVersion(impl->display, &glxMajor, &glxMinor);
printf("GLX-Version %d.%d\n", glxMajor, glxMinor);

impl->ctx = glXCreateContext(impl->display, vi, nullptr, GL_TRUE);

Window xParent = parent
? (Window)parent
: RootWindow(impl->display, impl->screen);

Colormap cmap = XCreateColormap(
impl->display, xParent, vi->visual, AllocNone);

XSetWindowAttributes attr;
memset(&attr, 0, sizeof(XSetWindowAttributes));
attr.colormap = cmap;
attr.border_pixel = 0;

attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask
| ButtonPressMask | ButtonReleaseMask
| PointerMotionMask | StructureNotifyMask;

impl->win = XCreateWindow(
impl->display, xParent,
0, 0, (unsigned int)view->width, (unsigned int)view->height, 0, vi->depth, InputOutput, vi->visual,
CWBorderPixel | CWColormap | CWEventMask, &attr);

XSizeHints sizeHints;
memset(&sizeHints, 0, sizeof(sizeHints));
if (!resizable) {
sizeHints.flags = PMinSize|PMaxSize;
sizeHints.min_width = width;
sizeHints.min_height = height;
sizeHints.max_width = width;
sizeHints.max_height = height;
XSetNormalHints(impl->display, impl->win, &sizeHints);
}

if (title) {
XStoreName(impl->display, impl->win, title);
}

if (!parent) {
Atom wmDelete = XInternAtom(impl->display, "WM_DELETE_WINDOW", True);
XSetWMProtocols(impl->display, impl->win, &wmDelete, 1);
}

if (addToDesktop) {
XMapRaised(impl->display, impl->win);
}

if (glXIsDirect(impl->display, impl->ctx)) {
printf("DRI enabled\n");
} else {
printf("no DRI available\n");
}

XFree(vi);

return view;
}

void
puglDestroy(PuglView* view)
{
if (!view) {
return;
}

glXDestroyContext(view->impl->display, view->impl->ctx);
XDestroyWindow(view->impl->display, view->impl->win);
XCloseDisplay(view->impl->display);
free(view->impl);
free(view);
}

static void
puglReshape(PuglView* view, int width, int height)
{
glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx);

if (view->reshapeFunc) {
view->reshapeFunc(view, width, height);
} else {
puglDefaultReshape(view, width, height);
}

view->width = width;
view->height = height;
}

static void
puglDisplay(PuglView* view)
{
glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

if (view->displayFunc) {
view->displayFunc(view);
}

glFlush();
if (view->impl->doubleBuffered) {
glXSwapBuffers(view->impl->display, view->impl->win);
}

view->redisplay = false;
}

static PuglKey
keySymToSpecial(KeySym sym)
{
switch (sym) {
case XK_F1: return PUGL_KEY_F1;
case XK_F2: return PUGL_KEY_F2;
case XK_F3: return PUGL_KEY_F3;
case XK_F4: return PUGL_KEY_F4;
case XK_F5: return PUGL_KEY_F5;
case XK_F6: return PUGL_KEY_F6;
case XK_F7: return PUGL_KEY_F7;
case XK_F8: return PUGL_KEY_F8;
case XK_F9: return PUGL_KEY_F9;
case XK_F10: return PUGL_KEY_F10;
case XK_F11: return PUGL_KEY_F11;
case XK_F12: return PUGL_KEY_F12;
case XK_Left: return PUGL_KEY_LEFT;
case XK_Up: return PUGL_KEY_UP;
case XK_Right: return PUGL_KEY_RIGHT;
case XK_Down: return PUGL_KEY_DOWN;
case XK_Page_Up: return PUGL_KEY_PAGE_UP;
case XK_Page_Down: return PUGL_KEY_PAGE_DOWN;
case XK_Home: return PUGL_KEY_HOME;
case XK_End: return PUGL_KEY_END;
case XK_Insert: return PUGL_KEY_INSERT;
case XK_Shift_L: return PUGL_KEY_SHIFT;
case XK_Shift_R: return PUGL_KEY_SHIFT;
case XK_Control_L: return PUGL_KEY_CTRL;
case XK_Control_R: return PUGL_KEY_CTRL;
case XK_Alt_L: return PUGL_KEY_ALT;
case XK_Alt_R: return PUGL_KEY_ALT;
case XK_Super_L: return PUGL_KEY_SUPER;
case XK_Super_R: return PUGL_KEY_SUPER;
}
return (PuglKey)0;
}

static void
setModifiers(PuglView* view, int xstate)
{
view->mods = 0;
view->mods |= (xstate & ShiftMask) ? PUGL_MOD_SHIFT : 0;
view->mods |= (xstate & ControlMask) ? PUGL_MOD_CTRL : 0;
view->mods |= (xstate & Mod1Mask) ? PUGL_MOD_ALT : 0;
view->mods |= (xstate & Mod4Mask) ? PUGL_MOD_SUPER : 0;
}

PuglStatus
puglProcessEvents(PuglView* view)
{
XEvent event;
while (XPending(view->impl->display) > 0) {
XNextEvent(view->impl->display, &event);
switch (event.type) {
case MapNotify:
puglReshape(view, view->width, view->height);
break;
case ConfigureNotify:
if ((event.xconfigure.width != view->width) ||
(event.xconfigure.height != view->height)) {
puglReshape(view,
event.xconfigure.width,
event.xconfigure.height);
}
break;
case Expose:
if (event.xexpose.count != 0) {
break;
}
puglDisplay(view);
view->redisplay = false;
break;
case MotionNotify:
setModifiers(view, (int)event.xmotion.state);
if (view->motionFunc) {
view->motionFunc(view, event.xmotion.x, event.xmotion.y);
}
break;
case ButtonPress:
setModifiers(view, (int)event.xbutton.state);
if (event.xbutton.button >= 4 && event.xbutton.button <= 7) {
if (view->scrollFunc) {
float dx = 0, dy = 0;
switch (event.xbutton.button) {
case 4: dy = 1.0f; break;
case 5: dy = -1.0f; break;
case 6: dx = -1.0f; break;
case 7: dx = 1.0f; break;
}
view->scrollFunc(view, dx, dy);
}
break;
}
// nobreak
case ButtonRelease:
setModifiers(view, (int)event.xbutton.state);
if (view->mouseFunc &&
(event.xbutton.button < 4 || event.xbutton.button > 7)) {
view->mouseFunc(view,
(int)event.xbutton.button, event.type == ButtonPress,
event.xbutton.x, event.xbutton.y);
}
break;
case KeyPress: {
setModifiers(view, (int)event.xkey.state);
KeySym sym;
char str[5];
int n = XLookupString(&event.xkey, str, 4, &sym, nullptr);
PuglKey key = keySymToSpecial(sym);
if (!key && view->keyboardFunc) {
if (n == 1) {
view->keyboardFunc(view, true, (uint32_t)str[0]);
} else {
fprintf(stderr, "warning: Unknown key %X\n", (int)sym);
}
} else if (view->specialFunc) {
view->specialFunc(view, true, key);
}
} break;
case KeyRelease: {
setModifiers(view, (int)event.xkey.state);
bool repeated = false;
if (view->ignoreKeyRepeat &&
XEventsQueued(view->impl->display, QueuedAfterReading)) {
XEvent next;
XPeekEvent(view->impl->display, &next);
if (next.type == KeyPress &&
next.xkey.time == event.xkey.time &&
next.xkey.keycode == event.xkey.keycode) {
XNextEvent(view->impl->display, &event);
repeated = true;
}
}

if (!repeated && view->keyboardFunc) {
KeySym sym = XKeycodeToKeysym(
view->impl->display, (KeyCode)event.xkey.keycode, 0);
PuglKey special = keySymToSpecial(sym);
if (!special) {
view->keyboardFunc(view, false, (uint32_t)sym);
} else if (view->specialFunc) {
view->specialFunc(view, false, special);
}
}
} break;
case ClientMessage:
if (!strcmp(XGetAtomName(view->impl->display,
event.xclient.message_type),
"WM_PROTOCOLS")) {
if (view->closeFunc) {
view->closeFunc(view);
}
}
break;
default:
break;
}
}

if (view->redisplay) {
puglDisplay(view);
}

return PUGL_SUCCESS;
}

void
puglPostRedisplay(PuglView* view)
{
view->redisplay = true;
}

PuglNativeWindow
puglGetNativeWindow(PuglView* view)
{
return static_cast<PuglNativeWindow>(view->impl->win);
}

PuglInternals*
puglGetInternalsImpl(PuglView* view)
{
return view->impl;
}

+ 0
- 46
source/libs/pugl/pugl_x11.h View File

@@ -1,46 +0,0 @@
/*
Copyright 2012 David Robillard <http://drobilla.net>
Copyright 2011-2012 Ben Loftis, Harrison Consoles

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/**
@file pugl_x11.h X11 Pugl Implementation (PuglInternalsImpl only).
*/

#ifndef PUGL_X11_H_INCLUDED
#define PUGL_X11_H_INCLUDED

#include "pugl.h"

#include <GL/gl.h>
#include <GL/glx.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>

struct PuglInternalsImpl {
Display* display;
int screen;
Window win;
GLXContext ctx;
Bool doubleBuffered;
};

typedef struct PuglInternalsImpl PuglInternals;

PuglInternals*
puglGetInternalsImpl(PuglView* view);

#endif /* PUGL_X11_H_INCLUDED */

Loading…
Cancel
Save