diff --git a/dgl/src/Window.cpp b/dgl/src/Window.cpp index 492e8287..1623a95b 100644 --- a/dgl/src/Window.cpp +++ b/dgl/src/Window.cpp @@ -15,8 +15,7 @@ */ // we need this for now -#define PUGL_HAVE_GL 1 -#define PUGL_GRAB_FOCUS 1 +//#define PUGL_GRAB_FOCUS 1 #include "AppPrivateData.hpp" #include "../Widget.hpp" @@ -63,7 +62,7 @@ struct Window::PrivateData { PrivateData(App& app, Window* const self) : fApp(app), fSelf(self), - fView(puglInit(nullptr, nullptr)), + fView(puglInit()), fFirstInit(true), fVisible(false), fResizable(true), @@ -91,7 +90,7 @@ struct Window::PrivateData { PrivateData(App& app, Window* const self, Window& parent) : fApp(app), fSelf(self), - fView(puglInit(nullptr, nullptr)), + fView(puglInit()), fFirstInit(true), fVisible(false), fResizable(true), @@ -129,7 +128,7 @@ struct Window::PrivateData { PrivateData(App& app, Window* const self, const intptr_t parentId) : fApp(app), fSelf(self), - fView(puglInit(nullptr, nullptr)), + fView(puglInit()), fFirstInit(true), fVisible(parentId != 0), fResizable(parentId == 0), @@ -193,7 +192,6 @@ struct Window::PrivateData { puglSetCloseFunc(fView, onCloseCallback); puglCreateWindow(fView, nullptr); - puglEnterContext(fView); PuglInternals* impl = fView->impl; #if defined(DISTRHO_OS_WINDOWS) @@ -458,7 +456,11 @@ struct Window::PrivateData { fResizable = yesNo; -#ifdef CARLA_OS_MAC +#if defined(DISTRHO_OS_WINDOWS) + const int winFlags = fResizable ? GetWindowLong(hwnd, GWL_STYLE) | WS_SIZEBOX + : GetWindowLong(hwnd, GWL_STYLE) & ~WS_SIZEBOX; + SetWindowLong(hwnd, GWL_STYLE, winFlags); +#elif defined(DISTRHO_OS_MAC) // FIXME? const uint flags(yesNo ? (NSViewWidthSizable|NSViewHeightSizable) : 0x0); [mView setAutoresizingMask:flags]; @@ -471,7 +473,7 @@ struct Window::PrivateData { void setSize(uint width, uint height, const bool forced = false) { - if (width == 0 || height == 0) + if (width <= 1 || height <= 1) { DBGp("Window setSize called with invalid value(s) %i %i, ignoring request\n", width, height); return; @@ -486,18 +488,15 @@ struct Window::PrivateData { fWidth = width; fHeight = height; - DBGp("Window setSize called %s, size %i %i\n", forced ? "(forced)" : "(not forced)", width, height); + DBGp("Window setSize called %s, size %i %i, resizable %s\n", forced ? "(forced)" : "(not forced)", width, height, fResizable?"true":"false"); #if defined(DISTRHO_OS_WINDOWS) - int winFlags = WS_POPUPWINDOW | WS_CAPTION; - - if (fResizable) - winFlags |= WS_SIZEBOX; - + const int winFlags = WS_POPUPWINDOW | WS_CAPTION | (fResizable ? WS_SIZEBOX : 0x0); RECT wr = { 0, 0, static_cast(width), static_cast(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); + SetWindowPos(hwnd, 0, 0, 0, wr.right-wr.left, wr.bottom-wr.top, + SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); if (! forced) UpdateWindow(hwnd); diff --git a/dgl/src/pugl/common.h b/dgl/src/pugl/common.h deleted file mode 100644 index 4255de69..00000000 --- a/dgl/src/pugl/common.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - Copyright 2014 David Robillard - - 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. -*/ - -#ifndef PUGL_COMMON_H_INCLUDED -#define PUGL_COMMON_H_INCLUDED - -#ifdef __cplusplus -extern "C" { -#endif - -/** - @addtogroup pugl - @{ -*/ - -/** - A Pugl 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; - -/** - Handle for opaque user data. -*/ -typedef void* PuglHandle; - -/** - Return status code. -*/ -typedef enum { - PUGL_SUCCESS = 0 -} PuglStatus; - -/** - Drawing context type. -*/ -typedef enum { - PUGL_GL, - PUGL_CAIRO -} PuglContextType; - -/** - Convenience symbols for ASCII control characters. -*/ -typedef enum { - PUGL_CHAR_BACKSPACE = 0x08, - PUGL_CHAR_ESCAPE = 0x1B, - PUGL_CHAR_DELETE = 0x7F -} PuglChar; - -/** - 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; - -/** - 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; - -/** - @} -*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* PUGL_COMMON_H_INCLUDED */ diff --git a/dgl/src/pugl/event.h b/dgl/src/pugl/event.h deleted file mode 100644 index 6fc80cf4..00000000 --- a/dgl/src/pugl/event.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - Copyright 2014 David Robillard - - 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. -*/ - -#ifndef PUGL_EVENT_H_INCLUDED -#define PUGL_EVENT_H_INCLUDED - -#ifdef __cplusplus -extern "C" { -#else -# include -#endif - -#include "pugl/common.h" - -/** - @addtogroup pugl - @{ -*/ - -/** - The type of a PuglEvent. -*/ -typedef enum { - PUGL_BUTTON_PRESS, - PUGL_BUTTON_RELEASE, - PUGL_CONFIGURE, - PUGL_EXPOSE, - PUGL_KEY_PRESS, - PUGL_KEY_RELEASE, - PUGL_ENTER_NOTIFY, - PUGL_LEAVE_NOTIFY, - PUGL_MOTION_NOTIFY, - PUGL_NOTHING, - PUGL_SCROLL -} PuglEventType; - -/** - Reason for a PuglEventCrossing. -*/ -typedef enum { - PUGL_CROSSING_NORMAL, /**< Crossing due to pointer motion. */ - PUGL_CROSSING_GRAB, /**< Crossing due to a grab. */ - PUGL_CROSSING_UNGRAB /**< Crossing due to a grab release. */ -} PuglCrossingMode; - -/** - Common header for all event structs. -*/ -typedef struct { - PuglEventType type; /**< Event type. */ - PuglView* view; /**< View that received this event. */ - bool send_event; /**< True iff event was sent explicitly. */ -} PuglEventAny; - -/** - Button press or release event. - - For event types PUGL_BUTTON_PRESS and PUGL_BUTTON_RELEASE. -*/ -typedef struct { - PuglEventType type; /**< PUGL_BUTTON_PRESS or PUGL_BUTTON_RELEASE. */ - PuglView* view; /**< View that received this event. */ - bool send_event; /**< True iff event was sent explicitly. */ - uint32_t time; /**< Time in milliseconds. */ - double x; /**< View-relative X coordinate. */ - double y; /**< View-relative Y coordinate. */ - double x_root; /**< Root-relative X coordinate. */ - double y_root; /**< Root-relative Y coordinate. */ - unsigned state; /**< Bitwise OR of PuglMod flags. */ - unsigned button; /**< 1-relative button number. */ -} PuglEventButton; - -/** - Configure event for when window size or position has changed. -*/ -typedef struct { - PuglEventType type; /**< PUGL_CONFIGURE. */ - PuglView* view; /**< View that received this event. */ - bool send_event; /**< True iff event was sent explicitly. */ - double x; /**< New parent-relative X coordinate. */ - double y; /**< New parent-relative Y coordinate. */ - double width; /**< New width. */ - double height; /**< New height. */ -} PuglEventConfigure; - -/** - Expose event for when a region must be redrawn. -*/ -typedef struct { - PuglEventType type; /**< PUGL_EXPOSE. */ - PuglView* view; /**< View that received this event. */ - bool send_event; /**< True iff event was sent explicitly. */ - double x; /**< View-relative X coordinate. */ - double y; /**< View-relative Y coordinate. */ - double width; /**< Width of exposed region. */ - double height; /**< Height of exposed region. */ - int count; /**< Number of expose events to follow. */ -} PuglEventExpose; - -/** - Key press event. - - Keys that correspond to a Unicode character are expressed as a character - code. For other keys, `character` will be 0 and `special` indicates the key - pressed. -*/ -typedef struct { - PuglEventType type; /**< PUGL_KEY_PRESS or PUGL_KEY_RELEASE. */ - PuglView* view; /**< View that received this event. */ - bool send_event; /**< True iff event was sent explicitly. */ - uint32_t time; /**< Time in milliseconds. */ - double x; /**< View-relative X coordinate. */ - double y; /**< View-relative Y coordinate. */ - double x_root; /**< Root-relative X coordinate. */ - double y_root; /**< Root-relative Y coordinate. */ - unsigned state; /**< Bitwise OR of PuglMod flags. */ - uint32_t character; /**< Unicode character code, or 0. */ - PuglKey special; /**< Special key, if character is 0. */ -} PuglEventKey; - -/** - Pointer crossing event (enter and leave). -*/ -typedef struct { - PuglEventType type; /**< PUGL_ENTER_NOTIFY or PUGL_LEAVE_NOTIFY. */ - PuglView* view; /**< View that received this event. */ - bool send_event; /**< True iff event was sent explicitly. */ - uint32_t time; /**< Time in milliseconds. */ - double x; /**< View-relative X coordinate. */ - double y; /**< View-relative Y coordinate. */ - double x_root; /**< Root-relative X coordinate. */ - double y_root; /**< Root-relative Y coordinate. */ - unsigned state; /**< Bitwise OR of PuglMod flags. */ - PuglCrossingMode mode; /**< Reason for crossing. */ -} PuglEventCrossing; - -/** - Pointer motion event. -*/ -typedef struct { - PuglEventType type; /**< PUGL_MOTION_NOTIFY. */ - PuglView* view; /**< View that received this event. */ - bool send_event; /**< True iff event was sent explicitly. */ - uint32_t time; /**< Time in milliseconds. */ - double x; /**< View-relative X coordinate. */ - double y; /**< View-relative Y coordinate. */ - double x_root; /**< Root-relative X coordinate. */ - double y_root; /**< Root-relative Y coordinate. */ - unsigned state; /**< Bitwise OR of PuglMod flags. */ - bool is_hint; /**< True iff this event is a motion hint. */ - bool focus; /**< True iff this is the focused window. */ -} PuglEventMotion; - -/** - Scroll event. - - The scroll distance is expressed in "lines", an arbitrary unit that - corresponds to a single tick of a detented mouse wheel. For example, `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. - */ -typedef struct { - PuglEventType type; /**< PUGL_SCROLL. */ - PuglView* view; /**< View that received this event. */ - bool send_event; /**< True iff event was sent explicitly. */ - uint32_t time; /**< Time in milliseconds. */ - double x; /**< View-relative X coordinate. */ - double y; /**< View-relative Y coordinate. */ - double x_root; /**< Root-relative X coordinate. */ - double y_root; /**< Root-relative Y coordinate. */ - unsigned state; /**< Bitwise OR of PuglMod flags. */ - double dx; /**< Scroll X distance in lines. */ - double dy; /**< Scroll Y distance in lines. */ -} PuglEventScroll; - -/** - Interface event. - - This is a union of all event structs. The `type` must be checked to - determine which fields are safe to access. A pointer to PuglEvent can - either be cast to the appropriate type, or the union members used. -*/ -typedef union { - PuglEventType type; /**< Event type. */ - PuglEventAny any; /**< Valid for all event types. */ - PuglEventButton button; /**< PUGL_BUTTON_PRESS, PUGL_BUTTON_RELEASE. */ - PuglEventConfigure configure; /**< PUGL_CONFIGURE. */ - PuglEventCrossing crossing; /**< PUGL_ENTER_NOTIFY, PUGL_LEAVE_NOTIFY. */ - PuglEventExpose expose; /**< PUGL_EXPOSE. */ - PuglEventKey key; /**< PUGL_KEY_PRESS, PUGL_KEY_RELEASE. */ - PuglEventMotion motion; /**< PUGL_MOTION_NOTIFY. */ - PuglEventScroll scroll; /**< PUGL_SCROLL. */ -} PuglEvent; - -/** - @} -*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* PUGL_EVENT_H_INCLUDED */ diff --git a/dgl/src/pugl/gl.h b/dgl/src/pugl/gl.h deleted file mode 100644 index 9a6aeefe..00000000 --- a/dgl/src/pugl/gl.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - Copyright 2012-2014 David Robillard - - 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 gl.h Portable header wrapper for gl.h. - - Unfortunately, GL includes vary across platforms so this header allows for - pure portable programs. -*/ - -#ifdef __APPLE__ -# include "OpenGL/gl.h" -#else -# ifdef _WIN32 -# include /* Broken Windows GL headers require this */ -# endif -# include "GL/gl.h" -#endif - diff --git a/dgl/src/pugl/glu.h b/dgl/src/pugl/glu.h deleted file mode 100644 index 0ed0055d..00000000 --- a/dgl/src/pugl/glu.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - Copyright 2012-2014 David Robillard - - 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 gl.h Portable header wrapper for glu.h. - - Unfortunately, GL includes vary across platforms so this header allows for - pure portable programs. -*/ - -#ifdef __APPLE__ -# include "OpenGL/glu.h" -#else -# ifdef _WIN32 -# include /* Broken Windows GL headers require this */ -# endif -# include "GL/glu.h" -#endif - diff --git a/dgl/src/pugl/pugl.h b/dgl/src/pugl/pugl.h index 68ecc195..c45c213e 100644 --- a/dgl/src/pugl/pugl.h +++ b/dgl/src/pugl/pugl.h @@ -23,8 +23,19 @@ #include -#include "pugl/common.h" -#include "pugl/event.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 /* Broken Windows GL headers require this */ +# endif +# include "GL/gl.h" +#endif #ifdef PUGL_SHARED # ifdef _WIN32 @@ -40,7 +51,11 @@ # define PUGL_API PUGL_LIB_IMPORT # endif #else -# define PUGL_API +# ifdef _WIN32 +# define PUGL_API +# else +# define PUGL_API __attribute__((visibility("hidden"))) +# endif #endif #ifdef __cplusplus @@ -56,9 +71,80 @@ extern "C" { */ /** - A function called when an event occurs. + 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 void (*PuglEventFunc)(PuglView* view, const PuglEvent* event); +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. @@ -114,19 +200,18 @@ typedef void (*PuglReshapeFunc)(PuglView* view, int width, int height); so programs should handle any value gracefully. @param view The view being scrolled. + @param x The window-relative x coordinate of the pointer. + @param y The window-relative y coordinate of the pointer. @param dx The scroll x distance. @param dx The scroll y distance. */ -typedef void (*PuglScrollFunc)(PuglView* view, - int x, - int y, - float dx, - float dy); +typedef void (*PuglScrollFunc)(PuglView* view, int x, int y, 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 are non-printable keys. @param view The view the event occured in. @param press True if the key was pressed, false if released. @@ -134,23 +219,14 @@ typedef void (*PuglScrollFunc)(PuglView* view, */ typedef void (*PuglSpecialFunc)(PuglView* view, bool press, PuglKey key); -/** - @name Initialization - Configuration functions which must be called before creating a window. - @{ -*/ - /** Create a Pugl context. To create a window, call the various puglInit* functions as necessary, then call puglCreateWindow(). - - @param pargc Pointer to argument count (unused, for GLUT compatibility). - @param argv Arguments (unused, for GLUT compatibility). */ PUGL_API PuglView* -puglInit(int* pargc, char** argv); +puglInit(void); /** Set the parent window before creating a window (for embedding). @@ -168,23 +244,7 @@ puglInitWindowSize(PuglView* view, int width, int height); Enable or disable resizing before creating a window. */ PUGL_API void -puglInitResizable(PuglView* view, bool resizable); - -/** - Set the context type before creating a window. -*/ -PUGL_API void -puglInitContextType(PuglView* view, PuglContextType type); - -/** - @} -*/ - -/** - @name Windows - Window management functions. - @{ -*/ +puglInitUserResizable(PuglView* view, bool resizable); /** Create a window with the settings given by the various puglInit functions. @@ -206,16 +266,6 @@ puglShowWindow(PuglView* view); PUGL_API void puglHideWindow(PuglView* view); -/** - Return the native window handle. -*/ -PUGL_API PuglNativeWindow -puglGetNativeWindow(PuglView* view); - -/** - @} -*/ - /** Set the handle to be passed to all callbacks. @@ -234,15 +284,6 @@ puglSetHandle(PuglView* view, PuglHandle handle); PUGL_API PuglHandle puglGetHandle(PuglView* view); -/** - Get the drawing context. - - For PUGL_GL contexts, this is unused and returns NULL. - For PUGL_CAIRO contexts, this returns a pointer to a cairo_t. -*/ -PUGL_API void* -puglGetContext(PuglView* view); - /** Return the timestamp (if any) of the currently-processing event. */ @@ -263,18 +304,6 @@ puglGetModifiers(PuglView* view); PUGL_API void puglIgnoreKeyRepeat(PuglView* view, bool ignore); -/** - @name Event Callbacks - Functions to set event callbacks for handling user input. - @{ -*/ - -/** - Set the function to call when an event occurs. -*/ -PUGL_API void -puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc); - /** Set the function to call when the window is closed. */ @@ -324,14 +353,10 @@ PUGL_API void puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc); /** - @} -*/ - -/** - Grab the input focus. + Return the native window handle. */ -PUGL_API void -puglGrabFocus(PuglView* view); +PUGL_API PuglNativeWindow +puglGetNativeWindow(PuglView* view); /** Process all pending window events. diff --git a/dgl/src/pugl/pugl_internal.h b/dgl/src/pugl/pugl_internal.h index 33fc303c..76ce41b3 100644 --- a/dgl/src/pugl/pugl_internal.h +++ b/dgl/src/pugl/pugl_internal.h @@ -1,5 +1,5 @@ /* - Copyright 2012-2014 David Robillard + Copyright 2012 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -24,14 +24,11 @@ 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" -#include "pugl/event.h" +#include "pugl.h" #ifdef PUGL_VERBOSE # include @@ -46,7 +43,6 @@ typedef struct PuglInternalsImpl PuglInternals; struct PuglViewImpl { PuglHandle handle; - PuglEventFunc eventFunc; PuglCloseFunc closeFunc; PuglDisplayFunc displayFunc; PuglKeyboardFunc keyboardFunc; @@ -57,9 +53,7 @@ struct PuglViewImpl { PuglSpecialFunc specialFunc; PuglInternals* impl; - PuglNativeWindow parent; - PuglContextType ctx_type; int width; int height; @@ -71,10 +65,10 @@ struct PuglViewImpl { uint32_t event_timestamp_ms; }; -PuglInternals* puglInitInternals(); +PuglInternals* puglInitInternals(void); PuglView* -puglInit(int* pargc, char** argv) +puglInit(void) { PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); if (!view) { @@ -92,9 +86,6 @@ puglInit(int* pargc, char** argv) view->height = 480; return view; - - // unused - (void)pargc; (void)argv; } void @@ -116,12 +107,6 @@ puglInitResizable(PuglView* view, bool resizable) view->resizable = resizable; } -void -puglInitContextType(PuglView* view, PuglContextType type) -{ - view->ctx_type = type; -} - void puglSetHandle(PuglView* view, PuglHandle handle) { @@ -146,16 +131,26 @@ puglGetModifiers(PuglView* view) return view->mods; } -void -puglIgnoreKeyRepeat(PuglView* view, bool ignore) +static void +puglDefaultReshape(PuglView* view, int width, int height) { - view->ignoreKeyRepeat = ignore; + 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 -puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc) +puglIgnoreKeyRepeat(PuglView* view, bool ignore) { - view->eventFunc = eventFunc; + view->ignoreKeyRepeat = ignore; } void @@ -205,81 +200,3 @@ puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc) { view->specialFunc = specialFunc; } - -void -puglEnterContext(PuglView* view); - -void -puglLeaveContext(PuglView* view, bool flush); - -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; - } -} diff --git a/dgl/src/pugl/pugl_osx.m b/dgl/src/pugl/pugl_osx.m index f4d71295..e98a9364 100644 --- a/dgl/src/pugl/pugl_osx.m +++ b/dgl/src/pugl/pugl_osx.m @@ -1,5 +1,5 @@ /* - Copyright 2012-2014 David Robillard + Copyright 2012 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -22,7 +22,7 @@ #import -#include "pugl/pugl_internal.h" +#include "pugl_internal.h" @interface PuglWindow : NSWindow { @@ -36,8 +36,6 @@ defer:(BOOL)flag; - (void) setPuglview:(PuglView*)view; - (BOOL) windowShouldClose:(id)sender; -- (BOOL) canBecomeKeyWindow:(id)sender; -- (BOOL) canBecomeMainWindow:(id)sender; @end @implementation PuglWindow @@ -78,22 +76,6 @@ (void)sender; } -- (BOOL) canBecomeKeyWindow:(id)sender -{ - return YES; - - // unused - (void)sender; -} - -- (BOOL) canBecomeMainWindow:(id)sender -{ - return YES; - - // unused - (void)sender; -} - @end static void @@ -214,6 +196,8 @@ puglDisplay(PuglView* view) if (puglview->reshapeFunc) { puglview->reshapeFunc(puglview, width, height); + } else { + puglDefaultReshape(puglview, width, height); } puglview->width = width; diff --git a/dgl/src/pugl/pugl_win.cpp b/dgl/src/pugl/pugl_win.cpp index 8334bf6c..68320c6d 100644 --- a/dgl/src/pugl/pugl_win.cpp +++ b/dgl/src/pugl/pugl_win.cpp @@ -1,5 +1,5 @@ /* - Copyright 2012-2014 David Robillard + Copyright 2012 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -22,11 +22,11 @@ #include #include +#include #include #include -#include -#include "pugl/pugl_internal.h" +#include "pugl_internal.h" #ifndef WM_MOUSEWHEEL # define WM_MOUSEWHEEL 0x020A @@ -38,7 +38,9 @@ # define WHEEL_DELTA 120 #endif -#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50) +const int LOCAL_CLOSE_MSG = WM_USER + 50; + +HINSTANCE hInstance = NULL; struct PuglInternalsImpl { HWND hwnd; @@ -47,11 +49,10 @@ struct PuglInternalsImpl { WNDCLASS wc; }; -static HINSTANCE hInstance = NULL; - LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +#if 0 extern "C" { BOOL WINAPI DllMain(HINSTANCE hInst, DWORD, LPVOID) @@ -60,6 +61,7 @@ DllMain(HINSTANCE hInst, DWORD, LPVOID) return 1; } } // extern "C" +#endif PuglInternals* puglInitInternals() @@ -67,27 +69,6 @@ puglInitInternals() return (PuglInternals*)calloc(1, sizeof(PuglInternals)); } -void -puglEnterContext(PuglView* view) -{ -#ifdef PUGL_HAVE_GL - if (view->ctx_type == PUGL_GL) { - wglMakeCurrent(view->impl->hdc, view->impl->hglrc); - } -#endif -} - -void -puglLeaveContext(PuglView* view, bool flush) -{ -#ifdef PUGL_HAVE_GL - if (view->ctx_type == PUGL_GL && flush) { - glFlush(); - SwapBuffers(view->impl->hdc); - } -#endif -} - int puglCreateWindow(PuglView* view, const char* title) { @@ -101,8 +82,9 @@ puglCreateWindow(PuglView* view, const char* title) // Should class be a parameter? Does this make sense on other platforms? static int wc_count = 0; char classNameBuf[256]; - srand((time(NULL))); - _snprintf(classNameBuf, sizeof(classNameBuf), "%d-%d_%s\n", ++wc_count, rand(), title); + std::srand((std::time(NULL))); + _snprintf(classNameBuf, sizeof(classNameBuf), "%s_%d-%d", title, std::rand(), ++wc_count); + classNameBuf[sizeof(classNameBuf)-1] = '\0'; impl->wc.style = CS_OWNDC; impl->wc.lpfnWndProc = wndProc; @@ -114,37 +96,35 @@ puglCreateWindow(PuglView* view, const char* title) impl->wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); impl->wc.lpszMenuName = NULL; impl->wc.lpszClassName = strdup(classNameBuf); - RegisterClass(&impl->wc); - int winFlags = WS_POPUPWINDOW | WS_CAPTION; - if (view->resizable) { - winFlags |= WS_SIZEBOX; + if (!RegisterClass(&impl->wc)) { + free((void*)impl->wc.lpszClassName); + free(impl); + free(view); + return 1; } // Adjust the overall window size to accomodate our requested client size + const int winFlags = WS_POPUPWINDOW | WS_CAPTION | (view->resizable ? WS_SIZEBOX : 0x0); RECT wr = { 0, 0, view->width, view->height }; AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST); impl->hwnd = CreateWindowEx( WS_EX_TOPMOST, classNameBuf, title, - view->parent ? WS_CHILD : winFlags, + view->parent ? (WS_CHILD | WS_VISIBLE) : winFlags, CW_USEDEFAULT, CW_USEDEFAULT, wr.right-wr.left, wr.bottom-wr.top, (HWND)view->parent, NULL, hInstance, NULL); if (!impl->hwnd) { - UnregisterClass(impl->wc.lpszClassName, hInstance); + UnregisterClass(impl->wc.lpszClassName, NULL); free((void*)impl->wc.lpszClassName); free(impl); free(view); return 1; } -#ifdef _WIN64 SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view); -#else - SetWindowLongPtr(impl->hwnd, GWL_USERDATA, (LONG)view); -#endif impl->hdc = GetDC(impl->hwnd); @@ -162,6 +142,16 @@ puglCreateWindow(PuglView* view, const char* title) SetPixelFormat(impl->hdc, format, &pfd); impl->hglrc = wglCreateContext(impl->hdc); + if (!impl->hglrc) { + ReleaseDC (impl->hwnd, impl->hdc); + DestroyWindow (impl->hwnd); + UnregisterClass (impl->wc.lpszClassName, NULL); + free((void*)impl->wc.lpszClassName); + free(impl); + free(view); + return 1; + } + wglMakeCurrent(impl->hdc, impl->hglrc); return 0; @@ -190,7 +180,7 @@ puglDestroy(PuglView* view) wglDeleteContext(view->impl->hglrc); ReleaseDC(view->impl->hwnd, view->impl->hdc); DestroyWindow(view->impl->hwnd); - UnregisterClass(view->impl->wc.lpszClassName, hInstance); + UnregisterClass(view->impl->wc.lpszClassName, NULL); free((void*)view->impl->wc.lpszClassName); free(view->impl); free(view); @@ -199,10 +189,12 @@ puglDestroy(PuglView* view) static void puglReshape(PuglView* view, int width, int height) { - puglEnterContext(view); + wglMakeCurrent(view->impl->hdc, view->impl->hglrc); if (view->reshapeFunc) { view->reshapeFunc(view, width, height); + } else { + puglDefaultReshape(view, width, height); } view->width = width; @@ -212,14 +204,15 @@ puglReshape(PuglView* view, int width, int height) static void puglDisplay(PuglView* view) { - puglEnterContext(view); + wglMakeCurrent(view->impl->hdc, view->impl->hglrc); + view->redisplay = false; if (view->displayFunc) { view->displayFunc(view); } - puglLeaveContext(view, true); - view->redisplay = false; + glFlush(); + SwapBuffers(view->impl->hdc); } static PuglKey @@ -308,7 +301,6 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_MOUSEMOVE: if (view->motionFunc) { - view->event_timestamp_ms = GetMessageTime(); view->motionFunc(view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); } break; @@ -333,17 +325,21 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) case WM_MOUSEWHEEL: if (view->scrollFunc) { view->event_timestamp_ms = GetMessageTime(); + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + ScreenToClient(view->impl->hwnd, &pt); view->scrollFunc( - view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), - 0.0f, (int16_t)HIWORD(wParam) / (float)WHEEL_DELTA); + view, pt.x, pt.y, + GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA, 0); } break; case WM_MOUSEHWHEEL: if (view->scrollFunc) { view->event_timestamp_ms = GetMessageTime(); + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + ScreenToClient(view->impl->hwnd, &pt); view->scrollFunc( - view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), - (int16_t)HIWORD(wParam) / float(WHEEL_DELTA), 0.0f); + view, pt.x, pt.y, + GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA, 0); } break; case WM_KEYDOWN: @@ -357,11 +353,18 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) view->specialFunc(view, message == WM_KEYDOWN, key); } } else if (view->keyboardFunc) { - view->keyboardFunc(view, message == WM_KEYDOWN, wParam); + static BYTE kbs[256]; + if (GetKeyboardState(kbs) != FALSE) { + char lb[2]; + UINT scanCode = (lParam >> 8) & 0xFFFFFF00; + if ( 1 == ToAscii(wParam, scanCode, kbs, (LPWORD)lb, 0)) { + view->keyboardFunc(view, message == WM_KEYDOWN, (char)lb[0]); + } + } } break; case WM_QUIT: - case PUGL_LOCAL_CLOSE_MSG: + case LOCAL_CLOSE_MSG: if (view->closeFunc) { view->closeFunc(view); } @@ -374,12 +377,6 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) return 0; } -void -puglGrabFocus(PuglView* /*view*/) -{ - // TODO -} - PuglStatus puglProcessEvents(PuglView* view) { @@ -388,7 +385,6 @@ puglProcessEvents(PuglView* view) handleMessage(view, msg.message, msg.wParam, msg.lParam); } - if (view->redisplay) { InvalidateRect(view->impl->hwnd, NULL, FALSE); } @@ -399,23 +395,19 @@ puglProcessEvents(PuglView* view) LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { -#ifdef _WIN64 PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWLP_USERDATA); -#else - PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWL_USERDATA); -#endif switch (message) { case WM_CREATE: PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0); return 0; case WM_CLOSE: - PostMessage(hwnd, PUGL_LOCAL_CLOSE_MSG, wParam, lParam); + PostMessage(hwnd, LOCAL_CLOSE_MSG, wParam, lParam); return 0; case WM_DESTROY: return 0; default: - if (view) { + if (view && hwnd == view->impl->hwnd) { return handleMessage(view, message, wParam, lParam); } else { return DefWindowProc(hwnd, message, wParam, lParam); diff --git a/dgl/src/pugl/pugl_x11.c b/dgl/src/pugl/pugl_x11.c index 31b90516..8548387d 100644 --- a/dgl/src/pugl/pugl_x11.c +++ b/dgl/src/pugl/pugl_x11.c @@ -1,7 +1,7 @@ /* Copyright 2012-2014 David Robillard - Copyright 2013 Robin Gareus Copyright 2011-2012 Ben Loftis, Harrison Consoles + Copyright 2013 Robin Gareus Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -24,170 +24,101 @@ #include #include +#include +#include #include #include -#include #include -#ifdef PUGL_HAVE_GL -#include -#include -#endif - -#ifdef PUGL_HAVE_CAIRO -#include -#include -#endif - -#include "pugl/event.h" -#include "pugl/pugl_internal.h" +#include "pugl_internal.h" struct PuglInternalsImpl { Display* display; int screen; Window win; -#ifdef PUGL_HAVE_CAIRO - cairo_t* cr; -#endif -#ifdef PUGL_HAVE_GL GLXContext ctx; Bool doubleBuffered; -#endif }; -PuglInternals* -puglInitInternals() -{ - return (PuglInternals*)calloc(1, sizeof(PuglInternals)); -} - -static XVisualInfo* -getVisual(PuglView* view) -{ - PuglInternals* const impl = view->impl; - XVisualInfo* vi = NULL; - -#ifdef PUGL_HAVE_GL - if (view->ctx_type == PUGL_GL) { - // Try to create double-buffered visual - int double_attrs[] = { GLX_RGBA, GLX_DOUBLEBUFFER, - GLX_RED_SIZE, 4, - GLX_GREEN_SIZE, 4, - GLX_BLUE_SIZE, 4, - GLX_DEPTH_SIZE, 16, - None }; - vi = glXChooseVisual(impl->display, impl->screen, double_attrs); - if (!vi) { - // Failed, create single-buffered visual - int single_attrs[] = { GLX_RGBA, - GLX_RED_SIZE, 4, - GLX_GREEN_SIZE, 4, - GLX_BLUE_SIZE, 4, - GLX_DEPTH_SIZE, 16, - None }; - vi = glXChooseVisual(impl->display, impl->screen, single_attrs); - impl->doubleBuffered = False; - } else { - impl->doubleBuffered = True; - } -#ifdef PUGL_VERBOSE - int glxMajor, glxMinor; - glXQueryVersion(impl->display, &glxMajor, &glxMinor); - PUGL_LOGF("GLX Version %d.%d\n", glxMajor, glxMinor); -#endif - } -#endif -#ifdef PUGL_HAVE_CAIRO - if (view->ctx_type == PUGL_CAIRO) { - XVisualInfo pat; - int n; - pat.screen = impl->screen; - vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n); - } -#endif - - return vi; -} - -static void -createContext(PuglView* view, XVisualInfo* vi) -{ - PuglInternals* const impl = view->impl; - -#ifdef PUGL_HAVE_GL - if (view->ctx_type == PUGL_GL) { - impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); -#ifdef PUGL_VERBOSE - if (glXIsDirect(impl->display, impl->ctx)) { - PUGL_LOG("DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n"); - } else { - PUGL_LOG("No DRI available\n"); - } -#endif - } -#endif -#ifdef PUGL_HAVE_CAIRO - if (view->ctx_type == PUGL_CAIRO) { - cairo_surface_t* surface = cairo_xlib_surface_create( - impl->display, impl->win, vi->visual, view->width, view->height); - if (!(impl->cr = cairo_create(surface))) { - fprintf(stderr, "failed to create cairo context\n"); - } - } -#endif -} +/** + 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 void -destroyContext(PuglView* view) -{ -#ifdef PUGL_HAVE_GL - if (view->ctx_type == PUGL_GL) { - glXDestroyContext(view->impl->display, view->impl->ctx); - } -#endif -#ifdef PUGL_HAVE_CAIRO - if (view->ctx_type == PUGL_CAIRO) { - glXDestroyContext(view->impl->display, view->impl->ctx); - } -#endif -} +/** + 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, + GLX_ARB_multisample, 1, + None +}; -void -puglEnterContext(PuglView* view) -{ -#ifdef PUGL_HAVE_GL - if (view->ctx_type == PUGL_GL) { - glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); - } -#endif -} +/** + 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 +}; -void -puglLeaveContext(PuglView* view, bool flush) +PuglInternals* +puglInitInternals(void) { -#ifdef PUGL_HAVE_GL - if (view->ctx_type == PUGL_GL && flush) { - glFlush(); - if (view->impl->doubleBuffered) { - glXSwapBuffers(view->impl->display, view->impl->win); - } - } -#endif + return (PuglInternals*)calloc(1, sizeof(PuglInternals)); } int puglCreateWindow(PuglView* view, const char* title) { - PuglInternals* const impl = view->impl; + PuglInternals* impl = view->impl; impl->display = XOpenDisplay(0); 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); + PUGL_LOG("multisampling (antialiasing) is not available\n"); + } - XVisualInfo* const vi = getVisual(view); if (!vi) { - return 1; + vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); + impl->doubleBuffered = False; + PUGL_LOG("singlebuffered rendering will be used, no doublebuffering available\n"); } + int glxMajor, glxMinor; + glXQueryVersion(impl->display, &glxMajor, &glxMinor); + PUGL_LOGF("GLX Version %d.%d\n", glxMajor, glxMinor); + + impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); + Window xParent = view->parent ? (Window)view->parent : RootWindow(impl->display, impl->screen); @@ -197,21 +128,20 @@ puglCreateWindow(PuglView* view, const char* title) XSetWindowAttributes attr; memset(&attr, 0, sizeof(XSetWindowAttributes)); - attr.background_pixel = BlackPixel(impl->display, impl->screen); - attr.border_pixel = BlackPixel(impl->display, impl->screen); - attr.colormap = cmap; - attr.event_mask = (ExposureMask | StructureNotifyMask | - EnterWindowMask | LeaveWindowMask | - KeyPressMask | KeyReleaseMask | - ButtonPressMask | ButtonReleaseMask | - PointerMotionMask); + attr.colormap = cmap; + attr.border_pixel = 0; + + attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask + | ButtonPressMask | ButtonReleaseMask +#ifdef PUGL_GRAB_FOCUS + | EnterWindowMask +#endif + | PointerMotionMask | StructureNotifyMask; impl->win = XCreateWindow( impl->display, xParent, 0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual, - CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &attr); - - createContext(view, vi); + CWBorderPixel | CWColormap | CWEventMask, &attr); XSizeHints sizeHints; memset(&sizeHints, 0, sizeof(sizeHints)); @@ -233,21 +163,33 @@ puglCreateWindow(PuglView* view, const char* title) XSetWMProtocols(impl->display, impl->win, &wmDelete, 1); } + if (glXIsDirect(impl->display, impl->ctx)) { + PUGL_LOG("DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n"); + } else { + PUGL_LOG("No DRI available\n"); + } + XFree(vi); + glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); + return 0; } void puglShowWindow(PuglView* view) { - XMapRaised(view->impl->display, view->impl->win); + PuglInternals* impl = view->impl; + + XMapRaised(impl->display, impl->win); } void puglHideWindow(PuglView* view) { - XUnmapWindow(view->impl->display, view->impl->win); + PuglInternals* impl = view->impl; + + XUnmapWindow(impl->display, impl->win); } void @@ -257,13 +199,46 @@ puglDestroy(PuglView* view) return; } - destroyContext(view); + 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); + + view->redisplay = false; + + if (view->displayFunc) { + view->displayFunc(view); + } + + glFlush(); + + if (view->impl->doubleBuffered) { + glXSwapBuffers(view->impl->display, view->impl->win); + } +} + static PuglKey keySymToSpecial(KeySym sym) { @@ -302,184 +277,145 @@ keySymToSpecial(KeySym sym) } static void -translateKey(XEvent* xevent, PuglEvent* event) +setModifiers(PuglView* view, unsigned xstate, unsigned xtime) { - KeySym sym; - char str[5]; - const int n = XLookupString(&xevent->xkey, str, 4, &sym, NULL); - if (n == 1) { - event->key.character = str[0]; // TODO: multi-byte support - } - event->key.special = keySymToSpecial(sym); -} + view->event_timestamp_ms = xtime; -static unsigned -translateModifiers(unsigned xstate) -{ - unsigned state = 0; - state |= (xstate & ShiftMask) ? PUGL_MOD_SHIFT : 0; - state |= (xstate & ControlMask) ? PUGL_MOD_CTRL : 0; - state |= (xstate & Mod1Mask) ? PUGL_MOD_ALT : 0; - state |= (xstate & Mod4Mask) ? PUGL_MOD_SUPER : 0; - return state; + 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; } -static PuglEvent -translateEvent(PuglView* view, XEvent xevent) +static void +dispatchKey(PuglView* view, XEvent* event, bool press) { - PuglEvent event; - memset(&event, 0, sizeof(event)); - - event.any.view = view; - event.any.send_event = xevent.xany.send_event; - - switch (xevent.type) { - case ConfigureNotify: - event.type = PUGL_CONFIGURE; - event.configure.x = xevent.xconfigure.x; - event.configure.y = xevent.xconfigure.y; - event.configure.width = xevent.xconfigure.width; - event.configure.height = xevent.xconfigure.height; - break; - case Expose: - event.type = PUGL_EXPOSE; - event.expose.x = xevent.xexpose.x; - event.expose.y = xevent.xexpose.y; - event.expose.width = xevent.xexpose.width; - event.expose.height = xevent.xexpose.height; - event.expose.count = xevent.xexpose.count; - break; - case MotionNotify: - event.type = PUGL_MOTION_NOTIFY; - event.motion.time = xevent.xmotion.time; - event.motion.x = xevent.xmotion.x; - event.motion.y = xevent.xmotion.y; - event.motion.x_root = xevent.xmotion.x_root; - event.motion.y_root = xevent.xmotion.y_root; - event.motion.state = translateModifiers(xevent.xmotion.state); - event.motion.is_hint = (xevent.xmotion.is_hint == NotifyHint); - break; - case ButtonPress: - if (xevent.xbutton.button >= 4 && xevent.xbutton.button <= 7) { - event.type = PUGL_SCROLL; - event.scroll.time = xevent.xbutton.time; - event.scroll.x = xevent.xbutton.x; - event.scroll.y = xevent.xbutton.y; - event.scroll.x_root = xevent.xbutton.x_root; - event.scroll.y_root = xevent.xbutton.y_root; - event.scroll.state = translateModifiers(xevent.xbutton.state); - event.scroll.dx = 0.0; - event.scroll.dy = 0.0; - switch (xevent.xbutton.button) { - case 4: event.scroll.dy = 1.0f; break; - case 5: event.scroll.dy = -1.0f; break; - case 6: event.scroll.dx = -1.0f; break; - case 7: event.scroll.dx = 1.0f; break; - } - } - // nobreak - case ButtonRelease: - if (xevent.xbutton.button < 4 || xevent.xbutton.button > 7) { - event.button.type = ((xevent.type == ButtonPress) - ? PUGL_BUTTON_PRESS - : PUGL_BUTTON_RELEASE); - event.button.time = xevent.xbutton.time; - event.button.x = xevent.xbutton.x; - event.button.y = xevent.xbutton.y; - event.button.x_root = xevent.xbutton.x_root; - event.button.y_root = xevent.xbutton.y_root; - event.button.state = translateModifiers(xevent.xbutton.state); - event.button.button = xevent.xbutton.button; - } - break; - case KeyPress: - case KeyRelease: - event.type = ((xevent.type == KeyPress) - ? PUGL_KEY_PRESS - : PUGL_KEY_RELEASE); - event.key.time = xevent.xbutton.time; - event.key.x = xevent.xbutton.x; - event.key.y = xevent.xbutton.y; - event.key.x_root = xevent.xbutton.x_root; - event.key.y_root = xevent.xbutton.y_root; - event.key.state = translateModifiers(xevent.xbutton.state); - translateKey(&xevent, &event); - break; - case EnterNotify: - case LeaveNotify: - event.type = ((xevent.type == EnterNotify) - ? PUGL_ENTER_NOTIFY - : PUGL_LEAVE_NOTIFY); - event.crossing.time = xevent.xcrossing.time; - event.crossing.x = xevent.xcrossing.x; - event.crossing.y = xevent.xcrossing.y; - event.crossing.x_root = xevent.xcrossing.x_root; - event.crossing.y_root = xevent.xcrossing.y_root; - event.crossing.state = translateModifiers(xevent.xcrossing.state); - event.crossing.mode = PUGL_CROSSING_NORMAL; - if (xevent.xcrossing.mode == NotifyGrab) { - event.crossing.mode = PUGL_CROSSING_GRAB; - } else if (xevent.xcrossing.mode == NotifyUngrab) { - event.crossing.mode = PUGL_CROSSING_UNGRAB; - } - break; - default: - break; - } + KeySym sym; + char str[5]; + const int n = XLookupString(&event->xkey, str, 4, &sym, NULL); - return event; -} + if (sym == XK_Escape && view->closeFunc && !press && !view->parent) { + view->closeFunc(view); + view->redisplay = false; + return; + } + if (n == 0) { + return; + } + if (n > 1) { + fprintf(stderr, "warning: Unsupported multi-byte key %X\n", (int)sym); + return; + } -void -puglGrabFocus(PuglView* view) -{ - XSetInputFocus( - view->impl->display, view->impl->win, RevertToPointerRoot, CurrentTime); + const PuglKey special = keySymToSpecial(sym); + if (special && view->specialFunc) { + view->specialFunc(view, press, special); + } else if (!special && view->keyboardFunc) { + view->keyboardFunc(view, press, str[0]); + } } PuglStatus puglProcessEvents(PuglView* view) { - XEvent xevent; + XEvent event; while (XPending(view->impl->display) > 0) { - XNextEvent(view->impl->display, &xevent); - bool ignore = false; - if (xevent.type == ClientMessage) { - // Handle close message - char* type = XGetAtomName(view->impl->display, - xevent.xclient.message_type); - if (!strcmp(type, "WM_PROTOCOLS") && view->closeFunc) { - view->closeFunc(view); + 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); } - XFree(type); - continue; - } else if (xevent.type == KeyRelease) { - // Ignore key repeat if necessary + break; + case Expose: + if (event.xexpose.count != 0) { + break; + } + puglDisplay(view); + break; + case MotionNotify: + 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, event.xbutton.state, event.xbutton.time); + 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, event.xbutton.x, event.xbutton.y, dx, dy); + } + break; + } + // nobreak + case ButtonRelease: + setModifiers(view, event.xbutton.state, event.xbutton.time); + if (view->mouseFunc && + (event.xbutton.button < 4 || event.xbutton.button > 7)) { + view->mouseFunc(view, + event.xbutton.button, event.type == ButtonPress, + event.xbutton.x, event.xbutton.y); + } + break; + case KeyPress: + setModifiers(view, event.xkey.state, event.xkey.time); + dispatchKey(view, &event, true); + break; + case KeyRelease: { + setModifiers(view, event.xkey.state, event.xkey.time); + 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 == xevent.xkey.time && - next.xkey.keycode == xevent.xkey.keycode) { - XNextEvent(view->impl->display, &xevent); - ignore = true; + next.xkey.time == event.xkey.time && + next.xkey.keycode == event.xkey.keycode) { + XNextEvent(view->impl->display, &event); + repeated = true; } } - } - - if (!ignore) { - // Translate and dispatch event - const PuglEvent event = translateEvent(view, xevent); - puglDispatchEvent(view, &event); + if (!repeated) { + dispatchKey(view, &event, false); + } + } break; + case ClientMessage: { + char* type = XGetAtomName(view->impl->display, + event.xclient.message_type); + if (!strcmp(type, "WM_PROTOCOLS")) { + if (view->closeFunc) { + view->closeFunc(view); + view->redisplay = false; + } + } + XFree(type); + } break; +#ifdef PUGL_GRAB_FOCUS + case EnterNotify: + XSetInputFocus(view->impl->display, view->impl->win, RevertToPointerRoot, CurrentTime); + break; +#endif + default: + break; } } if (view->redisplay) { - const PuglEventExpose expose = { - PUGL_EXPOSE, view, true, 0.0, 0.0, (double)view->width, (double)view->height, 0 - }; - puglDispatchEvent(view, (const PuglEvent*)&expose); + puglDisplay(view); } return PUGL_SUCCESS; @@ -496,17 +432,3 @@ puglGetNativeWindow(PuglView* view) { return view->impl->win; } - -void* -puglGetContext(PuglView* view) -{ -#ifdef PUGL_HAVE_CAIRO - if (view->ctx_type == PUGL_CAIRO) { - return view->impl->cr; - } -#endif - return NULL; - - // possibly unused - (void)view; -}