@@ -19,10 +19,6 @@ | |||||
#include "../Base.hpp" | #include "../Base.hpp" | ||||
#undef PUGL_HAVE_CAIRO | |||||
#undef PUGL_HAVE_GL | |||||
#define PUGL_HAVE_GL 1 | |||||
#include "pugl/pugl.h" | #include "pugl/pugl.h" | ||||
#if defined(__GNUC__) && (__GNUC__ >= 7) | #if defined(__GNUC__) && (__GNUC__ >= 7) | ||||
@@ -619,7 +615,7 @@ struct Window::PrivateData { | |||||
sizeHints.max_width = static_cast<int>(width); | sizeHints.max_width = static_cast<int>(width); | ||||
sizeHints.max_height = static_cast<int>(height); | sizeHints.max_height = static_cast<int>(height); | ||||
XSetNormalHints(xDisplay, xWindow, &sizeHints); | |||||
XSetWMNormalHints(xDisplay, xWindow, &sizeHints); | |||||
} | } | ||||
if (! forced) | if (! forced) | ||||
@@ -32,6 +32,7 @@ | |||||
# include "OpenGL/gl.h" | # include "OpenGL/gl.h" | ||||
#else | #else | ||||
# ifdef _WIN32 | # ifdef _WIN32 | ||||
# include <winsock2.h> | |||||
# include <windows.h> /* Broken Windows GL headers require this */ | # include <windows.h> /* Broken Windows GL headers require this */ | ||||
# endif | # endif | ||||
# include "GL/gl.h" | # include "GL/gl.h" | ||||
@@ -177,6 +178,16 @@ typedef void (*PuglMouseFunc)( | |||||
*/ | */ | ||||
typedef void (*PuglReshapeFunc)(PuglView* view, int width, int height); | typedef void (*PuglReshapeFunc)(PuglView* view, int width, int height); | ||||
/** | |||||
A function called outside of gl-context when the plugin schedules a resize via puglPostResize. | |||||
@param view The view being resized. | |||||
@param width The new width to resize to (variable is initialized to current size) | |||||
@param height The new height to resize to (variable is initialized to current size) | |||||
@param set_hints If not null, set window-hints | |||||
*/ | |||||
typedef void (*PuglResizeFunc)(PuglView* view, int *width, int *height, int *set_hints); | |||||
/** | /** | ||||
A function called on scrolling (e.g. mouse wheel or track pad). | A function called on scrolling (e.g. mouse wheel or track pad). | ||||
@@ -281,13 +292,31 @@ PUGL_API int | |||||
puglCreateWindow(PuglView* view, const char* title); | puglCreateWindow(PuglView* view, const char* title); | ||||
/** | /** | ||||
Show the current window. | |||||
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 min_width, | |||||
int min_height, | |||||
int width, | |||||
int height, | |||||
bool resizable, | |||||
unsigned long transientId); | |||||
/** | |||||
Show Window (external ui) | |||||
*/ | */ | ||||
PUGL_API void | PUGL_API void | ||||
puglShowWindow(PuglView* view); | puglShowWindow(PuglView* view); | ||||
/** | /** | ||||
Hide the current window. | |||||
Hide Window (external ui) | |||||
*/ | */ | ||||
PUGL_API void | PUGL_API void | ||||
puglHideWindow(PuglView* view); | puglHideWindow(PuglView* view); | ||||
@@ -394,6 +423,12 @@ puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc); | |||||
PUGL_API void | PUGL_API void | ||||
puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc); | puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc); | ||||
/** | |||||
Set callback function to change window size. | |||||
*/ | |||||
PUGL_API void | |||||
puglSetResizeFunc(PuglView* view, PuglResizeFunc resizeFunc); | |||||
/** | /** | ||||
Set the function to call on file-browser selections. | Set the function to call on file-browser selections. | ||||
*/ | */ | ||||
@@ -404,6 +439,12 @@ puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc); | |||||
@} | @} | ||||
*/ | */ | ||||
/** | |||||
TODO document this. | |||||
*/ | |||||
PUGL_API int | |||||
puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect); | |||||
/** | /** | ||||
Grab the input focus. | Grab the input focus. | ||||
*/ | */ | ||||
@@ -425,6 +466,12 @@ puglProcessEvents(PuglView* view); | |||||
PUGL_API void | PUGL_API void | ||||
puglPostRedisplay(PuglView* view); | puglPostRedisplay(PuglView* view); | ||||
/** | |||||
Request a resize on the next call to puglProcessEvents(). | |||||
*/ | |||||
PUGL_API void | |||||
puglPostResize(PuglView* view); | |||||
/** | /** | ||||
Destroy a GL window. | Destroy a GL window. | ||||
*/ | */ | ||||
@@ -20,26 +20,9 @@ | |||||
Note this file contains function definitions, so it must be compiled into | Note this file contains function definitions, so it must be compiled into | ||||
the final binary exactly once. Each platform specific implementation file | the final binary exactly once. Each platform specific implementation file | ||||
including it once should achieve this. | including it once should achieve this. | ||||
If you are copying the pugl code into your source tree, the following | |||||
symbols can be defined to tweak pugl behaviour: | |||||
PUGL_HAVE_CAIRO: Include Cairo support code. | |||||
PUGL_HAVE_GL: Include OpenGL support code. | |||||
PUGL_GRAB_FOCUS: Work around reparent keyboard issues by grabbing focus. | |||||
PUGL_VERBOSE: Print GL information to console. | |||||
*/ | */ | ||||
#include "pugl/pugl.h" | |||||
#ifdef PUGL_VERBOSE | |||||
# include <stdio.h> | |||||
# define PUGL_LOG(str) fprintf(stderr, "pugl: " str) | |||||
# define PUGL_LOGF(fmt, ...) fprintf(stderr, "pugl: " fmt, __VA_ARGS__) | |||||
#else | |||||
# define PUGL_LOG(str) | |||||
# define PUGL_LOGF(fmt, ...) | |||||
#endif | |||||
#include "pugl.h" | |||||
typedef struct PuglInternalsImpl PuglInternals; | typedef struct PuglInternalsImpl PuglInternals; | ||||
@@ -51,12 +34,12 @@ struct PuglViewImpl { | |||||
PuglMotionFunc motionFunc; | PuglMotionFunc motionFunc; | ||||
PuglMouseFunc mouseFunc; | PuglMouseFunc mouseFunc; | ||||
PuglReshapeFunc reshapeFunc; | PuglReshapeFunc reshapeFunc; | ||||
PuglResizeFunc resizeFunc; | |||||
PuglScrollFunc scrollFunc; | PuglScrollFunc scrollFunc; | ||||
PuglSpecialFunc specialFunc; | PuglSpecialFunc specialFunc; | ||||
PuglFileSelectedFunc fileSelectedFunc; | PuglFileSelectedFunc fileSelectedFunc; | ||||
PuglInternals* impl; | |||||
PuglInternals* impl; | |||||
PuglNativeWindow parent; | PuglNativeWindow parent; | ||||
uintptr_t transient_parent; | uintptr_t transient_parent; | ||||
@@ -68,7 +51,8 @@ struct PuglViewImpl { | |||||
bool mouse_in_view; | bool mouse_in_view; | ||||
bool ignoreKeyRepeat; | bool ignoreKeyRepeat; | ||||
bool redisplay; | bool redisplay; | ||||
bool resizable; | |||||
bool user_resizable; | |||||
bool pending_resize; | |||||
uint32_t event_timestamp_ms; | uint32_t event_timestamp_ms; | ||||
}; | }; | ||||
@@ -118,7 +102,7 @@ puglInitWindowParent(PuglView* view, PuglNativeWindow parent) | |||||
void | void | ||||
puglInitUserResizable(PuglView* view, bool resizable) | puglInitUserResizable(PuglView* view, bool resizable) | ||||
{ | { | ||||
view->resizable = resizable; | |||||
view->user_resizable = resizable; | |||||
} | } | ||||
void | void | ||||
@@ -127,6 +111,35 @@ puglInitTransientFor(PuglView* view, uintptr_t parent) | |||||
view->transient_parent = parent; | view->transient_parent = parent; | ||||
} | } | ||||
PuglView* | |||||
puglCreate(PuglNativeWindow parent, | |||||
const char* title, | |||||
int min_width, | |||||
int min_height, | |||||
int width, | |||||
int height, | |||||
bool resizable, | |||||
unsigned long transientId) | |||||
{ | |||||
PuglView* view = puglInit(); | |||||
if (!view) { | |||||
return NULL; | |||||
} | |||||
puglInitWindowParent(view, parent); | |||||
puglInitWindowMinSize(view, min_width, min_height); | |||||
puglInitWindowSize(view, width, height); | |||||
puglInitUserResizable(view, resizable); | |||||
puglInitTransientFor(view, transientId); | |||||
if (!puglCreateWindow(view, title)) { | |||||
free(view); | |||||
return NULL; | |||||
} | |||||
return view; | |||||
} | |||||
void | void | ||||
puglSetHandle(PuglView* view, PuglHandle handle) | puglSetHandle(PuglView* view, PuglHandle handle) | ||||
{ | { | ||||
@@ -193,6 +206,12 @@ puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc) | |||||
view->reshapeFunc = reshapeFunc; | view->reshapeFunc = reshapeFunc; | ||||
} | } | ||||
void | |||||
puglSetResizeFunc(PuglView* view, PuglResizeFunc resizeFunc) | |||||
{ | |||||
view->resizeFunc = resizeFunc; | |||||
} | |||||
void | void | ||||
puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc) | puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc) | ||||
{ | { | ||||
@@ -217,45 +236,19 @@ puglEnterContext(PuglView* view); | |||||
void | void | ||||
puglLeaveContext(PuglView* view, bool flush); | puglLeaveContext(PuglView* view, bool flush); | ||||
#if 0 | |||||
/** Return the code point for buf, or the replacement character on error. */ | |||||
static uint32_t | |||||
puglDecodeUTF8(const uint8_t* buf) | |||||
{ | |||||
#define FAIL_IF(cond) { if (cond) return 0xFFFD; } | |||||
/* http://en.wikipedia.org/wiki/UTF-8 */ | |||||
if (buf[0] < 0x80) { | |||||
return buf[0]; | |||||
} else if (buf[0] < 0xC2) { | |||||
return 0xFFFD; | |||||
} else if (buf[0] < 0xE0) { | |||||
FAIL_IF((buf[1] & 0xC0) != 0x80); | |||||
return (buf[0] << 6) + buf[1] - 0x3080; | |||||
} else if (buf[0] < 0xF0) { | |||||
FAIL_IF((buf[1] & 0xC0) != 0x80); | |||||
FAIL_IF(buf[0] == 0xE0 && buf[1] < 0xA0); | |||||
FAIL_IF((buf[2] & 0xC0) != 0x80); | |||||
return (buf[0] << 12) + (buf[1] << 6) + buf[2] - 0xE2080; | |||||
} else if (buf[0] < 0xF5) { | |||||
FAIL_IF((buf[1] & 0xC0) != 0x80); | |||||
FAIL_IF(buf[0] == 0xF0 && buf[1] < 0x90); | |||||
FAIL_IF(buf[0] == 0xF4 && buf[1] >= 0x90); | |||||
FAIL_IF((buf[2] & 0xC0) != 0x80); | |||||
FAIL_IF((buf[3] & 0xC0) != 0x80); | |||||
return ((buf[0] << 18) + | |||||
(buf[1] << 12) + | |||||
(buf[2] << 6) + | |||||
buf[3] - 0x3C82080); | |||||
} | |||||
return 0xFFFD; | |||||
} | |||||
#endif | |||||
static void | static void | ||||
puglDefaultReshape(PuglView* view, int width, int height) | |||||
puglDefaultReshape(int width, int height) | |||||
{ | { | ||||
#ifdef ROBTK_HERE | |||||
glViewport(0, 0, width, height); | |||||
glMatrixMode(GL_PROJECTION); | |||||
glLoadIdentity(); | |||||
glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); | |||||
glClear(GL_COLOR_BUFFER_BIT); | |||||
glMatrixMode(GL_MODELVIEW); | |||||
glLoadIdentity(); | |||||
#else | |||||
glMatrixMode(GL_PROJECTION); | glMatrixMode(GL_PROJECTION); | ||||
glLoadIdentity(); | glLoadIdentity(); | ||||
glOrtho(0, width, height, 0, 0, 1); | glOrtho(0, width, height, 0, 0, 1); | ||||
@@ -263,82 +256,5 @@ puglDefaultReshape(PuglView* view, int width, int height) | |||||
glMatrixMode(GL_MODELVIEW); | glMatrixMode(GL_MODELVIEW); | ||||
glLoadIdentity(); | glLoadIdentity(); | ||||
return; | |||||
// unused | |||||
(void)view; | |||||
} | |||||
#if 0 | |||||
static void | |||||
puglDispatchEvent(PuglView* view, const PuglEvent* event) | |||||
{ | |||||
if (view->eventFunc) { | |||||
view->eventFunc(view, event); | |||||
} | |||||
switch (event->type) { | |||||
case PUGL_CONFIGURE: | |||||
puglEnterContext(view); | |||||
view->width = event->configure.width; | |||||
view->height = event->configure.height; | |||||
if (view->reshapeFunc) { | |||||
view->reshapeFunc(view, view->width, view->height); | |||||
} | |||||
puglLeaveContext(view, false); | |||||
break; | |||||
case PUGL_EXPOSE: | |||||
if (event->expose.count == 0) { | |||||
puglEnterContext(view); | |||||
if (view->displayFunc) { | |||||
view->displayFunc(view); | |||||
} | |||||
view->redisplay = false; | |||||
puglLeaveContext(view, true); | |||||
} | |||||
break; | |||||
case PUGL_MOTION_NOTIFY: | |||||
view->event_timestamp_ms = event->motion.time; | |||||
view->mods = event->motion.state; | |||||
if (view->motionFunc) { | |||||
view->motionFunc(view, event->motion.x, event->motion.y); | |||||
} | |||||
break; | |||||
case PUGL_SCROLL: | |||||
if (view->scrollFunc) { | |||||
view->scrollFunc(view, | |||||
event->scroll.x, event->scroll.y, | |||||
event->scroll.dx, event->scroll.dy); | |||||
} | |||||
break; | |||||
case PUGL_BUTTON_PRESS: | |||||
case PUGL_BUTTON_RELEASE: | |||||
view->event_timestamp_ms = event->button.time; | |||||
view->mods = event->button.state; | |||||
if (view->mouseFunc) { | |||||
view->mouseFunc(view, | |||||
event->button.button, | |||||
event->type == PUGL_BUTTON_PRESS, | |||||
event->button.x, | |||||
event->button.y); | |||||
} | |||||
break; | |||||
case PUGL_KEY_PRESS: | |||||
case PUGL_KEY_RELEASE: | |||||
view->event_timestamp_ms = event->key.time; | |||||
view->mods = event->key.state; | |||||
if (event->key.special && view->specialFunc) { | |||||
view->specialFunc(view, | |||||
event->type == PUGL_KEY_PRESS, | |||||
event->key.special); | |||||
} else if (event->key.character && view->keyboardFunc) { | |||||
view->keyboardFunc(view, | |||||
event->type == PUGL_KEY_PRESS, | |||||
event->key.character); | |||||
} | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
} | |||||
#endif | #endif | ||||
} |
@@ -218,7 +218,7 @@ puglDisplay(PuglView* view) | |||||
if (puglview->reshapeFunc) { | if (puglview->reshapeFunc) { | ||||
puglview->reshapeFunc(puglview, width, height); | puglview->reshapeFunc(puglview, width, height); | ||||
} else { | } else { | ||||
puglDefaultReshape(puglview, width, height); | |||||
puglDefaultReshape(width, height); | |||||
} | } | ||||
puglLeaveContext(puglview, false); | puglLeaveContext(puglview, false); | ||||
@@ -459,7 +459,7 @@ puglCreateWindow(PuglView* view, const char* title) | |||||
impl->glview->puglview = view; | impl->glview->puglview = view; | ||||
if (view->resizable) { | |||||
if (view->user_resizable) { | |||||
[impl->glview setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; | [impl->glview setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; | ||||
} | } | ||||
@@ -129,7 +129,7 @@ puglCreateWindow(PuglView* view, const char* title) | |||||
} | } | ||||
int winFlags = WS_POPUPWINDOW | WS_CAPTION; | int winFlags = WS_POPUPWINDOW | WS_CAPTION; | ||||
if (view->resizable) { | |||||
if (view->user_resizable) { | |||||
winFlags |= WS_SIZEBOX; | winFlags |= WS_SIZEBOX; | ||||
if (view->min_width > 0 && view->min_height > 0) { | if (view->min_width > 0 && view->min_height > 0) { | ||||
// Adjust the minimum window size to accomodate requested view size | // Adjust the minimum window size to accomodate requested view size | ||||
@@ -223,7 +223,7 @@ puglReshape(PuglView* view, int width, int height) | |||||
if (view->reshapeFunc) { | if (view->reshapeFunc) { | ||||
view->reshapeFunc(view, width, height); | view->reshapeFunc(view, width, height); | ||||
} else { | } else { | ||||
puglDefaultReshape(view, width, height); | |||||
puglDefaultReshape(width, height); | |||||
} | } | ||||
view->width = width; | view->width = width; | ||||
@@ -1,7 +1,7 @@ | |||||
/* | /* | ||||
Copyright 2012-2014 David Robillard <http://drobilla.net> | Copyright 2012-2014 David Robillard <http://drobilla.net> | ||||
Copyright 2013 Robin Gareus <robin@gareus.org> | |||||
Copyright 2011-2012 Ben Loftis, Harrison Consoles | Copyright 2011-2012 Ben Loftis, Harrison Consoles | ||||
Copyright 2013,2015 Robin Gareus <robin@gareus.org> | |||||
Permission to use, copy, modify, and/or distribute this software for any | Permission to use, copy, modify, and/or distribute this software for any | ||||
purpose with or without fee is hereby granted, provided that the above | purpose with or without fee is hereby granted, provided that the above | ||||
@@ -24,15 +24,14 @@ | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <GL/gl.h> | |||||
#include <GL/glx.h> | |||||
#include <X11/Xatom.h> | #include <X11/Xatom.h> | ||||
#include <X11/Xlib.h> | #include <X11/Xlib.h> | ||||
#include <X11/Xutil.h> | #include <X11/Xutil.h> | ||||
#include <X11/keysym.h> | #include <X11/keysym.h> | ||||
#include <GL/gl.h> | |||||
#include <GL/glx.h> | |||||
#include "pugl/pugl_internal.h" | |||||
#include "pugl_internal.h" | |||||
#ifndef DGL_FILE_BROWSER_DISABLED | #ifndef DGL_FILE_BROWSER_DISABLED | ||||
#define SOFD_HAVE_X11 | #define SOFD_HAVE_X11 | ||||
@@ -40,108 +39,74 @@ | |||||
#include "../sofd/libsofd.c" | #include "../sofd/libsofd.c" | ||||
#endif | #endif | ||||
/* work around buggy re-parent & focus issues on some systems | |||||
* where no keyboard events are passed through even if the | |||||
* app has mouse-focus and all other events are working. | |||||
*/ | |||||
//#define PUGL_GRAB_FOCUS | |||||
/* show messages during initalization | |||||
*/ | |||||
//#define PUGL_VERBOSE | |||||
struct PuglInternalsImpl { | struct PuglInternalsImpl { | ||||
Display* display; | Display* display; | ||||
int screen; | int screen; | ||||
Window win; | Window win; | ||||
XIM xim; | |||||
XIC xic; | |||||
GLXContext ctx; | GLXContext ctx; | ||||
Bool doubleBuffered; | Bool doubleBuffered; | ||||
}; | }; | ||||
PuglInternals* | |||||
puglInitInternals(void) | |||||
{ | |||||
return (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||||
} | |||||
static XVisualInfo* | |||||
getVisual(PuglView* view) | |||||
{ | |||||
PuglInternals* const impl = view->impl; | |||||
XVisualInfo* vi = NULL; | |||||
/** | |||||
Attributes for single-buffered RGBA with at least | |||||
4 bits per color and a 16 bit depth buffer. | |||||
*/ | |||||
int attrListSgl[] = { | |||||
GLX_RGBA, | |||||
GLX_RED_SIZE, 4, | |||||
GLX_GREEN_SIZE, 4, | |||||
GLX_BLUE_SIZE, 4, | |||||
GLX_DEPTH_SIZE, 16, | |||||
GLX_ARB_multisample, 1, | |||||
None | |||||
}; | |||||
/** | |||||
Attributes for double-buffered RGBA with at least | |||||
4 bits per color and a 16 bit depth buffer. | |||||
*/ | |||||
int attrListDbl[] = { | |||||
GLX_RGBA, | |||||
GLX_DOUBLEBUFFER, | |||||
GLX_RED_SIZE, 4, | |||||
GLX_GREEN_SIZE, 4, | |||||
GLX_BLUE_SIZE, 4, | |||||
GLX_DEPTH_SIZE, 16, | |||||
GLX_ARB_multisample, 1, | |||||
None | |||||
}; | |||||
/** | |||||
Attributes for double-buffered RGBA with multi-sampling | |||||
(antialiasing) | |||||
*/ | |||||
int attrListDblMS[] = { | |||||
GLX_RGBA, | |||||
GLX_DOUBLEBUFFER, | |||||
GLX_RED_SIZE, 4, | |||||
GLX_GREEN_SIZE, 4, | |||||
GLX_BLUE_SIZE, 4, | |||||
GLX_ALPHA_SIZE, 4, | |||||
GLX_DEPTH_SIZE, 16, | |||||
GLX_SAMPLE_BUFFERS, 1, | |||||
GLX_SAMPLES, 4, | |||||
None | |||||
}; | |||||
impl->doubleBuffered = True; | |||||
vi = glXChooseVisual(impl->display, impl->screen, attrListDblMS); | |||||
if (vi == NULL) { | |||||
vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); | |||||
PUGL_LOG("multisampling (antialiasing) is not available\n"); | |||||
} | |||||
if (vi == NULL) { | |||||
vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | |||||
impl->doubleBuffered = False; | |||||
PUGL_LOG("singlebuffered rendering will be used, no doublebuffering available\n"); | |||||
} | |||||
return vi; | |||||
} | |||||
/** | |||||
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, | |||||
GLX_ARB_multisample, 1, | |||||
None | |||||
}; | |||||
static bool | |||||
createContext(PuglView* view, XVisualInfo* vi) | |||||
{ | |||||
PuglInternals* const impl = view->impl; | |||||
/** | |||||
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, True, | |||||
GLX_RED_SIZE, 4, | |||||
GLX_GREEN_SIZE, 4, | |||||
GLX_BLUE_SIZE, 4, | |||||
GLX_DEPTH_SIZE, 16, | |||||
GLX_ARB_multisample, 1, | |||||
None | |||||
}; | |||||
impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | |||||
return (impl->ctx != NULL); | |||||
} | |||||
/** | |||||
Attributes for double-buffered RGBA with multi-sampling | |||||
(antialiasing) | |||||
*/ | |||||
static int attrListDblMS[] = { | |||||
GLX_RGBA, | |||||
GLX_DOUBLEBUFFER, True, | |||||
GLX_RED_SIZE, 4, | |||||
GLX_GREEN_SIZE, 4, | |||||
GLX_BLUE_SIZE, 4, | |||||
GLX_ALPHA_SIZE, 4, | |||||
GLX_DEPTH_SIZE, 16, | |||||
GLX_SAMPLE_BUFFERS, 1, | |||||
GLX_SAMPLES, 4, | |||||
None | |||||
}; | |||||
static void | |||||
destroyContext(PuglView* view) | |||||
PuglInternals* | |||||
puglInitInternals(void) | |||||
{ | { | ||||
PuglInternals* const impl = view->impl; | |||||
glXDestroyContext(impl->display, impl->ctx); | |||||
impl->ctx = NULL; | |||||
return (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||||
} | } | ||||
void | void | ||||
@@ -165,21 +130,53 @@ puglLeaveContext(PuglView* view, bool flush) | |||||
int | int | ||||
puglCreateWindow(PuglView* view, const char* title) | puglCreateWindow(PuglView* view, const char* title) | ||||
{ | { | ||||
PuglInternals* const impl = view->impl; | |||||
PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||||
if (!impl) { | |||||
return 1; | |||||
} | |||||
view->impl = impl; | |||||
impl->display = XOpenDisplay(NULL); | impl->display = XOpenDisplay(NULL); | ||||
impl->screen = DefaultScreen(impl->display); | |||||
if (!impl->display) { | |||||
free(impl); | |||||
return 1; | |||||
} | |||||
impl->screen = DefaultScreen(impl->display); | |||||
impl->doubleBuffered = True; | |||||
XVisualInfo* 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"); | |||||
#endif | |||||
} | |||||
if (!vi) { | |||||
vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | |||||
impl->doubleBuffered = False; | |||||
} | |||||
XVisualInfo* const vi = getVisual(view); | |||||
if (!vi) { | if (!vi) { | ||||
XCloseDisplay(impl->display); | XCloseDisplay(impl->display); | ||||
impl->display = NULL; | |||||
free(impl); | |||||
return 1; | return 1; | ||||
} | } | ||||
#ifdef PUGL_VERBOSE | |||||
int glxMajor, glxMinor; | int glxMajor, glxMinor; | ||||
glXQueryVersion(impl->display, &glxMajor, &glxMinor); | glXQueryVersion(impl->display, &glxMajor, &glxMinor); | ||||
PUGL_LOGF("GLX Version %d.%d\n", glxMajor, glxMinor); | |||||
printf("puGL: GLX-Version : %d.%d\n", glxMajor, glxMinor); | |||||
#endif | |||||
impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | |||||
if (!impl->ctx) { | |||||
XCloseDisplay(impl->display); | |||||
free(impl); | |||||
return 1; | |||||
} | |||||
Window xParent = view->parent | Window xParent = view->parent | ||||
? (Window)view->parent | ? (Window)view->parent | ||||
@@ -204,62 +201,40 @@ puglCreateWindow(PuglView* view, const char* title) | |||||
0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual, | 0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual, | ||||
CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &attr); | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &attr); | ||||
if (!createContext(view, vi)) { | |||||
XDestroyWindow(impl->display, impl->win); | |||||
impl->win = 0; | |||||
if (!impl->win) { | |||||
XCloseDisplay(impl->display); | XCloseDisplay(impl->display); | ||||
impl->display = NULL; | |||||
free(impl); | |||||
return 1; | return 1; | ||||
} | } | ||||
XSizeHints sizeHints; | |||||
memset(&sizeHints, 0, sizeof(sizeHints)); | |||||
if (!view->resizable) { | |||||
sizeHints.flags = PMinSize|PMaxSize; | |||||
sizeHints.min_width = view->width; | |||||
sizeHints.min_height = view->height; | |||||
sizeHints.max_width = view->width; | |||||
sizeHints.max_height = view->height; | |||||
XSetNormalHints(impl->display, impl->win, &sizeHints); | |||||
} else if (view->min_width > 0 && view->min_height > 0) { | |||||
sizeHints.flags = PMinSize; | |||||
sizeHints.min_width = view->min_width; | |||||
sizeHints.min_height = view->min_height; | |||||
XSetNormalHints(impl->display, impl->win, &sizeHints); | |||||
} | |||||
puglUpdateGeometryConstraints(view, view->min_width, view->min_height, view->min_width != view->width); | |||||
XResizeWindow(view->impl->display, view->impl->win, view->width, view->height); | |||||
if (title) { | if (title) { | ||||
XStoreName(impl->display, impl->win, title); | XStoreName(impl->display, impl->win, title); | ||||
} | } | ||||
if (!view->parent) { | |||||
if (view->transient_parent > 0) { | |||||
XSetTransientForHint(impl->display, impl->win, (Window)view->transient_parent); | |||||
} | |||||
if (view->parent) { | |||||
XMapRaised(impl->display, impl->win); | |||||
} else { | |||||
Atom wmDelete = XInternAtom(impl->display, "WM_DELETE_WINDOW", True); | Atom wmDelete = XInternAtom(impl->display, "WM_DELETE_WINDOW", True); | ||||
XSetWMProtocols(impl->display, impl->win, &wmDelete, 1); | XSetWMProtocols(impl->display, impl->win, &wmDelete, 1); | ||||
} | } | ||||
#ifdef PUGL_VERBOSE | |||||
if (glXIsDirect(impl->display, impl->ctx)) { | if (glXIsDirect(impl->display, impl->ctx)) { | ||||
PUGL_LOG("DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n"); | |||||
printf("puGL: DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n"); | |||||
} else { | } else { | ||||
PUGL_LOG("No DRI available\n"); | |||||
printf("puGL: No DRI available\n"); | |||||
} | } | ||||
#endif | |||||
XFree(vi); | XFree(vi); | ||||
return PUGL_SUCCESS; | |||||
} | |||||
void | |||||
puglShowWindow(PuglView* view) | |||||
{ | |||||
XMapRaised(view->impl->display, view->impl->win); | |||||
} | |||||
void | |||||
puglHideWindow(PuglView* view) | |||||
{ | |||||
XUnmapWindow(view->impl->display, view->impl->win); | |||||
return 0; | |||||
} | } | ||||
void | void | ||||
@@ -268,18 +243,29 @@ puglDestroy(PuglView* view) | |||||
if (!view) { | if (!view) { | ||||
return; | return; | ||||
} | } | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | #ifndef DGL_FILE_BROWSER_DISABLED | ||||
x_fib_close(view->impl->display); | x_fib_close(view->impl->display); | ||||
#endif | #endif | ||||
destroyContext(view); | |||||
glXDestroyContext(view->impl->display, view->impl->ctx); | |||||
XDestroyWindow(view->impl->display, view->impl->win); | XDestroyWindow(view->impl->display, view->impl->win); | ||||
XCloseDisplay(view->impl->display); | XCloseDisplay(view->impl->display); | ||||
free(view->impl); | free(view->impl); | ||||
free(view); | free(view); | ||||
} | } | ||||
void | |||||
puglShowWindow(PuglView* view) | |||||
{ | |||||
XMapRaised(view->impl->display, view->impl->win); | |||||
} | |||||
void | |||||
puglHideWindow(PuglView* view) | |||||
{ | |||||
XUnmapWindow(view->impl->display, view->impl->win); | |||||
} | |||||
static void | static void | ||||
puglReshape(PuglView* view, int width, int height) | puglReshape(PuglView* view, int width, int height) | ||||
{ | { | ||||
@@ -288,7 +274,7 @@ puglReshape(PuglView* view, int width, int height) | |||||
if (view->reshapeFunc) { | if (view->reshapeFunc) { | ||||
view->reshapeFunc(view, width, height); | view->reshapeFunc(view, width, height); | ||||
} else { | } else { | ||||
puglDefaultReshape(view, width, height); | |||||
puglDefaultReshape(width, height); | |||||
} | } | ||||
puglLeaveContext(view, false); | puglLeaveContext(view, false); | ||||
@@ -303,7 +289,6 @@ puglDisplay(PuglView* view) | |||||
puglEnterContext(view); | puglEnterContext(view); | ||||
view->redisplay = false; | view->redisplay = false; | ||||
if (view->displayFunc) { | if (view->displayFunc) { | ||||
view->displayFunc(view); | view->displayFunc(view); | ||||
} | } | ||||
@@ -311,6 +296,36 @@ puglDisplay(PuglView* view) | |||||
puglLeaveContext(view, true); | puglLeaveContext(view, true); | ||||
} | } | ||||
static void | |||||
puglResize(PuglView* view) | |||||
{ | |||||
int set_hints = 1; | |||||
view->pending_resize = false; | |||||
if (!view->resizeFunc) { return; } | |||||
/* ask the plugin about the new size */ | |||||
view->resizeFunc(view, &view->width, &view->height, &set_hints); | |||||
if (set_hints) { | |||||
XSizeHints sizeHints; | |||||
memset(&sizeHints, 0, sizeof(sizeHints)); | |||||
sizeHints.flags = PMinSize|PMaxSize; | |||||
sizeHints.min_width = view->width; | |||||
sizeHints.min_height = view->height; | |||||
sizeHints.max_width = view->user_resizable ? 4096 : view->width; | |||||
sizeHints.max_height = view->user_resizable ? 4096 : view->height; | |||||
XSetWMNormalHints(view->impl->display, view->impl->win, &sizeHints); | |||||
} | |||||
XResizeWindow(view->impl->display, view->impl->win, view->width, view->height); | |||||
XFlush(view->impl->display); | |||||
#ifdef PUGL_VERBOSE | |||||
printf("puGL: window resize (%dx%d)\n", view->width, view->height); | |||||
#endif | |||||
/* and call Reshape in glX context */ | |||||
puglReshape(view, view->width, view->height); | |||||
} | |||||
static PuglKey | static PuglKey | ||||
keySymToSpecial(KeySym sym) | keySymToSpecial(KeySym sym) | ||||
{ | { | ||||
@@ -439,6 +454,11 @@ puglProcessEvents(PuglView* view) | |||||
} | } | ||||
switch (event.type) { | switch (event.type) { | ||||
case UnmapNotify: | |||||
if (view->motionFunc) { | |||||
view->motionFunc(view, -1, -1); | |||||
} | |||||
break; | |||||
case MapNotify: | case MapNotify: | ||||
puglReshape(view, view->width, view->height); | puglReshape(view, view->width, view->height); | ||||
break; | break; | ||||
@@ -530,6 +550,10 @@ puglProcessEvents(PuglView* view) | |||||
} | } | ||||
} | } | ||||
if (view->pending_resize) { | |||||
puglResize(view); | |||||
} | |||||
if (view->redisplay) { | if (view->redisplay) { | ||||
puglDisplay(view); | puglDisplay(view); | ||||
} | } | ||||
@@ -543,8 +567,35 @@ puglPostRedisplay(PuglView* view) | |||||
view->redisplay = true; | view->redisplay = true; | ||||
} | } | ||||
void | |||||
puglPostResize(PuglView* view) | |||||
{ | |||||
view->pending_resize = true; | |||||
} | |||||
PuglNativeWindow | PuglNativeWindow | ||||
puglGetNativeWindow(PuglView* view) | puglGetNativeWindow(PuglView* view) | ||||
{ | { | ||||
return view->impl->win; | return view->impl->win; | ||||
} | } | ||||
int | |||||
puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect) | |||||
{ | |||||
XSizeHints sizeHints; | |||||
memset(&sizeHints, 0, sizeof(sizeHints)); | |||||
sizeHints.flags = PMinSize|PMaxSize; | |||||
sizeHints.min_width = min_width; | |||||
sizeHints.min_height = min_height; | |||||
sizeHints.max_width = view->user_resizable ? 4096 : min_width; | |||||
sizeHints.max_height = view->user_resizable ? 4096 : min_height; | |||||
if (aspect) { | |||||
sizeHints.flags |= PAspect; | |||||
sizeHints.min_aspect.x = min_width; | |||||
sizeHints.min_aspect.y = min_height; | |||||
sizeHints.max_aspect.x = min_width; | |||||
sizeHints.max_aspect.y = min_height; | |||||
} | |||||
XSetWMNormalHints(view->impl->display, view->impl->win, &sizeHints); | |||||
return 0; | |||||
} |