Browse Source

Update built-in DPF

Signed-off-by: falkTX <falktx@falktx.com>
main
falkTX 2 weeks ago
parent
commit
1d8dcb5aab
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
59 changed files with 3319 additions and 2605 deletions
  1. +1
    -1
      data/update-dpf
  2. +18
    -1
      source/modules/dgl/Application.hpp
  3. +4
    -0
      source/modules/dgl/Base.hpp
  4. +12
    -1
      source/modules/dgl/Color.hpp
  5. +9
    -9
      source/modules/dgl/Geometry.hpp
  6. +10
    -6
      source/modules/dgl/Image.hpp
  7. +2
    -0
      source/modules/dgl/Makefile
  8. +6
    -0
      source/modules/dgl/OpenGL-include.hpp
  9. +140
    -17
      source/modules/dgl/OpenGL.hpp
  10. +8
    -3
      source/modules/dgl/src/Application.cpp
  11. +5
    -13
      source/modules/dgl/src/ApplicationPrivateData.cpp
  12. +8
    -5
      source/modules/dgl/src/ApplicationPrivateData.hpp
  13. +9
    -1
      source/modules/dgl/src/Color.cpp
  14. +1
    -8
      source/modules/dgl/src/EventHandlers.cpp
  15. +2
    -0
      source/modules/dgl/src/NanoVG.cpp
  16. +35
    -562
      source/modules/dgl/src/OpenGL.cpp
  17. +570
    -0
      source/modules/dgl/src/OpenGL2.cpp
  18. +1025
    -0
      source/modules/dgl/src/OpenGL3.cpp
  19. +36
    -31
      source/modules/dgl/src/Window.cpp
  20. +29
    -15
      source/modules/dgl/src/WindowPrivateData.cpp
  21. +5
    -1
      source/modules/dgl/src/WindowPrivateData.hpp
  22. +24
    -20
      source/modules/dgl/src/nanovg/nanovg_gl.h
  23. +2
    -17
      source/modules/dgl/src/pugl-upstream/include/pugl/attributes.h
  24. +6
    -10
      source/modules/dgl/src/pugl-upstream/include/pugl/gl.h
  25. +279
    -786
      source/modules/dgl/src/pugl-upstream/include/pugl/pugl.h
  26. +3
    -4
      source/modules/dgl/src/pugl-upstream/include/pugl/stub.h
  27. +98
    -53
      source/modules/dgl/src/pugl-upstream/src/common.c
  28. +92
    -7
      source/modules/dgl/src/pugl-upstream/src/internal.c
  29. +31
    -6
      source/modules/dgl/src/pugl-upstream/src/internal.h
  30. +1
    -1
      source/modules/dgl/src/pugl-upstream/src/mac.h
  31. +142
    -225
      source/modules/dgl/src/pugl-upstream/src/mac.m
  32. +1
    -1
      source/modules/dgl/src/pugl-upstream/src/mac_cairo.m
  33. +1
    -1
      source/modules/dgl/src/pugl-upstream/src/mac_gl.m
  34. +1
    -1
      source/modules/dgl/src/pugl-upstream/src/mac_stub.m
  35. +3
    -3
      source/modules/dgl/src/pugl-upstream/src/mac_vulkan.m
  36. +22
    -7
      source/modules/dgl/src/pugl-upstream/src/platform.h
  37. +2
    -1
      source/modules/dgl/src/pugl-upstream/src/stub.h
  38. +18
    -24
      source/modules/dgl/src/pugl-upstream/src/types.h
  39. +247
    -296
      source/modules/dgl/src/pugl-upstream/src/win.c
  40. +6
    -15
      source/modules/dgl/src/pugl-upstream/src/win.h
  41. +1
    -1
      source/modules/dgl/src/pugl-upstream/src/win_cairo.c
  42. +37
    -25
      source/modules/dgl/src/pugl-upstream/src/win_gl.c
  43. +1
    -1
      source/modules/dgl/src/pugl-upstream/src/win_stub.c
  44. +1
    -1
      source/modules/dgl/src/pugl-upstream/src/win_vulkan.c
  45. +151
    -212
      source/modules/dgl/src/pugl-upstream/src/x11.c
  46. +3
    -6
      source/modules/dgl/src/pugl-upstream/src/x11.h
  47. +9
    -9
      source/modules/dgl/src/pugl-upstream/src/x11_cairo.c
  48. +4
    -6
      source/modules/dgl/src/pugl-upstream/src/x11_gl.c
  49. +2
    -2
      source/modules/dgl/src/pugl-upstream/src/x11_stub.c
  50. +2
    -2
      source/modules/dgl/src/pugl-upstream/src/x11_vulkan.c
  51. +96
    -100
      source/modules/dgl/src/pugl.cpp
  52. +3
    -3
      source/modules/dgl/src/pugl.hpp
  53. +3
    -4
      source/modules/distrho/DistrhoPluginMain.cpp
  54. +8
    -6
      source/modules/distrho/DistrhoUI.hpp
  55. +5
    -0
      source/modules/distrho/extra/ScopedPointer.hpp
  56. +51
    -56
      source/modules/distrho/extra/String.hpp
  57. +6
    -5
      source/modules/distrho/src/DistrhoUIInternal.hpp
  58. +14
    -11
      source/modules/distrho/src/DistrhoUIPrivateData.hpp
  59. +8
    -3
      source/modules/distrho/src/DistrhoUtils.cpp

+ 1
- 1
data/update-dpf View File

@@ -53,7 +53,7 @@ rm ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/src/.clang-tidy

rm ${CARLA_DIR}/source/modules/distrho/DistrhoInfo.hpp
rm ${CARLA_DIR}/source/modules/distrho/DistrhoUI_win32.cpp
rm ${CARLA_DIR}/source/modules/distrho/src/DistrhoPlugin{AU,CLAP,Export,JACK,LADSPA+DSSI,LV2,LV2export,Stub,VST2,VST3}.cpp
rm ${CARLA_DIR}/source/modules/distrho/src/DistrhoPlugin{AU,CLAP,Export,JACK,LADSPA+DSSI,LV2,LV2export,MAPI,Stub,VST2,VST3}.cpp
rm ${CARLA_DIR}/source/modules/distrho/src/DistrhoPluginVST.hpp
rm ${CARLA_DIR}/source/modules/distrho/src/DistrhoUI{DSSI,LV2,Stub,VST3}.cpp



+ 18
- 1
source/modules/dgl/Application.hpp View File

@@ -83,10 +83,21 @@ BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_off)
class DISTRHO_API Application
{
public:
/**
Type of application to setup, either "classic" or "modern".

What this means depends on the OS.
*/
enum Type {
kTypeAuto,
kTypeClassic,
kTypeModern,
};

/**
Constructor for standalone or plugin application.
*/
Application(bool isStandalone = true);
Application(bool isStandalone = true, Type type = kTypeAuto);

/**
Constructor for a standalone application.
@@ -141,6 +152,12 @@ public:
*/
double getTime() const;

/**
Return the application type, either kTypeClassic or kTypeModern.
This function never return kTypeAuto.
*/
Type getType() const noexcept;

/**
Add a callback function to be triggered on every idle cycle.
You can add more than one, and remove them at anytime with removeIdleCallback().


+ 4
- 0
source/modules/dgl/Base.hpp View File

@@ -49,6 +49,10 @@
# error DGL_FILE_BROWSER_DISABLED has been replaced by DGL_USE_FILE_BROWSER (opt-in vs opt-out)
#endif

#ifndef DGL_ALLOW_DEPRECATED_METHODS
# define DGL_ALLOW_DEPRECATED_METHODS 1
#endif

// --------------------------------------------------------------------------------------------------------------------
// Define namespace



+ 12
- 1
source/modules/dgl/Color.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
*
* 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
@@ -115,6 +115,17 @@ struct Color {
*/
static Color fromHTML(const char* rgb, float alpha = 1.0f) noexcept;

/**
Create a color from a RGB unsigned integer.
Basically doing:
```
uint8_t red = (color >> 24) & 0xff;
uint8_t green = (color >> 16) & 0xff;
uint8_t blue = (color >> 8) & 0xff;
```
*/
static Color fromRGB(uint color, float alpha = 1.0f) noexcept;

/**
Linearly interpolate this color against another.
*/


+ 9
- 9
source/modules/dgl/Geometry.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
*
* 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
@@ -360,25 +360,23 @@ public:
*/
bool isNotNull() const noexcept;

#ifndef DPF_TEST_POINT_CPP
/**
Draw this line using the provided graphics context, optionally specifying line width.
*/
void draw(const GraphicsContext& context, T width = 1);
#endif

Line<T>& operator=(const Line<T>& line) noexcept;
bool operator==(const Line<T>& line) const noexcept;
bool operator!=(const Line<T>& line) const noexcept;

#ifndef DPF_TEST_POINT_CPP
#ifdef DGL_ALLOW_DEPRECATED_METHODS
/**
Draw this line using the current OpenGL state.@n
DEPRECATED Please use draw(const GraphicsContext&) instead.
*/
DISTRHO_DEPRECATED_BY("draw(const GraphicsContext&)")
void draw();
#endif
#endif

private:
Point<T> posStart, posEnd;
@@ -489,7 +487,7 @@ public:
bool operator==(const Circle<T>& cir) const noexcept;
bool operator!=(const Circle<T>& cir) const noexcept;

#ifndef DPF_TEST_POINT_CPP
#ifdef DGL_ALLOW_DEPRECATED_METHODS
/**
Draw this circle using the current OpenGL state.@n
DEPRECATED Please use draw(const GraphicsContext&) instead.
@@ -503,7 +501,7 @@ public:
*/
DISTRHO_DEPRECATED_BY("drawOutline(const GraphicsContext&)")
void drawOutline();
#endif
#endif

private:
Point<T> fPos;
@@ -582,7 +580,7 @@ public:
bool operator==(const Triangle<T>& tri) const noexcept;
bool operator!=(const Triangle<T>& tri) const noexcept;

#ifndef DPF_TEST_POINT_CPP
#ifdef DGL_ALLOW_DEPRECATED_METHODS
/**
Draw this triangle using the current OpenGL state.@n
DEPRECATED Please use draw(const GraphicsContext&) instead.
@@ -596,7 +594,7 @@ public:
*/
DISTRHO_DEPRECATED_BY("drawOutline(const GraphicsContext&)")
void drawOutline();
#endif
#endif

private:
Point<T> pos1, pos2, pos3;
@@ -813,6 +811,7 @@ public:
bool operator==(const Rectangle<T>& size) const noexcept;
bool operator!=(const Rectangle<T>& size) const noexcept;

#ifdef DGL_ALLOW_DEPRECATED_METHODS
/**
Draw this rectangle using the current OpenGL state.@n
DEPRECATED Please use draw(const GraphicsContext&) instead.
@@ -826,6 +825,7 @@ public:
*/
DISTRHO_DEPRECATED_BY("drawOutline(const GraphicsContext&)")
void drawOutline();
#endif

private:
Point<T> pos;


+ 10
- 6
source/modules/dgl/Image.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
*
* 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
@@ -17,17 +17,21 @@
#ifndef DGL_IMAGE_HPP_INCLUDED
#define DGL_IMAGE_HPP_INCLUDED

#ifdef DGL_CAIRO
#include "Cairo.hpp"
#if defined(DGL_CAIRO)
# include "Cairo.hpp"
#elif defined(DGL_OPENGL)
# include "OpenGL.hpp"
#elif defined(DGL_VULKAN)
# include "Vulkan.hpp"
#else
#include "OpenGL.hpp"
# include "Base.hpp"
#endif

START_NAMESPACE_DGL

#ifdef DGL_CAIRO
#if defined(DGL_CAIRO)
typedef CairoImage Image;
#else
#elif defined(DGL_OPENGL)
typedef OpenGLImage Image;
#endif



+ 2
- 0
source/modules/dgl/Makefile View File

@@ -32,6 +32,7 @@ OBJS = \
$(OBJDIR)/ImageBaseWidgets.cpp.o \
$(OBJDIR)/NanoVG.cpp.o \
$(OBJDIR)/OpenGL.cpp.o \
$(OBJDIR)/OpenGL2.cpp.o \
$(OBJDIR)/SubWidget.cpp.o \
$(OBJDIR)/SubWidgetPrivateData.cpp.o \
$(OBJDIR)/TopLevelWidget.cpp.o \
@@ -51,6 +52,7 @@ OBJS_wine = \
$(OBJDIR)/ImageBase.cpp-wine.o \
$(OBJDIR)/ImageBaseWidgets.cpp-wine.o \
$(OBJDIR)/OpenGL.cpp-wine.o \
$(OBJDIR)/OpenGL2.cpp-wine.o \
$(OBJDIR)/SubWidget.cpp-wine.o \
$(OBJDIR)/SubWidgetPrivateData.cpp-wine.o \
$(OBJDIR)/TopLevelWidget.cpp-wine.o \


+ 6
- 0
source/modules/dgl/OpenGL-include.hpp View File

@@ -53,6 +53,12 @@

#ifdef DISTRHO_OS_MAC
# ifdef DGL_USE_OPENGL3
// NOTE GLES with macOS is not supported
# ifdef DGL_USE_GLES
# undef DGL_USE_GLES
# undef DGL_USE_GLES2
# undef DGL_USE_GLES3
# endif
# include <OpenGL/gl3.h>
# include <OpenGL/gl3ext.h>
# else


+ 140
- 17
source/modules/dgl/OpenGL.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
*
* 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
@@ -24,34 +24,131 @@

START_NAMESPACE_DGL

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

#ifdef DGL_USE_OPENGL3
/**
OpenGL Graphics context.
OpenGL3 Graphics context.

This provides access to the program, shaders and uniforms used by the underlying DPF implementation.
*/
struct OpenGLGraphicsContext : GraphicsContext
struct OpenGL3GraphicsContext : GraphicsContext
{
#ifdef DGL_USE_OPENGL3
#endif
/**
The OpenGL3 program used for this context.
It is activated automatically before any widget onDisplay() is called.
If changing the current OpenGL program make sure to revert back to this one at the end of your pipeline.

@code
// use custom program
glUseProgram(context.program);

// custom stuff here

// revert back
glUseProgram(context.program);
@endcode
*/
GLuint program;

/**
A vec4 uniform used to set the next drawing color.

@code
const GLfloat color[4] = { red, green, blue, alpha };
glUniform4fv(context.color, 1, color);
@endcode
*/
GLuint color;

/**
A vertex shader attribute directly linked to gl_Position.
Use this to set the bounds for drawing, normalized as -1.0 to +1.0.
The @a width and @a height provide the total window size for convenience.

@code
const GLfloat triangle[] = { x1, y1, x2, y2, x3, y3 };
glEnableVertexAttribArray(context.bounds);
glVertexAttribPointer(context.bounds, 2, GL_FLOAT, GL_FALSE, 0, triangle);
@endcode
*/
GLuint bounds;

/**
A vertex shader attribute directly linked to GL_TEXTURE0 map.
// TODO find the correct wording, map??.

@code
const GLfloat map[] = { 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f, 0.f };
glEnableVertexAttribArray(context.textureMap);
glVertexAttribPointer(context.textureMap, 2, GL_FLOAT, GL_FALSE, 0, map);
@endcode
*/
GLuint textureMap;

/**
A boolean uniform used to indicate if next drawing should @a texture or @a color.
Set to 0 for color mode, 1 for texture.
Default mode is color, if changed make sure to revert to color mode at the end of your pipeline.

@code
// setup for drawing based on texture
glUniform1i(context.usingTexture, 1);

// bind texture
glBindTexture(GL_TEXTURE_2D, myTextureId);
// etc..

// glDrawElements or similar

// unbind texture
glBindTexture(GL_TEXTURE_2D, 0);
// etc..

// revert to color mode
glUniform1i(context.usingTexture, 0);
@endcode
*/
GLuint usingTexture;

/**
Set of buffers created with glGenBuffers.
Used internally in DPF to draw generic shapes, can be reused in custom code.
Unbound by default, make sure to leave them unbound at the end of your pipeline.
*/
GLuint buffers[2];

/**
Total width of the window used for this context.
*/
uint width;

/**
Total height of the window used for this context.
*/
uint height;
};
#endif

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

static inline
ImageFormat asDISTRHOImageFormat(const GLenum format)
{
switch (format)
{
#ifdef DGL_USE_OPENGL3
#if defined(DGL_USE_OPENGL3) && !defined(DGL_USE_GLES2)
case GL_RED:
#else
#else
case GL_LUMINANCE:
#endif
#endif
return kImageFormatGrayscale;
#ifndef DGL_USE_GLES
case GL_BGR:
return kImageFormatBGR;
case GL_BGRA:
return kImageFormatBGRA;
#endif
case GL_RGB:
return kImageFormatRGB;
case GL_RGBA:
@@ -69,25 +166,33 @@ GLenum asOpenGLImageFormat(const ImageFormat format)
case kImageFormatNull:
break;
case kImageFormatGrayscale:
#ifdef DGL_USE_OPENGL3
#if defined(DGL_USE_OPENGL3) && !defined(DGL_USE_GLES2)
return GL_RED;
#else
#else
return GL_LUMINANCE;
#endif
#endif
case kImageFormatBGR:
#ifndef DGL_USE_GLES
return GL_BGR;
#else
return 0;
#endif
case kImageFormatBGRA:
#ifndef DGL_USE_GLES
return GL_BGRA;
#else
return 0;
#endif
case kImageFormatRGB:
return GL_RGB;
case kImageFormatRGBA:
return GL_RGBA;
}

return 0x0;
return 0;
}

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

/**
OpenGL Image class.
@@ -144,6 +249,18 @@ public:
*/
void drawAt(const GraphicsContext& context, const Point<int>& pos) override;

#ifdef DGL_USE_GLES
/**
Get the image format.
*/
ImageFormat getFormat() const noexcept;

/**
Get the raw image data.
*/
const char* getRawData() const noexcept;
#endif

/**
TODO document this.
*/
@@ -157,6 +274,7 @@ public:
inline void drawAt(const GraphicsContext& context, int x, int y)
{ drawAt(context, Point<int>(x, y)); }

#ifdef DGL_ALLOW_DEPRECATED_METHODS
/**
Constructor using raw image data, specifying an OpenGL image format.
@note @a rawData must remain valid for the lifetime of this Image.
@@ -200,14 +318,19 @@ public:
*/
DISTRHO_DEPRECATED
GLenum getType() const noexcept { return GL_UNSIGNED_BYTE; }
#endif // DGL_ALLOW_DEPRECATED_METHODS

private:
bool setupCalled;
bool textureInit;
GLuint textureId;
#ifdef DGL_USE_GLES
mutable char* convertedData;
mutable const char* rawDataLast;
#endif
};

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

typedef ImageBaseAboutWindow<OpenGLImage> OpenGLImageAboutWindow;
typedef ImageBaseButton<OpenGLImage> OpenGLImageButton;
@@ -215,7 +338,7 @@ typedef ImageBaseKnob<OpenGLImage> OpenGLImageKnob;
typedef ImageBaseSlider<OpenGLImage> OpenGLImageSlider;
typedef ImageBaseSwitch<OpenGLImage> OpenGLImageSwitch;

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

END_NAMESPACE_DGL



+ 8
- 3
source/modules/dgl/src/Application.cpp View File

@@ -98,8 +98,8 @@ static void app_idle(void* const app)
}
#endif

Application::Application(const bool isStandalone)
: pData(new PrivateData(isStandalone))
Application::Application(const bool isStandalone, const Type type)
: pData(new PrivateData(isStandalone, type))
{
// build config sentinels
#ifdef DPF_DEBUG
@@ -126,7 +126,7 @@ Application::Application(const bool isStandalone)
}

Application::Application(int argc, char* argv[])
: pData(new PrivateData(true))
: pData(new PrivateData(true, kTypeAuto))
{
#if defined(HAVE_X11) && defined(DISTRHO_OS_LINUX) && defined(DGL_USE_WEB_VIEW)
if (argc >= 2 && std::strcmp(argv[1], "dpf-ld-linux-webview") == 0)
@@ -213,6 +213,11 @@ double Application::getTime() const
return pData->getTime();
}

Application::Type Application::getType() const noexcept
{
return pData->isModern ? kTypeModern : kTypeClassic;
}

void Application::addIdleCallback(IdleCallback* const callback)
{
DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,)


+ 5
- 13
source/modules/dgl/src/ApplicationPrivateData.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
*
* 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
@@ -53,13 +53,14 @@ const char* Application::getClassName() const noexcept

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

Application::PrivateData::PrivateData(const bool standalone)
Application::PrivateData::PrivateData(const bool standalone, const Type type)
: world(puglNewWorld(standalone ? PUGL_PROGRAM : PUGL_MODULE,
standalone ? PUGL_WORLD_THREADS : 0x0)),
(standalone ? PUGL_WORLD_THREADS : 0))),
isModern(false),
isStandalone(standalone),
isStarting(true),
isQuitting(false),
isQuittingInNextCycle(false),
isStarting(true),
needsRepaint(false),
visibleWindows(0),
mainThreadHandle(getCurrentThreadHandle()),
@@ -68,16 +69,11 @@ Application::PrivateData::PrivateData(const bool standalone)
{
DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,);

#ifdef DGL_USING_SDL
SDL_Init(SDL_INIT_EVENTS|SDL_INIT_TIMER|SDL_INIT_VIDEO);
#else
puglSetWorldHandle(world, this);
#ifdef __EMSCRIPTEN__
puglSetWorldString(world, PUGL_CLASS_NAME, "canvas");
#else
puglSetWorldString(world, PUGL_CLASS_NAME, DISTRHO_MACRO_AS_STRING(DGL_NAMESPACE));
#endif
#endif
}

Application::PrivateData::~PrivateData()
@@ -88,12 +84,8 @@ Application::PrivateData::~PrivateData()
windows.clear();
idleCallbacks.clear();

#ifdef DGL_USING_SDL
SDL_Quit();
#else
if (world != nullptr)
puglFreeWorld(world);
#endif
}

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


+ 8
- 5
source/modules/dgl/src/ApplicationPrivateData.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
*
* 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
@@ -51,18 +51,21 @@ struct Application::PrivateData {
/** Pugl world instance. */
PuglWorld* const world;

/** Whether the applicating uses modern backend, otherwise classic. */
const bool isModern;

/** Whether the application is running as standalone, otherwise it is part of a plugin. */
const bool isStandalone;

/** Whether the applicating is starting up, that is, no windows have been made visible yet. Defaults to true. */
bool isStarting;

/** Whether the applicating is about to quit, or already stopped. Defaults to false. */
bool isQuitting;

/** Helper for safely close everything from main thread. */
bool isQuittingInNextCycle;

/** Whether the applicating is starting up, that is, no windows have been made visible yet. Defaults to true. */
bool isStarting;

/** When true force all windows to be repainted on next idle. */
bool needsRepaint;

@@ -80,7 +83,7 @@ struct Application::PrivateData {
std::list<DGL_NAMESPACE::IdleCallback*> idleCallbacks;

/** Constructor and destructor */
explicit PrivateData(bool standalone);
explicit PrivateData(bool standalone, Type type);
~PrivateData();

/** Flag one window as shown, which increments @a visibleWindows.


+ 9
- 1
source/modules/dgl/src/Color.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
*
* 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
@@ -242,6 +242,14 @@ Color Color::fromHTML(const char* rgb, const float alpha) noexcept
return Color(r, g, b, alpha);
}

Color Color::fromRGB(const uint color, const float alpha) noexcept
{
return Color(static_cast<int>(color >> 24) & 0xff,
static_cast<int>(color >> 16) & 0xff,
static_cast<int>(color >> 8) & 0xff,
alpha);
}

void Color::interpolate(const Color& other, float u) noexcept
{
fixRange(u);


+ 1
- 8
source/modules/dgl/src/EventHandlers.cpp View File

@@ -108,13 +108,6 @@ struct ButtonEventHandler::PrivateData {
if (! enabledInput)
return false;

// keep pressed
if (button != -1)
{
lastMotionPos = ev.pos;
return true;
}

bool ret = false;

if (widget->contains(ev.pos))
@@ -143,7 +136,7 @@ struct ButtonEventHandler::PrivateData {
}

lastMotionPos = ev.pos;
return ret;
return ret || button != -1;
}

void setActive(const bool active2, const bool sendCallback) noexcept


+ 2
- 0
source/modules/dgl/src/NanoVG.cpp View File

@@ -89,6 +89,8 @@ DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding)
//#define STB_IMAGE_STATIC
#if defined(DGL_USE_GLES2)
# define NANOVG_GLES2_IMPLEMENTATION
#elif defined(DGL_USE_GLES3)
# define NANOVG_GLES3_IMPLEMENTATION
#elif defined(DGL_USE_OPENGL3)
# define NANOVG_GL3_IMPLEMENTATION
#else


+ 35
- 562
source/modules/dgl/src/OpenGL.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
*
* 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
@@ -20,7 +20,6 @@
#endif

#include "../OpenGL.hpp"
#include "../Color.hpp"
#include "../ImageWidgets.hpp"

#include "SubWidgetPrivateData.hpp"
@@ -28,416 +27,20 @@
#include "WidgetPrivateData.hpp"
#include "WindowPrivateData.hpp"

// templated classes
#include "ImageBaseWidgets.cpp"

START_NAMESPACE_DGL

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

#ifdef DGL_USE_OPENGL3
static void notImplemented(const char* const name)
{
d_stderr2("OpenGL3 function not implemented: %s", name);
}
#else
# define DGL_USE_COMPAT_OPENGL
#endif

// -----------------------------------------------------------------------
// Color

void Color::setFor(const GraphicsContext&, const bool includeAlpha)
{
#ifdef DGL_USE_COMPAT_OPENGL
if (includeAlpha)
glColor4f(red, green, blue, alpha);
else
glColor3f(red, green, blue);
#else
notImplemented("Color::setFor");
// unused
(void)includeAlpha;
#endif
}

// -----------------------------------------------------------------------
// Line

#ifdef DGL_USE_COMPAT_OPENGL
template<typename T>
static void drawLine(const Point<T>& posStart, const Point<T>& posEnd)
{
DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,);

glBegin(GL_LINES);

{
glVertex2d(posStart.getX(), posStart.getY());
glVertex2d(posEnd.getX(), posEnd.getY());
}

glEnd();
}
#endif

template<typename T>
void Line<T>::draw(const GraphicsContext&, const T width)
{
#ifdef DGL_USE_COMPAT_OPENGL
DISTRHO_SAFE_ASSERT_RETURN(width != 0,);

glLineWidth(static_cast<GLfloat>(width));
drawLine<T>(posStart, posEnd);
#else
notImplemented("Line::draw");
#endif
}

// deprecated calls
template<typename T>
void Line<T>::draw()
{
#ifdef DGL_USE_COMPAT_OPENGL
drawLine<T>(posStart, posEnd);
#else
notImplemented("Line::draw");
#endif
}

template class Line<double>;
template class Line<float>;
template class Line<int>;
template class Line<uint>;
template class Line<short>;
template class Line<ushort>;

// -----------------------------------------------------------------------
// Circle

#ifdef DGL_USE_COMPAT_OPENGL
template<typename T>
static void drawCircle(const Point<T>& pos,
const uint numSegments,
const float size,
const float sin,
const float cos,
const bool outline)
{
DISTRHO_SAFE_ASSERT_RETURN(numSegments >= 3 && size > 0.0f,);

const T origx = pos.getX();
const T origy = pos.getY();
double t, x = size, y = 0.0;

glBegin(outline ? GL_LINE_LOOP : GL_POLYGON);

for (uint i=0; i<numSegments; ++i)
{
glVertex2d(x + origx, y + origy);

t = x;
x = cos * x - sin * y;
y = sin * t + cos * y;
}

glEnd();
}
#endif

template<typename T>
void Circle<T>::draw(const GraphicsContext&)
{
#ifdef DGL_USE_COMPAT_OPENGL
drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false);
#else
notImplemented("Circle::draw");
#endif
}

template<typename T>
void Circle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
{
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);

glLineWidth(static_cast<GLfloat>(lineWidth));
#ifdef DGL_USE_COMPAT_OPENGL
drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true);
#else
notImplemented("Circle::drawOutline");
#endif
}

// deprecated calls
template<typename T>
void Circle<T>::draw()
{
#ifdef DGL_USE_COMPAT_OPENGL
drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false);
#else
notImplemented("Circle::draw");
#endif
}

template<typename T>
void Circle<T>::drawOutline()
{
#ifdef DGL_USE_COMPAT_OPENGL
drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true);
#else
notImplemented("Circle::drawOutline");
#endif
}

template class Circle<double>;
template class Circle<float>;
template class Circle<int>;
template class Circle<uint>;
template class Circle<short>;
template class Circle<ushort>;

// -----------------------------------------------------------------------
// Triangle

#ifdef DGL_USE_COMPAT_OPENGL
template<typename T>
static void drawTriangle(const Point<T>& pos1,
const Point<T>& pos2,
const Point<T>& pos3,
const bool outline)
{
DISTRHO_SAFE_ASSERT_RETURN(pos1 != pos2 && pos1 != pos3,);

glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES);

{
glVertex2d(pos1.getX(), pos1.getY());
glVertex2d(pos2.getX(), pos2.getY());
glVertex2d(pos3.getX(), pos3.getY());
}

glEnd();
}
#endif

template<typename T>
void Triangle<T>::draw(const GraphicsContext&)
{
#ifdef DGL_USE_COMPAT_OPENGL
drawTriangle<T>(pos1, pos2, pos3, false);
#else
notImplemented("Triangle::draw");
#endif
}

template<typename T>
void Triangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
{
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);

glLineWidth(static_cast<GLfloat>(lineWidth));
#ifdef DGL_USE_COMPAT_OPENGL
drawTriangle<T>(pos1, pos2, pos3, true);
#else
notImplemented("Triangle::drawOutline");
#endif
}

// deprecated calls
template<typename T>
void Triangle<T>::draw()
{
#ifdef DGL_USE_COMPAT_OPENGL
drawTriangle<T>(pos1, pos2, pos3, false);
#else
notImplemented("Triangle::draw");
#endif
}

template<typename T>
void Triangle<T>::drawOutline()
{
#ifdef DGL_USE_COMPAT_OPENGL
drawTriangle<T>(pos1, pos2, pos3, true);
#else
notImplemented("Triangle::drawOutline");
#endif
}

template class Triangle<double>;
template class Triangle<float>;
template class Triangle<int>;
template class Triangle<uint>;
template class Triangle<short>;
template class Triangle<ushort>;

// -----------------------------------------------------------------------
// Rectangle

#ifdef DGL_USE_COMPAT_OPENGL
template<typename T>
static void drawRectangle(const Rectangle<T>& rect, const bool outline)
{
DISTRHO_SAFE_ASSERT_RETURN(rect.isValid(),);

glBegin(outline ? GL_LINE_LOOP : GL_QUADS);

{
const T x = rect.getX();
const T y = rect.getY();
const T w = rect.getWidth();
const T h = rect.getHeight();

glTexCoord2f(0.0f, 0.0f);
glVertex2d(x, y);

glTexCoord2f(1.0f, 0.0f);
glVertex2d(x+w, y);

glTexCoord2f(1.0f, 1.0f);
glVertex2d(x+w, y+h);

glTexCoord2f(0.0f, 1.0f);
glVertex2d(x, y+h);
}

glEnd();
}
#endif

template<typename T>
void Rectangle<T>::draw(const GraphicsContext&)
{
#ifdef DGL_USE_COMPAT_OPENGL
drawRectangle<T>(*this, false);
#else
notImplemented("Rectangle::draw");
#endif
}

template<typename T>
void Rectangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
{
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);

glLineWidth(static_cast<GLfloat>(lineWidth));
#ifdef DGL_USE_COMPAT_OPENGL
drawRectangle<T>(*this, true);
#else
notImplemented("Rectangle::drawOutline");
#endif
}

// deprecated calls
template<typename T>
void Rectangle<T>::draw()
{
#ifdef DGL_USE_COMPAT_OPENGL
drawRectangle<T>(*this, false);
#else
notImplemented("Rectangle::draw");
#endif
}

template<typename T>
void Rectangle<T>::drawOutline()
{
#ifdef DGL_USE_COMPAT_OPENGL
drawRectangle<T>(*this, true);
#else
notImplemented("Rectangle::drawOutline");
#endif
}

template class Rectangle<double>;
template class Rectangle<float>;
template class Rectangle<int>;
template class Rectangle<uint>;
template class Rectangle<short>;
template class Rectangle<ushort>;

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// OpenGLImage

static void setupOpenGLImage(const OpenGLImage& image, GLuint textureId)
{
DISTRHO_SAFE_ASSERT_RETURN(image.isValid(),);

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureId);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);

static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);

glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
static_cast<GLsizei>(image.getWidth()),
static_cast<GLsizei>(image.getHeight()),
0,
asOpenGLImageFormat(image.getFormat()), GL_UNSIGNED_BYTE, image.getRawData());

glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}

static void drawOpenGLImage(const OpenGLImage& image, const Point<int>& pos, const GLuint textureId, bool& setupCalled)
{
if (textureId == 0 || image.isInvalid())
return;

if (! setupCalled)
{
setupOpenGLImage(image, textureId);
setupCalled = true;
}

#ifdef DGL_USE_COMPAT_OPENGL
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
#endif

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureId);

#ifdef DGL_USE_COMPAT_OPENGL
glBegin(GL_QUADS);

{
const int x = pos.getX();
const int y = pos.getY();
const int w = static_cast<int>(image.getWidth());
const int h = static_cast<int>(image.getHeight());

glTexCoord2f(0.0f, 0.0f);
glVertex2d(x, y);

glTexCoord2f(1.0f, 0.0f);
glVertex2d(x+w, y);

glTexCoord2f(1.0f, 1.0f);
glVertex2d(x+w, y+h);

glTexCoord2f(0.0f, 1.0f);
glVertex2d(x, y+h);
}

glEnd();
#endif

glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}

OpenGLImage::OpenGLImage()
: ImageBase(),
setupCalled(false),
textureInit(false),
textureId(0)
#ifdef DGL_USE_GLES
, convertedData(nullptr)
, rawDataLast(nullptr)
#endif
{
}

@@ -446,6 +49,10 @@ OpenGLImage::OpenGLImage(const char* const rdata, const uint w, const uint h, co
setupCalled(false),
textureInit(true),
textureId(0)
#ifdef DGL_USE_GLES
, convertedData(nullptr)
, rawDataLast(nullptr)
#endif
{
glGenTextures(1, &textureId);
DISTRHO_SAFE_ASSERT(textureId != 0);
@@ -456,6 +63,10 @@ OpenGLImage::OpenGLImage(const char* const rdata, const Size<uint>& s, const Ima
setupCalled(false),
textureInit(true),
textureId(0)
#ifdef DGL_USE_GLES
, convertedData(nullptr)
, rawDataLast(nullptr)
#endif
{
glGenTextures(1, &textureId);
DISTRHO_SAFE_ASSERT(textureId != 0);
@@ -466,6 +77,10 @@ OpenGLImage::OpenGLImage(const OpenGLImage& image)
setupCalled(false),
textureInit(true),
textureId(0)
#ifdef DGL_USE_GLES
, convertedData(nullptr)
, rawDataLast(nullptr)
#endif
{
glGenTextures(1, &textureId);
DISTRHO_SAFE_ASSERT(textureId != 0);
@@ -475,6 +90,10 @@ OpenGLImage::~OpenGLImage()
{
if (textureId != 0)
glDeleteTextures(1, &textureId);

#ifdef DGL_USE_GLES
std::free(convertedData);
#endif
}

void OpenGLImage::loadFromMemory(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) noexcept
@@ -489,11 +108,6 @@ void OpenGLImage::loadFromMemory(const char* const rdata, const Size<uint>& s, c
ImageBase::loadFromMemory(rdata, s, fmt);
}

void OpenGLImage::drawAt(const GraphicsContext&, const Point<int>& pos)
{
drawOpenGLImage(*this, pos, textureId, setupCalled);
}

OpenGLImage& OpenGLImage::operator=(const OpenGLImage& image) noexcept
{
rawData = image.rawData;
@@ -511,12 +125,16 @@ OpenGLImage& OpenGLImage::operator=(const OpenGLImage& image) noexcept
return *this;
}

// deprecated calls
#ifdef DGL_ALLOW_DEPRECATED_METHODS
OpenGLImage::OpenGLImage(const char* const rdata, const uint w, const uint h, const GLenum fmt)
: ImageBase(rdata, w, h, asDISTRHOImageFormat(fmt)),
setupCalled(false),
textureInit(true),
textureId(0)
#ifdef DGL_USE_GLES
, convertedData(nullptr)
, rawDataLast(nullptr)
#endif
{
glGenTextures(1, &textureId);
DISTRHO_SAFE_ASSERT(textureId != 0);
@@ -527,155 +145,17 @@ OpenGLImage::OpenGLImage(const char* const rdata, const Size<uint>& s, const GLe
setupCalled(false),
textureInit(true),
textureId(0)
#ifdef DGL_USE_GLES
, convertedData(nullptr)
, rawDataLast(nullptr)
#endif
{
glGenTextures(1, &textureId);
DISTRHO_SAFE_ASSERT(textureId != 0);
}

void OpenGLImage::draw()
{
drawOpenGLImage(*this, Point<int>(0, 0), textureId, setupCalled);
}

void OpenGLImage::drawAt(const int x, const int y)
{
drawOpenGLImage(*this, Point<int>(x, y), textureId, setupCalled);
}

void OpenGLImage::drawAt(const Point<int>& pos)
{
drawOpenGLImage(*this, pos, textureId, setupCalled);
}

// -----------------------------------------------------------------------
// ImageBaseAboutWindow

#if 0
template <>
void ImageBaseAboutWindow<OpenGLImage>::onDisplay()
{
const GraphicsContext& context(getGraphicsContext());
img.draw(context);
}
#endif

template class ImageBaseAboutWindow<OpenGLImage>;

// -----------------------------------------------------------------------
// ImageBaseButton

template class ImageBaseButton<OpenGLImage>;

// -----------------------------------------------------------------------
// ImageBaseKnob

template <>
void ImageBaseKnob<OpenGLImage>::PrivateData::init()
{
glTextureId = 0;
glGenTextures(1, &glTextureId);
}

template <>
void ImageBaseKnob<OpenGLImage>::PrivateData::cleanup()
{
if (glTextureId == 0)
return;

glDeleteTextures(1, &glTextureId);
glTextureId = 0;
}

template <>
void ImageBaseKnob<OpenGLImage>::onDisplay()
{
const GraphicsContext& context(getGraphicsContext());
const float normValue = getNormalizedValue();

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, pData->glTextureId);

if (! pData->isReady)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);

static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);

glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

uint imageDataOffset = 0;

if (pData->rotationAngle == 0)
{
DISTRHO_SAFE_ASSERT_RETURN(pData->imgLayerCount > 0,);
DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,);

const uint& v1(pData->isImgVertical ? pData->imgLayerWidth : pData->imgLayerHeight);
const uint& v2(pData->isImgVertical ? pData->imgLayerHeight : pData->imgLayerWidth);

// TODO kImageFormatGreyscale
const uint layerDataSize = v1 * v2 * ((pData->image.getFormat() == kImageFormatBGRA ||
pData->image.getFormat() == kImageFormatRGBA) ? 4 : 3);
/* */ imageDataOffset = layerDataSize * uint(normValue * float(pData->imgLayerCount-1));
}

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
static_cast<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0,
asOpenGLImageFormat(pData->image.getFormat()), GL_UNSIGNED_BYTE, pData->image.getRawData() + imageDataOffset);

pData->isReady = true;
}

const int w = static_cast<int>(getWidth());
const int h = static_cast<int>(getHeight());

if (pData->rotationAngle != 0)
{
#ifdef DGL_USE_COMPAT_OPENGL
glPushMatrix();
#endif

const int w2 = w/2;
const int h2 = h/2;

#ifdef DGL_USE_COMPAT_OPENGL
glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f);
glRotatef(normValue*static_cast<float>(pData->rotationAngle), 0.0f, 0.0f, 1.0f);
#endif

Rectangle<int>(-w2, -h2, w, h).draw(context);

#ifdef DGL_USE_COMPAT_OPENGL
glPopMatrix();
#endif
}
else
{
Rectangle<int>(0, 0, w, h).draw(context);
}

glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}

template class ImageBaseKnob<OpenGLImage>;

// -----------------------------------------------------------------------
// ImageBaseSlider

template class ImageBaseSlider<OpenGLImage>;

// -----------------------------------------------------------------------
// ImageBaseSwitch

template class ImageBaseSwitch<OpenGLImage>;

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

void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor)
{
@@ -736,7 +216,7 @@ void SubWidget::PrivateData::display(const uint width, const uint height, const
selfw->pData->displaySubWidgets(width, height, autoScaleFactor);
}

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

void TopLevelWidget::PrivateData::display()
{
@@ -757,7 +237,7 @@ void TopLevelWidget::PrivateData::display()
selfw->pData->displaySubWidgets(width, height, window.pData->autoScaleFactor);
}

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

void Window::PrivateData::renderToPicture(const char* const filename,
const GraphicsContext&,
@@ -787,13 +267,6 @@ void Window::PrivateData::renderToPicture(const char* const filename,
fclose(f);
}

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

const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept
{
return (const GraphicsContext&)graphicsContext;
}

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

END_NAMESPACE_DGL

+ 570
- 0
source/modules/dgl/src/OpenGL2.cpp View File

@@ -0,0 +1,570 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
*
* 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.
*
* THE 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.
*/

#ifdef _MSC_VER
// instantiated template classes whose methods are defined elsewhere
# pragma warning(disable:4661)
#endif

#include "../OpenGL.hpp"
#include "../Color.hpp"
#include "../ImageWidgets.hpp"

// #include "SubWidgetPrivateData.hpp"
// #include "TopLevelWidgetPrivateData.hpp"
// #include "WidgetPrivateData.hpp"
#include "WindowPrivateData.hpp"

// templated classes
#include "ImageBaseWidgets.cpp"

START_NAMESPACE_DGL

// --------------------------------------------------------------------------------------------------------------------
// Check for correct build config

#ifndef DGL_OPENGL
# error Build config error, OpenGL was NOT requested while building OpenGL2 code
#endif
#ifdef DGL_CAIRO
# error Build config error, Cairo requested while building OpenGL2 code
#endif
#ifdef DGL_VULKAN
# error Build config error, Vulkan requested while building OpenGL2 code
#endif
#ifdef DGL_USE_GLES2
# error Build config error, GLESv2 requested while building OpenGL2 code
#endif
#ifdef DGL_USE_GLES3
# error Build config error, GLESv3 requested while building OpenGL2 code
#endif
#ifdef DGL_USE_OPENGL3
# error Build config error, OpenGL3 requested while building OpenGL2 code
#endif

// --------------------------------------------------------------------------------------------------------------------
// Color

void Color::setFor(const GraphicsContext&, const bool includeAlpha)
{
if (includeAlpha)
glColor4f(red, green, blue, alpha);
else
glColor3f(red, green, blue);
}

// --------------------------------------------------------------------------------------------------------------------
// Line

template<typename T>
static void drawLine(const Point<T>& posStart, const Point<T>& posEnd)
{
DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,);

glBegin(GL_LINES);

{
glVertex2d(posStart.getX(), posStart.getY());
glVertex2d(posEnd.getX(), posEnd.getY());
}

glEnd();
}

template<typename T>
void Line<T>::draw(const GraphicsContext&, const T width)
{
DISTRHO_SAFE_ASSERT_RETURN(width != 0,);

glLineWidth(static_cast<GLfloat>(width));
drawLine<T>(posStart, posEnd);
}

#ifdef DGL_ALLOW_DEPRECATED_METHODS
template<typename T>
void Line<T>::draw()
{
drawLine<T>(posStart, posEnd);
}
#endif

template class Line<double>;
template class Line<float>;
template class Line<int>;
template class Line<uint>;
template class Line<short>;
template class Line<ushort>;

// --------------------------------------------------------------------------------------------------------------------
// Circle

template<typename T>
static void drawCircle(const Point<T>& pos,
const uint numSegments,
const float size,
const float sin,
const float cos,
const bool outline)
{
DISTRHO_SAFE_ASSERT_RETURN(numSegments >= 3 && size > 0.0f,);

const double origx = static_cast<double>(pos.getX());
const double origy = static_cast<double>(pos.getY());
double t;
double x = size;
double y = 0.0;

glBegin(outline ? GL_LINE_LOOP : GL_POLYGON);

for (uint i = 0; i < numSegments; ++i)
{
glVertex2d(x + origx, y + origy);

t = x;
x = cos * x - sin * y;
y = sin * t + cos * y;
}

glEnd();
}

template<typename T>
static void drawCircle(const GraphicsContext&,
const Point<T>& pos,
const uint numSegments,
const float size,
const float sin,
const float cos,
const bool outline)
{
drawCircle<T>(pos, numSegments, size, sin, cos, outline);
}

template<typename T>
void Circle<T>::draw(const GraphicsContext& context)
{
drawCircle<T>(context, fPos, fNumSegments, fSize, fSin, fCos, false);
}

template<typename T>
void Circle<T>::drawOutline(const GraphicsContext& context, const T lineWidth)
{
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);

glLineWidth(static_cast<GLfloat>(lineWidth));
drawCircle<T>(context, fPos, fNumSegments, fSize, fSin, fCos, true);
}

#ifdef DGL_ALLOW_DEPRECATED_METHODS
template<typename T>
void Circle<T>::draw()
{
drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false);
}

template<typename T>
void Circle<T>::drawOutline()
{
drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true);
}
#endif

template class Circle<double>;
template class Circle<float>;
template class Circle<int>;
template class Circle<uint>;
template class Circle<short>;
template class Circle<ushort>;

// --------------------------------------------------------------------------------------------------------------------
// Triangle

template<typename T>
static void drawTriangle(const Point<T>& pos1,
const Point<T>& pos2,
const Point<T>& pos3,
const bool outline)
{
DISTRHO_SAFE_ASSERT_RETURN(pos1 != pos2 && pos1 != pos3,);

glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES);

{
glVertex2d(pos1.getX(), pos1.getY());
glVertex2d(pos2.getX(), pos2.getY());
glVertex2d(pos3.getX(), pos3.getY());
}

glEnd();
}

template<typename T>
static void drawTriangle(const GraphicsContext&,
const Point<T>& pos1,
const Point<T>& pos2,
const Point<T>& pos3,
const bool outline)
{
drawTriangle<T>(pos1, pos2, pos3, outline);
}

template<typename T>
void Triangle<T>::draw(const GraphicsContext&)
{
drawTriangle<T>(pos1, pos2, pos3, false);
}

template<typename T>
void Triangle<T>::drawOutline(const GraphicsContext&, const T lineWidth)
{
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);

glLineWidth(static_cast<GLfloat>(lineWidth));
drawTriangle<T>(pos1, pos2, pos3, true);
}

#ifdef DGL_ALLOW_DEPRECATED_METHODS
template<typename T>
void Triangle<T>::draw()
{
drawTriangle<T>(pos1, pos2, pos3, false);
}

template<typename T>
void Triangle<T>::drawOutline()
{
drawTriangle<T>(pos1, pos2, pos3, true);
}
#endif

template class Triangle<double>;
template class Triangle<float>;
template class Triangle<int>;
template class Triangle<uint>;
template class Triangle<short>;
template class Triangle<ushort>;

// --------------------------------------------------------------------------------------------------------------------
// Rectangle

template<typename T>
static void drawRectangle(const Rectangle<T>& rect, const bool outline)
{
DISTRHO_SAFE_ASSERT_RETURN(rect.isValid(),);

glBegin(outline ? GL_LINE_LOOP : GL_QUADS);

{
const T x = rect.getX();
const T y = rect.getY();
const T w = rect.getWidth();
const T h = rect.getHeight();

glTexCoord2f(0.0f, 0.0f);
glVertex2d(x, y);

glTexCoord2f(1.0f, 0.0f);
glVertex2d(x+w, y);

glTexCoord2f(1.0f, 1.0f);
glVertex2d(x+w, y+h);

glTexCoord2f(0.0f, 1.0f);
glVertex2d(x, y+h);
}

glEnd();
}

template<typename T>
void Rectangle<T>::draw(const GraphicsContext& context)
{
drawRectangle<T>(*this, false);
}

template<typename T>
void Rectangle<T>::drawOutline(const GraphicsContext& context, const T lineWidth)
{
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);

glLineWidth(static_cast<GLfloat>(lineWidth));
drawRectangle<T>(*this, true);
}

#ifdef DGL_ALLOW_DEPRECATED_METHODS
template<typename T>
void Rectangle<T>::draw()
{
drawRectangle<T>(*this, false);
}

template<typename T>
void Rectangle<T>::drawOutline()
{
drawRectangle<T>(*this, true);
}
#endif

template class Rectangle<double>;
template class Rectangle<float>;
template class Rectangle<int>;
template class Rectangle<uint>;
template class Rectangle<short>;
template class Rectangle<ushort>;

// --------------------------------------------------------------------------------------------------------------------
// OpenGLImage

static void setupOpenGLImage(const OpenGLImage& image, GLuint textureId)
{
DISTRHO_SAFE_ASSERT_RETURN(image.isValid(),);

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureId);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);

static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);

glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA,
static_cast<GLsizei>(image.getWidth()),
static_cast<GLsizei>(image.getHeight()),
0,
asOpenGLImageFormat(image.getFormat()),
GL_UNSIGNED_BYTE,
image.getRawData());

glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}

static void drawOpenGLImage(const OpenGLImage& image, const Point<int>& pos, const GLuint textureId, bool& setupCalled)
{
if (textureId == 0 || image.isInvalid())
return;

if (! setupCalled)
{
setupOpenGLImage(image, textureId);
setupCalled = true;
}

glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureId);

glBegin(GL_QUADS);

{
const int x = pos.getX();
const int y = pos.getY();
const int w = static_cast<int>(image.getWidth());
const int h = static_cast<int>(image.getHeight());

glTexCoord2f(0.0f, 0.0f);
glVertex2d(x, y);

glTexCoord2f(1.0f, 0.0f);
glVertex2d(x+w, y);

glTexCoord2f(1.0f, 1.0f);
glVertex2d(x+w, y+h);

glTexCoord2f(0.0f, 1.0f);
glVertex2d(x, y+h);
}

glEnd();

glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}

void OpenGLImage::drawAt(const GraphicsContext&, const Point<int>& pos)
{
drawOpenGLImage(*this, pos, textureId, setupCalled);
}

#ifdef DGL_ALLOW_DEPRECATED_METHODS
void OpenGLImage::draw()
{
drawOpenGLImage(*this, Point<int>(0, 0), textureId, setupCalled);
}

void OpenGLImage::drawAt(const int x, const int y)
{
drawOpenGLImage(*this, Point<int>(x, y), textureId, setupCalled);
}

void OpenGLImage::drawAt(const Point<int>& pos)
{
drawOpenGLImage(*this, pos, textureId, setupCalled);
}
#endif

// --------------------------------------------------------------------------------------------------------------------
// ImageBaseAboutWindow

#if 0
template <>
void ImageBaseAboutWindow<OpenGLImage>::onDisplay()
{
const GraphicsContext& context(getGraphicsContext());
img.draw(context);
}
#endif

template class ImageBaseAboutWindow<OpenGLImage>;

// --------------------------------------------------------------------------------------------------------------------
// ImageBaseButton

template class ImageBaseButton<OpenGLImage>;

// --------------------------------------------------------------------------------------------------------------------
// ImageBaseKnob

template <>
void ImageBaseKnob<OpenGLImage>::PrivateData::init()
{
glTextureId = 0;
glGenTextures(1, &glTextureId);
}

template <>
void ImageBaseKnob<OpenGLImage>::PrivateData::cleanup()
{
if (glTextureId == 0)
return;

glDeleteTextures(1, &glTextureId);
glTextureId = 0;
}

template <>
void ImageBaseKnob<OpenGLImage>::onDisplay()
{
const GraphicsContext& context(getGraphicsContext());
const float normValue = getNormalizedValue();

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, pData->glTextureId);

if (! pData->isReady)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);

static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);

glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

uint imageDataOffset = 0;

if (pData->rotationAngle == 0)
{
DISTRHO_SAFE_ASSERT_RETURN(pData->imgLayerCount > 0,);
DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,);

const uint& v1(pData->isImgVertical ? pData->imgLayerWidth : pData->imgLayerHeight);
const uint& v2(pData->isImgVertical ? pData->imgLayerHeight : pData->imgLayerWidth);

// TODO kImageFormatGreyscale
const uint layerDataSize = v1 * v2 * ((pData->image.getFormat() == kImageFormatBGRA ||
pData->image.getFormat() == kImageFormatRGBA) ? 4 : 3);
/* */ imageDataOffset = layerDataSize * uint(normValue * float(pData->imgLayerCount-1));
}

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
static_cast<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0,
asOpenGLImageFormat(pData->image.getFormat()), GL_UNSIGNED_BYTE, pData->image.getRawData() + imageDataOffset);

pData->isReady = true;
}

const int w = static_cast<int>(getWidth());
const int h = static_cast<int>(getHeight());

if (pData->rotationAngle != 0)
{
glPushMatrix();

const int w2 = w/2;
const int h2 = h/2;

glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f);
glRotatef(normValue*static_cast<float>(pData->rotationAngle), 0.0f, 0.0f, 1.0f);

Rectangle<int>(-w2, -h2, w, h).draw(context);

glPopMatrix();
}
else
{
Rectangle<int>(0, 0, w, h).draw(context);
}

glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}

template class ImageBaseKnob<OpenGLImage>;

// --------------------------------------------------------------------------------------------------------------------
// ImageBaseSlider

template class ImageBaseSlider<OpenGLImage>;

// --------------------------------------------------------------------------------------------------------------------
// ImageBaseSwitch

template class ImageBaseSwitch<OpenGLImage>;

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

void Window::PrivateData::createContextIfNeeded()
{
}

void Window::PrivateData::destroyContext()
{
}

void Window::PrivateData::startContext()
{
}

void Window::PrivateData::endContext()
{
}

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

END_NAMESPACE_DGL

+ 1025
- 0
source/modules/dgl/src/OpenGL3.cpp
File diff suppressed because it is too large
View File


+ 36
- 31
source/modules/dgl/src/Window.cpp View File

@@ -28,7 +28,11 @@ Window::ScopedGraphicsContext::ScopedGraphicsContext(Window& win)
: window(win),
ppData(nullptr),
active(window.pData->view != nullptr && puglBackendEnter(window.pData->view)),
reenter(false) {}
reenter(false)
{
if (active)
window.pData->createContextIfNeeded();
}

Window::ScopedGraphicsContext::ScopedGraphicsContext(Window& win, Window& transientWin)
: window(win),
@@ -40,6 +44,8 @@ Window::ScopedGraphicsContext::ScopedGraphicsContext(Window& win, Window& transi
{
puglBackendLeave(ppData->view);
active = puglBackendEnter(window.pData->view);
if (active)
window.pData->createContextIfNeeded();
}
}

@@ -180,22 +186,22 @@ int Window::getOffsetX() const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);

return puglGetFrame(pData->view).x;
return puglGetPositionHint(pData->view, PUGL_CURRENT_POSITION).x;
}

int Window::getOffsetY() const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);

return puglGetFrame(pData->view).y;
return puglGetPositionHint(pData->view, PUGL_CURRENT_POSITION).y;
}

Point<int> Window::getOffset() const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, Point<int>());

const PuglRect rect = puglGetFrame(pData->view);
return Point<int>(rect.x, rect.y);
const PuglPoint pos = puglGetPositionHint(pData->view, PUGL_CURRENT_POSITION);
return Point<int>(pos.x, pos.y);
}

void Window::setOffsetX(const int x)
@@ -214,7 +220,7 @@ void Window::setOffset(const int x, const int y)
DISTRHO_SAFE_ASSERT_RETURN(!pData->isEmbed,);

if (pData->view != nullptr)
puglSetPosition(pData->view, x, y);
puglSetPositionHint(pData->view, PUGL_CURRENT_POSITION, x, y);
}

void Window::setOffset(const Point<int>& offset)
@@ -226,29 +232,28 @@ uint Window::getWidth() const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);

const double width = puglGetFrame(pData->view).width;
DISTRHO_SAFE_ASSERT_RETURN(width > 0.0, 0);
return static_cast<uint>(width + 0.5);
const PuglSpan width = puglGetSizeHint(pData->view, PUGL_CURRENT_SIZE).width;
DISTRHO_SAFE_ASSERT(width > 0);
return width;
}

uint Window::getHeight() const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0);

const double height = puglGetFrame(pData->view).height;
DISTRHO_SAFE_ASSERT_RETURN(height > 0.0, 0);
return static_cast<uint>(height + 0.5);
const PuglSpan height = puglGetSizeHint(pData->view, PUGL_CURRENT_SIZE).height;
DISTRHO_SAFE_ASSERT(height > 0);
return height;
}

Size<uint> Window::getSize() const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, Size<uint>());

const PuglRect rect = puglGetFrame(pData->view);
DISTRHO_SAFE_ASSERT_RETURN(rect.width > 0.0, Size<uint>());
DISTRHO_SAFE_ASSERT_RETURN(rect.height > 0.0, Size<uint>());
return Size<uint>(static_cast<uint>(rect.width + 0.5),
static_cast<uint>(rect.height + 0.5));
const PuglArea size = puglGetSizeHint(pData->view, PUGL_CURRENT_SIZE);
DISTRHO_SAFE_ASSERT(size.width > 0);
DISTRHO_SAFE_ASSERT(size.height > 0);
return Size<uint>(size.width, size.height);
}

void Window::setWidth(const uint width)
@@ -443,7 +448,7 @@ void Window::repaint() noexcept
if (pData->usesScheduledRepaints)
pData->appData->needsRepaint = true;

puglPostRedisplay(pData->view);
puglObscureView(pData->view);
}

void Window::repaint(const Rectangle<uint>& rect) noexcept
@@ -454,22 +459,22 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept
if (pData->usesScheduledRepaints)
pData->appData->needsRepaint = true;

PuglRect prect = {
static_cast<PuglCoord>(rect.getX()),
static_cast<PuglCoord>(rect.getY()),
static_cast<PuglSpan>(rect.getWidth()),
static_cast<PuglSpan>(rect.getHeight()),
};
int x = static_cast<int>(rect.getX());
int y = static_cast<int>(rect.getY());
uint width = rect.getWidth();
uint height = rect.getHeight();

if (pData->autoScaling)
{
const double autoScaleFactor = pData->autoScaleFactor;

prect.x = static_cast<PuglCoord>(prect.x * autoScaleFactor);
prect.y = static_cast<PuglCoord>(prect.y * autoScaleFactor);
prect.width = static_cast<PuglSpan>(prect.width * autoScaleFactor + 0.5);
prect.height = static_cast<PuglSpan>(prect.height * autoScaleFactor + 0.5);
x = d_roundToIntPositive(x * autoScaleFactor);
y = d_roundToIntPositive(y * autoScaleFactor);
width = d_roundToUnsignedInt(width * autoScaleFactor);
height = d_roundToUnsignedInt(height * autoScaleFactor);
}
puglPostRedisplayRect(pData->view, prect);

puglObscureRegion(pData->view, x, y, width, height);
}

void Window::renderToPicture(const char* const filename)
@@ -523,8 +528,8 @@ void Window::setGeometryConstraints(uint minimumWidth,
{
const Size<uint> size(getSize());

setSize(static_cast<uint>(size.getWidth() * scaleFactor + 0.5),
static_cast<uint>(size.getHeight() * scaleFactor + 0.5));
setSize(d_roundToUnsignedInt(size.getWidth() * scaleFactor),
d_roundToUnsignedInt(size.getHeight() * scaleFactor));
}
}



+ 29
- 15
source/modules/dgl/src/WindowPrivateData.cpp View File

@@ -91,10 +91,10 @@ static PuglView* puglNewViewWithParentWindow(PuglWorld* const world, const uintp

if (PuglView* const view = puglNewView(world))
{
puglSetParentWindow(view, parentWindowHandle);
puglSetParent(view, parentWindowHandle);

if (parentWindowHandle != 0)
puglSetPosition(view, 0, 0);
puglSetPositionHint(view, PUGL_DEFAULT_POSITION, 0, 0);

return view;
}
@@ -268,6 +268,9 @@ Window::PrivateData::~PrivateData()
isVisible = false;
}

#ifndef DPF_TEST_WINDOW_CPP
destroyContext();
#endif
puglFreeView(view);
}

@@ -300,8 +303,8 @@ void Window::PrivateData::initPre(const uint width, const uint height, const boo
// PUGL_SAMPLES ??
puglSetEventFunc(view, puglEventCallback);

// setting default size triggers system-level calls, do it last
puglSetSizeHint(view, PUGL_DEFAULT_SIZE, static_cast<PuglSpan>(width), static_cast<PuglSpan>(height));
// setting size triggers system-level calls, do it last
puglSetSizeAndDefault(view, width, height);
}

bool Window::PrivateData::initPost()
@@ -366,10 +369,6 @@ void Window::PrivateData::show()
isClosed = false;
appData->oneWindowShown();

// FIXME
// PuglRect rect = puglGetFrame(view);
// puglSetWindowSize(view, static_cast<uint>(rect.width), static_cast<uint>(rect.height));

#if defined(DISTRHO_OS_WINDOWS)
puglWin32ShowCentered(view);
#elif defined(DISTRHO_OS_MAC)
@@ -453,6 +452,13 @@ void Window::PrivateData::setResizable(const bool resizable)
puglSetResizable(view, resizable);
}

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

const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept
{
return reinterpret_cast<const GraphicsContext&>(graphicsContext);
}

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

void Window::PrivateData::idleCallback()
@@ -538,9 +544,9 @@ bool Window::PrivateData::createWebView(const char* const url, const DGL_NAMESPA
if (webViewHandle != nullptr)
webViewDestroy(webViewHandle);

const PuglRect rect = puglGetFrame(view);
uint initialWidth = static_cast<uint>(rect.width) - options.offset.x;
uint initialHeight = static_cast<uint>(rect.height) - options.offset.y;
const PuglArea size = puglGetSizeHint(view, PUGL_CURRENT_SIZE);
uint initialWidth = size.width - options.offset.x;
uint initialHeight = size.height - options.offset.y;

webViewOffset = Point<int>(options.offset.x, options.offset.y);

@@ -640,6 +646,10 @@ void Window::PrivateData::onPuglConfigure(const uint width, const uint height)

DGL_DBGp("PUGL: onReshape : %d %d\n", width, height);

#ifndef DPF_TEST_WINDOW_CPP
createContextIfNeeded();
#endif

if (autoScaling)
{
const double scaleHorizontal = width / static_cast<double>(minWidth);
@@ -682,7 +692,7 @@ void Window::PrivateData::onPuglConfigure(const uint width, const uint height)
#endif

// always repaint after a resize
puglPostRedisplay(view);
puglObscureView(view);
}

void Window::PrivateData::onPuglExpose()
@@ -692,6 +702,8 @@ void Window::PrivateData::onPuglExpose()
puglOnDisplayPrepare(view);

#ifndef DPF_TEST_WINDOW_CPP
startContext();

FOR_EACH_TOP_LEVEL_WIDGET(it)
{
TopLevelWidget* const widget(*it);
@@ -702,11 +714,13 @@ void Window::PrivateData::onPuglExpose()

if (char* const filename = filenameToRenderInto)
{
const PuglRect rect = puglGetFrame(view);
const PuglArea size = puglGetSizeHint(view, PUGL_CURRENT_SIZE);
filenameToRenderInto = nullptr;
renderToPicture(filename, getGraphicsContext(), static_cast<uint>(rect.width), static_cast<uint>(rect.height));
renderToPicture(filename, getGraphicsContext(), size.width, size.height);
std::free(filename);
}

endContext();
#endif
}

@@ -978,7 +992,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu
SetClassLongPtr(view->impl->hwnd, GCLP_HICON, (LONG_PTR) LoadIcon(hInstance, MAKEINTRESOURCE(DGL_WINDOWS_ICON_ID)));
#endif
#ifdef DGL_USING_X11
puglX11SetWindowTypeAndPID(view, pData->appData->isStandalone);
puglX11SetWindowType(view, pData->appData->isStandalone);
#endif
}
break;


+ 5
- 1
source/modules/dgl/src/WindowPrivateData.hpp View File

@@ -45,7 +45,11 @@ struct Window::PrivateData : IdleCallback {
PuglView* view;

/** Reserved space for graphics context. */
mutable uint8_t graphicsContext[sizeof(void*)];
mutable uint8_t graphicsContext[sizeof(int) * 9];
void createContextIfNeeded();
void destroyContext();
void startContext();
void endContext();

/** The top-level widgets associated with this Window. */
std::list<TopLevelWidget*> topLevelWidgets;


+ 24
- 20
source/modules/dgl/src/nanovg/nanovg_gl.h View File

@@ -173,7 +173,7 @@ struct GLNVGtexture {
int width, height;
int type;
int flags;
#if defined NANOVG_GLES2
#if defined(NANOVG_GLES2) || defined(NANOVG_GLES3)
unsigned char* data;
#endif
};
@@ -813,10 +813,10 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im
switch (type)
{
case NVG_TEXTURE_BGR:
#if NANOVG_GLES2
// GLES2 cannot handle GL_BGR, do local conversion to GL_RGB
#if defined(NANOVG_GLES2) || defined(NANOVG_GLES3)
// GLES cannot handle GL_BGR, do local conversion to GL_RGB
tex->data = (uint8_t*)malloc(sizeof(uint8_t) * 3 * w * h);
for (uint32_t i=0; i<w*h; ++i)
for (int i = 0; i < w * h; ++i)
{
tex->data[i*3+0] = data[i*3+2];
tex->data[i*3+1] = data[i*3+1];
@@ -829,34 +829,34 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im
#endif
break;
case NVG_TEXTURE_BGRA:
#if NANOVG_GLES2
// GLES2 cannot handle GL_BGRA, do local conversion to GL_RGBA
#if defined(NANOVG_GLES2) || defined(NANOVG_GLES3)
// GLES cannot handle GL_BGRA, do local conversion to GL_RGBA
tex->data = (uint8_t*)malloc(sizeof(uint8_t) * 4 * w * h);
for (uint32_t i=0; i<w*h; ++i)
for (int i = 0; i < w * h; ++i)
{
tex->data[i*3+0] = data[i*3+3];
tex->data[i*3+1] = data[i*3+2];
tex->data[i*3+2] = data[i*3+1];
tex->data[i*3+3] = data[i*3+0];
tex->data[i*4+0] = data[i*4+2];
tex->data[i*4+1] = data[i*4+1];
tex->data[i*4+2] = data[i*4+0];
tex->data[i*4+3] = data[i*4+3];
}
data = tex->data;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, data);
#endif
break;
case NVG_TEXTURE_RGB:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
break;
case NVG_TEXTURE_RGBA:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
break;
default:
#if defined(NANOVG_GLES2) || defined (NANOVG_GL2)
#if defined(NANOVG_GL2) || defined(NANOVG_GLES2)
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
#elif defined(NANOVG_GLES3)
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, data);
#else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, data);
#endif
break;
@@ -960,19 +960,23 @@ static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w
switch (tex->type)
{
case NVG_TEXTURE_BGR:
#if !(defined(NANOVG_GLES2) || defined(NANOVG_GLES3))
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_BGR, GL_UNSIGNED_BYTE, data);
break;
case NVG_TEXTURE_BGRA:
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_BGRA, GL_UNSIGNED_BYTE, data);
break;
#endif
case NVG_TEXTURE_RGB:
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGB, GL_UNSIGNED_BYTE, data);
break;
case NVG_TEXTURE_BGRA:
#if !(defined(NANOVG_GLES2) || defined(NANOVG_GLES3))
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_BGRA, GL_UNSIGNED_BYTE, data);
break;
#endif
case NVG_TEXTURE_RGBA:
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGBA, GL_UNSIGNED_BYTE, data);
break;
default:
#if defined(NANOVG_GLES2) || defined(NANOVG_GL2)
#if defined(NANOVG_GL2) || defined(NANOVG_GLES2)
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
#else
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RED, GL_UNSIGNED_BYTE, data);


+ 2
- 17
source/modules/dgl/src/pugl-upstream/include/pugl/attributes.h View File

@@ -26,17 +26,6 @@
# endif
#endif

// Deprecated API
#ifndef PUGL_DISABLE_DEPRECATED
# if defined(__clang__)
# define PUGL_DEPRECATED_BY(rep) __attribute__((deprecated("", rep)))
# elif defined(__GNUC__)
# define PUGL_DEPRECATED_BY(rep) __attribute__((deprecated("Use " rep)))
# else
# define PUGL_DEPRECATED_BY(rep)
# endif
#endif

// GCC function attributes
#if defined(__GNUC__)
# define PUGL_CONST_FUNC __attribute__((const))
@@ -47,13 +36,9 @@
#endif

/// A const function in the public API that only reads parameters
#define PUGL_CONST_API \
PUGL_API \
PUGL_CONST_FUNC
#define PUGL_CONST_API PUGL_API PUGL_CONST_FUNC

/// A malloc function in the public API that returns allocated memory
#define PUGL_MALLOC_API \
PUGL_API \
PUGL_MALLOC_FUNC
#define PUGL_MALLOC_API PUGL_API PUGL_MALLOC_FUNC

#endif // PUGL_ATTRIBUTES_H

+ 6
- 10
source/modules/dgl/src/pugl-upstream/include/pugl/gl.h View File

@@ -4,8 +4,8 @@
#ifndef PUGL_GL_H
#define PUGL_GL_H

#include "pugl/attributes.h"
#include "pugl/pugl.h"
#include <pugl/attributes.h>
#include <pugl/pugl.h>

// IWYU pragma: begin_exports

@@ -42,8 +42,7 @@ typedef void (*PuglGlFunc)(void);
/**
Return the address of an OpenGL extension function.
*/
PUGL_API
PuglGlFunc
PUGL_API PuglGlFunc
puglGetProcAddress(const char* name);

/**
@@ -53,8 +52,7 @@ puglGetProcAddress(const char* name);
doing things like loading textures. Note that this must not be used for
drawing, which may only be done while processing an expose event.
*/
PUGL_API
PuglStatus
PUGL_API PuglStatus
puglEnterContext(PuglView* view);

/**
@@ -62,8 +60,7 @@ puglEnterContext(PuglView* view);

This must only be called after puglEnterContext().
*/
PUGL_API
PuglStatus
PUGL_API PuglStatus
puglLeaveContext(PuglView* view);

/**
@@ -71,8 +68,7 @@ puglLeaveContext(PuglView* view);

Pass the returned value to puglSetBackend() to draw to a view with OpenGL.
*/
PUGL_CONST_API
const PuglBackend*
PUGL_CONST_API const PuglBackend*
puglGlBackend(void);

PUGL_END_DECLS


+ 279
- 786
source/modules/dgl/src/pugl-upstream/include/pugl/pugl.h
File diff suppressed because it is too large
View File


+ 3
- 4
source/modules/dgl/src/pugl-upstream/include/pugl/stub.h View File

@@ -4,8 +4,8 @@
#ifndef PUGL_STUB_H
#define PUGL_STUB_H

#include "pugl/attributes.h"
#include "pugl/pugl.h"
#include <pugl/attributes.h>
#include <pugl/pugl.h>

PUGL_BEGIN_DECLS

@@ -22,8 +22,7 @@ PUGL_BEGIN_DECLS
This backend just creates a simple native window without setting up any
portable graphics API.
*/
PUGL_CONST_API
const PuglBackend*
PUGL_CONST_API const PuglBackend*
puglStubBackend(void);

/**


+ 98
- 53
source/modules/dgl/src/pugl-upstream/src/common.c View File

@@ -4,13 +4,11 @@
// Common implementations of public API functions in the core library

#include "internal.h"

#include "platform.h"
#include "types.h"

#include "pugl/pugl.h"
#include <pugl/pugl.h>

#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
@@ -27,6 +25,7 @@ puglStrerror(const PuglStatus status)
case PUGL_BAD_BACKEND: return "Invalid or missing backend";
case PUGL_BAD_CONFIGURATION: return "Invalid view configuration";
case PUGL_BAD_PARAMETER: return "Invalid parameter";
case PUGL_BAD_CALL: return "Invalid call";
case PUGL_BACKEND_FAILED: return "Backend initialisation failed";
case PUGL_REGISTRATION_FAILED: return "Class registration failed";
case PUGL_REALIZE_FAILED: return "View creation failed";
@@ -106,27 +105,37 @@ puglGetWorldString(const PuglWorld* const world, const PuglStringHint key)
}

static void
puglSetDefaultHints(PuglHints hints)
puglSetDefaultHints(PuglView* const view)
{
hints[PUGL_CONTEXT_API] = PUGL_OPENGL_API;
hints[PUGL_CONTEXT_VERSION_MAJOR] = 2;
hints[PUGL_CONTEXT_VERSION_MINOR] = 0;
hints[PUGL_CONTEXT_PROFILE] = PUGL_OPENGL_CORE_PROFILE;
hints[PUGL_CONTEXT_DEBUG] = PUGL_FALSE;
hints[PUGL_RED_BITS] = 8;
hints[PUGL_GREEN_BITS] = 8;
hints[PUGL_BLUE_BITS] = 8;
hints[PUGL_ALPHA_BITS] = 8;
hints[PUGL_DEPTH_BITS] = 0;
hints[PUGL_STENCIL_BITS] = 0;
hints[PUGL_SAMPLE_BUFFERS] = PUGL_DONT_CARE;
hints[PUGL_SAMPLES] = 0;
hints[PUGL_DOUBLE_BUFFER] = PUGL_TRUE;
hints[PUGL_SWAP_INTERVAL] = PUGL_DONT_CARE;
hints[PUGL_RESIZABLE] = PUGL_FALSE;
hints[PUGL_IGNORE_KEY_REPEAT] = PUGL_FALSE;
hints[PUGL_REFRESH_RATE] = PUGL_DONT_CARE;
hints[PUGL_VIEW_TYPE] = PUGL_DONT_CARE;
view->hints[PUGL_CONTEXT_API] = PUGL_OPENGL_API;
view->hints[PUGL_CONTEXT_VERSION_MAJOR] = 2;
view->hints[PUGL_CONTEXT_VERSION_MINOR] = 0;
view->hints[PUGL_CONTEXT_PROFILE] = PUGL_OPENGL_CORE_PROFILE;
view->hints[PUGL_CONTEXT_DEBUG] = PUGL_FALSE;
view->hints[PUGL_RED_BITS] = 8;
view->hints[PUGL_GREEN_BITS] = 8;
view->hints[PUGL_BLUE_BITS] = 8;
view->hints[PUGL_ALPHA_BITS] = 8;
view->hints[PUGL_DEPTH_BITS] = 0;
view->hints[PUGL_STENCIL_BITS] = 0;
view->hints[PUGL_SAMPLE_BUFFERS] = PUGL_DONT_CARE;
view->hints[PUGL_SAMPLES] = 0;
view->hints[PUGL_DOUBLE_BUFFER] = PUGL_TRUE;
view->hints[PUGL_SWAP_INTERVAL] = PUGL_DONT_CARE;
view->hints[PUGL_RESIZABLE] = PUGL_FALSE;
view->hints[PUGL_IGNORE_KEY_REPEAT] = PUGL_FALSE;
view->hints[PUGL_REFRESH_RATE] = PUGL_DONT_CARE;
view->hints[PUGL_VIEW_TYPE] = PUGL_DONT_CARE;

for (unsigned i = 0U; i < PUGL_NUM_POSITION_HINTS; ++i) {
view->positionHints[i].x = INT16_MIN;
view->positionHints[i].y = INT16_MIN;
}

for (unsigned i = 0U; i < PUGL_NUM_SIZE_HINTS; ++i) {
view->sizeHints[i].width = 0U;
view->sizeHints[i].height = 0U;
}
}

PuglView*
@@ -138,13 +147,8 @@ puglNewView(PuglWorld* const world)
return NULL;
}

view->world = world;
view->sizeHints[PUGL_MIN_SIZE].width = 1;
view->sizeHints[PUGL_MIN_SIZE].height = 1;
view->defaultX = INT_MIN;
view->defaultY = INT_MIN;

puglSetDefaultHints(view->hints);
view->world = world;
puglSetDefaultHints(view);

// Enlarge world view list
const size_t newNumViews = world->numViews + 1U;
@@ -287,43 +291,84 @@ puglGetViewString(const PuglView* const view, const PuglStringHint key)
return view->strings[key];
}

PuglRect
puglGetFrame(const PuglView* view)
PuglPoint
puglGetPositionHint(const PuglView* const view, const PuglPositionHint hint)
{
if (view->lastConfigure.type == PUGL_CONFIGURE) {
// Return the last configured frame
const PuglRect frame = {view->lastConfigure.x,
view->lastConfigure.y,
view->lastConfigure.width,
view->lastConfigure.height};
return frame;
if (hint == PUGL_CURRENT_POSITION) {
PuglPoint pos = {0, 0};
if (view->lastConfigure.type == PUGL_CONFIGURE) {
pos.x = view->lastConfigure.x;
pos.y = view->lastConfigure.y;
} else {
const PuglPoint defaultPos = view->positionHints[PUGL_DEFAULT_POSITION];
if (puglIsValidPosition(defaultPos.x, defaultPos.y)) {
pos.x = defaultPos.x;
pos.y = defaultPos.y;
}
}
return pos;
}

// Get the default position if set, or fallback to (0, 0)
int x = view->defaultX;
int y = view->defaultY;
if (x < INT16_MIN || x > INT16_MAX || y < INT16_MIN || y > INT16_MAX) {
x = 0;
y = 0;
return view->positionHints[hint];
}

PuglStatus
puglSetPositionHint(PuglView* const view,
const PuglPositionHint hint,
const int x,
const int y)
{
if (view->world->state == PUGL_WORLD_EXPOSING) {
return PUGL_BAD_CALL;
}

// Return the default frame, sanitized if necessary
const PuglRect frame = {(PuglCoord)x,
(PuglCoord)y,
view->sizeHints[PUGL_DEFAULT_SIZE].width,
view->sizeHints[PUGL_DEFAULT_SIZE].height};
return frame;
if (x <= INT16_MIN || x > INT16_MAX || y <= INT16_MIN || y > INT16_MAX) {
return PUGL_BAD_PARAMETER;
}

view->positionHints[hint].x = (PuglCoord)x;
view->positionHints[hint].y = (PuglCoord)y;

return (hint != PUGL_CURRENT_POSITION) ? PUGL_SUCCESS
: puglGetNativeView(view) ? puglSetWindowPosition(view, x, y)
: PUGL_FAILURE;
}

PuglArea
puglGetSizeHint(const PuglView* const view, const PuglSizeHint hint)
{
if (hint == PUGL_CURRENT_SIZE && view->lastConfigure.type == PUGL_CONFIGURE) {
const PuglArea area = {view->lastConfigure.width,
view->lastConfigure.height};
return area;
}

return view->sizeHints[hint];
}

PuglStatus
puglSetParentWindow(PuglView* view, PuglNativeView parent)
puglSetParent(PuglView* view, PuglNativeView parent)
{
view->parent = parent;
return PUGL_SUCCESS;
}

PuglStatus
puglSetSizeHint(PuglView* const view,
const PuglSizeHint hint,
const unsigned width,
const unsigned height)
{
const PuglStatus st = puglStoreSizeHint(view, hint, width, height);

return st ? st
: (hint != PUGL_CURRENT_SIZE) ? puglApplySizeHint(view, hint)
: puglGetNativeView(view) ? puglSetWindowSize(view, width, height)
: PUGL_FAILURE;
}

PuglNativeView
puglGetParentWindow(const PuglView* const view)
puglGetParent(const PuglView* const view)
{
return view->parent;
}


+ 92
- 7
source/modules/dgl/src/pugl-upstream/src/internal.c View File

@@ -5,19 +5,80 @@

#include "types.h"

#include "pugl/pugl.h"
#include <pugl/pugl.h>

#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

static PuglPoint
make_point(const PuglCoord x, const PuglCoord y)
{
const PuglPoint point = {x, y};
return point;
}

bool
puglIsValidPosition(const int x, const int y)
{
// INT16_MIN is a sentinel, INT16_MAX is impossible with non-zero size
return x > INT16_MIN && x < INT16_MAX && y > INT16_MIN && y < INT16_MAX;
}

bool
puglIsValidSize(const PuglViewSize size)
puglIsValidSize(const unsigned width, const unsigned height)
{
return width && height && width <= INT16_MAX && height <= INT16_MAX;
}

bool
puglIsValidArea(const PuglArea size)
{
return size.width && size.height;
}

PuglArea
puglGetInitialSize(const PuglView* const view)
{
if (view->lastConfigure.type == PUGL_CONFIGURE) {
// Use the last configured size
const PuglConfigureEvent config = view->lastConfigure;
const PuglArea size = {config.width, config.height};
return size;
}

// Use the default size hint set by the application
return view->sizeHints[PUGL_DEFAULT_SIZE];
}

PuglPoint
puglGetInitialPosition(const PuglView* const view, const PuglArea size)
{
if (view->lastConfigure.type == PUGL_CONFIGURE) {
// Use the last configured frame
return make_point(view->lastConfigure.x, view->lastConfigure.y);
}

const PuglPoint defaultPos = view->positionHints[PUGL_DEFAULT_POSITION];
if (puglIsValidPosition(defaultPos.x, defaultPos.y)) {
// Use the default position hint set by the application
return make_point(defaultPos.x, defaultPos.y);
}

if (view->parent) {
// Default to the top/left origin of the parent
return make_point(0, 0);
}

// Center frame on a transient ancestor, or failing that, the screen
const PuglPoint center = puglGetAncestorCenter(view);
const PuglPoint pos = {(PuglCoord)(center.x - (size.width / 2)),
(PuglCoord)(center.y - (size.height / 2))};
return pos;
}

void
puglEnsureHint(PuglView* const view, const PuglViewHint hint, const int value)
{
@@ -68,6 +129,25 @@ puglSetString(char** dest, const char* string)
}
}

PuglStatus
puglStoreSizeHint(PuglView* const view,
const PuglSizeHint hint,
const unsigned width,
const unsigned height)
{
if (view->world->state == PUGL_WORLD_EXPOSING) {
return PUGL_BAD_CALL;
}

if (!puglIsValidSize(width, height)) {
return PUGL_BAD_PARAMETER;
}

view->sizeHints[hint].width = (PuglSpan)width;
view->sizeHints[hint].height = (PuglSpan)height;
return PUGL_SUCCESS;
}

uint32_t
puglDecodeUTF8(const uint8_t* buf)
{
@@ -159,11 +239,12 @@ puglPreRealize(PuglView* const view)
}

// Ensure that the default size is set to a valid size
if (!puglIsValidSize(view->sizeHints[PUGL_DEFAULT_SIZE])) {
if (!puglIsValidArea(view->sizeHints[PUGL_DEFAULT_SIZE])) {
return PUGL_BAD_CONFIGURATION;
}

return PUGL_SUCCESS;
return (view->world->state == PUGL_WORLD_EXPOSING) ? PUGL_BAD_CALL
: PUGL_SUCCESS;
}

PuglStatus
@@ -173,7 +254,7 @@ puglDispatchSimpleEvent(PuglView* view, const PuglEventType type)
type == PUGL_UPDATE || type == PUGL_CLOSE || type == PUGL_LOOP_ENTER ||
type == PUGL_LOOP_LEAVE);

const PuglEvent event = {{type, 0}};
const PuglEvent event = {{type, 0U}};
return puglDispatchEvent(view, &event);
}

@@ -240,8 +321,12 @@ puglDispatchEvent(PuglView* view, const PuglEvent* event)
case PUGL_EXPOSE:
assert(view->stage == PUGL_VIEW_STAGE_CONFIGURED);
if (!(st0 = view->backend->enter(view, &event->expose))) {
st0 = view->eventFunc(view, event);
st1 = view->backend->leave(view, &event->expose);
const PuglWorldState old_state = view->world->state;

view->world->state = PUGL_WORLD_EXPOSING;
st0 = view->eventFunc(view, event);
view->world->state = old_state;
st1 = view->backend->leave(view, &event->expose);
}
break;



+ 31
- 6
source/modules/dgl/src/pugl-upstream/src/internal.h View File

@@ -9,8 +9,8 @@
#include "attributes.h"
#include "types.h"

#include "pugl/attributes.h"
#include "pugl/pugl.h"
#include <pugl/attributes.h>
#include <pugl/pugl.h>

#include <stdbool.h>
#include <stddef.h>
@@ -18,9 +18,29 @@

PUGL_BEGIN_DECLS

/// Return true if `x`,`y` is a valid position
bool
puglIsValidPosition(int x, int y);

/// Return true if `width`,`height` is a valid position
bool
puglIsValidSize(unsigned width, unsigned height);

/// Return true if `size` is a valid view size
bool
puglIsValidSize(PuglViewSize size);
puglIsValidArea(PuglArea size);

/// Return the center point of some "soft" ancestor (parent window or screen)
PuglPoint
puglGetAncestorCenter(const PuglView* view);

/// Return the initial size of a view
PuglArea
puglGetInitialSize(const PuglView* view);

/// Return the initial position of a view if known, or an invalid position
PuglPoint
puglGetInitialPosition(const PuglView* view, PuglArea size);

/// Set hint to a default value if it is unset (PUGL_DONT_CARE)
void
@@ -34,8 +54,14 @@ puglSetBlob(PuglBlob* dest, const void* data, size_t len);
void
puglSetString(char** dest, const char* string);

/// Store `width` and `height` as the current value of a size `hint`
PuglStatus
puglStoreSizeHint(PuglView* view,
PuglSizeHint hint,
unsigned width,
unsigned height);

/// Handle a changed string property
PUGL_API
PuglStatus
puglViewStringChanged(PuglView* view, PuglStringHint key, const char* value);

@@ -56,8 +82,7 @@ PuglStatus
puglDispatchSimpleEvent(PuglView* view, PuglEventType type);

/// Process configure event while already in the graphics context
PUGL_WARN_UNUSED_RESULT
PuglStatus
PUGL_WARN_UNUSED_RESULT PuglStatus
puglConfigure(PuglView* view, const PuglEvent* event);

/// Dispatch `event` to `view`, entering graphics context if necessary


+ 1
- 1
source/modules/dgl/src/pugl-upstream/src/mac.h View File

@@ -5,7 +5,7 @@
#ifndef PUGL_SRC_MAC_H
#define PUGL_SRC_MAC_H

#include "pugl/pugl.h"
#include <pugl/pugl.h>

#import <Cocoa/Cocoa.h>



+ 142
- 225
source/modules/dgl/src/pugl-upstream/src/mac.m View File

@@ -7,9 +7,10 @@
#include "mac.h"

#include "internal.h"
#include "macros.h"
#include "platform.h"

#include "pugl/pugl.h"
#include <pugl/pugl.h>

#import <Cocoa/Cocoa.h>

@@ -121,7 +122,7 @@ viewScreen(const PuglView* view)
}

static NSRect
nsRectToPoints(PuglView* view, const NSRect rect)
nsRectToPoints(const PuglView* view, const NSRect rect)
{
const double scaleFactor = [viewScreen(view) backingScaleFactor];

@@ -132,7 +133,7 @@ nsRectToPoints(PuglView* view, const NSRect rect)
}

static NSRect
nsRectFromPoints(PuglView* view, const NSRect rect)
nsRectFromPoints(const PuglView* view, const NSRect rect)
{
const double scaleFactor = [viewScreen(view) backingScaleFactor];

@@ -143,21 +144,15 @@ nsRectFromPoints(PuglView* view, const NSRect rect)
}

static NSPoint
nsPointFromPoints(PuglView* view, const NSPoint point)
nsPointFromPoints(const PuglView* view, const NSPoint point)
{
const double scaleFactor = [viewScreen(view) backingScaleFactor];

return NSMakePoint(point.x * scaleFactor, point.y * scaleFactor);
}

static NSRect
rectToNsRect(const PuglRect rect)
{
return NSMakeRect(rect.x, rect.y, rect.width, rect.height);
}

static NSSize
sizePoints(PuglView* view, const double width, const double height)
sizePoints(PuglView* view, const PuglSpan width, const PuglSpan height)
{
const double scaleFactor = [viewScreen(view) backingScaleFactor];

@@ -188,7 +183,7 @@ getCurrentViewStyleFlags(PuglView* const view)
}

static PuglStatus
dispatchCurrentChildViewConfiguration(PuglView* const view, bool drawViewResize)
dispatchCurrentChildViewConfiguration(PuglView* const view)
{
const NSRect framePt = [view->impl->wrapperView frame];
const NSRect framePx = nsRectFromPoints(view, framePt);
@@ -197,14 +192,9 @@ dispatchCurrentChildViewConfiguration(PuglView* const view, bool drawViewResize)
return PUGL_SUCCESS;
}

if (drawViewResize) {
const NSSize sizePt = [view->impl->drawView convertSizeFromBacking:framePx.size];
[view->impl->drawView setFrameSize:sizePt];
}

const PuglConfigureEvent ev = {
PUGL_CONFIGURE,
0,
0U,
(PuglCoord)framePx.origin.x,
(PuglCoord)framePx.origin.y,
(PuglSpan)framePx.size.width,
@@ -254,7 +244,7 @@ dispatchCurrentChildViewConfiguration(PuglView* const view, bool drawViewResize)

const PuglConfigureEvent ev = {
PUGL_CONFIGURE,
0,
0U,
(PuglCoord)contentPx.origin.x,
(PuglCoord)(screenHeight - contentPx.origin.y - contentPx.size.height),
(PuglSpan)contentPx.size.width,
@@ -322,7 +312,7 @@ dispatchCurrentChildViewConfiguration(PuglView* const view, bool drawViewResize)
if (puglview->impl->window) {
[puglview->impl->window dispatchCurrentConfiguration];
} else {
dispatchCurrentChildViewConfiguration(puglview, true);
dispatchCurrentChildViewConfiguration(puglview);
}
reshaped = false;
}
@@ -336,7 +326,7 @@ dispatchCurrentChildViewConfiguration(PuglView* const view, bool drawViewResize)

const PuglExposeEvent ev = {
PUGL_EXPOSE,
0,
0U,
(PuglCoord)(rect.origin.x * scaleFactor),
(PuglCoord)viewY,
(PuglSpan)(rect.size.width * scaleFactor),
@@ -350,9 +340,9 @@ dispatchCurrentChildViewConfiguration(PuglView* const view, bool drawViewResize)

- (NSSize)intrinsicContentSize
{
const PuglViewSize defaultSize = puglview->sizeHints[PUGL_DEFAULT_SIZE];
const PuglArea defaultSize = puglview->sizeHints[PUGL_DEFAULT_SIZE];

return puglIsValidSize(defaultSize)
return puglIsValidArea(defaultSize)
? sizePoints(puglview, defaultSize.width, defaultSize.height)
: NSMakeSize(NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric);
}
@@ -468,7 +458,7 @@ keySymToSpecial(const NSEvent* const ev)
return PUGL_KEY_PAD_9;
}

return (PuglKey)0;
return PUGL_KEY_NONE;
}

- (void)updateTrackingAreas
@@ -501,7 +491,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)
const NSPoint rloc = [NSEvent mouseLocation];
const PuglCrossingEvent ev = {
type,
0,
0U,
[event timestamp],
wloc.x,
wloc.y,
@@ -542,7 +532,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)
const NSPoint rloc = [NSEvent mouseLocation];
const PuglMotionEvent ev = {
PUGL_MOTION,
0,
0U,
[event timestamp],
wloc.x,
wloc.y,
@@ -577,7 +567,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)
const NSPoint rloc = [NSEvent mouseLocation];
const PuglButtonEvent ev = {
PUGL_BUTTON_PRESS,
0,
0U,
[event timestamp],
wloc.x,
wloc.y,
@@ -598,7 +588,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)
const NSPoint rloc = [NSEvent mouseLocation];
const PuglButtonEvent ev = {
PUGL_BUTTON_RELEASE,
0,
0U,
[event timestamp],
wloc.x,
wloc.y,
@@ -638,11 +628,11 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)
const NSPoint wloc = [self eventLocation:event];
const NSPoint rloc = [NSEvent mouseLocation];

double dx = -[event scrollingDeltaX] / 2.0;
double dy = [event scrollingDeltaY] / 2.0;
double dx = -[event scrollingDeltaX];
double dy = [event scrollingDeltaY];
if ([event hasPreciseScrollingDeltas]) {
dx /= 10.0;
dy /= 10.0;
dx /= 20.0;
dy /= 20.0;
}

const PuglScrollDirection dir =
@@ -657,7 +647,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)

const PuglScrollEvent ev = {
PUGL_SCROLL,
0,
0U,
[event timestamp],
wloc.x,
wloc.y,
@@ -689,7 +679,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)

const PuglKeyEvent ev = {
PUGL_KEY_PRESS,
0,
0U,
[event timestamp],
wloc.x,
wloc.y,
@@ -720,7 +710,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)

const PuglKeyEvent ev = {
PUGL_KEY_RELEASE,
0,
0U,
[event timestamp],
wloc.x,
wloc.y,
@@ -832,7 +822,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)

PuglTextEvent ev = {
PUGL_TEXT,
0,
0U,
[event timestamp],
wloc.x,
wloc.y,
@@ -861,7 +851,7 @@ flagDiffers(const uint32_t lhs, const uint32_t rhs, const uint32_t mask)
- (void)flagsChanged:(NSEvent*)event
{
const uint32_t mods = getModifiers(event);
PuglKey special = (PuglKey)0;
PuglKey special = PUGL_KEY_NONE;

const uint16_t keyCode = [event keyCode];
if (flagDiffers(mods, puglview->impl->mods, PUGL_MOD_SHIFT)) {
@@ -882,7 +872,7 @@ flagDiffers(const uint32_t lhs, const uint32_t rhs, const uint32_t mask)
const bool release = [event type] == NSEventTypeKeyUp;

const PuglKeyEvent ev = {release ? PUGL_KEY_RELEASE : PUGL_KEY_PRESS,
0,
0U,
[event timestamp],
wloc.x,
wloc.y,
@@ -924,7 +914,7 @@ flagDiffers(const uint32_t lhs, const uint32_t rhs, const uint32_t mask)
- (void)timerTick:(NSTimer*)userTimer
{
const NSNumber* userInfo = userTimer.userInfo;
const PuglTimerEvent ev = {PUGL_TIMER, 0, userInfo.unsignedLongValue};
const PuglTimerEvent ev = {PUGL_TIMER, 0U, userInfo.unsignedLongValue};

PuglEvent timerEvent;
timerEvent.timer = ev;
@@ -989,7 +979,7 @@ flagDiffers(const uint32_t lhs, const uint32_t rhs, const uint32_t mask)
{
(void)notification;

PuglEvent ev = {{PUGL_FOCUS_IN, 0}};
PuglEvent ev = {{PUGL_FOCUS_IN, 0U}};
ev.focus.mode = PUGL_CROSSING_NORMAL;
puglDispatchEvent(window->puglview, &ev);
}
@@ -998,7 +988,7 @@ flagDiffers(const uint32_t lhs, const uint32_t rhs, const uint32_t mask)
{
(void)notification;

PuglEvent ev = {{PUGL_FOCUS_OUT, 0}};
PuglEvent ev = {{PUGL_FOCUS_OUT, 0U}};
ev.focus.mode = PUGL_CROSSING_NORMAL;
puglDispatchEvent(window->puglview, &ev);
}
@@ -1117,17 +1107,18 @@ puglConstraint(const id item,
constant:(CGFloat)constant];
}

static PuglStatus
updateSizeHint(PuglView* const view, const PuglSizeHint hint)
PuglStatus
puglApplySizeHint(PuglView* const view, const PuglSizeHint hint)
{
const PuglSpan width = view->sizeHints[hint].width;
const PuglSpan height = view->sizeHints[hint].height;
if (!puglIsValidSize(view->sizeHints[hint])) {
if (!puglIsValidArea(view->sizeHints[hint])) {
return PUGL_FAILURE;
}

switch (hint) {
case PUGL_DEFAULT_SIZE:
case PUGL_CURRENT_SIZE:
break;

case PUGL_MIN_SIZE:
@@ -1150,38 +1141,18 @@ updateSizeHint(PuglView* const view, const PuglSizeHint hint)
return PUGL_SUCCESS;
}

static void
updateSizeHints(PuglView* const view)
PuglStatus
puglUpdateSizeHints(PuglView* const view)
{
for (unsigned i = 0U; i < PUGL_NUM_SIZE_HINTS; ++i) {
updateSizeHint(view, (PuglSizeHint)i);
puglApplySizeHint(view, (PuglSizeHint)i);
}
return PUGL_SUCCESS;
}

static PuglRect
getInitialFrame(PuglView* const view)
PuglPoint
puglGetAncestorCenter(const PuglView* const view)
{
if (view->lastConfigure.type == PUGL_CONFIGURE) {
// Use the last configured frame
const PuglRect frame = {view->lastConfigure.x,
view->lastConfigure.y,
view->lastConfigure.width,
view->lastConfigure.height};
return frame;
}

const int x = view->defaultX;
const int y = view->defaultY;
if (x >= INT16_MIN && x <= INT16_MAX && y >= INT16_MIN && y <= INT16_MAX) {
// Use the default position set with puglSetPosition while unrealized
const PuglRect frame = {(PuglCoord)x,
(PuglCoord)y,
view->sizeHints[PUGL_DEFAULT_SIZE].width,
view->sizeHints[PUGL_DEFAULT_SIZE].height};
return frame;
}

// Get a bounding rect from the transient parent or the screen
const NSScreen* const screen = viewScreen(view);
const NSRect boundsPt =
rectFromScreen(screen,
@@ -1189,17 +1160,11 @@ getInitialFrame(PuglView* const view)
? [[(const NSView*)view->transientParent window] frame]
: [screen frame]);

// Center the frame around the center of the bounding rectangle
const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE];
const NSRect boundsPx = nsRectFromPoints(view, boundsPt);
const double centerX = boundsPx.origin.x + boundsPx.size.width / 2;
const double centerY = boundsPx.origin.y + boundsPx.size.height / 2;

const PuglRect frame = {(PuglCoord)(centerX - (defaultSize.width / 2U)),
(PuglCoord)(centerY - (defaultSize.height / 2U)),
view->sizeHints[PUGL_DEFAULT_SIZE].width,
view->sizeHints[PUGL_DEFAULT_SIZE].height};
return frame;
const NSRect boundsPx = nsRectFromPoints(view, boundsPt);
const PuglPoint center = {
(PuglCoord)(boundsPx.origin.x + (boundsPx.size.width / 2.0)),
(PuglCoord)(boundsPx.origin.y + (boundsPx.size.height / 2.0))};
return center;
}

PuglStatus
@@ -1247,11 +1212,12 @@ puglRealize(PuglView* view)
CVDisplayLinkRelease(link);
}

// Get the initial frame to use from the defaults or last configuration
const PuglRect initialFrame = getInitialFrame(view);
// Get the initial size and position from the defaults or last configuration
const PuglArea size = puglGetInitialSize(view);
const PuglPoint pos = puglGetInitialPosition(view, size);

// Convert frame to points
const NSRect framePx = rectToNsRect(initialFrame);
const NSRect framePx = NSMakeRect(pos.x, pos.y, size.width, size.height);
const NSRect framePt = NSMakeRect(framePx.origin.x / scaleFactor,
framePx.origin.y / scaleFactor,
framePx.size.width / scaleFactor,
@@ -1277,7 +1243,7 @@ puglRealize(PuglView* view)
NSLayoutRelationGreaterThanOrEqual,
view->sizeHints[PUGL_MIN_SIZE].height)];

if (puglIsValidSize(view->sizeHints[PUGL_MAX_SIZE])) {
if (puglIsValidArea(view->sizeHints[PUGL_MAX_SIZE])) {
[impl->wrapperView
addConstraint:puglConstraint(impl->wrapperView,
NSLayoutAttributeWidth,
@@ -1337,10 +1303,19 @@ puglRealize(PuglView* view)
((NSWindow*)window).delegate =
[[PuglWindowDelegate alloc] initWithPuglWindow:window];

// Set basic window hints and attributes
puglSetFrame(view, initialFrame);
// Set window frame
const NSRect screenPt = rectToScreen(screen, framePt);
const NSRect winFrame = [impl->window frameRectForContentRect:screenPt];
[impl->window setFrame:winFrame display:NO];

// Resize views and move them to (0, 0)
const NSRect sizePx = {{0, 0}, {framePx.size.width, framePx.size.height}};
const NSRect sizePt = [impl->drawView convertRectFromBacking:sizePx];
[impl->wrapperView setFrame:sizePt];
[impl->drawView setFrame:sizePt];

puglSetTransientParent(view, view->transientParent);
updateSizeHints(view);
puglUpdateSizeHints(view);

[window setContentView:impl->wrapperView];
[view->world->impl->app activateIgnoringOtherApps:YES];
@@ -1393,24 +1368,23 @@ puglUnrealize(PuglView* const view)
PuglStatus
puglShow(PuglView* view, const PuglShowCommand command)
{
if (!view->impl->wrapperView) {
const PuglStatus st = puglRealize(view);
if (st) {
return st;
}
PuglInternals* impl = view->impl;
PuglStatus st = impl->wrapperView ? PUGL_SUCCESS : puglRealize(view);
if (st || !impl->wrapperView) {
return st;
}

NSWindow* const window = [view->impl->wrapperView window];
NSWindow* const window = [impl->wrapperView window];
if (![window isVisible]) {
[window setIsVisible:YES];
[view->impl->drawView setNeedsDisplay:YES];
[impl->drawView setNeedsDisplay:YES];
}

switch (command) {
case PUGL_SHOW_PASSIVE:
break;
case PUGL_SHOW_RAISE:
[window orderFront:view->impl->wrapperView];
[window orderFront:impl->wrapperView];
break;
case PUGL_SHOW_FORCE_RAISE:
[window orderFrontRegardless];
@@ -1583,6 +1557,10 @@ puglStopTimer(PuglView* view, uintptr_t id)
PuglStatus
puglSendEvent(PuglView* view, const PuglEvent* event)
{
if (!view->impl->window || view->world->state == PUGL_WORLD_EXPOSING) {
return PUGL_FAILURE;
}

if (event->type == PUGL_CLIENT) {
PuglEvent copiedEvent = *event;

@@ -1610,18 +1588,17 @@ puglSendEvent(PuglView* view, const PuglEvent* event)
return PUGL_UNSUPPORTED;
}

#ifndef PUGL_DISABLE_DEPRECATED
PuglStatus
puglWaitForEvent(PuglView* view)
{
return puglPollEvents(view->world, -1.0);
}
#endif

PuglStatus
puglUpdate(PuglWorld* world, const double timeout)
{
@autoreleasepool {
const PuglWorldState startState = world->state;
if (startState == PUGL_WORLD_IDLE) {
world->state = PUGL_WORLD_UPDATING;
} else if (startState != PUGL_WORLD_RECURSING) {
return PUGL_BAD_CALL;
}

if (world->type == PUGL_PROGRAM) {
NSDate* date =
((timeout < 0) ? [NSDate distantFuture]
@@ -1650,19 +1627,13 @@ puglUpdate(PuglWorld* world, const double timeout)

[view->impl->drawView displayIfNeeded];
}

world->state = startState;
}

return PUGL_SUCCESS;
}

#ifndef PUGL_DISABLE_DEPRECATED
PuglStatus
puglProcessEvents(PuglView* view)
{
return puglDispatchEvents(view->world);
}
#endif

double
puglGetTime(const PuglWorld* world)
{
@@ -1674,22 +1645,45 @@ puglGetTime(const PuglWorld* world)
}

PuglStatus
puglPostRedisplay(PuglView* view)
puglObscureView(PuglView* view)
{
if (view->world->state == PUGL_WORLD_EXPOSING) {
return PUGL_BAD_CALL;
}

[view->impl->drawView setNeedsDisplay:YES];
return PUGL_SUCCESS;
}

PuglStatus
puglPostRedisplayRect(PuglView* view, const PuglRect rect)
puglObscureRegion(PuglView* view,
const int x,
const int y,
const unsigned width,
const unsigned height)
{
const NSRect rectPx = {
{(double)rect.x,
(double)view->lastConfigure.height - (rect.y + rect.height)},
{(double)rect.width, (double)rect.height},
};
if (view->world->state == PUGL_WORLD_EXPOSING) {
return PUGL_BAD_CALL;
}

if (!puglIsValidPosition(x, y) || !puglIsValidSize(width, height)) {
return PUGL_BAD_PARAMETER;
}

const PuglSpan viewHeight = view->lastConfigure.height;

const int cx = MAX(0, x);
const int cy = MAX(0, viewHeight - y - (int)height);
const unsigned cw = MIN(view->lastConfigure.width, width);
const unsigned ch = MIN(view->lastConfigure.height, height);

if (cw == view->lastConfigure.width && ch == view->lastConfigure.height) {
[view->impl->drawView setNeedsDisplay:YES];
} else {
const NSRect rectPx = NSMakeRect(cx, cy, cw, ch);

[view->impl->drawView setNeedsDisplayInRect:nsRectToPoints(view, rectPx)];
[view->impl->drawView setNeedsDisplayInRect:nsRectToPoints(view, rectPx)];
}

return PUGL_SUCCESS;
}
@@ -1735,107 +1729,35 @@ puglGetScaleFactor(const PuglView* const view)
}

PuglStatus
puglSetFrame(PuglView* view, const PuglRect frame)
{
PuglInternals* const impl = view->impl;
const NSRect framePx = rectToNsRect(frame);
const NSRect framePt = nsRectToPoints(view, framePx);

if (!impl->wrapperView) {
// Set defaults to be used when realized
view->defaultX = frame.x;
view->defaultY = frame.y;
view->sizeHints[PUGL_DEFAULT_SIZE].width = (PuglSpan)frame.width;
view->sizeHints[PUGL_DEFAULT_SIZE].height = (PuglSpan)frame.height;
return PUGL_SUCCESS;
}

if (impl->window) {
const NSRect screenPt = rectToScreen(viewScreen(view), framePt);

// Move and resize window to fit new content rect
const NSRect winFrame = [impl->window frameRectForContentRect:screenPt];
[impl->window setFrame:winFrame display:NO];

// Resize views
const NSRect sizePx = NSMakeRect(0, 0, frame.width, frame.height);
const NSRect sizePt = [impl->drawView convertRectFromBacking:sizePx];
[impl->wrapperView setFrame:sizePt];
[impl->drawView setFrame:sizePt];
[impl->window dispatchCurrentConfiguration];
return PUGL_SUCCESS;
}

// Resize view
const NSRect sizePx = NSMakeRect(0, 0, frame.width, frame.height);
const NSRect sizePt = [impl->drawView convertRectFromBacking:sizePx];

[impl->wrapperView setFrame:framePt];
[impl->drawView setFrame:sizePt];
return dispatchCurrentChildViewConfiguration(view, false);
}

PuglStatus
puglSetPosition(PuglView* const view, const int x, const int y)
puglSetWindowPosition(PuglView* const view, const int x, const int y)
{
if (x < INT16_MIN || x > INT16_MAX || y < INT16_MIN || y > INT16_MAX) {
return PUGL_BAD_PARAMETER;
}

PuglInternals* const impl = view->impl;
if (!impl->wrapperView) {
// Set defaults to be used when realized
view->defaultX = x;
view->defaultY = y;
return PUGL_SUCCESS;
}

const PuglRect frame = {(PuglCoord)x,
(PuglCoord)y,
view->lastConfigure.width,
view->lastConfigure.height};
const NSRect framePx =
NSMakeRect(x, y, view->lastConfigure.width, view->lastConfigure.height);

const NSRect framePt = nsRectToPoints(view, framePx);

if (impl->window) {
// Adjust top-level window frame
return puglSetFrame(view, frame);
const NSRect screenPt = rectToScreen(viewScreen(view), framePt);
[impl->window setFrameOrigin:screenPt.origin];
return PUGL_SUCCESS;
}

// Set wrapper view origin
const NSRect framePx = rectToNsRect(frame);
const NSRect framePt = nsRectToPoints(view, framePx);
[impl->wrapperView setFrameOrigin:framePt.origin];

// Set draw view origin
const NSRect drawPx = NSMakeRect(0, 0, frame.width, frame.height);
const NSRect drawPt = [impl->drawView convertRectFromBacking:drawPx];
[impl->drawView setFrameOrigin:drawPt.origin];

// Dispatch new configuration
return dispatchCurrentChildViewConfiguration(view, false);
return dispatchCurrentChildViewConfiguration(view);
}

PuglStatus
puglSetSize(PuglView* const view, const unsigned width, const unsigned height)
puglSetWindowSize(PuglView* const view,
const unsigned width,
const unsigned height)
{
if (width > INT16_MAX || height > INT16_MAX) {
return PUGL_BAD_PARAMETER;
}

PuglInternals* const impl = view->impl;
if (!impl->wrapperView) {
// Set defaults to be used when realized
view->sizeHints[PUGL_DEFAULT_SIZE].width = (PuglSpan)width;
view->sizeHints[PUGL_DEFAULT_SIZE].height = (PuglSpan)height;
return PUGL_SUCCESS;
}

if (impl->window) {
// Adjust top-level window frame
PuglRect frame = puglGetFrame(view);
frame.width = (PuglSpan)width;
frame.height = (PuglSpan)height;
return puglSetFrame(view, frame);
}

// Set wrapper view size
const double scaleFactor = [viewScreen(view) backingScaleFactor];
@@ -1847,24 +1769,20 @@ puglSetSize(PuglView* const view, const unsigned width, const unsigned height)
const NSRect drawPt = [impl->drawView convertRectFromBacking:drawPx];
[impl->drawView setFrameSize:drawPt.size];

// Dispatch new configuration
return dispatchCurrentChildViewConfiguration(view, false);
}
if (impl->window) {
const NSRect framePx =
NSMakeRect(view->lastConfigure.x, view->lastConfigure.y, width, height);
const NSRect framePt = nsRectToPoints(view, framePx);
const NSRect screenPt = rectToScreen(viewScreen(view), framePt);

PuglStatus
puglSetSizeHint(PuglView* const view,
const PuglSizeHint hint,
const PuglSpan width,
const PuglSpan height)
{
if ((unsigned)hint >= PUGL_NUM_SIZE_HINTS) {
return PUGL_BAD_PARAMETER;
// Resize window to fit new content rect
const NSRect winFrame = [impl->window frameRectForContentRect:screenPt];
[impl->window setFrame:winFrame display:NO];
[impl->window dispatchCurrentConfiguration];
}

view->sizeHints[hint].width = width;
view->sizeHints[hint].height = height;

return view->impl->window ? updateSizeHint(view, hint) : PUGL_SUCCESS;
// Dispatch new configuration
return dispatchCurrentChildViewConfiguration(view);
}

PuglStatus
@@ -1892,7 +1810,7 @@ puglPaste(PuglView* const view)
{
const PuglDataOfferEvent offer = {
PUGL_DATA_OFFER,
0,
0U,
puglGetTime(view->world),
};

@@ -1939,7 +1857,7 @@ puglAcceptOffer(PuglView* const view,
PuglWrapperView* const wrapper = view->impl->wrapperView;
NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard];
if (!pasteboard) {
return PUGL_BAD_PARAMETER;
return PUGL_UNKNOWN_ERROR;
}

const NSArray<NSPasteboardType>* const types = [pasteboard types];
@@ -1950,13 +1868,12 @@ puglAcceptOffer(PuglView* const view,
wrapper->dragOperation = NSDragOperationCopy;
wrapper->dragTypeIndex = typeIndex;

const PuglDataEvent data = {
PUGL_DATA, 0U, puglGetTime(view->world), (uint32_t)typeIndex};
const double now = puglGetTime(view->world);
const PuglDataEvent data = {PUGL_DATA, 0U, now, typeIndex};

PuglEvent dataEvent;
dataEvent.data = data;
puglDispatchEvent(view, &dataEvent);
return PUGL_SUCCESS;
return puglDispatchEvent(view, &dataEvent);
}

const void*


+ 1
- 1
source/modules/dgl/src/pugl-upstream/src/mac_cairo.m View File

@@ -5,7 +5,7 @@
#include "mac.h"
#include "stub.h"

#include "pugl/cairo.h"
#include <pugl/cairo.h>

#include <cairo-quartz.h>



+ 1
- 1
source/modules/dgl/src/pugl-upstream/src/mac_gl.m View File

@@ -5,7 +5,7 @@
#include "mac.h"
#include "stub.h"

#include "pugl/gl.h"
#include <pugl/gl.h>

#ifndef __MAC_10_10
# define NSOpenGLProfileVersion4_1Core NSOpenGLProfileVersion3_2Core


+ 1
- 1
source/modules/dgl/src/pugl-upstream/src/mac_stub.m View File

@@ -5,7 +5,7 @@
#include "mac.h"
#include "stub.h"

#include "pugl/stub.h"
#include <pugl/stub.h>

#import <Cocoa/Cocoa.h>



+ 3
- 3
source/modules/dgl/src/pugl-upstream/src/mac_vulkan.m View File

@@ -8,9 +8,9 @@
#include "stub.h"
#include "types.h"

#include "pugl/pugl.h"
#include "pugl/stub.h"
#include "pugl/vulkan.h"
#include <pugl/pugl.h>
#include <pugl/stub.h>
#include <pugl/vulkan.h>

#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_macos.h>


+ 22
- 7
source/modules/dgl/src/pugl-upstream/src/platform.h View File

@@ -1,20 +1,20 @@
// Copyright 2012-2022 David Robillard <d@drobilla.net>
// Copyright 2012-2025 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC

// The API that a platform implementation must define
// The internal API that a platform implementation must define

#ifndef PUGL_PLATFORM_H
#define PUGL_PLATFORM_H

#include "types.h"

#include "pugl/pugl.h"
#include <pugl/attributes.h>
#include <pugl/pugl.h>

PUGL_BEGIN_DECLS

/// Allocate and initialise world internals (implemented once per platform)
PUGL_MALLOC_FUNC
PuglWorldInternals*
PUGL_MALLOC_FUNC PuglWorldInternals*
puglInitWorldInternals(PuglWorldType type, PuglWorldFlags flags);

/// Destroy and free world internals (implemented once per platform)
@@ -22,14 +22,29 @@ void
puglFreeWorldInternals(PuglWorld* world);

/// Allocate and initialise view internals (implemented once per platform)
PUGL_MALLOC_FUNC
PuglInternals*
PUGL_MALLOC_FUNC PuglInternals*
puglInitViewInternals(PuglWorld* world);

/// Destroy and free view internals (implemented once per platform)
void
puglFreeViewInternals(PuglView* view);

/// Adapt to the change of a size hint if necessary
PuglStatus
puglApplySizeHint(PuglView* view, PuglSizeHint hint);

/// Adapt to all configured size hints
PuglStatus
puglUpdateSizeHints(PuglView* view);

/// Set the current position of a view window
PuglStatus
puglSetWindowPosition(PuglView* view, int x, int y);

/// Set the current size of a view window
PuglStatus
puglSetWindowSize(PuglView* view, unsigned width, unsigned height);

PUGL_END_DECLS

#endif // PUGL_PLATFORM_H

+ 2
- 1
source/modules/dgl/src/pugl-upstream/src/stub.h View File

@@ -4,7 +4,8 @@
#ifndef PUGL_SRC_STUB_H
#define PUGL_SRC_STUB_H

#include "pugl/pugl.h"
#include <pugl/attributes.h>
#include <pugl/pugl.h>

#include <stddef.h>



+ 18
- 24
source/modules/dgl/src/pugl-upstream/src/types.h View File

@@ -6,7 +6,7 @@

#include "attributes.h"

#include "pugl/pugl.h"
#include <pugl/pugl.h>

#include <stdbool.h>
#include <stddef.h>
@@ -21,24 +21,20 @@ typedef struct PuglInternalsImpl PuglInternals;
/// View hints
typedef int PuglHints[PUGL_NUM_VIEW_HINTS];

/// View position (both X and Y coordinates) or general point
typedef struct {
PuglCoord x;
PuglCoord y;
} PuglPoint;

/// View size (both X and Y coordinates)
typedef struct {
PuglSpan width;
PuglSpan height;
} PuglViewSize;

/// Blob of arbitrary data
typedef struct {
void* data; ///< Dynamically allocated data
size_t len; ///< Length of data in bytes
} PuglBlob;

/// State of the world in the process of an update
typedef enum {
PUGL_WORLD_IDLE, ///< Idle, not in puglUpdate()
PUGL_WORLD_UPDATING, ///< Event processing stage of puglUpdate()
PUGL_WORLD_EXPOSING, ///< Exposing stage of puglUpdate()
PUGL_WORLD_RECURSING, ///< Currently in recursive loop (Windows)
} PuglWorldState;

/// Stage of a view along its lifespan
typedef enum {
PUGL_VIEW_STAGE_ALLOCATED,
@@ -57,10 +53,9 @@ struct PuglViewImpl {
uintptr_t transientParent;
PuglConfigureEvent lastConfigure;
PuglHints hints;
PuglViewSize sizeHints[PUGL_NUM_SIZE_HINTS];
PuglPoint positionHints[PUGL_NUM_POSITION_HINTS];
PuglArea sizeHints[PUGL_NUM_SIZE_HINTS];
char* strings[PUGL_NUM_STRING_HINTS];
int defaultX;
int defaultY;
PuglViewStage stage;
bool resizing;
};
@@ -74,6 +69,7 @@ struct PuglWorldImpl {
PuglView** views;
char* strings[PUGL_NUM_STRING_HINTS];
PuglWorldType type;
PuglWorldState state;
};

/// Opaque surface used by graphics backend
@@ -82,23 +78,21 @@ typedef void PuglSurface;
/// Graphics backend interface
struct PuglBackendImpl {
/// Get visual information from display and setup view as necessary
PUGL_WARN_UNUSED_RESULT
PuglStatus (*configure)(PuglView*);
PUGL_WARN_UNUSED_RESULT PuglStatus (*configure)(PuglView*);

/// Create surface and drawing context
PUGL_WARN_UNUSED_RESULT
PuglStatus (*create)(PuglView*);
PUGL_WARN_UNUSED_RESULT PuglStatus (*create)(PuglView*);

/// Destroy surface and drawing context
void (*destroy)(PuglView*);

/// Enter drawing context, for drawing if expose is non-null
PUGL_WARN_UNUSED_RESULT
PuglStatus (*enter)(PuglView*, const PuglExposeEvent*);
PUGL_WARN_UNUSED_RESULT PuglStatus (*enter)(PuglView*,
const PuglExposeEvent*);

/// Leave drawing context, after drawing if expose is non-null
PUGL_WARN_UNUSED_RESULT
PuglStatus (*leave)(PuglView*, const PuglExposeEvent*);
PUGL_WARN_UNUSED_RESULT PuglStatus (*leave)(PuglView*,
const PuglExposeEvent*);

/// Return the puglGetContext() handle for the application, if any
void* (*getContext)(PuglView*);


+ 247
- 296
source/modules/dgl/src/pugl-upstream/src/win.c View File

@@ -4,9 +4,10 @@
#include "win.h"

#include "internal.h"
#include "macros.h"
#include "platform.h"

#include "pugl/pugl.h"
#include <pugl/pugl.h>

#include <dwmapi.h>
#include <windows.h>
@@ -42,13 +43,11 @@
#define PUGL_USER_TIMER_MIN 9470

#ifdef __cplusplus
# define PUGL_INIT_STRUCT \
{}
#else
# define PUGL_INIT_STRUCT \
{ \
0 \
}
#else
# define PUGL_INIT_STRUCT {0}
#endif

typedef BOOL(WINAPI* PFN_SetProcessDPIAware)(void);
@@ -58,8 +57,12 @@ typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*);
LRESULT CALLBACK
wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

static wchar_t*
puglUtf8ToWideChar(const char* const utf8)
#ifdef UNICODE

typedef wchar_t ArgStringChar;

static ArgStringChar*
puglArgStringNew(const char* const utf8)
{
const int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
if (len > 0) {
@@ -71,6 +74,30 @@ puglUtf8ToWideChar(const char* const utf8)
return NULL;
}

static void
puglArgStringFree(ArgStringChar* const utf8)
{
free(utf8);
}

#else // !defined(UNICODE)

typedef const char ArgStringChar;

static ArgStringChar*
puglArgStringNew(const char* const utf8)
{
return utf8;
}

static void
puglArgStringFree(ArgStringChar* const utf8)
{
(void)utf8;
}

#endif

static char*
puglWideCharToUtf8(const wchar_t* const wstr, size_t* len)
{
@@ -94,11 +121,7 @@ puglWinStatus(const BOOL success)
static bool
puglRegisterWindowClass(const char* name)
{
#ifdef UNICODE
wchar_t* const wname = puglUtf8ToWideChar(name);
#else
const char* const wname = name;
#endif
ArgStringChar* const nameArg = puglArgStringNew(name);

HMODULE module = NULL;
if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
@@ -109,7 +132,7 @@ puglRegisterWindowClass(const char* name)
}

WNDCLASSEX wc = PUGL_INIT_STRUCT;
if (GetClassInfoEx(module, wname, &wc)) {
if (GetClassInfoEx(module, nameArg, &wc)) {
return true; // Already registered
}

@@ -120,12 +143,10 @@ puglRegisterWindowClass(const char* name)
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszClassName = wname;
wc.lpszClassName = nameArg;

const bool success = !!RegisterClassEx(&wc);
#ifdef UNICODE
free(wname);
#endif
puglArgStringFree(nameArg);
return success;
}

@@ -184,7 +205,7 @@ static double
puglWinGetViewScaleFactor(const PuglView* const view)
{
const HMODULE shcore =
LoadLibraryExA("Shcore.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
LoadLibraryEx(TEXT("Shcore.dll"), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!shcore) {
return 1.0;
}
@@ -219,7 +240,7 @@ puglInitWorldInternals(PuglWorldType type, PuglWorldFlags PUGL_UNUSED(flags))

if (type == PUGL_PROGRAM) {
HMODULE user32 =
LoadLibraryExA("user32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
LoadLibraryEx(TEXT("user32.dll"), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (user32) {
PFN_SetProcessDPIAware SetProcessDPIAware =
(PFN_SetProcessDPIAware)GetProcAddress(user32, "SetProcessDPIAware");
@@ -250,20 +271,6 @@ puglInitViewInternals(PuglWorld* PUGL_UNUSED(world))
return (PuglInternals*)calloc(1, sizeof(PuglInternals));
}

static PuglStatus
puglPollWinEvents(PuglWorld* world, const double timeout)
{
(void)world;

if (timeout < 0) {
WaitMessage();
} else {
MsgWaitForMultipleObjects(
0, NULL, FALSE, (DWORD)(timeout * 1e3), QS_ALLEVENTS);
}
return PUGL_SUCCESS;
}

PuglStatus
puglRealize(PuglView* view)
{
@@ -287,9 +294,9 @@ puglRealize(PuglView* view)
puglEnsureHint(view, PUGL_ALPHA_BITS, 8);

// Get refresh rate for resize draw timer
DEVMODEA devMode;
DEVMODE devMode;
memset(&devMode, 0, sizeof(devMode));
EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devMode);
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devMode);
view->hints[PUGL_REFRESH_RATE] = (int)devMode.dmDisplayFrequency;

// Register window class if necessary
@@ -308,16 +315,16 @@ puglRealize(PuglView* view)
puglSetViewString(view, PUGL_WINDOW_TITLE, view->strings[PUGL_WINDOW_TITLE]);
puglSetTransientParent(view, view->transientParent);

view->impl->scaleFactor = puglWinGetViewScaleFactor(view);
view->impl->cursor = LoadCursor(NULL, IDC_ARROW);
impl->scaleFactor = puglWinGetViewScaleFactor(view);
impl->cursor = LoadCursor(NULL, IDC_ARROW);

if (view->hints[PUGL_DARK_FRAME]) {
const BOOL useDarkMode = TRUE;
if ((DwmSetWindowAttribute(view->impl->hwnd,
if ((DwmSetWindowAttribute(impl->hwnd,
DWMWA_USE_IMMERSIVE_DARK_MODE,
&useDarkMode,
sizeof(useDarkMode)) != S_OK)) {
DwmSetWindowAttribute(view->impl->hwnd,
DwmSetWindowAttribute(impl->hwnd,
PRE_20H1_DWMWA_USE_IMMERSIVE_DARK_MODE,
&useDarkMode,
sizeof(useDarkMode));
@@ -343,51 +350,48 @@ puglUnrealize(PuglView* const view)
view->backend->destroy(view);
}

ReleaseDC(view->impl->hwnd, view->impl->hdc);
view->impl->hdc = NULL;

DestroyWindow(view->impl->hwnd);
view->impl->hwnd = NULL;

memset(&view->lastConfigure, 0, sizeof(PuglConfigureEvent));
return PUGL_SUCCESS;
ReleaseDC(impl->hwnd, impl->hdc);
impl->hdc = NULL;

const PuglStatus st = puglWinStatus(DestroyWindow(impl->hwnd));
impl->hwnd = NULL;
return st;
}

PuglStatus
puglShow(PuglView* view, const PuglShowCommand command)
{
PuglInternals* impl = view->impl;
PuglStatus st = impl->hwnd ? PUGL_SUCCESS : puglRealize(view);

if (!impl->hwnd) {
const PuglStatus st = puglRealize(view);
if (st) {
return st;
if (!st) {
switch (command) {
case PUGL_SHOW_PASSIVE:
ShowWindow(impl->hwnd, SW_SHOWNOACTIVATE);
break;
case PUGL_SHOW_RAISE:
ShowWindow(impl->hwnd, SW_SHOWNORMAL);
st = SetActiveWindow(impl->hwnd) ? PUGL_SUCCESS : PUGL_FAILURE;
break;
case PUGL_SHOW_FORCE_RAISE:
ShowWindow(impl->hwnd, SW_SHOWNORMAL);
st = SetForegroundWindow(impl->hwnd) ? PUGL_SUCCESS : PUGL_FAILURE;
break;
}
}

switch (command) {
case PUGL_SHOW_PASSIVE:
ShowWindow(impl->hwnd, SW_SHOWNOACTIVATE);
break;
case PUGL_SHOW_RAISE:
ShowWindow(impl->hwnd, SW_SHOWNORMAL);
SetActiveWindow(impl->hwnd);
break;
case PUGL_SHOW_FORCE_RAISE:
ShowWindow(impl->hwnd, SW_SHOWNORMAL);
SetForegroundWindow(impl->hwnd);
break;
}

return PUGL_SUCCESS;
return st;
}

PuglStatus
puglHide(PuglView* view)
{
PuglInternals* impl = view->impl;
if (view->world->state == PUGL_WORLD_EXPOSING) {
return PUGL_BAD_CALL;
}

ShowWindow(impl->hwnd, SW_HIDE);
ShowWindow(view->impl->hwnd, SW_HIDE);
return PUGL_SUCCESS;
}

@@ -408,14 +412,11 @@ puglFreeViewInternals(PuglView* view)
void
puglFreeWorldInternals(PuglWorld* world)
{
#ifdef UNICODE
wchar_t* const wname = puglUtf8ToWideChar(world->strings[PUGL_CLASS_NAME]);
UnregisterClass(wname, NULL);
free(wname);
#else
UnregisterClass(world->strings[PUGL_CLASS_NAME], NULL);
#endif
const char* const className = world->strings[PUGL_CLASS_NAME];
ArgStringChar* const classNameArg = puglArgStringNew(className);

UnregisterClass(classNameArg, NULL);
puglArgStringFree(classNameArg);
free(world->impl);
}

@@ -426,14 +427,14 @@ keyInRange(const WPARAM winSym,
const PuglKey puglMin)
{
return (winSym >= winMin && winSym <= winMax)
? (PuglKey)(puglMin + (winSym - winMin))
: (PuglKey)0;
? (PuglKey)((WPARAM)puglMin + (winSym - winMin))
: PUGL_KEY_NONE;
}

static PuglKey
keySymToSpecial(const WPARAM sym, const bool ext)
{
PuglKey key = (PuglKey)0;
PuglKey key = PUGL_KEY_NONE;
if ((key = keyInRange(sym, VK_F1, VK_F12, PUGL_KEY_F1)) ||
(key = keyInRange(sym,
VK_PRIOR,
@@ -482,23 +483,26 @@ keySymToSpecial(const WPARAM sym, const bool ext)
// clang-format on
}

return (PuglKey)0;
return PUGL_KEY_NONE;
}

static bool
is_toggled(int vkey)
{
return (unsigned)GetKeyState(vkey) & 1U;
}

static uint32_t
getModifiers(void)
{
// clang-format off
return (
((GetKeyState(VK_SHIFT) < 0) ? (uint32_t)PUGL_MOD_SHIFT : 0U) |
((GetKeyState(VK_CONTROL) < 0) ? (uint32_t)PUGL_MOD_CTRL : 0U) |
((GetKeyState(VK_MENU) < 0) ? (uint32_t)PUGL_MOD_ALT : 0U) |
((GetKeyState(VK_LWIN) < 0) ? (uint32_t)PUGL_MOD_SUPER : 0U) |
((GetKeyState(VK_RWIN) < 0) ? (uint32_t)PUGL_MOD_SUPER : 0U) |
((GetKeyState(VK_NUMLOCK) & 1U) ? (uint32_t)PUGL_MOD_NUM_LOCK : 0U) |
((GetKeyState(VK_SCROLL) & 1U) ? (uint32_t)PUGL_MOD_SCROLL_LOCK : 0U) |
((GetKeyState(VK_CAPITAL) & 1U) ? (uint32_t)PUGL_MOD_CAPS_LOCK : 0U));
// clang-format on
return ((uint32_t)(((GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0) |
((GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0) |
((GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0) |
((GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0) |
((GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0) |
(is_toggled(VK_NUMLOCK) ? PUGL_MOD_NUM_LOCK : 0) |
(is_toggled(VK_SCROLL) ? PUGL_MOD_SCROLL_LOCK : 0) |
(is_toggled(VK_CAPITAL) ? PUGL_MOD_CAPS_LOCK : 0)));
}

static void
@@ -673,7 +677,7 @@ handleCrossing(PuglView* view, const PuglEventType type, POINT pos)

const PuglCrossingEvent ev = {
type,
0,
0U,
GetMessageTime() / 1e3,
(double)pos.x,
(double)pos.y,
@@ -683,7 +687,7 @@ handleCrossing(PuglView* view, const PuglEventType type, POINT pos)
PUGL_CROSSING_NORMAL,
};

PuglEvent crossingEvent = {{type, 0}};
PuglEvent crossingEvent = {{type, 0U}};
crossingEvent.crossing = ev;
puglDispatchEvent(view, &crossingEvent);
}
@@ -693,8 +697,8 @@ constrainAspect(const PuglView* const view,
RECT* const size,
const WPARAM wParam)
{
const PuglViewSize minAspect = view->sizeHints[PUGL_MIN_ASPECT];
const PuglViewSize maxAspect = view->sizeHints[PUGL_MAX_ASPECT];
const PuglArea minAspect = view->sizeHints[PUGL_MIN_ASPECT];
const PuglArea maxAspect = view->sizeHints[PUGL_MAX_ASPECT];

const float minA = (float)minAspect.width / (float)minAspect.height;
const float maxA = (float)maxAspect.width / (float)maxAspect.height;
@@ -733,7 +737,7 @@ constrainAspect(const PuglView* const view,
static LRESULT
handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
{
PuglEvent event = {{PUGL_NOTHING, 0}};
PuglEvent event = {{PUGL_NOTHING, 0U}};
RECT rect = {0, 0, 0, 0};
POINT pt = {0, 0};
MINMAXINFO* mmi = NULL;
@@ -779,8 +783,8 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
handleConfigure(view, &event);
break;
case WM_SIZING:
if (puglIsValidSize(view->sizeHints[PUGL_MIN_ASPECT]) &&
puglIsValidSize(view->sizeHints[PUGL_MAX_ASPECT])) {
if (puglIsValidArea(view->sizeHints[PUGL_MIN_ASPECT]) &&
puglIsValidArea(view->sizeHints[PUGL_MAX_ASPECT])) {
constrainAspect(view, (RECT*)lParam, wParam);
return TRUE;
}
@@ -795,7 +799,7 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
break;
case WM_TIMER:
if (wParam >= PUGL_USER_TIMER_MIN) {
PuglEvent ev = {{PUGL_TIMER, 0}};
PuglEvent ev = {{PUGL_TIMER, 0U}};
ev.timer.id = wParam - PUGL_USER_TIMER_MIN;
puglDispatchEvent(view, &ev);
}
@@ -812,7 +816,7 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
mmi = (MINMAXINFO*)lParam;
mmi->ptMinTrackSize.x = view->sizeHints[PUGL_MIN_SIZE].width;
mmi->ptMinTrackSize.y = view->sizeHints[PUGL_MIN_SIZE].height;
if (puglIsValidSize(view->sizeHints[PUGL_MAX_SIZE])) {
if (puglIsValidArea(view->sizeHints[PUGL_MAX_SIZE])) {
mmi->ptMaxTrackSize.x = view->sizeHints[PUGL_MAX_SIZE].width;
mmi->ptMaxTrackSize.y = view->sizeHints[PUGL_MAX_SIZE].height;
}
@@ -948,8 +952,7 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
PuglStatus
puglGrabFocus(PuglView* view)
{
SetFocus(view->impl->hwnd);
return PUGL_SUCCESS;
return puglWinStatus(!!SetFocus(view->impl->hwnd));
}

bool
@@ -1023,20 +1026,32 @@ puglSetViewStyle(PuglView* const view, const PuglViewStyleFlags flags)
const bool newMaximized = styleIsMaximized(flags);
if (oldMaximized != newMaximized) {
ShowWindow(impl->hwnd, newMaximized ? SW_SHOWMAXIMIZED : SW_RESTORE);
puglPostRedisplay(view);
puglObscureView(view);
}

return PUGL_SUCCESS;
}

PuglStatus
puglApplySizeHint(PuglView* const PUGL_UNUSED(view),
const PuglSizeHint PUGL_UNUSED(hint))
{
return PUGL_SUCCESS;
}

PuglStatus
puglUpdateSizeHints(PuglView* const PUGL_UNUSED(view))
{
return PUGL_SUCCESS;
}

PuglStatus
puglStartTimer(PuglView* view, uintptr_t id, double timeout)
{
const UINT msec = (UINT)floor(timeout * 1000.0);

return (SetTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id, msec, NULL)
? PUGL_SUCCESS
: PUGL_UNKNOWN_ERROR);
SetTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id, msec, NULL);
return PUGL_SUCCESS;
}

PuglStatus
@@ -1048,32 +1063,24 @@ puglStopTimer(PuglView* view, uintptr_t id)
PuglStatus
puglSendEvent(PuglView* view, const PuglEvent* event)
{
if (!view->impl->hwnd || view->world->state == PUGL_WORLD_EXPOSING) {
return PUGL_FAILURE;
}

if (event->type == PUGL_CLOSE) {
PostMessage(view->impl->hwnd, WM_CLOSE, 0, 0);
return PUGL_SUCCESS;
return puglWinStatus(PostMessage(view->impl->hwnd, WM_CLOSE, 0, 0));
}

if (event->type == PUGL_CLIENT) {
PostMessage(view->impl->hwnd,
PUGL_LOCAL_CLIENT_MSG,
(WPARAM)event->client.data1,
(LPARAM)event->client.data2);

return PUGL_SUCCESS;
return puglWinStatus(PostMessage(view->impl->hwnd,
PUGL_LOCAL_CLIENT_MSG,
(WPARAM)event->client.data1,
(LPARAM)event->client.data2));
}

return PUGL_UNSUPPORTED;
}

#ifndef PUGL_DISABLE_DEPRECATED
PuglStatus
puglWaitForEvent(PuglView* PUGL_UNUSED(view))
{
WaitMessage();
return PUGL_SUCCESS;
}
#endif

static PuglStatus
puglDispatchViewEvents(PuglView* view)
{
@@ -1118,21 +1125,31 @@ puglDispatchWinEvents(PuglWorld* world)
PuglStatus
puglUpdate(PuglWorld* world, double timeout)
{
const double startTime = puglGetTime(world);
PuglStatus st = PUGL_SUCCESS;
static const double minWaitSeconds = 0.002;

const double startTime = puglGetTime(world);
const PuglWorldState startState = world->state;
PuglStatus st = PUGL_SUCCESS;

if (startState == PUGL_WORLD_IDLE) {
world->state = PUGL_WORLD_UPDATING;
} else if (startState != PUGL_WORLD_RECURSING) {
return PUGL_BAD_CALL;
}

if (timeout < 0.0) {
st = puglPollWinEvents(world, timeout);
st = st ? st : puglDispatchWinEvents(world);
} else if (timeout <= 0.001) {
WaitMessage();
st = puglDispatchWinEvents(world);
} else if (timeout < minWaitSeconds) {
st = puglDispatchWinEvents(world);
} else {
const double endTime = startTime + timeout - 0.001;
for (double t = startTime; t < endTime; t = puglGetTime(world)) {
if ((st = puglPollWinEvents(world, endTime - t)) ||
(st = puglDispatchWinEvents(world))) {
break;
}
const double endTime = startTime + timeout - minWaitSeconds;
double t = startTime;
while (!st && t < endTime) {
const DWORD timeoutMs = (DWORD)((endTime - t) * 1e3);
MsgWaitForMultipleObjects(0, NULL, FALSE, timeoutMs, QS_ALLEVENTS);
st = puglDispatchWinEvents(world);
t = puglGetTime(world);
}
}

@@ -1144,17 +1161,10 @@ puglUpdate(PuglWorld* world, double timeout)
UpdateWindow(world->views[i]->impl->hwnd);
}

world->state = startState;
return st;
}

#ifndef PUGL_DISABLE_DEPRECATED
PuglStatus
puglProcessEvents(PuglView* view)
{
return puglUpdate(view->world, 0.0);
}
#endif

LRESULT CALLBACK
wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
@@ -1188,23 +1198,35 @@ puglGetTime(const PuglWorld* world)
}

PuglStatus
puglPostRedisplay(PuglView* view)
puglObscureView(PuglView* view)
{
InvalidateRect(view->impl->hwnd, NULL, false);
return PUGL_SUCCESS;
return view->world->state == PUGL_WORLD_EXPOSING
? PUGL_BAD_CALL
: puglWinStatus(InvalidateRect(view->impl->hwnd, NULL, false));
}

PuglStatus
puglPostRedisplayRect(PuglView* view, const PuglRect rect)
puglObscureRegion(PuglView* const view,
const int x,
const int y,
const unsigned width,
const unsigned height)
{
const RECT r = {(long)floor(rect.x),
(long)floor(rect.y),
(long)ceil(rect.x + rect.width),
(long)ceil(rect.y + rect.height)};
if (view->world->state == PUGL_WORLD_EXPOSING) {
return PUGL_BAD_CALL;
}

if (!puglIsValidPosition(x, y) || !puglIsValidSize(width, height)) {
return PUGL_BAD_PARAMETER;
}

InvalidateRect(view->impl->hwnd, &r, false);
const int cx = MAX(0, x);
const int cy = MAX(0, y);
const unsigned cw = MIN(view->lastConfigure.width, width);
const unsigned ch = MIN(view->lastConfigure.height, height);

return PUGL_SUCCESS;
const RECT r = {cx, cy, cx + (long)cw, cy + (long)ch};
return puglWinStatus(InvalidateRect(view->impl->hwnd, &r, false));
}

PuglNativeView
@@ -1218,19 +1240,18 @@ puglViewStringChanged(PuglView* const view,
const PuglStringHint key,
const char* const value)
{
PuglStatus st = PUGL_SUCCESS;
if (!view->impl->hwnd) {
return PUGL_SUCCESS;
return st;
}

if (key == PUGL_WINDOW_TITLE) {
wchar_t* const wtitle = puglUtf8ToWideChar(value);
if (wtitle) {
SetWindowTextW(view->impl->hwnd, wtitle);
free(wtitle);
}
ArgStringChar* const titleArg = puglArgStringNew(value);
st = puglWinStatus(SetWindowText(view->impl->hwnd, titleArg));
puglArgStringFree(titleArg);
}

return PUGL_SUCCESS;
return st;
}

static RECT
@@ -1256,44 +1277,8 @@ puglGetScaleFactor(const PuglView* const view)
}

PuglStatus
puglSetFrame(PuglView* view, const PuglRect frame)
{
if (!view->impl->hwnd) {
// Set defaults to be used when realized
view->defaultX = frame.x;
view->defaultY = frame.y;
view->sizeHints[PUGL_DEFAULT_SIZE].width = frame.width;
view->sizeHints[PUGL_DEFAULT_SIZE].height = frame.height;
return PUGL_SUCCESS;
}

const RECT rect =
adjustedWindowRect(view, frame.x, frame.y, frame.width, frame.height);

return puglWinStatus(
SetWindowPos(view->impl->hwnd,
HWND_TOP,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER));
}

PuglStatus
puglSetPosition(PuglView* const view, const int x, const int y)
puglSetWindowPosition(PuglView* const view, const int x, const int y)
{
if (x < INT16_MIN || x > INT16_MAX || y < INT16_MIN || y > INT16_MAX) {
return PUGL_BAD_PARAMETER;
}

if (!view->impl->hwnd) {
// Set defaults to be used when realized
view->defaultX = x;
view->defaultY = y;
return PUGL_SUCCESS;
}

const RECT rect = adjustedWindowRect(
view, x, y, view->lastConfigure.width, view->lastConfigure.height);

@@ -1305,19 +1290,10 @@ puglSetPosition(PuglView* const view, const int x, const int y)
}

PuglStatus
puglSetSize(PuglView* const view, const unsigned width, const unsigned height)
puglSetWindowSize(PuglView* const view,
const unsigned width,
const unsigned height)
{
if (width > INT16_MAX || height > INT16_MAX) {
return PUGL_BAD_PARAMETER;
}

if (!view->impl->hwnd) {
// Set defaults to be used when realized
view->sizeHints[PUGL_DEFAULT_SIZE].width = (PuglSpan)width;
view->sizeHints[PUGL_DEFAULT_SIZE].height = (PuglSpan)height;
return PUGL_SUCCESS;
}

const RECT rect = adjustedWindowRect(view,
view->lastConfigure.x,
view->lastConfigure.y,
@@ -1336,21 +1312,6 @@ puglSetSize(PuglView* const view, const unsigned width, const unsigned height)
flags));
}

PuglStatus
puglSetSizeHint(PuglView* const view,
const PuglSizeHint hint,
const PuglSpan width,
const PuglSpan height)
{
if ((unsigned)hint >= PUGL_NUM_SIZE_HINTS) {
return PUGL_BAD_PARAMETER;
}

view->sizeHints[hint].width = width;
view->sizeHints[hint].height = height;
return PUGL_SUCCESS;
}

PuglStatus
puglSetTransientParent(PuglView* view, PuglNativeView parent)
{
@@ -1394,15 +1355,14 @@ puglAcceptOffer(PuglView* const view,

const PuglDataEvent data = {
PUGL_DATA,
0,
0U,
GetMessageTime() / 1e3,
0,
};

PuglEvent dataEvent;
dataEvent.data = data;
puglDispatchEvent(view, &dataEvent);
return PUGL_SUCCESS;
return puglDispatchEvent(view, &dataEvent);
}

const void*
@@ -1412,8 +1372,21 @@ puglGetClipboard(PuglView* const view,
{
PuglInternals* const impl = view->impl;

if (typeIndex > 0U || !IsClipboardFormatAvailable(CF_UNICODETEXT) ||
!OpenClipboard(impl->hwnd)) {
if (typeIndex > 0U || !IsClipboardFormatAvailable(CF_UNICODETEXT)) {
return NULL;
}

// Try to open the clipboard several times since others may have locked it
BOOL opened = FALSE;
static const unsigned max_tries = 16U;
for (unsigned i = 0U; !opened && i < max_tries; ++i) {
opened = OpenClipboard(impl->hwnd);
if (!opened) {
Sleep(0);
}
}

if (!opened) {
return NULL;
}

@@ -1424,15 +1397,14 @@ puglGetClipboard(PuglView* const view,
return NULL;
}

free(view->impl->clipboard.data);
view->impl->clipboard.data =
puglWideCharToUtf8(wstr, &view->impl->clipboard.len);
free(impl->clipboard.data);
impl->clipboard.data = puglWideCharToUtf8(wstr, &impl->clipboard.len);

GlobalUnlock(mem);
CloseClipboard();

*len = view->impl->clipboard.len;
return view->impl->clipboard.data;
*len = impl->clipboard.len;
return impl->clipboard.data;
}

PuglStatus
@@ -1443,7 +1415,7 @@ puglSetClipboard(PuglView* const view,
{
PuglInternals* const impl = view->impl;

PuglStatus st = puglSetBlob(&view->impl->clipboard, data, len);
PuglStatus st = puglSetBlob(&impl->clipboard, data, len);
if (st) {
return st;
}
@@ -1488,14 +1460,13 @@ puglPaste(PuglView* const view)
{
const PuglDataOfferEvent offer = {
PUGL_DATA_OFFER,
0,
0U,
GetMessageTime() / 1e3,
};

PuglEvent offerEvent;
offerEvent.offer = offer;
puglDispatchEvent(view, &offerEvent);
return PUGL_SUCCESS;
return puglDispatchEvent(view, &offerEvent);
}

static const TCHAR* const cursor_ids[] = {
@@ -1563,42 +1534,18 @@ puglWinGetPixelFormatDescriptor(const PuglHints hints)
return pfd;
}

static PuglRect
getInitialFrame(PuglView* const view)
PuglPoint
puglGetAncestorCenter(const PuglView* const view)
{
if (view->lastConfigure.type == PUGL_CONFIGURE) {
// Use the last configured frame
const PuglRect frame = {view->lastConfigure.x,
view->lastConfigure.y,
view->lastConfigure.width,
view->lastConfigure.height};
return frame;
}
RECT rect = {0, 0, 0, 0};
GetWindowRect(view->transientParent ? (HWND)view->transientParent
: GetDesktopWindow(),
&rect);

const PuglSpan defaultWidth = view->sizeHints[PUGL_DEFAULT_SIZE].width;
const PuglSpan defaultHeight = view->sizeHints[PUGL_DEFAULT_SIZE].height;
const int x = view->defaultX;
const int y = view->defaultY;
if (x >= INT16_MIN && x <= INT16_MAX && y >= INT16_MIN && y <= INT16_MAX) {
// Use the default position set with puglSetPosition while unrealized
const PuglRect frame = {
(PuglCoord)x, (PuglCoord)y, defaultWidth, defaultHeight};
return frame;
}

// Get a bounding rect from the "nearest" parent or parent-like window
const HWND hwnd = puglWinGetWindow(view);
RECT rect = {0, 0, 0, 0};
GetWindowRect(hwnd ? hwnd : GetDesktopWindow(), &rect);

// Center the frame around the center of the bounding rectangle
const LONG centerX = rect.left + (rect.right - rect.left) / 2;
const LONG centerY = rect.top + (rect.bottom - rect.top) / 2;
const PuglRect frame = {(PuglCoord)(centerX - (defaultWidth / 2)),
(PuglCoord)(centerY - (defaultHeight / 2)),
defaultWidth,
defaultHeight};
return frame;
const PuglPoint center = {
(PuglCoord)(rect.left + ((rect.right - rect.left) / 2)),
(PuglCoord)(rect.top + ((rect.bottom - rect.top) / 2))};
return center;
}

PuglStatus
@@ -1613,28 +1560,35 @@ puglWinCreateWindow(PuglView* const view,
PuglNativeView parent = view->parent ? view->parent : view->transientParent;

// Calculate initial window rectangle
const unsigned winFlags = puglWinGetWindowFlags(view);
const unsigned winExFlags = puglWinGetWindowExFlags(view);
const PuglRect frame = getInitialFrame(view);
RECT wr = {(long)frame.x,
(long)frame.y,
(long)frame.x + frame.width,
(long)frame.y + frame.height};
const unsigned winFlags = puglWinGetWindowFlags(view);
const unsigned winExFlags = puglWinGetWindowExFlags(view);
const PuglArea size = puglGetInitialSize(view);
const PuglPoint pos = puglGetInitialPosition(view, size);
RECT wr = {(long)pos.x,
(long)pos.y,
(long)pos.x + size.width,
(long)pos.y + size.height};
AdjustWindowRectEx(&wr, winFlags, FALSE, winExFlags);

ArgStringChar* const classNameArg = puglArgStringNew(className);
ArgStringChar* const titleArg = puglArgStringNew(title);

// Create window and get drawing context
if (!(*hwnd = CreateWindowExA(winExFlags,
className,
title,
winFlags,
wr.left,
wr.right,
wr.right - wr.left,
wr.bottom - wr.top,
(HWND)parent,
NULL,
NULL,
NULL))) {
*hwnd = CreateWindowEx(winExFlags,
classNameArg,
titleArg,
winFlags,
wr.left,
wr.right,
wr.right - wr.left,
wr.bottom - wr.top,
(HWND)parent,
NULL,
NULL,
NULL);
puglArgStringFree(titleArg);
puglArgStringFree(classNameArg);
if (!*hwnd) {
return PUGL_REALIZE_FAILED;
}

@@ -1660,7 +1614,6 @@ puglWinConfigure(PuglView* view)
{
PuglInternals* const impl = view->impl;
PuglStatus st = PUGL_SUCCESS;

if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) {
return st;
}
@@ -1673,20 +1626,18 @@ puglWinConfigure(PuglView* view)
DestroyWindow(impl->hwnd);
impl->hwnd = NULL;
impl->hdc = NULL;
return PUGL_SET_FORMAT_FAILED;
st = PUGL_SET_FORMAT_FAILED;
}

return PUGL_SUCCESS;
return st;
}

PuglStatus
puglWinEnter(PuglView* view, const PuglExposeEvent* expose)
{
if (expose) {
BeginPaint(view->impl->hwnd, &view->impl->paint);
}

return PUGL_SUCCESS;
return expose
? puglWinStatus(!!BeginPaint(view->impl->hwnd, &view->impl->paint))
: PUGL_SUCCESS;
}

PuglStatus


+ 6
- 15
source/modules/dgl/src/pugl-upstream/src/win.h View File

@@ -6,7 +6,7 @@

#include "internal.h"

#include "pugl/pugl.h"
#include <pugl/pugl.h>

#include <windows.h>

@@ -37,28 +37,19 @@ struct PuglInternalsImpl {
bool fullscreen;
};

PUGL_API
PuglWinPFD
PUGL_API PuglWinPFD
puglWinGetPixelFormatDescriptor(const PuglHints hints);

PUGL_WARN_UNUSED_RESULT
PUGL_API
PuglStatus
PUGL_WARN_UNUSED_RESULT PUGL_API PuglStatus
puglWinCreateWindow(PuglView* view, const char* title, HWND* hwnd, HDC* hdc);

PUGL_WARN_UNUSED_RESULT
PUGL_API
PuglStatus
PUGL_WARN_UNUSED_RESULT PUGL_API PuglStatus
puglWinConfigure(PuglView* view);

PUGL_WARN_UNUSED_RESULT
PUGL_API
PuglStatus
PUGL_WARN_UNUSED_RESULT PUGL_API PuglStatus
puglWinEnter(PuglView* view, const PuglExposeEvent* expose);

PUGL_WARN_UNUSED_RESULT
PUGL_API
PuglStatus
PUGL_WARN_UNUSED_RESULT PUGL_API PuglStatus
puglWinLeave(PuglView* view, const PuglExposeEvent* expose);

#endif // PUGL_SRC_WIN_H

+ 1
- 1
source/modules/dgl/src/pugl-upstream/src/win_cairo.c View File

@@ -5,7 +5,7 @@
#include "types.h"
#include "win.h"

#include "pugl/cairo.h"
#include <pugl/cairo.h>

#include <cairo-win32.h>
#include <cairo.h>


+ 37
- 25
source/modules/dgl/src/pugl-upstream/src/win_gl.c View File

@@ -5,7 +5,7 @@
#include "types.h"
#include "win.h"

#include "pugl/gl.h"
#include <pugl/gl.h>

#include <windows.h>

@@ -14,30 +14,42 @@
#include <stdbool.h>
#include <stdlib.h>

#define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_ACCELERATION_ARB 0x2003
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_PIXEL_TYPE_ARB 0x2013
#define WGL_RED_BITS_ARB 0x2015
#define WGL_GREEN_BITS_ARB 0x2017
#define WGL_BLUE_BITS_ARB 0x2019
#define WGL_ALPHA_BITS_ARB 0x201b
#define WGL_DEPTH_BITS_ARB 0x2022
#define WGL_STENCIL_BITS_ARB 0x2023
#define WGL_FULL_ACCELERATION_ARB 0x2027
#define WGL_TYPE_RGBA_ARB 0x202b
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
#define WGL_SAMPLES_ARB 0x2042

#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define WGL_CONTEXT_FLAGS_ARB 0x2094
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126

#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
typedef enum {
WGL_DRAW_TO_WINDOW_ARB = 0x2001,
WGL_ACCELERATION_ARB = 0x2003,
WGL_SUPPORT_OPENGL_ARB = 0x2010,
WGL_DOUBLE_BUFFER_ARB = 0x2011,
WGL_PIXEL_TYPE_ARB = 0x2013,
WGL_RED_BITS_ARB = 0x2015,
WGL_GREEN_BITS_ARB = 0x2017,
WGL_BLUE_BITS_ARB = 0x2019,
WGL_ALPHA_BITS_ARB = 0x201B,
WGL_DEPTH_BITS_ARB = 0x2022,
WGL_STENCIL_BITS_ARB = 0x2023,
WGL_SAMPLE_BUFFERS_ARB = 0x2041,
WGL_SAMPLES_ARB = 0x2042,
} PuglWinGlHintName;

typedef enum {
WGL_FULL_ACCELERATION_ARB = 0x2027,
WGL_TYPE_RGBA_ARB = 0x202B,
} PuglWinGlHintValue;

typedef enum {
WGL_CONTEXT_MAJOR_VERSION_ARB = 0x2091,
WGL_CONTEXT_MINOR_VERSION_ARB = 0x2092,
WGL_CONTEXT_FLAGS_ARB = 0x2094,
WGL_CONTEXT_PROFILE_MASK_ARB = 0x9126,
} PuglWinGlContextAttribName;

typedef enum {
WGL_CONTEXT_CORE_PROFILE_BIT_ARB = 0x00000001,
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x00000002,
} PuglWinGlContextProfileBit;

typedef enum {
WGL_CONTEXT_DEBUG_BIT_ARB = 0x00000001,
} PuglWinGlContextDebugBit;

typedef HGLRC(WINAPI* WglCreateContextAttribs)(HDC, HGLRC, const int*);



+ 1
- 1
source/modules/dgl/src/pugl-upstream/src/win_stub.c View File

@@ -5,7 +5,7 @@
#include "types.h"
#include "win.h"

#include "pugl/stub.h"
#include <pugl/stub.h>

static PuglStatus
puglWinStubConfigure(PuglView* view)


+ 1
- 1
source/modules/dgl/src/pugl-upstream/src/win_vulkan.c View File

@@ -7,7 +7,7 @@
#include "types.h"
#include "win.h"

#include "pugl/vulkan.h"
#include <pugl/vulkan.h>

#include <vulkan/vulkan.h>
#include <vulkan/vulkan_win32.h>


+ 151
- 212
source/modules/dgl/src/pugl-upstream/src/x11.c View File

@@ -11,7 +11,7 @@
#include "platform.h"
#include "types.h"

#include "pugl/pugl.h"
#include <pugl/pugl.h>

#include <X11/X.h>
#include <X11/Xatom.h>
@@ -69,13 +69,11 @@
#include <unistd.h>

#ifdef __cplusplus
# define PUGL_INIT_STRUCT \
{}
#else
# define PUGL_INIT_STRUCT \
{ \
0 \
}
#else
# define PUGL_INIT_STRUCT {0}
#endif

enum WmClientStateMessageAction {
@@ -396,8 +394,15 @@ findView(PuglWorld* const world, const Window window)
return NULL;
}

static PuglStatus
updateSizeHints(const PuglView* const view)
PuglStatus
puglApplySizeHint(PuglView* const view, const PuglSizeHint PUGL_UNUSED(hint))
{
// No fine-grained updates, hints are always recalculated together
return puglUpdateSizeHints(view);
}

PuglStatus
puglUpdateSizeHints(PuglView* const view)
{
if (!view->impl->win) {
return PUGL_SUCCESS;
@@ -407,40 +412,44 @@ updateSizeHints(const PuglView* const view)
XSizeHints sizeHints = PUGL_INIT_STRUCT;

if (!view->hints[PUGL_RESIZABLE]) {
const PuglRect frame = puglGetFrame(view);
PuglArea size = puglGetSizeHint(view, PUGL_CURRENT_SIZE);
if (!puglIsValidSize(size.width, size.height)) {
size = puglGetSizeHint(view, PUGL_DEFAULT_SIZE);
}

sizeHints.flags = PBaseSize | PMinSize | PMaxSize;
sizeHints.base_width = (int)frame.width;
sizeHints.base_height = (int)frame.height;
sizeHints.min_width = (int)frame.width;
sizeHints.min_height = (int)frame.height;
sizeHints.max_width = (int)frame.width;
sizeHints.max_height = (int)frame.height;
sizeHints.base_width = (int)size.width;
sizeHints.base_height = (int)size.height;
sizeHints.min_width = (int)size.width;
sizeHints.min_height = (int)size.height;
sizeHints.max_width = (int)size.width;
sizeHints.max_height = (int)size.height;
} else {
// Avoid setting PBaseSize for top level views to avoid window manager bugs
const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE];
if (puglIsValidSize(defaultSize) && view->parent) {
const PuglArea defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE];
if (puglIsValidArea(defaultSize) && view->parent) {
sizeHints.flags |= PBaseSize;
sizeHints.base_width = defaultSize.width;
sizeHints.base_height = defaultSize.height;
}

const PuglViewSize minSize = view->sizeHints[PUGL_MIN_SIZE];
if (puglIsValidSize(minSize)) {
const PuglArea minSize = view->sizeHints[PUGL_MIN_SIZE];
if (puglIsValidArea(minSize)) {
sizeHints.flags |= PMinSize;
sizeHints.min_width = minSize.width;
sizeHints.min_height = minSize.height;
}

const PuglViewSize maxSize = view->sizeHints[PUGL_MAX_SIZE];
if (puglIsValidSize(maxSize)) {
const PuglArea maxSize = view->sizeHints[PUGL_MAX_SIZE];
if (puglIsValidArea(maxSize)) {
sizeHints.flags |= PMaxSize;
sizeHints.max_width = maxSize.width;
sizeHints.max_height = maxSize.height;
}

const PuglViewSize minAspect = view->sizeHints[PUGL_MIN_ASPECT];
const PuglViewSize maxAspect = view->sizeHints[PUGL_MAX_ASPECT];
if (puglIsValidSize(minAspect) && puglIsValidSize(maxAspect)) {
const PuglArea minAspect = view->sizeHints[PUGL_MIN_ASPECT];
const PuglArea maxAspect = view->sizeHints[PUGL_MAX_ASPECT];
if (puglIsValidArea(minAspect) && puglIsValidArea(maxAspect)) {
sizeHints.flags |= PAspect;
sizeHints.min_aspect.x = minAspect.width;
sizeHints.min_aspect.y = minAspect.height;
@@ -448,8 +457,8 @@ updateSizeHints(const PuglView* const view)
sizeHints.max_aspect.y = maxAspect.height;
}

const PuglViewSize fixedAspect = view->sizeHints[PUGL_FIXED_ASPECT];
if (puglIsValidSize(fixedAspect)) {
const PuglArea fixedAspect = view->sizeHints[PUGL_FIXED_ASPECT];
if (puglIsValidArea(fixedAspect)) {
sizeHints.flags |= PAspect;
sizeHints.min_aspect.x = fixedAspect.width;
sizeHints.min_aspect.y = fixedAspect.height;
@@ -513,48 +522,21 @@ clearX11Clipboard(PuglX11Clipboard* const board)
board->data.len = 0;
}

static PuglRect
getInitialFrame(PuglView* const view)
PuglPoint
puglGetAncestorCenter(const PuglView* const view)
{
if (view->lastConfigure.type == PUGL_CONFIGURE) {
// Use the last configured frame
const PuglRect frame = {view->lastConfigure.x,
view->lastConfigure.y,
view->lastConfigure.width,
view->lastConfigure.height};
return frame;
}

const PuglSpan defaultWidth = view->sizeHints[PUGL_DEFAULT_SIZE].width;
const PuglSpan defaultHeight = view->sizeHints[PUGL_DEFAULT_SIZE].height;
const int x = view->defaultX;
const int y = view->defaultY;
if (x >= INT16_MIN && x <= INT16_MAX && y >= INT16_MIN && y <= INT16_MAX) {
// Use the default position set with puglSetPosition while unrealized
const PuglRect frame = {
(PuglCoord)x, (PuglCoord)y, defaultWidth, defaultHeight};
return frame;
}

// Get the best "parentish" window to position the window in
Display* const display = view->world->impl->display;
const Window parent =
(view->parent ? (Window)view->parent
: view->transientParent ? (Window)view->transientParent
: RootWindow(display, view->impl->screen));

// Get the position/size of the parent as bounds for the new window
XWindowAttributes parentAttrs = PUGL_INIT_STRUCT;
XGetWindowAttributes(display, parent, &parentAttrs);
Display* const display = view->world->impl->display;
const int screen = view->impl->screen;
XWindowAttributes ancestorAttrs = PUGL_INIT_STRUCT;
XGetWindowAttributes(display,
view->transientParent ? (Window)view->transientParent
: RootWindow(display, screen),
&ancestorAttrs);

// Center the frame within the parent bounds
const int centerX = parentAttrs.x + parentAttrs.width / 2;
const int centerY = parentAttrs.y + parentAttrs.height / 2;
const PuglRect frame = {(PuglCoord)(centerX - (defaultWidth / 2)),
(PuglCoord)(centerY - (defaultHeight / 2)),
defaultWidth,
defaultHeight};
return frame;
const PuglPoint center = {
(PuglCoord)(ancestorAttrs.x + (ancestorAttrs.width / 2)),
(PuglCoord)(ancestorAttrs.y + (ancestorAttrs.height / 2))};
return center;
}

PuglStatus
@@ -609,16 +591,17 @@ puglRealize(PuglView* const view)
attr.event_mask |= StructureNotifyMask;
attr.event_mask |= VisibilityChangeMask;

// Calculate the initial window rectangle
const PuglRect initialFrame = getInitialFrame(view);
// Calculate the initial window frame
const PuglArea initialSize = puglGetInitialSize(view);
const PuglPoint initialPos = puglGetInitialPosition(view, initialSize);

// Create the window
impl->win = XCreateWindow(display,
parent,
initialFrame.x,
initialFrame.y,
initialFrame.width,
initialFrame.height,
initialPos.x,
initialPos.y,
initialSize.width,
initialSize.height,
0,
impl->vi->depth,
InputOutput,
@@ -650,7 +633,7 @@ puglRealize(PuglView* const view)
if (XRRQueryExtension(display, &ignored, &ignored)) {
// Set refresh rate hint to the real refresh rate
XRRScreenConfiguration* conf = XRRGetScreenInfo(display, parent);
short current_rate = XRRConfigCurrentRate(conf);
const short current_rate = XRRConfigCurrentRate(conf);

view->hints[PUGL_REFRESH_RATE] = current_rate;
XRRFreeScreenConfigInfo(conf);
@@ -663,7 +646,7 @@ puglRealize(PuglView* const view)
XSetClassHint(display, impl->win, &classHint);
puglSetViewString(view, PUGL_WINDOW_TITLE, view->strings[PUGL_WINDOW_TITLE]);
puglSetTransientParent(view, view->transientParent);
updateSizeHints(view);
puglUpdateSizeHints(view);

// Set PID and hostname so the window manager can access our process
char hostname[256] = PUGL_INIT_STRUCT;
@@ -759,21 +742,22 @@ puglUnrealize(PuglView* const view)
PuglStatus
puglShow(PuglView* const view, const PuglShowCommand command)
{
PuglStatus st = view->impl->win ? PUGL_SUCCESS : puglRealize(view);
PuglInternals* impl = view->impl;
PuglStatus st = impl->win ? PUGL_SUCCESS : puglRealize(view);

if (!st) {
switch (command) {
case PUGL_SHOW_PASSIVE:
XMapWindow(view->world->impl->display, view->impl->win);
XMapWindow(view->world->impl->display, impl->win);
break;
case PUGL_SHOW_RAISE:
case PUGL_SHOW_FORCE_RAISE:
XMapRaised(view->world->impl->display, view->impl->win);
XMapRaised(view->world->impl->display, impl->win);
break;
}

if (view->stage == PUGL_VIEW_STAGE_CONFIGURED) {
st = puglPostRedisplay(view);
st = puglObscureView(view);
}
}

@@ -783,6 +767,10 @@ puglShow(PuglView* const view, const PuglShowCommand command)
PuglStatus
puglHide(PuglView* const view)
{
if (view->world->state == PUGL_WORLD_EXPOSING) {
return PUGL_BAD_CALL;
}

XUnmapWindow(view->world->impl->display, view->impl->win);
return PUGL_SUCCESS;
}
@@ -817,13 +805,13 @@ keyInRange(const KeySym xSym,
const PuglKey puglMin)
{
return (xSym >= xMin && xSym <= xMax) ? (PuglKey)(puglMin + (xSym - xMin))
: (PuglKey)0;
: PUGL_KEY_NONE;
}

static PuglKey
keySymToSpecial(const KeySym sym)
{
PuglKey key = (PuglKey)0;
PuglKey key = PUGL_KEY_NONE;
if ((key = keyInRange(sym, XK_F1, XK_F12, PUGL_KEY_F1)) ||
(key = keyInRange(sym, XK_Page_Up, XK_End, PUGL_KEY_PAGE_UP)) ||
(key = keyInRange(sym, XK_Home, XK_Down, PUGL_KEY_HOME)) ||
@@ -856,7 +844,7 @@ keySymToSpecial(const KeySym sym)
}
// clang-format on

return (PuglKey)0;
return PUGL_KEY_NONE;
}

static int
@@ -897,7 +885,8 @@ translateKey(PuglView* const view, XEvent* const xevent, PuglEvent* const event)
event->key.key = (PuglKey)puglDecodeUTF8((const uint8_t*)ustr);
}

if (xevent->type == KeyPress && !filter && !special && view->impl->xic) {
if (xevent->type == KeyPress && !filter && (!special || ufound > 0) &&
view->impl->xic) {
// Lookup shifted key for possible text event
xevent->xkey.state = state;

@@ -1028,7 +1017,7 @@ translateClientMessage(PuglView* const view, XClientMessageEvent message)
{
Display* const display = view->world->impl->display;
const PuglX11Atoms* const atoms = &view->world->impl->atoms;
PuglEvent event = {{PUGL_NOTHING, 0}};
PuglEvent event = {{PUGL_NOTHING, 0U}};

if (message.message_type == atoms->WM_PROTOCOLS) {
const Atom protocol = (Atom)message.data.l[0];
@@ -1101,17 +1090,19 @@ getCurrentConfiguration(PuglView* const view)
XWindowAttributes attrs;
XGetWindowAttributes(display, view->impl->win, &attrs);

// Get window position relative to the root window
// Get window position (relative to the root window if not a child)
Window ignoredChild = 0;
int rootX = 0;
int rootY = 0;
XTranslateCoordinates(
display, view->impl->win, attrs.root, 0, 0, &rootX, &rootY, &ignoredChild);
int x = attrs.x;
int y = attrs.y;
if (!view->parent) {
XTranslateCoordinates(
display, view->impl->win, attrs.root, 0, 0, &x, &y, &ignoredChild);
}

// Build a configure event based on the current window configuration
PuglEvent configureEvent = {{PUGL_CONFIGURE, 0}};
configureEvent.configure.x = (PuglCoord)rootX;
configureEvent.configure.y = (PuglCoord)rootY;
PuglEvent configureEvent = {{PUGL_CONFIGURE, 0U}};
configureEvent.configure.x = (PuglCoord)x;
configureEvent.configure.y = (PuglCoord)y;
configureEvent.configure.width = (PuglSpan)attrs.width;
configureEvent.configure.height = (PuglSpan)attrs.height;
configureEvent.configure.style = getCurrentViewStyleFlags(view);
@@ -1140,7 +1131,7 @@ translatePropertyNotify(PuglView* const view, XPropertyEvent message)
{
const PuglInternals* const impl = view->impl;
const PuglX11Atoms* const atoms = &view->world->impl->atoms;
PuglEvent event = {{PUGL_NOTHING, 0}};
PuglEvent event = {{PUGL_NOTHING, 0U}};

if (message.atom == atoms->NET_WM_STATE) {
// Get all the current states set in the window hints
@@ -1190,7 +1181,7 @@ translatePropertyNotify(PuglView* const view, XPropertyEvent message)
static PuglEvent
translateEvent(PuglView* const view, XEvent xevent)
{
PuglEvent event = {{PUGL_NOTHING, 0}};
PuglEvent event = {{PUGL_NOTHING, 0U}};
event.any.flags = xevent.xany.send_event ? PUGL_IS_SEND_EVENT : 0;

switch (xevent.type) {
@@ -1211,6 +1202,9 @@ translateEvent(PuglView* const view, XEvent xevent)
view->impl->mapped = false;
event = makeConfigureEvent(view);
break;
case DestroyNotify:
view->impl->win = None;
break;
case ConfigureNotify:
event = makeConfigureEvent(view);
event.configure.width = (PuglSpan)xevent.xconfigure.width;
@@ -1503,7 +1497,7 @@ puglSendEvent(PuglView* const view, const PuglEvent* const event)
PuglInternals* const impl = view->impl;
Display* const display = view->world->impl->display;
XEvent xev = PUGL_INIT_STRUCT;
if (!impl->win) {
if (!impl->win || view->world->state == PUGL_WORLD_EXPOSING) {
return PUGL_FAILURE;
}

@@ -1534,21 +1528,11 @@ puglSendEvent(PuglView* const view, const PuglEvent* const event)
return PUGL_UNSUPPORTED;
}

#ifndef PUGL_DISABLE_DEPRECATED
PuglStatus
puglWaitForEvent(PuglView* const view)
{
XEvent xevent;
XPeekEvent(view->world->impl->display, &xevent);
return PUGL_SUCCESS;
}
#endif

static void
mergeExposeEvents(PuglExposeEvent* const dst, const PuglExposeEvent* const src)
{
if (!dst->type) {
if (src->width > 0.0 && src->height > 0.0) {
if (src->width && src->height) {
*dst = *src;
}
} else {
@@ -1612,7 +1596,7 @@ handleSelectionNotify(const PuglWorld* const world,
Display* const display = view->world->impl->display;
const Atom selection = event->selection;
PuglX11Clipboard* const board = getX11SelectionClipboard(view, selection);
PuglEvent puglEvent = {{PUGL_NOTHING, 0}};
PuglEvent puglEvent = {{PUGL_NOTHING, 0U}};

if (event->target == atoms->TARGETS) {
// Notification of available datatypes
@@ -1622,7 +1606,7 @@ handleSelectionNotify(const PuglWorld* const world,
view, event->requestor, event->property, &numFormats, &formats) &&
!setClipboardFormats(view, board, numFormats, formats)) {
const PuglDataOfferEvent offer = {
PUGL_DATA_OFFER, 0, (double)event->time / 1e3};
PUGL_DATA_OFFER, 0U, (double)event->time / 1e3};

puglEvent.offer = offer;
board->acceptedFormatIndex = UINT32_MAX;
@@ -1699,21 +1683,24 @@ handleSelectionRequest(const PuglWorld* const world,
}

/// Flush pending configure and expose events for all views
PUGL_WARN_UNUSED_RESULT
static PuglStatus
PUGL_WARN_UNUSED_RESULT static PuglStatus
flushExposures(PuglWorld* const world)
{
PuglStatus st0 = PUGL_SUCCESS;
PuglStatus st1 = PUGL_SUCCESS;
PuglStatus st2 = PUGL_SUCCESS;

// Send update events so the application can trigger redraws
for (size_t i = 0; i < world->numViews; ++i) {
PuglView* const view = world->views[i];

// Send update event so the application can trigger redraws
if (puglGetVisible(view)) {
puglDispatchSimpleEvent(view, PUGL_UPDATE);
if (puglGetVisible(world->views[i])) {
puglDispatchSimpleEvent(world->views[i], PUGL_UPDATE);
}
}

// Expose any dirty views
world->state = PUGL_WORLD_EXPOSING;
for (size_t i = 0; i < world->numViews; ++i) {
PuglView* const view = world->views[i];

// Copy and reset pending events (in case their handlers write new ones)
const PuglEvent configure = view->impl->pendingConfigure;
@@ -1753,7 +1740,7 @@ handleTimerEvent(PuglWorld* const world, const XEvent xevent)

for (size_t i = 0; i < world->impl->numTimers; ++i) {
if (world->impl->timers[i].alarm == notify->alarm) {
PuglEvent event = {{PUGL_TIMER, 0}};
PuglEvent event = {{PUGL_TIMER, 0U}};
event.timer.id = world->impl->timers[i].id;
puglDispatchEvent(world->impl->timers[i].view, &event);
}
@@ -1851,26 +1838,24 @@ dispatchX11Events(PuglWorld* const world)
return st;
}

#ifndef PUGL_DISABLE_DEPRECATED
PuglStatus
puglProcessEvents(PuglView* const view)
{
return puglUpdate(view->world, 0.0);
}
#endif

PuglStatus
puglUpdate(PuglWorld* const world, const double timeout)
{
const double startTime = puglGetTime(world);
PuglStatus st0 = PUGL_SUCCESS;
PuglStatus st1 = PUGL_SUCCESS;
const double startTime = puglGetTime(world);
const PuglWorldState startState = world->state;
PuglStatus st0 = PUGL_SUCCESS;
PuglStatus st1 = PUGL_SUCCESS;

world->impl->dispatchingEvents = true;
if (startState == PUGL_WORLD_IDLE) {
world->state = PUGL_WORLD_UPDATING;
} else if (startState != PUGL_WORLD_RECURSING) {
return PUGL_BAD_CALL;
}

if (timeout < 0.0) {
st0 = pollX11Socket(world, timeout);
st0 = st0 ? st0 : dispatchX11Events(world);
if (!(st0 = pollX11Socket(world, timeout))) {
st0 = dispatchX11Events(world);
}
} else if (timeout <= 0.001) {
st0 = dispatchX11Events(world);
} else {
@@ -1885,10 +1870,8 @@ puglUpdate(PuglWorld* const world, const double timeout)
}
}

st1 = flushExposures(world);

world->impl->dispatchingEvents = false;

st1 = flushExposures(world);
world->state = startState;
return st0 ? st0 : st1;
}

@@ -1896,38 +1879,52 @@ double
puglGetTime(const PuglWorld* const world)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
return 0.0;
}

return ((double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0) -
world->startTime;
}

PuglStatus
puglPostRedisplay(PuglView* const view)
puglObscureView(PuglView* const view)
{
PuglRect rect = puglGetFrame(view);
rect.x = 0;
rect.y = 0;

return puglPostRedisplayRect(view, rect);
return puglObscureRegion(
view, 0, 0, view->lastConfigure.width, view->lastConfigure.height);
}

PuglStatus
puglPostRedisplayRect(PuglView* const view, const PuglRect rect)
puglObscureRegion(PuglView* const view,
const int x,
const int y,
const unsigned width,
const unsigned height)
{
const PuglExposeEvent event = {
PUGL_EXPOSE, 0, rect.x, rect.y, rect.width, rect.height};
if (!puglIsValidPosition(x, y) || !puglIsValidSize(width, height)) {
return PUGL_BAD_PARAMETER;
}

const PuglCoord cx = MAX((PuglCoord)0, (PuglCoord)x);
const PuglCoord cy = MAX((PuglCoord)0, (PuglCoord)y);
const PuglSpan cw = MIN(view->lastConfigure.width, (PuglSpan)width);
const PuglSpan ch = MIN(view->lastConfigure.height, (PuglSpan)height);

const PuglExposeEvent event = {PUGL_EXPOSE, 0U, cx, cy, cw, ch};

if (view->world->impl->dispatchingEvents) {
PuglStatus st = PUGL_SUCCESS;
if (view->world->state == PUGL_WORLD_UPDATING) {
// Currently dispatching events, add/expand expose for the loop end
mergeExposeEvents(&view->impl->pendingExpose.expose, &event);
} else if (view->world->state == PUGL_WORLD_EXPOSING) {
st = PUGL_BAD_CALL;
} else if (view->impl->win) {
// Not dispatching events, send an X expose so we wake up next time
PuglEvent exposeEvent = {{PUGL_EXPOSE, 0}};
PuglEvent exposeEvent = {{PUGL_EXPOSE, 0U}};
exposeEvent.expose = event;
return puglSendEvent(view, &exposeEvent);
st = puglSendEvent(view, &exposeEvent);
}

return PUGL_SUCCESS;
return st;
}

PuglNativeView
@@ -1977,79 +1974,21 @@ puglGetScaleFactor(const PuglView* const view)
}

PuglStatus
puglSetFrame(PuglView* const view, const PuglRect frame)
{
if (!view->impl->win) {
// Set defaults to be used when realized
view->defaultX = frame.x;
view->defaultY = frame.y;
view->sizeHints[PUGL_DEFAULT_SIZE].width = frame.width;
view->sizeHints[PUGL_DEFAULT_SIZE].height = frame.height;
return PUGL_SUCCESS;
}

return puglX11Status(XMoveResizeWindow(view->world->impl->display,
view->impl->win,
frame.x,
frame.y,
frame.width,
frame.height));
}

PuglStatus
puglSetPosition(PuglView* const view, const int x, const int y)
puglSetWindowPosition(PuglView* const view, const int x, const int y)
{
Display* const display = view->world->impl->display;

if (x < INT16_MIN || x > INT16_MAX || y < INT16_MIN || y > INT16_MAX) {
return PUGL_BAD_PARAMETER;
}

if (!view->impl->win) {
// Set defaults to be used when realized
view->defaultX = x;
view->defaultY = y;
return PUGL_SUCCESS;
}

return puglX11Status(XMoveWindow(display,
return puglX11Status(XMoveWindow(view->world->impl->display,
view->impl->win,
(int)(x - view->impl->frameExtentLeft),
(int)(y - view->impl->frameExtentTop)));
}

PuglStatus
puglSetSize(PuglView* const view, const unsigned width, const unsigned height)
{
Display* const display = view->world->impl->display;

if (width > INT16_MAX || height > INT16_MAX) {
return PUGL_BAD_PARAMETER;
}

if (!view->impl->win) {
// Set defaults to be used when realized
view->sizeHints[PUGL_DEFAULT_SIZE].width = (PuglSpan)width;
view->sizeHints[PUGL_DEFAULT_SIZE].height = (PuglSpan)height;
return PUGL_SUCCESS;
}

return puglX11Status(XResizeWindow(display, view->impl->win, width, height));
}

PuglStatus
puglSetSizeHint(PuglView* const view,
const PuglSizeHint hint,
const PuglSpan width,
const PuglSpan height)
puglSetWindowSize(PuglView* const view,
const unsigned width,
const unsigned height)
{
if ((unsigned)hint >= PUGL_NUM_SIZE_HINTS) {
return PUGL_BAD_PARAMETER;
}

view->sizeHints[hint].width = width;
view->sizeHints[hint].height = height;
return updateSizeHints(view);
return puglX11Status(
XResizeWindow(view->world->impl->display, view->impl->win, width, height));
}

PuglStatus


+ 3
- 6
source/modules/dgl/src/pugl-upstream/src/x11.h View File

@@ -7,8 +7,8 @@
#include "attributes.h"
#include "types.h"

#include "pugl/attributes.h"
#include "pugl/pugl.h"
#include <pugl/attributes.h>
#include <pugl/pugl.h>

#include <X11/X.h>
#include <X11/Xlib.h>
@@ -75,7 +75,6 @@ struct PuglWorldInternalsImpl {
XID serverTimeCounter;
int syncEventBase;
bool syncSupported;
bool dispatchingEvents;
};

struct PuglInternalsImpl {
@@ -93,9 +92,7 @@ struct PuglInternalsImpl {
bool mapped;
};

PUGL_WARN_UNUSED_RESULT
PUGL_API
PuglStatus
PUGL_WARN_UNUSED_RESULT PUGL_API PuglStatus
puglX11Configure(PuglView* view);

#endif // PUGL_SRC_X11_H

+ 9
- 9
source/modules/dgl/src/pugl-upstream/src/x11_cairo.c View File

@@ -5,8 +5,8 @@
#include "types.h"
#include "x11.h"

#include "pugl/cairo.h"
#include "pugl/pugl.h"
#include <pugl/cairo.h>
#include <pugl/pugl.h>

#include <cairo-xlib.h>
#include <cairo.h>
@@ -19,10 +19,10 @@ typedef struct {
cairo_t* cr;
} PuglX11CairoSurface;

static PuglViewSize
static PuglArea
puglX11CairoGetViewSize(const PuglView* const view)
{
PuglViewSize size = {0U, 0U};
PuglArea size = {0U, 0U};

if (view->lastConfigure.type == PUGL_CONFIGURE) {
// Use the size of the last configured frame
@@ -97,11 +97,11 @@ puglX11CairoEnter(PuglView* view, const PuglExposeEvent* expose)
PuglStatus st = PUGL_SUCCESS;

if (expose) {
const PuglViewSize viewSize = puglX11CairoGetViewSize(view);
const PuglSpan right = (PuglSpan)(expose->x + expose->width);
const PuglSpan bottom = (PuglSpan)(expose->y + expose->height);
const PuglSpan surfaceWidth = MAX(right, viewSize.width);
const PuglSpan surfaceHeight = MAX(bottom, viewSize.height);
const PuglArea viewSize = puglX11CairoGetViewSize(view);
const PuglSpan right = (PuglSpan)(expose->x + expose->width);
const PuglSpan bottom = (PuglSpan)(expose->y + expose->height);
const PuglSpan surfaceWidth = MAX(right, viewSize.width);
const PuglSpan surfaceHeight = MAX(bottom, viewSize.height);
if (!(st = puglX11CairoOpen(view, surfaceWidth, surfaceHeight))) {
surface->cr = cairo_create(surface->front);
if (cairo_status(surface->cr)) {


+ 4
- 6
source/modules/dgl/src/pugl-upstream/src/x11_gl.c View File

@@ -6,8 +6,8 @@
#include "types.h"
#include "x11.h"

#include "pugl/gl.h"
#include "pugl/pugl.h"
#include <pugl/gl.h>
#include <pugl/pugl.h>

#include <GL/glx.h>
#include <X11/X.h>
@@ -101,8 +101,7 @@ puglX11GlConfigure(PuglView* view)
return PUGL_SUCCESS;
}

PUGL_WARN_UNUSED_RESULT
static PuglStatus
PUGL_WARN_UNUSED_RESULT static PuglStatus
puglX11GlEnter(PuglView* view, const PuglExposeEvent* PUGL_UNUSED(expose))
{
PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface;
@@ -115,8 +114,7 @@ puglX11GlEnter(PuglView* view, const PuglExposeEvent* PUGL_UNUSED(expose))
: PUGL_FAILURE;
}

PUGL_WARN_UNUSED_RESULT
static PuglStatus
PUGL_WARN_UNUSED_RESULT static PuglStatus
puglX11GlLeave(PuglView* view, const PuglExposeEvent* expose)
{
Display* const display = view->world->impl->display;


+ 2
- 2
source/modules/dgl/src/pugl-upstream/src/x11_stub.c View File

@@ -1,13 +1,13 @@
// Copyright 2012-2021 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC

#include "pugl/stub.h"
#include <pugl/stub.h>

#include "stub.h"
#include "types.h"
#include "x11.h"

#include "pugl/pugl.h"
#include <pugl/pugl.h>

const PuglBackend*
puglStubBackend(void)


+ 2
- 2
source/modules/dgl/src/pugl-upstream/src/x11_vulkan.c View File

@@ -8,8 +8,8 @@
#include "types.h"
#include "x11.h"

#include "pugl/pugl.h"
#include "pugl/vulkan.h"
#include <pugl/pugl.h>
#include <pugl/vulkan.h>

#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_xlib.h>


+ 96
- 100
source/modules/dgl/src/pugl.cpp View File

@@ -250,21 +250,23 @@ void puglSetMatchingBackendForCurrentBuild(PuglView* const view)

if (view->backend != nullptr)
{
#ifdef DGL_OPENGL
#if defined(DGL_USE_GLES2)
puglSetViewHint(view, PUGL_CONTEXT_API, PUGL_OPENGL_ES_API);
puglSetViewHint(view, PUGL_CONTEXT_PROFILE, PUGL_OPENGL_CORE_PROFILE);
puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 2);
#elif defined(DGL_USE_GLES3)
puglSetViewHint(view, PUGL_CONTEXT_API, PUGL_OPENGL_ES_API);
puglSetViewHint(view, PUGL_CONTEXT_PROFILE, PUGL_OPENGL_CORE_PROFILE);
puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 3);
#elif defined(DGL_USE_OPENGL3)
puglSetViewHint(view, PUGL_CONTEXT_API, PUGL_OPENGL_API);
puglSetViewHint(view, PUGL_CONTEXT_PROFILE, PUGL_OPENGL_CORE_PROFILE);
puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 3);
#else
#elif defined(DGL_OPENGL)
puglSetViewHint(view, PUGL_CONTEXT_API, PUGL_OPENGL_API);
puglSetViewHint(view, PUGL_CONTEXT_PROFILE, PUGL_OPENGL_COMPATIBILITY_PROFILE);
puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 2);
#endif
#endif
}
else
{
@@ -277,19 +279,20 @@ void puglSetMatchingBackendForCurrentBuild(PuglView* const view)

void puglRaiseWindow(PuglView* const view)
{
#if defined(DISTRHO_OS_HAIKU)
#elif defined(DISTRHO_OS_MAC)
if (NSWindow* const window = view->impl->window ? view->impl->window
: [view->impl->wrapperView window])
[window orderFrontRegardless];
#elif defined(DISTRHO_OS_WASM)
// this does the same as puglShow(view, PUGL_SHOW_FORCE_RAISE) + puglShow(view, PUGL_SHOW_RAISE)
#if defined(DISTRHO_OS_HAIKU)
#elif defined(DISTRHO_OS_MAC)
NSWindow* const window = [view->impl->wrapperView window];
[window orderFrontRegardless];
[window orderFront:view->impl->wrapperView];
#elif defined(DISTRHO_OS_WASM)
// nothing
#elif defined(DISTRHO_OS_WINDOWS)
#elif defined(DISTRHO_OS_WINDOWS)
SetForegroundWindow(view->impl->hwnd);
SetActiveWindow(view->impl->hwnd);
#elif defined(HAVE_X11)
#elif defined(HAVE_X11)
XRaiseWindow(view->world->impl->display, view->impl->win);
#endif
#endif
}

// --------------------------------------------------------------------------------------------------------------------
@@ -306,29 +309,31 @@ PuglStatus puglSetGeometryConstraints(PuglView* const view, const uint width, co
view->sizeHints[PUGL_FIXED_ASPECT].height = static_cast<PuglSpan>(height);
}

#if defined(DISTRHO_OS_HAIKU)
#elif defined(DISTRHO_OS_MAC)
#if defined(DISTRHO_OS_HAIKU)
#elif defined(DISTRHO_OS_MAC)
if (view->impl->window)
{
if (const PuglStatus status = updateSizeHint(view, PUGL_MIN_SIZE))
return status;

if (const PuglStatus status = updateSizeHint(view, PUGL_FIXED_ASPECT))
if (const PuglStatus status = puglUpdateSizeHints(view))
return status;
}
#elif defined(DISTRHO_OS_WASM)
#elif defined(DISTRHO_OS_WASM)
const char* const className = view->world->strings[PUGL_CLASS_NAME];
EM_ASM({
var canvasWrapper = document.getElementById(UTF8ToString($0)).parentElement;
canvasWrapper.style.setProperty("min-width", parseInt($1 / window.devicePixelRatio) + 'px');
canvasWrapper.style.setProperty("min-height", parseInt($2 / window.devicePixelRatio) + 'px');
}, className, width, height);
#elif defined(DISTRHO_OS_WINDOWS)
// nothing
#elif defined(DISTRHO_OS_WINDOWS)
// nothing
#elif defined(HAVE_X11)
#elif defined(HAVE_X11)
if (view->impl->win)
{
if (const PuglStatus status = updateSizeHints(view))
if (const PuglStatus status = puglUpdateSizeHints(view))
return status;

XFlush(view->world->impl->display);
}
#endif
#endif

return PUGL_SUCCESS;
}
@@ -340,99 +345,79 @@ void puglSetResizable(PuglView* const view, const bool resizable)
{
puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE);

#if defined(DISTRHO_OS_HAIKU)
#elif defined(DISTRHO_OS_MAC)
#if defined(DISTRHO_OS_HAIKU)
#elif defined(DISTRHO_OS_MAC)
if (PuglWindow* const window = view->impl->window)
{
const uint style = (NSClosableWindowMask | NSTitledWindowMask | NSMiniaturizableWindowMask)
| (resizable ? NSResizableWindowMask : 0x0);
| (resizable ? NSResizableWindowMask : 0);
[window setStyleMask:style];
}
// FIXME use [view setAutoresizingMask:NSViewNotSizable] ?
#elif defined(DISTRHO_OS_WASM)
// nothing
#elif defined(DISTRHO_OS_WINDOWS)
#elif defined(DISTRHO_OS_WASM)
puglUpdateSizeHints(view);
#elif defined(DISTRHO_OS_WINDOWS)
if (const HWND hwnd = view->impl->hwnd)
{
const uint winFlags = resizable ? GetWindowLong(hwnd, GWL_STYLE) | (WS_SIZEBOX | WS_MAXIMIZEBOX)
: GetWindowLong(hwnd, GWL_STYLE) & ~(WS_SIZEBOX | WS_MAXIMIZEBOX);
SetWindowLong(hwnd, GWL_STYLE, winFlags);
}
#elif defined(HAVE_X11)
updateSizeHints(view);
#endif
#elif defined(HAVE_X11)
puglUpdateSizeHints(view);
#endif
}

// --------------------------------------------------------------------------------------------------------------------
// set window size while also changing default

PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height)
PuglStatus puglSetSizeAndDefault(PuglView* const view, const uint width, const uint height)
{
if (width > INT16_MAX || height > INT16_MAX)
return PUGL_BAD_PARAMETER;

#ifdef DGL_USING_X11
// workaround issues in fluxbox, see https://github.com/lv2/pugl/issues/118
// NOTE troublesome if used under KDE
if (view->impl->win && !view->parent && !view->transientParent && std::getenv("KDE_SESSION_VERSION") == nullptr)
{
view->sizeHints[PUGL_DEFAULT_SIZE].width = view->sizeHints[PUGL_DEFAULT_SIZE].height = 0;
}
else
#endif
// set default size first
{
view->sizeHints[PUGL_DEFAULT_SIZE].width = static_cast<PuglSpan>(width);
view->sizeHints[PUGL_DEFAULT_SIZE].height = static_cast<PuglSpan>(height);
}
view->sizeHints[PUGL_DEFAULT_SIZE].width = view->sizeHints[PUGL_CURRENT_SIZE].width = width;
view->sizeHints[PUGL_DEFAULT_SIZE].height = view->sizeHints[PUGL_CURRENT_SIZE].height = height;

#if defined(DISTRHO_OS_HAIKU)
#elif defined(DISTRHO_OS_MAC)
#if defined(DISTRHO_OS_HAIKU)
#elif defined(DISTRHO_OS_MAC)
// matches upstream pugl
if (view->impl->wrapperView)
{
if (const PuglStatus status = puglSetSize(view, width, height))
return status;

// nothing to do for PUGL_DEFAULT_SIZE hint

if (const PuglStatus status = puglSetWindowSize(view, width, height))
return status;
}
#elif defined(DISTRHO_OS_WASM)
d_stdout("className is %s", view->world->strings[PUGL_CLASS_NAME]);
#elif defined(DISTRHO_OS_WASM)
if (const PuglStatus status = puglUpdateSizeHints(view))
return status;

emscripten_set_canvas_element_size(view->world->strings[PUGL_CLASS_NAME], width, height);
#elif defined(DISTRHO_OS_WINDOWS)
#elif defined(DISTRHO_OS_WINDOWS)
// matches upstream pugl, except we re-enter context after resize
if (view->impl->hwnd)
{
if (const PuglStatus status = puglSetSize(view, width, height))
return status;

// nothing to do for PUGL_DEFAULT_SIZE hint

if (const PuglStatus status = puglSetWindowSize(view, width, height))
return status;

// make sure to return context back to ourselves
puglBackendEnter(view);
}
#elif defined(HAVE_X11)
#elif defined(HAVE_X11)
// matches upstream pugl, adds flush at the end
if (view->impl->win)
{
if (const PuglStatus status = puglSetSize(view, width, height))
if (const PuglStatus status = puglUpdateSizeHints(view))
return status;

// updateSizeHints will use last known size, which is not yet updated
const PuglSpan lastWidth = view->lastConfigure.width;
const PuglSpan lastHeight = view->lastConfigure.height;
view->lastConfigure.width = static_cast<PuglSpan>(width);
view->lastConfigure.height = static_cast<PuglSpan>(height);

updateSizeHints(view);

view->lastConfigure.width = lastWidth;
view->lastConfigure.height = lastHeight;
if (const PuglStatus status = puglSetWindowSize(view, width, height))
return status;

// flush size changes
XFlush(view->world->impl->display);
}
#endif
#endif

return PUGL_SUCCESS;
}
@@ -456,11 +441,12 @@ void puglOnDisplayPrepare(PuglView*)
void puglFallbackOnResize(PuglView* const view, const uint width, const uint height)
{
#ifdef DGL_OPENGL
#if defined(DGL_USE_OPENGL3)
glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height));
#else
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#ifdef DGL_USE_OPENGL3
glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height));
#else
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, static_cast<GLdouble>(width), static_cast<GLdouble>(height), 0.0, 0.0, 1.0);
@@ -469,9 +455,10 @@ void puglFallbackOnResize(PuglView* const view, const uint width, const uint hei
glLoadIdentity();
#endif
#else
return;
// unused
(void)view;
(void)width;
(void)height;
#endif
}

@@ -618,55 +605,64 @@ void puglWin32ShowCentered(PuglView* const view)

PuglStatus puglX11UpdateWithoutExposures(PuglWorld* const world)
{
const bool wasDispatchingEvents = world->impl->dispatchingEvents;
world->impl->dispatchingEvents = true;
const PuglWorldState startState = world->state;
world->state = PUGL_WORLD_UPDATING;
PuglStatus st = PUGL_SUCCESS;

const double startTime = puglGetTime(world);
const double endTime = startTime + 0.03;
const double endTime = startTime + 0.03;

for (double t = startTime; !st && t < endTime; t = puglGetTime(world))
{
pollX11Socket(world, endTime - t);
st = dispatchX11Events(world);
if (!(st = pollX11Socket(world, endTime - t)))
st = dispatchX11Events(world);
}

world->impl->dispatchingEvents = wasDispatchingEvents;
world->state = startState;
return st;
}

// --------------------------------------------------------------------------------------------------------------------
// X11 specific, set dialog window type and pid hints
// X11 specific, set dialog window type

void puglX11SetWindowTypeAndPID(const PuglView* const view, const bool isStandalone)
void puglX11SetWindowType(const PuglView* const view, const bool isStandalone)
{
const PuglInternals* const impl = view->impl;
Display* const display = view->world->impl->display;

const pid_t pid = getpid();
const Atom _nwp = XInternAtom(display, "_NET_WM_PID", False);
XChangeProperty(display, impl->win, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1);

#if defined(DGL_X11_WINDOW_ICON_NAME) && defined(DGL_X11_WINDOW_ICON_SIZE)
if (isStandalone)
{
const Atom _nwi = XInternAtom(display, "_NET_WM_ICON", False);
XChangeProperty(display, impl->win, _nwi, XA_CARDINAL, 32, PropModeReplace,
(const uchar*)DGL_X11_WINDOW_ICON_NAME, DGL_X11_WINDOW_ICON_SIZE);
const Atom NET_WM_ICON = XInternAtom(display, "_NET_WM_ICON", False);
XChangeProperty(display,
impl->win,
NET_WM_ICON,
XA_CARDINAL,
32,
PropModeReplace,
reinterpret_cast<const uchar*>(DGL_X11_WINDOW_ICON_NAME),
DGL_X11_WINDOW_ICON_SIZE);
}
#endif

const Atom _wt = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
const Atom NET_WM_WINDOW_TYPE = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);

Atom _wts[2];
int numAtoms = 0;
Atom windowTypes[2];
int numWindowTypes = 0;

if (! isStandalone)
_wts[numAtoms++] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False);

_wts[numAtoms++] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);

XChangeProperty(display, impl->win, _wt, XA_ATOM, 32, PropModeReplace, (const uchar*)&_wts, numAtoms);
windowTypes[numWindowTypes++] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False);

windowTypes[numWindowTypes++] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);

XChangeProperty(display,
impl->win,
NET_WM_WINDOW_TYPE,
XA_ATOM,
32,
PropModeReplace,
reinterpret_cast<const uchar*>(&windowTypes),
numWindowTypes);
}

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


+ 3
- 3
source/modules/dgl/src/pugl.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
*
* 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
@@ -121,8 +121,8 @@ void puglWin32ShowCentered(PuglView* view);
// X11 specific, update world without triggering exposure events
PuglStatus puglX11UpdateWithoutExposures(PuglWorld* world);

// X11 specific, set dialog window type and pid hints
void puglX11SetWindowTypeAndPID(const PuglView* view, bool isStandalone);
// X11 specific, set dialog window type
void puglX11SetWindowType(const PuglView* view, bool isStandalone);

#endif



+ 3
- 4
source/modules/distrho/DistrhoPluginMain.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
*
* 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
@@ -29,15 +29,14 @@
#elif defined(DISTRHO_PLUGIN_TARGET_LV2)
# include "src/DistrhoPluginLV2.cpp"
# include "src/DistrhoPluginLV2export.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_MAPI)
# include "src/DistrhoPluginMAPI.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_VST2)
# include "src/DistrhoPluginVST2.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_VST3)
# include "src/DistrhoPluginVST3.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_EXPORT)
# include "src/DistrhoPluginExport.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_SHARED)
DISTRHO_PLUGIN_EXPORT DISTRHO_NAMESPACE::Plugin* createSharedPlugin();
DISTRHO_PLUGIN_EXPORT DISTRHO_NAMESPACE::Plugin* createSharedPlugin() { return DISTRHO_NAMESPACE::createPlugin(); }
#elif defined(DISTRHO_PLUGIN_TARGET_STATIC)
START_NAMESPACE_DISTRHO
Plugin* createStaticPlugin() { return createPlugin(); }


+ 8
- 6
source/modules/distrho/DistrhoUI.hpp View File

@@ -106,10 +106,11 @@ public:

The following example code can be use to extract individual colors:
```
const int red = (bgColor >> 24) & 0xff;
const int green = (bgColor >> 16) & 0xff;
const int blue = (bgColor >> 8) & 0xff;
int red = (bgColor >> 24) & 0xff;
int green = (bgColor >> 16) & 0xff;
int blue = (bgColor >> 8) & 0xff;
```
@see Color::fromRGB
*/
uint getBackgroundColor() const noexcept;

@@ -119,10 +120,11 @@ public:

The following example code can be use to extract individual colors:
```
const int red = (fgColor >> 24) & 0xff;
const int green = (fgColor >> 16) & 0xff;
const int blue = (fgColor >> 8) & 0xff;
int red = (fgColor >> 24) & 0xff;
int green = (fgColor >> 16) & 0xff;
int blue = (fgColor >> 8) & 0xff;
```
@see Color::fromRGB
*/
uint getForegroundColor() const noexcept;



+ 5
- 0
source/modules/distrho/extra/ScopedPointer.hpp View File

@@ -172,6 +172,11 @@ public:
/** Lets you access methods and properties of the object that this ScopedPointer refers to. */
ObjectType* operator->() const noexcept { return object; }

//==============================================================================
/** Removes the current object from this ScopedPointer and deletes it.
*/
void reset() noexcept { ObjectType* const o = object; object = nullptr; delete o; }

//==============================================================================
/** Removes the current object from this ScopedPointer without deleting it.
This will return the current object, and set the ScopedPointer to a null pointer.


+ 51
- 56
source/modules/distrho/extra/String.hpp View File

@@ -269,7 +269,7 @@ public:
/*
* Get length of the string.
*/
std::size_t length() const noexcept
size_t length() const noexcept
{
return fBufferLen;
}
@@ -295,7 +295,7 @@ public:
*/
bool contains(const char c) const noexcept
{
for (std::size_t i=0; i<fBufferLen; ++i)
for (size_t i=0; i<fBufferLen; ++i)
{
if (fBuffer[i] == c)
return true;
@@ -334,7 +334,7 @@ public:
/*
* Check if character at 'pos' is a digit.
*/
bool isDigit(const std::size_t pos) const noexcept
bool isDigit(const size_t pos) const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(pos < fBufferLen, false);

@@ -358,7 +358,7 @@ public:
{
DISTRHO_SAFE_ASSERT_RETURN(prefix != nullptr, false);

const std::size_t prefixLen(std::strlen(prefix));
const size_t prefixLen(std::strlen(prefix));

if (fBufferLen < prefixLen)
return false;
@@ -383,7 +383,7 @@ public:
{
DISTRHO_SAFE_ASSERT_RETURN(suffix != nullptr, false);

const std::size_t suffixLen(std::strlen(suffix));
const size_t suffixLen(std::strlen(suffix));

if (fBufferLen < suffixLen)
return false;
@@ -395,7 +395,7 @@ public:
* Find the first occurrence of character 'c' in the string.
* Returns "length()" if the character is not found.
*/
std::size_t find(const char c, bool* const found = nullptr) const noexcept
size_t find(const char c, bool* const found = nullptr) const noexcept
{
if (fBufferLen == 0 || c == '\0')
{
@@ -404,7 +404,7 @@ public:
return fBufferLen;
}

for (std::size_t i=0; i < fBufferLen; ++i)
for (size_t i=0; i < fBufferLen; ++i)
{
if (fBuffer[i] == c)
{
@@ -423,7 +423,7 @@ public:
* Find the first occurrence of string 'strBuf' in the string.
* Returns "length()" if the string is not found.
*/
std::size_t find(const char* const strBuf, bool* const found = nullptr) const noexcept
size_t find(const char* const strBuf, bool* const found = nullptr) const noexcept
{
if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
{
@@ -448,7 +448,7 @@ public:

if (found != nullptr)
*found = true;
return static_cast<std::size_t>(ret);
return static_cast<size_t>(ret);
}

if (found != nullptr)
@@ -460,7 +460,7 @@ public:
* Find the last occurrence of character 'c' in the string.
* Returns "length()" if the character is not found.
*/
std::size_t rfind(const char c, bool* const found = nullptr) const noexcept
size_t rfind(const char c, bool* const found = nullptr) const noexcept
{
if (fBufferLen == 0 || c == '\0')
{
@@ -469,7 +469,7 @@ public:
return fBufferLen;
}

for (std::size_t i=fBufferLen; i > 0; --i)
for (size_t i=fBufferLen; i > 0; --i)
{
if (fBuffer[i-1] == c)
{
@@ -488,7 +488,7 @@ public:
* Find the last occurrence of string 'strBuf' in the string.
* Returns "length()" if the string is not found.
*/
std::size_t rfind(const char* const strBuf, bool* const found = nullptr) const noexcept
size_t rfind(const char* const strBuf, bool* const found = nullptr) const noexcept
{
if (found != nullptr)
*found = false;
@@ -496,12 +496,12 @@ public:
if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
return fBufferLen;

const std::size_t strBufLen(std::strlen(strBuf));
const size_t strBufLen(std::strlen(strBuf));

std::size_t ret = fBufferLen;
size_t ret = fBufferLen;
const char* tmpBuf = fBuffer;

for (std::size_t i=0; i < fBufferLen; ++i)
for (size_t i=0; i < fBufferLen; ++i)
{
if (std::strstr(tmpBuf+1, strBuf) == nullptr && std::strncmp(tmpBuf, strBuf, strBufLen) == 0)
{
@@ -532,7 +532,7 @@ public:
{
DISTRHO_SAFE_ASSERT_RETURN(before != '\0' /* && after != '\0' */, *this);

for (std::size_t i=0; i < fBufferLen; ++i)
for (size_t i=0; i < fBufferLen; ++i)
{
if (fBuffer[i] == before)
fBuffer[i] = after;
@@ -551,7 +551,7 @@ public:
if (fBufferLen == 0)
return *this;

for (std::size_t i=0; i < fBufferLen; ++i)
for (size_t i=0; i < fBufferLen; ++i)
{
if (fBuffer[i] == c)
{
@@ -567,7 +567,7 @@ public:
/*
* Truncate the string to size 'n'.
*/
String& truncate(const std::size_t n) noexcept
String& truncate(const size_t n) noexcept
{
if (n >= fBufferLen)
return *this;
@@ -583,7 +583,7 @@ public:
*/
String& toBasic() noexcept
{
for (std::size_t i=0; i < fBufferLen; ++i)
for (size_t i=0; i < fBufferLen; ++i)
{
if (fBuffer[i] >= '0' && fBuffer[i] <= '9')
continue;
@@ -607,7 +607,7 @@ public:
{
static constexpr const char kCharDiff = 'a' - 'A';

for (std::size_t i=0; i < fBufferLen; ++i)
for (size_t i=0; i < fBufferLen; ++i)
{
if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
fBuffer[i] = static_cast<char>(fBuffer[i] + kCharDiff);
@@ -623,7 +623,7 @@ public:
{
static constexpr const char kCharDiff = 'a' - 'A';

for (std::size_t i=0; i < fBufferLen; ++i)
for (size_t i=0; i < fBufferLen; ++i)
{
if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
fBuffer[i] = static_cast<char>(fBuffer[i] - kCharDiff);
@@ -688,31 +688,28 @@ public:
// base64 stuff, based on http://www.adp-gmbh.ch/cpp/common/base64.html
// Copyright (C) 2004-2008 René Nyffenegger

static String asBase64(const void* const data, const std::size_t dataSize)
static String asBase64(const void* const data, const size_t dataSize)
{
static constexpr const char* const kBase64Chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";

#ifndef _MSC_VER
const std::size_t kTmpBufSize = std::min(d_nextPowerOf2(static_cast<uint32_t>(dataSize/3)), 65536U);
#else
constexpr std::size_t kTmpBufSize = 65536U;
#endif
const size_t strBufSize = std::min(d_nextPowerOf2(static_cast<uint32_t>(dataSize/3)), 65536U);
char* strBuf = static_cast<char*>(std::malloc(strBufSize));
DISTRHO_SAFE_ASSERT_RETURN(strBuf != nullptr, String());

const uchar* bytesToEncode((const uchar*)data);
strBuf[strBufSize] = '\0';
size_t strBufIndex = 0;

const uchar* bytesToEncode = static_cast<const uchar*>(data);

uint i=0, j=0;
uint charArray3[3], charArray4[4];

char strBuf[kTmpBufSize + 1];
strBuf[kTmpBufSize] = '\0';
std::size_t strBufIndex = 0;

String ret;

for (std::size_t s=0; s<dataSize; ++s)
for (size_t s = 0; s < dataSize; ++s)
{
charArray3[i++] = *(bytesToEncode++);

@@ -723,10 +720,10 @@ public:
charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
charArray4[3] = charArray3[2] & 0x3f;

for (i=0; i<4; ++i)
for (i = 0; i < 4; ++i)
strBuf[strBufIndex++] = kBase64Chars[charArray4[i]];

if (strBufIndex >= kTmpBufSize-7)
if (strBufIndex >= strBufSize - 7)
{
strBuf[strBufIndex] = '\0';
strBufIndex = 0;
@@ -739,7 +736,7 @@ public:

if (i != 0)
{
for (j=i; j<3; ++j)
for (j = i; j < 3; ++j)
charArray3[j] = '\0';

charArray4[0] = (charArray3[0] & 0xfc) >> 2;
@@ -747,7 +744,7 @@ public:
charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6);
charArray4[3] = charArray3[2] & 0x3f;

for (j=0; j<4 && i<3 && j<i+1; ++j)
for (j = 0; j < 4 && i < 3 && j < i + 1; ++j)
strBuf[strBufIndex++] = kBase64Chars[charArray4[j]];

for (; i++ < 3;)
@@ -760,6 +757,7 @@ public:
ret += strBuf;
}

std::free(strBuf);
return ret;
}

@@ -778,7 +776,7 @@ public:

char* newbufptr = newbuf;

for (std::size_t i=0; i < fBufferLen; ++i)
for (size_t i=0; i < fBufferLen; ++i)
{
const char c = fBuffer[i];

@@ -901,7 +899,7 @@ public:

char* newbufptr = newbuf;

for (std::size_t i=0; i < fBufferLen; ++i)
for (size_t i=0; i < fBufferLen; ++i)
{
const char c = fBuffer[i];

@@ -957,19 +955,16 @@ public:
return fBuffer;
}

char operator[](const std::size_t pos) const noexcept
char operator[](const size_t pos) const noexcept
{
if (pos < fBufferLen)
return fBuffer[pos];

d_safe_assert("pos < fBufferLen", __FILE__, __LINE__);

static char fallback;
fallback = '\0';
return fallback;
return '\0';
}

char& operator[](const std::size_t pos) noexcept
char& operator[](const size_t pos) noexcept
{
if (pos < fBufferLen)
return fBuffer[pos];
@@ -1020,7 +1015,7 @@ public:
if (strBuf == nullptr || strBuf[0] == '\0')
return *this;

const std::size_t strBufLen = std::strlen(strBuf);
const size_t strBufLen = std::strlen(strBuf);

// for empty strings, we can just take the appended string as our entire data
if (isEmpty())
@@ -1054,8 +1049,8 @@ public:
if (isEmpty())
return String(strBuf);

const std::size_t strBufLen = std::strlen(strBuf);
const std::size_t newBufSize = fBufferLen + strBufLen;
const size_t strBufLen = std::strlen(strBuf);
const size_t newBufSize = fBufferLen + strBufLen;
char* const newBuf = static_cast<char*>(std::malloc(newBufSize + 1));
DISTRHO_SAFE_ASSERT_RETURN(newBuf != nullptr, String());

@@ -1080,7 +1075,7 @@ public:

private:
char* fBuffer; // the actual string buffer
std::size_t fBufferLen; // string length
size_t fBufferLen; // string length
bool fBufferAlloc; // wherever the buffer is allocated, not using _null()

/*
@@ -1101,7 +1096,7 @@ private:
* - Allocates string only if 'strBuf' is not null and new string contents are different
* - If 'strBuf' is null, 'size' must be 0
*/
void _dup(const char* const strBuf, const std::size_t size = 0) noexcept
void _dup(const char* const strBuf, const size_t size = 0) noexcept
{
if (strBuf != nullptr)
{
@@ -1158,9 +1153,9 @@ String operator+(const String& strBefore, const char* const strBufAfter) noexcep
if (strBefore.isEmpty())
return String(strBufAfter);

const std::size_t strBeforeLen = strBefore.length();
const std::size_t strBufAfterLen = std::strlen(strBufAfter);
const std::size_t newBufSize = strBeforeLen + strBufAfterLen;
const size_t strBeforeLen = strBefore.length();
const size_t strBufAfterLen = std::strlen(strBufAfter);
const size_t newBufSize = strBeforeLen + strBufAfterLen;
char* const newBuf = static_cast<char*>(malloc(newBufSize + 1));
DISTRHO_SAFE_ASSERT_RETURN(newBuf != nullptr, String());

@@ -1178,9 +1173,9 @@ String operator+(const char* const strBufBefore, const String& strAfter) noexcep
if (strBufBefore == nullptr || strBufBefore[0] == '\0')
return strAfter;

const std::size_t strBufBeforeLen = std::strlen(strBufBefore);
const std::size_t strAfterLen = strAfter.length();
const std::size_t newBufSize = strBufBeforeLen + strAfterLen;
const size_t strBufBeforeLen = std::strlen(strBufBefore);
const size_t strAfterLen = strAfter.length();
const size_t newBufSize = strBufBeforeLen + strAfterLen;
char* const newBuf = static_cast<char*>(malloc(newBufSize + 1));
DISTRHO_SAFE_ASSERT_RETURN(newBuf != nullptr, String());



+ 6
- 5
source/modules/distrho/src/DistrhoUIInternal.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
*
* 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
@@ -21,18 +21,18 @@

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// UI exporter class

class UIExporter
{
// -------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// UI Widget and its private data

UI* ui;
UI::PrivateData* uiData;

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

public:
UIExporter(void* const callbacksPtr,
@@ -47,11 +47,12 @@ public:
const char* const bundlePath = nullptr,
void* const dspPtr = nullptr,
const double scaleFactor = 0.0,
const DGL_NAMESPACE::Application::Type appType = DGL_NAMESPACE::Application::kTypeAuto,
const uint32_t bgColor = 0,
const uint32_t fgColor = 0xffffffff,
const char* const appClassName = nullptr)
: ui(nullptr),
uiData(new UI::PrivateData(appClassName))
uiData(new UI::PrivateData(appClassName, appType))
{
uiData->sampleRate = sampleRate;
uiData->bundlePath = bundlePath != nullptr ? strdup(bundlePath) : nullptr;


+ 14
- 11
source/modules/distrho/src/DistrhoUIPrivateData.hpp View File

@@ -67,14 +67,14 @@ START_NAMESPACE_DISTRHO
int dpf_webview_start(int argc, char* argv[]);
#endif

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// Plugin Application, will set class name based on plugin details

class PluginApplication : public DGL_NAMESPACE::Application
{
public:
explicit PluginApplication(const char* className)
: DGL_NAMESPACE::Application(DISTRHO_UI_IS_STANDALONE)
explicit PluginApplication(const char* className, const Application::Type type)
: DGL_NAMESPACE::Application(DISTRHO_UI_IS_STANDALONE, type)
{
#if defined(__MOD_DEVICES__) || !defined(__EMSCRIPTEN__)
if (className == nullptr)
@@ -108,7 +108,7 @@ public:
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication)
};

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// Plugin Window, will pass some Window events to UI

class PluginWindow : public DGL_NAMESPACE::Window
@@ -138,7 +138,10 @@ public:

// this is called just before creating UI, ensuring proper context to it
if (pData->initPost())
{
puglBackendEnter(pData->view);
pData->createContextIfNeeded();
}
}

~PluginWindow() override
@@ -240,7 +243,7 @@ protected:
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow)
};

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// UI callbacks

typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started);
@@ -250,7 +253,7 @@ typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8
typedef void (*setSizeFunc) (void* ptr, uint width, uint height);
typedef bool (*fileRequestFunc) (void* ptr, const char* key);

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// UI private data

struct UI::PrivateData {
@@ -289,8 +292,8 @@ struct UI::PrivateData {
setSizeFunc setSizeCallbackFunc;
fileRequestFunc fileRequestCallbackFunc;

PrivateData(const char* const appClassName) noexcept
: app(appClassName),
PrivateData(const char* const appClassName, const DGL_NAMESPACE::Application::Type appType) noexcept
: app(appClassName, appType),
window(nullptr),
#if DISTRHO_UI_USE_WEB_VIEW
webview(nullptr),
@@ -389,7 +392,7 @@ struct UI::PrivateData {
#endif
};

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// UI private data fileRequestCallback, which requires PluginWindow definitions

inline bool UI::PrivateData::fileRequestCallback(const char* const key)
@@ -416,7 +419,7 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key)
return false;
}

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// PluginWindow onFileSelected that require UI::PrivateData definitions

#if DISTRHO_UI_FILE_BROWSER
@@ -454,7 +457,7 @@ inline void PluginWindow::onFileSelected(const char* const filename)
}
#endif

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

END_NAMESPACE_DISTRHO



+ 8
- 3
source/modules/distrho/src/DistrhoUtils.cpp View File

@@ -119,8 +119,10 @@ const char* getPluginFormatName() noexcept
static inline
void _createDirIfNeeded(const char* const dir)
{
if (access(dir, F_OK) != 0)
mkdir(dir, 0755);
try {
if (access(dir, F_OK) != 0)
mkdir(dir, 0755);
} DISTRHO_SAFE_EXCEPTION("createDirIfNeeded");
}
#endif

@@ -255,7 +257,10 @@ static const char* _getDocumentsDir()

// ${XDG_CONFIG_HOME}/user-dirs.dirs does not exist or has bad data
if (dir.isEmpty())
dir = _getDocumentsDir();
{
dir = _getHomeDir();
dir += "Documents/";
}

_createDirIfNeeded(dir);
#endif


Loading…
Cancel
Save