diff --git a/dgl/src/pugl-custom/pugl.h b/dgl/src/pugl-custom/pugl.h deleted file mode 100644 index 20a38140..00000000 --- a/dgl/src/pugl-custom/pugl.h +++ /dev/null @@ -1,492 +0,0 @@ -/* - Copyright 2012-2014 David Robillard - Copyright 2012-2019 Filipe Coelho - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/** - @file pugl.h API for Pugl, a minimal portable API for OpenGL. -*/ - -#ifndef PUGL_H_INCLUDED -#define PUGL_H_INCLUDED - -#include - -/* - 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 -#else -# ifdef _WIN32 -# include -# include /* Broken Windows GL headers require this */ -# endif -# include -#endif - -#ifdef __cplusplus -extern "C" { -#else -# include -#endif - -/** - @defgroup pugl Pugl - A minimal portable API for OpenGL. - @{ -*/ - -/** - 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; - -/** - Return status code. -*/ -typedef enum { - PUGL_SUCCESS = 0 -} PuglStatus; - -/** - Convenience symbols for ASCII control characters. -*/ -typedef enum { - PUGL_CHAR_BACKSPACE = 0x08, - PUGL_CHAR_ESCAPE = 0x1B, - PUGL_CHAR_DELETE = 0x7F -} PuglChar; - -/** - Special (non-Unicode) keyboard keys. -*/ -typedef enum { - PUGL_KEY_F1 = 1, - PUGL_KEY_F2, - PUGL_KEY_F3, - PUGL_KEY_F4, - PUGL_KEY_F5, - PUGL_KEY_F6, - PUGL_KEY_F7, - PUGL_KEY_F8, - PUGL_KEY_F9, - PUGL_KEY_F10, - PUGL_KEY_F11, - PUGL_KEY_F12, - PUGL_KEY_LEFT, - PUGL_KEY_UP, - PUGL_KEY_RIGHT, - PUGL_KEY_DOWN, - PUGL_KEY_PAGE_UP, - PUGL_KEY_PAGE_DOWN, - PUGL_KEY_HOME, - PUGL_KEY_END, - PUGL_KEY_INSERT, - PUGL_KEY_SHIFT, - PUGL_KEY_CTRL, - PUGL_KEY_ALT, - PUGL_KEY_SUPER -} PuglKey; - -/** - Keyboard modifier flags. -*/ -typedef enum { - PUGL_MOD_SHIFT = 1 << 0, /**< Shift key */ - PUGL_MOD_CTRL = 1 << 1, /**< Control key */ - PUGL_MOD_ALT = 1 << 2, /**< Alt/Option key */ - PUGL_MOD_SUPER = 1 << 3 /**< Mod4/Command/Windows key */ -} PuglMod; - -/** - Handle for opaque user data. -*/ -typedef void* PuglHandle; - -/** - A function called when the window is closed. -*/ -typedef void (*PuglCloseFunc)(PuglView* view); - -/** - A function called to draw the view contents with OpenGL. -*/ -typedef void (*PuglDisplayFunc)(PuglView* view); - -/** - A function called when a key is pressed or released. - @param view The view the event occured in. - @param press True if the key was pressed, false if released. - @param key Unicode point of the key pressed. - @return 0 if event was handled, otherwise send event to parent window. -*/ -typedef int (*PuglKeyboardFunc)(PuglView* view, bool press, uint32_t key); - -/** - A function called when the pointer moves. - @param view The view the event occured in. - @param x The window-relative x coordinate of the pointer. - @param y The window-relative y coordinate of the pointer. -*/ -typedef void (*PuglMotionFunc)(PuglView* view, int x, int y); - -/** - A function called when a mouse button is pressed or released. - @param view The view the event occured in. - @param button The button number (1 = left, 2 = middle, 3 = right). - @param press True if the key was pressed, false if released. - @param x The window-relative x coordinate of the pointer. - @param y The window-relative y coordinate of the pointer. -*/ -typedef void (*PuglMouseFunc)( - PuglView* view, int button, bool press, int x, int y); - -/** - A function called when the view is resized. - @param view The view being resized. - @param width The new view width. - @param height The new view height. -*/ -typedef void (*PuglReshapeFunc)(PuglView* view, int width, int height); - -/** - A function called outside of gl-context when the plugin schedules a resize via puglPostResize. - - @param view The view being resized. - @param width The new width to resize to (variable is initialized to current size) - @param height The new height to resize to (variable is initialized to current size) - @param set_hints If not null, set window-hints - */ -typedef void (*PuglResizeFunc)(PuglView* view, int *width, int *height, int *set_hints); - -/** - A function called on scrolling (e.g. mouse wheel or track pad). - - The distances used here are in "lines", a single tick of a clicking mouse - wheel. For example, @p dy = 1.0 scrolls 1 line up. Some systems and - devices support finer resolution and/or higher values for fast scrolls, - so programs should handle any value gracefully. - - @param view The view being scrolled. - @param 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); - -/** - 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. - @param key The key pressed. - @return 0 if event was handled, otherwise send event to parent window. -*/ -typedef int (*PuglSpecialFunc)(PuglView* view, bool press, PuglKey key); - -/** - A function called when a filename is selected via file-browser. - - @param view The view the event occured in. - @param filename The selected file name or NULL if the dialog was canceled. -*/ -typedef void (*PuglFileSelectedFunc)(PuglView* view, const char* filename); - -/** - @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(). -*/ -PuglView* -puglInit(void); - -/** - Set the parent window before creating a window (for embedding). -*/ -void -puglInitWindowParent(PuglView* view, PuglNativeWindow parent); - -/** - Set the window size before creating a window. -*/ -void -puglInitWindowSize(PuglView* view, int width, int height); - -/** - Set the minimum window size before creating a window. -*/ -void -puglInitWindowMinSize(PuglView* view, int width, int height); - -/** - Enable or disable resizing before creating a window. -*/ -void -puglInitUserResizable(PuglView* view, bool resizable); - -/** - Set transient parent before creating a window. - - On X11, parent_id must be a Window. - On OSX, parent_id must be an NSView*. -*/ -void -puglInitTransientFor(PuglView* view, uintptr_t parent); - -/** - @} -*/ - -/** - @name Windows - Window management functions. - @{ -*/ - -/** - Create a window with the settings given by the various puglInit functions. - - @return 1 (pugl does not currently support multiple windows). -*/ -int -puglCreateWindow(PuglView* view, const char* title); - -/** - Create a new GL window. - @param parent Parent window, or 0 for top level. - @param title Window title, or NULL. - @param width Window width in pixels. - @param height Window height in pixels. - @param resizable Whether window should be user resizable. -*/ -PuglView* -puglCreate(PuglNativeWindow parent, - const char* title, - int min_width, - int min_height, - int width, - int height, - bool resizable, - unsigned long transientId); - -/** - Show Window (external ui) -*/ -void -puglShowWindow(PuglView* view); - -/** - Hide Window (external ui) -*/ -void -puglHideWindow(PuglView* view); - -/** - Return the native window handle. -*/ -PuglNativeWindow -puglGetNativeWindow(PuglView* view); - -/** - @} -*/ - -/** - Set the handle to be passed to all callbacks. - - This is generally a pointer to a struct which contains all necessary state. - Everything needed in callbacks should be here, not in static variables. - - Note the lack of this facility makes GLUT unsuitable for plugins or - non-trivial programs; this mistake is largely why Pugl exists. -*/ -void -puglSetHandle(PuglView* view, PuglHandle handle); - -/** - Get the handle to be passed to all callbacks. -*/ -PuglHandle -puglGetHandle(PuglView* view); - -/** - Get the drawing context. - For Cairo contexts, this returns a pointer to a cairo_t. - For everything else, this is unused and returns NULL. -*/ -void* -puglGetContext(PuglView* view); - -/** - Return the timestamp (if any) of the currently-processing event. -*/ -uint32_t -puglGetEventTimestamp(PuglView* view); - -/** - Get the currently active modifiers (PuglMod flags). - - This should only be called from an event handler. -*/ -int -puglGetModifiers(PuglView* view); - -/** - Ignore synthetic repeated key events. -*/ -void -puglIgnoreKeyRepeat(PuglView* view, bool ignore); - -/** - @name Event Callbacks - Functions to set event callbacks for handling user input. - @{ -*/ - -/** - Set the function to call when the window is closed. -*/ -void -puglSetCloseFunc(PuglView* view, PuglCloseFunc closeFunc); - -/** - Set the display function which should draw the UI using GL. -*/ -void -puglSetDisplayFunc(PuglView* view, PuglDisplayFunc displayFunc); - -/** - Set the function to call on keyboard events. -*/ -void -puglSetKeyboardFunc(PuglView* view, PuglKeyboardFunc keyboardFunc); - -/** - Set the function to call on mouse motion. -*/ -void -puglSetMotionFunc(PuglView* view, PuglMotionFunc motionFunc); - -/** - Set the function to call on mouse button events. -*/ -void -puglSetMouseFunc(PuglView* view, PuglMouseFunc mouseFunc); - -/** - Set the function to call on scroll events. -*/ -void -puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc); - -/** - Set the function to call on special events. -*/ -void -puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc); - -/** - Set the function to call when the window size changes. -*/ -void -puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc); - -/** - Set callback function to change window size. -*/ -void -puglSetResizeFunc(PuglView* view, PuglResizeFunc resizeFunc); - -/** - Set the function to call on file-browser selections. -*/ -void -puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc); - -/** - @} -*/ - -/** - TODO document this. - */ -int -puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect); - -/** - Grab the input focus. -*/ -void -puglGrabFocus(PuglView* view); - -/** - Process all pending window events. - - This handles input events as well as rendering, so it should be called - regularly and rapidly enough to keep the UI responsive. -*/ -PuglStatus -puglProcessEvents(PuglView* view); - -/** - Request a redisplay on the next call to puglProcessEvents(). -*/ -void -puglPostRedisplay(PuglView* view); - -/** - Request a resize on the next call to puglProcessEvents(). -*/ -void -puglPostResize(PuglView* view); - -/** - Destroy a GL window. -*/ -void -puglDestroy(PuglView* view); - -/** - @} -*/ - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* PUGL_H_INCLUDED */ diff --git a/dgl/src/pugl-custom/pugl_haiku.cpp b/dgl/src/pugl-custom/pugl_haiku.cpp deleted file mode 100644 index d7f8dca3..00000000 --- a/dgl/src/pugl-custom/pugl_haiku.cpp +++ /dev/null @@ -1,441 +0,0 @@ -/* - Copyright 2019 Filipe Coelho - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/** - @file pugl_haiku.cpp BeOS/HaikuOS Pugl Implementation. -*/ - -#include -#include - -#ifdef PUGL_CAIRO -#include -typedef BView BViewType; -#endif -#ifdef PUGL_OPENGL -#include -#include -typedef BGLView BViewType; -#endif - -#include "pugl_internal.h" - -class DWindow; - -struct PuglInternalsImpl { - BApplication* app; - BViewType* view; - DWindow* window; -}; - -static void -puglReshape(PuglView* view, int width, int height) -{ - puglEnterContext(view); - - if (view->reshapeFunc) { - view->reshapeFunc(view, width, height); - } else { - puglDefaultReshape(width, height); - } - - puglLeaveContext(view, false); - - view->width = width; - view->height = height; -} - -static void -puglDisplay(PuglView* view) -{ - puglEnterContext(view); - - view->redisplay = false; - if (view->displayFunc) { - view->displayFunc(view); - } - - puglLeaveContext(view, true); -} - -void -puglEnterContext(PuglView* view) -{ - PuglInternals* impl = view->impl; - -#ifdef PUGL_OPENGL - // FIXME without the first unlock we freeze - impl->view->UnlockGL(); - impl->view->LockGL(); -#endif -} - -void -puglLeaveContext(PuglView* view, bool flush) -{ - PuglInternals* impl = view->impl; - -#ifdef PUGL_OPENGL - if (flush) - impl->view->SwapBuffers(); - - impl->view->UnlockGL(); -#endif -} - -PuglInternals* -puglInitInternals() -{ - return (PuglInternals*)calloc(1, sizeof(PuglInternals)); -} - -class DView : public BViewType -{ -public: -#ifdef PUGL_CAIRO - DView(PuglView* const v) - : BView(nullptr, - B_FULL_UPDATE_ON_RESIZE|B_WILL_DRAW|B_FRAME_EVENTS|B_NAVIGABLE|B_INPUT_METHOD_AWARE), - puglView(v) {} -#endif - -#ifdef PUGL_OPENGL - DView(PuglView* const v) - : BGLView(BRect(), // causes "bitmap bounds is much too large: BRect(0.0, 0.0, 4294967296.0, 4294967296.0)" - "DPF-GLView", - 0x0, // resize mode - B_FULL_UPDATE_ON_RESIZE|B_WILL_DRAW|B_NAVIGABLE_JUMP|B_FRAME_EVENTS|B_NAVIGABLE|B_INPUT_METHOD_AWARE, - BGL_RGB|BGL_DOUBLE|BGL_ALPHA|BGL_DEPTH|BGL_STENCIL), - puglView(v) - { - } -#endif - -protected: - void GetPreferredSize(float* width, float* height) override - { - d_stdout("%s %i", __func__, __LINE__); - if (width != nullptr) - *width = puglView->width; - if (height != nullptr) - *height = puglView->height; - d_stdout("%s %i", __func__, __LINE__); - } - - void Draw(BRect updateRect) override - { - d_stdout("%s %i", __func__, __LINE__); - puglDisplay(puglView); -#ifdef PUGL_OPENGL - BGLView::Draw(updateRect); - d_stdout("%s %i", __func__, __LINE__); -#endif - } - - void MessageReceived(BMessage* message) - { - d_stdout("MessageReceived %p", message); - BViewType::MessageReceived(message); - } - - void MouseDown(BPoint where) override - { - if (puglView->mouseFunc) { - // puglView->event_timestamp_ms = GetMessageTime(); - d_stdout("MouseDown mask %u", EventMask()); - puglView->mouseFunc(puglView, 1, true, where.x, where.y); - SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); - } - //BViewType::MouseDown(where); - } - - void MouseUp(BPoint where) override - { - if (puglView->mouseFunc) { - d_stdout("MouseUp mask %u", EventMask()); - // puglView->event_timestamp_ms = GetMessageTime(); - puglView->mouseFunc(puglView, 1, false, where.x, where.y); - } - //BViewType::MouseUp(where); - } - - void MouseMoved(BPoint where, uint32, const BMessage*) override - { - if (puglView->motionFunc) { - // puglView->event_timestamp_ms = GetMessageTime(); - puglView->motionFunc(puglView, where.x, where.y); - } - } - - void KeyDown(const char* bytes, int32 numBytes) override - { - d_stdout("KeyDown %i", numBytes); - if (numBytes != 1) - return; // TODO - - if (puglView->keyboardFunc) { - puglView->keyboardFunc(puglView, true, bytes[0]); - } - } - - void KeyUp(const char* bytes, int32 numBytes) override - { - d_stdout("KeyUp %i", numBytes); - if (numBytes != 1) - return; // TODO - - if (puglView->keyboardFunc) { - puglView->keyboardFunc(puglView, false, bytes[0]); - } - } - - void ScrollTo(BPoint where) override - { - d_stdout("ScrollTo mask %u", EventMask()); - BViewType::ScrollTo(where); - } - - void FrameResized(float newWidth, float newHeight) override - { - d_stdout("%s %i", __func__, __LINE__); - puglReshape(puglView, static_cast(newWidth), static_cast(newHeight)); -#ifdef PUGL_OPENGL - BGLView::FrameResized(newWidth, newHeight); -#endif - d_stdout("%s %i", __func__, __LINE__); - } - -private: - PuglView* const puglView; -}; - -class DWindow : public BWindow -{ -public: - DWindow(PuglView* const v) - : BWindow(BRect(1.0f), "DPF-Window", B_TITLED_WINDOW, 0x0), - puglView(v), - needsQuit(true) - { - } - - bool NeedsQuit() const - { - return needsQuit; - } - -protected: - bool QuitRequested() override - { - d_stdout("%s %i", __func__, __LINE__); - if (puglView->closeFunc) { - puglView->closeFunc(puglView); - puglView->redisplay = false; - } - needsQuit = false; - d_stdout("%s %i", __func__, __LINE__); - return true; - } - -private: - PuglView* const puglView; - bool needsQuit; -}; - -int -puglCreateWindow(PuglView* view, const char* title) -{ - PuglInternals* impl = view->impl; - - if (be_app == nullptr) - { - d_stdout("creating app"); - status_t status; - BApplication* const app = new BApplication("application/x-vnd.dpf-application", &status); - - if (status != B_OK) - { - d_stdout("app status error %u", status); - delete app; - return 1; - } - - impl->app = app; - } - else - { - d_stdout("using existing app"); - } - - if (view->parent == 0) { - impl->window = new DWindow(view); - impl->window->Lock(); - } - - impl->view = new DView(view); - - if (view->parent != 0) { - BView* const pview = (BView*)view->parent; - pview->AddChild(impl->view); - impl->view->LockGL(); - return 0; - } - - if (title != nullptr) { - impl->window->SetTitle(title); - } - - impl->window->AddChild(impl->view); - impl->view->LockGL(); - //puglEnterContext(view); - impl->window->Unlock(); - return 0; -} - -void -puglShowWindow(PuglView* view) -{ - PuglInternals* impl = view->impl; - - if (impl->window != nullptr) - { - if (impl->window->LockLooper()) - { - impl->window->Show(); - impl->window->UnlockLooper(); - } - } - else - { - impl->view->Show(); - } -} - -void -puglHideWindow(PuglView* view) -{ - PuglInternals* impl = view->impl; - - if (impl->window != nullptr) - { - if (impl->window->LockLooper()) - { - impl->window->Hide(); - impl->window->UnlockLooper(); - } - } - else - { - impl->view->Show(); - } -} - -void -puglDestroy(PuglView* view) -{ - PuglInternals* impl = view->impl; - - if (impl->window != nullptr) - { - // impl->window->Lock(); - puglLeaveContext(view, false); - impl->window->RemoveChild(impl->view); - // impl->window->Unlock(); - - if (impl->window->NeedsQuit()) - impl->window->Quit(); - } - - delete impl->view; - impl->view = nullptr; - impl->window = nullptr; - - if (impl->app != nullptr && impl->app->CountWindows() == 0) - { - d_stdout("deleting app"); - delete impl->app; - impl->app = nullptr; - } else - d_stdout("NOT deleting app"); -} - -PuglStatus -puglProcessEvents(PuglView* view) -{ - return PUGL_SUCCESS; -} - -void -puglPostRedisplay(PuglView* view) -{ - PuglInternals* impl = view->impl; - - view->redisplay = true; - - if (impl->window != nullptr) - { - if (impl->window->LockLooper()) - { - impl->view->Invalidate(); - impl->window->UnlockLooper(); - } - } - else - { - impl->view->Invalidate(); - } -} - -PuglNativeWindow -puglGetNativeWindow(PuglView* view) -{ - PuglInternals* impl = view->impl; - -#ifdef PUGL_OPENGL - // return (PuglNativeWindow)impl->view->EmbeddedView(); -#endif - - return (PuglNativeWindow)(BView*)impl->view; -} - -void* -puglGetContext(PuglView* view) -{ - return NULL; -} - -int -puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect) -{ - PuglInternals* impl = view->impl; - - d_stdout("puglUpdateGeometryConstraints %i %i %i %i", min_width, min_height, view->width, view->height); - if (impl->window->LockLooper()) - { - impl->window->SetSizeLimits(min_width, - view->user_resizable ? 4096 : min_width, - min_height, - view->user_resizable ? 4096 : min_height); - - impl->window->UnlockLooper(); - return 0; - } - - return 1; - - // TODO - (void)aspect; -} diff --git a/dgl/src/pugl-custom/pugl_internal.h b/dgl/src/pugl-custom/pugl_internal.h deleted file mode 100644 index 609c97b9..00000000 --- a/dgl/src/pugl-custom/pugl_internal.h +++ /dev/null @@ -1,263 +0,0 @@ -/* - Copyright 2012-2014 David Robillard - Copyright 2012-2019 Filipe Coelho - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/** - @file pugl_internal.h Private platform-independent definitions. - - Note this file contains function definitions, so it must be compiled into - the final binary exactly once. Each platform specific implementation file - including it once should achieve this. -*/ - -#include "pugl.h" - -typedef struct PuglInternalsImpl PuglInternals; - -struct PuglViewImpl { - PuglHandle handle; - PuglCloseFunc closeFunc; - PuglDisplayFunc displayFunc; - PuglKeyboardFunc keyboardFunc; - PuglMotionFunc motionFunc; - PuglMouseFunc mouseFunc; - PuglReshapeFunc reshapeFunc; - PuglResizeFunc resizeFunc; - PuglScrollFunc scrollFunc; - PuglSpecialFunc specialFunc; - PuglFileSelectedFunc fileSelectedFunc; - - PuglInternals* impl; - PuglNativeWindow parent; - uintptr_t transient_parent; - - int width; - int height; - int min_width; - int min_height; - int mods; - bool mouse_in_view; - bool ignoreKeyRepeat; - bool redisplay; - bool user_resizable; - bool pending_resize; - uint32_t event_timestamp_ms; -}; - -PuglInternals* puglInitInternals(void); - -PuglView* -puglInit(void) -{ - PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); - if (!view) { - return NULL; - } - - PuglInternals* impl = puglInitInternals(); - if (!impl) { - free(view); - return NULL; - } - - view->impl = impl; - view->width = 640; - view->height = 480; - - return view; -} - -void -puglInitWindowSize(PuglView* view, int width, int height) -{ - view->width = width; - view->height = height; -} - -void -puglInitWindowMinSize(PuglView* view, int width, int height) -{ - view->min_width = width; - view->min_height = height; -} - -void -puglInitWindowParent(PuglView* view, PuglNativeWindow parent) -{ - view->parent = parent; -} - -void -puglInitUserResizable(PuglView* view, bool resizable) -{ - view->user_resizable = resizable; -} - -void -puglInitTransientFor(PuglView* view, uintptr_t parent) -{ - view->transient_parent = parent; -} - -PuglView* -puglCreate(PuglNativeWindow parent, - const char* title, - int min_width, - int min_height, - int width, - int height, - bool resizable, - unsigned long transientId) -{ - PuglView* view = puglInit(); - if (!view) { - return NULL; - } - - puglInitWindowParent(view, parent); - puglInitWindowMinSize(view, min_width, min_height); - puglInitWindowSize(view, width, height); - puglInitUserResizable(view, resizable); - puglInitTransientFor(view, transientId); - - if (!puglCreateWindow(view, title)) { - free(view); - return NULL; - } - - return view; -} - -void -puglSetHandle(PuglView* view, PuglHandle handle) -{ - view->handle = handle; -} - -PuglHandle -puglGetHandle(PuglView* view) -{ - return view->handle; -} - -uint32_t -puglGetEventTimestamp(PuglView* view) -{ - return view->event_timestamp_ms; -} - -int -puglGetModifiers(PuglView* view) -{ - return view->mods; -} - -void -puglIgnoreKeyRepeat(PuglView* view, bool ignore) -{ - view->ignoreKeyRepeat = ignore; -} - -void -puglSetCloseFunc(PuglView* view, PuglCloseFunc closeFunc) -{ - view->closeFunc = closeFunc; -} - -void -puglSetDisplayFunc(PuglView* view, PuglDisplayFunc displayFunc) -{ - view->displayFunc = displayFunc; -} - -void -puglSetKeyboardFunc(PuglView* view, PuglKeyboardFunc keyboardFunc) -{ - view->keyboardFunc = keyboardFunc; -} - -void -puglSetMotionFunc(PuglView* view, PuglMotionFunc motionFunc) -{ - view->motionFunc = motionFunc; -} - -void -puglSetMouseFunc(PuglView* view, PuglMouseFunc mouseFunc) -{ - view->mouseFunc = mouseFunc; -} - -void -puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc) -{ - view->reshapeFunc = reshapeFunc; -} - -void -puglSetResizeFunc(PuglView* view, PuglResizeFunc resizeFunc) -{ - view->resizeFunc = resizeFunc; -} - -void -puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc) -{ - view->scrollFunc = scrollFunc; -} - -void -puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc) -{ - view->specialFunc = specialFunc; -} - -void -puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc) -{ - view->fileSelectedFunc = fileSelectedFunc; -} - -void -puglEnterContext(PuglView* view); - -void -puglLeaveContext(PuglView* view, bool flush); - -static void -puglDefaultReshape(int width, int height) -{ -#ifdef PUGL_OPENGL -#ifdef ROBTK_HERE - glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); -#else - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, width, height, 0, 0, 1); - glViewport(0, 0, width, height); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); -#endif -#endif // PUGL_OPENGL -} diff --git a/dgl/src/pugl-custom/pugl_osx.m b/dgl/src/pugl-custom/pugl_osx.m deleted file mode 100644 index da595381..00000000 --- a/dgl/src/pugl-custom/pugl_osx.m +++ /dev/null @@ -1,974 +0,0 @@ -/* - Copyright 2012 David Robillard - Copyright 2012-2019 Filipe Coelho - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/** - @file pugl_osx.m OSX/Cocoa Pugl Implementation. -*/ - -#include - -#ifdef PUGL_CAIRO -#import -#import -#endif -#import - -#include "pugl_internal.h" - -@interface PuglWindow : NSWindow -{ -@public - PuglView* puglview; -} - -- (id) initWithContentRect:(NSRect)contentRect - styleMask:(unsigned int)aStyle - backing:(NSBackingStoreType)bufferingType - defer:(BOOL)flag; -- (void) setPuglview:(PuglView*)view; -- (BOOL) canBecomeKeyWindow; -- (BOOL) windowShouldClose:(id)sender; -@end - -@implementation PuglWindow - -- (id)initWithContentRect:(NSRect)contentRect - styleMask:(unsigned int)aStyle - backing:(NSBackingStoreType)bufferingType - defer:(BOOL)flag -{ - NSWindow* result = [super initWithContentRect:contentRect - styleMask:(NSClosableWindowMask | - NSTitledWindowMask | - NSResizableWindowMask) - backing:NSBackingStoreBuffered defer:NO]; - - [result setAcceptsMouseMovedEvents:YES]; - [result setLevel: CGShieldingWindowLevel() + 1]; - - return (PuglWindow*)result; - - // unused - (void)aStyle; (void)bufferingType; (void)flag; -} - -- (void)setPuglview:(PuglView*)view -{ - puglview = view; - [self setContentSize:NSMakeSize(view->width, view->height)]; -} - -- (BOOL)canBecomeKeyWindow -{ - return YES; -} - -- (BOOL)windowShouldClose:(id)sender -{ - if (puglview->closeFunc) - puglview->closeFunc(puglview); - return YES; - - // unused - (void)sender; -} - -@end - -static void -puglDisplay(PuglView* view) -{ - view->redisplay = false; - if (view->displayFunc) { - view->displayFunc(view); - } -} - -@protocol PuglGenericView -@required -- (PuglView *) puglview; -- (void) setPuglview:(PuglView *)pv; -- (NSTrackingArea *) puglTrackingArea; -- (void) setPuglTrackingArea:(NSTrackingArea *)area; -@end - -static unsigned -getModifiers(PuglView* view, NSEvent* ev) -{ - const unsigned modifierFlags = [ev modifierFlags]; - - view->event_timestamp_ms = fmod([ev timestamp] * 1000.0, UINT32_MAX); - - unsigned mods = 0; - mods |= (modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0; - mods |= (modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0; - mods |= (modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0; - mods |= (modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0; - return mods; -} - -static int -getFixedAppKitButton(NSInteger button) -{ - switch (button) { - case 0: return 1; - case 1: return 3; - case 2: return 2; - default: return button; - } -} - -static void -cursorUpdate(NSView *self, NSEvent* event) -{ - [[NSCursor arrowCursor] set]; - (void)self; - (void)event; -} - -static void -updateTrackingAreas(NSView *self) -{ - static const int opts = NSTrackingMouseEnteredAndExited - | NSTrackingMouseMoved - | NSTrackingEnabledDuringMouseDrag - | NSTrackingInVisibleRect - | NSTrackingActiveAlways - | NSTrackingCursorUpdate; - - NSTrackingArea *trackingArea = [self puglTrackingArea]; - if (trackingArea != nil) { - [self removeTrackingArea:trackingArea]; - [trackingArea release]; - } - - trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] - options:opts - owner:self - userInfo:nil]; - [self setPuglTrackingArea:trackingArea]; - [self addTrackingArea:trackingArea]; -} - -static void -viewWillMoveToWindow(NSView *self, NSWindow* newWindow) -{ - if (newWindow != nil) { - [newWindow setAcceptsMouseMovedEvents:YES]; - [newWindow makeFirstResponder:self]; - } -} - -static void -reshape(NSView *self) -{ - PuglView* puglview = [self puglview]; - - NSRect bounds = [self bounds]; - int width = bounds.size.width; - int height = bounds.size.height; - - puglEnterContext(puglview); - - if (puglview->reshapeFunc) { - puglview->reshapeFunc(puglview, width, height); - } else { - puglDefaultReshape(width, height); - } - - puglLeaveContext(puglview, false); - - puglview->width = width; - puglview->height = height; -} - -static void -mouseMoved(NSView *self, NSEvent *event) -{ - PuglView* puglview = [self puglview]; - - if (puglview->motionFunc) { - NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; - puglview->mods = getModifiers(puglview, event); - puglview->motionFunc(puglview, loc.x, loc.y); - } -} - -static void -mouseDown(NSView *self, NSEvent *event) -{ - PuglView* puglview = [self puglview]; - - if (puglview->mouseFunc) { - NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; - puglview->mods = getModifiers(puglview, event); - puglview->mouseFunc(puglview, getFixedAppKitButton([event buttonNumber]), true, loc.x, loc.y); - } -} - -static void -mouseUp(NSView *self, NSEvent *event) -{ - PuglView* puglview = [self puglview]; - - if (puglview->mouseFunc) { - NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; - puglview->mods = getModifiers(puglview, event); - puglview->mouseFunc(puglview, getFixedAppKitButton([event buttonNumber]), false, loc.x, loc.y); - } -} - -static void -scrollWheel(NSView *self, NSEvent *event) -{ - PuglView* puglview = [self puglview]; - - if (puglview->scrollFunc) { - NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; - puglview->mods = getModifiers(puglview, event); - puglview->scrollFunc(puglview, - loc.x, loc.y, - [event deltaX], [event deltaY]); - } -} - -static void -keyDown(NSView *self, NSEvent *event) -{ - PuglView* puglview = [self puglview]; - - if (puglview->keyboardFunc && !(puglview->ignoreKeyRepeat && [event isARepeat])) { - NSString* chars = [event characters]; - puglview->mods = getModifiers(puglview, event); - puglview->keyboardFunc(puglview, true, [chars characterAtIndex:0]); - } -} - -static void -keyUp(NSView *self, NSEvent *event) -{ - PuglView* puglview = [self puglview]; - - if (puglview->keyboardFunc) { - NSString* chars = [event characters]; - puglview->mods = getModifiers(puglview, event); - puglview->keyboardFunc(puglview, false, [chars characterAtIndex:0]); - } -} - -static void -flagsChanged(NSView *self, NSEvent *event) -{ - PuglView* puglview = [self puglview]; - - if (puglview->specialFunc) { - const unsigned mods = getModifiers(puglview, event); - if ((mods & PUGL_MOD_SHIFT) != (puglview->mods & PUGL_MOD_SHIFT)) { - puglview->specialFunc(puglview, mods & PUGL_MOD_SHIFT, PUGL_KEY_SHIFT); - } else if ((mods & PUGL_MOD_CTRL) != (puglview->mods & PUGL_MOD_CTRL)) { - puglview->specialFunc(puglview, mods & PUGL_MOD_CTRL, PUGL_KEY_CTRL); - } else if ((mods & PUGL_MOD_ALT) != (puglview->mods & PUGL_MOD_ALT)) { - puglview->specialFunc(puglview, mods & PUGL_MOD_ALT, PUGL_KEY_ALT); - } else if ((mods & PUGL_MOD_SUPER) != (puglview->mods & PUGL_MOD_SUPER)) { - puglview->specialFunc(puglview, mods & PUGL_MOD_SUPER, PUGL_KEY_SUPER); - } - puglview->mods = mods; - } -} - -#ifdef PUGL_OPENGL -@interface PuglOpenGLView : NSOpenGLView -{ -@public - PuglView* puglview; - NSTrackingArea* trackingArea; - bool doubleBuffered; -} - -- (PuglView *) puglview; -- (void) setPuglview:(PuglView *)pv; -- (NSTrackingArea *) puglTrackingArea; -- (void) setPuglTrackingArea:(NSTrackingArea *)area; - -- (BOOL) acceptsFirstMouse:(NSEvent*)e; -- (BOOL) acceptsFirstResponder; -- (BOOL) isFlipped; -- (BOOL) isOpaque; -- (BOOL) preservesContentInLiveResize; -- (id) initWithFrame:(NSRect)frame; -- (void) reshape; -- (void) drawRect:(NSRect)r; -- (void) cursorUpdate:(NSEvent*)e; -- (void) updateTrackingAreas; -- (void) viewWillMoveToWindow:(NSWindow*)newWindow; -- (void) mouseMoved:(NSEvent*)event; -- (void) mouseDragged:(NSEvent*)event; -- (void) rightMouseDragged:(NSEvent*)event; -- (void) otherMouseDragged:(NSEvent*)event; -- (void) mouseDown:(NSEvent*)event; -- (void) rightMouseDown:(NSEvent*)event; -- (void) otherMouseDown:(NSEvent*)event; -- (void) mouseUp:(NSEvent*)event; -- (void) rightMouseUp:(NSEvent*)event; -- (void) otherMouseUp:(NSEvent*)event; -- (void) scrollWheel:(NSEvent*)event; -- (void) keyDown:(NSEvent*)event; -- (void) keyUp:(NSEvent*)event; -- (void) flagsChanged:(NSEvent*)event; -- (void) resizeWithOldSuperviewSize:(NSSize)oldSize; - -@end - -@implementation PuglOpenGLView -- (PuglView *) puglview { - return self->puglview; -} - -- (void) setPuglview:(PuglView *)pv { - self->puglview = pv; -} - -- (NSTrackingArea *) puglTrackingArea { - return self->trackingArea; -} - -- (void) setPuglTrackingArea:(NSTrackingArea *)area { - self->trackingArea = area; -} - -- (BOOL) acceptsFirstMouse:(NSEvent*)e -{ - return YES; - - // unused - (void)e; -} - -- (BOOL) acceptsFirstResponder -{ - return YES; -} - -- (BOOL) isFlipped -{ - return YES; -} - -- (BOOL) isOpaque -{ - return YES; -} - -- (BOOL) preservesContentInLiveResize -{ - return NO; -} - -- (id) initWithFrame:(NSRect)frame -{ - puglview = nil; - trackingArea = nil; - doubleBuffered = true; - - NSOpenGLPixelFormatAttribute pixelAttribs[] = { - NSOpenGLPFAColorSize, 24, - NSOpenGLPFAAlphaSize, 8, - NSOpenGLPFADepthSize, 16, - NSOpenGLPFADoubleBuffer, - NSOpenGLPFAAccelerated, - 0 - }; - - NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] - initWithAttributes:pixelAttribs]; - - if (pixelFormat) { - self = [super initWithFrame:frame pixelFormat:pixelFormat]; - [pixelFormat release]; - printf("Is doubleBuffered? TRUE\n"); - } else { - self = [super initWithFrame:frame]; - doubleBuffered = false; - printf("Is doubleBuffered? FALSE\n"); - } - - if (self) { - GLint swapInterval = 1; - [[self openGLContext] setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; - - [self reshape]; - } - - return self; -} - -- (void) reshape -{ - if (!puglview) { - /* NOTE: Apparently reshape gets called when the GC gets around to - deleting the view (?), so we must have reset puglview to NULL when - this comes around. - */ - return; - } - - [[self openGLContext] update]; - - reshape(self); -} - -- (void) drawRect:(NSRect)r -{ - puglEnterContext(puglview); - puglDisplay(puglview); - puglLeaveContext(puglview, true); - - // unused - return; (void)r; -} - -- (void) cursorUpdate:(NSEvent*)e -{ - cursorUpdate(self, e); -} - -- (void) updateTrackingAreas -{ - updateTrackingAreas(self); - [super updateTrackingAreas]; -} - -- (void) viewWillMoveToWindow:(NSWindow*)newWindow -{ - viewWillMoveToWindow(self, newWindow); - [super viewWillMoveToWindow:newWindow]; -} - -- (void) mouseMoved:(NSEvent*)event -{ - mouseMoved(self, event); -} - -- (void) mouseDragged:(NSEvent*)event -{ - mouseMoved(self, event); -} - -- (void) rightMouseDragged:(NSEvent*)event -{ - mouseMoved(self, event); -} - -- (void) otherMouseDragged:(NSEvent*)event -{ - mouseMoved(self, event); -} - -- (void) mouseDown:(NSEvent*)event -{ - mouseDown(self, event); -} - -- (void) rightMouseDown:(NSEvent*)event -{ - mouseDown(self, event); -} - -- (void) otherMouseDown:(NSEvent*)event -{ - mouseDown(self, event); -} - -- (void) mouseUp:(NSEvent*)event -{ - mouseUp(self, event); -} - -- (void) rightMouseUp:(NSEvent*)event -{ - mouseUp(self, event); -} - -- (void) otherMouseUp:(NSEvent*)event -{ - mouseUp(self, event); -} - -- (void) scrollWheel:(NSEvent*)event -{ - scrollWheel(self, event); -} - -- (void) keyDown:(NSEvent*)event -{ - keyDown(self, event); -} - -- (void) keyUp:(NSEvent*)event -{ - keyUp(self, event); -} - -- (void) flagsChanged:(NSEvent*)event -{ - flagsChanged(self, event); -} - -- (void) resizeWithOldSuperviewSize:(NSSize)oldSize -{ - PuglView *pv = self->puglview; - - if (pv->width <= 1 && pv->height <= 1) - { - /* NOTE: if the view size was not initialized yet, don't perform an - autoresize; it fixes manual resizing in Reaper. - */ - return; - } - - [super resizeWithOldSuperviewSize:oldSize]; -} - -@end -#endif - -#ifdef PUGL_CAIRO -@interface PuglCairoView : NSView -{ - PuglView* puglview; - cairo_t* cr; - NSTrackingArea* trackingArea; -} - -- (PuglView *) puglview; -- (void) setPuglview:(PuglView *)pv; -- (NSTrackingArea *) puglTrackingArea; -- (void) setPuglTrackingArea:(NSTrackingArea *)area; - -- (cairo_t *) cairoContext; - -- (BOOL) acceptsFirstMouse:(NSEvent*)e; -- (BOOL) acceptsFirstResponder; -- (BOOL) isFlipped; -- (BOOL) isOpaque; -- (BOOL) preservesContentInLiveResize; -- (id) initWithFrame:(NSRect)frame; -- (void) reshape; -- (void) drawRect:(NSRect)r; -- (void) cursorUpdate:(NSEvent*)e; -- (void) updateTrackingAreas; -- (void) viewWillMoveToWindow:(NSWindow*)newWindow; -- (void) mouseMoved:(NSEvent*)event; -- (void) mouseDragged:(NSEvent*)event; -- (void) rightMouseDragged:(NSEvent*)event; -- (void) otherMouseDragged:(NSEvent*)event; -- (void) mouseDown:(NSEvent*)event; -- (void) rightMouseDown:(NSEvent*)event; -- (void) otherMouseDown:(NSEvent*)event; -- (void) mouseUp:(NSEvent*)event; -- (void) rightMouseUp:(NSEvent*)event; -- (void) otherMouseUp:(NSEvent*)event; -- (void) scrollWheel:(NSEvent*)event; -- (void) keyDown:(NSEvent*)event; -- (void) keyUp:(NSEvent*)event; -- (void) flagsChanged:(NSEvent*)event; -- (void) resizeWithOldSuperviewSize:(NSSize)oldSize; -@end - -@implementation PuglCairoView -- (PuglView *) puglview { - return self->puglview; -} - -- (void) setPuglview:(PuglView *)pv { - self->puglview = pv; -} - -- (NSTrackingArea *) puglTrackingArea { - return self->trackingArea; -} - -- (void) setPuglTrackingArea:(NSTrackingArea *)area { - self->trackingArea = area; -} - -- (cairo_t *) cairoContext { - return cr; -} - -- (BOOL) acceptsFirstMouse:(NSEvent*)e -{ - return YES; - - // unused - (void)e; -} - -- (BOOL) acceptsFirstResponder -{ - return YES; -} - -- (BOOL) isFlipped -{ - return YES; -} - -- (BOOL) isOpaque -{ - return YES; -} - -- (BOOL) preservesContentInLiveResize -{ - return NO; -} - -- (id) initWithFrame:(NSRect)frame { - puglview = nil; - cr = NULL; - trackingArea = nil; - [super initWithFrame:frame]; - return self; -} - -- (void) reshape -{ - if (!puglview) { - /* NOTE: Apparently reshape gets called when the GC gets around to - deleting the view (?), so we must have reset puglview to NULL when - this comes around. - */ - return; - } - - reshape(self); -} - -- (void) drawRect:(NSRect)r { - CGContextRef ctx = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; - NSRect bounds = [self bounds]; - cairo_surface_t* surface; - cairo_t* cairo; - - surface = cairo_quartz_surface_create_for_cg_context(ctx, bounds.size.width, bounds.size.height); - if (surface) { - cairo = cairo_create(surface); - if (cairo) { - self->cr = cairo; - puglEnterContext(puglview); - puglDisplay(puglview); - puglLeaveContext(puglview, true); - self->cr = NULL; - cairo_destroy(cairo); - } - cairo_surface_destroy(surface); - } -} - -- (void) cursorUpdate:(NSEvent*)e -{ - cursorUpdate(self, e); -} - -- (void) updateTrackingAreas -{ - updateTrackingAreas(self); - [super updateTrackingAreas]; -} - -- (void) viewWillMoveToWindow:(NSWindow*)newWindow -{ - viewWillMoveToWindow(self, newWindow); - [super viewWillMoveToWindow:newWindow]; -} - -- (void) mouseMoved:(NSEvent*)event -{ - mouseMoved(self, event); -} - -- (void) mouseDragged:(NSEvent*)event -{ - mouseMoved(self, event); -} - -- (void) rightMouseDragged:(NSEvent*)event -{ - mouseMoved(self, event); -} - -- (void) otherMouseDragged:(NSEvent*)event -{ - mouseMoved(self, event); -} - -- (void) mouseDown:(NSEvent*)event -{ - mouseDown(self, event); -} - -- (void) rightMouseDown:(NSEvent*)event -{ - mouseDown(self, event); -} - -- (void) otherMouseDown:(NSEvent*)event -{ - mouseDown(self, event); -} - -- (void) mouseUp:(NSEvent*)event -{ - mouseUp(self, event); -} - -- (void) rightMouseUp:(NSEvent*)event -{ - mouseUp(self, event); -} - -- (void) otherMouseUp:(NSEvent*)event -{ - mouseUp(self, event); -} - -- (void) scrollWheel:(NSEvent*)event -{ - scrollWheel(self, event); -} - -- (void) keyDown:(NSEvent*)event -{ - keyDown(self, event); -} - -- (void) keyUp:(NSEvent*)event -{ - keyUp(self, event); -} - -- (void) flagsChanged:(NSEvent*)event -{ - flagsChanged(self, event); -} - -- (void) resizeWithOldSuperviewSize:(NSSize)oldSize -{ - PuglView *pv = self->puglview; - - if (pv->width <= 1 && pv->height <= 1) - { - /* NOTE: if the view size was not initialized yet, don't perform an - autoresize; it fixes manual resizing in Reaper. - */ - return; - } - - [super resizeWithOldSuperviewSize:oldSize]; -} - -@end -#endif - -struct PuglInternalsImpl { - union { - NSView* view; -#ifdef PUGL_OPENGL - PuglOpenGLView* glview; -#endif -#ifdef PUGL_CAIRO - PuglCairoView* cairoview; -#endif - }; - id window; -}; - -PuglInternals* -puglInitInternals() -{ - return (PuglInternals*)calloc(1, sizeof(PuglInternals)); -} - -void -puglEnterContext(PuglView* view) -{ -#ifdef PUGL_OPENGL - [[view->impl->glview openGLContext] makeCurrentContext]; -#endif -} - -void -puglLeaveContext(PuglView* view, bool flush) -{ - if (flush) { -#ifdef PUGL_OPENGL - if (view->impl->glview->doubleBuffered) { - [[view->impl->glview openGLContext] flushBuffer]; - } else { - glFlush(); - } - //[NSOpenGLContext clearCurrentContext]; -#endif - } -} - -int -puglCreateWindow(PuglView* view, const char* title) -{ - PuglInternals* impl = view->impl; - - [NSAutoreleasePool new]; - [NSApplication sharedApplication]; - -#ifdef PUGL_OPENGL - impl->glview = [PuglOpenGLView new]; -#endif -#ifdef PUGL_CAIRO - impl->cairoview = [PuglCairoView new]; -#endif - - if (!impl->view) { - return 1; - } - - [impl->view setPuglview:view]; - - if (view->user_resizable) { - [impl->view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; - } - - if (view->parent) { - [impl->view retain]; - NSView* pview = (NSView*)view->parent; - [pview addSubview:impl->view]; - return 0; - } - - id window = [[PuglWindow new]retain]; - - if (title) { - NSString* titleString = [[NSString alloc] - initWithBytes:title - length:strlen(title) - encoding:NSUTF8StringEncoding]; - - [window setTitle:titleString]; - } - - [window setPuglview:view]; - [window setContentView:impl->view]; - [window makeFirstResponder:impl->view]; - [window makeKeyAndOrderFront:window]; - - // wait for first puglShowWindow - [window setIsVisible:NO]; - - [NSApp activateIgnoringOtherApps:YES]; - [window center]; - - impl->window = window; - - return 0; -} - -void -puglShowWindow(PuglView* view) -{ - PuglInternals* impl = view->impl; - - if (impl->window) { - [impl->window setIsVisible:YES]; - } else { - [view->impl->view setHidden:NO]; - } -} - -void -puglHideWindow(PuglView* view) -{ - PuglInternals* impl = view->impl; - - if (impl->window) { - [impl->window setIsVisible:NO]; - } else { - [impl->view setHidden:YES]; - } -} - -void -puglDestroy(PuglView* view) -{ - [view->impl->view setPuglview:NULL]; - - if (view->impl->window) { - [view->impl->window close]; - [view->impl->view release]; - [view->impl->window release]; - } else { - [view->impl->view release]; - } - - free(view->impl); - free(view); -} - -PuglStatus -puglProcessEvents(PuglView* view) -{ - return PUGL_SUCCESS; - - // unused - (void)view; -} - -void -puglPostRedisplay(PuglView* view) -{ - view->redisplay = true; - [view->impl->view setNeedsDisplay:YES]; -} - -PuglNativeWindow -puglGetNativeWindow(PuglView* view) -{ - return (PuglNativeWindow)view->impl->view; -} - -void* -puglGetContext(PuglView* view) -{ -#ifdef PUGL_CAIRO - return [view->impl->cairoview cairoContext]; -#endif - return NULL; - - // may be unused - (void)view; -} - -int -puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect) -{ - // TODO - return 1; - - (void)view; - (void)min_width; - (void)min_height; - (void)aspect; -} diff --git a/dgl/src/pugl-custom/pugl_win.cpp b/dgl/src/pugl-custom/pugl_win.cpp deleted file mode 100644 index 90aa5975..00000000 --- a/dgl/src/pugl-custom/pugl_win.cpp +++ /dev/null @@ -1,565 +0,0 @@ -/* - Copyright 2012-2014 David Robillard - Copyright 2012-2019 Filipe Coelho - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/** - @file pugl_win.cpp Windows/WGL Pugl Implementation. -*/ - -#include -#include -#include - -#include -#include -#include -#ifdef PUGL_CAIRO -#include -#include -#endif -#ifdef PUGL_OPENGL -#include -#endif - -#include "pugl_internal.h" - -#ifndef WM_MOUSEWHEEL -# define WM_MOUSEWHEEL 0x020A -#endif -#ifndef WM_MOUSEHWHEEL -# define WM_MOUSEHWHEEL 0x020E -#endif -#ifndef WHEEL_DELTA -# define WHEEL_DELTA 120 -#endif -#ifndef GWLP_USERDATA -# define GWLP_USERDATA (-21) -#endif - -#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50) - -HINSTANCE hInstance = NULL; - -struct PuglInternalsImpl { - HWND hwnd; -#ifdef PUGL_OPENGL - HDC hdc; - HGLRC hglrc; -#endif -#ifdef PUGL_CAIRO - cairo_t* buffer_cr; - cairo_surface_t* buffer_surface; -#endif - HDC paintHdc; - WNDCLASS wc; -}; - -LRESULT CALLBACK -wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); - -#if 0 -extern "C" { -BOOL WINAPI -DllMain(HINSTANCE hInst, DWORD, LPVOID) -{ - hInstance = hInst; - return 1; -} -} // extern "C" -#endif - -PuglInternals* -puglInitInternals() -{ - return (PuglInternals*)calloc(1, sizeof(PuglInternals)); -} - -void -puglEnterContext(PuglView* view) -{ -#ifdef PUGL_OPENGL - wglMakeCurrent(view->impl->hdc, view->impl->hglrc); -#endif -} - -void -puglLeaveContext(PuglView* view, bool flush) -{ -#ifdef PUGL_OPENGL - if (flush) { - glFlush(); - SwapBuffers(view->impl->hdc); - } - wglMakeCurrent(NULL, NULL); -#endif -} - -int -puglCreateWindow(PuglView* view, const char* title) -{ - PuglInternals* impl = view->impl; - - if (!title) { - title = "Window"; - } - - // FIXME: This is nasty, and pugl should not have static anything. - // Should class be a parameter? Does this make sense on other platforms? - static int wc_count = 0; - char classNameBuf[256]; - std::srand((std::time(NULL))); -#ifdef __WINE__ - std::snprintf(classNameBuf, sizeof(classNameBuf), "%s_%d-%d", title, std::rand(), ++wc_count); -#else - _snprintf(classNameBuf, sizeof(classNameBuf), "%s_%d-%d", title, std::rand(), ++wc_count); -#endif - classNameBuf[sizeof(classNameBuf)-1] = '\0'; - - impl->wc.style = CS_OWNDC; - impl->wc.lpfnWndProc = wndProc; - impl->wc.cbClsExtra = 0; - impl->wc.cbWndExtra = 0; - impl->wc.hInstance = hInstance; - impl->wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION); - impl->wc.hCursor = LoadCursor(hInstance, IDC_ARROW); - impl->wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - impl->wc.lpszMenuName = NULL; - impl->wc.lpszClassName = strdup(classNameBuf); - - if (!RegisterClass(&impl->wc)) { - free((void*)impl->wc.lpszClassName); - free(impl); - return 1; - } - - int winFlags = WS_POPUPWINDOW | WS_CAPTION; - if (view->user_resizable) { - winFlags |= WS_SIZEBOX; - if (view->min_width > 0 && view->min_height > 0) { - // Adjust the minimum window size to accomodate requested view size - RECT mr = { 0, 0, view->min_width, view->min_height }; - AdjustWindowRectEx(&mr, view->parent ? WS_CHILD : winFlags, FALSE, WS_EX_TOPMOST); - view->min_width = mr.right - mr.left; - view->min_height = mr.bottom - mr.top; - } - } - - // Adjust the window size to accomodate requested view size - RECT wr = { 0, 0, view->width, view->height }; - AdjustWindowRectEx(&wr, view->parent ? WS_CHILD : winFlags, FALSE, WS_EX_TOPMOST); - - impl->hwnd = CreateWindowEx( - WS_EX_TOPMOST, - classNameBuf, title, - 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, NULL); - free((void*)impl->wc.lpszClassName); - free(impl); - return 1; - } - - SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view); - -#ifdef PUGL_OPENGL - impl->hdc = GetDC(impl->hwnd); - - PIXELFORMATDESCRIPTOR pfd; - ZeroMemory(&pfd, sizeof(pfd)); - pfd.nSize = sizeof(pfd); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 24; - pfd.cDepthBits = 16; - pfd.iLayerType = PFD_MAIN_PLANE; - - int format = ChoosePixelFormat(impl->hdc, &pfd); - SetPixelFormat(impl->hdc, format, &pfd); - - impl->hglrc = wglCreateContext(impl->hdc); - if (!impl->hglrc) { - ReleaseDC (impl->hwnd, impl->hdc); - DestroyWindow (impl->hwnd); - UnregisterClass (impl->wc.lpszClassName, NULL); - free((void*)impl->wc.lpszClassName); - free(impl); - return 1; - } -#endif - - return PUGL_SUCCESS; -} - -void -puglShowWindow(PuglView* view) -{ - ShowWindow(view->impl->hwnd, SW_SHOWNORMAL); -} - -void -puglHideWindow(PuglView* view) -{ - ShowWindow(view->impl->hwnd, SW_HIDE); -} - -void -puglDestroy(PuglView* view) -{ - if (!view) { - return; - } - - PuglInternals* const impl = view->impl; - -#ifdef PUGL_OPENGL - wglMakeCurrent(NULL, NULL); - wglDeleteContext(impl->hglrc); - ReleaseDC(impl->hwnd, impl->hdc); -#endif -#ifdef PUGL_CAIRO - cairo_destroy(impl->buffer_cr); - cairo_surface_destroy(impl->buffer_surface); -#endif - DestroyWindow(impl->hwnd); - UnregisterClass(impl->wc.lpszClassName, NULL); - free((void*)impl->wc.lpszClassName); - free(impl); - free(view); -} - -static void -puglReshape(PuglView* view, int width, int height) -{ - puglEnterContext(view); - - if (view->reshapeFunc) { - view->reshapeFunc(view, width, height); - } else { - puglDefaultReshape(width, height); - } - - view->width = width; - view->height = height; -} - -static void -puglDisplay(PuglView* view) -{ - PuglInternals* impl = view->impl; - bool success = true; - - puglEnterContext(view); - -#ifdef PUGL_CAIRO - cairo_t *wc = NULL; - cairo_t *bc = NULL; - cairo_surface_t *ws = NULL; - cairo_surface_t *bs = NULL; - - HDC hdc = impl->paintHdc; - bc = impl->buffer_cr; - bs = impl->buffer_surface; - int w = view->width; - int h = view->height; - int bw = bs ? cairo_image_surface_get_width(bs) : -1; - int bh = bs ? cairo_image_surface_get_height(bs) : -1; - ws = hdc ? cairo_win32_surface_create(hdc) : NULL; - wc = ws ? cairo_create(ws) : NULL; - if (wc && (!bc || bw != w || bh != h)) { - cairo_destroy(bc); - cairo_surface_destroy(bs); - bs = cairo_surface_create_similar_image(ws, CAIRO_FORMAT_ARGB32, w, h); - bc = bs ? cairo_create(bs) : NULL; - impl->buffer_cr = bc; - impl->buffer_surface = bs; - } - success = wc != NULL && bc != NULL; -#endif - - if (success) { - view->redisplay = false; - if (view->displayFunc) { - view->displayFunc(view); - } -#ifdef PUGL_CAIRO - cairo_set_source_surface(wc, bs, 0, 0); - cairo_paint(wc); -#endif - } - - puglLeaveContext(view, success); - -#ifdef PUGL_CAIRO - cairo_destroy(wc); - cairo_surface_destroy(ws); -#endif - - return; - (void)impl; -} - -static PuglKey -keySymToSpecial(int sym) -{ - switch (sym) { - case VK_F1: return PUGL_KEY_F1; - case VK_F2: return PUGL_KEY_F2; - case VK_F3: return PUGL_KEY_F3; - case VK_F4: return PUGL_KEY_F4; - case VK_F5: return PUGL_KEY_F5; - case VK_F6: return PUGL_KEY_F6; - case VK_F7: return PUGL_KEY_F7; - case VK_F8: return PUGL_KEY_F8; - case VK_F9: return PUGL_KEY_F9; - case VK_F10: return PUGL_KEY_F10; - case VK_F11: return PUGL_KEY_F11; - case VK_F12: return PUGL_KEY_F12; - case VK_LEFT: return PUGL_KEY_LEFT; - case VK_UP: return PUGL_KEY_UP; - case VK_RIGHT: return PUGL_KEY_RIGHT; - case VK_DOWN: return PUGL_KEY_DOWN; - case VK_PRIOR: return PUGL_KEY_PAGE_UP; - case VK_NEXT: return PUGL_KEY_PAGE_DOWN; - case VK_HOME: return PUGL_KEY_HOME; - case VK_END: return PUGL_KEY_END; - case VK_INSERT: return PUGL_KEY_INSERT; - case VK_SHIFT: return PUGL_KEY_SHIFT; - case VK_CONTROL: return PUGL_KEY_CTRL; - case VK_MENU: return PUGL_KEY_ALT; - case VK_LWIN: return PUGL_KEY_SUPER; - case VK_RWIN: return PUGL_KEY_SUPER; - } - return (PuglKey)0; -} - -static void -processMouseEvent(PuglView* view, int button, bool press, LPARAM lParam) -{ - view->event_timestamp_ms = GetMessageTime(); - if (press) { - SetCapture(view->impl->hwnd); - } else { - ReleaseCapture(); - } - - if (view->mouseFunc) { - view->mouseFunc(view, button, press, - GET_X_LPARAM(lParam), - GET_Y_LPARAM(lParam)); - } -} - -static void -setModifiers(PuglView* view) -{ - view->mods = 0; - view->mods |= (GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0; - view->mods |= (GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0; - view->mods |= (GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0; - view->mods |= (GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0; - view->mods |= (GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0; -} - -static LRESULT -handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) -{ - PAINTSTRUCT ps; - PuglKey key; - RECT rect; - MINMAXINFO* mmi; - - setModifiers(view); - switch (message) { - case WM_CREATE: - case WM_SHOWWINDOW: - case WM_SIZE: - GetClientRect(view->impl->hwnd, &rect); - puglReshape(view, rect.right, rect.bottom); - break; - case WM_GETMINMAXINFO: - mmi = (MINMAXINFO*)lParam; - mmi->ptMinTrackSize.x = view->min_width; - mmi->ptMinTrackSize.y = view->min_height; - break; - case WM_PAINT: - view->impl->paintHdc = BeginPaint(view->impl->hwnd, &ps); - puglDisplay(view); - view->impl->paintHdc = NULL; - EndPaint(view->impl->hwnd, &ps); - break; - case WM_MOUSEMOVE: - if (view->motionFunc) { - view->event_timestamp_ms = GetMessageTime(); - view->motionFunc(view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - } - break; - case WM_LBUTTONDOWN: - processMouseEvent(view, 1, true, lParam); - break; - case WM_MBUTTONDOWN: - processMouseEvent(view, 2, true, lParam); - break; - case WM_RBUTTONDOWN: - processMouseEvent(view, 3, true, lParam); - break; - case WM_LBUTTONUP: - processMouseEvent(view, 1, false, lParam); - break; - case WM_MBUTTONUP: - processMouseEvent(view, 2, false, lParam); - break; - case WM_RBUTTONUP: - processMouseEvent(view, 3, false, lParam); - break; - case WM_MOUSEWHEEL: - if (view->scrollFunc) { - view->event_timestamp_ms = GetMessageTime(); - POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; - ScreenToClient(view->impl->hwnd, &pt); - view->scrollFunc( - view, pt.x, pt.y, - 0.0f, GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA); - } - 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, pt.x, pt.y, - GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA, 0.0f); - } - break; - case WM_KEYDOWN: - if (view->ignoreKeyRepeat && (lParam & (1 << 30))) { - break; - } // else nobreak - case WM_KEYUP: - view->event_timestamp_ms = GetMessageTime(); - if ((key = keySymToSpecial(wParam))) { - if (view->specialFunc) { - view->specialFunc(view, message == WM_KEYDOWN, key); - } - } else if (view->keyboardFunc) { - 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: - if (view->closeFunc) { - view->closeFunc(view); - view->redisplay = false; - } - break; - default: - return DefWindowProc( - view->impl->hwnd, message, wParam, lParam); - } - - return 0; -} - -void -puglGrabFocus(PuglView* /*view*/) -{ - // TODO -} - -PuglStatus -puglProcessEvents(PuglView* view) -{ - MSG msg; - while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) { - handleMessage(view, msg.message, msg.wParam, msg.lParam); - } - - if (view->redisplay) { - InvalidateRect(view->impl->hwnd, NULL, FALSE); - } - - return PUGL_SUCCESS; -} - -LRESULT CALLBACK -wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - - switch (message) { - case WM_CREATE: - PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0); - return 0; - case WM_CLOSE: - PostMessage(hwnd, PUGL_LOCAL_CLOSE_MSG, wParam, lParam); - return 0; - case WM_DESTROY: - return 0; - default: - if (view && hwnd == view->impl->hwnd) { - return handleMessage(view, message, wParam, lParam); - } else { - return DefWindowProc(hwnd, message, wParam, lParam); - } - } -} - -void -puglPostRedisplay(PuglView* view) -{ - view->redisplay = true; -} - -PuglNativeWindow -puglGetNativeWindow(PuglView* view) -{ - return (PuglNativeWindow)view->impl->hwnd; -} - -void* -puglGetContext(PuglView* view) -{ -#ifdef PUGL_CAIRO - return view->impl->buffer_cr; -#endif - return NULL; - - // may be unused - (void)view; -} - -int -puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect) -{ - // TODO - return 1; - - (void)view; - (void)min_width; - (void)min_height; - (void)aspect; -} diff --git a/dgl/src/pugl-custom/pugl_x11.c b/dgl/src/pugl-custom/pugl_x11.c deleted file mode 100644 index bf897068..00000000 --- a/dgl/src/pugl-custom/pugl_x11.c +++ /dev/null @@ -1,739 +0,0 @@ -/* - Copyright 2012-2014 David Robillard - Copyright 2011-2012 Ben Loftis, Harrison Consoles - Copyright 2013,2015 Robin Gareus - Copyright 2012-2019 Filipe Coelho - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/** - @file pugl_x11.c X11 Pugl Implementation. -*/ - -#include -#include -#include - -#ifdef PUGL_CAIRO -#include -#include -#endif -#ifdef PUGL_OPENGL -#include -#include -#endif -#include -#include -#include -#include - -#include "pugl_internal.h" - -#ifndef DGL_FILE_BROWSER_DISABLED -#define SOFD_HAVE_X11 -#include "../sofd/libsofd.h" -#include "../sofd/libsofd.c" -#endif - -/* work around buggy re-parent & focus issues on some systems - * where no keyboard events are passed through even if the - * app has mouse-focus and all other events are working. - */ -//#define PUGL_GRAB_FOCUS - -/* show messages during initalization - */ -//#define PUGL_VERBOSE - -struct PuglInternalsImpl { - Display* display; - int screen; - Window win; -#ifdef PUGL_CAIRO - cairo_t* xlib_cr; - cairo_t* buffer_cr; - cairo_surface_t* xlib_surface; - cairo_surface_t* buffer_surface; -#endif -#ifdef PUGL_OPENGL - GLXContext ctx; - Bool doubleBuffered; -#endif -}; - -#ifdef PUGL_OPENGL -/** - 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_STENCIL_SIZE, 8, - GLX_ARB_multisample, 1, - None -}; - -/** - Attributes for double-buffered RGBA with at least - 4 bits per color and a 16 bit depth buffer. -*/ -static int attrListDbl[] = { - GLX_RGBA, - GLX_DOUBLEBUFFER, True, - GLX_RED_SIZE, 4, - GLX_GREEN_SIZE, 4, - GLX_BLUE_SIZE, 4, - GLX_DEPTH_SIZE, 16, - GLX_STENCIL_SIZE, 8, - GLX_ARB_multisample, 1, - None -}; - -/** - 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_STENCIL_SIZE, 8, - GLX_SAMPLE_BUFFERS, 1, - GLX_SAMPLES, 4, - None -}; -#endif - -PuglInternals* -puglInitInternals(void) -{ - return (PuglInternals*)calloc(1, sizeof(PuglInternals)); -} - -void -puglEnterContext(PuglView* view) -{ -#ifdef PUGL_OPENGL - glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); -#endif -} - -void -puglLeaveContext(PuglView* view, bool flush) -{ -#ifdef PUGL_OPENGL - if (flush) { - glFlush(); - if (view->impl->doubleBuffered) { - glXSwapBuffers(view->impl->display, view->impl->win); - } - } - glXMakeCurrent(view->impl->display, None, NULL); -#endif -} - -int -puglCreateWindow(PuglView* view, const char* title) -{ - PuglInternals* impl = view->impl; - if (!impl) { - return 1; - } - - view->impl = impl; - impl->display = XOpenDisplay(NULL); - if (!impl->display) { - free(impl); - return 1; - } - impl->screen = DefaultScreen(impl->display); - - XVisualInfo* vi = NULL; - -#ifdef PUGL_OPENGL - impl->doubleBuffered = True; - vi = glXChooseVisual(impl->display, impl->screen, attrListDblMS); - - if (!vi) { - vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); -#ifdef PUGL_VERBOSE - printf("puGL: multisampling (antialiasing) is not available\n"); -#endif - } - - if (!vi) { - vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); - impl->doubleBuffered = False; - } -#endif -#ifdef PUGL_CAIRO - XVisualInfo pat; - int n; - pat.screen = impl->screen; - vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n); -#endif - - if (!vi) { - XCloseDisplay(impl->display); - free(impl); - return 1; - } - -#ifdef PUGL_VERBOSE -#ifdef PUGL_OPENGL - int glxMajor, glxMinor; - glXQueryVersion(impl->display, &glxMajor, &glxMinor); - printf("puGL: GLX-Version : %d.%d\n", glxMajor, glxMinor); -#endif -#endif - -#ifdef PUGL_OPENGL - impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); - - if (!impl->ctx) { - XFree(vi); - XCloseDisplay(impl->display); - free(impl); - return 1; - } -#endif - - Window xParent = view->parent - ? (Window)view->parent - : RootWindow(impl->display, impl->screen); - - Colormap cmap = XCreateColormap( - impl->display, xParent, vi->visual, AllocNone); - - XSetWindowAttributes attr; - memset(&attr, 0, sizeof(XSetWindowAttributes)); - attr.border_pixel = BlackPixel(impl->display, impl->screen); - attr.colormap = cmap; - attr.event_mask = (ExposureMask | StructureNotifyMask | - EnterWindowMask | LeaveWindowMask | - KeyPressMask | KeyReleaseMask | - ButtonPressMask | ButtonReleaseMask | - PointerMotionMask | FocusChangeMask); - - impl->win = XCreateWindow( - impl->display, xParent, - 0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual, - CWBorderPixel | CWColormap | CWEventMask, &attr); - - if (!impl->win) { -#ifdef PUGL_OPENGL - glXDestroyContext(impl->display, impl->ctx); -#endif - XFree(vi); - XCloseDisplay(impl->display); - free(impl); - return 1; - } - -#ifdef PUGL_CAIRO - impl->xlib_surface = cairo_xlib_surface_create( - impl->display, impl->win, vi->visual, view->width, view->height); - if (impl->xlib_surface == NULL || cairo_surface_status(impl->xlib_surface) != CAIRO_STATUS_SUCCESS) { - printf("puGL: failed to create cairo surface\n"); - } - else { - impl->xlib_cr = cairo_create(impl->xlib_surface); - } - if (impl->xlib_cr == NULL || cairo_status(impl->xlib_cr) != CAIRO_STATUS_SUCCESS) { - cairo_destroy(impl->xlib_cr); - cairo_surface_destroy(impl->xlib_surface); - XDestroyWindow(impl->display, impl->win); - XFree(vi); - XCloseDisplay(impl->display); - free(impl); - printf("puGL: failed to create cairo context\n"); - return 1; - } -#endif - - if (view->width > 1 || view->height > 1) { - puglUpdateGeometryConstraints(view, view->min_width, view->min_height, view->min_width != view->width); - XResizeWindow(view->impl->display, view->impl->win, view->width, view->height); - } - - if (title) { - XStoreName(impl->display, impl->win, title); - Atom netWmName = XInternAtom(impl->display, "_NET_WM_NAME", False); - Atom utf8String = XInternAtom(impl->display, "UTF8_STRING", False); - XChangeProperty(impl->display, impl->win, netWmName, utf8String, 8, PropModeReplace, (unsigned char *)title, strlen(title)); - } - - if (view->transient_parent > 0) { - XSetTransientForHint(impl->display, impl->win, (Window)view->transient_parent); - } - - if (view->parent) { - XMapRaised(impl->display, impl->win); - } else { - Atom wmDelete = XInternAtom(impl->display, "WM_DELETE_WINDOW", True); - XSetWMProtocols(impl->display, impl->win, &wmDelete, 1); - } - -#ifdef PUGL_VERBOSE -#ifdef PUGL_OPENGL - if (glXIsDirect(impl->display, impl->ctx)) { - printf("puGL: DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n"); - } else { - printf("puGL: No DRI available\n"); - } -#endif -#endif - - XFree(vi); - return 0; -} - -void -puglDestroy(PuglView* view) -{ - if (!view) { - return; - } - - PuglInternals* const impl = view->impl; - -#ifndef DGL_FILE_BROWSER_DISABLED - x_fib_close(impl->display); -#endif - -#ifdef PUGL_OPENGL - glXDestroyContext(impl->display, impl->ctx); -#endif -#ifdef PUGL_CAIRO - cairo_destroy(impl->xlib_cr); - cairo_destroy(impl->buffer_cr); - cairo_surface_destroy(impl->xlib_surface); - cairo_surface_destroy(impl->buffer_surface); -#endif - XDestroyWindow(impl->display, impl->win); - XCloseDisplay(impl->display); - free(impl); - free(view); -} - -void -puglShowWindow(PuglView* view) -{ - XMapRaised(view->impl->display, view->impl->win); -} - -void -puglHideWindow(PuglView* view) -{ - XUnmapWindow(view->impl->display, view->impl->win); -} - -static void -puglReshape(PuglView* view, int width, int height) -{ - puglEnterContext(view); - - if (view->reshapeFunc) { - view->reshapeFunc(view, width, height); - } else { - puglDefaultReshape(width, height); - } - - puglLeaveContext(view, false); - - view->width = width; - view->height = height; -} - -static void -puglDisplay(PuglView* view) -{ - PuglInternals* impl = view->impl; - - puglEnterContext(view); - -#ifdef PUGL_CAIRO - cairo_t* bc = impl->buffer_cr; - cairo_surface_t* xs = impl->xlib_surface; - cairo_surface_t* bs = impl->buffer_surface; - int w = cairo_xlib_surface_get_width(xs); - int h = cairo_xlib_surface_get_height(xs); - - int bw = bs ? cairo_image_surface_get_width(bs) : -1; - int bh = bs ? cairo_image_surface_get_height(bs) : -1; - if (!bc || bw != w || bh != h) { - cairo_destroy(bc); - cairo_surface_destroy(bs); - bs = cairo_surface_create_similar_image(xs, CAIRO_FORMAT_ARGB32, w, h); - bc = bs ? cairo_create(bs) : NULL; - impl->buffer_cr = bc; - impl->buffer_surface = bs; - } - - if (!bc) { - puglLeaveContext(view, false); - return; - } -#endif - - view->redisplay = false; - if (view->displayFunc) { - view->displayFunc(view); - } - -#ifdef PUGL_CAIRO - cairo_t* xc = impl->xlib_cr; - cairo_set_source_surface(xc, impl->buffer_surface, 0, 0); - cairo_paint(xc); -#endif - - puglLeaveContext(view, true); - (void)impl; -} - -static void -puglResize(PuglView* view) -{ - int set_hints = 1; - view->pending_resize = false; - if (!view->resizeFunc) { return; } - /* ask the plugin about the new size */ - view->resizeFunc(view, &view->width, &view->height, &set_hints); - - if (set_hints) { - XSizeHints sizeHints; - memset(&sizeHints, 0, sizeof(sizeHints)); - sizeHints.flags = PMinSize|PMaxSize; - sizeHints.min_width = view->width; - sizeHints.min_height = view->height; - sizeHints.max_width = view->user_resizable ? 4096 : view->width; - sizeHints.max_height = view->user_resizable ? 4096 : view->height; - XSetWMNormalHints(view->impl->display, view->impl->win, &sizeHints); - } - XResizeWindow(view->impl->display, view->impl->win, view->width, view->height); - XFlush(view->impl->display); - -#ifdef PUGL_VERBOSE - printf("puGL: window resize (%dx%d)\n", view->width, view->height); -#endif - - /* and call Reshape in glX context */ - puglReshape(view, view->width, view->height); -} - -static PuglKey -keySymToSpecial(KeySym sym) -{ - switch (sym) { - case XK_F1: return PUGL_KEY_F1; - case XK_F2: return PUGL_KEY_F2; - case XK_F3: return PUGL_KEY_F3; - case XK_F4: return PUGL_KEY_F4; - case XK_F5: return PUGL_KEY_F5; - case XK_F6: return PUGL_KEY_F6; - case XK_F7: return PUGL_KEY_F7; - case XK_F8: return PUGL_KEY_F8; - case XK_F9: return PUGL_KEY_F9; - case XK_F10: return PUGL_KEY_F10; - case XK_F11: return PUGL_KEY_F11; - case XK_F12: return PUGL_KEY_F12; - case XK_Left: return PUGL_KEY_LEFT; - case XK_Up: return PUGL_KEY_UP; - case XK_Right: return PUGL_KEY_RIGHT; - case XK_Down: return PUGL_KEY_DOWN; - case XK_Page_Up: return PUGL_KEY_PAGE_UP; - case XK_Page_Down: return PUGL_KEY_PAGE_DOWN; - case XK_Home: return PUGL_KEY_HOME; - case XK_End: return PUGL_KEY_END; - case XK_Insert: return PUGL_KEY_INSERT; - case XK_Shift_L: return PUGL_KEY_SHIFT; - case XK_Shift_R: return PUGL_KEY_SHIFT; - case XK_Control_L: return PUGL_KEY_CTRL; - case XK_Control_R: return PUGL_KEY_CTRL; - case XK_Alt_L: return PUGL_KEY_ALT; - case XK_Alt_R: return PUGL_KEY_ALT; - case XK_Super_L: return PUGL_KEY_SUPER; - case XK_Super_R: return PUGL_KEY_SUPER; - } - return (PuglKey)0; -} - -static void -setModifiers(PuglView* view, unsigned xstate, unsigned xtime) -{ - view->event_timestamp_ms = xtime; - - view->mods = 0; - view->mods |= (xstate & ShiftMask) ? PUGL_MOD_SHIFT : 0; - view->mods |= (xstate & ControlMask) ? PUGL_MOD_CTRL : 0; - view->mods |= (xstate & Mod1Mask) ? PUGL_MOD_ALT : 0; - view->mods |= (xstate & Mod4Mask) ? PUGL_MOD_SUPER : 0; -} - -static void -dispatchKey(PuglView* view, XEvent* event, bool press) -{ - KeySym sym; - char str[5]; - PuglKey special; - const int n = XLookupString(&event->xkey, str, 4, &sym, NULL); - - if (sym == XK_Escape && view->closeFunc && !press && !view->parent) { - view->closeFunc(view); - view->redisplay = false; - return; - } - if (n == 0 && sym == 0) { - goto send_event; - return; - } - if (n > 1) { - fprintf(stderr, "warning: Unsupported multi-byte key %X\n", (int)sym); - goto send_event; - return; - } - - special = keySymToSpecial(sym); - if (special && view->specialFunc) { - if (view->specialFunc(view, press, special) == 0) { - return; - } - } else if (!special && view->keyboardFunc) { - if (view->keyboardFunc(view, press, str[0]) == 0) { - return; - } - } - -send_event: - if (view->parent != 0) { - event->xkey.time = 0; // purposefully set an invalid time, used for feedback detection on bad hosts - event->xany.window = view->parent; - XSendEvent(view->impl->display, view->parent, False, NoEventMask, event); - } -} - -PuglStatus -puglProcessEvents(PuglView* view) -{ - int conf_width = -1; - int conf_height = -1; - - XEvent event; - while (XPending(view->impl->display) > 0) { - XNextEvent(view->impl->display, &event); - -#ifndef DGL_FILE_BROWSER_DISABLED - if (x_fib_handle_events(view->impl->display, &event)) { - const int status = x_fib_status(); - - if (status > 0) { - char* const filename = x_fib_filename(); - x_fib_close(view->impl->display); - if (view->fileSelectedFunc) { - view->fileSelectedFunc(view, filename); - } - free(filename); - } else if (status < 0) { - x_fib_close(view->impl->display); - if (view->fileSelectedFunc) { - view->fileSelectedFunc(view, NULL); - } - } - break; - } -#endif - - if (event.xany.window != view->impl->win && - (view->parent == 0 || event.xany.window != (Window)view->parent)) { - continue; - } - if ((event.type == KeyPress || event.type == KeyRelease) && event.xkey.time == 0) { - continue; - } - - switch (event.type) { - case UnmapNotify: - if (view->motionFunc) { - view->motionFunc(view, -1, -1); - } - break; - case MapNotify: - puglReshape(view, view->width, view->height); - break; - case ConfigureNotify: - if ((event.xconfigure.width != view->width) || - (event.xconfigure.height != view->height)) { - conf_width = event.xconfigure.width; - conf_height = event.xconfigure.height; - } - break; - case Expose: - if (event.xexpose.count != 0) { - break; - } - view->redisplay = true; - 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 == event.xkey.time && - next.xkey.keycode == event.xkey.keycode) { - XNextEvent(view->impl->display, &event); - repeated = true; - } - } - 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 (conf_width != -1) { -#ifdef PUGL_CAIRO - // Resize surfaces/contexts before dispatching - view->redisplay = true; - cairo_xlib_surface_set_size(view->impl->xlib_surface, - conf_width, conf_height); -#endif - puglReshape(view, conf_width, conf_height); - } - - if (view->pending_resize) { - puglResize(view); - } - - if (view->redisplay) { - puglDisplay(view); - } - - return PUGL_SUCCESS; -} - -void -puglPostRedisplay(PuglView* view) -{ - view->redisplay = true; -} - -void -puglPostResize(PuglView* view) -{ - view->pending_resize = true; -} - -PuglNativeWindow -puglGetNativeWindow(PuglView* view) -{ - return view->impl->win; -} - -void* -puglGetContext(PuglView* view) -{ -#ifdef PUGL_CAIRO - return view->impl->buffer_cr; -#endif - return NULL; - - // may be unused - (void)view; -} - -int -puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect) -{ - XSizeHints sizeHints; - memset(&sizeHints, 0, sizeof(sizeHints)); - sizeHints.flags = PMinSize|PMaxSize; - sizeHints.min_width = min_width; - sizeHints.min_height = min_height; - sizeHints.max_width = view->user_resizable ? 4096 : min_width; - sizeHints.max_height = view->user_resizable ? 4096 : min_height; - if (aspect) { - sizeHints.flags |= PAspect; - sizeHints.min_aspect.x = min_width; - sizeHints.min_aspect.y = min_height; - sizeHints.max_aspect.x = min_width; - sizeHints.max_aspect.y = min_height; - } - XSetWMNormalHints(view->impl->display, view->impl->win, &sizeHints); - return 0; -}