Browse Source

Update DGL module

tags/1.9.6
falkTX 9 years ago
parent
commit
deeb75cf8f
10 changed files with 432 additions and 997 deletions
  1. +15
    -16
      source/modules/dgl/src/Window.cpp
  2. +0
    -121
      source/modules/dgl/src/pugl/common.h
  3. +0
    -217
      source/modules/dgl/src/pugl/event.h
  4. +0
    -32
      source/modules/dgl/src/pugl/gl.h
  5. +0
    -32
      source/modules/dgl/src/pugl/glu.h
  6. +100
    -75
      source/modules/dgl/src/pugl/pugl.h
  7. +19
    -102
      source/modules/dgl/src/pugl/pugl_internal.h
  8. +4
    -20
      source/modules/dgl/src/pugl/pugl_osx.m
  9. +55
    -65
      source/modules/dgl/src/pugl/pugl_win.cpp
  10. +239
    -317
      source/modules/dgl/src/pugl/pugl_x11.c

+ 15
- 16
source/modules/dgl/src/Window.cpp View File

@@ -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<long>(width), static_cast<long>(height) };
AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST);
AdjustWindowRectEx(&wr, fUsingEmbed ? WS_CHILD : 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);


+ 0
- 121
source/modules/dgl/src/pugl/common.h View File

@@ -1,121 +0,0 @@
/*
Copyright 2014 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.
*/

#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 */

+ 0
- 217
source/modules/dgl/src/pugl/event.h View File

@@ -1,217 +0,0 @@
/*
Copyright 2014 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.
*/

#ifndef PUGL_EVENT_H_INCLUDED
#define PUGL_EVENT_H_INCLUDED

#ifdef __cplusplus
extern "C" {
#else
# include <stdbool.h>
#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 */

+ 0
- 32
source/modules/dgl/src/pugl/gl.h View File

@@ -1,32 +0,0 @@
/*
Copyright 2012-2014 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 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 <windows.h> /* Broken Windows GL headers require this */
# endif
# include "GL/gl.h"
#endif


+ 0
- 32
source/modules/dgl/src/pugl/glu.h View File

@@ -1,32 +0,0 @@
/*
Copyright 2012-2014 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 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 <windows.h> /* Broken Windows GL headers require this */
# endif
# include "GL/glu.h"
#endif


+ 100
- 75
source/modules/dgl/src/pugl/pugl.h View File

@@ -23,8 +23,19 @@

#include <stdint.h>

#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 <windows.h> /* 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.


+ 19
- 102
source/modules/dgl/src/pugl/pugl_internal.h View File

@@ -1,5 +1,5 @@
/*
Copyright 2012-2014 David Robillard <http://drobilla.net>
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
@@ -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 <stdio.h>
@@ -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;
}
}

+ 4
- 20
source/modules/dgl/src/pugl/pugl_osx.m View File

@@ -1,5 +1,5 @@
/*
Copyright 2012-2014 David Robillard <http://drobilla.net>
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
@@ -22,7 +22,7 @@

#import <Cocoa/Cocoa.h>

#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;


+ 55
- 65
source/modules/dgl/src/pugl/pugl_win.cpp View File

@@ -1,5 +1,5 @@
/*
Copyright 2012-2014 David Robillard <http://drobilla.net>
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
@@ -22,11 +22,11 @@
#include <windowsx.h>
#include <GL/gl.h>

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

#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,8 +49,6 @@ struct PuglInternalsImpl {
WNDCLASS wc;
};

static HINSTANCE hInstance = NULL;

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

@@ -69,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)
{
@@ -103,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;
@@ -116,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);
AdjustWindowRectEx(&wr, view->parent ? WS_CHILD : 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);

@@ -164,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;
@@ -192,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);
@@ -201,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;
@@ -214,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
@@ -310,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;
@@ -335,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:
@@ -359,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);
}
@@ -376,12 +377,6 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
return 0;
}

void
puglGrabFocus(PuglView* /*view*/)
{
// TODO
}

PuglStatus
puglProcessEvents(PuglView* view)
{
@@ -390,7 +385,6 @@ puglProcessEvents(PuglView* view)
handleMessage(view, msg.message, msg.wParam, msg.lParam);
}


if (view->redisplay) {
InvalidateRect(view->impl->hwnd, NULL, FALSE);
}
@@ -401,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);


+ 239
- 317
source/modules/dgl/src/pugl/pugl_x11.c View File

@@ -1,7 +1,7 @@
/*
Copyright 2012-2014 David Robillard <http://drobilla.net>
Copyright 2013 Robin Gareus <robin@gareus.org>
Copyright 2011-2012 Ben Loftis, Harrison Consoles
Copyright 2013 Robin Gareus <robin@gareus.org>

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 <stdlib.h>
#include <string.h>

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

#ifdef PUGL_HAVE_GL
#include <GL/gl.h>
#include <GL/glx.h>
#endif

#ifdef PUGL_HAVE_CAIRO
#include <cairo/cairo.h>
#include <cairo/cairo-xlib.h>
#endif

#include "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;
}

Loading…
Cancel
Save