DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

pugl.cpp (22921B)


      1 /*
      2  * DISTRHO Plugin Framework (DPF)
      3  * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com>
      4  *
      5  * Permission to use, copy, modify, and/or distribute this software for any purpose with
      6  * or without fee is hereby granted, provided that the above copyright notice and this
      7  * permission notice appear in all copies.
      8  *
      9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
     10  * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
     11  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
     12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
     13  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #include "pugl.hpp"
     18 
     19 // --------------------------------------------------------------------------------------------------------------------
     20 // include base headers
     21 
     22 #ifdef DGL_CAIRO
     23 # include <cairo.h>
     24 #endif
     25 #ifdef DGL_OPENGL
     26 # include "../OpenGL-include.hpp"
     27 #endif
     28 #ifdef DGL_VULKAN
     29 # include <vulkan/vulkan_core.h>
     30 #endif
     31 
     32 /* we will include all header files used in pugl in their C++ friendly form, then pugl stuff in custom namespace */
     33 #include <cassert>
     34 #include <cmath>
     35 #include <cstdlib>
     36 #include <cstdio>
     37 #include <cstring>
     38 #include <ctime>
     39 
     40 #if defined(DISTRHO_OS_HAIKU)
     41 # include <Application.h>
     42 # include <Window.h>
     43 # ifdef DGL_OPENGL
     44 #  include <GL/gl.h>
     45 #  include <opengl/GLView.h>
     46 # endif
     47 #elif defined(DISTRHO_OS_MAC)
     48 # import <Cocoa/Cocoa.h>
     49 # include <dlfcn.h>
     50 # include <mach/mach_time.h>
     51 # ifdef DGL_CAIRO
     52 #  include <cairo-quartz.h>
     53 # endif
     54 # ifdef DGL_VULKAN
     55 #  import <QuartzCore/CAMetalLayer.h>
     56 #  include <vulkan/vulkan_macos.h>
     57 # endif
     58 #elif defined(DISTRHO_OS_WASM)
     59 # include <emscripten/emscripten.h>
     60 # include <emscripten/html5.h>
     61 # ifdef DGL_OPENGL
     62 #  include <EGL/egl.h>
     63 # endif
     64 #elif defined(DISTRHO_OS_WINDOWS)
     65 # include <wctype.h>
     66 # include <winsock2.h>
     67 # include <windows.h>
     68 # include <windowsx.h>
     69 # ifdef DGL_CAIRO
     70 #  include <cairo-win32.h>
     71 # endif
     72 # ifdef DGL_OPENGL
     73 #  include <GL/gl.h>
     74 # endif
     75 # ifdef DGL_VULKAN
     76 #  include <vulkan/vulkan.h>
     77 #  include <vulkan/vulkan_win32.h>
     78 # endif
     79 #elif defined(HAVE_X11)
     80 # include <dlfcn.h>
     81 # include <limits.h>
     82 # include <unistd.h>
     83 # include <sys/select.h>
     84 // # include <sys/time.h>
     85 # include <X11/X.h>
     86 # include <X11/Xatom.h>
     87 # include <X11/Xlib.h>
     88 # include <X11/Xresource.h>
     89 # include <X11/Xutil.h>
     90 # include <X11/keysym.h>
     91 # ifdef HAVE_XCURSOR
     92 #  include <X11/Xcursor/Xcursor.h>
     93 // #  include <X11/cursorfont.h>
     94 # endif
     95 # ifdef HAVE_XRANDR
     96 #  include <X11/extensions/Xrandr.h>
     97 # endif
     98 # ifdef HAVE_XSYNC
     99 #  include <X11/extensions/sync.h>
    100 #  include <X11/extensions/syncconst.h>
    101 # endif
    102 # ifdef DGL_CAIRO
    103 #  include <cairo-xlib.h>
    104 # endif
    105 # ifdef DGL_OPENGL
    106 #  include <GL/glx.h>
    107 # endif
    108 # ifdef DGL_VULKAN
    109 #  include <vulkan/vulkan_xlib.h>
    110 # endif
    111 #endif
    112 
    113 #ifndef DGL_FILE_BROWSER_DISABLED
    114 # define FILE_BROWSER_DIALOG_DGL_NAMESPACE
    115 # define FILE_BROWSER_DIALOG_NAMESPACE DGL_NAMESPACE
    116 # define DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED
    117 START_NAMESPACE_DGL
    118 # include "../../distrho/extra/FileBrowserDialogImpl.hpp"
    119 END_NAMESPACE_DGL
    120 # include "../../distrho/extra/FileBrowserDialogImpl.cpp"
    121 #endif
    122 
    123 #if defined(DGL_USING_X11) && defined(DGL_X11_WINDOW_ICON_NAME)
    124 extern const ulong* DGL_X11_WINDOW_ICON_NAME;
    125 #endif
    126 
    127 #ifndef DISTRHO_OS_MAC
    128 START_NAMESPACE_DGL
    129 #endif
    130 
    131 // --------------------------------------------------------------------------------------------------------------------
    132 
    133 #if defined(DISTRHO_OS_HAIKU)
    134 # include "pugl-extra/haiku.cpp"
    135 # include "pugl-extra/haiku_stub.cpp"
    136 # ifdef DGL_OPENGL
    137 #  include "pugl-extra/haiku_gl.cpp"
    138 # endif
    139 #elif defined(DISTRHO_OS_MAC)
    140 # ifndef DISTRHO_MACOS_NAMESPACE_MACRO
    141 #  ifndef DISTRHO_MACOS_NAMESPACE_TIME
    142 #   define DISTRHO_MACOS_NAMESPACE_TIME __apple_build_version__
    143 #  endif
    144 #  define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, SEP, TIME, INTERFACE) NS ## SEP ## TIME ## SEP ## INTERFACE
    145 #  define DISTRHO_MACOS_NAMESPACE_MACRO(NS, TIME, INTERFACE) DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, _, TIME, INTERFACE)
    146 #  define PuglCairoView      DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglCairoView)
    147 #  define PuglOpenGLView     DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglOpenGLView)
    148 #  define PuglStubView       DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglStubView)
    149 #  define PuglVulkanView     DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglVulkanView)
    150 #  define PuglWindow         DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglWindow)
    151 #  define PuglWindowDelegate DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglWindowDelegate)
    152 #  define PuglWrapperView    DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglWrapperView)
    153 # endif
    154 # pragma clang diagnostic push
    155 # pragma clang diagnostic ignored "-Wdeprecated-declarations"
    156 # import "pugl-upstream/src/mac.m"
    157 # import "pugl-upstream/src/mac_stub.m"
    158 # ifdef DGL_CAIRO
    159 #  import "pugl-upstream/src/mac_cairo.m"
    160 # endif
    161 # ifdef DGL_OPENGL
    162 #  import "pugl-upstream/src/mac_gl.m"
    163 # endif
    164 # ifdef DGL_VULKAN
    165 #  import "pugl-upstream/src/mac_vulkan.m"
    166 # endif
    167 # pragma clang diagnostic pop
    168 #elif defined(DISTRHO_OS_WASM)
    169 # include "pugl-extra/wasm.c"
    170 # include "pugl-extra/wasm_stub.c"
    171 # ifdef DGL_OPENGL
    172 #  include "pugl-extra/wasm_gl.c"
    173 # endif
    174 #elif defined(DISTRHO_OS_WINDOWS)
    175 # include "pugl-upstream/src/win.c"
    176 # include "pugl-upstream/src/win_stub.c"
    177 # ifdef DGL_CAIRO
    178 #  include "pugl-upstream/src/win_cairo.c"
    179 # endif
    180 # ifdef DGL_OPENGL
    181 #  include "pugl-upstream/src/win_gl.c"
    182 # endif
    183 # ifdef DGL_VULKAN
    184 #  include "pugl-upstream/src/win_vulkan.c"
    185 # endif
    186 #elif defined(HAVE_X11)
    187 # if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
    188 #  pragma GCC diagnostic push
    189 #  pragma GCC diagnostic ignored "-Wsign-conversion"
    190 # endif
    191 # include "pugl-upstream/src/x11.c"
    192 # if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
    193 #  pragma GCC diagnostic pop
    194 # endif
    195 # include "pugl-upstream/src/x11_stub.c"
    196 # ifdef DGL_CAIRO
    197 #  include "pugl-upstream/src/x11_cairo.c"
    198 # endif
    199 # ifdef DGL_OPENGL
    200 #  include "pugl-upstream/src/x11_gl.c"
    201 # endif
    202 # ifdef DGL_VULKAN
    203 #  include "pugl-upstream/src/x11_vulkan.c"
    204 # endif
    205 #endif
    206 
    207 #include "pugl-upstream/src/common.c"
    208 #include "pugl-upstream/src/internal.c"
    209 
    210 // --------------------------------------------------------------------------------------------------------------------
    211 // DGL specific, expose backend enter
    212 
    213 bool puglBackendEnter(PuglView* const view)
    214 {
    215     return view->backend->enter(view, nullptr) == PUGL_SUCCESS;
    216 }
    217 
    218 // --------------------------------------------------------------------------------------------------------------------
    219 // DGL specific, expose backend leave
    220 
    221 bool puglBackendLeave(PuglView* const view)
    222 {
    223     return view->backend->leave(view, nullptr) == PUGL_SUCCESS;
    224 }
    225 
    226 // --------------------------------------------------------------------------------------------------------------------
    227 // DGL specific, assigns backend that matches current DGL build
    228 
    229 void puglSetMatchingBackendForCurrentBuild(PuglView* const view)
    230 {
    231    #ifdef DGL_CAIRO
    232     puglSetBackend(view, puglCairoBackend());
    233    #endif
    234    #ifdef DGL_OPENGL
    235     puglSetBackend(view, puglGlBackend());
    236    #endif
    237    #ifdef DGL_VULKAN
    238     puglSetBackend(view, puglVulkanBackend());
    239    #endif
    240 
    241     if (view->backend != nullptr)
    242     {
    243       #ifdef DGL_OPENGL
    244        #if defined(DGL_USE_GLES2)
    245         puglSetViewHint(view, PUGL_CONTEXT_API, PUGL_OPENGL_ES_API);
    246         puglSetViewHint(view, PUGL_CONTEXT_PROFILE, PUGL_OPENGL_CORE_PROFILE);
    247         puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 2);
    248        #elif defined(DGL_USE_OPENGL3)
    249         puglSetViewHint(view, PUGL_CONTEXT_API, PUGL_OPENGL_API);
    250         puglSetViewHint(view, PUGL_CONTEXT_PROFILE, PUGL_OPENGL_CORE_PROFILE);
    251         puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 3);
    252        #else
    253         puglSetViewHint(view, PUGL_CONTEXT_API, PUGL_OPENGL_API);
    254         puglSetViewHint(view, PUGL_CONTEXT_PROFILE, PUGL_OPENGL_COMPATIBILITY_PROFILE);
    255         puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 2);
    256        #endif
    257       #endif
    258     }
    259     else
    260     {
    261         puglSetBackend(view, puglStubBackend());
    262     }
    263 }
    264 
    265 // --------------------------------------------------------------------------------------------------------------------
    266 // bring view window into the foreground, aka "raise" window
    267 
    268 void puglRaiseWindow(PuglView* const view)
    269 {
    270 #if defined(DISTRHO_OS_HAIKU)
    271 #elif defined(DISTRHO_OS_MAC)
    272     if (NSWindow* const window = view->impl->window ? view->impl->window
    273                                                     : [view->impl->wrapperView window])
    274         [window orderFrontRegardless];
    275 #elif defined(DISTRHO_OS_WASM)
    276     // nothing
    277 #elif defined(DISTRHO_OS_WINDOWS)
    278     SetForegroundWindow(view->impl->hwnd);
    279     SetActiveWindow(view->impl->hwnd);
    280 #elif defined(HAVE_X11)
    281     XRaiseWindow(view->world->impl->display, view->impl->win);
    282 #endif
    283 }
    284 
    285 // --------------------------------------------------------------------------------------------------------------------
    286 // Combined puglSetSizeHint using PUGL_MIN_SIZE and PUGL_FIXED_ASPECT
    287 
    288 PuglStatus puglSetGeometryConstraints(PuglView* const view, const uint width, const uint height, const bool aspect)
    289 {
    290     view->sizeHints[PUGL_MIN_SIZE].width = static_cast<PuglSpan>(width);
    291     view->sizeHints[PUGL_MIN_SIZE].height = static_cast<PuglSpan>(height);
    292 
    293     if (aspect)
    294     {
    295         view->sizeHints[PUGL_FIXED_ASPECT].width = static_cast<PuglSpan>(width);
    296         view->sizeHints[PUGL_FIXED_ASPECT].height = static_cast<PuglSpan>(height);
    297     }
    298 
    299 #if defined(DISTRHO_OS_HAIKU)
    300 #elif defined(DISTRHO_OS_MAC)
    301     if (view->impl->window)
    302     {
    303         if (const PuglStatus status = updateSizeHint(view, PUGL_MIN_SIZE))
    304             return status;
    305 
    306         if (const PuglStatus status = updateSizeHint(view, PUGL_FIXED_ASPECT))
    307             return status;
    308     }
    309 #elif defined(DISTRHO_OS_WASM)
    310     // nothing
    311 #elif defined(DISTRHO_OS_WINDOWS)
    312     // nothing
    313 #elif defined(HAVE_X11)
    314     if (view->impl->win)
    315     {
    316         if (const PuglStatus status = updateSizeHints(view))
    317             return status;
    318 
    319         XFlush(view->world->impl->display);
    320     }
    321 #endif
    322 
    323     return PUGL_SUCCESS;
    324 }
    325 
    326 // --------------------------------------------------------------------------------------------------------------------
    327 // set view as resizable (or not) during runtime
    328 
    329 void puglSetResizable(PuglView* const view, const bool resizable)
    330 {
    331     puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE);
    332 
    333 #if defined(DISTRHO_OS_HAIKU)
    334 #elif defined(DISTRHO_OS_MAC)
    335     if (PuglWindow* const window = view->impl->window)
    336     {
    337         const uint style = (NSClosableWindowMask | NSTitledWindowMask | NSMiniaturizableWindowMask)
    338                          | (resizable ? NSResizableWindowMask : 0x0);
    339         [window setStyleMask:style];
    340     }
    341     // FIXME use [view setAutoresizingMask:NSViewNotSizable] ?
    342 #elif defined(DISTRHO_OS_WASM)
    343     // nothing
    344 #elif defined(DISTRHO_OS_WINDOWS)
    345     if (const HWND hwnd = view->impl->hwnd)
    346     {
    347         const uint winFlags = resizable ? GetWindowLong(hwnd, GWL_STYLE) |  (WS_SIZEBOX | WS_MAXIMIZEBOX)
    348                                         : GetWindowLong(hwnd, GWL_STYLE) & ~(WS_SIZEBOX | WS_MAXIMIZEBOX);
    349         SetWindowLong(hwnd, GWL_STYLE, winFlags);
    350     }
    351 #elif defined(HAVE_X11)
    352     updateSizeHints(view);
    353 #endif
    354 }
    355 
    356 // --------------------------------------------------------------------------------------------------------------------
    357 // set window size while also changing default
    358 
    359 PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height)
    360 {
    361     if (width > INT16_MAX || height > INT16_MAX)
    362         return PUGL_BAD_PARAMETER;
    363 
    364 #ifdef DGL_USING_X11
    365     // workaround issues in fluxbox, see https://github.com/lv2/pugl/issues/118
    366     if (view->impl->win && !view->parent && !view->transientParent)
    367     {
    368         view->sizeHints[PUGL_DEFAULT_SIZE].width = view->sizeHints[PUGL_DEFAULT_SIZE].height = 0;
    369     }
    370     else
    371 #endif
    372     // set default size first
    373     {
    374         view->sizeHints[PUGL_DEFAULT_SIZE].width = static_cast<PuglSpan>(width);
    375         view->sizeHints[PUGL_DEFAULT_SIZE].height = static_cast<PuglSpan>(height);
    376     }
    377 
    378 #if defined(DISTRHO_OS_HAIKU)
    379 #elif defined(DISTRHO_OS_MAC)
    380     // matches upstream pugl
    381     if (view->impl->wrapperView)
    382     {
    383         if (const PuglStatus status = puglSetSize(view, width, height))
    384             return status;
    385 
    386         // nothing to do for PUGL_DEFAULT_SIZE hint
    387     }
    388 #elif defined(DISTRHO_OS_WASM)
    389     d_stdout("className is %s", view->world->strings[PUGL_CLASS_NAME]);
    390     emscripten_set_canvas_element_size(view->world->strings[PUGL_CLASS_NAME], width, height);
    391 #elif defined(DISTRHO_OS_WINDOWS)
    392     // matches upstream pugl, except we re-enter context after resize
    393     if (view->impl->hwnd)
    394     {
    395         if (const PuglStatus status = puglSetSize(view, width, height))
    396             return status;
    397 
    398         // nothing to do for PUGL_DEFAULT_SIZE hint
    399 
    400         // make sure to return context back to ourselves
    401         puglBackendEnter(view);
    402     }
    403 #elif defined(HAVE_X11)
    404     // matches upstream pugl, adds flush at the end
    405     if (view->impl->win)
    406     {
    407         if (const PuglStatus status = puglSetSize(view, width, height))
    408             return status;
    409 
    410         // updateSizeHints will use last known size, which is not yet updated
    411         const PuglSpan lastWidth = view->lastConfigure.width;
    412         const PuglSpan lastHeight = view->lastConfigure.height;
    413         view->lastConfigure.width = static_cast<PuglSpan>(width);
    414         view->lastConfigure.height = static_cast<PuglSpan>(height);
    415 
    416         updateSizeHints(view);
    417 
    418         view->lastConfigure.width = lastWidth;
    419         view->lastConfigure.height = lastHeight;
    420 
    421         // flush size changes
    422         XFlush(view->world->impl->display);
    423     }
    424 #endif
    425 
    426     return PUGL_SUCCESS;
    427 }
    428 
    429 // --------------------------------------------------------------------------------------------------------------------
    430 // DGL specific, build-specific drawing prepare
    431 
    432 void puglOnDisplayPrepare(PuglView*)
    433 {
    434   #ifdef DGL_OPENGL
    435     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    436    #ifndef DGL_USE_OPENGL3
    437     glLoadIdentity();
    438    #endif
    439   #endif
    440 }
    441 
    442 // --------------------------------------------------------------------------------------------------------------------
    443 // DGL specific, build-specific fallback resize
    444 
    445 void puglFallbackOnResize(PuglView* const view, const uint width, const uint height)
    446 {
    447   #ifdef DGL_OPENGL
    448     glEnable(GL_BLEND);
    449     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    450    #ifdef DGL_USE_OPENGL3
    451     glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height));
    452    #else
    453     glMatrixMode(GL_PROJECTION);
    454     glLoadIdentity();
    455     glOrtho(0.0, static_cast<GLdouble>(width), static_cast<GLdouble>(height), 0.0, 0.0, 1.0);
    456     glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height));
    457     glMatrixMode(GL_MODELVIEW);
    458     glLoadIdentity();
    459    #endif
    460   #else
    461     return;
    462     // unused
    463     (void)view;
    464   #endif
    465 }
    466 
    467 // --------------------------------------------------------------------------------------------------------------------
    468 
    469 #if defined(DISTRHO_OS_HAIKU)
    470 
    471 // --------------------------------------------------------------------------------------------------------------------
    472 
    473 #elif defined(DISTRHO_OS_MAC)
    474 
    475 // --------------------------------------------------------------------------------------------------------------------
    476 // macOS specific, add another view's window as child
    477 
    478 PuglStatus
    479 puglMacOSAddChildWindow(PuglView* const view, PuglView* const child)
    480 {
    481     if (NSWindow* const viewWindow = view->impl->window ? view->impl->window
    482                                                         : [view->impl->wrapperView window])
    483     {
    484         if (NSWindow* const childWindow = child->impl->window ? child->impl->window
    485                                                               : [child->impl->wrapperView window])
    486         {
    487             [viewWindow addChildWindow:childWindow ordered:NSWindowAbove];
    488             return PUGL_SUCCESS;
    489         }
    490     }
    491 
    492     return PUGL_FAILURE;
    493 }
    494 
    495 // --------------------------------------------------------------------------------------------------------------------
    496 // macOS specific, remove another view's window as child
    497 
    498 PuglStatus
    499 puglMacOSRemoveChildWindow(PuglView* const view, PuglView* const child)
    500 {
    501     if (NSWindow* const viewWindow = view->impl->window ? view->impl->window
    502                                                         : [view->impl->wrapperView window])
    503     {
    504         if (NSWindow* const childWindow = child->impl->window ? child->impl->window
    505                                                               : [child->impl->wrapperView window])
    506         {
    507             [viewWindow removeChildWindow:childWindow];
    508             return PUGL_SUCCESS;
    509         }
    510     }
    511 
    512     return PUGL_FAILURE;
    513 }
    514 
    515 // --------------------------------------------------------------------------------------------------------------------
    516 // macOS specific, center view based on parent coordinates (if there is one)
    517 
    518 void puglMacOSShowCentered(PuglView* const view)
    519 {
    520     if (puglShow(view, PUGL_SHOW_RAISE) != PUGL_SUCCESS)
    521         return;
    522 
    523     if (view->transientParent != 0)
    524     {
    525         NSWindow* const transientWindow = [(NSView*)view->transientParent window];
    526         DISTRHO_SAFE_ASSERT_RETURN(transientWindow != nullptr,);
    527 
    528         const NSRect ourFrame       = [view->impl->window frame];
    529         const NSRect transientFrame = [transientWindow frame];
    530 
    531         const int x = transientFrame.origin.x + (transientFrame.size.width - ourFrame.size.width) / 2;
    532         const int y = transientFrame.origin.y + (transientFrame.size.height - ourFrame.size.height) / 2;
    533 
    534         [view->impl->window setFrameTopLeftPoint:NSMakePoint(x, y)];
    535     }
    536     else
    537     {
    538         [view->impl->window center];
    539     }
    540 }
    541 
    542 // --------------------------------------------------------------------------------------------------------------------
    543 
    544 #elif defined(DISTRHO_OS_WINDOWS)
    545 
    546 // --------------------------------------------------------------------------------------------------------------------
    547 // win32 specific, call ShowWindow with SW_RESTORE
    548 
    549 void puglWin32RestoreWindow(PuglView* const view)
    550 {
    551     PuglInternals* impl = view->impl;
    552     DISTRHO_SAFE_ASSERT_RETURN(impl->hwnd != nullptr,);
    553 
    554     ShowWindow(impl->hwnd, SW_RESTORE);
    555     SetFocus(impl->hwnd);
    556 }
    557 
    558 // --------------------------------------------------------------------------------------------------------------------
    559 // win32 specific, center view based on parent coordinates (if there is one)
    560 
    561 void puglWin32ShowCentered(PuglView* const view)
    562 {
    563     PuglInternals* impl = view->impl;
    564     DISTRHO_SAFE_ASSERT_RETURN(impl->hwnd != nullptr,);
    565 
    566     RECT rectChild, rectParent;
    567 
    568     if (view->transientParent != 0 &&
    569         GetWindowRect(impl->hwnd, &rectChild) &&
    570         GetWindowRect((HWND)view->transientParent, &rectParent))
    571     {
    572         SetWindowPos(impl->hwnd, HWND_TOP,
    573                      rectParent.left + (rectParent.right-rectParent.left)/2 - (rectChild.right-rectChild.left)/2,
    574                      rectParent.top + (rectParent.bottom-rectParent.top)/2 - (rectChild.bottom-rectChild.top)/2,
    575                      0, 0, SWP_SHOWWINDOW|SWP_NOSIZE);
    576     }
    577     else
    578     {
    579         MONITORINFO mInfo;
    580         std::memset(&mInfo, 0, sizeof(mInfo));
    581         mInfo.cbSize = sizeof(mInfo);
    582 
    583         if (GetMonitorInfo(MonitorFromWindow(impl->hwnd, MONITOR_DEFAULTTOPRIMARY), &mInfo))
    584             SetWindowPos(impl->hwnd, HWND_TOP,
    585                          mInfo.rcWork.left + (mInfo.rcWork.right - mInfo.rcWork.left - view->lastConfigure.width) / 2,
    586                          mInfo.rcWork.top + (mInfo.rcWork.bottom - mInfo.rcWork.top - view->lastConfigure.height) / 2,
    587                          0, 0, SWP_SHOWWINDOW|SWP_NOSIZE);
    588         else
    589             ShowWindow(impl->hwnd, SW_NORMAL);
    590     }
    591 
    592     SetFocus(impl->hwnd);
    593 }
    594 
    595 // --------------------------------------------------------------------------------------------------------------------
    596 
    597 #elif defined(DISTRHO_OS_WASM)
    598 
    599 // nothing here yet
    600 
    601 // --------------------------------------------------------------------------------------------------------------------
    602 
    603 #elif defined(HAVE_X11)
    604 
    605 // --------------------------------------------------------------------------------------------------------------------
    606 // X11 specific, update world without triggering exposure events
    607 
    608 PuglStatus puglX11UpdateWithoutExposures(PuglWorld* const world)
    609 {
    610     const bool wasDispatchingEvents = world->impl->dispatchingEvents;
    611     world->impl->dispatchingEvents = true;
    612     PuglStatus st = PUGL_SUCCESS;
    613 
    614     const double startTime = puglGetTime(world);
    615     const double endTime  = startTime + 0.03;
    616 
    617     for (double t = startTime; !st && t < endTime; t = puglGetTime(world))
    618     {
    619         pollX11Socket(world, endTime - t);
    620         st = dispatchX11Events(world);
    621     }
    622 
    623     world->impl->dispatchingEvents = wasDispatchingEvents;
    624     return st;
    625 }
    626 
    627 // --------------------------------------------------------------------------------------------------------------------
    628 // X11 specific, set dialog window type and pid hints
    629 
    630 void puglX11SetWindowTypeAndPID(const PuglView* const view, const bool isStandalone)
    631 {
    632     const PuglInternals* const impl    = view->impl;
    633     Display*             const display = view->world->impl->display;
    634 
    635     const pid_t pid = getpid();
    636     const Atom _nwp = XInternAtom(display, "_NET_WM_PID", False);
    637     XChangeProperty(display, impl->win, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1);
    638 
    639    #if defined(DGL_X11_WINDOW_ICON_NAME) && defined(DGL_X11_WINDOW_ICON_SIZE)
    640     if (isStandalone)
    641     {
    642         const Atom _nwi = XInternAtom(display, "_NET_WM_ICON", False);
    643         XChangeProperty(display, impl->win, _nwi, XA_CARDINAL, 32, PropModeReplace,
    644                         (const uchar*)DGL_X11_WINDOW_ICON_NAME, DGL_X11_WINDOW_ICON_SIZE);
    645     }
    646    #endif
    647 
    648     const Atom _wt = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
    649 
    650     Atom _wts[2];
    651     int numAtoms = 0;
    652 
    653     if (! isStandalone)
    654         _wts[numAtoms++] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
    655 
    656     _wts[numAtoms++] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
    657 
    658     XChangeProperty(display, impl->win, _wt, XA_ATOM, 32, PropModeReplace, (const uchar*)&_wts, numAtoms);
    659 }
    660 
    661 // --------------------------------------------------------------------------------------------------------------------
    662 
    663 #endif // HAVE_X11
    664 
    665 #ifndef DISTRHO_OS_MAC
    666 END_NAMESPACE_DGL
    667 #endif