diff options
Diffstat (limited to 'intern/ghost/intern')
58 files changed, 3135 insertions, 2696 deletions
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 65e7de707ec..710512881e8 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -30,6 +30,14 @@ GHOST_SystemHandle GHOST_CreateSystem(void) return (GHOST_SystemHandle)system; } +GHOST_SystemHandle GHOST_CreateSystemBackground(void) +{ + GHOST_ISystem::createSystemBackground(); + GHOST_ISystem *system = GHOST_ISystem::getSystem(); + + return (GHOST_SystemHandle)system; +} + void GHOST_SystemInitDebug(GHOST_SystemHandle systemhandle, GHOST_Debug debug) { GHOST_ISystem *system = (GHOST_ISystem *)systemhandle; @@ -861,8 +869,7 @@ void GHOST_putClipboard(const char *buffer, bool selection) bool GHOST_setConsoleWindowState(GHOST_TConsoleWindowState action) { GHOST_ISystem *system = GHOST_ISystem::getSystem(); - /* FIXME: use `bool` instead of int for this value. */ - return (bool)system->setConsoleWindowState(action); + return system->setConsoleWindowState(action); } bool GHOST_UseNativePixels(void) diff --git a/intern/ghost/intern/GHOST_Context.cpp b/intern/ghost/intern/GHOST_Context.cpp index f4b3d08ffc5..aa379efbc1f 100644 --- a/intern/ghost/intern/GHOST_Context.cpp +++ b/intern/ghost/intern/GHOST_Context.cpp @@ -10,7 +10,7 @@ #include "GHOST_Context.h" #ifdef _WIN32 -# include <GL/wglew.h> // only for symbolic constants, do not use API functions +# include <epoxy/wgl.h> # include <tchar.h> # # ifndef ERROR_PROFILE_DOES_NOT_MATCH_DEVICE @@ -123,11 +123,6 @@ bool win32_chk(bool result, const char *file, int line, const char *text) #endif // _WIN32 -void GHOST_Context::initContextGLEW() -{ - GLEW_CHK(glewInit()); -} - void GHOST_Context::initClearGL() { glClearColor(0.294, 0.294, 0.294, 0.000); diff --git a/intern/ghost/intern/GHOST_Context.h b/intern/ghost/intern/GHOST_Context.h index e707f1c3475..04d445e7f85 100644 --- a/intern/ghost/intern/GHOST_Context.h +++ b/intern/ghost/intern/GHOST_Context.h @@ -11,7 +11,7 @@ #include "GHOST_IContext.h" #include "GHOST_Types.h" -#include "glew-mx.h" +#include <epoxy/gl.h> #include <cstdlib> // for NULL @@ -36,19 +36,19 @@ class GHOST_Context : public GHOST_IContext { * Swaps front and back buffers of a window. * \return A boolean success indicator. */ - virtual GHOST_TSuccess swapBuffers() = 0; + virtual GHOST_TSuccess swapBuffers() override = 0; /** * Activates the drawing context of this window. * \return A boolean success indicator. */ - virtual GHOST_TSuccess activateDrawingContext() = 0; + virtual GHOST_TSuccess activateDrawingContext() override = 0; /** * Release the drawing context of the calling thread. * \return A boolean success indicator. */ - virtual GHOST_TSuccess releaseDrawingContext() = 0; + virtual GHOST_TSuccess releaseDrawingContext() override = 0; /** * Call immediately after new to initialize. If this fails then immediately delete the object. @@ -130,14 +130,12 @@ class GHOST_Context : public GHOST_IContext { * Gets the OpenGL frame-buffer associated with the OpenGL context * \return The ID of an OpenGL frame-buffer object. */ - virtual unsigned int getDefaultFramebuffer() + virtual unsigned int getDefaultFramebuffer() override { return 0; } protected: - void initContextGLEW(); - bool m_stereoVisual; /** Caller specified, not for internal use. */ diff --git a/intern/ghost/intern/GHOST_ContextCGL.h b/intern/ghost/intern/GHOST_ContextCGL.h index badc3241107..130b926f25c 100644 --- a/intern/ghost/intern/GHOST_ContextCGL.h +++ b/intern/ghost/intern/GHOST_ContextCGL.h @@ -9,8 +9,13 @@ #include "GHOST_Context.h" +#include <Cocoa/Cocoa.h> +#include <Metal/Metal.h> +#include <QuartzCore/QuartzCore.h> + @class CAMetalLayer; @class MTLCommandQueue; +@class MTLDevice; @class MTLRenderPipelineState; @class MTLTexture; @class NSOpenGLContext; @@ -36,62 +41,89 @@ class GHOST_ContextCGL : public GHOST_Context { * Swaps front and back buffers of a window. * \return A boolean success indicator. */ - GHOST_TSuccess swapBuffers(); + GHOST_TSuccess swapBuffers() override; /** * Activates the drawing context of this window. * \return A boolean success indicator. */ - GHOST_TSuccess activateDrawingContext(); + GHOST_TSuccess activateDrawingContext() override; /** * Release the drawing context of the calling thread. * \return A boolean success indicator. */ - GHOST_TSuccess releaseDrawingContext(); + GHOST_TSuccess releaseDrawingContext() override; - unsigned int getDefaultFramebuffer(); + unsigned int getDefaultFramebuffer() override; /** * Call immediately after new to initialize. If this fails then immediately delete the object. * \return Indication as to whether initialization has succeeded. */ - GHOST_TSuccess initializeDrawingContext(); + GHOST_TSuccess initializeDrawingContext() override; /** * Removes references to native handles from this context and then returns * \return GHOST_kSuccess if it is OK for the parent to release the handles and * GHOST_kFailure if releasing the handles will interfere with sharing */ - GHOST_TSuccess releaseNativeHandles(); + GHOST_TSuccess releaseNativeHandles() override; /** * Sets the swap interval for #swapBuffers. * \param interval: The swap interval to use. * \return A boolean success indicator. */ - GHOST_TSuccess setSwapInterval(int interval); + GHOST_TSuccess setSwapInterval(int interval) override; /** * Gets the current swap interval for #swapBuffers. * \param intervalOut: Variable to store the swap interval if it can be read. * \return Whether the swap interval can be read. */ - GHOST_TSuccess getSwapInterval(int &); + GHOST_TSuccess getSwapInterval(int &) override; /** * Updates the drawing context of this window. * Needed whenever the window is changed. * \return Indication of success. */ - GHOST_TSuccess updateDrawingContext(); + GHOST_TSuccess updateDrawingContext() override; + + /** + * Returns a texture that Metal code can use as a render target. The current + * contents of this texture will be composited on top of the frame-buffer + * each time `swapBuffers` is called. + */ + id<MTLTexture> metalOverlayTexture(); + + /** + * Return a pointer to the Metal command queue used by this context. + */ + MTLCommandQueue *metalCommandQueue(); + + /** + * Return a pointer to the Metal device associated with this context. + */ + MTLDevice *metalDevice(); + + /** + * Register present callback + */ + void metalRegisterPresentCallback(void (*callback)( + MTLRenderPassDescriptor *, id<MTLRenderPipelineState>, id<MTLTexture>, id<CAMetalDrawable>)); private: /** Metal state */ + /* Set this flag to `true` when rendering with Metal API for Viewport. + * TODO(Metal): This should be assigned to externally. */ + bool m_useMetalForRendering = false; NSView *m_metalView; CAMetalLayer *m_metalLayer; MTLCommandQueue *m_metalCmdQueue; MTLRenderPipelineState *m_metalRenderPipeline; + bool m_ownsMetalDevice; /** OpenGL state, for GPUs that don't support Metal */ NSOpenGLView *m_openGLView; @@ -103,10 +135,30 @@ class GHOST_ContextCGL : public GHOST_Context { unsigned int m_defaultFramebuffer; /** The virtualized default frame-buffer's texture. */ - MTLTexture *m_defaultFramebufferMetalTexture; - - bool m_coreProfile; - + /** + * Texture that you can render into with Metal. The texture will be + * composited on top of `m_defaultFramebufferMetalTexture` whenever + * `swapBuffers` is called. + */ + static const int METAL_SWAPCHAIN_SIZE = 3; + struct MTLSwapchainTexture { + id<MTLTexture> texture; + unsigned int index; + }; + MTLSwapchainTexture m_defaultFramebufferMetalTexture[METAL_SWAPCHAIN_SIZE]; + unsigned int current_swapchain_index = 0; + + /* Present callback. + * We use this such that presentation can be controlled from within the Metal + * Context. This is required for optimal performance and clean control flow. + * Also helps ensure flickering does not occur by present being dependent + * on existing submissions. */ + void (*contextPresentCallback)(MTLRenderPassDescriptor *, + id<MTLRenderPipelineState>, + id<MTLTexture>, + id<CAMetalDrawable>); + + int mtl_SwapInterval; const bool m_debug; /** The first created OpenGL context (for sharing display lists) */ @@ -119,4 +171,5 @@ class GHOST_ContextCGL : public GHOST_Context { void metalInitFramebuffer(); void metalUpdateFramebuffer(); void metalSwapBuffers(); + void initClear(); }; diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm index dd800ef52a3..ff53ecdbbba 100644 --- a/intern/ghost/intern/GHOST_ContextCGL.mm +++ b/intern/ghost/intern/GHOST_ContextCGL.mm @@ -55,159 +55,291 @@ GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual, m_openGLView(openGLView), m_openGLContext(nil), m_defaultFramebuffer(0), - m_defaultFramebufferMetalTexture(nil), m_debug(false) { -#if defined(WITH_GL_PROFILE_CORE) - m_coreProfile = true; -#else - m_coreProfile = false; -#endif - + /* Initialize Metal Swap-chain. */ + current_swapchain_index = 0; + for (int i = 0; i < METAL_SWAPCHAIN_SIZE; i++) { + m_defaultFramebufferMetalTexture[i].texture = nil; + m_defaultFramebufferMetalTexture[i].index = i; + } if (m_metalView) { + m_ownsMetalDevice = false; metalInit(); } + else { + /* Prepare offscreen GHOST Context Metal device. */ + id<MTLDevice> metalDevice = MTLCreateSystemDefaultDevice(); + + if (m_debug) { + printf("Selected Metal Device: %s\n", [metalDevice.name UTF8String]); + } + + m_ownsMetalDevice = true; + if (metalDevice) { + m_metalLayer = [[CAMetalLayer alloc] init]; + [m_metalLayer setEdgeAntialiasingMask:0]; + [m_metalLayer setMasksToBounds:NO]; + [m_metalLayer setOpaque:YES]; + [m_metalLayer setFramebufferOnly:YES]; + [m_metalLayer setPresentsWithTransaction:NO]; + [m_metalLayer removeAllAnimations]; + [m_metalLayer setDevice:metalDevice]; + m_metalLayer.allowsNextDrawableTimeout = NO; + metalInit(); + } + else { + ghost_fatal_error_dialog( + "[ERROR] Failed to create Metal device for offscreen GHOST Context.\n"); + } + } + + /* Initialize swap-interval. */ + mtl_SwapInterval = 60; } GHOST_ContextCGL::~GHOST_ContextCGL() { metalFree(); - if (m_openGLContext != nil) { - if (m_openGLContext == [NSOpenGLContext currentContext]) { - [NSOpenGLContext clearCurrentContext]; + if (!m_useMetalForRendering) { +#if WITH_OPENGL + if (m_openGLContext != nil) { + if (m_openGLContext == [NSOpenGLContext currentContext]) { + [NSOpenGLContext clearCurrentContext]; - if (m_openGLView) { - [m_openGLView clearGLContext]; + if (m_openGLView) { + [m_openGLView clearGLContext]; + } } - } - if (m_openGLContext != s_sharedOpenGLContext || s_sharedCount == 1) { - assert(s_sharedCount > 0); + if (m_openGLContext != s_sharedOpenGLContext || s_sharedCount == 1) { + assert(s_sharedCount > 0); - s_sharedCount--; + s_sharedCount--; - if (s_sharedCount == 0) - s_sharedOpenGLContext = nil; + if (s_sharedCount == 0) + s_sharedOpenGLContext = nil; - [m_openGLContext release]; + [m_openGLContext release]; + } + } +#endif + } + + if (m_ownsMetalDevice) { + if (m_metalLayer) { + [m_metalLayer release]; + m_metalLayer = nil; } } } GHOST_TSuccess GHOST_ContextCGL::swapBuffers() { - if (m_openGLContext != nil) { - if (m_metalView) { - metalSwapBuffers(); + GHOST_TSuccess return_value = GHOST_kFailure; + + if (!m_useMetalForRendering) { +#if WITH_OPENGL + if (m_openGLContext != nil) { + if (m_metalView) { + metalSwapBuffers(); + } + else if (m_openGLView) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [m_openGLContext flushBuffer]; + [pool drain]; + } + return_value = GHOST_kSuccess; } - else if (m_openGLView) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [m_openGLContext flushBuffer]; - [pool drain]; + else { + return_value = GHOST_kFailure; } - return GHOST_kSuccess; +#endif } else { - return GHOST_kFailure; + if (m_metalView) { + metalSwapBuffers(); + } + return_value = GHOST_kSuccess; } + return return_value; } GHOST_TSuccess GHOST_ContextCGL::setSwapInterval(int interval) { - if (m_openGLContext != nil) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [m_openGLContext setValues:&interval forParameter:NSOpenGLCPSwapInterval]; - [pool drain]; - return GHOST_kSuccess; + + if (!m_useMetalForRendering) { +#if WITH_OPENGL + if (m_openGLContext != nil) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [m_openGLContext setValues:&interval forParameter:NSOpenGLCPSwapInterval]; + [pool drain]; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +#endif } else { - return GHOST_kFailure; + mtl_SwapInterval = interval; + return GHOST_kSuccess; } } GHOST_TSuccess GHOST_ContextCGL::getSwapInterval(int &intervalOut) { - if (m_openGLContext != nil) { - GLint interval; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + if (!m_useMetalForRendering) { +#if WITH_OPENGL + if (m_openGLContext != nil) { + GLint interval; - [m_openGLContext getValues:&interval forParameter:NSOpenGLCPSwapInterval]; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [pool drain]; + [m_openGLContext getValues:&interval forParameter:NSOpenGLCPSwapInterval]; - intervalOut = static_cast<int>(interval); + [pool drain]; - return GHOST_kSuccess; + intervalOut = static_cast<int>(interval); + + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +#endif } else { - return GHOST_kFailure; + intervalOut = mtl_SwapInterval; + return GHOST_kSuccess; } } GHOST_TSuccess GHOST_ContextCGL::activateDrawingContext() { - if (m_openGLContext != nil) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [m_openGLContext makeCurrentContext]; - [pool drain]; - return GHOST_kSuccess; + + if (!m_useMetalForRendering) { +#if WITH_OPENGL + if (m_openGLContext != nil) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [m_openGLContext makeCurrentContext]; + [pool drain]; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +#endif } else { - return GHOST_kFailure; + return GHOST_kSuccess; } } GHOST_TSuccess GHOST_ContextCGL::releaseDrawingContext() { - if (m_openGLContext != nil) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [NSOpenGLContext clearCurrentContext]; - [pool drain]; - return GHOST_kSuccess; + + if (!m_useMetalForRendering) { +#if WITH_OPENGL + if (m_openGLContext != nil) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [NSOpenGLContext clearCurrentContext]; + [pool drain]; + return GHOST_kSuccess; + } + else { + return GHOST_kFailure; + } +#endif } else { - return GHOST_kFailure; + return GHOST_kSuccess; } } unsigned int GHOST_ContextCGL::getDefaultFramebuffer() { - return m_defaultFramebuffer; + + if (!m_useMetalForRendering) { + return m_defaultFramebuffer; + } + /* NOTE(Metal): This is not valid. */ + return 0; } GHOST_TSuccess GHOST_ContextCGL::updateDrawingContext() { - if (m_openGLContext != nil) { - if (m_metalView) { - metalUpdateFramebuffer(); + + if (!m_useMetalForRendering) { +#if WITH_OPENGL + if (m_openGLContext != nil) { + if (m_metalView) { + metalUpdateFramebuffer(); + } + else if (m_openGLView) { + @autoreleasepool { + [m_openGLContext update]; + } + } + + return GHOST_kSuccess; } - else if (m_openGLView) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [m_openGLContext update]; - [pool drain]; + else { + return GHOST_kFailure; } - - return GHOST_kSuccess; +#endif } else { - return GHOST_kFailure; + if (m_metalView) { + metalUpdateFramebuffer(); + return GHOST_kSuccess; + } } + return GHOST_kFailure; +} + +id<MTLTexture> GHOST_ContextCGL::metalOverlayTexture() +{ + /* Increment Swap-chain - Only needed if context is requesting a new texture */ + current_swapchain_index = (current_swapchain_index + 1) % METAL_SWAPCHAIN_SIZE; + + /* Ensure backing texture is ready for current swapchain index */ + updateDrawingContext(); + + /* Return texture. */ + return m_defaultFramebufferMetalTexture[current_swapchain_index].texture; +} + +MTLCommandQueue *GHOST_ContextCGL::metalCommandQueue() +{ + return m_metalCmdQueue; +} +MTLDevice *GHOST_ContextCGL::metalDevice() +{ + id<MTLDevice> device = m_metalLayer.device; + return (MTLDevice *)device; +} + +void GHOST_ContextCGL::metalRegisterPresentCallback(void (*callback)( + MTLRenderPassDescriptor *, id<MTLRenderPipelineState>, id<MTLTexture>, id<CAMetalDrawable>)) +{ + this->contextPresentCallback = callback; } static void makeAttribList(std::vector<NSOpenGLPixelFormatAttribute> &attribs, - bool coreProfile, bool stereoVisual, bool needAlpha, - bool softwareGL) + bool softwareGL, + bool increasedSamplerLimit) { attribs.clear(); attribs.push_back(NSOpenGLPFAOpenGLProfile); - attribs.push_back(coreProfile ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy); + attribs.push_back(NSOpenGLProfileVersion3_2Core); - /* Pixel Format Attributes for the windowed NSOpenGLContext. */ + /* Pixel Format Attributes for the windowed #NSOpenGLContext. */ attribs.push_back(NSOpenGLPFADoubleBuffer); if (softwareGL) { @@ -217,6 +349,12 @@ static void makeAttribList(std::vector<NSOpenGLPixelFormatAttribute> &attribs, else { attribs.push_back(NSOpenGLPFAAccelerated); attribs.push_back(NSOpenGLPFANoRecovery); + + /* Attempt to initialize device with extended sampler limit. + * Resolves EEVEE purple rendering artifacts on macOS. */ + if (increasedSamplerLimit) { + attribs.push_back((NSOpenGLPixelFormatAttribute)400); + } } if (stereoVisual) @@ -232,88 +370,143 @@ static void makeAttribList(std::vector<NSOpenGLPixelFormatAttribute> &attribs, GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext() { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + @autoreleasepool { #ifdef GHOST_OPENGL_ALPHA - static const bool needAlpha = true; + static const bool needAlpha = true; #else - static const bool needAlpha = false; + static const bool needAlpha = false; #endif - /* Command-line argument would be better. */ - static bool softwareGL = getenv("BLENDER_SOFTWAREGL"); - - std::vector<NSOpenGLPixelFormatAttribute> attribs; - attribs.reserve(40); - makeAttribList(attribs, m_coreProfile, m_stereoVisual, needAlpha, softwareGL); + /* Command-line argument would be better. */ + if (!m_useMetalForRendering) { +#if WITH_OPENGL + /* Command-line argument would be better. */ + static bool softwareGL = getenv("BLENDER_SOFTWAREGL"); + + NSOpenGLPixelFormat *pixelFormat = nil; + std::vector<NSOpenGLPixelFormatAttribute> attribs; + bool increasedSamplerLimit = false; + + /* Attempt to initialize device with increased sampler limit. + * If this is unsupported and initialization fails, initialize GL Context as normal. + * + * NOTE: This is not available when using the SoftwareGL path, or for Intel-based + * platforms. */ + if (!softwareGL) { + if (@available(macos 11.0, *)) { + increasedSamplerLimit = true; + } + } + const int max_ctx_attempts = increasedSamplerLimit ? 2 : 1; + for (int ctx_create_attempt = 0; ctx_create_attempt < max_ctx_attempts; + ctx_create_attempt++) { + + attribs.clear(); + attribs.reserve(40); + makeAttribList(attribs, m_stereoVisual, needAlpha, softwareGL, increasedSamplerLimit); + + pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]]; + if (pixelFormat == nil) { + /* If pixel format creation fails when testing increased sampler limit, + * attempt initialization again with feature disabled, otherwise, fail. */ + if (increasedSamplerLimit) { + increasedSamplerLimit = false; + continue; + } + return GHOST_kFailure; + } + + /* Attempt to create context. */ + m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat + shareContext:s_sharedOpenGLContext]; + [pixelFormat release]; + + if (m_openGLContext == nil) { + /* If context creation fails when testing increased sampler limit, + * attempt re-creation with feature disabled. Otherwise, error. */ + if (increasedSamplerLimit) { + increasedSamplerLimit = false; + continue; + } + + /* Default context creation attempt failed. */ + return GHOST_kFailure; + } + + /* Created GL context successfully, activate. */ + [m_openGLContext makeCurrentContext]; + + /* When increasing sampler limit, verify created context is a supported configuration. */ + if (increasedSamplerLimit) { + const char *vendor = (const char *)glGetString(GL_VENDOR); + const char *renderer = (const char *)glGetString(GL_RENDERER); + + /* If generated context type is unsupported, release existing context and + * fallback to creating a normal context below. */ + if (strstr(vendor, "Intel") || strstr(renderer, "Software")) { + [m_openGLContext release]; + m_openGLContext = nil; + increasedSamplerLimit = false; + continue; + } + } + } - NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]]; - if (pixelFormat == nil) { - goto error; - } + if (m_debug) { + GLint major = 0, minor = 0; + glGetIntegerv(GL_MAJOR_VERSION, &major); + glGetIntegerv(GL_MINOR_VERSION, &minor); + fprintf(stderr, "OpenGL version %d.%d%s\n", major, minor, softwareGL ? " (software)" : ""); + fprintf(stderr, "Renderer: %s\n", glGetString(GL_RENDERER)); + } - m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat - shareContext:s_sharedOpenGLContext]; - [pixelFormat release]; +# ifdef GHOST_WAIT_FOR_VSYNC + { + GLint swapInt = 1; + /* Wait for vertical-sync, to avoid tearing artifacts. */ + [m_openGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; + } +# endif + + if (m_metalView) { + if (m_defaultFramebuffer == 0) { + /* Create a virtual frame-buffer. */ + [m_openGLContext makeCurrentContext]; + metalInitFramebuffer(); + initClearGL(); + } + } + else if (m_openGLView) { + [m_openGLView setOpenGLContext:m_openGLContext]; + [m_openGLContext setView:m_openGLView]; + initClearGL(); + } - [m_openGLContext makeCurrentContext]; + [m_openGLContext flushBuffer]; - if (m_debug) { - GLint major = 0, minor = 0; - glGetIntegerv(GL_MAJOR_VERSION, &major); - glGetIntegerv(GL_MINOR_VERSION, &minor); - fprintf(stderr, "OpenGL version %d.%d%s\n", major, minor, softwareGL ? " (software)" : ""); - fprintf(stderr, "Renderer: %s\n", glGetString(GL_RENDERER)); - } + if (s_sharedCount == 0) + s_sharedOpenGLContext = m_openGLContext; -#ifdef GHOST_WAIT_FOR_VSYNC - { - GLint swapInt = 1; - /* Wait for vertical-sync, to avoid tearing artifacts. */ - [m_openGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; - } + s_sharedCount++; #endif - - initContextGLEW(); - - if (m_metalView) { - if (m_defaultFramebuffer == 0) { - /* Create a virtual frame-buffer. */ - [m_openGLContext makeCurrentContext]; - metalInitFramebuffer(); - initClearGL(); + } + else { + /* NOTE(Metal): Metal-only path. */ + if (m_metalView) { + metalInitFramebuffer(); + } } } - else if (m_openGLView) { - [m_openGLView setOpenGLContext:m_openGLContext]; - [m_openGLContext setView:m_openGLView]; - initClearGL(); - } - - [m_openGLContext flushBuffer]; - - if (s_sharedCount == 0) - s_sharedOpenGLContext = m_openGLContext; - - s_sharedCount++; - - [pool drain]; - return GHOST_kSuccess; - -error: - - [pixelFormat release]; - - [pool drain]; - - return GHOST_kFailure; } GHOST_TSuccess GHOST_ContextCGL::releaseNativeHandles() { +#if WITH_OPENGL m_openGLContext = nil; m_openGLView = nil; +#endif m_metalView = nil; return GHOST_kSuccess; @@ -363,10 +556,14 @@ void GHOST_ContextCGL::metalInit() fragment float4 fragment_shader(Vertex v [[stage_in]], texture2d<float> t [[texture(0)]]) { - return t.sample(s, v.texCoord); - } - )msl"; + /* Final blit should ensure alpha is 1.0. This resolves + * rendering artifacts for blitting of final backbuffer. */ + float4 out_tex = t.sample(s, v.texCoord); + out_tex.a = 1.0; + return out_tex; + } + )msl"; MTLCompileOptions *options = [[[MTLCompileOptions alloc] init] autorelease]; options.languageVersion = MTLLanguageVersion1_1; @@ -383,6 +580,8 @@ void GHOST_ContextCGL::metalInit() desc.fragmentFunction = [library newFunctionWithName:@"fragment_shader"]; desc.vertexFunction = [library newFunctionWithName:@"vertex_shader"]; + /* Ensure library is released. */ + [library autorelease]; [desc.colorAttachments objectAtIndexedSubscript:0].pixelFormat = METAL_FRAMEBUFFERPIXEL_FORMAT; @@ -393,6 +592,20 @@ void GHOST_ContextCGL::metalInit() ghost_fatal_error_dialog( "GHOST_ContextCGL::metalInit: newRenderPipelineStateWithDescriptor:error: failed!"); } + + /* Create a render pipeline to composite things rendered with Metal on top + * of the frame-buffer contents. Uses the same vertex and fragment shader + * as the blit above, but with alpha blending enabled. */ + desc.label = @"Metal Overlay"; + desc.colorAttachments[0].blendingEnabled = YES; + desc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; + desc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + + if (error) { + ghost_fatal_error_dialog( + "GHOST_ContextCGL::metalInit: newRenderPipelineStateWithDescriptor:error: failed (when " + "creating the Metal overlay pipeline)!"); + } } } @@ -404,123 +617,206 @@ void GHOST_ContextCGL::metalFree() if (m_metalRenderPipeline) { [m_metalRenderPipeline release]; } - if (m_defaultFramebufferMetalTexture) { - [m_defaultFramebufferMetalTexture release]; + + for (int i = 0; i < METAL_SWAPCHAIN_SIZE; i++) { + if (m_defaultFramebufferMetalTexture[i].texture) { + [m_defaultFramebufferMetalTexture[i].texture release]; + } } } void GHOST_ContextCGL::metalInitFramebuffer() { - glGenFramebuffers(1, &m_defaultFramebuffer); + if (!m_useMetalForRendering) { +#if WITH_OPENGL + glGenFramebuffers(1, &m_defaultFramebuffer); +#endif + } updateDrawingContext(); - glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer); + + if (!m_useMetalForRendering) { +#if WITH_OPENGL + glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer); +#endif + } } void GHOST_ContextCGL::metalUpdateFramebuffer() { - assert(m_defaultFramebuffer != 0); + if (!m_useMetalForRendering) { +#if WITH_OPENGL + assert(m_defaultFramebuffer != 0); +#endif + } NSRect bounds = [m_metalView bounds]; NSSize backingSize = [m_metalView convertSizeToBacking:bounds.size]; size_t width = (size_t)backingSize.width; size_t height = (size_t)backingSize.height; - { - /* Test if there is anything to update */ - id<MTLTexture> tex = (id<MTLTexture>)m_defaultFramebufferMetalTexture; - if (tex && tex.width == width && tex.height == height) { - return; +#if WITH_OPENGL + unsigned int glTex; + CVPixelBufferRef cvPixelBuffer = nil; + CVOpenGLTextureCacheRef cvGLTexCache = nil; + CVOpenGLTextureRef cvGLTex = nil; + CVMetalTextureCacheRef cvMetalTexCache = nil; + CVMetalTextureRef cvMetalTex = nil; +#endif + + if (!m_useMetalForRendering) { +#if WITH_OPENGL + /* OPENGL path */ + { + /* Test if there is anything to update */ + id<MTLTexture> tex = m_defaultFramebufferMetalTexture[current_swapchain_index].texture; + if (tex && tex.width == width && tex.height == height) { + return; + } } - } - activateDrawingContext(); + activateDrawingContext(); + + NSDictionary *cvPixelBufferProps = @{ + (__bridge NSString *)kCVPixelBufferOpenGLCompatibilityKey : @YES, + (__bridge NSString *)kCVPixelBufferMetalCompatibilityKey : @YES, + }; + CVReturn cvret = CVPixelBufferCreate(kCFAllocatorDefault, + width, + height, + METAL_CORE_VIDEO_PIXEL_FORMAT, + (__bridge CFDictionaryRef)cvPixelBufferProps, + &cvPixelBuffer); + if (cvret != kCVReturnSuccess) { + ghost_fatal_error_dialog( + "GHOST_ContextCGL::metalUpdateFramebuffer: CVPixelBufferCreate failed!"); + } - NSDictionary *cvPixelBufferProps = @{ - (__bridge NSString *)kCVPixelBufferOpenGLCompatibilityKey : @YES, - (__bridge NSString *)kCVPixelBufferMetalCompatibilityKey : @YES, - }; - CVPixelBufferRef cvPixelBuffer = nil; - CVReturn cvret = CVPixelBufferCreate(kCFAllocatorDefault, - width, - height, - METAL_CORE_VIDEO_PIXEL_FORMAT, - (__bridge CFDictionaryRef)cvPixelBufferProps, - &cvPixelBuffer); - if (cvret != kCVReturnSuccess) { - ghost_fatal_error_dialog( - "GHOST_ContextCGL::metalUpdateFramebuffer: CVPixelBufferCreate failed!"); - } - - /* Create an OpenGL texture. */ - CVOpenGLTextureCacheRef cvGLTexCache = nil; - cvret = CVOpenGLTextureCacheCreate(kCFAllocatorDefault, - nil, - m_openGLContext.CGLContextObj, - m_openGLContext.pixelFormat.CGLPixelFormatObj, - nil, - &cvGLTexCache); - if (cvret != kCVReturnSuccess) { - ghost_fatal_error_dialog( - "GHOST_ContextCGL::metalUpdateFramebuffer: CVOpenGLTextureCacheCreate failed!"); - } + /* Create an OpenGL texture. */ + cvret = CVOpenGLTextureCacheCreate(kCFAllocatorDefault, + nil, + m_openGLContext.CGLContextObj, + m_openGLContext.pixelFormat.CGLPixelFormatObj, + nil, + &cvGLTexCache); + if (cvret != kCVReturnSuccess) { + ghost_fatal_error_dialog( + "GHOST_ContextCGL::metalUpdateFramebuffer: CVOpenGLTextureCacheCreate failed!"); + } - CVOpenGLTextureRef cvGLTex = nil; - cvret = CVOpenGLTextureCacheCreateTextureFromImage( - kCFAllocatorDefault, cvGLTexCache, cvPixelBuffer, nil, &cvGLTex); - if (cvret != kCVReturnSuccess) { - ghost_fatal_error_dialog( - "GHOST_ContextCGL::metalUpdateFramebuffer: " - "CVOpenGLTextureCacheCreateTextureFromImage failed!"); - } + cvret = CVOpenGLTextureCacheCreateTextureFromImage( + kCFAllocatorDefault, cvGLTexCache, cvPixelBuffer, nil, &cvGLTex); + if (cvret != kCVReturnSuccess) { + ghost_fatal_error_dialog( + "GHOST_ContextCGL::metalUpdateFramebuffer: " + "CVOpenGLTextureCacheCreateTextureFromImage failed!"); + } - unsigned int glTex; - glTex = CVOpenGLTextureGetName(cvGLTex); + glTex = CVOpenGLTextureGetName(cvGLTex); - /* Create a Metal texture. */ - CVMetalTextureCacheRef cvMetalTexCache = nil; - cvret = CVMetalTextureCacheCreate( - kCFAllocatorDefault, nil, m_metalLayer.device, nil, &cvMetalTexCache); - if (cvret != kCVReturnSuccess) { - ghost_fatal_error_dialog( - "GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureCacheCreate failed!"); - } + /* Create a Metal texture. */ + cvret = CVMetalTextureCacheCreate( + kCFAllocatorDefault, nil, m_metalLayer.device, nil, &cvMetalTexCache); + if (cvret != kCVReturnSuccess) { + ghost_fatal_error_dialog( + "GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureCacheCreate failed!"); + } - CVMetalTextureRef cvMetalTex = nil; - cvret = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, - cvMetalTexCache, - cvPixelBuffer, - nil, - METAL_FRAMEBUFFERPIXEL_FORMAT, - width, - height, - 0, - &cvMetalTex); - if (cvret != kCVReturnSuccess) { - ghost_fatal_error_dialog( - "GHOST_ContextCGL::metalUpdateFramebuffer: " - "CVMetalTextureCacheCreateTextureFromImage failed!"); - } + cvret = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, + cvMetalTexCache, + cvPixelBuffer, + nil, + METAL_FRAMEBUFFERPIXEL_FORMAT, + width, + height, + 0, + &cvMetalTex); + if (cvret != kCVReturnSuccess) { + ghost_fatal_error_dialog( + "GHOST_ContextCGL::metalUpdateFramebuffer: " + "CVMetalTextureCacheCreateTextureFromImage failed!"); + } + + id<MTLTexture> tex = CVMetalTextureGetTexture(cvMetalTex); - MTLTexture *tex = (MTLTexture *)CVMetalTextureGetTexture(cvMetalTex); + if (!tex) { + ghost_fatal_error_dialog( + "GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureGetTexture failed!"); + } - if (!tex) { - ghost_fatal_error_dialog( - "GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureGetTexture failed!"); + [m_defaultFramebufferMetalTexture[current_swapchain_index].texture release]; + m_defaultFramebufferMetalTexture[current_swapchain_index].texture = [tex retain]; +#endif } + else { + /* NOTE(Metal): Metal API Path. */ + if (m_defaultFramebufferMetalTexture[current_swapchain_index].texture && + m_defaultFramebufferMetalTexture[current_swapchain_index].texture.width == width && + m_defaultFramebufferMetalTexture[current_swapchain_index].texture.height == height) { + return; + } - [m_defaultFramebufferMetalTexture release]; - m_defaultFramebufferMetalTexture = [tex retain]; + /* Free old texture */ + [m_defaultFramebufferMetalTexture[current_swapchain_index].texture release]; - glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, glTex, 0); + id<MTLDevice> device = m_metalLayer.device; + MTLTextureDescriptor *overlayDesc = [MTLTextureDescriptor + texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA16Float + width:width + height:height + mipmapped:NO]; + overlayDesc.storageMode = MTLStorageModePrivate; + overlayDesc.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead; + + id<MTLTexture> overlayTex = [device newTextureWithDescriptor:overlayDesc]; + if (!overlayTex) { + ghost_fatal_error_dialog( + "GHOST_ContextCGL::metalUpdateFramebuffer: failed to create Metal overlay texture!"); + } + else { + overlayTex.label = [NSString + stringWithFormat:@"Metal Overlay for GHOST Context %p", this]; //@""; - [m_metalLayer setDrawableSize:CGSizeMake((CGFloat)width, (CGFloat)height)]; + // NSLog(@"Created new Metal Overlay (backbuffer) for context %p\n", this); + } + + m_defaultFramebufferMetalTexture[current_swapchain_index].texture = + overlayTex; //[(MTLTexture *)overlayTex retain]; + + /* Clear texture on create */ + id<MTLCommandBuffer> cmdBuffer = [m_metalCmdQueue commandBuffer]; + MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; + { + auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0]; + attachment.texture = m_defaultFramebufferMetalTexture[current_swapchain_index].texture; + attachment.loadAction = MTLLoadActionClear; + attachment.clearColor = MTLClearColorMake(0.294, 0.294, 0.294, 1.000); + attachment.storeAction = MTLStoreActionStore; + } + { + id<MTLRenderCommandEncoder> enc = [cmdBuffer + renderCommandEncoderWithDescriptor:passDescriptor]; + [enc endEncoding]; + } + [cmdBuffer commit]; + } - CVPixelBufferRelease(cvPixelBuffer); - CVOpenGLTextureCacheRelease(cvGLTexCache); - CVOpenGLTextureRelease(cvGLTex); - CFRelease(cvMetalTexCache); - CFRelease(cvMetalTex); + if (!m_useMetalForRendering) { +#if WITH_OPENGL + glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, glTex, 0); +#endif + } + + [m_metalLayer setDrawableSize:CGSizeMake((CGFloat)width, (CGFloat)height)]; + if (!m_useMetalForRendering) { +#if WITH_OPENGL + CVPixelBufferRelease(cvPixelBuffer); + CVOpenGLTextureCacheRelease(cvGLTexCache); + CVOpenGLTextureRelease(cvGLTex); + CFRelease(cvMetalTexCache); + CFRelease(cvMetalTex); +#endif + } } void GHOST_ContextCGL::metalSwapBuffers() @@ -529,40 +825,88 @@ void GHOST_ContextCGL::metalSwapBuffers() @autoreleasepool { /* clang-format on */ updateDrawingContext(); - glFlush(); - assert(m_defaultFramebufferMetalTexture != 0); + if (!m_useMetalForRendering) { +#if WITH_OPENGL + glFlush(); + assert(m_defaultFramebufferMetalTexture[current_swapchain_index].texture != nil); +#endif + } id<CAMetalDrawable> drawable = [m_metalLayer nextDrawable]; if (!drawable) { return; } - id<MTLCommandBuffer> cmdBuffer = [m_metalCmdQueue commandBuffer]; - MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; { auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0]; attachment.texture = drawable.texture; - attachment.loadAction = MTLLoadActionDontCare; + attachment.loadAction = MTLLoadActionClear; + attachment.clearColor = MTLClearColorMake(1.0, 0.294, 0.294, 1.000); attachment.storeAction = MTLStoreActionStore; } - id<MTLTexture> srcTexture = (id<MTLTexture>)m_defaultFramebufferMetalTexture; + if (!m_useMetalForRendering) { + id<MTLCommandBuffer> cmdBuffer = [m_metalCmdQueue commandBuffer]; + { + assert(m_defaultFramebufferMetalTexture[current_swapchain_index].texture != nil); + id<MTLRenderCommandEncoder> enc = [cmdBuffer + renderCommandEncoderWithDescriptor:passDescriptor]; + [enc setRenderPipelineState:(id<MTLRenderPipelineState>)m_metalRenderPipeline]; + [enc setFragmentTexture:m_defaultFramebufferMetalTexture[current_swapchain_index].texture + atIndex:0]; + [enc drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3]; + [enc endEncoding]; + } + + [cmdBuffer presentDrawable:drawable]; + + /* Submit command buffer */ + [cmdBuffer commit]; + } + else { + assert(contextPresentCallback); + assert(m_defaultFramebufferMetalTexture[current_swapchain_index].texture != nil); + (*contextPresentCallback)(passDescriptor, + (id<MTLRenderPipelineState>)m_metalRenderPipeline, + m_defaultFramebufferMetalTexture[current_swapchain_index].texture, + drawable); + } + } +} + +void GHOST_ContextCGL::initClear() +{ + + if (!m_useMetalForRendering) { +#if WITH_OPENGL + glClearColor(0.294, 0.294, 0.294, 0.000); + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(0.000, 0.000, 0.000, 0.000); +#endif + } + else { +#if WITH_METAL + // TODO (mg_gpusw_apple) this path is never taken, this is legacy left from inital integration + // of metal and gl, the whole file should be cleaned up and stripped of the legacy path + id<MTLCommandBuffer> cmdBuffer = [m_metalCmdQueue commandBuffer]; + MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; + { + auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0]; + attachment.texture = m_defaultFramebufferMetalTexture[current_swapchain_index].texture; + attachment.loadAction = MTLLoadActionClear; + attachment.clearColor = MTLClearColorMake(0.294, 0.294, 0.294, 1.000); + attachment.storeAction = MTLStoreActionStore; + } + // encoding { id<MTLRenderCommandEncoder> enc = [cmdBuffer renderCommandEncoderWithDescriptor:passDescriptor]; - - [enc setRenderPipelineState:(id<MTLRenderPipelineState>)m_metalRenderPipeline]; - [enc setFragmentTexture:srcTexture atIndex:0]; - [enc drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3]; - [enc endEncoding]; } - - [cmdBuffer presentDrawable:drawable]; - [cmdBuffer commit]; +#endif } } diff --git a/intern/ghost/intern/GHOST_ContextD3D.cpp b/intern/ghost/intern/GHOST_ContextD3D.cpp index ded76daa145..857323941ea 100644 --- a/intern/ghost/intern/GHOST_ContextD3D.cpp +++ b/intern/ghost/intern/GHOST_ContextD3D.cpp @@ -10,8 +10,7 @@ #include <iostream> #include <string> -#include <GL/glew.h> -#include <GL/wglew.h> +#include <epoxy/wgl.h> #include "GHOST_ContextD3D.h" #include "GHOST_ContextWGL.h" /* For shared drawing */ @@ -124,8 +123,6 @@ class GHOST_SharedOpenGLResource { ID3D11RenderTargetView *render_target = nullptr) : m_device(device), m_device_ctx(device_ctx), m_cur_width(width), m_cur_height(height) { - ID3D11Resource *backbuffer_res; - if (!render_target) { D3D11_TEXTURE2D_DESC texDesc{}; D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc{}; @@ -158,11 +155,12 @@ class GHOST_SharedOpenGLResource { m_render_target = render_target; if (m_render_target) { + ID3D11Resource *backbuffer_res = nullptr; m_render_target->GetResource(&backbuffer_res); - } - if (backbuffer_res) { - backbuffer_res->QueryInterface<ID3D11Texture2D>(&m_render_target_tex); - backbuffer_res->Release(); + if (backbuffer_res) { + backbuffer_res->QueryInterface<ID3D11Texture2D>(&m_render_target_tex); + backbuffer_res->Release(); + } } if (!m_render_target || !m_render_target_tex) { diff --git a/intern/ghost/intern/GHOST_ContextEGL.cpp b/intern/ghost/intern/GHOST_ContextEGL.cpp index 8c44dfe0158..ef13133d3a3 100644 --- a/intern/ghost/intern/GHOST_ContextEGL.cpp +++ b/intern/ghost/intern/GHOST_ContextEGL.cpp @@ -151,19 +151,6 @@ static bool egl_chk(bool result, # define EGL_CHK(x) egl_chk(x) #endif -static inline bool bindAPI(EGLenum api) -{ - if (EGLEW_VERSION_1_2) { - return (EGL_CHK(eglBindAPI(api)) == EGL_TRUE); - } - - return false; -} - -#ifdef WITH_GL_ANGLE -HMODULE GHOST_ContextEGL::s_d3dcompiler = nullptr; -#endif - EGLContext GHOST_ContextEGL::s_gl_sharedContext = EGL_NO_CONTEXT; EGLint GHOST_ContextEGL::s_gl_sharedCount = 0; @@ -256,7 +243,7 @@ GHOST_TSuccess GHOST_ContextEGL::swapBuffers() GHOST_TSuccess GHOST_ContextEGL::setSwapInterval(int interval) { - if (EGLEW_VERSION_1_1) { + if (epoxy_egl_version(m_display) >= 11) { if (EGL_CHK(::eglSwapInterval(m_display, interval))) { m_swap_interval = interval; @@ -313,26 +300,13 @@ GHOST_TSuccess GHOST_ContextEGL::releaseDrawingContext() return GHOST_kFailure; } -bool GHOST_ContextEGL::initContextEGLEW() +inline bool GHOST_ContextEGL::bindAPI(EGLenum api) { - /* We have to manually get this function before we can call eglewInit, since - * it requires a display argument. glewInit() does the same, but we only want - * to initialize EGLEW here. */ - eglGetDisplay = (PFNEGLGETDISPLAYPROC)eglGetProcAddress("eglGetDisplay"); - if (eglGetDisplay == nullptr) { - return false; - } - - if (!EGL_CHK((m_display = ::eglGetDisplay(m_nativeDisplay)) != EGL_NO_DISPLAY)) { - return false; - } - - if (GLEW_CHK(eglewInit(m_display)) != GLEW_OK) { - fprintf(stderr, "Warning! EGLEW failed to initialize properly.\n"); - return false; + if (epoxy_egl_version(m_display) >= 12) { + return (EGL_CHK(eglBindAPI(api)) == EGL_TRUE); } - return true; + return false; } static const std::string &api_string(EGLenum api) @@ -355,34 +329,41 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext() } m_stereoVisual = false; /* It doesn't matter what the Window wants. */ - if (!initContextEGLEW()) { - return GHOST_kFailure; - } - -#ifdef WITH_GL_ANGLE - /* `d3dcompiler_XX.dll` needs to be loaded before ANGLE will work. */ - if (s_d3dcompiler == nullptr) { - s_d3dcompiler = LoadLibrary(D3DCOMPILER); - - WIN32_CHK(s_d3dcompiler != nullptr); - - if (s_d3dcompiler == nullptr) { - fprintf(stderr, "LoadLibrary(\"" D3DCOMPILER "\") failed!\n"); - return GHOST_kFailure; - } - } -#endif - EGLDisplay prev_display = eglGetCurrentDisplay(); EGLSurface prev_draw = eglGetCurrentSurface(EGL_DRAW); EGLSurface prev_read = eglGetCurrentSurface(EGL_READ); EGLContext prev_context = eglGetCurrentContext(); - EGLint egl_major, egl_minor; + EGLint egl_major = 0, egl_minor = 0; - if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor))) { + if (!EGL_CHK((m_display = ::eglGetDisplay(m_nativeDisplay)) != EGL_NO_DISPLAY)) { goto error; } + + if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor)) || + (egl_major == 0 && egl_minor == 0)) { + /* We failed to create a regular render window, retry and see if we can create a headless + * render context. */ + ::eglTerminate(m_display); + + const char *egl_extension_st = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + assert(egl_extension_st != nullptr); + assert(strstr(egl_extension_st, "EGL_MESA_platform_surfaceless") != nullptr); + if (egl_extension_st == nullptr || + strstr(egl_extension_st, "EGL_MESA_platform_surfaceless") == nullptr) { + goto error; + } + + m_display = eglGetPlatformDisplayEXT( + EGL_PLATFORM_SURFACELESS_MESA, EGL_DEFAULT_DISPLAY, nullptr); + + if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor))) { + goto error; + } + /* Because the first eglInitialize will print an error to the terminal, print a "success" + * message here to let the user know that we successfully recovered from the error. */ + fprintf(stderr, "\nManaged to successfully fallback to surfaceless EGL rendering!\n\n"); + } #ifdef WITH_GHOST_DEBUG fprintf(stderr, "EGL Version %d.%d\n", egl_major, egl_minor); #endif @@ -398,7 +379,7 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext() attrib_list.reserve(20); - if (m_api == EGL_OPENGL_ES_API && EGLEW_VERSION_1_2) { + if (m_api == EGL_OPENGL_ES_API && epoxy_egl_version(m_display) >= 12) { /* According to the spec it seems that you are required to set EGL_RENDERABLE_TYPE, * but some implementations (ANGLE) do not seem to care. */ @@ -421,9 +402,11 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext() m_contextMinorVersion); } - if (!((m_contextMajorVersion == 1) || (m_contextMajorVersion == 2 && EGLEW_VERSION_1_3) || - (m_contextMajorVersion == 3 && /*EGLEW_VERSION_1_4 &&*/ EGLEW_KHR_create_context) || - (m_contextMajorVersion == 3 && EGLEW_VERSION_1_5))) { + if (!((m_contextMajorVersion == 1) || + (m_contextMajorVersion == 2 && epoxy_egl_version(m_display) >= 13) || + (m_contextMajorVersion == 3 && + epoxy_has_egl_extension(m_display, "KHR_create_context")) || + (m_contextMajorVersion == 3 && epoxy_egl_version(m_display) >= 15))) { fprintf(stderr, "Warning! May not be able to create a version %d.%d ES context with version %d.%d " "of EGL\n", @@ -488,7 +471,8 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext() } attrib_list.clear(); - if (EGLEW_VERSION_1_5 || EGLEW_KHR_create_context) { + if (epoxy_egl_version(m_display) >= 15 || + epoxy_has_egl_extension(m_display, "KHR_create_context")) { if (m_api == EGL_OPENGL_API || m_api == EGL_OPENGL_ES_API) { if (m_contextMajorVersion != 0) { attrib_list.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); @@ -530,7 +514,7 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext() } } - if (m_api == EGL_OPENGL_API || EGLEW_VERSION_1_5) { + if (m_api == EGL_OPENGL_API || epoxy_egl_version(m_display) >= 15) { if (m_contextResetNotificationStrategy != 0) { attrib_list.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR); attrib_list.push_back(m_contextResetNotificationStrategy); @@ -598,10 +582,10 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext() goto error; } - initContextGLEW(); - - initClearGL(); - ::eglSwapBuffers(m_display, m_surface); + if (m_nativeWindow != 0) { + initClearGL(); + ::eglSwapBuffers(m_display, m_surface); + } return GHOST_kSuccess; diff --git a/intern/ghost/intern/GHOST_ContextEGL.h b/intern/ghost/intern/GHOST_ContextEGL.h index 3250dc94978..3ccd34f0338 100644 --- a/intern/ghost/intern/GHOST_ContextEGL.h +++ b/intern/ghost/intern/GHOST_ContextEGL.h @@ -10,7 +10,8 @@ #include "GHOST_Context.h" #include "GHOST_System.h" -#include <GL/eglew.h> +#include <epoxy/egl.h> +#include <epoxy/gl.h> #ifndef GHOST_OPENGL_EGL_CONTEXT_FLAGS # define GHOST_OPENGL_EGL_CONTEXT_FLAGS 0 @@ -96,7 +97,7 @@ class GHOST_ContextEGL : public GHOST_Context { EGLContext getContext() const; private: - bool initContextEGLEW(); + bool bindAPI(EGLenum api); const GHOST_System *const m_system; @@ -129,8 +130,4 @@ class GHOST_ContextEGL : public GHOST_Context { static EGLContext s_vg_sharedContext; static EGLint s_vg_sharedCount; - -#ifdef WITH_GL_ANGLE - static HMODULE s_d3dcompiler; -#endif }; diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp index b4a076e4598..ed1c874c236 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.cpp +++ b/intern/ghost/intern/GHOST_ContextGLX.cpp @@ -95,11 +95,6 @@ GHOST_TSuccess GHOST_ContextGLX::releaseDrawingContext() return ::glXMakeCurrent(m_display, None, nullptr) ? GHOST_kSuccess : GHOST_kFailure; } -void GHOST_ContextGLX::initContextGLXEW() -{ - initContextGLEW(); -} - GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext() { GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store); @@ -278,18 +273,11 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext() glXMakeCurrent(m_display, m_window, m_context); - /* Seems that this has to be called after #glXMakeCurrent, - * which means we cannot use `glX` extensions until after we create a context. */ - initContextGLXEW(); - if (m_window) { initClearGL(); ::glXSwapBuffers(m_display, m_window); } - /* re initialize to get the extensions properly */ - initContextGLXEW(); - version = glGetString(GL_VERSION); if (!version || version[0] < '3' || ((version[0] == '3') && (version[2] < '3'))) { @@ -318,7 +306,7 @@ GHOST_TSuccess GHOST_ContextGLX::releaseNativeHandles() GHOST_TSuccess GHOST_ContextGLX::setSwapInterval(int interval) { - if (!GLXEW_EXT_swap_control) { + if (!epoxy_has_glx_extension(m_display, DefaultScreen(m_display), "GLX_EXT_swap_control")) { ::glXSwapIntervalEXT(m_display, m_window, interval); return GHOST_kSuccess; } @@ -327,7 +315,7 @@ GHOST_TSuccess GHOST_ContextGLX::setSwapInterval(int interval) GHOST_TSuccess GHOST_ContextGLX::getSwapInterval(int &intervalOut) { - if (GLXEW_EXT_swap_control) { + if (epoxy_has_glx_extension(m_display, DefaultScreen(m_display), "GLX_EXT_swap_control")) { unsigned int interval = 0; ::glXQueryDrawable(m_display, m_window, GLX_SWAP_INTERVAL_EXT, &interval); diff --git a/intern/ghost/intern/GHOST_ContextGLX.h b/intern/ghost/intern/GHOST_ContextGLX.h index c6184bbd3da..d526e6b1b32 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.h +++ b/intern/ghost/intern/GHOST_ContextGLX.h @@ -9,7 +9,7 @@ #include "GHOST_Context.h" -#include <GL/glxew.h> +#include <epoxy/glx.h> #ifndef GHOST_OPENGL_GLX_CONTEXT_FLAGS /* leave as convenience define for the future */ @@ -89,8 +89,6 @@ class GHOST_ContextGLX : public GHOST_Context { GHOST_TSuccess getSwapInterval(int &intervalOut); private: - void initContextGLXEW(); - Display *m_display; GLXFBConfig m_fbconfig; Window m_window; diff --git a/intern/ghost/intern/GHOST_ContextSDL.cpp b/intern/ghost/intern/GHOST_ContextSDL.cpp index 5b02fe1c1e6..63b5927895d 100644 --- a/intern/ghost/intern/GHOST_ContextSDL.cpp +++ b/intern/ghost/intern/GHOST_ContextSDL.cpp @@ -138,8 +138,6 @@ GHOST_TSuccess GHOST_ContextSDL::initializeDrawingContext() success = (SDL_GL_MakeCurrent(m_window, m_context) < 0) ? GHOST_kFailure : GHOST_kSuccess; - initContextGLEW(); - initClearGL(); SDL_GL_SwapWindow(m_window); diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp index 7417358e9ae..d3c190a13b1 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.cpp +++ b/intern/ghost/intern/GHOST_ContextWGL.cpp @@ -87,7 +87,7 @@ GHOST_TSuccess GHOST_ContextWGL::swapBuffers() GHOST_TSuccess GHOST_ContextWGL::setSwapInterval(int interval) { - if (WGLEW_EXT_swap_control) + if (epoxy_has_wgl_extension(m_hDC, "WGL_EXT_swap_control")) return WIN32_CHK(::wglSwapIntervalEXT(interval)) == TRUE ? GHOST_kSuccess : GHOST_kFailure; else return GHOST_kFailure; @@ -95,7 +95,7 @@ GHOST_TSuccess GHOST_ContextWGL::setSwapInterval(int interval) GHOST_TSuccess GHOST_ContextWGL::getSwapInterval(int &intervalOut) { - if (WGLEW_EXT_swap_control) { + if (epoxy_has_wgl_extension(m_hDC, "WGL_EXT_swap_control")) { intervalOut = ::wglGetSwapIntervalEXT(); return GHOST_kSuccess; } @@ -266,89 +266,6 @@ static HWND clone_window(HWND hWnd, LPVOID lpParam) return hwndCloned; } -void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD) -{ - HWND dummyHWND = NULL; - - HDC dummyHDC = NULL; - HGLRC dummyHGLRC = NULL; - - HDC prevHDC; - HGLRC prevHGLRC; - - int iPixelFormat; - - SetLastError(NO_ERROR); - - prevHDC = ::wglGetCurrentDC(); - WIN32_CHK(GetLastError() == NO_ERROR); - - prevHGLRC = ::wglGetCurrentContext(); - WIN32_CHK(GetLastError() == NO_ERROR); - - iPixelFormat = choose_pixel_format_legacy(m_hDC, preferredPFD); - - if (iPixelFormat == 0) - goto finalize; - - PIXELFORMATDESCRIPTOR chosenPFD; - if (!WIN32_CHK( - ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD))) - goto finalize; - - if (m_hWnd) { - dummyHWND = clone_window(m_hWnd, NULL); - - if (dummyHWND == NULL) - goto finalize; - - dummyHDC = GetDC(dummyHWND); - } - - if (!WIN32_CHK(dummyHDC != NULL)) - goto finalize; - - if (!WIN32_CHK(::SetPixelFormat(dummyHDC, iPixelFormat, &chosenPFD))) - goto finalize; - - dummyHGLRC = ::wglCreateContext(dummyHDC); - - if (!WIN32_CHK(dummyHGLRC != NULL)) - goto finalize; - - if (!WIN32_CHK(::wglMakeCurrent(dummyHDC, dummyHGLRC))) - goto finalize; - - if (GLEW_CHK(glewInit()) != GLEW_OK) { - fprintf(stderr, "Warning! Dummy GLEW/WGLEW failed to initialize properly.\n"); - } - - /* The following are not technically WGLEW, but they also require a context to work. */ - -#ifndef NDEBUG - free((void *)m_dummyRenderer); - free((void *)m_dummyVendor); - free((void *)m_dummyVersion); - - m_dummyRenderer = _strdup(reinterpret_cast<const char *>(glGetString(GL_RENDERER))); - m_dummyVendor = _strdup(reinterpret_cast<const char *>(glGetString(GL_VENDOR))); - m_dummyVersion = _strdup(reinterpret_cast<const char *>(glGetString(GL_VERSION))); -#endif - -finalize: - WIN32_CHK(::wglMakeCurrent(prevHDC, prevHGLRC)); - - if (dummyHGLRC != NULL) - WIN32_CHK(::wglDeleteContext(dummyHGLRC)); - - if (dummyHWND != NULL) { - if (dummyHDC != NULL) - WIN32_CHK(::ReleaseDC(dummyHWND, dummyHDC)); - - WIN32_CHK(::DestroyWindow(dummyHWND)); - } -} - static void makeAttribList(std::vector<int> &out, bool stereoVisual, bool needAlpha) { out.clear(); @@ -385,6 +302,130 @@ static void makeAttribList(std::vector<int> &out, bool stereoVisual, bool needAl out.push_back(0); } +/* Temporary context used to create the actual context. We need ARB pixel format + * and context extensions, which are only available within a context. */ +struct DummyContextWGL { + HWND dummyHWND = NULL; + + HDC dummyHDC = NULL; + HGLRC dummyHGLRC = NULL; + + HDC prevHDC = NULL; + HGLRC prevHGLRC = NULL; + + int dummyPixelFormat = 0; + + PIXELFORMATDESCRIPTOR preferredPFD; + + bool has_WGL_ARB_pixel_format = false; + bool has_WGL_ARB_create_context = false; + bool has_WGL_ARB_create_context_profile = false; + bool has_WGL_ARB_create_context_robustness = false; + + DummyContextWGL(HDC hDC, HWND hWnd, bool stereoVisual, bool needAlpha) + { + preferredPFD = { + sizeof(PIXELFORMATDESCRIPTOR), /* size */ + 1, /* version */ + (DWORD)(PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | + PFD_DOUBLEBUFFER | /* support double-buffering */ + (stereoVisual ? PFD_STEREO : 0) | /* support stereo */ + ( +#ifdef WIN32_COMPOSITING + /* Support composition for transparent background. */ + needAlpha ? PFD_SUPPORT_COMPOSITION : +#endif + 0)), + PFD_TYPE_RGBA, /* color type */ + (BYTE)(needAlpha ? 32 : 24), /* preferred color depth */ + 0, + 0, + 0, + 0, + 0, + 0, /* color bits (ignored) */ + (BYTE)(needAlpha ? 8 : 0), /* alpha buffer */ + 0, /* alpha shift (ignored) */ + 0, /* no accumulation buffer */ + 0, + 0, + 0, + 0, /* accum bits (ignored) */ + 0, /* depth buffer */ + 0, /* stencil buffer */ + 0, /* no auxiliary buffers */ + PFD_MAIN_PLANE, /* main layer */ + 0, /* reserved */ + 0, + 0, + 0 /* layer, visible, and damage masks (ignored) */ + }; + + SetLastError(NO_ERROR); + + prevHDC = ::wglGetCurrentDC(); + WIN32_CHK(GetLastError() == NO_ERROR); + + prevHGLRC = ::wglGetCurrentContext(); + WIN32_CHK(GetLastError() == NO_ERROR); + + dummyPixelFormat = choose_pixel_format_legacy(hDC, preferredPFD); + + if (dummyPixelFormat == 0) + return; + + PIXELFORMATDESCRIPTOR chosenPFD; + if (!WIN32_CHK(::DescribePixelFormat( + hDC, dummyPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD))) + return; + + if (hWnd) { + dummyHWND = clone_window(hWnd, NULL); + + if (dummyHWND == NULL) + return; + + dummyHDC = GetDC(dummyHWND); + } + + if (!WIN32_CHK(dummyHDC != NULL)) + return; + + if (!WIN32_CHK(::SetPixelFormat(dummyHDC, dummyPixelFormat, &chosenPFD))) + return; + + dummyHGLRC = ::wglCreateContext(dummyHDC); + + if (!WIN32_CHK(dummyHGLRC != NULL)) + return; + + if (!WIN32_CHK(::wglMakeCurrent(dummyHDC, dummyHGLRC))) + return; + + has_WGL_ARB_pixel_format = epoxy_has_wgl_extension(hDC, "WGL_ARB_pixel_format"); + has_WGL_ARB_create_context = epoxy_has_wgl_extension(hDC, "WGL_ARB_create_context"); + has_WGL_ARB_create_context_profile = epoxy_has_wgl_extension(hDC, + "WGL_ARB_create_context_profile"); + has_WGL_ARB_create_context_robustness = epoxy_has_wgl_extension( + hDC, "WGL_ARB_create_context_robustness"); + } + + ~DummyContextWGL() + { + WIN32_CHK(::wglMakeCurrent(prevHDC, prevHGLRC)); + + if (dummyHGLRC != NULL) + WIN32_CHK(::wglDeleteContext(dummyHGLRC)); + + if (dummyHWND != NULL) { + if (dummyHDC != NULL) + WIN32_CHK(::ReleaseDC(dummyHWND, dummyHDC)); + + WIN32_CHK(::DestroyWindow(dummyHWND)); + } + } +}; + int GHOST_ContextWGL::_choose_pixel_format_arb_1(bool stereoVisual, bool needAlpha) { std::vector<int> iAttributes; @@ -454,58 +495,6 @@ int GHOST_ContextWGL::choose_pixel_format_arb(bool stereoVisual, bool needAlpha) return iPixelFormat; } -int GHOST_ContextWGL::choose_pixel_format(bool stereoVisual, bool needAlpha) -{ - PIXELFORMATDESCRIPTOR preferredPFD = { - sizeof(PIXELFORMATDESCRIPTOR), /* size */ - 1, /* version */ - (DWORD)(PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | - PFD_DOUBLEBUFFER | /* support double-buffering */ - (stereoVisual ? PFD_STEREO : 0) | /* support stereo */ - ( -#ifdef WIN32_COMPOSITING - /* Support composition for transparent background. */ - needAlpha ? PFD_SUPPORT_COMPOSITION : -#endif - 0)), - PFD_TYPE_RGBA, /* color type */ - (BYTE)(needAlpha ? 32 : 24), /* preferred color depth */ - 0, - 0, - 0, - 0, - 0, - 0, /* color bits (ignored) */ - (BYTE)(needAlpha ? 8 : 0), /* alpha buffer */ - 0, /* alpha shift (ignored) */ - 0, /* no accumulation buffer */ - 0, - 0, - 0, - 0, /* accum bits (ignored) */ - 0, /* depth buffer */ - 0, /* stencil buffer */ - 0, /* no auxiliary buffers */ - PFD_MAIN_PLANE, /* main layer */ - 0, /* reserved */ - 0, - 0, - 0 /* layer, visible, and damage masks (ignored) */ - }; - - initContextWGLEW(preferredPFD); - - int iPixelFormat = 0; - - if (WGLEW_ARB_pixel_format) - iPixelFormat = choose_pixel_format_arb(stereoVisual, needAlpha); - - if (iPixelFormat == 0) - iPixelFormat = choose_pixel_format_legacy(m_hDC, preferredPFD); - - return iPixelFormat; -} - #ifndef NDEBUG static void reportContextString(const char *name, const char *dummy, const char *context) { @@ -526,107 +515,96 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext() HDC prevHDC = ::wglGetCurrentDC(); WIN32_CHK(GetLastError() == NO_ERROR); - if (!WGLEW_ARB_create_context || ::GetPixelFormat(m_hDC) == 0) { + { const bool needAlpha = m_alphaBackground; - int iPixelFormat; - int lastPFD; - - PIXELFORMATDESCRIPTOR chosenPFD; - - iPixelFormat = choose_pixel_format(m_stereoVisual, needAlpha); + DummyContextWGL dummy(m_hDC, m_hWnd, m_stereoVisual, needAlpha); - if (iPixelFormat == 0) { - goto error; - } + if (!dummy.has_WGL_ARB_create_context || ::GetPixelFormat(m_hDC) == 0) { + int iPixelFormat = 0; - lastPFD = ::DescribePixelFormat( - m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD); - - if (!WIN32_CHK(lastPFD != 0)) { - goto error; - } + if (dummy.has_WGL_ARB_pixel_format) + iPixelFormat = choose_pixel_format_arb(m_stereoVisual, needAlpha); - if (needAlpha && chosenPFD.cAlphaBits == 0) - fprintf(stderr, "Warning! Unable to find a pixel format with an alpha channel.\n"); + if (iPixelFormat == 0) + iPixelFormat = choose_pixel_format_legacy(m_hDC, dummy.preferredPFD); - if (!WIN32_CHK(::SetPixelFormat(m_hDC, iPixelFormat, &chosenPFD))) { - goto error; - } - } + if (iPixelFormat == 0) { + goto error; + } - if (WGLEW_ARB_create_context) { - int profileBitCore = m_contextProfileMask & WGL_CONTEXT_CORE_PROFILE_BIT_ARB; - int profileBitCompat = m_contextProfileMask & WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + PIXELFORMATDESCRIPTOR chosenPFD; + int lastPFD = ::DescribePixelFormat( + m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD); -#ifdef WITH_GLEW_ES - int profileBitES = m_contextProfileMask & WGL_CONTEXT_ES_PROFILE_BIT_EXT; -#endif + if (!WIN32_CHK(lastPFD != 0)) { + goto error; + } - if (!WGLEW_ARB_create_context_profile && profileBitCore) - fprintf(stderr, "Warning! OpenGL core profile not available.\n"); + if (needAlpha && chosenPFD.cAlphaBits == 0) + fprintf(stderr, "Warning! Unable to find a pixel format with an alpha channel.\n"); - if (!WGLEW_ARB_create_context_profile && profileBitCompat) - fprintf(stderr, "Warning! OpenGL compatibility profile not available.\n"); + if (!WIN32_CHK(::SetPixelFormat(m_hDC, iPixelFormat, &chosenPFD))) { + goto error; + } + } -#ifdef WITH_GLEW_ES - if (!WGLEW_EXT_create_context_es_profile && profileBitES && m_contextMajorVersion == 1) - fprintf(stderr, "Warning! OpenGL ES profile not available.\n"); + if (dummy.has_WGL_ARB_create_context) { + int profileBitCore = m_contextProfileMask & WGL_CONTEXT_CORE_PROFILE_BIT_ARB; + int profileBitCompat = m_contextProfileMask & WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; - if (!WGLEW_EXT_create_context_es2_profile && profileBitES && m_contextMajorVersion == 2) - fprintf(stderr, "Warning! OpenGL ES2 profile not available.\n"); -#endif + if (!dummy.has_WGL_ARB_create_context_profile && profileBitCore) + fprintf(stderr, "Warning! OpenGL core profile not available.\n"); - int profileMask = 0; + if (!dummy.has_WGL_ARB_create_context_profile && profileBitCompat) + fprintf(stderr, "Warning! OpenGL compatibility profile not available.\n"); - if (WGLEW_ARB_create_context_profile && profileBitCore) - profileMask |= profileBitCore; + int profileMask = 0; - if (WGLEW_ARB_create_context_profile && profileBitCompat) - profileMask |= profileBitCompat; + if (dummy.has_WGL_ARB_create_context_profile && profileBitCore) + profileMask |= profileBitCore; -#ifdef WITH_GLEW_ES - if (WGLEW_EXT_create_context_es_profile && profileBitES) - profileMask |= profileBitES; -#endif + if (dummy.has_WGL_ARB_create_context_profile && profileBitCompat) + profileMask |= profileBitCompat; - if (profileMask != m_contextProfileMask) - fprintf(stderr, "Warning! Ignoring untested OpenGL context profile mask bits."); + if (profileMask != m_contextProfileMask) + fprintf(stderr, "Warning! Ignoring untested OpenGL context profile mask bits."); - std::vector<int> iAttributes; + std::vector<int> iAttributes; - if (profileMask) { - iAttributes.push_back(WGL_CONTEXT_PROFILE_MASK_ARB); - iAttributes.push_back(profileMask); - } - - if (m_contextMajorVersion != 0) { - iAttributes.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB); - iAttributes.push_back(m_contextMajorVersion); - } + if (profileMask) { + iAttributes.push_back(WGL_CONTEXT_PROFILE_MASK_ARB); + iAttributes.push_back(profileMask); + } - if (m_contextMinorVersion != 0) { - iAttributes.push_back(WGL_CONTEXT_MINOR_VERSION_ARB); - iAttributes.push_back(m_contextMinorVersion); - } + if (m_contextMajorVersion != 0) { + iAttributes.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB); + iAttributes.push_back(m_contextMajorVersion); + } - if (m_contextFlags != 0) { - iAttributes.push_back(WGL_CONTEXT_FLAGS_ARB); - iAttributes.push_back(m_contextFlags); - } + if (m_contextMinorVersion != 0) { + iAttributes.push_back(WGL_CONTEXT_MINOR_VERSION_ARB); + iAttributes.push_back(m_contextMinorVersion); + } - if (m_contextResetNotificationStrategy != 0) { - if (WGLEW_ARB_create_context_robustness) { - iAttributes.push_back(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); - iAttributes.push_back(m_contextResetNotificationStrategy); + if (m_contextFlags != 0) { + iAttributes.push_back(WGL_CONTEXT_FLAGS_ARB); + iAttributes.push_back(m_contextFlags); } - else { - fprintf(stderr, "Warning! Cannot set the reset notification strategy."); + + if (m_contextResetNotificationStrategy != 0) { + if (dummy.has_WGL_ARB_create_context_robustness) { + iAttributes.push_back(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); + iAttributes.push_back(m_contextResetNotificationStrategy); + } + else { + fprintf(stderr, "Warning! Cannot set the reset notification strategy."); + } } - } - iAttributes.push_back(0); + iAttributes.push_back(0); - m_hGLRC = ::wglCreateContextAttribsARB(m_hDC, NULL, &(iAttributes[0])); + m_hGLRC = ::wglCreateContextAttribsARB(m_hDC, NULL, &(iAttributes[0])); + } } /* Silence warnings interpreted as errors by users when trying to get @@ -651,8 +629,6 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext() goto error; } - initContextGLEW(); - if (is_crappy_intel_card()) { /* Some Intel cards with context 4.1 or 4.2 * don't have the point sprite enabled by default. diff --git a/intern/ghost/intern/GHOST_ContextWGL.h b/intern/ghost/intern/GHOST_ContextWGL.h index ca0bf70b128..c02c0616422 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.h +++ b/intern/ghost/intern/GHOST_ContextWGL.h @@ -11,7 +11,7 @@ #include "GHOST_Context.h" -#include <GL/wglew.h> +#include <epoxy/wgl.h> #ifndef GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY # define GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY 0 @@ -86,12 +86,9 @@ class GHOST_ContextWGL : public GHOST_Context { GHOST_TSuccess getSwapInterval(int &intervalOut); private: - int choose_pixel_format(bool stereoVisual, bool needAlpha); int choose_pixel_format_arb(bool stereoVisual, bool needAlpha); int _choose_pixel_format_arb_1(bool stereoVisual, bool needAlpha); - void initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD); - HWND m_hWnd; HDC m_hDC; diff --git a/intern/ghost/intern/GHOST_DisplayManagerNULL.h b/intern/ghost/intern/GHOST_DisplayManagerNULL.h index ba72dcbe8dd..dbef4fafd8f 100644 --- a/intern/ghost/intern/GHOST_DisplayManagerNULL.h +++ b/intern/ghost/intern/GHOST_DisplayManagerNULL.h @@ -8,38 +8,38 @@ #pragma once #include "GHOST_DisplayManager.h" -#include "GHOST_SystemNULL.h" +#include "GHOST_SystemHeadless.h" -class GHOST_SystemNULL; +class GHOST_SystemHeadless; class GHOST_DisplayManagerNULL : public GHOST_DisplayManager { public: - GHOST_DisplayManagerNULL(GHOST_SystemNULL *system) : GHOST_DisplayManager(), m_system(system) + GHOST_DisplayManagerNULL() : GHOST_DisplayManager() { /* nop */ } - GHOST_TSuccess getNumDisplays(uint8_t &numDisplays) const + GHOST_TSuccess getNumDisplays(uint8_t & /*numDisplays*/) const override { return GHOST_kFailure; } - GHOST_TSuccess getNumDisplaySettings(uint8_t display, int32_t &numSettings) const + GHOST_TSuccess getNumDisplaySettings(uint8_t /*display*/, + int32_t & /*numSettings*/) const override { return GHOST_kFailure; } - GHOST_TSuccess getDisplaySetting(uint8_t display, - int32_t index, - GHOST_DisplaySetting &setting) const + GHOST_TSuccess getDisplaySetting(uint8_t /*display*/, + int32_t /*index*/, + GHOST_DisplaySetting & /*setting*/) const override { return GHOST_kFailure; } - GHOST_TSuccess getCurrentDisplaySetting(uint8_t display, GHOST_DisplaySetting &setting) const + GHOST_TSuccess getCurrentDisplaySetting(uint8_t display, + GHOST_DisplaySetting &setting) const override { return getDisplaySetting(display, int32_t(0), setting); } - GHOST_TSuccess setCurrentDisplaySetting(uint8_t display, const GHOST_DisplaySetting &setting) + GHOST_TSuccess setCurrentDisplaySetting(uint8_t /*display*/, + const GHOST_DisplaySetting & /*setting*/) override { return GHOST_kSuccess; } - - private: - GHOST_SystemNULL *m_system; }; diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp index 3d8920d7c52..ee79792bb7e 100644 --- a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp +++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp @@ -11,8 +11,9 @@ #define WIN32_LEAN_AND_MEAN #include <windows.h> -// We do not support multiple monitors at the moment +/* We do not support multiple monitors at the moment. */ #define COMPILE_MULTIMON_STUBS + #include <multimon.h> GHOST_DisplayManagerWin32::GHOST_DisplayManagerWin32(void) @@ -31,16 +32,15 @@ static BOOL get_dd(DWORD d, DISPLAY_DEVICE *dd) return ::EnumDisplayDevices(NULL, d, dd, 0); } -/* - * When you call EnumDisplaySettings with iModeNum set to zero, the operating system - * initializes and caches information about the display device. When you call - * EnumDisplaySettings with iModeNum set to a non-zero value, the function returns - * the information that was cached the last time the function was called with iModeNum - * set to zero. - */ GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplaySettings(uint8_t display, int32_t &numSettings) const { + /* When you call #EnumDisplaySettings with #iModeNum set to zero, the operating system + * initializes and caches information about the display device. + * When you call #EnumDisplaySettings with #iModeNum set to a non-zero value, + * the function returns the information that was cached the last time the + * function was called with #iModeNum set to zero. */ + DISPLAY_DEVICE display_device; if (!get_dd(display, &display_device)) return GHOST_kFailure; @@ -70,21 +70,20 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::getDisplaySetting(uint8_t display, dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency); -#endif // WITH_GHOST_DEBUG +#endif /* WITH_GHOST_DEBUG */ setting.xPixels = dm.dmPelsWidth; setting.yPixels = dm.dmPelsHeight; setting.bpp = dm.dmBitsPerPel; - /* When you call the EnumDisplaySettings function, the dmDisplayFrequency member + /* When you call the #EnumDisplaySettings function, the #dmDisplayFrequency member * may return with the value 0 or 1. These values represent the display hardware's * default refresh rate. This default rate is typically set by switches on a display * card or computer motherboard, or by a configuration program that does not use - * Win32 display functions such as ChangeDisplaySettings. - */ - /* First, we tried to explicitly set the frequency to 60 if EnumDisplaySettings + * Win32 display functions such as #ChangeDisplaySettings. */ + + /* First, we tried to explicitly set the frequency to 60 if #EnumDisplaySettings * returned 0 or 1 but this doesn't work since later on an exact match will * be searched. And this will never happen if we change it to 60. Now we rely - * on the default h/w setting. - */ + * on the default hardware setting. */ setting.frequency = dm.dmDisplayFrequency; success = GHOST_kSuccess; } @@ -117,22 +116,23 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::setCurrentDisplaySetting( break; } } - /* - * dm.dmBitsPerPel = match.bpp; - * dm.dmPelsWidth = match.xPixels; - * dm.dmPelsHeight = match.yPixels; - * dm.dmDisplayFrequency = match.frequency; - * dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; - * dm.dmSize = sizeof(DEVMODE); - * dm.dmDriverExtra = 0; - */ +#if 0 + dm.dmBitsPerPel = match.bpp; + dm.dmPelsWidth = match.xPixels; + dm.dmPelsHeight = match.yPixels; + dm.dmDisplayFrequency = match.frequency; + dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; + dm.dmSize = sizeof(DEVMODE); + dm.dmDriverExtra = 0; +#endif + #ifdef WITH_GHOST_DEBUG printf("display change: Requested settings:\n"); printf(" dmBitsPerPel=%d\n", dm.dmBitsPerPel); printf(" dmPelsWidth=%d\n", dm.dmPelsWidth); printf(" dmPelsHeight=%d\n", dm.dmPelsHeight); printf(" dmDisplayFrequency=%d\n", dm.dmDisplayFrequency); -#endif // WITH_GHOST_DEBUG +#endif /* WITH_GHOST_DEBUG */ LONG status = ::ChangeDisplaySettings(&dm, CDS_FULLSCREEN); #ifdef WITH_GHOST_DEBUG @@ -166,6 +166,6 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::setCurrentDisplaySetting( printf("display change: Return value invalid\n"); break; } -#endif // WITH_GHOST_DEBUG +#endif /* WITH_GHOST_DEBUG */ return status == DISP_CHANGE_SUCCESSFUL ? GHOST_kSuccess : GHOST_kFailure; } diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp index a82a31e7386..2831f2ee8ad 100644 --- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp +++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp @@ -13,9 +13,9 @@ #include "utfconv.h" #ifdef WITH_GHOST_DEBUG -// utility +/* utility */ void printLastError(void); -#endif // WITH_GHOST_DEBUG +#endif /* WITH_GHOST_DEBUG */ GHOST_DropTargetWin32::GHOST_DropTargetWin32(GHOST_WindowWin32 *window, GHOST_SystemWin32 *system) : m_window(window), m_system(system) @@ -32,22 +32,21 @@ GHOST_DropTargetWin32::~GHOST_DropTargetWin32() /* * IUnknown::QueryInterface */ -HRESULT __stdcall GHOST_DropTargetWin32::QueryInterface(REFIID riid, void **ppvObj) +HRESULT __stdcall GHOST_DropTargetWin32::QueryInterface(REFIID riid, void **ppv_obj) { - if (!ppvObj) + if (!ppv_obj) { return E_INVALIDARG; - *ppvObj = NULL; + } + *ppv_obj = NULL; if (riid == IID_IUnknown || riid == IID_IDropTarget) { AddRef(); - *ppvObj = (void *)this; + *ppv_obj = (void *)this; return S_OK; } - else { - *ppvObj = NULL; - return E_NOINTERFACE; - } + *ppv_obj = NULL; + return E_NOINTERFACE; } /* @@ -78,16 +77,16 @@ ULONG __stdcall GHOST_DropTargetWin32::Release(void) /* * Implementation of IDropTarget::DragEnter */ -HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *pDataObject, - DWORD grfKeyState, +HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *p_data_object, + DWORD grf_key_state, POINTL pt, - DWORD *pdwEffect) + DWORD *pdw_effect) { - // we accept all drop by default + /* We accept all drop by default. */ m_window->setAcceptDragOperation(true); - *pdwEffect = DROPEFFECT_NONE; + *pdw_effect = DROPEFFECT_NONE; - m_draggedObjectType = getGhostType(pDataObject); + m_draggedObjectType = getGhostType(p_data_object); m_system->pushDragDropEvent( GHOST_kEventDraggingEntered, m_draggedObjectType, m_window, pt.x, pt.y, NULL); return S_OK; @@ -96,15 +95,17 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *pDataObject, /* * Implementation of IDropTarget::DragOver */ -HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) +HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD grf_key_state, + POINTL pt, + DWORD *pdw_effect) { if (m_window->canAcceptDragOperation()) { - *pdwEffect = allowedDropEffect(*pdwEffect); + *pdw_effect = allowedDropEffect(*pdw_effect); } else { - *pdwEffect = DROPEFFECT_NONE; - // XXX Uncomment to test drop. Drop will not be called if pdwEffect == DROPEFFECT_NONE. - // *pdwEffect = DROPEFFECT_COPY; + *pdw_effect = DROPEFFECT_NONE; + /* XXX Uncomment to test drop. Drop will not be called if `pdw_effect == DROPEFFECT_NONE`. */ + // *pdw_effect = DROPEFFECT_COPY; } m_system->pushDragDropEvent( GHOST_kEventDraggingUpdated, m_draggedObjectType, m_window, pt.x, pt.y, NULL); @@ -123,25 +124,25 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragLeave(void) } /* Implementation of IDropTarget::Drop - * This function will not be called if pdwEffect is set to DROPEFFECT_NONE in + * This function will not be called if pdw_effect is set to DROPEFFECT_NONE in * the implementation of IDropTarget::DragOver */ -HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject *pDataObject, - DWORD grfKeyState, +HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject *p_data_object, + DWORD grf_key_state, POINTL pt, - DWORD *pdwEffect) + DWORD *pdw_effect) { - void *data = getGhostData(pDataObject); + void *data = getGhostData(p_data_object); if (m_window->canAcceptDragOperation()) { - *pdwEffect = allowedDropEffect(*pdwEffect); + *pdw_effect = allowedDropEffect(*pdw_effect); } else { - *pdwEffect = DROPEFFECT_NONE; + *pdw_effect = DROPEFFECT_NONE; } - if (data) + if (data) { m_system->pushDragDropEvent( GHOST_kEventDraggingDropDone, m_draggedObjectType, m_window, pt.x, pt.y, data); - + } m_draggedObjectType = GHOST_kDragnDropTypeUnknown; return S_OK; } @@ -150,150 +151,132 @@ HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject *pDataObject, * Helpers */ -DWORD GHOST_DropTargetWin32::allowedDropEffect(DWORD dwAllowed) +DWORD GHOST_DropTargetWin32::allowedDropEffect(DWORD dw_allowed) { - DWORD dwEffect = DROPEFFECT_NONE; - if (dwAllowed & DROPEFFECT_COPY) - dwEffect = DROPEFFECT_COPY; - - return dwEffect; + DWORD dw_effect = DROPEFFECT_NONE; + if (dw_allowed & DROPEFFECT_COPY) { + dw_effect = DROPEFFECT_COPY; + } + return dw_effect; } -GHOST_TDragnDropTypes GHOST_DropTargetWin32::getGhostType(IDataObject *pDataObject) +GHOST_TDragnDropTypes GHOST_DropTargetWin32::getGhostType(IDataObject *p_data_object) { /* Text * NOTE: Unicode text is available as CF_TEXT too, the system can do the * conversion, but we do the conversion our self with #WC_NO_BEST_FIT_CHARS. */ FORMATETC fmtetc = {CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; - if (pDataObject->QueryGetData(&fmtetc) == S_OK) { + if (p_data_object->QueryGetData(&fmtetc) == S_OK) { return GHOST_kDragnDropTypeString; } - // Filesnames + /* Files-names. */ fmtetc.cfFormat = CF_HDROP; - if (pDataObject->QueryGetData(&fmtetc) == S_OK) { + if (p_data_object->QueryGetData(&fmtetc) == S_OK) { return GHOST_kDragnDropTypeFilenames; } return GHOST_kDragnDropTypeUnknown; } -void *GHOST_DropTargetWin32::getGhostData(IDataObject *pDataObject) +void *GHOST_DropTargetWin32::getGhostData(IDataObject *p_data_object) { - GHOST_TDragnDropTypes type = getGhostType(pDataObject); + GHOST_TDragnDropTypes type = getGhostType(p_data_object); switch (type) { case GHOST_kDragnDropTypeFilenames: - return getDropDataAsFilenames(pDataObject); - break; + return getDropDataAsFilenames(p_data_object); case GHOST_kDragnDropTypeString: - return getDropDataAsString(pDataObject); - break; + return getDropDataAsString(p_data_object); case GHOST_kDragnDropTypeBitmap: - // return getDropDataAsBitmap(pDataObject); + // return getDropDataAsBitmap(p_data_object); break; default: #ifdef WITH_GHOST_DEBUG ::printf("\nGHOST_kDragnDropTypeUnknown"); -#endif // WITH_GHOST_DEBUG +#endif /* WITH_GHOST_DEBUG */ return NULL; - break; } return NULL; } -void *GHOST_DropTargetWin32::getDropDataAsFilenames(IDataObject *pDataObject) +void *GHOST_DropTargetWin32::getDropDataAsFilenames(IDataObject *p_data_object) { - UINT totfiles, nvalid = 0; - WCHAR fpath[MAX_PATH]; - char *temp_path; - GHOST_TStringArray *strArray = NULL; + GHOST_TStringArray *str_array = NULL; FORMATETC fmtetc = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; - STGMEDIUM stgmed; - HDROP hdrop; - - // Check if dataobject supplies the format we want. - // Double checking here, first in getGhostType. - if (pDataObject->QueryGetData(&fmtetc) == S_OK) { - if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK) { - hdrop = (HDROP)::GlobalLock(stgmed.hGlobal); - - totfiles = ::DragQueryFileW(hdrop, -1, NULL, 0); - if (!totfiles) { - ::GlobalUnlock(stgmed.hGlobal); - return NULL; - } - strArray = (GHOST_TStringArray *)::malloc(sizeof(GHOST_TStringArray)); - strArray->count = 0; - strArray->strings = (uint8_t **)::malloc(totfiles * sizeof(uint8_t *)); - - for (UINT nfile = 0; nfile < totfiles; nfile++) { - if (::DragQueryFileW(hdrop, nfile, fpath, MAX_PATH) > 0) { - if (!(temp_path = alloc_utf_8_from_16(fpath, 0))) { - continue; + /* Check if data-object supplies the format we want. + * Double checking here, first in #getGhostType. */ + if (p_data_object->QueryGetData(&fmtetc) == S_OK) { + STGMEDIUM stgmed; + if (p_data_object->GetData(&fmtetc, &stgmed) == S_OK) { + const HDROP hdrop = (HDROP)::GlobalLock(stgmed.hGlobal); + + const UINT totfiles = ::DragQueryFileW(hdrop, -1, NULL, 0); + if (totfiles) { + str_array = (GHOST_TStringArray *)::malloc(sizeof(GHOST_TStringArray)); + str_array->count = 0; + str_array->strings = (uint8_t **)::malloc(totfiles * sizeof(uint8_t *)); + + for (UINT nfile = 0; nfile < totfiles; nfile++) { + WCHAR fpath[MAX_PATH]; + if (::DragQueryFileW(hdrop, nfile, fpath, MAX_PATH) > 0) { + char *temp_path; + if (!(temp_path = alloc_utf_8_from_16(fpath, 0))) { + /* Just ignore paths that could not be converted verbatim. */ + continue; + } + str_array->strings[str_array->count++] = (uint8_t *)temp_path; } - // Just ignore paths that could not be converted verbatim. - - strArray->strings[nvalid] = (uint8_t *)temp_path; - strArray->count = nvalid + 1; - nvalid++; } } - // Free up memory. + /* Free up memory. */ ::GlobalUnlock(stgmed.hGlobal); ::ReleaseStgMedium(&stgmed); - - return strArray; } } - return NULL; + return str_array; } -void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject) +void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *p_data_object) { char *tmp_string; FORMATETC fmtetc = {CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM stgmed; - // Try unicode first. - // Check if dataobject supplies the format we want. - if (pDataObject->QueryGetData(&fmtetc) == S_OK) { - if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK) { + /* Try unicode first. + * Check if data-object supplies the format we want. */ + if (p_data_object->QueryGetData(&fmtetc) == S_OK) { + if (p_data_object->GetData(&fmtetc, &stgmed) == S_OK) { LPCWSTR wstr = (LPCWSTR)::GlobalLock(stgmed.hGlobal); - if (!(tmp_string = alloc_utf_8_from_16((wchar_t *)wstr, 0))) { - ::GlobalUnlock(stgmed.hGlobal); - return NULL; - } - // Free memory + + tmp_string = alloc_utf_8_from_16((wchar_t *)wstr, 0); + + /* Free memory. */ ::GlobalUnlock(stgmed.hGlobal); ::ReleaseStgMedium(&stgmed); + #ifdef WITH_GHOST_DEBUG - ::printf("\n<converted droped unicode string>\n%s\n</droped converted unicode string>\n", - tmp_string); -#endif // WITH_GHOST_DEBUG + if (tmp_string) { + ::printf("\n<converted droped unicode string>\n%s\n</droped converted unicode string>\n", + tmp_string); + } +#endif /* WITH_GHOST_DEBUG */ return tmp_string; } } fmtetc.cfFormat = CF_TEXT; - if (pDataObject->QueryGetData(&fmtetc) == S_OK) { - if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK) { + if (p_data_object->QueryGetData(&fmtetc) == S_OK) { + if (p_data_object->GetData(&fmtetc, &stgmed) == S_OK) { char *str = (char *)::GlobalLock(stgmed.hGlobal); tmp_string = (char *)::malloc(::strlen(str) + 1); - if (!tmp_string) { - ::GlobalUnlock(stgmed.hGlobal); - return NULL; - } - - if (!::strcpy(tmp_string, str)) { - ::free(tmp_string); - ::GlobalUnlock(stgmed.hGlobal); - return NULL; + if (tmp_string) { + ::strcpy(tmp_string, str); } - // Free memory + /* Free memory. */ ::GlobalUnlock(stgmed.hGlobal); ::ReleaseStgMedium(&stgmed); @@ -307,13 +290,13 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject) int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char *&out) { int size; - out = NULL; // caller should free if != NULL + out = NULL; /* caller should free if != NULL */ - // Get the required size. - size = ::WideCharToMultiByte(CP_ACP, // System Default Codepage - 0x00000400, // WC_NO_BEST_FIT_CHARS + /* Get the required size. */ + size = ::WideCharToMultiByte(CP_ACP, /* System Default Codepage */ + 0x00000400, /* WC_NO_BEST_FIT_CHARS */ in, - -1, //-1 null terminated, makes output null terminated too. + -1, /* -1 null terminated, makes output null terminated too. */ NULL, 0, NULL, @@ -322,7 +305,7 @@ int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char *&out) if (!size) { #ifdef WITH_GHOST_DEBUG ::printLastError(); -#endif // WITH_GHOST_DEBUG +#endif /* WITH_GHOST_DEBUG */ return 0; } @@ -337,7 +320,7 @@ int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char *&out) if (!size) { #ifdef WITH_GHOST_DEBUG ::printLastError(); -#endif // WITH_GHOST_DEBUG +#endif /* WITH_GHOST_DEBUG */ ::free(out); out = NULL; } @@ -362,4 +345,4 @@ void printLastError(void) LocalFree(s); } } -#endif // WITH_GHOST_DEBUG +#endif /* WITH_GHOST_DEBUG */ diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.h b/intern/ghost/intern/GHOST_DropTargetWin32.h index 2f628e81b56..03e5492fcb1 100644 --- a/intern/ghost/intern/GHOST_DropTargetWin32.h +++ b/intern/ghost/intern/GHOST_DropTargetWin32.h @@ -21,7 +21,7 @@ class GHOST_DropTargetWin32 : public IDropTarget { * inherited, directly or indirectly, from IUnknown. Therefore, the three * methods in IUnknown are the first entries in the VTable for every interface. */ - HRESULT __stdcall QueryInterface(REFIID riid, void **ppvObj); + HRESULT __stdcall QueryInterface(REFIID riid, void **ppv_obj); ULONG __stdcall AddRef(void); ULONG __stdcall Release(void); @@ -44,13 +44,16 @@ class GHOST_DropTargetWin32 : public IDropTarget { * RevokeDragDrop functions. */ - HRESULT __stdcall DragEnter(IDataObject *pDataObject, - DWORD grfKeyState, + HRESULT __stdcall DragEnter(IDataObject *p_data_object, + DWORD grf_key_state, POINTL pt, - DWORD *pdwEffect); - HRESULT __stdcall DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); + DWORD *pdw_effect); + HRESULT __stdcall DragOver(DWORD grf_key_state, POINTL pt, DWORD *pdw_effect); HRESULT __stdcall DragLeave(void); - HRESULT __stdcall Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); + HRESULT __stdcall Drop(IDataObject *p_data_object, + DWORD grf_key_state, + POINTL pt, + DWORD *pdw_effect); /** * Constructor @@ -76,36 +79,36 @@ class GHOST_DropTargetWin32 : public IDropTarget { * \param dwAllowed: Drop sources allowed drop effect. * \return The allowed drop effect. */ - DWORD allowedDropEffect(DWORD dwAllowed); + DWORD allowedDropEffect(DWORD dw_allowed); /** * Query DataObject for the data types it supports. - * \param pDataObject: Pointer to the DataObject. + * \param p_data_object: Pointer to the DataObject. * \return GHOST data type. */ - GHOST_TDragnDropTypes getGhostType(IDataObject *pDataObject); + GHOST_TDragnDropTypes getGhostType(IDataObject *p_data_object); /** * Get data to pass in event. * It checks the type and calls specific functions for each type. - * \param pDataObject: Pointer to the DataObject. + * \param p_data_object: Pointer to the DataObject. * \return Pointer to data. */ - void *getGhostData(IDataObject *pDataObject); + void *getGhostData(IDataObject *p_data_object); /** * Allocate data as file array to pass in event. - * \param pDataObject: Pointer to the DataObject. + * \param p_data_object: Pointer to the DataObject. * \return Pointer to data. */ - void *getDropDataAsFilenames(IDataObject *pDataObject); + void *getDropDataAsFilenames(IDataObject *p_data_object); /** * Allocate data as string to pass in event. - * \param pDataObject: Pointer to the DataObject. + * \param p_data_object: Pointer to the DataObject. * \return Pointer to data. */ - void *getDropDataAsString(IDataObject *pDataObject); + void *getDropDataAsString(IDataObject *p_data_object); /** * Convert Unicode to ANSI, replacing uncomfortable chars with '?'. diff --git a/intern/ghost/intern/GHOST_DropTargetX11.cpp b/intern/ghost/intern/GHOST_DropTargetX11.cpp index 4da3c7c996d..1403639a36f 100644 --- a/intern/ghost/intern/GHOST_DropTargetX11.cpp +++ b/intern/ghost/intern/GHOST_DropTargetX11.cpp @@ -114,7 +114,7 @@ void *GHOST_DropTargetX11::getURIListGhostData(unsigned char *dropBuffer, int dr /* Count total number of file paths in buffer. */ for (int i = 0; i <= dropBufferSize; i++) { - if (dropBuffer[i] == 0 || dropBuffer[i] == '\n' || dropBuffer[i] == '\r') { + if (ELEM(dropBuffer[i], 0, '\n', '\r')) { if (curLength) { totPaths++; curLength = 0; @@ -131,7 +131,7 @@ void *GHOST_DropTargetX11::getURIListGhostData(unsigned char *dropBuffer, int dr curLength = 0; for (int i = 0; i <= dropBufferSize; i++) { - if (dropBuffer[i] == 0 || dropBuffer[i] == '\n' || dropBuffer[i] == '\r') { + if (ELEM(dropBuffer[i], 0, '\n', '\r')) { if (curLength) { char *curPath = (char *)malloc(curLength + 1); char *decodedPath; @@ -182,7 +182,7 @@ void *GHOST_DropTargetX11::getGhostData(Atom dropType, data = decodedPath; } } - else if (dropType == dndTypePlainText || dropType == dndTypeOctetStream) { + else if (ELEM(dropType, dndTypePlainText, dndTypeOctetStream)) { m_draggedObjectType = GHOST_kDragnDropTypeString; data = tmpBuffer; needsFree = false; diff --git a/intern/ghost/intern/GHOST_EventPrinter.cpp b/intern/ghost/intern/GHOST_EventPrinter.cpp index 2620bcc075d..7c20cd701b0 100644 --- a/intern/ghost/intern/GHOST_EventPrinter.cpp +++ b/intern/ghost/intern/GHOST_EventPrinter.cpp @@ -220,8 +220,11 @@ void GHOST_EventPrinter::getKeyString(GHOST_TKey key, char str[32]) const case GHOST_kKeyRightAlt: tstr = "RightAlt"; break; - case GHOST_kKeyOS: - tstr = "OS"; + case GHOST_kKeyLeftOS: + tstr = "LeftOS"; + break; + case GHOST_kKeyRightOS: + tstr = "RightOS"; break; case GHOST_kKeyApp: tstr = "App"; diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp index 4f6a9531077..13eccf661f5 100644 --- a/intern/ghost/intern/GHOST_ISystem.cpp +++ b/intern/ghost/intern/GHOST_ISystem.cpp @@ -9,14 +9,14 @@ * Copyright (C) 2001 NaN Technologies B.V. */ +#include <stdexcept> + #include "GHOST_ISystem.h" +#include "GHOST_SystemHeadless.h" -#if defined(WITH_HEADLESS) -# include "GHOST_SystemNULL.h" -#elif defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND) +#if defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND) # include "GHOST_SystemWayland.h" # include "GHOST_SystemX11.h" -# include <stdexcept> #elif defined(WITH_GHOST_X11) # include "GHOST_SystemX11.h" #elif defined(WITH_GHOST_WAYLAND) @@ -49,26 +49,50 @@ GHOST_TSuccess GHOST_ISystem::createSystem() #endif #if defined(WITH_HEADLESS) - m_system = new GHOST_SystemNULL(); + /* Pass. */ #elif defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND) /* Special case, try Wayland, fall back to X11. */ try { m_system = has_wayland_libraries ? new GHOST_SystemWayland() : nullptr; } catch (const std::runtime_error &) { - /* fallback to X11. */ delete m_system; m_system = nullptr; } if (!m_system) { - m_system = new GHOST_SystemX11(); + /* Try to fallback to X11. */ + try { + m_system = new GHOST_SystemX11(); + } + catch (const std::runtime_error &) { + delete m_system; + m_system = nullptr; + } } #elif defined(WITH_GHOST_X11) - m_system = new GHOST_SystemX11(); + try { + m_system = new GHOST_SystemX11(); + } + catch (const std::runtime_error &) { + delete m_system; + m_system = nullptr; + } #elif defined(WITH_GHOST_WAYLAND) - m_system = has_wayland_libraries ? new GHOST_SystemWayland() : nullptr; + try { + m_system = has_wayland_libraries ? new GHOST_SystemWayland() : nullptr; + } + catch (const std::runtime_error &) { + delete m_system; + m_system = nullptr; + } #elif defined(WITH_GHOST_SDL) - m_system = new GHOST_SystemSDL(); + try { + m_system = new GHOST_SystemSDL(); + } + catch (const std::runtime_error &) { + delete m_system; + m_system = nullptr; + } #elif defined(WIN32) m_system = new GHOST_SystemWin32(); #elif defined(__APPLE__) @@ -85,6 +109,30 @@ GHOST_TSuccess GHOST_ISystem::createSystem() return success; } +GHOST_TSuccess GHOST_ISystem::createSystemBackground() +{ + GHOST_TSuccess success; + if (!m_system) { +#if !defined(WITH_HEADLESS) + /* Try to create a off-screen render surface with the graphical systems. */ + success = createSystem(); + if (success) { + return success; + } + /* Try to fallback to headless mode if all else fails. */ +#endif + m_system = new GHOST_SystemHeadless(); + success = m_system != nullptr ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + if (success) { + success = m_system->init(); + } + return success; +} + GHOST_TSuccess GHOST_ISystem::disposeSystem() { GHOST_TSuccess success = GHOST_kSuccess; diff --git a/intern/ghost/intern/GHOST_IXrGraphicsBinding.h b/intern/ghost/intern/GHOST_IXrGraphicsBinding.h index 1246aa19a99..152b6b68026 100644 --- a/intern/ghost/intern/GHOST_IXrGraphicsBinding.h +++ b/intern/ghost/intern/GHOST_IXrGraphicsBinding.h @@ -17,11 +17,8 @@ class GHOST_IXrGraphicsBinding { public: union { #if defined(WITH_GHOST_X11) -# if defined(WITH_GL_EGL) XrGraphicsBindingEGLMNDX egl; -# else XrGraphicsBindingOpenGLXlibKHR glx; -# endif #elif defined(WIN32) XrGraphicsBindingOpenGLWin32KHR wgl; XrGraphicsBindingD3D11KHR d3d11; diff --git a/intern/ghost/intern/GHOST_ImeWin32.cpp b/intern/ghost/intern/GHOST_ImeWin32.cpp index c3fcd7214ca..0a62359cd77 100644 --- a/intern/ghost/intern/GHOST_ImeWin32.cpp +++ b/intern/ghost/intern/GHOST_ImeWin32.cpp @@ -512,4 +512,4 @@ void GHOST_ImeWin32::UpdateInfo(HWND window_handle) } } -#endif // WITH_INPUT_IME +#endif /* WITH_INPUT_IME */ diff --git a/intern/ghost/intern/GHOST_ImeWin32.h b/intern/ghost/intern/GHOST_ImeWin32.h index 0ae2bbc59e9..85c8ed7b4bd 100644 --- a/intern/ghost/intern/GHOST_ImeWin32.h +++ b/intern/ghost/intern/GHOST_ImeWin32.h @@ -351,4 +351,4 @@ class GHOST_ImeWin32 { bool is_first, is_enable; }; -#endif // WITH_INPUT_IME +#endif /* WITH_INPUT_IME */ diff --git a/intern/ghost/intern/GHOST_ModifierKeys.cpp b/intern/ghost/intern/GHOST_ModifierKeys.cpp index d31dc8f0770..5ecbae77f46 100644 --- a/intern/ghost/intern/GHOST_ModifierKeys.cpp +++ b/intern/ghost/intern/GHOST_ModifierKeys.cpp @@ -10,6 +10,7 @@ */ #include "GHOST_ModifierKeys.h" +#include "GHOST_Debug.h" GHOST_ModifierKeys::GHOST_ModifierKeys() { @@ -42,11 +43,15 @@ GHOST_TKey GHOST_ModifierKeys::getModifierKeyCode(GHOST_TModifierKey mask) case GHOST_kModifierKeyRightControl: key = GHOST_kKeyRightControl; break; - case GHOST_kModifierKeyOS: - key = GHOST_kKeyOS; + case GHOST_kModifierKeyLeftOS: + key = GHOST_kKeyLeftOS; + break; + case GHOST_kModifierKeyRightOS: + key = GHOST_kKeyRightOS; break; default: - // Should not happen + /* Should not happen. */ + GHOST_ASSERT(0, "Invalid key!"); key = GHOST_kKeyUnknown; break; } @@ -68,9 +73,12 @@ bool GHOST_ModifierKeys::get(GHOST_TModifierKey mask) const return m_LeftControl; case GHOST_kModifierKeyRightControl: return m_RightControl; - case GHOST_kModifierKeyOS: - return m_OS; + case GHOST_kModifierKeyLeftOS: + return m_LeftOS; + case GHOST_kModifierKeyRightOS: + return m_RightOS; default: + GHOST_ASSERT(0, "Invalid key!"); return false; } } @@ -96,10 +104,14 @@ void GHOST_ModifierKeys::set(GHOST_TModifierKey mask, bool down) case GHOST_kModifierKeyRightControl: m_RightControl = down; break; - case GHOST_kModifierKeyOS: - m_OS = down; + case GHOST_kModifierKeyLeftOS: + m_LeftOS = down; + break; + case GHOST_kModifierKeyRightOS: + m_RightOS = down; break; default: + GHOST_ASSERT(0, "Invalid key!"); break; } } @@ -112,7 +124,8 @@ void GHOST_ModifierKeys::clear() m_RightAlt = false; m_LeftControl = false; m_RightControl = false; - m_OS = false; + m_LeftOS = false; + m_RightOS = false; } bool GHOST_ModifierKeys::equals(const GHOST_ModifierKeys &keys) const @@ -120,5 +133,5 @@ bool GHOST_ModifierKeys::equals(const GHOST_ModifierKeys &keys) const return (m_LeftShift == keys.m_LeftShift) && (m_RightShift == keys.m_RightShift) && (m_LeftAlt == keys.m_LeftAlt) && (m_RightAlt == keys.m_RightAlt) && (m_LeftControl == keys.m_LeftControl) && (m_RightControl == keys.m_RightControl) && - (m_OS == keys.m_OS); + (m_LeftOS == keys.m_LeftOS) && (m_RightOS == keys.m_RightOS); } diff --git a/intern/ghost/intern/GHOST_ModifierKeys.h b/intern/ghost/intern/GHOST_ModifierKeys.h index ce1bf3df2ae..e2afc879411 100644 --- a/intern/ghost/intern/GHOST_ModifierKeys.h +++ b/intern/ghost/intern/GHOST_ModifierKeys.h @@ -55,18 +55,19 @@ struct GHOST_ModifierKeys { */ bool equals(const GHOST_ModifierKeys &keys) const; - /** Bitfield that stores the appropriate key state. */ + /** Bit-field that stores the appropriate key state. */ uint8_t m_LeftShift : 1; - /** Bitfield that stores the appropriate key state. */ + /** Bit-field that stores the appropriate key state. */ uint8_t m_RightShift : 1; - /** Bitfield that stores the appropriate key state. */ + /** Bit-field that stores the appropriate key state. */ uint8_t m_LeftAlt : 1; - /** Bitfield that stores the appropriate key state. */ + /** Bit-field that stores the appropriate key state. */ uint8_t m_RightAlt : 1; - /** Bitfield that stores the appropriate key state. */ + /** Bit-field that stores the appropriate key state. */ uint8_t m_LeftControl : 1; - /** Bitfield that stores the appropriate key state. */ + /** Bit-field that stores the appropriate key state. */ uint8_t m_RightControl : 1; - /** Bitfield that stores the appropriate key state. */ - uint8_t m_OS : 1; + /** Bit-field that stores the appropriate key state. */ + uint8_t m_LeftOS : 1; + uint8_t m_RightOS : 1; }; diff --git a/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp b/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp index 36202278ea1..43f31cb2368 100644 --- a/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp +++ b/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp @@ -7,10 +7,10 @@ GHOST_NDOFManagerWin32::GHOST_NDOFManagerWin32(GHOST_System &sys) : GHOST_NDOFMa /* pass */ } -// whether multi-axis functionality is available (via the OS or driver) -// does not imply that a device is plugged in or being used +/* Whether multi-axis functionality is available (via the OS or driver) + * does not imply that a device is plugged in or being used. */ bool GHOST_NDOFManagerWin32::available() { - // always available since RawInput is built into Windows + /* Always available since RawInput is built into Windows. */ return true; } diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp index cf04287af9f..714565568dc 100644 --- a/intern/ghost/intern/GHOST_System.cpp +++ b/intern/ghost/intern/GHOST_System.cpp @@ -8,7 +8,7 @@ #include "GHOST_System.h" #include <chrono> -#include <cstdio> /* just for printf */ +#include <cstdio> /* Just for #printf. */ #include "GHOST_DisplayManager.h" #include "GHOST_EventManager.h" @@ -110,8 +110,7 @@ bool GHOST_System::validWindow(GHOST_IWindow *window) GHOST_TSuccess GHOST_System::beginFullScreen(const GHOST_DisplaySetting &setting, GHOST_IWindow **window, - const bool stereoVisual, - const bool alphaBackground) + const bool stereoVisual) { GHOST_TSuccess success = GHOST_kFailure; GHOST_ASSERT(m_windowManager, "GHOST_System::beginFullScreen(): invalid window manager"); @@ -125,8 +124,7 @@ GHOST_TSuccess GHOST_System::beginFullScreen(const GHOST_DisplaySetting &setting setting); if (success == GHOST_kSuccess) { // GHOST_PRINT("GHOST_System::beginFullScreen(): creating full-screen window\n"); - success = createFullScreenWindow( - (GHOST_Window **)window, setting, stereoVisual, alphaBackground); + success = createFullScreenWindow((GHOST_Window **)window, setting, stereoVisual); if (success == GHOST_kSuccess) { m_windowManager->beginFullScreen(*window, stereoVisual); } @@ -373,18 +371,13 @@ GHOST_TSuccess GHOST_System::exit() GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window, const GHOST_DisplaySetting &settings, - const bool stereoVisual, - const bool alphaBackground) + const bool stereoVisual) { GHOST_GLSettings glSettings = {0}; if (stereoVisual) { glSettings.flags |= GHOST_glStereoVisual; } - if (alphaBackground) { - glSettings.flags |= GHOST_glAlphaBackground; - } - /* NOTE: don't use #getCurrentDisplaySetting() because on X11 we may * be zoomed in and the desktop may be bigger than the viewport. */ GHOST_ASSERT(m_displayManager, diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index d5558be3444..83f8cb254ce 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -120,11 +120,10 @@ class GHOST_System : public GHOST_ISystem { */ GHOST_TSuccess beginFullScreen(const GHOST_DisplaySetting &setting, GHOST_IWindow **window, - const bool stereoVisual, - const bool alphaBackground); + const bool stereoVisual); /** - * Updates the resolution while in fullscreen mode. + * Updates the resolution while in full-screen mode. * \param setting: The new setting of the display. * \param window: Window displayed in full screen. * @@ -370,14 +369,13 @@ class GHOST_System : public GHOST_ISystem { virtual GHOST_TSuccess exit(); /** - * Creates a fullscreen window. + * Creates a full-screen window. * \param window: The window created. * \return Indication of success. */ GHOST_TSuccess createFullScreenWindow(GHOST_Window **window, const GHOST_DisplaySetting &settings, - const bool stereoVisual, - const bool alphaBackground = 0); + const bool stereoVisual); /** The display manager (platform dependent). */ GHOST_DisplayManager *m_displayManager; @@ -401,7 +399,7 @@ class GHOST_System : public GHOST_ISystem { GHOST_EventPrinter *m_eventPrinter; #endif // WITH_GHOST_DEBUG - /** Settings of the display before the display went fullscreen. */ + /** Settings of the display before the display went full-screen. */ GHOST_DisplaySetting m_preFullScreenSetting; /** Which tablet API to use. */ diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h index 8b6dfb4efed..dbb41c7fddf 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.h +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -79,7 +79,7 @@ class GHOST_SystemCocoa : public GHOST_System { * \param state: The state of the window when opened. * \param type: The type of drawing context installed in this window. * \param glSettings: Misc OpenGL settings. - * \param exclusive: Use to show the window ontop and ignore others (used fullscreen). + * \param exclusive: Use to show the window on top and ignore others (used full-screen). * \param parentWindow: Parent (embedder) window. * \return The new window (or 0 if creation failed). */ @@ -236,9 +236,9 @@ class GHOST_SystemCocoa : public GHOST_System { /** * \see GHOST_ISystem */ - int setConsoleWindowState(GHOST_TConsoleWindowState action) + bool setConsoleWindowState(GHOST_TConsoleWindowState action) { - return 0; + return false; } /** diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index c247ef3daa0..fe5992343ab 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -856,7 +856,7 @@ GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(int32_t x, int32_t y) GHOST_TSuccess GHOST_SystemCocoa::getModifierKeys(GHOST_ModifierKeys &keys) const { - keys.set(GHOST_kModifierKeyOS, (m_modifierMask & NSEventModifierFlagCommand) ? true : false); + keys.set(GHOST_kModifierKeyLeftOS, (m_modifierMask & NSEventModifierFlagCommand) ? true : false); keys.set(GHOST_kModifierKeyLeftAlt, (m_modifierMask & NSEventModifierFlagOption) ? true : false); keys.set(GHOST_kModifierKeyLeftShift, (m_modifierMask & NSEventModifierFlagShift) ? true : false); @@ -1020,7 +1020,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent() (modifiers & NSEventModifierFlagCommand) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp, window, - GHOST_kKeyOS, + GHOST_kKeyLeftOS, false)); } @@ -1123,6 +1123,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType case GHOST_kEventDraggingEntered: case GHOST_kEventDraggingUpdated: case GHOST_kEventDraggingExited: + window->clientToScreenIntern(mouseX, mouseY, mouseX, mouseY); pushEvent(new GHOST_EventDragnDrop( getMilliSeconds(), eventType, draggedObjectType, window, mouseX, mouseY, NULL)); break; @@ -1331,6 +1332,8 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType return GHOST_kFailure; break; } + + window->clientToScreenIntern(mouseX, mouseY, mouseX, mouseY); pushEvent(new GHOST_EventDragnDrop( getMilliSeconds(), eventType, draggedObjectType, window, mouseX, mouseY, eventData)); @@ -1898,7 +1901,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr) [event timestamp] * 1000, (modifiers & NSEventModifierFlagCommand) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp, window, - GHOST_kKeyOS, + GHOST_kKeyLeftOS, false)); } diff --git a/intern/ghost/intern/GHOST_SystemHeadless.h b/intern/ghost/intern/GHOST_SystemHeadless.h new file mode 100644 index 00000000000..b02a82fc9eb --- /dev/null +++ b/intern/ghost/intern/GHOST_SystemHeadless.h @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup GHOST + * Declaration of GHOST_SystemHeadless class. + */ + +#pragma once + +#include "../GHOST_Types.h" +#include "GHOST_DisplayManagerNULL.h" +#include "GHOST_System.h" +#include "GHOST_WindowNULL.h" + +#ifdef __linux__ +# include "GHOST_ContextEGL.h" +#endif +#include "GHOST_ContextNone.h" + +class GHOST_WindowNULL; + +class GHOST_SystemHeadless : public GHOST_System { + public: + GHOST_SystemHeadless() : GHOST_System() + { /* nop */ + } + ~GHOST_SystemHeadless() override = default; + + bool processEvents(bool /*waitForEvent*/) override + { + return false; + } + bool setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) override + { + return 0; + } + GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys & /*keys*/) const override + { + return GHOST_kSuccess; + } + GHOST_TSuccess getButtons(GHOST_Buttons & /*buttons*/) const override + { + return GHOST_kSuccess; + } + char *getClipboard(bool /*selection*/) const override + { + return nullptr; + } + void putClipboard(const char * /*buffer*/, bool /*selection*/) const override + { /* nop */ + } + uint64_t getMilliSeconds() const override + { + return 0; + } + uint8_t getNumDisplays() const override + { + return uint8_t(1); + } + GHOST_TSuccess getCursorPosition(int32_t & /*x*/, int32_t & /*y*/) const override + { + return GHOST_kFailure; + } + GHOST_TSuccess setCursorPosition(int32_t /*x*/, int32_t /*y*/) override + { + return GHOST_kFailure; + } + void getMainDisplayDimensions(uint32_t & /*width*/, uint32_t & /*height*/) const override + { /* nop */ + } + void getAllDisplayDimensions(uint32_t & /*width*/, uint32_t & /*height*/) const override + { /* nop */ + } + GHOST_IContext *createOffscreenContext(GHOST_GLSettings /*glSettings*/) override + { +#ifdef __linux__ + GHOST_Context *context; + for (int minor = 6; minor >= 0; --minor) { + context = new GHOST_ContextEGL((GHOST_System *)this, + false, + EGLNativeWindowType(0), + EGLNativeDisplayType(EGL_DEFAULT_DISPLAY), + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + 4, + minor, + GHOST_OPENGL_EGL_CONTEXT_FLAGS, + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_API); + + if (context->initializeDrawingContext()) { + return context; + } + delete context; + context = nullptr; + } + + context = new GHOST_ContextEGL((GHOST_System *)this, + false, + EGLNativeWindowType(0), + EGLNativeDisplayType(EGL_DEFAULT_DISPLAY), + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + 3, + 3, + GHOST_OPENGL_EGL_CONTEXT_FLAGS, + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_API); + + if (context->initializeDrawingContext() != GHOST_kSuccess) { + delete context; + context = nullptr; + } + return context; +#else + return nullptr; +#endif + } + GHOST_TSuccess disposeContext(GHOST_IContext *context) override + { + delete context; + + return GHOST_kSuccess; + } + + GHOST_TSuccess init() override + { + GHOST_TSuccess success = GHOST_System::init(); + + if (success) { + m_displayManager = new GHOST_DisplayManagerNULL(); + + if (m_displayManager) { + return GHOST_kSuccess; + } + } + + return GHOST_kFailure; + } + + GHOST_IWindow *createWindow(const char *title, + int32_t left, + int32_t top, + uint32_t width, + uint32_t height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + GHOST_GLSettings glSettings, + const bool /*exclusive*/, + const bool /*is_dialog*/, + const GHOST_IWindow *parentWindow) override + { + return new GHOST_WindowNULL(title, + left, + top, + width, + height, + state, + parentWindow, + type, + ((glSettings.flags & GHOST_glStereoVisual) != 0)); + } + + GHOST_IWindow *getWindowUnderCursor(int32_t /*x*/, int32_t /*y*/) override + { + return nullptr; + } +}; diff --git a/intern/ghost/intern/GHOST_SystemNULL.h b/intern/ghost/intern/GHOST_SystemNULL.h deleted file mode 100644 index 644eb1ba0a5..00000000000 --- a/intern/ghost/intern/GHOST_SystemNULL.h +++ /dev/null @@ -1,122 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup GHOST - * Declaration of GHOST_SystemNULL class. - */ - -#pragma once - -#include "../GHOST_Types.h" -#include "GHOST_DisplayManagerNULL.h" -#include "GHOST_System.h" -#include "GHOST_WindowNULL.h" - -class GHOST_WindowNULL; - -class GHOST_SystemNULL : public GHOST_System { - public: - GHOST_SystemNULL() : GHOST_System() - { /* nop */ - } - ~GHOST_SystemNULL() - { /* nop */ - } - bool processEvents(bool waitForEvent) - { - return false; - } - int setConsoleWindowState(GHOST_TConsoleWindowState action) - { - return 0; - } - GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const - { - return GHOST_kSuccess; - } - GHOST_TSuccess getButtons(GHOST_Buttons &buttons) const - { - return GHOST_kSuccess; - } - char *getClipboard(bool selection) const - { - return nullptr; - } - void putClipboard(const char *buffer, bool selection) const - { /* nop */ - } - uint64_t getMilliSeconds() const - { - return 0; - } - uint8_t getNumDisplays() const - { - return uint8_t(1); - } - GHOST_TSuccess getCursorPosition(int32_t &x, int32_t &y) const - { - return GHOST_kFailure; - } - GHOST_TSuccess setCursorPosition(int32_t x, int32_t y) - { - return GHOST_kFailure; - } - void getMainDisplayDimensions(uint32_t &width, uint32_t &height) const - { /* nop */ - } - void getAllDisplayDimensions(uint32_t &width, uint32_t &height) const - { /* nop */ - } - GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings) - { - return nullptr; - } - GHOST_TSuccess disposeContext(GHOST_IContext *context) - { - return GHOST_kFailure; - } - - GHOST_TSuccess init() - { - GHOST_TSuccess success = GHOST_System::init(); - - if (success) { - m_displayManager = new GHOST_DisplayManagerNULL(this); - - if (m_displayManager) { - return GHOST_kSuccess; - } - } - - return GHOST_kFailure; - } - - GHOST_IWindow *createWindow(const char *title, - int32_t left, - int32_t top, - uint32_t width, - uint32_t height, - GHOST_TWindowState state, - GHOST_TDrawingContextType type, - GHOST_GLSettings glSettings, - const bool exclusive, - const bool is_dialog, - const GHOST_IWindow *parentWindow) - { - return new GHOST_WindowNULL(this, - title, - left, - top, - width, - height, - state, - parentWindow, - type, - ((glSettings.flags & GHOST_glStereoVisual) != 0)); - } - - GHOST_IWindow *getWindowUnderCursor(int32_t x, int32_t y) - { - return nullptr; - } -}; diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp index 41babc5d312..7e1d3d868c6 100644 --- a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp +++ b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp @@ -5,22 +5,17 @@ * \ingroup GHOST */ -#include <cstdio> #include <sstream> #include "GHOST_SystemPathsUnix.h" #include "GHOST_Debug.h" -// For timing - +/* For timing. */ #include <sys/time.h> #include <unistd.h> -#include <cstdio> /* for fprintf only */ -#include <cstdlib> /* for exit */ - -#include <pwd.h> /* for get home without use getenv() */ +#include <pwd.h> /* For get home without use `getenv()`. */ #include <string> using std::string; diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp index d912b57f049..76770e735fa 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.cpp +++ b/intern/ghost/intern/GHOST_SystemSDL.cpp @@ -5,6 +5,7 @@ */ #include <cassert> +#include <stdexcept> #include "GHOST_ContextSDL.h" #include "GHOST_SystemSDL.h" @@ -20,7 +21,7 @@ GHOST_SystemSDL::GHOST_SystemSDL() : GHOST_System() { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) { - printf("Error initializing SDL: %s\n", SDL_GetError()); + throw std::runtime_error("Error initializing SDL: " + std::string(SDL_GetError())); } SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); @@ -160,7 +161,8 @@ GHOST_TSuccess GHOST_SystemSDL::getModifierKeys(GHOST_ModifierKeys &keys) const keys.set(GHOST_kModifierKeyRightControl, (mod & KMOD_RCTRL) != 0); keys.set(GHOST_kModifierKeyLeftAlt, (mod & KMOD_LALT) != 0); keys.set(GHOST_kModifierKeyRightAlt, (mod & KMOD_RALT) != 0); - keys.set(GHOST_kModifierKeyOS, (mod & (KMOD_LGUI | KMOD_RGUI)) != 0); + keys.set(GHOST_kModifierKeyLeftOS, (mod & KMOD_LGUI) != 0); + keys.set(GHOST_kModifierKeyRightOS, (mod & KMOD_RGUI) != 0); return GHOST_kSuccess; } @@ -218,8 +220,8 @@ static GHOST_TKey convertSDLKey(SDL_Scancode key) GXMAP(type, SDL_SCANCODE_RCTRL, GHOST_kKeyRightControl); GXMAP(type, SDL_SCANCODE_LALT, GHOST_kKeyLeftAlt); GXMAP(type, SDL_SCANCODE_RALT, GHOST_kKeyRightAlt); - GXMAP(type, SDL_SCANCODE_LGUI, GHOST_kKeyOS); - GXMAP(type, SDL_SCANCODE_RGUI, GHOST_kKeyOS); + GXMAP(type, SDL_SCANCODE_LGUI, GHOST_kKeyLeftOS); + GXMAP(type, SDL_SCANCODE_RGUI, GHOST_kKeyRightOS); GXMAP(type, SDL_SCANCODE_APPLICATION, GHOST_kKeyApp); GXMAP(type, SDL_SCANCODE_INSERT, GHOST_kKeyInsert); diff --git a/intern/ghost/intern/GHOST_SystemSDL.h b/intern/ghost/intern/GHOST_SystemSDL.h index aefea5eda34..bee277ba674 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.h +++ b/intern/ghost/intern/GHOST_SystemSDL.h @@ -33,9 +33,9 @@ class GHOST_SystemSDL : public GHOST_System { bool processEvents(bool waitForEvent); - int setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) + bool setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) { - return 0; + return false; } GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const; diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index 18d91d43057..dd82d435397 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -19,12 +19,14 @@ #include "GHOST_ContextEGL.h" +#ifdef WITH_INPUT_NDOF +# include "GHOST_NDOFManagerUnix.h" +#endif + #ifdef WITH_GHOST_WAYLAND_DYNLOAD # include <wayland_dynload_API.h> /* For `ghost_wl_dynload_libraries`. */ #endif -#include <EGL/egl.h> - #ifdef WITH_GHOST_WAYLAND_DYNLOAD # include <wayland_dynload_egl.h> #endif @@ -62,7 +64,7 @@ /* Logging, use `ghost.wl.*` prefix. */ #include "CLG_log.h" -static void keyboard_handle_key_repeat_cancel(struct input_t *input); +static void keyboard_handle_key_repeat_cancel(struct GWL_Seat *seat); static void output_handle_done(void *data, struct wl_output *wl_output); @@ -84,10 +86,6 @@ static void output_handle_done(void *data, struct wl_output *wl_output); static bool use_gnome_confine_hack = false; #endif -#define XKB_STATE_MODS_ALL \ - (enum xkb_state_component)(XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED | \ - XKB_STATE_MODS_LOCKED | XKB_STATE_MODS_EFFECTIVE) - /* -------------------------------------------------------------------- */ /** \name Inline Event Codes * @@ -125,6 +123,69 @@ static bool use_gnome_confine_hack = false; /** \} */ /* -------------------------------------------------------------------- */ +/** \name Modifier Table + * + * Convenient access to modifier key values, allow looping over modifier keys. + * \{ */ + +enum { + MOD_INDEX_SHIFT = 0, + MOD_INDEX_ALT = 1, + MOD_INDEX_CTRL = 2, + MOD_INDEX_OS = 3, +}; +#define MOD_INDEX_NUM (MOD_INDEX_OS + 1) + +struct GWL_ModifierInfo { + /** Only for printing messages. */ + const char *display_name; + const char *xkb_id; + GHOST_TKey key_l, key_r; + GHOST_TModifierKey mod_l, mod_r; +}; + +static const GWL_ModifierInfo g_modifier_info_table[MOD_INDEX_NUM] = { + [MOD_INDEX_SHIFT] = + { + .display_name = "Shift", + .xkb_id = XKB_MOD_NAME_SHIFT, + .key_l = GHOST_kKeyLeftShift, + .key_r = GHOST_kKeyRightShift, + .mod_l = GHOST_kModifierKeyLeftShift, + .mod_r = GHOST_kModifierKeyRightShift, + }, + [MOD_INDEX_ALT] = + { + .display_name = "Alt", + .xkb_id = XKB_MOD_NAME_ALT, + .key_l = GHOST_kKeyLeftAlt, + .key_r = GHOST_kKeyRightAlt, + .mod_l = GHOST_kModifierKeyLeftAlt, + .mod_r = GHOST_kModifierKeyRightAlt, + }, + [MOD_INDEX_CTRL] = + { + .display_name = "Control", + .xkb_id = XKB_MOD_NAME_CTRL, + .key_l = GHOST_kKeyLeftControl, + .key_r = GHOST_kKeyRightControl, + .mod_l = GHOST_kModifierKeyLeftControl, + .mod_r = GHOST_kModifierKeyRightControl, + }, + [MOD_INDEX_OS] = + { + .display_name = "OS", + .xkb_id = XKB_MOD_NAME_LOGO, + .key_l = GHOST_kKeyLeftOS, + .key_r = GHOST_kKeyRightOS, + .mod_l = GHOST_kModifierKeyLeftOS, + .mod_r = GHOST_kModifierKeyRightOS, + }, +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Private Types & Defines * \{ */ @@ -134,7 +195,7 @@ static bool use_gnome_confine_hack = false; */ #define EVDEV_OFFSET 8 -struct cursor_t { +struct GWL_Cursor { bool visible = false; /** * When false, hide the hardware cursor, while the cursor is still considered to be `visible`, @@ -161,28 +222,28 @@ struct cursor_t { * WAYLAND exposes tools via #zwp_tablet_tool_v2. * Since are no API's to access properties of the tool, store the values here. */ -struct tablet_tool_input_t { - struct input_t *input = nullptr; - struct wl_surface *cursor_surface = nullptr; - /** Used to delay clearing tablet focused surface until the frame is handled. */ +struct GWL_TabletTool { + struct GWL_Seat *seat = nullptr; + struct wl_surface *wl_surface_cursor = nullptr; + /** Used to delay clearing tablet focused wl_surface until the frame is handled. */ bool proximity = false; GHOST_TabletData data = GHOST_TABLET_DATA_NONE; }; -struct data_offer_t { +struct GWL_DataOffer { std::unordered_set<std::string> types; uint32_t source_actions = 0; uint32_t dnd_action = 0; struct wl_data_offer *id = nullptr; std::atomic<bool> in_use = false; struct { - /** Compatible with #input_t.xy coordinates. */ + /** Compatible with #GWL_Seat.xy coordinates. */ wl_fixed_t xy[2] = {0, 0}; } dnd; }; -struct data_source_t { +struct GWL_DataSource { struct wl_data_source *data_source = nullptr; char *buffer_out = nullptr; }; @@ -192,11 +253,11 @@ struct data_source_t { * * \note it's important not to store the target window here * as it can be closed while the key is repeating, - * instead use the focused keyboard from #intput_t which is cleared when windows are closed. + * instead use the focused keyboard from #GWL_Seat which is cleared when windows are closed. * Therefor keyboard events must always check the window has not been cleared. */ -struct key_repeat_payload_t { - struct input_t *input = nullptr; +struct GWL_KeyRepeatPlayload { + struct GWL_Seat *seat = nullptr; xkb_keycode_t key_code; @@ -210,7 +271,7 @@ struct key_repeat_payload_t { }; /** Internal variables used to track grab-state. */ -struct input_grab_state_t { +struct GWL_SeatStateGrab { bool use_lock = false; bool use_confine = false; }; @@ -218,7 +279,7 @@ struct input_grab_state_t { /** * State of the pointing device (tablet or mouse). */ -struct input_state_pointer_t { +struct GWL_SeatStatePointer { /** * High precision coordinates. * @@ -227,15 +288,15 @@ struct input_state_pointer_t { * \code{.cc} * const wl_fixed_t scale = win->scale(); * const int event_xy[2] = { - * wl_fixed_to_int(scale * input_state->xy[0]), - * wl_fixed_to_int(scale * input_state->xy[1]), + * wl_fixed_to_int(scale * seat_state_pointer->xy[0]), + * wl_fixed_to_int(scale * seat_state_pointer->xy[1]), * }; * \endcode */ wl_fixed_t xy[2] = {0, 0}; /** Outputs on which the cursor is visible. */ - std::unordered_set<const output_t *> outputs; + std::unordered_set<const GWL_Output *> outputs; int theme_scale = 1; @@ -243,7 +304,7 @@ struct input_state_pointer_t { uint32_t serial = 0; /** - * The surface last used with this pointing device + * The wl_surface last used with this pointing device * (events with this pointing device will be sent here). */ struct wl_surface *wl_surface = nullptr; @@ -252,20 +313,29 @@ struct input_state_pointer_t { }; /** - * State of the keyboard. + * State of the keyboard (in #GWL_Seat). */ -struct input_state_keyboard_t { +struct GWL_SeatStateKeyboard { /** The serial of the last used pointer or tablet. */ uint32_t serial = 0; /** - * The surface last used with this pointing device + * The wl_surface last used with this pointing device * (events with this pointing device will be sent here). */ struct wl_surface *wl_surface = nullptr; }; -struct input_t { +/** + * Store held keys (only modifiers), could store other keys in the future. + * + * Needed as #GWL_Seat.xkb_state doesn't store which modifier keys are held. + */ +struct WGL_KeyboardDepressedState { + int16_t mods[GHOST_KEY_MODIFIER_NUM] = {0}; +}; + +struct GWL_Seat { GHOST_SystemWayland *system = nullptr; std::string name; @@ -280,12 +350,12 @@ struct input_t { /** Use to check if the last cursor input was tablet or pointer. */ uint32_t cursor_source_serial = 0; - input_state_pointer_t pointer; + GWL_SeatStatePointer pointer; /** Mostly this can be interchanged with `pointer` however it can't be locked/confined. */ - input_state_pointer_t tablet; + GWL_SeatStatePointer tablet; - input_state_keyboard_t keyboard; + GWL_SeatStateKeyboard keyboard; #ifdef USE_GNOME_CONFINE_HACK bool use_pointer_software_confine = false; @@ -293,7 +363,7 @@ struct input_t { /** The cursor location (in pixel-space) when hidden grab started (#GHOST_kGrabHide). */ wl_fixed_t grab_lock_xy[2] = {0, 0}; - struct cursor_t cursor; + struct GWL_Cursor cursor; struct zwp_relative_pointer_v1 *relative_pointer = nullptr; struct zwp_locked_pointer_v1 *locked_pointer = nullptr; @@ -312,19 +382,15 @@ struct input_t { */ struct xkb_state *xkb_state_empty_with_numlock = nullptr; + /** Keys held matching `xkb_state`. */ + struct WGL_KeyboardDepressedState key_depressed; + /** * Cache result of `xkb_keymap_mod_get_index` * so every time a modifier is accessed a string lookup isn't required. * Be sure to check for #XKB_MOD_INVALID before using. */ - struct { - xkb_mod_index_t shift; /* #XKB_MOD_NAME_SHIFT */ - xkb_mod_index_t caps; /* #XKB_MOD_NAME_CAPS */ - xkb_mod_index_t ctrl; /* #XKB_MOD_NAME_CTRL */ - xkb_mod_index_t alt; /* #XKB_MOD_NAME_ALT */ - xkb_mod_index_t num; /* #XKB_MOD_NAME_NUM */ - xkb_mod_index_t logo; /* #XKB_MOD_NAME_LOGO */ - } xkb_keymap_mod_index; + xkb_mod_index_t xkb_keymap_mod_index[MOD_INDEX_NUM]; struct { /** Key repetition in character per second. */ @@ -335,25 +401,25 @@ struct input_t { GHOST_ITimerTask *timer = nullptr; } key_repeat; - struct wl_surface *focus_dnd = nullptr; + struct wl_surface *wl_surface_focus_dnd = nullptr; struct wl_data_device *data_device = nullptr; /** Drag & Drop. */ - struct data_offer_t *data_offer_dnd = nullptr; + struct GWL_DataOffer *data_offer_dnd = nullptr; std::mutex data_offer_dnd_mutex; /** Copy & Paste. */ - struct data_offer_t *data_offer_copy_paste = nullptr; + struct GWL_DataOffer *data_offer_copy_paste = nullptr; std::mutex data_offer_copy_paste_mutex; - struct data_source_t *data_source = nullptr; + struct GWL_DataSource *data_source = nullptr; std::mutex data_source_mutex; /** Last device that was active. */ uint32_t data_source_serial = 0; }; -struct display_t { +struct GWL_Display { GHOST_SystemWayland *system = nullptr; struct wl_display *display = nullptr; @@ -368,8 +434,8 @@ struct display_t { struct zxdg_output_manager_v1 *xdg_output_manager = nullptr; struct wl_shm *shm = nullptr; - std::vector<output_t *> outputs; - std::vector<input_t *> inputs; + std::vector<GWL_Output *> outputs; + std::vector<GWL_Seat *> seats; struct wl_data_device_manager *data_device_manager = nullptr; struct zwp_tablet_manager_v2 *tablet_manager = nullptr; @@ -407,31 +473,31 @@ static void ghost_wayland_log_handler(const char *msg, va_list arg) } } -static input_state_pointer_t *input_state_pointer_active(input_t *input) +static GWL_SeatStatePointer *seat_state_pointer_active(GWL_Seat *seat) { - if (input->pointer.serial == input->cursor_source_serial) { - return &input->pointer; + if (seat->pointer.serial == seat->cursor_source_serial) { + return &seat->pointer; } - if (input->tablet.serial == input->cursor_source_serial) { - return &input->tablet; + if (seat->tablet.serial == seat->cursor_source_serial) { + return &seat->tablet; } return nullptr; } -static input_state_pointer_t *input_state_pointer_from_cursor_surface(input_t *input, - const wl_surface *wl_surface) +static GWL_SeatStatePointer *seat_state_pointer_from_cursor_surface(GWL_Seat *seat, + const wl_surface *wl_surface) { if (ghost_wl_surface_own_cursor_pointer(wl_surface)) { - return &input->pointer; + return &seat->pointer; } if (ghost_wl_surface_own_cursor_tablet(wl_surface)) { - return &input->tablet; + return &seat->tablet; } GHOST_ASSERT(0, "Surface found without pointer/tablet tag"); return nullptr; } -static void display_destroy(display_t *d) +static void display_destroy(GWL_Display *d) { if (d->data_device_manager) { wl_data_device_manager_destroy(d->data_device_manager); @@ -441,77 +507,77 @@ static void display_destroy(display_t *d) zwp_tablet_manager_v2_destroy(d->tablet_manager); } - for (output_t *output : d->outputs) { + for (GWL_Output *output : d->outputs) { wl_output_destroy(output->wl_output); delete output; } - for (input_t *input : d->inputs) { + for (GWL_Seat *seat : d->seats) { /* First handle members that require locking. * While highly unlikely, it's possible they are being used while this function runs. */ { - std::lock_guard lock{input->data_source_mutex}; - if (input->data_source) { - free(input->data_source->buffer_out); - if (input->data_source->data_source) { - wl_data_source_destroy(input->data_source->data_source); + std::lock_guard lock{seat->data_source_mutex}; + if (seat->data_source) { + free(seat->data_source->buffer_out); + if (seat->data_source->data_source) { + wl_data_source_destroy(seat->data_source->data_source); } - delete input->data_source; + delete seat->data_source; } } { - std::lock_guard lock{input->data_offer_dnd_mutex}; - if (input->data_offer_dnd) { - wl_data_offer_destroy(input->data_offer_dnd->id); - delete input->data_offer_dnd; + std::lock_guard lock{seat->data_offer_dnd_mutex}; + if (seat->data_offer_dnd) { + wl_data_offer_destroy(seat->data_offer_dnd->id); + delete seat->data_offer_dnd; } } { - std::lock_guard lock{input->data_offer_copy_paste_mutex}; - if (input->data_offer_copy_paste) { - wl_data_offer_destroy(input->data_offer_copy_paste->id); - delete input->data_offer_copy_paste; + std::lock_guard lock{seat->data_offer_copy_paste_mutex}; + if (seat->data_offer_copy_paste) { + wl_data_offer_destroy(seat->data_offer_copy_paste->id); + delete seat->data_offer_copy_paste; } } - if (input->data_device) { - wl_data_device_release(input->data_device); + if (seat->data_device) { + wl_data_device_release(seat->data_device); } - if (input->cursor.custom_data) { - munmap(input->cursor.custom_data, input->cursor.custom_data_size); + if (seat->cursor.custom_data) { + munmap(seat->cursor.custom_data, seat->cursor.custom_data_size); } - if (input->wl_pointer) { - if (input->cursor.wl_surface) { - wl_surface_destroy(input->cursor.wl_surface); + if (seat->wl_pointer) { + if (seat->cursor.wl_surface) { + wl_surface_destroy(seat->cursor.wl_surface); } - if (input->cursor.wl_theme) { - wl_cursor_theme_destroy(input->cursor.wl_theme); + if (seat->cursor.wl_theme) { + wl_cursor_theme_destroy(seat->cursor.wl_theme); } - if (input->wl_pointer) { - wl_pointer_destroy(input->wl_pointer); + if (seat->wl_pointer) { + wl_pointer_destroy(seat->wl_pointer); } } - if (input->wl_keyboard) { - if (input->key_repeat.timer) { - keyboard_handle_key_repeat_cancel(input); + if (seat->wl_keyboard) { + if (seat->key_repeat.timer) { + keyboard_handle_key_repeat_cancel(seat); } - wl_keyboard_destroy(input->wl_keyboard); + wl_keyboard_destroy(seat->wl_keyboard); } /* Un-referencing checks for NULL case. */ - xkb_state_unref(input->xkb_state); - xkb_state_unref(input->xkb_state_empty); - xkb_state_unref(input->xkb_state_empty_with_numlock); + xkb_state_unref(seat->xkb_state); + xkb_state_unref(seat->xkb_state_empty); + xkb_state_unref(seat->xkb_state_empty_with_numlock); - xkb_context_unref(input->xkb_context); + xkb_context_unref(seat->xkb_context); - wl_seat_destroy(input->wl_seat); - delete input; + wl_seat_destroy(seat->wl_seat); + delete seat; } if (d->shm) { @@ -611,8 +677,8 @@ static GHOST_TKey xkb_map_gkey(const xkb_keysym_t sym) GXMAP(gkey, XKB_KEY_Control_R, GHOST_kKeyRightControl); GXMAP(gkey, XKB_KEY_Alt_L, GHOST_kKeyLeftAlt); GXMAP(gkey, XKB_KEY_Alt_R, GHOST_kKeyRightAlt); - GXMAP(gkey, XKB_KEY_Super_L, GHOST_kKeyOS); - GXMAP(gkey, XKB_KEY_Super_R, GHOST_kKeyOS); + GXMAP(gkey, XKB_KEY_Super_L, GHOST_kKeyLeftOS); + GXMAP(gkey, XKB_KEY_Super_R, GHOST_kKeyRightOS); GXMAP(gkey, XKB_KEY_Menu, GHOST_kKeyApp); GXMAP(gkey, XKB_KEY_Caps_Lock, GHOST_kKeyCapsLock); @@ -860,6 +926,78 @@ static wl_buffer *ghost_wl_buffer_create_for_image(struct wl_shm *shm, /** \} */ /* -------------------------------------------------------------------- */ +/** \name Private Keyboard Depressed Key Tracking + * + * Don't track physical key-codes because there may be multiple keyboards connected. + * Instead, count the number of #GHOST_kKey are pressed. + * This may seem susceptible to bugs with sticky-keys however XKB works this way internally. + * \{ */ + +static CLG_LogRef LOG_WL_KEYBOARD_DEPRESSED_STATE = {"ghost.wl.keyboard.depressed"}; +#define LOG (&LOG_WL_KEYBOARD_DEPRESSED_STATE) + +static void keyboard_depressed_state_reset(GWL_Seat *seat) +{ + for (int i = 0; i < GHOST_KEY_MODIFIER_NUM; i++) { + seat->key_depressed.mods[i] = 0; + } +} + +static void keyboard_depressed_state_key_event(GWL_Seat *seat, + const GHOST_TKey gkey, + const GHOST_TEventType etype) +{ + if (GHOST_KEY_MODIFIER_CHECK(gkey)) { + const int index = GHOST_KEY_MODIFIER_TO_INDEX(gkey); + int16_t &value = seat->key_depressed.mods[index]; + if (etype == GHOST_kEventKeyUp) { + value -= 1; + if (UNLIKELY(value < 0)) { + CLOG_WARN(LOG, "modifier (%d) has negative keys held (%d)!", index, value); + value = 0; + } + } + else { + value += 1; + } + } +} + +static void keyboard_depressed_state_push_events_from_change( + GWL_Seat *seat, const WGL_KeyboardDepressedState &key_depressed_prev) +{ + GHOST_IWindow *win = ghost_wl_surface_user_data(seat->keyboard.wl_surface); + GHOST_SystemWayland *system = seat->system; + + /* Separate key up and down into separate passes so key down events always come after key up. + * Do this so users of GHOST can use the last pressed or released modifier to check + * if the modifier is held instead of counting modifiers pressed as is done here, + * this isn't perfect but works well enough in practice. */ + for (int i = 0; i < GHOST_KEY_MODIFIER_NUM; i++) { + for (int d = seat->key_depressed.mods[i] - key_depressed_prev.mods[i]; d < 0; d++) { + const GHOST_TKey gkey = GHOST_KEY_MODIFIER_FROM_INDEX(i); + seat->system->pushEvent( + new GHOST_EventKey(system->getMilliSeconds(), GHOST_kEventKeyUp, win, gkey, false)); + + CLOG_INFO(LOG, 2, "modifier (%d) up", i); + } + } + + for (int i = 0; i < GHOST_KEY_MODIFIER_NUM; i++) { + for (int d = seat->key_depressed.mods[i] - key_depressed_prev.mods[i]; d > 0; d--) { + const GHOST_TKey gkey = GHOST_KEY_MODIFIER_FROM_INDEX(i); + seat->system->pushEvent( + new GHOST_EventKey(system->getMilliSeconds(), GHOST_kEventKeyDown, win, gkey, false)); + CLOG_INFO(LOG, 2, "modifier (%d) down", i); + } + } +} + +#undef LOG + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Listener (Relative Motion), #zwp_relative_pointer_v1_listener * * These callbacks are registered for Wayland interfaces and called when @@ -870,19 +1008,19 @@ static CLG_LogRef LOG_WL_RELATIVE_POINTER = {"ghost.wl.handle.relative_pointer"} #define LOG (&LOG_WL_RELATIVE_POINTER) /** - * The caller is responsible for setting the value of `input->xy`. + * The caller is responsible for setting the value of `seat->xy`. */ -static void relative_pointer_handle_relative_motion_impl(input_t *input, +static void relative_pointer_handle_relative_motion_impl(GWL_Seat *seat, GHOST_WindowWayland *win, const wl_fixed_t xy[2]) { const wl_fixed_t scale = win->scale(); - input->pointer.xy[0] = xy[0]; - input->pointer.xy[1] = xy[1]; + seat->pointer.xy[0] = xy[0]; + seat->pointer.xy[1] = xy[1]; #ifdef USE_GNOME_CONFINE_HACK - if (input->use_pointer_software_confine) { + if (seat->use_pointer_software_confine) { GHOST_Rect bounds; win->getClientBounds(bounds); /* Needed or the cursor is considered outside the window and doesn't restore the location. */ @@ -893,15 +1031,15 @@ static void relative_pointer_handle_relative_motion_impl(input_t *input, bounds.m_t = wl_fixed_from_int(bounds.m_t) / scale; bounds.m_r = wl_fixed_from_int(bounds.m_r) / scale; bounds.m_b = wl_fixed_from_int(bounds.m_b) / scale; - bounds.clampPoint(UNPACK2(input->pointer.xy)); + bounds.clampPoint(UNPACK2(seat->pointer.xy)); } #endif - input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(), - GHOST_kEventCursorMove, - win, - wl_fixed_to_int(scale * input->pointer.xy[0]), - wl_fixed_to_int(scale * input->pointer.xy[1]), - GHOST_TABLET_DATA_NONE)); + seat->system->pushEvent(new GHOST_EventCursor(seat->system->getMilliSeconds(), + GHOST_kEventCursorMove, + win, + wl_fixed_to_int(scale * seat->pointer.xy[0]), + wl_fixed_to_int(scale * seat->pointer.xy[1]), + GHOST_TABLET_DATA_NONE)); } static void relative_pointer_handle_relative_motion( @@ -914,16 +1052,16 @@ static void relative_pointer_handle_relative_motion( const wl_fixed_t /*dx_unaccel*/, const wl_fixed_t /*dy_unaccel*/) { - input_t *input = static_cast<input_t *>(data); - if (wl_surface *focus_surface = input->pointer.wl_surface) { + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { CLOG_INFO(LOG, 2, "relative_motion"); - GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface); + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); const wl_fixed_t scale = win->scale(); const wl_fixed_t xy_next[2] = { - input->pointer.xy[0] + (dx / scale), - input->pointer.xy[1] + (dy / scale), + seat->pointer.xy[0] + (dx / scale), + seat->pointer.xy[1] + (dy / scale), }; - relative_pointer_handle_relative_motion_impl(input, win, xy_next); + relative_pointer_handle_relative_motion_impl(seat, win, xy_next); } else { CLOG_INFO(LOG, 2, "relative_motion (skipped)"); @@ -945,26 +1083,26 @@ static const zwp_relative_pointer_v1_listener relative_pointer_listener = { static CLG_LogRef LOG_WL_DATA_SOURCE = {"ghost.wl.handle.data_source"}; #define LOG (&LOG_WL_DATA_SOURCE) -static void dnd_events(const input_t *const input, const GHOST_TEventType event) +static void dnd_events(const GWL_Seat *const seat, const GHOST_TEventType event) { - /* NOTE: `input->data_offer_dnd_mutex` must already be locked. */ - if (wl_surface *focus_surface = input->focus_dnd) { - GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface); + /* NOTE: `seat->data_offer_dnd_mutex` must already be locked. */ + if (wl_surface *wl_surface_focus = seat->wl_surface_focus_dnd) { + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); const wl_fixed_t scale = win->scale(); const int event_xy[2] = { - wl_fixed_to_int(scale * input->data_offer_dnd->dnd.xy[0]), - wl_fixed_to_int(scale * input->data_offer_dnd->dnd.xy[1]), + wl_fixed_to_int(scale * seat->data_offer_dnd->dnd.xy[0]), + wl_fixed_to_int(scale * seat->data_offer_dnd->dnd.xy[1]), }; - const uint64_t time = input->system->getMilliSeconds(); + const uint64_t time = seat->system->getMilliSeconds(); for (const std::string &type : mime_preference_order) { - input->system->pushEvent(new GHOST_EventDragnDrop( + seat->system->pushEvent(new GHOST_EventDragnDrop( time, event, mime_dnd.at(type), win, UNPACK2(event_xy), nullptr)); } } } -static std::string read_pipe(data_offer_t *data_offer, +static std::string read_pipe(GWL_DataOffer *data_offer, const std::string mime_receive, std::mutex *mutex) { @@ -1011,12 +1149,12 @@ static void data_source_handle_send(void *data, const char * /*mime_type*/, const int32_t fd) { - input_t *input = static_cast<input_t *>(data); - std::lock_guard lock{input->data_source_mutex}; + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + std::lock_guard lock{seat->data_source_mutex}; CLOG_INFO(LOG, 2, "send"); - const char *const buffer = input->data_source->buffer_out; + const char *const buffer = seat->data_source->buffer_out; if (write(fd, buffer, strlen(buffer)) < 0) { GHOST_PRINT("error writing to clipboard: " << std::strerror(errno) << std::endl); } @@ -1094,7 +1232,7 @@ static void data_offer_handle_offer(void *data, const char *mime_type) { CLOG_INFO(LOG, 2, "offer (mime_type=%s)", mime_type); - static_cast<data_offer_t *>(data)->types.insert(mime_type); + static_cast<GWL_DataOffer *>(data)->types.insert(mime_type); } static void data_offer_handle_source_actions(void *data, @@ -1102,7 +1240,7 @@ static void data_offer_handle_source_actions(void *data, const uint32_t source_actions) { CLOG_INFO(LOG, 2, "source_actions (%u)", source_actions); - static_cast<data_offer_t *>(data)->source_actions = source_actions; + static_cast<GWL_DataOffer *>(data)->source_actions = source_actions; } static void data_offer_handle_action(void *data, @@ -1110,7 +1248,7 @@ static void data_offer_handle_action(void *data, const uint32_t dnd_action) { CLOG_INFO(LOG, 2, "actions (%u)", dnd_action); - static_cast<data_offer_t *>(data)->dnd_action = dnd_action; + static_cast<GWL_DataOffer *>(data)->dnd_action = dnd_action; } static const struct wl_data_offer_listener data_offer_listener = { @@ -1136,7 +1274,7 @@ static void data_device_handle_data_offer(void * /*data*/, { CLOG_INFO(LOG, 2, "data_offer"); - data_offer_t *data_offer = new data_offer_t; + GWL_DataOffer *data_offer = new GWL_DataOffer; data_offer->id = id; wl_data_offer_add_listener(id, &data_offer_listener, data_offer); } @@ -1144,23 +1282,23 @@ static void data_device_handle_data_offer(void * /*data*/, static void data_device_handle_enter(void *data, struct wl_data_device * /*wl_data_device*/, const uint32_t serial, - struct wl_surface *surface, + struct wl_surface *wl_surface, const wl_fixed_t x, const wl_fixed_t y, struct wl_data_offer *id) { - if (!ghost_wl_surface_own(surface)) { + if (!ghost_wl_surface_own(wl_surface)) { CLOG_INFO(LOG, 2, "enter (skipped)"); return; } CLOG_INFO(LOG, 2, "enter"); - input_t *input = static_cast<input_t *>(data); - std::lock_guard lock{input->data_offer_dnd_mutex}; + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + std::lock_guard lock{seat->data_offer_dnd_mutex}; - delete input->data_offer_dnd; - input->data_offer_dnd = static_cast<data_offer_t *>(wl_data_offer_get_user_data(id)); - data_offer_t *data_offer = input->data_offer_dnd; + delete seat->data_offer_dnd; + seat->data_offer_dnd = static_cast<GWL_DataOffer *>(wl_data_offer_get_user_data(id)); + GWL_DataOffer *data_offer = seat->data_offer_dnd; data_offer->in_use.store(true); data_offer->dnd.xy[0] = x; @@ -1175,24 +1313,24 @@ static void data_device_handle_enter(void *data, wl_data_offer_accept(id, serial, type.c_str()); } - input->focus_dnd = surface; - dnd_events(input, GHOST_kEventDraggingEntered); + seat->wl_surface_focus_dnd = wl_surface; + dnd_events(seat, GHOST_kEventDraggingEntered); } static void data_device_handle_leave(void *data, struct wl_data_device * /*wl_data_device*/) { - input_t *input = static_cast<input_t *>(data); - std::lock_guard lock{input->data_offer_dnd_mutex}; + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + std::lock_guard lock{seat->data_offer_dnd_mutex}; CLOG_INFO(LOG, 2, "leave"); - dnd_events(input, GHOST_kEventDraggingExited); - input->focus_dnd = nullptr; + dnd_events(seat, GHOST_kEventDraggingExited); + seat->wl_surface_focus_dnd = nullptr; - if (input->data_offer_dnd && !input->data_offer_dnd->in_use.load()) { - wl_data_offer_destroy(input->data_offer_dnd->id); - delete input->data_offer_dnd; - input->data_offer_dnd = nullptr; + if (seat->data_offer_dnd && !seat->data_offer_dnd->in_use.load()) { + wl_data_offer_destroy(seat->data_offer_dnd->id); + delete seat->data_offer_dnd; + seat->data_offer_dnd = nullptr; } } @@ -1202,23 +1340,23 @@ static void data_device_handle_motion(void *data, const wl_fixed_t x, const wl_fixed_t y) { - input_t *input = static_cast<input_t *>(data); - std::lock_guard lock{input->data_offer_dnd_mutex}; + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + std::lock_guard lock{seat->data_offer_dnd_mutex}; CLOG_INFO(LOG, 2, "motion"); - input->data_offer_dnd->dnd.xy[0] = x; - input->data_offer_dnd->dnd.xy[1] = y; + seat->data_offer_dnd->dnd.xy[0] = x; + seat->data_offer_dnd->dnd.xy[1] = y; - dnd_events(input, GHOST_kEventDraggingUpdated); + dnd_events(seat, GHOST_kEventDraggingUpdated); } static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_data_device*/) { - input_t *input = static_cast<input_t *>(data); - std::lock_guard lock{input->data_offer_dnd_mutex}; + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + std::lock_guard lock{seat->data_offer_dnd_mutex}; - data_offer_t *data_offer = input->data_offer_dnd; + GWL_DataOffer *data_offer = seat->data_offer_dnd; const std::string mime_receive = *std::find_first_of(mime_preference_order.begin(), mime_preference_order.end(), @@ -1227,9 +1365,9 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat CLOG_INFO(LOG, 2, "drop mime_recieve=%s", mime_receive.c_str()); - auto read_uris_fn = [](input_t *const input, - data_offer_t *data_offer, - wl_surface *surface, + auto read_uris_fn = [](GWL_Seat *const seat, + GWL_DataOffer *data_offer, + wl_surface *wl_surface, const std::string mime_receive) { const wl_fixed_t xy[2] = {UNPACK2(data_offer->dnd.xy)}; @@ -1241,13 +1379,13 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat wl_data_offer_finish(data_offer->id); wl_data_offer_destroy(data_offer->id); - if (input->data_offer_dnd == data_offer) { - input->data_offer_dnd = nullptr; + if (seat->data_offer_dnd == data_offer) { + seat->data_offer_dnd = nullptr; } delete data_offer; data_offer = nullptr; - GHOST_SystemWayland *const system = input->system; + GHOST_SystemWayland *const system = seat->system; if (mime_receive == mime_text_uri) { static constexpr const char *file_proto = "file://"; @@ -1255,7 +1393,7 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat * So support both, once `\n` is found, strip the preceding `\r` if found. */ static constexpr const char *lf = "\n"; - GHOST_WindowWayland *win = ghost_wl_surface_user_data(surface); + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface); std::vector<std::string> uris; size_t pos = 0; @@ -1302,9 +1440,10 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat wl_display_roundtrip(system->display()); }; - /* Pass in `input->focus_dnd` instead of accessing it from `input` since the leave callback - * (#data_device_handle_leave) will clear the value once this function starts. */ - std::thread read_thread(read_uris_fn, input, data_offer, input->focus_dnd, mime_receive); + /* Pass in `seat->wl_surface_focus_dnd` instead of accessing it from `seat` since the leave + * callback (#data_device_handle_leave) will clear the value once this function starts. */ + std::thread read_thread( + read_uris_fn, seat, data_offer, seat->wl_surface_focus_dnd, mime_receive); read_thread.detach(); } @@ -1312,17 +1451,18 @@ static void data_device_handle_selection(void *data, struct wl_data_device * /*wl_data_device*/, struct wl_data_offer *id) { - input_t *input = static_cast<input_t *>(data); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); - std::lock_guard lock{input->data_offer_copy_paste_mutex}; + std::lock_guard lock{seat->data_offer_copy_paste_mutex}; - data_offer_t *data_offer = input->data_offer_copy_paste; + GWL_DataOffer *data_offer = seat->data_offer_copy_paste; /* Delete old data offer. */ if (data_offer != nullptr) { wl_data_offer_destroy(data_offer->id); delete data_offer; data_offer = nullptr; + seat->data_offer_copy_paste = nullptr; } if (id == nullptr) { @@ -1332,14 +1472,14 @@ static void data_device_handle_selection(void *data, CLOG_INFO(LOG, 2, "selection"); /* Get new data offer. */ - data_offer = static_cast<data_offer_t *>(wl_data_offer_get_user_data(id)); - input->data_offer_copy_paste = data_offer; + data_offer = static_cast<GWL_DataOffer *>(wl_data_offer_get_user_data(id)); + seat->data_offer_copy_paste = data_offer; - auto read_selection_fn = [](input_t *input) { - GHOST_SystemWayland *const system = input->system; - input->data_offer_copy_paste_mutex.lock(); + auto read_selection_fn = [](GWL_Seat *seat) { + GHOST_SystemWayland *const system = seat->system; + seat->data_offer_copy_paste_mutex.lock(); - data_offer_t *data_offer = input->data_offer_copy_paste; + GWL_DataOffer *data_offer = seat->data_offer_copy_paste; std::string mime_receive; for (const std::string type : {mime_text_utf8, mime_text_plain}) { if (data_offer->types.count(type)) { @@ -1348,7 +1488,7 @@ static void data_device_handle_selection(void *data, } } const std::string data = read_pipe( - data_offer, mime_receive, &input->data_offer_copy_paste_mutex); + data_offer, mime_receive, &seat->data_offer_copy_paste_mutex); { std::lock_guard lock{system_selection_mutex}; @@ -1356,7 +1496,7 @@ static void data_device_handle_selection(void *data, } }; - std::thread read_thread(read_selection_fn, input); + std::thread read_thread(read_selection_fn, seat); read_thread.detach(); } @@ -1384,7 +1524,7 @@ static void cursor_buffer_handle_release(void *data, struct wl_buffer *wl_buffer { CLOG_INFO(LOG, 2, "release"); - cursor_t *cursor = static_cast<cursor_t *>(data); + GWL_Cursor *cursor = static_cast<GWL_Cursor *>(data); wl_buffer_destroy(wl_buffer); if (wl_buffer == cursor->wl_buffer) { @@ -1408,22 +1548,22 @@ static const struct wl_buffer_listener cursor_buffer_listener = { static CLG_LogRef LOG_WL_CURSOR_SURFACE = {"ghost.wl.handle.cursor_surface"}; #define LOG (&LOG_WL_CURSOR_SURFACE) -static bool update_cursor_scale(cursor_t &cursor, +static bool update_cursor_scale(GWL_Cursor &cursor, wl_shm *shm, - input_state_pointer_t *input_state, - wl_surface *cursor_surface) + GWL_SeatStatePointer *seat_state_pointer, + wl_surface *wl_cursor_surface) { int scale = 0; - for (const output_t *output : input_state->outputs) { + for (const GWL_Output *output : seat_state_pointer->outputs) { if (output->scale > scale) { scale = output->scale; } } - if (scale > 0 && input_state->theme_scale != scale) { - input_state->theme_scale = scale; + if (scale > 0 && seat_state_pointer->theme_scale != scale) { + seat_state_pointer->theme_scale = scale; if (!cursor.is_custom) { - wl_surface_set_buffer_scale(cursor_surface, scale); + wl_surface_set_buffer_scale(wl_cursor_surface, scale); } wl_cursor_theme_destroy(cursor.wl_theme); cursor.wl_theme = wl_cursor_theme_load(cursor.theme_name.c_str(), scale * cursor.size, shm); @@ -1434,36 +1574,38 @@ static bool update_cursor_scale(cursor_t &cursor, static void cursor_surface_handle_enter(void *data, struct wl_surface *wl_surface, - struct wl_output *output) + struct wl_output *wl_output) { - if (!ghost_wl_output_own(output)) { + if (!ghost_wl_output_own(wl_output)) { CLOG_INFO(LOG, 2, "handle_enter (skipped)"); return; } CLOG_INFO(LOG, 2, "handle_enter"); - input_t *input = static_cast<input_t *>(data); - input_state_pointer_t *input_state = input_state_pointer_from_cursor_surface(input, wl_surface); - const output_t *reg_output = ghost_wl_output_user_data(output); - input_state->outputs.insert(reg_output); - update_cursor_scale(input->cursor, input->system->shm(), input_state, wl_surface); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + GWL_SeatStatePointer *seat_state_pointer = seat_state_pointer_from_cursor_surface(seat, + wl_surface); + const GWL_Output *reg_output = ghost_wl_output_user_data(wl_output); + seat_state_pointer->outputs.insert(reg_output); + update_cursor_scale(seat->cursor, seat->system->shm(), seat_state_pointer, wl_surface); } static void cursor_surface_handle_leave(void *data, struct wl_surface *wl_surface, - struct wl_output *output) + struct wl_output *wl_output) { - if (!(output && ghost_wl_output_own(output))) { + if (!(wl_output && ghost_wl_output_own(wl_output))) { CLOG_INFO(LOG, 2, "handle_leave (skipped)"); return; } CLOG_INFO(LOG, 2, "handle_leave"); - input_t *input = static_cast<input_t *>(data); - input_state_pointer_t *input_state = input_state_pointer_from_cursor_surface(input, wl_surface); - const output_t *reg_output = ghost_wl_output_user_data(output); - input_state->outputs.erase(reg_output); - update_cursor_scale(input->cursor, input->system->shm(), input_state, wl_surface); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + GWL_SeatStatePointer *seat_state_pointer = seat_state_pointer_from_cursor_surface(seat, + wl_surface); + const GWL_Output *reg_output = ghost_wl_output_user_data(wl_output); + seat_state_pointer->outputs.erase(reg_output); + update_cursor_scale(seat->cursor, seat->system->shm(), seat_state_pointer, wl_surface); } static const struct wl_surface_listener cursor_surface_listener = { @@ -1485,48 +1627,48 @@ static CLG_LogRef LOG_WL_POINTER = {"ghost.wl.handle.pointer"}; static void pointer_handle_enter(void *data, struct wl_pointer * /*wl_pointer*/, const uint32_t serial, - struct wl_surface *surface, + struct wl_surface *wl_surface, const wl_fixed_t surface_x, const wl_fixed_t surface_y) { - if (!ghost_wl_surface_own(surface)) { + if (!ghost_wl_surface_own(wl_surface)) { CLOG_INFO(LOG, 2, "enter (skipped)"); return; } CLOG_INFO(LOG, 2, "enter"); - GHOST_WindowWayland *win = ghost_wl_surface_user_data(surface); + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface); win->activate(); - input_t *input = static_cast<input_t *>(data); - input->cursor_source_serial = serial; - input->pointer.serial = serial; - input->pointer.xy[0] = surface_x; - input->pointer.xy[1] = surface_y; - input->pointer.wl_surface = surface; + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + seat->cursor_source_serial = serial; + seat->pointer.serial = serial; + seat->pointer.xy[0] = surface_x; + seat->pointer.xy[1] = surface_y; + seat->pointer.wl_surface = wl_surface; win->setCursorShape(win->getCursorShape()); const wl_fixed_t scale = win->scale(); - input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(), - GHOST_kEventCursorMove, - win, - wl_fixed_to_int(scale * input->pointer.xy[0]), - wl_fixed_to_int(scale * input->pointer.xy[1]), - GHOST_TABLET_DATA_NONE)); + seat->system->pushEvent(new GHOST_EventCursor(seat->system->getMilliSeconds(), + GHOST_kEventCursorMove, + win, + wl_fixed_to_int(scale * seat->pointer.xy[0]), + wl_fixed_to_int(scale * seat->pointer.xy[1]), + GHOST_TABLET_DATA_NONE)); } static void pointer_handle_leave(void *data, struct wl_pointer * /*wl_pointer*/, const uint32_t /*serial*/, - struct wl_surface *surface) + struct wl_surface *wl_surface) { /* First clear the `pointer.wl_surface`, since the window won't exist when closing the window. */ - static_cast<input_t *>(data)->pointer.wl_surface = nullptr; - if (surface && ghost_wl_surface_own(surface)) { + static_cast<GWL_Seat *>(data)->pointer.wl_surface = nullptr; + if (wl_surface && ghost_wl_surface_own(wl_surface)) { CLOG_INFO(LOG, 2, "leave"); - GHOST_WindowWayland *win = ghost_wl_surface_user_data(surface); + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface); win->deactivate(); } else { @@ -1540,20 +1682,20 @@ static void pointer_handle_motion(void *data, const wl_fixed_t surface_x, const wl_fixed_t surface_y) { - input_t *input = static_cast<input_t *>(data); - input->pointer.xy[0] = surface_x; - input->pointer.xy[1] = surface_y; + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + seat->pointer.xy[0] = surface_x; + seat->pointer.xy[1] = surface_y; - if (wl_surface *focus_surface = input->pointer.wl_surface) { + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { CLOG_INFO(LOG, 2, "motion"); - GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface); + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); const wl_fixed_t scale = win->scale(); - input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(), - GHOST_kEventCursorMove, - win, - wl_fixed_to_int(scale * input->pointer.xy[0]), - wl_fixed_to_int(scale * input->pointer.xy[1]), - GHOST_TABLET_DATA_NONE)); + seat->system->pushEvent(new GHOST_EventCursor(seat->system->getMilliSeconds(), + GHOST_kEventCursorMove, + win, + wl_fixed_to_int(scale * seat->pointer.xy[0]), + wl_fixed_to_int(scale * seat->pointer.xy[1]), + GHOST_TABLET_DATA_NONE)); } else { CLOG_INFO(LOG, 2, "motion (skipped)"); @@ -1569,7 +1711,7 @@ static void pointer_handle_button(void *data, { CLOG_INFO(LOG, 2, "button (button=%u, state=%u)", button, state); - input_t *input = static_cast<input_t *>(data); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); GHOST_TEventType etype = GHOST_kEventUnknown; switch (state) { case WL_POINTER_BUTTON_STATE_RELEASED: @@ -1605,13 +1747,13 @@ static void pointer_handle_button(void *data, break; } - input->data_source_serial = serial; - input->pointer.buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED); + seat->data_source_serial = serial; + seat->pointer.buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED); - if (wl_surface *focus_surface = input->pointer.wl_surface) { - GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface); - input->system->pushEvent(new GHOST_EventButton( - input->system->getMilliSeconds(), etype, win, ebutton, GHOST_TABLET_DATA_NONE)); + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); + seat->system->pushEvent(new GHOST_EventButton( + seat->system->getMilliSeconds(), etype, win, ebutton, GHOST_TABLET_DATA_NONE)); } } @@ -1648,15 +1790,15 @@ static void pointer_handle_axis_discrete(void *data, { CLOG_INFO(LOG, 2, "axis_discrete (axis=%u, discrete=%d)", axis, discrete); - input_t *input = static_cast<input_t *>(data); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) { return; } - if (wl_surface *focus_surface = input->pointer.wl_surface) { - GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface); - input->system->pushEvent(new GHOST_EventWheel( - input->system->getMilliSeconds(), win, std::signbit(discrete) ? +1 : -1)); + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); + seat->system->pushEvent(new GHOST_EventWheel( + seat->system->getMilliSeconds(), win, std::signbit(discrete) ? +1 : -1)); } } @@ -1689,9 +1831,9 @@ static void tablet_tool_handle_type(void *data, { CLOG_INFO(LOG, 2, "type (type=%u)", tool_type); - tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data); + GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(data); - tool_input->data.Active = tablet_tool_map_type((enum zwp_tablet_tool_v2_type)tool_type); + tablet_tool->data.Active = tablet_tool_map_type((enum zwp_tablet_tool_v2_type)tool_type); } static void tablet_tool_handle_hardware_serial(void * /*data*/, @@ -1734,47 +1876,47 @@ static void tablet_tool_handle_removed(void *data, struct zwp_tablet_tool_v2 *zw { CLOG_INFO(LOG, 2, "removed"); - tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data); - input_t *input = tool_input->input; + GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(data); + GWL_Seat *seat = tablet_tool->seat; - if (tool_input->cursor_surface) { - wl_surface_destroy(tool_input->cursor_surface); + if (tablet_tool->wl_surface_cursor) { + wl_surface_destroy(tablet_tool->wl_surface_cursor); } - input->tablet_tools.erase(zwp_tablet_tool_v2); + seat->tablet_tools.erase(zwp_tablet_tool_v2); - delete tool_input; + delete tablet_tool; } static void tablet_tool_handle_proximity_in(void *data, struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/, const uint32_t serial, struct zwp_tablet_v2 * /*tablet*/, - struct wl_surface *surface) + struct wl_surface *wl_surface) { - if (!ghost_wl_surface_own(surface)) { + if (!ghost_wl_surface_own(wl_surface)) { CLOG_INFO(LOG, 2, "proximity_in (skipped)"); return; } CLOG_INFO(LOG, 2, "proximity_in"); - tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data); - tool_input->proximity = true; + GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(data); + tablet_tool->proximity = true; - input_t *input = tool_input->input; - input->cursor_source_serial = serial; - input->tablet.wl_surface = surface; - input->tablet.serial = serial; + GWL_Seat *seat = tablet_tool->seat; + seat->cursor_source_serial = serial; + seat->tablet.wl_surface = wl_surface; + seat->tablet.serial = serial; - input->data_source_serial = serial; + seat->data_source_serial = serial; /* Update #GHOST_TabletData. */ - GHOST_TabletData &td = tool_input->data; + GHOST_TabletData &td = tablet_tool->data; /* Reset, to avoid using stale tilt/pressure. */ td.Xtilt = 0.0f; td.Ytilt = 0.0f; /* In case pressure isn't supported. */ td.Pressure = 1.0f; - GHOST_WindowWayland *win = ghost_wl_surface_user_data(input->tablet.wl_surface); + GHOST_WindowWayland *win = ghost_wl_surface_user_data(seat->tablet.wl_surface); win->activate(); @@ -1784,10 +1926,10 @@ static void tablet_tool_handle_proximity_out(void *data, struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/) { CLOG_INFO(LOG, 2, "proximity_out"); - tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data); - /* Defer clearing the surface until the frame is handled. - * Without this, the frame can not access the surface. */ - tool_input->proximity = false; + GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(data); + /* Defer clearing the wl_surface until the frame is handled. + * Without this, the frame can not access the wl_surface. */ + tablet_tool->proximity = false; } static void tablet_tool_handle_down(void *data, @@ -1796,18 +1938,18 @@ static void tablet_tool_handle_down(void *data, { CLOG_INFO(LOG, 2, "down"); - tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data); - input_t *input = tool_input->input; + GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(data); + GWL_Seat *seat = tablet_tool->seat; const GHOST_TButton ebutton = GHOST_kButtonMaskLeft; const GHOST_TEventType etype = GHOST_kEventButtonDown; - input->data_source_serial = serial; - input->tablet.buttons.set(ebutton, true); + seat->data_source_serial = serial; + seat->tablet.buttons.set(ebutton, true); - if (wl_surface *focus_surface = input->tablet.wl_surface) { - GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface); - input->system->pushEvent(new GHOST_EventButton( - input->system->getMilliSeconds(), etype, win, ebutton, tool_input->data)); + if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) { + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); + seat->system->pushEvent(new GHOST_EventButton( + seat->system->getMilliSeconds(), etype, win, ebutton, tablet_tool->data)); } } @@ -1815,17 +1957,17 @@ static void tablet_tool_handle_up(void *data, struct zwp_tablet_tool_v2 * /*zwp_ { CLOG_INFO(LOG, 2, "up"); - tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data); - input_t *input = tool_input->input; + GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(data); + GWL_Seat *seat = tablet_tool->seat; const GHOST_TButton ebutton = GHOST_kButtonMaskLeft; const GHOST_TEventType etype = GHOST_kEventButtonUp; - input->tablet.buttons.set(ebutton, false); + seat->tablet.buttons.set(ebutton, false); - if (wl_surface *focus_surface = input->tablet.wl_surface) { - GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface); - input->system->pushEvent(new GHOST_EventButton( - input->system->getMilliSeconds(), etype, win, ebutton, tool_input->data)); + if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) { + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); + seat->system->pushEvent(new GHOST_EventButton( + seat->system->getMilliSeconds(), etype, win, ebutton, tablet_tool->data)); } } @@ -1836,11 +1978,11 @@ static void tablet_tool_handle_motion(void *data, { CLOG_INFO(LOG, 2, "motion"); - tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data); - input_t *input = tool_input->input; + GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(data); + GWL_Seat *seat = tablet_tool->seat; - input->tablet.xy[0] = x; - input->tablet.xy[1] = y; + seat->tablet.xy[0] = x; + seat->tablet.xy[1] = y; /* NOTE: #tablet_tool_handle_frame generates the event (with updated pressure, tilt... etc). */ } @@ -1852,8 +1994,8 @@ static void tablet_tool_handle_pressure(void *data, const float pressure_unit = (float)pressure / 65535; CLOG_INFO(LOG, 2, "pressure (%.4f)", pressure_unit); - tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data); - GHOST_TabletData &td = tool_input->data; + GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(data); + GHOST_TabletData &td = tablet_tool->data; td.Pressure = pressure_unit; } static void tablet_tool_handle_distance(void * /*data*/, @@ -1874,8 +2016,8 @@ static void tablet_tool_handle_tilt(void *data, (float)(wl_fixed_to_double(tilt_y) / 90.0), }; CLOG_INFO(LOG, 2, "tilt (x=%.4f, y=%.4f)", UNPACK2(tilt_unit)); - tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data); - GHOST_TabletData &td = tool_input->data; + GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(data); + GHOST_TabletData &td = tablet_tool->data; td.Xtilt = tilt_unit[0]; td.Ytilt = tilt_unit[1]; CLAMP(td.Xtilt, -1.0f, 1.0f); @@ -1905,11 +2047,11 @@ static void tablet_tool_handle_wheel(void *data, } CLOG_INFO(LOG, 2, "wheel (clicks=%d)", clicks); - tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data); - input_t *input = tool_input->input; - if (wl_surface *focus_surface = input->tablet.wl_surface) { - GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface); - input->system->pushEvent(new GHOST_EventWheel(input->system->getMilliSeconds(), win, clicks)); + GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(data); + GWL_Seat *seat = tablet_tool->seat; + if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) { + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); + seat->system->pushEvent(new GHOST_EventWheel(seat->system->getMilliSeconds(), win, clicks)); } } static void tablet_tool_handle_button(void *data, @@ -1920,8 +2062,8 @@ static void tablet_tool_handle_button(void *data, { CLOG_INFO(LOG, 2, "button (button=%u, state=%u)", button, state); - tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data); - input_t *input = tool_input->input; + GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(data); + GWL_Seat *seat = tablet_tool->seat; GHOST_TEventType etype = GHOST_kEventUnknown; switch (state) { @@ -1946,13 +2088,13 @@ static void tablet_tool_handle_button(void *data, break; } - input->data_source_serial = serial; - input->tablet.buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED); + seat->data_source_serial = serial; + seat->tablet.buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED); - if (wl_surface *focus_surface = input->tablet.wl_surface) { - GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface); - input->system->pushEvent(new GHOST_EventButton( - input->system->getMilliSeconds(), etype, win, ebutton, tool_input->data)); + if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) { + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); + seat->system->pushEvent(new GHOST_EventButton( + seat->system->getMilliSeconds(), etype, win, ebutton, tablet_tool->data)); } } static void tablet_tool_handle_frame(void *data, @@ -1961,26 +2103,26 @@ static void tablet_tool_handle_frame(void *data, { CLOG_INFO(LOG, 2, "frame"); - tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data); - input_t *input = tool_input->input; + GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(data); + GWL_Seat *seat = tablet_tool->seat; /* No need to check the surfaces origin, it's already known to be owned by GHOST. */ - if (wl_surface *focus_surface = input->tablet.wl_surface) { - GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface); + if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) { + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); const wl_fixed_t scale = win->scale(); - input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(), - GHOST_kEventCursorMove, - win, - wl_fixed_to_int(scale * input->tablet.xy[0]), - wl_fixed_to_int(scale * input->tablet.xy[1]), - tool_input->data)); - if (tool_input->proximity == false) { + seat->system->pushEvent(new GHOST_EventCursor(seat->system->getMilliSeconds(), + GHOST_kEventCursorMove, + win, + wl_fixed_to_int(scale * seat->tablet.xy[0]), + wl_fixed_to_int(scale * seat->tablet.xy[1]), + tablet_tool->data)); + if (tablet_tool->proximity == false) { win->setCursorShape(win->getCursorShape()); } } - if (tool_input->proximity == false) { - input->tablet.wl_surface = nullptr; + if (tablet_tool->proximity == false) { + seat->tablet.wl_surface = nullptr; } } @@ -2030,19 +2172,19 @@ static void tablet_seat_handle_tool_added(void *data, { CLOG_INFO(LOG, 2, "tool_added (id=%p)", id); - input_t *input = static_cast<input_t *>(data); - tablet_tool_input_t *tool_input = new tablet_tool_input_t(); - tool_input->input = input; + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + GWL_TabletTool *tablet_tool = new GWL_TabletTool(); + tablet_tool->seat = seat; - /* Every tool has it's own cursor surface. */ - tool_input->cursor_surface = wl_compositor_create_surface(input->system->compositor()); - ghost_wl_surface_tag_cursor_tablet(tool_input->cursor_surface); + /* Every tool has it's own cursor wl_surface. */ + tablet_tool->wl_surface_cursor = wl_compositor_create_surface(seat->system->compositor()); + ghost_wl_surface_tag_cursor_tablet(tablet_tool->wl_surface_cursor); - wl_surface_add_listener(tool_input->cursor_surface, &cursor_surface_listener, (void *)input); + wl_surface_add_listener(tablet_tool->wl_surface_cursor, &cursor_surface_listener, (void *)seat); - zwp_tablet_tool_v2_add_listener(id, &tablet_tool_listner, tool_input); + zwp_tablet_tool_v2_add_listener(id, &tablet_tool_listner, tablet_tool); - input->tablet_tools.insert(id); + seat->tablet_tools.insert(id); } static void tablet_seat_handle_pad_added(void * /*data*/, @@ -2075,7 +2217,7 @@ static void keyboard_handle_keymap(void *data, const int32_t fd, const uint32_t size) { - input_t *input = static_cast<input_t *>(data); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); if ((!data) || (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)) { CLOG_INFO(LOG, 2, "keymap (no data or wrong version)"); @@ -2090,7 +2232,7 @@ static void keyboard_handle_keymap(void *data, } struct xkb_keymap *keymap = xkb_keymap_new_from_string( - input->xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + seat->xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); munmap(map_str, size); close(fd); @@ -2102,31 +2244,31 @@ static void keyboard_handle_keymap(void *data, CLOG_INFO(LOG, 2, "keymap"); /* In practice we can assume `xkb_state_new` always succeeds. */ - xkb_state_unref(input->xkb_state); - input->xkb_state = xkb_state_new(keymap); + xkb_state_unref(seat->xkb_state); + seat->xkb_state = xkb_state_new(keymap); - xkb_state_unref(input->xkb_state_empty); - input->xkb_state_empty = xkb_state_new(keymap); + xkb_state_unref(seat->xkb_state_empty); + seat->xkb_state_empty = xkb_state_new(keymap); - xkb_state_unref(input->xkb_state_empty_with_numlock); - input->xkb_state_empty_with_numlock = nullptr; + xkb_state_unref(seat->xkb_state_empty_with_numlock); + seat->xkb_state_empty_with_numlock = nullptr; { const xkb_mod_index_t mod2 = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_NUM); const xkb_mod_index_t num = xkb_keymap_mod_get_index(keymap, "NumLock"); if (num != XKB_MOD_INVALID && mod2 != XKB_MOD_INVALID) { - input->xkb_state_empty_with_numlock = xkb_state_new(keymap); + seat->xkb_state_empty_with_numlock = xkb_state_new(keymap); xkb_state_update_mask( - input->xkb_state_empty_with_numlock, (1 << mod2), 0, (1 << num), 0, 0, 0); + seat->xkb_state_empty_with_numlock, (1 << mod2), 0, (1 << num), 0, 0, 0); } } - input->xkb_keymap_mod_index.shift = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); - input->xkb_keymap_mod_index.caps = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); - input->xkb_keymap_mod_index.ctrl = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); - input->xkb_keymap_mod_index.alt = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT); - input->xkb_keymap_mod_index.num = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_NUM); - input->xkb_keymap_mod_index.logo = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_LOGO); + for (int i = 0; i < MOD_INDEX_NUM; i++) { + const GWL_ModifierInfo &mod_info = g_modifier_info_table[i]; + seat->xkb_keymap_mod_index[i] = xkb_keymap_mod_get_index(keymap, mod_info.xkb_id); + } + + keyboard_depressed_state_reset(seat); xkb_keymap_unref(keymap); } @@ -2134,92 +2276,65 @@ static void keyboard_handle_keymap(void *data, /** * Enter event. * - * Notification that this seat's keyboard focus is on a certain - * surface. + * Notification that this seat's keyboard focus is on a certain wl_surface. */ static void keyboard_handle_enter(void *data, struct wl_keyboard * /*wl_keyboard*/, const uint32_t serial, - struct wl_surface *surface, + struct wl_surface *wl_surface, struct wl_array *keys) { - if (!ghost_wl_surface_own(surface)) { + if (!ghost_wl_surface_own(wl_surface)) { CLOG_INFO(LOG, 2, "enter (skipped)"); return; } CLOG_INFO(LOG, 2, "enter"); - input_t *input = static_cast<input_t *>(data); - input->keyboard.serial = serial; - input->keyboard.wl_surface = surface; - - if (keys->size != 0) { - /* If there are any keys held when activating the window, - * modifiers will be compared against the input state, - * only enabling modifiers that were previously disabled. */ - - const xkb_mod_mask_t state = xkb_state_serialize_mods(input->xkb_state, XKB_STATE_MODS_ALL); - uint32_t *key; - WL_ARRAY_FOR_EACH (key, keys) { - const xkb_keycode_t key_code = *key + EVDEV_OFFSET; - const xkb_keysym_t sym = xkb_state_key_get_one_sym(input->xkb_state, key_code); - GHOST_TKey gkey = GHOST_kKeyUnknown; - -#define MOD_TEST(state, mod) ((mod != XKB_MOD_INVALID) && (state & (1 << mod))) -#define MOD_TEST_CASE(xkb_key, ghost_key, mod_index) \ - case xkb_key: \ - if (!MOD_TEST(state, input->xkb_keymap_mod_index.mod_index)) { \ - gkey = ghost_key; \ - } \ - break - - switch (sym) { - MOD_TEST_CASE(XKB_KEY_Shift_L, GHOST_kKeyLeftShift, shift); - MOD_TEST_CASE(XKB_KEY_Shift_R, GHOST_kKeyRightShift, shift); - MOD_TEST_CASE(XKB_KEY_Control_L, GHOST_kKeyLeftControl, ctrl); - MOD_TEST_CASE(XKB_KEY_Control_R, GHOST_kKeyRightControl, ctrl); - MOD_TEST_CASE(XKB_KEY_Alt_L, GHOST_kKeyLeftAlt, alt); - MOD_TEST_CASE(XKB_KEY_Alt_R, GHOST_kKeyRightAlt, alt); - MOD_TEST_CASE(XKB_KEY_Super_L, GHOST_kKeyOS, logo); - MOD_TEST_CASE(XKB_KEY_Super_R, GHOST_kKeyOS, logo); - } - -#undef MOD_TEST -#undef MOD_TEST_CASE - - if (gkey != GHOST_kKeyUnknown) { - GHOST_IWindow *win = ghost_wl_surface_user_data(surface); - GHOST_SystemWayland *system = input->system; - input->system->pushEvent( - new GHOST_EventKey(system->getMilliSeconds(), GHOST_kEventKeyDown, win, gkey, false)); - } + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + seat->keyboard.serial = serial; + seat->keyboard.wl_surface = wl_surface; + + /* If there are any keys held when activating the window, + * modifiers will be compared against the seat state, + * only enabling modifiers that were previously disabled. */ + WGL_KeyboardDepressedState key_depressed_prev = seat->key_depressed; + keyboard_depressed_state_reset(seat); + + uint32_t *key; + WL_ARRAY_FOR_EACH (key, keys) { + const xkb_keycode_t key_code = *key + EVDEV_OFFSET; + const xkb_keysym_t sym = xkb_state_key_get_one_sym(seat->xkb_state, key_code); + const GHOST_TKey gkey = xkb_map_gkey_or_scan_code(sym, *key); + if (gkey != GHOST_kKeyUnknown) { + keyboard_depressed_state_key_event(seat, gkey, GHOST_kEventKeyDown); } } + + keyboard_depressed_state_push_events_from_change(seat, key_depressed_prev); } /** * Leave event. * - * Notification that this seat's keyboard focus is no longer on a - * certain surface. + * Notification that this seat's keyboard focus is no longer on a certain wl_surface. */ static void keyboard_handle_leave(void *data, struct wl_keyboard * /*wl_keyboard*/, const uint32_t /*serial*/, - struct wl_surface *surface) + struct wl_surface *wl_surface) { - if (!(surface && ghost_wl_surface_own(surface))) { + if (!(wl_surface && ghost_wl_surface_own(wl_surface))) { CLOG_INFO(LOG, 2, "leave (skipped)"); return; } CLOG_INFO(LOG, 2, "leave"); - input_t *input = static_cast<input_t *>(data); - input->keyboard.wl_surface = nullptr; + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + seat->keyboard.wl_surface = nullptr; /* Losing focus must stop repeating text. */ - if (input->key_repeat.timer) { - keyboard_handle_key_repeat_cancel(input); + if (seat->key_repeat.timer) { + keyboard_handle_key_repeat_cancel(seat); } } @@ -2253,12 +2368,12 @@ static xkb_keysym_t xkb_state_key_get_one_sym_without_modifiers( return sym; } -static void keyboard_handle_key_repeat_cancel(input_t *input) +static void keyboard_handle_key_repeat_cancel(GWL_Seat *seat) { - GHOST_ASSERT(input->key_repeat.timer != nullptr, "Caller much check for timer"); - delete static_cast<key_repeat_payload_t *>(input->key_repeat.timer->getUserData()); - input->system->removeTimer(input->key_repeat.timer); - input->key_repeat.timer = nullptr; + GHOST_ASSERT(seat->key_repeat.timer != nullptr, "Caller much check for timer"); + delete static_cast<GWL_KeyRepeatPlayload *>(seat->key_repeat.timer->getUserData()); + seat->system->removeTimer(seat->key_repeat.timer); + seat->key_repeat.timer = nullptr; } /** @@ -2266,17 +2381,17 @@ static void keyboard_handle_key_repeat_cancel(input_t *input) * \param use_delay: When false, use the interval * (prevents pause when the setting changes while the key is held). */ -static void keyboard_handle_key_repeat_reset(input_t *input, const bool use_delay) +static void keyboard_handle_key_repeat_reset(GWL_Seat *seat, const bool use_delay) { - GHOST_ASSERT(input->key_repeat.timer != nullptr, "Caller much check for timer"); - GHOST_SystemWayland *system = input->system; - GHOST_ITimerTask *timer = input->key_repeat.timer; + GHOST_ASSERT(seat->key_repeat.timer != nullptr, "Caller much check for timer"); + GHOST_SystemWayland *system = seat->system; + GHOST_ITimerTask *timer = seat->key_repeat.timer; GHOST_TimerProcPtr key_repeat_fn = timer->getTimerProc(); - GHOST_TUserDataPtr payload = input->key_repeat.timer->getUserData(); - input->system->removeTimer(input->key_repeat.timer); - const uint64_t time_step = 1000 / input->key_repeat.rate; - const uint64_t time_start = use_delay ? input->key_repeat.delay : time_step; - input->key_repeat.timer = system->installTimer(time_start, time_step, key_repeat_fn, payload); + GHOST_TUserDataPtr payload = seat->key_repeat.timer->getUserData(); + seat->system->removeTimer(seat->key_repeat.timer); + const uint64_t time_step = 1000 / seat->key_repeat.rate; + const uint64_t time_start = use_delay ? seat->key_repeat.delay : time_step; + seat->key_repeat.timer = system->installTimer(time_start, time_step, key_repeat_fn, payload); } static void keyboard_handle_key(void *data, @@ -2286,11 +2401,11 @@ static void keyboard_handle_key(void *data, const uint32_t key, const uint32_t state) { - input_t *input = static_cast<input_t *>(data); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); const xkb_keycode_t key_code = key + EVDEV_OFFSET; const xkb_keysym_t sym = xkb_state_key_get_one_sym_without_modifiers( - input->xkb_state_empty, input->xkb_state_empty_with_numlock, key_code); + seat->xkb_state_empty, seat->xkb_state_empty_with_numlock, key_code); if (sym == XKB_KEY_NoSymbol) { CLOG_INFO(LOG, 2, "key (no symbol, skipped)"); return; @@ -2307,15 +2422,15 @@ static void keyboard_handle_key(void *data, break; } - struct key_repeat_payload_t *key_repeat_payload = nullptr; + struct GWL_KeyRepeatPlayload *key_repeat_payload = nullptr; /* Delete previous timer. */ - if (input->key_repeat.timer) { + if (seat->key_repeat.timer) { enum { NOP = 1, RESET, CANCEL } timer_action = NOP; - key_repeat_payload = static_cast<key_repeat_payload_t *>( - input->key_repeat.timer->getUserData()); + key_repeat_payload = static_cast<GWL_KeyRepeatPlayload *>( + seat->key_repeat.timer->getUserData()); - if (input->key_repeat.rate == 0) { + if (seat->key_repeat.rate == 0) { /* Repeat was disabled (unlikely but possible). */ timer_action = CANCEL; } @@ -2323,7 +2438,7 @@ static void keyboard_handle_key(void *data, /* Releasing the key that was held always cancels. */ timer_action = CANCEL; } - else if (xkb_keymap_key_repeats(xkb_state_get_keymap(input->xkb_state), key_code)) { + else if (xkb_keymap_key_repeats(xkb_state_get_keymap(seat->xkb_state), key_code)) { if (etype == GHOST_kEventKeyDown) { /* Any other key-down always cancels (and may start it's own repeat timer). */ timer_action = CANCEL; @@ -2346,16 +2461,16 @@ static void keyboard_handle_key(void *data, } case RESET: { /* The payload will be added again. */ - input->system->removeTimer(input->key_repeat.timer); - input->key_repeat.timer = nullptr; + seat->system->removeTimer(seat->key_repeat.timer); + seat->key_repeat.timer = nullptr; break; } case CANCEL: { delete key_repeat_payload; key_repeat_payload = nullptr; - input->system->removeTimer(input->key_repeat.timer); - input->key_repeat.timer = nullptr; + seat->system->removeTimer(seat->key_repeat.timer); + seat->key_repeat.timer = nullptr; break; } } @@ -2364,24 +2479,26 @@ static void keyboard_handle_key(void *data, const GHOST_TKey gkey = xkb_map_gkey_or_scan_code(sym, key); char utf8_buf[sizeof(GHOST_TEventKeyData::utf8_buf)] = {'\0'}; if (etype == GHOST_kEventKeyDown) { - xkb_state_key_get_utf8(input->xkb_state, key_code, utf8_buf, sizeof(utf8_buf)); + xkb_state_key_get_utf8(seat->xkb_state, key_code, utf8_buf, sizeof(utf8_buf)); } - input->data_source_serial = serial; + seat->data_source_serial = serial; + + keyboard_depressed_state_key_event(seat, gkey, etype); - if (wl_surface *focus_surface = input->keyboard.wl_surface) { - GHOST_IWindow *win = ghost_wl_surface_user_data(focus_surface); - input->system->pushEvent( - new GHOST_EventKey(input->system->getMilliSeconds(), etype, win, gkey, false, utf8_buf)); + if (wl_surface *wl_surface_focus = seat->keyboard.wl_surface) { + GHOST_IWindow *win = ghost_wl_surface_user_data(wl_surface_focus); + seat->system->pushEvent( + new GHOST_EventKey(seat->system->getMilliSeconds(), etype, win, gkey, false, utf8_buf)); } /* An existing payload means the key repeat timer is reset and will be added again. */ if (key_repeat_payload == nullptr) { /* Start timer for repeating key, if applicable. */ - if ((input->key_repeat.rate > 0) && (etype == GHOST_kEventKeyDown) && - xkb_keymap_key_repeats(xkb_state_get_keymap(input->xkb_state), key_code)) { - key_repeat_payload = new key_repeat_payload_t({ - .input = input, + if ((seat->key_repeat.rate > 0) && (etype == GHOST_kEventKeyDown) && + xkb_keymap_key_repeats(xkb_state_get_keymap(seat->xkb_state), key_code)) { + key_repeat_payload = new GWL_KeyRepeatPlayload({ + .seat = seat, .key_code = key_code, .key_data = {.gkey = gkey}, }); @@ -2390,16 +2507,16 @@ static void keyboard_handle_key(void *data, if (key_repeat_payload) { auto key_repeat_fn = [](GHOST_ITimerTask *task, uint64_t /*time*/) { - struct key_repeat_payload_t *payload = static_cast<key_repeat_payload_t *>( + struct GWL_KeyRepeatPlayload *payload = static_cast<GWL_KeyRepeatPlayload *>( task->getUserData()); - input_t *input = payload->input; - if (wl_surface *focus_surface = input->keyboard.wl_surface) { - GHOST_IWindow *win = ghost_wl_surface_user_data(focus_surface); - GHOST_SystemWayland *system = input->system; + GWL_Seat *seat = payload->seat; + if (wl_surface *wl_surface_focus = seat->keyboard.wl_surface) { + GHOST_IWindow *win = ghost_wl_surface_user_data(wl_surface_focus); + GHOST_SystemWayland *system = seat->system; /* Calculate this value every time in case modifier keys are pressed. */ char utf8_buf[sizeof(GHOST_TEventKeyData::utf8_buf)] = {'\0'}; - xkb_state_key_get_utf8(input->xkb_state, payload->key_code, utf8_buf, sizeof(utf8_buf)); + xkb_state_key_get_utf8(seat->xkb_state, payload->key_code, utf8_buf, sizeof(utf8_buf)); system->pushEvent(new GHOST_EventKey(system->getMilliSeconds(), GHOST_kEventKeyDown, win, @@ -2408,8 +2525,8 @@ static void keyboard_handle_key(void *data, utf8_buf)); } }; - input->key_repeat.timer = input->system->installTimer( - input->key_repeat.delay, 1000 / input->key_repeat.rate, key_repeat_fn, key_repeat_payload); + seat->key_repeat.timer = seat->system->installTimer( + seat->key_repeat.delay, 1000 / seat->key_repeat.rate, key_repeat_fn, key_repeat_payload); } } @@ -2429,13 +2546,13 @@ static void keyboard_handle_modifiers(void *data, mods_locked, group); - input_t *input = static_cast<input_t *>(data); - xkb_state_update_mask(input->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group); + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + xkb_state_update_mask(seat->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group); /* A modifier changed so reset the timer, * see comment in #keyboard_handle_key regarding this behavior. */ - if (input->key_repeat.timer) { - keyboard_handle_key_repeat_reset(input, true); + if (seat->key_repeat.timer) { + keyboard_handle_key_repeat_reset(seat, true); } } @@ -2446,13 +2563,13 @@ static void keyboard_repeat_handle_info(void *data, { CLOG_INFO(LOG, 2, "info (rate=%d, delay=%d)", rate, delay); - input_t *input = static_cast<input_t *>(data); - input->key_repeat.rate = rate; - input->key_repeat.delay = delay; + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + seat->key_repeat.rate = rate; + seat->key_repeat.delay = delay; /* Unlikely possible this setting changes while repeating. */ - if (input->key_repeat.timer) { - keyboard_handle_key_repeat_reset(input, false); + if (seat->key_repeat.timer) { + keyboard_handle_key_repeat_reset(seat, false); } } @@ -2487,35 +2604,35 @@ static void seat_handle_capabilities(void *data, (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) != 0, (capabilities & WL_SEAT_CAPABILITY_TOUCH) != 0); - input_t *input = static_cast<input_t *>(data); - input->wl_pointer = nullptr; - input->wl_keyboard = nullptr; + GWL_Seat *seat = static_cast<GWL_Seat *>(data); + seat->wl_pointer = nullptr; + seat->wl_keyboard = nullptr; if (capabilities & WL_SEAT_CAPABILITY_POINTER) { - input->wl_pointer = wl_seat_get_pointer(wl_seat); - input->cursor.wl_surface = wl_compositor_create_surface(input->system->compositor()); - input->cursor.visible = true; - input->cursor.wl_buffer = nullptr; - if (!get_cursor_settings(input->cursor.theme_name, input->cursor.size)) { - input->cursor.theme_name = std::string(); - input->cursor.size = default_cursor_size; + seat->wl_pointer = wl_seat_get_pointer(wl_seat); + seat->cursor.wl_surface = wl_compositor_create_surface(seat->system->compositor()); + seat->cursor.visible = true; + seat->cursor.wl_buffer = nullptr; + if (!get_cursor_settings(seat->cursor.theme_name, seat->cursor.size)) { + seat->cursor.theme_name = std::string(); + seat->cursor.size = default_cursor_size; } - wl_pointer_add_listener(input->wl_pointer, &pointer_listener, data); + wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, data); - wl_surface_add_listener(input->cursor.wl_surface, &cursor_surface_listener, data); - ghost_wl_surface_tag_cursor_pointer(input->cursor.wl_surface); + wl_surface_add_listener(seat->cursor.wl_surface, &cursor_surface_listener, data); + ghost_wl_surface_tag_cursor_pointer(seat->cursor.wl_surface); } if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { - input->wl_keyboard = wl_seat_get_keyboard(wl_seat); - wl_keyboard_add_listener(input->wl_keyboard, &keyboard_listener, data); + seat->wl_keyboard = wl_seat_get_keyboard(wl_seat); + wl_keyboard_add_listener(seat->wl_keyboard, &keyboard_listener, data); } } static void seat_handle_name(void *data, struct wl_seat * /*wl_seat*/, const char *name) { CLOG_INFO(LOG, 2, "name (name=\"%s\")", name); - static_cast<input_t *>(data)->name = std::string(name); + static_cast<GWL_Seat *>(data)->name = std::string(name); } static const struct wl_seat_listener seat_listener = { @@ -2541,7 +2658,7 @@ static void xdg_output_handle_logical_position(void *data, { CLOG_INFO(LOG, 2, "logical_position [%d, %d]", x, y); - output_t *output = static_cast<output_t *>(data); + GWL_Output *output = static_cast<GWL_Output *>(data); output->position_logical[0] = x; output->position_logical[1] = y; output->has_position_logical = true; @@ -2554,7 +2671,7 @@ static void xdg_output_handle_logical_size(void *data, { CLOG_INFO(LOG, 2, "logical_size [%d, %d]", width, height); - output_t *output = static_cast<output_t *>(data); + GWL_Output *output = static_cast<GWL_Output *>(data); if (output->size_logical[0] != 0 && output->size_logical[1] != 0) { /* Original comment from SDL. */ /* FIXME(@flibit): GNOME has a bug where the logical size does not account for @@ -2586,7 +2703,7 @@ static void xdg_output_handle_done(void *data, struct zxdg_output_v1 * /*xdg_out CLOG_INFO(LOG, 2, "done"); /* NOTE: `xdg-output.done` events are deprecated and only apply below version 3 of the protocol. * `wl-output.done` event will be emitted in version 3 or higher. */ - output_t *output = static_cast<output_t *>(data); + GWL_Output *output = static_cast<GWL_Output *>(data); if (zxdg_output_v1_get_version(output->xdg_output) < 3) { output_handle_done(data, output->wl_output); } @@ -2645,7 +2762,7 @@ static void output_handle_geometry(void *data, physical_width, physical_height); - output_t *output = static_cast<output_t *>(data); + GWL_Output *output = static_cast<GWL_Output *>(data); output->transform = transform; output->make = std::string(make); output->model = std::string(model); @@ -2666,7 +2783,7 @@ static void output_handle_mode(void *data, } CLOG_INFO(LOG, 2, "mode (size=[%d, %d], flags=%u)", width, height, flags); - output_t *output = static_cast<output_t *>(data); + GWL_Output *output = static_cast<GWL_Output *>(data); output->size_native[0] = width; output->size_native[1] = height; @@ -2690,7 +2807,7 @@ static void output_handle_done(void *data, struct wl_output * /*wl_output*/) { CLOG_INFO(LOG, 2, "done"); - output_t *output = static_cast<output_t *>(data); + GWL_Output *output = static_cast<GWL_Output *>(data); int32_t size_native[2]; if (output->transform & WL_OUTPUT_TRANSFORM_90) { size_native[0] = output->size_native[1]; @@ -2718,14 +2835,12 @@ static void output_handle_done(void *data, struct wl_output * /*wl_output*/) static void output_handle_scale(void *data, struct wl_output * /*wl_output*/, const int32_t factor) { CLOG_INFO(LOG, 2, "scale"); - static_cast<output_t *>(data)->scale = factor; + static_cast<GWL_Output *>(data)->scale = factor; if (window_manager) { for (GHOST_IWindow *iwin : window_manager->getWindows()) { GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(iwin); win->outputs_changed_update_scale(); - /* TODO(@campbellbarton): support refreshing the UI when the DPI changes. - * There are glitches when resizing the monitor which would be nice to solve. */ } } } @@ -2747,7 +2862,7 @@ static const struct wl_output_listener output_listener = { #ifndef WITH_GHOST_WAYLAND_LIBDECOR -static CLG_LogRef LOG_WL_XDG_WM_BASE = {"ghost.wl.handle.output"}; +static CLG_LogRef LOG_WL_XDG_WM_BASE = {"ghost.wl.handle.xdg_wm_base"}; # define LOG (&LOG_WL_XDG_WM_BASE) static void shell_handle_ping(void * /*data*/, @@ -2815,35 +2930,35 @@ static void global_handle_add(void *data, /* Log last since it can be noted if the interface was handled or not. */ bool found = true; - struct display_t *display = static_cast<struct display_t *>(data); - if (!strcmp(interface, wl_compositor_interface.name)) { + struct GWL_Display *display = static_cast<struct GWL_Display *>(data); + if (STREQ(interface, wl_compositor_interface.name)) { display->compositor = static_cast<wl_compositor *>( wl_registry_bind(wl_registry, name, &wl_compositor_interface, 3)); } #ifdef WITH_GHOST_WAYLAND_LIBDECOR /* Pass. */ #else - else if (!strcmp(interface, xdg_wm_base_interface.name)) { + else if (STREQ(interface, xdg_wm_base_interface.name)) { display->xdg_shell = static_cast<xdg_wm_base *>( wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1)); xdg_wm_base_add_listener(display->xdg_shell, &shell_listener, nullptr); } - else if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name)) { + else if (STREQ(interface, zxdg_decoration_manager_v1_interface.name)) { display->xdg_decoration_manager = static_cast<zxdg_decoration_manager_v1 *>( wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, 1)); } #endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */ - else if (!strcmp(interface, zxdg_output_manager_v1_interface.name)) { + else if (STREQ(interface, zxdg_output_manager_v1_interface.name)) { display->xdg_output_manager = static_cast<zxdg_output_manager_v1 *>( wl_registry_bind(wl_registry, name, &zxdg_output_manager_v1_interface, 2)); - for (output_t *output : display->outputs) { + for (GWL_Output *output : display->outputs) { output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager, output->wl_output); zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output); } } - else if (!strcmp(interface, wl_output_interface.name)) { - output_t *output = new output_t; + else if (STREQ(interface, wl_output_interface.name)) { + GWL_Output *output = new GWL_Output; output->wl_output = static_cast<wl_output *>( wl_registry_bind(wl_registry, name, &wl_output_interface, 2)); ghost_wl_output_tag(output->wl_output); @@ -2858,33 +2973,33 @@ static void global_handle_add(void *data, zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output); } } - else if (!strcmp(interface, wl_seat_interface.name)) { - input_t *input = new input_t; - input->system = display->system; - input->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - input->data_source = new data_source_t; - input->wl_seat = static_cast<wl_seat *>( + else if (STREQ(interface, wl_seat_interface.name)) { + GWL_Seat *seat = new GWL_Seat; + seat->system = display->system; + seat->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + seat->data_source = new GWL_DataSource; + seat->wl_seat = static_cast<wl_seat *>( wl_registry_bind(wl_registry, name, &wl_seat_interface, 5)); - display->inputs.push_back(input); - wl_seat_add_listener(input->wl_seat, &seat_listener, input); + display->seats.push_back(seat); + wl_seat_add_listener(seat->wl_seat, &seat_listener, seat); } - else if (!strcmp(interface, wl_shm_interface.name)) { + else if (STREQ(interface, wl_shm_interface.name)) { display->shm = static_cast<wl_shm *>( wl_registry_bind(wl_registry, name, &wl_shm_interface, 1)); } - else if (!strcmp(interface, wl_data_device_manager_interface.name)) { + else if (STREQ(interface, wl_data_device_manager_interface.name)) { display->data_device_manager = static_cast<wl_data_device_manager *>( wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 3)); } - else if (!strcmp(interface, zwp_tablet_manager_v2_interface.name)) { + else if (STREQ(interface, zwp_tablet_manager_v2_interface.name)) { display->tablet_manager = static_cast<zwp_tablet_manager_v2 *>( wl_registry_bind(wl_registry, name, &zwp_tablet_manager_v2_interface, 1)); } - else if (!strcmp(interface, zwp_relative_pointer_manager_v1_interface.name)) { + else if (STREQ(interface, zwp_relative_pointer_manager_v1_interface.name)) { display->relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1 *>( wl_registry_bind(wl_registry, name, &zwp_relative_pointer_manager_v1_interface, 1)); } - else if (!strcmp(interface, zwp_pointer_constraints_v1_interface.name)) { + else if (STREQ(interface, zwp_pointer_constraints_v1_interface.name)) { display->pointer_constraints = static_cast<zwp_pointer_constraints_v1 *>( wl_registry_bind(wl_registry, name, &zwp_pointer_constraints_v1_interface, 1)); } @@ -2932,7 +3047,7 @@ static const struct wl_registry_listener registry_listener = { * WAYLAND specific implementation of the #GHOST_System interface. * \{ */ -GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t) +GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new GWL_Display) { wl_log_set_handler_client(ghost_wayland_log_handler); @@ -2968,18 +3083,17 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t) /* Register data device per seat for IPC between Wayland clients. */ if (d->data_device_manager) { - for (input_t *input : d->inputs) { - input->data_device = wl_data_device_manager_get_data_device(d->data_device_manager, - input->wl_seat); - wl_data_device_add_listener(input->data_device, &data_device_listener, input); + for (GWL_Seat *seat : d->seats) { + seat->data_device = wl_data_device_manager_get_data_device(d->data_device_manager, + seat->wl_seat); + wl_data_device_add_listener(seat->data_device, &data_device_listener, seat); } } if (d->tablet_manager) { - for (input_t *input : d->inputs) { - input->tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(d->tablet_manager, - input->wl_seat); - zwp_tablet_seat_v2_add_listener(input->tablet_seat, &tablet_seat_listener, input); + for (GWL_Seat *seat : d->seats) { + seat->tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(d->tablet_manager, seat->wl_seat); + zwp_tablet_seat_v2_add_listener(seat->tablet_seat, &tablet_seat_listener, seat); } } } @@ -2989,9 +3103,36 @@ GHOST_SystemWayland::~GHOST_SystemWayland() display_destroy(d); } +GHOST_TSuccess GHOST_SystemWayland::init() +{ + GHOST_TSuccess success = GHOST_System::init(); + + if (success) { +#ifdef WITH_INPUT_NDOF + m_ndofManager = new GHOST_NDOFManagerUnix(*this); +#endif + return GHOST_kSuccess; + } + + return GHOST_kFailure; +} + bool GHOST_SystemWayland::processEvents(bool waitForEvent) { - const bool fired = getTimerManager()->fireTimers(getMilliSeconds()); + bool any_processed = false; + + if (getTimerManager()->fireTimers(getMilliSeconds())) { + any_processed = true; + } + +#ifdef WITH_INPUT_NDOF + if (static_cast<GHOST_NDOFManagerUnix *>(m_ndofManager)->processEvents()) { + /* As NDOF bypasses WAYLAND event handling, + * never wait for an event when an NDOF event was found. */ + waitForEvent = false; + any_processed = true; + } +#endif /* WITH_INPUT_NDOF */ if (waitForEvent) { wl_display_dispatch(d->display); @@ -3000,65 +3141,79 @@ bool GHOST_SystemWayland::processEvents(bool waitForEvent) wl_display_roundtrip(d->display); } - return fired || (getEventManager()->getNumEvents() > 0); + if ((getEventManager()->getNumEvents() > 0)) { + any_processed = true; + } + + return any_processed; } -int GHOST_SystemWayland::setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) +bool GHOST_SystemWayland::setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) { - return 0; + return false; } GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) const { - if (UNLIKELY(d->inputs.empty())) { + if (UNLIKELY(d->seats.empty())) { return GHOST_kFailure; } - input_t *input = d->inputs[0]; - - bool val; - - /* NOTE: XKB doesn't differentiate between left/right modifiers - * for it's internal modifier state storage. */ - const xkb_mod_mask_t state = xkb_state_serialize_mods(input->xkb_state, XKB_STATE_MODS_ALL); + GWL_Seat *seat = d->seats[0]; -#define MOD_TEST(state, mod) ((mod != XKB_MOD_INVALID) && (state & (1 << mod))) + const xkb_mod_mask_t state = xkb_state_serialize_mods(seat->xkb_state, XKB_STATE_MODS_DEPRESSED); - val = MOD_TEST(state, input->xkb_keymap_mod_index.shift); - keys.set(GHOST_kModifierKeyLeftShift, val); - keys.set(GHOST_kModifierKeyRightShift, val); - - val = MOD_TEST(state, input->xkb_keymap_mod_index.alt); - keys.set(GHOST_kModifierKeyLeftAlt, val); - keys.set(GHOST_kModifierKeyRightAlt, val); - - val = MOD_TEST(state, input->xkb_keymap_mod_index.ctrl); - keys.set(GHOST_kModifierKeyLeftControl, val); - keys.set(GHOST_kModifierKeyRightControl, val); - - val = MOD_TEST(state, input->xkb_keymap_mod_index.logo); - keys.set(GHOST_kModifierKeyOS, val); - - val = MOD_TEST(state, input->xkb_keymap_mod_index.num); - keys.set(GHOST_kModifierKeyNum, val); + /* Use local #WGL_KeyboardDepressedState to check which key is pressed. + * Use XKB as the source of truth, if there is any discrepancy. */ + for (int i = 0; i < MOD_INDEX_NUM; i++) { + if (UNLIKELY(seat->xkb_keymap_mod_index[i] == XKB_MOD_INVALID)) { + continue; + } + const GWL_ModifierInfo &mod_info = g_modifier_info_table[i]; + const bool val = (state & (1 << seat->xkb_keymap_mod_index[i])) != 0; + bool val_l = seat->key_depressed.mods[GHOST_KEY_MODIFIER_TO_INDEX(mod_info.key_l)] > 0; + bool val_r = seat->key_depressed.mods[GHOST_KEY_MODIFIER_TO_INDEX(mod_info.key_r)] > 0; + + /* This shouldn't be needed, but guard against any possibility of modifiers being stuck. + * Warn so if this happens it can be investigated. */ + if (val) { + if (UNLIKELY(!(val_l || val_r))) { + CLOG_WARN(&LOG_WL_KEYBOARD_DEPRESSED_STATE, + "modifier (%s) state is inconsistent (held keys do not match XKB)", + mod_info.display_name); + /* Picking the left is arbitrary. */ + val_l = true; + } + } + else { + if (UNLIKELY(val_l || val_r)) { + CLOG_WARN(&LOG_WL_KEYBOARD_DEPRESSED_STATE, + "modifier (%s) state is inconsistent (released keys do not match XKB)", + mod_info.display_name); + val_l = false; + val_r = false; + } + } -#undef MOD_TEST + keys.set(mod_info.mod_l, val_l); + keys.set(mod_info.mod_r, val_r); + } return GHOST_kSuccess; } GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const { - if (UNLIKELY(d->inputs.empty())) { + if (UNLIKELY(d->seats.empty())) { return GHOST_kFailure; } - input_t *input = d->inputs[0]; - input_state_pointer_t *input_state = input_state_pointer_active(input); - if (!input_state) { + GWL_Seat *seat = d->seats[0]; + GWL_SeatStatePointer *seat_state_pointer = seat_state_pointer_active(seat); + if (!seat_state_pointer) { return GHOST_kFailure; } - buttons = input_state->buttons; + buttons = seat_state_pointer->buttons; return GHOST_kSuccess; } @@ -3071,15 +3226,15 @@ char *GHOST_SystemWayland::getClipboard(bool /*selection*/) const void GHOST_SystemWayland::putClipboard(const char *buffer, bool /*selection*/) const { - if (UNLIKELY(!d->data_device_manager || d->inputs.empty())) { + if (UNLIKELY(!d->data_device_manager || d->seats.empty())) { return; } - input_t *input = d->inputs[0]; + GWL_Seat *seat = d->seats[0]; - std::lock_guard lock{input->data_source_mutex}; + std::lock_guard lock{seat->data_source_mutex}; - data_source_t *data_source = input->data_source; + GWL_DataSource *data_source = seat->data_source; /* Copy buffer. */ free(data_source->buffer_out); @@ -3089,15 +3244,15 @@ void GHOST_SystemWayland::putClipboard(const char *buffer, bool /*selection*/) c data_source->data_source = wl_data_device_manager_create_data_source(d->data_device_manager); - wl_data_source_add_listener(data_source->data_source, &data_source_listener, input); + wl_data_source_add_listener(data_source->data_source, &data_source_listener, seat); for (const std::string &type : mime_send) { wl_data_source_offer(data_source->data_source, type.c_str()); } - if (input->data_device) { + if (seat->data_device) { wl_data_device_set_selection( - input->data_device, data_source->data_source, input->data_source_serial); + seat->data_device, data_source->data_source, seat->data_source_serial); } } @@ -3107,18 +3262,18 @@ uint8_t GHOST_SystemWayland::getNumDisplays() const } static GHOST_TSuccess getCursorPositionClientRelative_impl( - const input_state_pointer_t *input_state, + const GWL_SeatStatePointer *seat_state_pointer, const GHOST_WindowWayland *win, int32_t &x, int32_t &y) { const wl_fixed_t scale = win->scale(); - x = wl_fixed_to_int(scale * input_state->xy[0]); - y = wl_fixed_to_int(scale * input_state->xy[1]); + x = wl_fixed_to_int(scale * seat_state_pointer->xy[0]); + y = wl_fixed_to_int(scale * seat_state_pointer->xy[1]); return GHOST_kSuccess; } -static GHOST_TSuccess setCursorPositionClientRelative_impl(input_t *input, +static GHOST_TSuccess setCursorPositionClientRelative_impl(GWL_Seat *seat, GHOST_WindowWayland *win, const int32_t x, const int32_t y) @@ -3126,7 +3281,7 @@ static GHOST_TSuccess setCursorPositionClientRelative_impl(input_t *input, /* NOTE: WAYLAND doesn't support warping the cursor. * However when grab is enabled, we already simulate a cursor location * so that can be set to a new location. */ - if (!input->relative_pointer) { + if (!seat->relative_pointer) { return GHOST_kFailure; } const wl_fixed_t scale = win->scale(); @@ -3136,7 +3291,7 @@ static GHOST_TSuccess setCursorPositionClientRelative_impl(input_t *input, }; /* As the cursor was "warped" generate an event at the new location. */ - relative_pointer_handle_relative_motion_impl(input, win, xy_next); + relative_pointer_handle_relative_motion_impl(seat, win, xy_next); return GHOST_kSuccess; } @@ -3145,60 +3300,60 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorPositionClientRelative(const GHOST_ int32_t &x, int32_t &y) const { - if (UNLIKELY(d->inputs.empty())) { + if (UNLIKELY(d->seats.empty())) { return GHOST_kFailure; } - input_t *input = d->inputs[0]; - input_state_pointer_t *input_state = input_state_pointer_active(input); - if (!input_state || !input_state->wl_surface) { + GWL_Seat *seat = d->seats[0]; + GWL_SeatStatePointer *seat_state_pointer = seat_state_pointer_active(seat); + if (!seat_state_pointer || !seat_state_pointer->wl_surface) { return GHOST_kFailure; } const GHOST_WindowWayland *win = static_cast<const GHOST_WindowWayland *>(window); - return getCursorPositionClientRelative_impl(input_state, win, x, y); + return getCursorPositionClientRelative_impl(seat_state_pointer, win, x, y); } GHOST_TSuccess GHOST_SystemWayland::setCursorPositionClientRelative(GHOST_IWindow *window, const int32_t x, const int32_t y) { - if (UNLIKELY(d->inputs.empty())) { + if (UNLIKELY(d->seats.empty())) { return GHOST_kFailure; } - input_t *input = d->inputs[0]; + GWL_Seat *seat = d->seats[0]; GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(window); - return setCursorPositionClientRelative_impl(input, win, x, y); + return setCursorPositionClientRelative_impl(seat, win, x, y); } GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(int32_t &x, int32_t &y) const { - if (UNLIKELY(d->inputs.empty())) { + if (UNLIKELY(d->seats.empty())) { return GHOST_kFailure; } - input_t *input = d->inputs[0]; - input_state_pointer_t *input_state = input_state_pointer_active(input); - if (!input_state) { + GWL_Seat *seat = d->seats[0]; + GWL_SeatStatePointer *seat_state_pointer = seat_state_pointer_active(seat); + if (!seat_state_pointer) { return GHOST_kFailure; } - if (wl_surface *focus_surface = input_state->wl_surface) { - GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface); - return getCursorPositionClientRelative_impl(input_state, win, x, y); + if (wl_surface *wl_surface_focus = seat_state_pointer->wl_surface) { + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); + return getCursorPositionClientRelative_impl(seat_state_pointer, win, x, y); } return GHOST_kFailure; } GHOST_TSuccess GHOST_SystemWayland::setCursorPosition(const int32_t x, const int32_t y) { - if (UNLIKELY(d->inputs.empty())) { + if (UNLIKELY(d->seats.empty())) { return GHOST_kFailure; } - input_t *input = d->inputs[0]; + GWL_Seat *seat = d->seats[0]; /* Intentionally different from `getCursorPosition` which supports both tablet & pointer. * In the case of setting the cursor location, tablets don't support this. */ - if (wl_surface *focus_surface = input->pointer.wl_surface) { - GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface); - return setCursorPositionClientRelative_impl(input, win, x, y); + if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) { + GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus); + return setCursorPositionClientRelative_impl(seat, win, x, y); } return GHOST_kFailure; } @@ -3218,7 +3373,7 @@ void GHOST_SystemWayland::getAllDisplayDimensions(uint32_t &width, uint32_t &hei int32_t xy_min[2] = {INT32_MAX, INT32_MAX}; int32_t xy_max[2] = {INT32_MIN, INT32_MIN}; - for (const output_t *output : d->outputs) { + for (const GWL_Output *output : d->outputs) { int32_t xy[2] = {0, 0}; if (output->has_position_logical) { xy[0] = output->position_logical[0]; @@ -3363,32 +3518,32 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title, * Show the buffer defined by #cursor_buffer_set without changing anything else, * so #cursor_buffer_hide can be used to display it again. * - * The caller is responsible for setting `input->cursor.visible`. + * The caller is responsible for setting `seat->cursor.visible`. */ -static void cursor_buffer_show(const input_t *input) +static void cursor_buffer_show(const GWL_Seat *seat) { - const cursor_t *c = &input->cursor; + const GWL_Cursor *c = &seat->cursor; - if (input->wl_pointer) { - const int scale = c->is_custom ? c->custom_scale : input->pointer.theme_scale; + if (seat->wl_pointer) { + const int scale = c->is_custom ? c->custom_scale : seat->pointer.theme_scale; const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / scale; const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / scale; - if (input->wl_pointer) { + if (seat->wl_pointer) { wl_pointer_set_cursor( - input->wl_pointer, input->pointer.serial, c->wl_surface, hotspot_x, hotspot_y); + seat->wl_pointer, seat->pointer.serial, c->wl_surface, hotspot_x, hotspot_y); } } - if (!input->tablet_tools.empty()) { - const int scale = c->is_custom ? c->custom_scale : input->tablet.theme_scale; + if (!seat->tablet_tools.empty()) { + const int scale = c->is_custom ? c->custom_scale : seat->tablet.theme_scale; const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / scale; const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / scale; - for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : input->tablet_tools) { - tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>( + for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->tablet_tools) { + GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>( zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2)); zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2, - input->tablet.serial, - tool_input->cursor_surface, + seat->tablet.serial, + tablet_tool->wl_surface_cursor, hotspot_x, hotspot_y); } @@ -3399,13 +3554,13 @@ static void cursor_buffer_show(const input_t *input) * Hide the buffer defined by #cursor_buffer_set without changing anything else, * so #cursor_buffer_show can be used to display it again. * - * The caller is responsible for setting `input->cursor.visible`. + * The caller is responsible for setting `seat->cursor.visible`. */ -static void cursor_buffer_hide(const input_t *input) +static void cursor_buffer_hide(const GWL_Seat *seat) { - wl_pointer_set_cursor(input->wl_pointer, input->pointer.serial, nullptr, 0, 0); - for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : input->tablet_tools) { - zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2, input->tablet.serial, nullptr, 0, 0); + wl_pointer_set_cursor(seat->wl_pointer, seat->pointer.serial, nullptr, 0, 0); + for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->tablet_tools) { + zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2, seat->tablet.serial, nullptr, 0, 0); } } @@ -3426,12 +3581,12 @@ static int cursor_buffer_compatible_scale_from_image(const struct wl_cursor_imag return scale; } -static void cursor_buffer_set_surface_impl(const input_t *input, +static void cursor_buffer_set_surface_impl(const GWL_Seat *seat, wl_buffer *buffer, struct wl_surface *wl_surface, const int scale) { - const wl_cursor_image *wl_image = &input->cursor.wl_image; + const wl_cursor_image *wl_image = &seat->cursor.wl_image; const int32_t image_size_x = int32_t(wl_image->width); const int32_t image_size_y = int32_t(wl_image->height); GHOST_ASSERT((image_size_x % scale) == 0 && (image_size_y % scale) == 0, @@ -3443,40 +3598,40 @@ static void cursor_buffer_set_surface_impl(const input_t *input, wl_surface_commit(wl_surface); } -static void cursor_buffer_set(const input_t *input, wl_buffer *buffer) +static void cursor_buffer_set(const GWL_Seat *seat, wl_buffer *buffer) { - const cursor_t *c = &input->cursor; - const wl_cursor_image *wl_image = &input->cursor.wl_image; + const GWL_Cursor *c = &seat->cursor; + const wl_cursor_image *wl_image = &seat->cursor.wl_image; const bool visible = (c->visible && c->is_hardware); /* This is a requirement of WAYLAND, when this isn't the case, * it causes Blender's window to close intermittently. */ - if (input->wl_pointer) { + if (seat->wl_pointer) { const int scale = cursor_buffer_compatible_scale_from_image( - wl_image, c->is_custom ? c->custom_scale : input->pointer.theme_scale); + wl_image, c->is_custom ? c->custom_scale : seat->pointer.theme_scale); const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale; const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale; - cursor_buffer_set_surface_impl(input, buffer, c->wl_surface, scale); - wl_pointer_set_cursor(input->wl_pointer, - input->pointer.serial, + cursor_buffer_set_surface_impl(seat, buffer, c->wl_surface, scale); + wl_pointer_set_cursor(seat->wl_pointer, + seat->pointer.serial, visible ? c->wl_surface : nullptr, hotspot_x, hotspot_y); } /* Set the cursor for all tablet tools as well. */ - if (!input->tablet_tools.empty()) { + if (!seat->tablet_tools.empty()) { const int scale = cursor_buffer_compatible_scale_from_image( - wl_image, c->is_custom ? c->custom_scale : input->tablet.theme_scale); + wl_image, c->is_custom ? c->custom_scale : seat->tablet.theme_scale); const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale; const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale; - for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : input->tablet_tools) { - tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>( + for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->tablet_tools) { + GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>( zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2)); - cursor_buffer_set_surface_impl(input, buffer, tool_input->cursor_surface, scale); + cursor_buffer_set_surface_impl(seat, buffer, tablet_tool->wl_surface_cursor, scale); zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2, - input->tablet.serial, - visible ? tool_input->cursor_surface : nullptr, + seat->tablet.serial, + visible ? tablet_tool->wl_surface_cursor : nullptr, hotspot_x, hotspot_y); } @@ -3489,12 +3644,12 @@ enum eCursorSetMode { CURSOR_VISIBLE_ONLY_SHOW, }; -static void cursor_visible_set(input_t *input, +static void cursor_visible_set(GWL_Seat *seat, const bool visible, const bool is_hardware, const enum eCursorSetMode set_mode) { - cursor_t *cursor = &input->cursor; + GWL_Cursor *cursor = &seat->cursor; const bool was_visible = cursor->is_hardware && cursor->visible; const bool use_visible = is_hardware && visible; @@ -3514,12 +3669,12 @@ static void cursor_visible_set(input_t *input, if (use_visible) { if (!was_visible) { - cursor_buffer_show(input); + cursor_buffer_show(seat); } } else { if (was_visible) { - cursor_buffer_hide(input); + cursor_buffer_hide(seat); } } cursor->visible = visible; @@ -3545,7 +3700,7 @@ static bool cursor_is_software(const GHOST_TGrabCursorMode mode, const bool use_ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(const GHOST_TStandardCursor shape) { - if (UNLIKELY(d->inputs.empty())) { + if (UNLIKELY(d->seats.empty())) { return GHOST_kFailure; } auto cursor_find = cursors.find(shape); @@ -3553,13 +3708,12 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(const GHOST_TStandardCursor s cursors.at(GHOST_kStandardCursorDefault) : (*cursor_find).second; - input_t *input = d->inputs[0]; - cursor_t *c = &input->cursor; + GWL_Seat *seat = d->seats[0]; + GWL_Cursor *c = &seat->cursor; if (!c->wl_theme) { - /* The cursor surface hasn't entered an output yet. Initialize theme with scale 1. */ - c->wl_theme = wl_cursor_theme_load( - c->theme_name.c_str(), c->size, d->inputs[0]->system->shm()); + /* The cursor wl_surface hasn't entered an output yet. Initialize theme with scale 1. */ + c->wl_theme = wl_cursor_theme_load(c->theme_name.c_str(), c->size, d->seats[0]->system->shm()); } wl_cursor *cursor = wl_cursor_theme_get_cursor(c->wl_theme, cursor_name); @@ -3580,7 +3734,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(const GHOST_TStandardCursor s c->wl_buffer = buffer; c->wl_image = *image; - cursor_buffer_set(input, buffer); + cursor_buffer_set(seat, buffer); return GHOST_kSuccess; } @@ -3606,11 +3760,11 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap, const int hotY, const bool /*canInvertColor*/) { - if (UNLIKELY(d->inputs.empty())) { + if (UNLIKELY(d->seats.empty())) { return GHOST_kFailure; } - cursor_t *cursor = &d->inputs[0]->cursor; + GWL_Cursor *cursor = &d->seats[0]->cursor; if (cursor->custom_data) { munmap(cursor->custom_data, cursor->custom_data_size); @@ -3666,14 +3820,14 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap, cursor->wl_image.hotspot_x = uint32_t(hotX); cursor->wl_image.hotspot_y = uint32_t(hotY); - cursor_buffer_set(d->inputs[0], buffer); + cursor_buffer_set(d->seats[0], buffer); return GHOST_kSuccess; } GHOST_TSuccess GHOST_SystemWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitmap) { - cursor_t *cursor = &d->inputs[0]->cursor; + GWL_Cursor *cursor = &d->seats[0]->cursor; if (cursor->custom_data == nullptr) { return GHOST_kFailure; } @@ -3694,12 +3848,12 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitma GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(const bool visible) { - if (UNLIKELY(d->inputs.empty())) { + if (UNLIKELY(d->seats.empty())) { return GHOST_kFailure; } - input_t *input = d->inputs[0]; - cursor_visible_set(input, visible, input->cursor.is_hardware, CURSOR_VISIBLE_ALWAYS_SET); + GWL_Seat *seat = d->seats[0]; + cursor_visible_set(seat, visible, seat->cursor.is_hardware, CURSOR_VISIBLE_ALWAYS_SET); return GHOST_kSuccess; } @@ -3718,13 +3872,13 @@ bool GHOST_SystemWayland::supportsWindowPosition() bool GHOST_SystemWayland::getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCursorMode mode) { - if (UNLIKELY(d->inputs.empty())) { + if (UNLIKELY(d->seats.empty())) { return false; } #ifdef USE_GNOME_CONFINE_HACK - input_t *input = d->inputs[0]; - const bool use_software_confine = input->use_pointer_software_confine; + GWL_Seat *seat = d->seats[0]; + const bool use_software_confine = seat->use_pointer_software_confine; #else const bool use_software_confine = false; #endif @@ -3734,7 +3888,7 @@ bool GHOST_SystemWayland::getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCurso #ifdef USE_GNOME_CONFINE_HACK static bool setCursorGrab_use_software_confine(const GHOST_TGrabCursorMode mode, - wl_surface *surface) + wl_surface *wl_surface) { # ifndef USE_GNOME_CONFINE_HACK_ALWAYS_ON if (use_gnome_confine_hack == false) { @@ -3744,7 +3898,7 @@ static bool setCursorGrab_use_software_confine(const GHOST_TGrabCursorMode mode, if (mode != GHOST_kGrabNormal) { return false; } - const GHOST_WindowWayland *win = ghost_wl_surface_user_data(surface); + const GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface); if (!win) { return false; } @@ -3758,11 +3912,11 @@ static bool setCursorGrab_use_software_confine(const GHOST_TGrabCursorMode mode, } #endif -static input_grab_state_t input_grab_state_from_mode(const GHOST_TGrabCursorMode mode, - const bool use_software_confine) +static GWL_SeatStateGrab seat_grab_state_from_mode(const GHOST_TGrabCursorMode mode, + const bool use_software_confine) { /* Initialize all members. */ - const struct input_grab_state_t grab_state = { + const struct GWL_SeatStateGrab grab_state = { /* Warping happens to require software cursor which also hides. */ .use_lock = ELEM(mode, GHOST_kGrabWrap, GHOST_kGrabHide) || use_software_confine, .use_confine = (mode == GHOST_kGrabNormal) && (use_software_confine == false), @@ -3781,44 +3935,45 @@ static const char *ghost_wl_surface_tag_id = "GHOST-window"; static const char *ghost_wl_surface_cursor_pointer_tag_id = "GHOST-cursor-pointer"; static const char *ghost_wl_surface_cursor_tablet_tag_id = "GHOST-cursor-tablet"; -bool ghost_wl_output_own(const struct wl_output *output) +bool ghost_wl_output_own(const struct wl_output *wl_output) { - return wl_proxy_get_tag((struct wl_proxy *)output) == &ghost_wl_output_tag_id; + return wl_proxy_get_tag((struct wl_proxy *)wl_output) == &ghost_wl_output_tag_id; } -bool ghost_wl_surface_own(const struct wl_surface *surface) +bool ghost_wl_surface_own(const struct wl_surface *wl_surface) { - return wl_proxy_get_tag((struct wl_proxy *)surface) == &ghost_wl_surface_tag_id; + return wl_proxy_get_tag((struct wl_proxy *)wl_surface) == &ghost_wl_surface_tag_id; } -bool ghost_wl_surface_own_cursor_pointer(const struct wl_surface *surface) +bool ghost_wl_surface_own_cursor_pointer(const struct wl_surface *wl_surface) { - return wl_proxy_get_tag((struct wl_proxy *)surface) == &ghost_wl_surface_cursor_pointer_tag_id; + return wl_proxy_get_tag((struct wl_proxy *)wl_surface) == + &ghost_wl_surface_cursor_pointer_tag_id; } -bool ghost_wl_surface_own_cursor_tablet(const struct wl_surface *surface) +bool ghost_wl_surface_own_cursor_tablet(const struct wl_surface *wl_surface) { - return wl_proxy_get_tag((struct wl_proxy *)surface) == &ghost_wl_surface_cursor_tablet_tag_id; + return wl_proxy_get_tag((struct wl_proxy *)wl_surface) == &ghost_wl_surface_cursor_tablet_tag_id; } -void ghost_wl_output_tag(struct wl_output *output) +void ghost_wl_output_tag(struct wl_output *wl_output) { - wl_proxy_set_tag((struct wl_proxy *)output, &ghost_wl_output_tag_id); + wl_proxy_set_tag((struct wl_proxy *)wl_output, &ghost_wl_output_tag_id); } -void ghost_wl_surface_tag(struct wl_surface *surface) +void ghost_wl_surface_tag(struct wl_surface *wl_surface) { - wl_proxy_set_tag((struct wl_proxy *)surface, &ghost_wl_surface_tag_id); + wl_proxy_set_tag((struct wl_proxy *)wl_surface, &ghost_wl_surface_tag_id); } -void ghost_wl_surface_tag_cursor_pointer(struct wl_surface *surface) +void ghost_wl_surface_tag_cursor_pointer(struct wl_surface *wl_surface) { - wl_proxy_set_tag((struct wl_proxy *)surface, &ghost_wl_surface_cursor_pointer_tag_id); + wl_proxy_set_tag((struct wl_proxy *)wl_surface, &ghost_wl_surface_cursor_pointer_tag_id); } -void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *surface) +void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *wl_surface) { - wl_proxy_set_tag((struct wl_proxy *)surface, &ghost_wl_surface_cursor_tablet_tag_id); + wl_proxy_set_tag((struct wl_proxy *)wl_surface, &ghost_wl_surface_cursor_tablet_tag_id); } /** \} */ @@ -3860,7 +4015,7 @@ zxdg_decoration_manager_v1 *GHOST_SystemWayland::xdg_decoration_manager() #endif /* !WITH_GHOST_WAYLAND_LIBDECOR */ -const std::vector<output_t *> &GHOST_SystemWayland::outputs() const +const std::vector<GWL_Output *> &GHOST_SystemWayland::outputs() const { return d->outputs; } @@ -3876,19 +4031,20 @@ wl_shm *GHOST_SystemWayland::shm() const /** \name Public WAYLAND Query Access * \{ */ -struct output_t *ghost_wl_output_user_data(struct wl_output *wl_output) +struct GWL_Output *ghost_wl_output_user_data(struct wl_output *wl_output) { GHOST_ASSERT(wl_output, "output must not be NULL"); GHOST_ASSERT(ghost_wl_output_own(wl_output), "output is not owned by GHOST"); - output_t *output = static_cast<output_t *>(wl_output_get_user_data(wl_output)); + GWL_Output *output = static_cast<GWL_Output *>(wl_output_get_user_data(wl_output)); return output; } -GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *surface) +GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *wl_surface) { - GHOST_ASSERT(surface, "surface must not be NULL"); - GHOST_ASSERT(ghost_wl_surface_own(surface), "surface is not owned by GHOST"); - GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(wl_surface_get_user_data(surface)); + GHOST_ASSERT(wl_surface, "wl_surface must not be NULL"); + GHOST_ASSERT(ghost_wl_surface_own(wl_surface), "wl_surface is not owned by GHOST"); + GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>( + wl_surface_get_user_data(wl_surface)); return win; } @@ -3905,20 +4061,20 @@ void GHOST_SystemWayland::selection_set(const std::string &selection) this->selection = selection; } -void GHOST_SystemWayland::window_surface_unref(const wl_surface *surface) +void GHOST_SystemWayland::window_surface_unref(const wl_surface *wl_surface) { #define SURFACE_CLEAR_PTR(surface_test) \ - if (surface_test == surface) { \ + if (surface_test == wl_surface) { \ surface_test = nullptr; \ } \ ((void)0); /* Only clear window surfaces (not cursors, off-screen surfaces etc). */ - for (input_t *input : d->inputs) { - SURFACE_CLEAR_PTR(input->pointer.wl_surface); - SURFACE_CLEAR_PTR(input->tablet.wl_surface); - SURFACE_CLEAR_PTR(input->keyboard.wl_surface); - SURFACE_CLEAR_PTR(input->focus_dnd); + for (GWL_Seat *seat : d->seats) { + SURFACE_CLEAR_PTR(seat->pointer.wl_surface); + SURFACE_CLEAR_PTR(seat->tablet.wl_surface); + SURFACE_CLEAR_PTR(seat->keyboard.wl_surface); + SURFACE_CLEAR_PTR(seat->wl_surface_focus_dnd); } #undef SURFACE_CLEAR_PTR } @@ -3928,7 +4084,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod int32_t init_grab_xy[2], const GHOST_Rect *wrap_bounds, const GHOST_TAxisFlag wrap_axis, - wl_surface *surface, + wl_surface *wl_surface, const int scale) { /* Ignore, if the required protocols are not supported. */ @@ -3936,7 +4092,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod return GHOST_kFailure; } - if (UNLIKELY(d->inputs.empty())) { + if (UNLIKELY(d->seats.empty())) { return GHOST_kFailure; } /* No change, success. */ @@ -3944,20 +4100,20 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod return GHOST_kSuccess; } - input_t *input = d->inputs[0]; + GWL_Seat *seat = d->seats[0]; #ifdef USE_GNOME_CONFINE_HACK - const bool was_software_confine = input->use_pointer_software_confine; - const bool use_software_confine = setCursorGrab_use_software_confine(mode, surface); + const bool was_software_confine = seat->use_pointer_software_confine; + const bool use_software_confine = setCursorGrab_use_software_confine(mode, wl_surface); #else const bool was_software_confine = false; const bool use_software_confine = false; #endif - const struct input_grab_state_t grab_state_prev = input_grab_state_from_mode( - mode_current, was_software_confine); - const struct input_grab_state_t grab_state_next = input_grab_state_from_mode( - mode, use_software_confine); + const struct GWL_SeatStateGrab grab_state_prev = seat_grab_state_from_mode(mode_current, + was_software_confine); + const struct GWL_SeatStateGrab grab_state_next = seat_grab_state_from_mode(mode, + use_software_confine); /* Check for wrap as #supportsCursorWarp isn't supported. */ const bool use_visible = !(ELEM(mode, GHOST_kGrabHide, GHOST_kGrabWrap) || use_software_confine); @@ -3965,17 +4121,17 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod /* Only hide so the cursor is not made visible before it's location is restored. * This function is called again at the end of this function which only shows. */ - cursor_visible_set(input, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_HIDE); + cursor_visible_set(seat, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_HIDE); /* Switching from one grab mode to another, * in this case disable the current locks as it makes logic confusing, * postpone changing the cursor to avoid flickering. */ if (!grab_state_next.use_lock) { - if (input->relative_pointer) { - zwp_relative_pointer_v1_destroy(input->relative_pointer); - input->relative_pointer = nullptr; + if (seat->relative_pointer) { + zwp_relative_pointer_v1_destroy(seat->relative_pointer); + seat->relative_pointer = nullptr; } - if (input->locked_pointer) { + if (seat->locked_pointer) { /* Potentially add a motion event so the application has updated X/Y coordinates. */ int32_t xy_motion[2] = {0, 0}; bool xy_motion_create_event = false; @@ -3984,7 +4140,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod if (mode_current == GHOST_kGrabWrap) { /* Since this call is initiated by Blender, we can be sure the window wasn't closed * by logic outside this function - as the window was needed to make this call. */ - int32_t xy_next[2] = {UNPACK2(input->pointer.xy)}; + int32_t xy_next[2] = {UNPACK2(seat->pointer.xy)}; GHOST_Rect bounds_scale; @@ -3996,26 +4152,26 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod bounds_scale.wrapPoint(UNPACK2(xy_next), 0, wrap_axis); /* Push an event so the new location is registered. */ - if ((xy_next[0] != input->pointer.xy[0]) || (xy_next[1] != input->pointer.xy[1])) { + if ((xy_next[0] != seat->pointer.xy[0]) || (xy_next[1] != seat->pointer.xy[1])) { xy_motion[0] = xy_next[0]; xy_motion[1] = xy_next[1]; xy_motion_create_event = true; } - input->pointer.xy[0] = xy_next[0]; - input->pointer.xy[1] = xy_next[1]; + seat->pointer.xy[0] = xy_next[0]; + seat->pointer.xy[1] = xy_next[1]; - zwp_locked_pointer_v1_set_cursor_position_hint(input->locked_pointer, UNPACK2(xy_next)); - wl_surface_commit(surface); + zwp_locked_pointer_v1_set_cursor_position_hint(seat->locked_pointer, UNPACK2(xy_next)); + wl_surface_commit(wl_surface); } else if (mode_current == GHOST_kGrabHide) { - if ((init_grab_xy[0] != input->grab_lock_xy[0]) || - (init_grab_xy[1] != input->grab_lock_xy[1])) { + if ((init_grab_xy[0] != seat->grab_lock_xy[0]) || + (init_grab_xy[1] != seat->grab_lock_xy[1])) { const wl_fixed_t xy_next[2] = { wl_fixed_from_int(init_grab_xy[0]) / scale, wl_fixed_from_int(init_grab_xy[1]) / scale, }; - zwp_locked_pointer_v1_set_cursor_position_hint(input->locked_pointer, UNPACK2(xy_next)); - wl_surface_commit(surface); + zwp_locked_pointer_v1_set_cursor_position_hint(seat->locked_pointer, UNPACK2(xy_next)); + wl_surface_commit(wl_surface); /* NOTE(@campbellbarton): The new cursor position is a hint, * it's possible the hint is ignored. It doesn't seem like there is a good way to @@ -4028,31 +4184,31 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod #ifdef USE_GNOME_CONFINE_HACK else if (mode_current == GHOST_kGrabNormal) { if (was_software_confine) { - zwp_locked_pointer_v1_set_cursor_position_hint(input->locked_pointer, - UNPACK2(input->pointer.xy)); - wl_surface_commit(surface); + zwp_locked_pointer_v1_set_cursor_position_hint(seat->locked_pointer, + UNPACK2(seat->pointer.xy)); + wl_surface_commit(wl_surface); } } #endif if (xy_motion_create_event) { - input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(), - GHOST_kEventCursorMove, - ghost_wl_surface_user_data(surface), - wl_fixed_to_int(scale * xy_motion[0]), - wl_fixed_to_int(scale * xy_motion[1]), - GHOST_TABLET_DATA_NONE)); + seat->system->pushEvent(new GHOST_EventCursor(seat->system->getMilliSeconds(), + GHOST_kEventCursorMove, + ghost_wl_surface_user_data(wl_surface), + wl_fixed_to_int(scale * xy_motion[0]), + wl_fixed_to_int(scale * xy_motion[1]), + GHOST_TABLET_DATA_NONE)); } - zwp_locked_pointer_v1_destroy(input->locked_pointer); - input->locked_pointer = nullptr; + zwp_locked_pointer_v1_destroy(seat->locked_pointer); + seat->locked_pointer = nullptr; } } if (!grab_state_next.use_confine) { - if (input->confined_pointer) { - zwp_confined_pointer_v1_destroy(input->confined_pointer); - input->confined_pointer = nullptr; + if (seat->confined_pointer) { + zwp_confined_pointer_v1_destroy(seat->confined_pointer); + seat->confined_pointer = nullptr; } } @@ -4063,32 +4219,32 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod * possible to support #GHOST_kGrabWrap by pragmatically settings it's coordinates. * An alternative could be to draw the cursor in software (and hide the real cursor), * or just accept a locked cursor on WAYLAND. */ - input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer( - d->relative_pointer_manager, input->wl_pointer); + seat->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer( + d->relative_pointer_manager, seat->wl_pointer); zwp_relative_pointer_v1_add_listener( - input->relative_pointer, &relative_pointer_listener, input); - input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer( + seat->relative_pointer, &relative_pointer_listener, seat); + seat->locked_pointer = zwp_pointer_constraints_v1_lock_pointer( d->pointer_constraints, - surface, - input->wl_pointer, + wl_surface, + seat->wl_pointer, nullptr, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); } if (mode == GHOST_kGrabHide) { /* Set the initial position to detect any changes when un-grabbing, * otherwise the unlocked cursor defaults to un-locking in-place. */ - init_grab_xy[0] = wl_fixed_to_int(scale * input->pointer.xy[0]); - init_grab_xy[1] = wl_fixed_to_int(scale * input->pointer.xy[1]); - input->grab_lock_xy[0] = init_grab_xy[0]; - input->grab_lock_xy[1] = init_grab_xy[1]; + init_grab_xy[0] = wl_fixed_to_int(scale * seat->pointer.xy[0]); + init_grab_xy[1] = wl_fixed_to_int(scale * seat->pointer.xy[1]); + seat->grab_lock_xy[0] = init_grab_xy[0]; + seat->grab_lock_xy[1] = init_grab_xy[1]; } } else if (grab_state_next.use_confine) { if (!grab_state_prev.use_confine) { - input->confined_pointer = zwp_pointer_constraints_v1_confine_pointer( + seat->confined_pointer = zwp_pointer_constraints_v1_confine_pointer( d->pointer_constraints, - surface, - input->wl_pointer, + wl_surface, + seat->wl_pointer, nullptr, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); } @@ -4096,10 +4252,10 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod } /* Only show so the cursor is made visible as the last step. */ - cursor_visible_set(input, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_SHOW); + cursor_visible_set(seat, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_SHOW); #ifdef USE_GNOME_CONFINE_HACK - input->use_pointer_software_confine = use_software_confine; + seat->use_pointer_software_confine = use_software_confine; #endif return GHOST_kSuccess; diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h index bdf5f2fc273..caea7b0d748 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.h +++ b/intern/ghost/intern/GHOST_SystemWayland.h @@ -31,11 +31,11 @@ class GHOST_WindowWayland; -struct display_t; +struct GWL_Display; -bool ghost_wl_output_own(const struct wl_output *output); -void ghost_wl_output_tag(struct wl_output *output); -struct output_t *ghost_wl_output_user_data(struct wl_output *output); +bool ghost_wl_output_own(const struct wl_output *wl_output); +void ghost_wl_output_tag(struct wl_output *wl_output); +struct GWL_Output *ghost_wl_output_user_data(struct wl_output *wl_output); bool ghost_wl_surface_own(const struct wl_surface *surface); void ghost_wl_surface_tag(struct wl_surface *surface); @@ -55,7 +55,7 @@ void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *surface); bool ghost_wl_dynload_libraries(); #endif -struct output_t { +struct GWL_Output { struct wl_output *wl_output = nullptr; struct zxdg_output_v1 *xdg_output = nullptr; /** Dimensions in pixels. */ @@ -93,9 +93,11 @@ class GHOST_SystemWayland : public GHOST_System { ~GHOST_SystemWayland() override; + GHOST_TSuccess init(); + bool processEvents(bool waitForEvent) override; - int setConsoleWindowState(GHOST_TConsoleWindowState action) override; + bool setConsoleWindowState(GHOST_TConsoleWindowState action) override; GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const override; @@ -171,7 +173,7 @@ class GHOST_SystemWayland : public GHOST_System { zxdg_decoration_manager_v1 *xdg_decoration_manager(); #endif - const std::vector<output_t *> &outputs() const; + const std::vector<GWL_Output *> &outputs() const; wl_shm *shm() const; @@ -180,17 +182,17 @@ class GHOST_SystemWayland : public GHOST_System { void selection_set(const std::string &selection); /** Clear all references to this surface to prevent accessing NULL pointers. */ - void window_surface_unref(const wl_surface *surface); + void window_surface_unref(const wl_surface *wl_surface); bool window_cursor_grab_set(const GHOST_TGrabCursorMode mode, const GHOST_TGrabCursorMode mode_current, int32_t init_grab_xy[2], const GHOST_Rect *wrap_bounds, GHOST_TAxisFlag wrap_axis, - wl_surface *surface, + wl_surface *wl_surface, int scale); private: - struct display_t *d; + struct GWL_Display *d; std::string selection; }; diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 7c07ea6cd64..5c58f9a856c 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -42,47 +42,48 @@ # include "GHOST_NDOFManagerWin32.h" #endif -// Key code values not found in winuser.h +/* Key code values not found in `winuser.h`. */ #ifndef VK_MINUS # define VK_MINUS 0xBD -#endif // VK_MINUS +#endif /* VK_MINUS */ #ifndef VK_SEMICOLON # define VK_SEMICOLON 0xBA -#endif // VK_SEMICOLON +#endif /* VK_SEMICOLON */ #ifndef VK_PERIOD # define VK_PERIOD 0xBE -#endif // VK_PERIOD +#endif /* VK_PERIOD */ #ifndef VK_COMMA # define VK_COMMA 0xBC -#endif // VK_COMMA +#endif /* VK_COMMA */ #ifndef VK_BACK_QUOTE # define VK_BACK_QUOTE 0xC0 -#endif // VK_BACK_QUOTE +#endif /* VK_BACK_QUOTE */ #ifndef VK_SLASH # define VK_SLASH 0xBF -#endif // VK_SLASH +#endif /* VK_SLASH */ #ifndef VK_BACK_SLASH # define VK_BACK_SLASH 0xDC -#endif // VK_BACK_SLASH +#endif /* VK_BACK_SLASH */ #ifndef VK_EQUALS # define VK_EQUALS 0xBB -#endif // VK_EQUALS +#endif /* VK_EQUALS */ #ifndef VK_OPEN_BRACKET # define VK_OPEN_BRACKET 0xDB -#endif // VK_OPEN_BRACKET +#endif /* VK_OPEN_BRACKET */ #ifndef VK_CLOSE_BRACKET # define VK_CLOSE_BRACKET 0xDD -#endif // VK_CLOSE_BRACKET +#endif /* VK_CLOSE_BRACKET */ #ifndef VK_GR_LESS # define VK_GR_LESS 0xE2 -#endif // VK_GR_LESS +#endif /* VK_GR_LESS */ -/* Workaround for some laptop touchpads, some of which seems to +/** + * Workaround for some laptop touch-pads, some of which seems to * have driver issues which makes it so window function receives - * the message, but PeekMessage doesn't pick those messages for + * the message, but #PeekMessage doesn't pick those messages for * some reason. * - * We send a dummy WM_USER message to force PeekMessage to receive + * We send a dummy WM_USER message to force #PeekMessage to receive * something, making it so blender's window manager sees the new * messages coming in. */ @@ -101,22 +102,23 @@ static void initRawInput() RAWINPUTDEVICE devices[DEVICE_COUNT]; memset(devices, 0, DEVICE_COUNT * sizeof(RAWINPUTDEVICE)); - // Initiates WM_INPUT messages from keyboard - // That way GHOST can retrieve true keys + /* Initiates WM_INPUT messages from keyboard + * That way GHOST can retrieve true keys. */ devices[0].usUsagePage = 0x01; devices[0].usUsage = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */ #ifdef WITH_INPUT_NDOF - // multi-axis mouse (SpaceNavigator, etc.) + /* multi-axis mouse (SpaceNavigator, etc.). */ devices[1].usUsagePage = 0x01; devices[1].usUsage = 0x08; #endif - if (RegisterRawInputDevices(devices, DEVICE_COUNT, sizeof(RAWINPUTDEVICE))) - ; // yay! - else + if (RegisterRawInputDevices(devices, DEVICE_COUNT, sizeof(RAWINPUTDEVICE))) { + /* Success. */ + } + else { GHOST_PRINTF("could not register for RawInput: %d\n", (int)GetLastError()); - + } #undef DEVICE_COUNT } @@ -129,17 +131,17 @@ GHOST_SystemWin32::GHOST_SystemWin32() GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n"); m_displayManager->initialize(); - m_consoleStatus = 1; + m_consoleStatus = true; - // Tell Windows we are per monitor DPI aware. This disables the default - // blurry scaling and enables WM_DPICHANGED to allow us to draw at proper DPI. + /* Tell Windows we are per monitor DPI aware. This disables the default + * blurry scaling and enables WM_DPICHANGED to allow us to draw at proper DPI. */ SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); - // Check if current keyboard layout uses AltGr and save keylayout ID for - // specialized handling if keys like VK_OEM_*. I.e. french keylayout - // generates VK_OEM_8 for their exclamation key (key left of right shift) + /* Check if current keyboard layout uses AltGr and save keylayout ID for + * specialized handling if keys like VK_OEM_*. I.e. french keylayout + * generates #VK_OEM_8 for their exclamation key (key left of right shift). */ this->handleKeyboardChange(); - // Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32. + /* Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32. */ OleInitialize(0); #ifdef WITH_INPUT_NDOF @@ -149,7 +151,7 @@ GHOST_SystemWin32::GHOST_SystemWin32() GHOST_SystemWin32::~GHOST_SystemWin32() { - // Shutdown COM + /* Shutdown COM. */ OleUninitialize(); if (isStartedFromCommandPrompt()) { @@ -159,7 +161,7 @@ GHOST_SystemWin32::~GHOST_SystemWin32() uint64_t GHOST_SystemWin32::performanceCounterToMillis(__int64 perf_ticks) const { - // Calculate the time passed since system initialization. + /* Calculate the time passed since system initialization. */ __int64 delta = (perf_ticks - m_start) * 1000; uint64_t t = (uint64_t)(delta / m_freq); @@ -173,12 +175,12 @@ uint64_t GHOST_SystemWin32::tickCountToMillis(__int64 ticks) const uint64_t GHOST_SystemWin32::getMilliSeconds() const { - // Hardware does not support high resolution timers. We will use GetTickCount instead then. + /* Hardware does not support high resolution timers. We will use GetTickCount instead then. */ if (!m_hasPerformanceCounter) { return tickCountToMillis(::GetTickCount()); } - // Retrieve current count + /* Retrieve current count */ __int64 count = 0; ::QueryPerformanceCounter((LARGE_INTEGER *)&count); @@ -227,13 +229,13 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title, state, type, ((glSettings.flags & GHOST_glStereoVisual) != 0), - ((glSettings.flags & GHOST_glAlphaBackground) != 0), + false, (GHOST_WindowWin32 *)parentWindow, ((glSettings.flags & GHOST_glDebugContext) != 0), is_dialog); if (window->getValid()) { - // Store the pointer to the window + /* Store the pointer to the window */ m_windowManager->addWindow(window); m_windowManager->setActiveWindow(window); } @@ -272,7 +274,7 @@ GHOST_IContext *GHOST_SystemWin32::createOffscreenContext(GHOST_GLSettings glSet HDC mHDC = GetDC(wnd); HDC prev_hdc = wglGetCurrentDC(); HGLRC prev_context = wglGetCurrentContext(); -#if defined(WITH_GL_PROFILE_CORE) + for (int minor = 5; minor >= 0; --minor) { context = new GHOST_ContextWGL(false, true, @@ -310,29 +312,6 @@ GHOST_IContext *GHOST_SystemWin32::createOffscreenContext(GHOST_GLSettings glSet return NULL; } -#elif defined(WITH_GL_PROFILE_COMPAT) - // ask for 2.1 context, driver gives any GL version >= 2.1 - // (hopefully the latest compatibility profile) - // 2.1 ignores the profile bit & is incompatible with core profile - context = new GHOST_ContextWGL(false, - true, - NULL, - NULL, - 0, // no profile bit - 2, - 1, - (debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0), - GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); - - if (context->initializeDrawingContext()) { - return context; - } - else { - delete context; - } -#else -# error // must specify either core or compat at build time -#endif finished: wglMakeCurrent(prev_hdc, prev_context); return context; @@ -374,6 +353,7 @@ GHOST_ContextD3D *GHOST_SystemWin32::createOffscreenContextD3D() context = new GHOST_ContextD3D(false, wnd); if (context->initializeDrawingContext() == GHOST_kFailure) { delete context; + context = nullptr; } return context; @@ -418,10 +398,10 @@ bool GHOST_SystemWin32::processEvents(bool waitForEvent) driveTrackpad(); - // Process all the events waiting for us + /* Process all the events waiting for us. */ while (::PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE) != 0) { - // TranslateMessage doesn't alter the message, and doesn't change our raw keyboard data. - // Needed for MapVirtualKey or if we ever need to get chars from wm_ime_char or similar. + /* #TranslateMessage doesn't alter the message, and doesn't change our raw keyboard data. + * Needed for #MapVirtualKey or if we ever need to get chars from wm_ime_char or similar. */ ::TranslateMessage(&msg); ::DispatchMessageW(&msg); hasEventHandled = true; @@ -453,8 +433,9 @@ GHOST_TSuccess GHOST_SystemWin32::getCursorPosition(int32_t &x, int32_t &y) cons GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(int32_t x, int32_t y) { - if (!::GetActiveWindow()) + if (!::GetActiveWindow()) { return GHOST_kFailure; + } return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure; } @@ -475,12 +456,11 @@ GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys &keys) cons down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0; keys.set(GHOST_kModifierKeyRightControl, down); - bool lwindown = HIBYTE(::GetKeyState(VK_LWIN)) != 0; - bool rwindown = HIBYTE(::GetKeyState(VK_RWIN)) != 0; - if (lwindown || rwindown) - keys.set(GHOST_kModifierKeyOS, true); - else - keys.set(GHOST_kModifierKeyOS, false); + down = HIBYTE(::GetKeyState(VK_LWIN)) != 0; + keys.set(GHOST_kModifierKeyLeftOS, down); + down = HIBYTE(::GetKeyState(VK_RWIN)) != 0; + keys.set(GHOST_kModifierKeyRightOS, down); + return GHOST_kSuccess; } @@ -512,7 +492,7 @@ GHOST_TSuccess GHOST_SystemWin32::init() initRawInput(); m_lfstart = ::GetTickCount(); - // Determine whether this system has a high frequency performance counter. */ + /* Determine whether this system has a high frequency performance counter. */ m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER *)&m_freq) == TRUE; if (m_hasPerformanceCounter) { GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer available\n"); @@ -543,7 +523,7 @@ GHOST_TSuccess GHOST_SystemWin32::init() wc.lpszMenuName = 0; wc.lpszClassName = L"GHOST_WindowClass"; - // Use RegisterClassEx for setting small icon + /* Use #RegisterClassEx for setting small icon. */ if (::RegisterClassW(&wc) == 0) { success = GHOST_kFailure; } @@ -557,76 +537,15 @@ GHOST_TSuccess GHOST_SystemWin32::exit() return GHOST_System::exit(); } -GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, - bool *r_keyDown, - bool *r_is_repeated_modifier) +GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, bool *r_key_down) { - bool is_repeated_modifier = false; - - GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); - GHOST_TKey key = GHOST_kKeyUnknown; - GHOST_ModifierKeys modifiers; - system->retrieveModifierKeys(modifiers); - - // RI_KEY_BREAK doesn't work for sticky keys release, so we also - // check for the up message + /* #RI_KEY_BREAK doesn't work for sticky keys release, so we also check for the up message. */ unsigned int msg = raw.data.keyboard.Message; - *r_keyDown = !(raw.data.keyboard.Flags & RI_KEY_BREAK) && msg != WM_KEYUP && msg != WM_SYSKEYUP; - - key = this->convertKey(raw.data.keyboard.VKey, - raw.data.keyboard.MakeCode, - (raw.data.keyboard.Flags & (RI_KEY_E1 | RI_KEY_E0))); - - // extra handling of modifier keys: don't send repeats out from GHOST - if (key >= GHOST_kKeyLeftShift && key <= GHOST_kKeyRightAlt) { - bool changed = false; - GHOST_TModifierKey modifier; - switch (key) { - case GHOST_kKeyLeftShift: { - changed = (modifiers.get(GHOST_kModifierKeyLeftShift) != *r_keyDown); - modifier = GHOST_kModifierKeyLeftShift; - break; - } - case GHOST_kKeyRightShift: { - changed = (modifiers.get(GHOST_kModifierKeyRightShift) != *r_keyDown); - modifier = GHOST_kModifierKeyRightShift; - break; - } - case GHOST_kKeyLeftControl: { - changed = (modifiers.get(GHOST_kModifierKeyLeftControl) != *r_keyDown); - modifier = GHOST_kModifierKeyLeftControl; - break; - } - case GHOST_kKeyRightControl: { - changed = (modifiers.get(GHOST_kModifierKeyRightControl) != *r_keyDown); - modifier = GHOST_kModifierKeyRightControl; - break; - } - case GHOST_kKeyLeftAlt: { - changed = (modifiers.get(GHOST_kModifierKeyLeftAlt) != *r_keyDown); - modifier = GHOST_kModifierKeyLeftAlt; - break; - } - case GHOST_kKeyRightAlt: { - changed = (modifiers.get(GHOST_kModifierKeyRightAlt) != *r_keyDown); - modifier = GHOST_kModifierKeyRightAlt; - break; - } - default: - break; - } + *r_key_down = !(raw.data.keyboard.Flags & RI_KEY_BREAK) && msg != WM_KEYUP && msg != WM_SYSKEYUP; - if (changed) { - modifiers.set(modifier, *r_keyDown); - system->storeModifierKeys(modifiers); - } - else { - is_repeated_modifier = true; - } - } - - *r_is_repeated_modifier = is_repeated_modifier; - return key; + return this->convertKey(raw.data.keyboard.VKey, + raw.data.keyboard.MakeCode, + (raw.data.keyboard.Flags & (RI_KEY_E1 | RI_KEY_E0))); } /** @@ -680,11 +599,11 @@ GHOST_TKey GHOST_SystemWin32::convertKey(short vKey, short scanCode, short exten GHOST_TKey key; if ((vKey >= '0') && (vKey <= '9')) { - // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) + /* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39). */ key = (GHOST_TKey)(vKey - '0' + GHOST_kKey0); } else if ((vKey >= 'A') && (vKey <= 'Z')) { - // VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) + /* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A). */ key = (GHOST_TKey)(vKey - 'A' + GHOST_kKeyA); } else if ((vKey >= VK_F1) && (vKey <= VK_F24)) { @@ -829,8 +748,10 @@ GHOST_TKey GHOST_SystemWin32::convertKey(short vKey, short scanCode, short exten key = (extend) ? GHOST_kKeyRightAlt : GHOST_kKeyLeftAlt; break; case VK_LWIN: + key = GHOST_kKeyLeftOS; + break; case VK_RWIN: - key = GHOST_kKeyOS; + key = GHOST_kKeyRightOS; break; case VK_APPS: key = GHOST_kKeyApp; @@ -979,11 +900,11 @@ void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window) new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData)); mouseMoveHandled = true; - break; } else { WINTAB_PRINTF(" ... but no system button\n"); } + break; } case GHOST_kEventButtonUp: { WINTAB_PRINTF("HWND %p Wintab button up", window->getHWND()); @@ -1058,7 +979,7 @@ void GHOST_SystemWin32::processPointerEvent( } switch (type) { - case WM_POINTERUPDATE: + case WM_POINTERUPDATE: { /* Coalesced pointer events are reverse chronological order, reorder chronologically. * Only contiguous move events are coalesced. */ for (uint32_t i = pointerInfo.size(); i-- > 0;) { @@ -1073,7 +994,8 @@ void GHOST_SystemWin32::processPointerEvent( /* Leave event unhandled so that system cursor is moved. */ break; - case WM_POINTERDOWN: + } + case WM_POINTERDOWN: { /* Move cursor to point of contact because GHOST_EventButton does not include position. */ system->pushEvent(new GHOST_EventCursor(pointerInfo[0].time, GHOST_kEventCursorMove, @@ -1092,7 +1014,8 @@ void GHOST_SystemWin32::processPointerEvent( eventHandled = true; break; - case WM_POINTERUP: + } + case WM_POINTERUP: { system->pushEvent(new GHOST_EventButton(pointerInfo[0].time, GHOST_kEventButtonUp, window, @@ -1104,8 +1027,10 @@ void GHOST_SystemWin32::processPointerEvent( eventHandled = true; break; - default: + } + default: { break; + } } } @@ -1122,6 +1047,12 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind system->getCursorPosition(x_screen, y_screen); if (window->getCursorGrabModeIsWarp()) { + /* WORKAROUND: + * Sometimes Windows ignores `SetCursorPos()` or `SendInput()` calls or the mouse event is + * outdated. Identify these cases by checking if the cursor is not yet within bounds. */ + static bool is_warping_x = false; + static bool is_warping_y = false; + int32_t x_new = x_screen; int32_t y_new = y_screen; int32_t x_accum, y_accum; @@ -1138,29 +1069,41 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind window->getCursorGrabAccum(x_accum, y_accum); if (x_new != x_screen || y_new != y_screen) { + system->setCursorPosition(x_new, y_new); /* wrap */ + + /* Do not update the accum values if we are an outdated or failed pos-warp event. */ + if (!is_warping_x) { + is_warping_x = x_new != x_screen; + if (is_warping_x) { + x_accum += (x_screen - x_new); + } + } + + if (!is_warping_y) { + is_warping_y = y_new != y_screen; + if (is_warping_y) { + y_accum += (y_screen - y_new); + } + } + window->setCursorGrabAccum(x_accum, y_accum); + /* When wrapping we don't need to add an event because the setCursorPosition call will cause * a new event after. */ - system->setCursorPosition(x_new, y_new); /* wrap */ - window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new)); - } - else { - return new GHOST_EventCursor(system->getMilliSeconds(), - GHOST_kEventCursorMove, - window, - x_screen + x_accum, - y_screen + y_accum, - GHOST_TABLET_DATA_NONE); + return NULL; } + + is_warping_x = false; + is_warping_y = false; + x_screen += x_accum; + y_screen += y_accum; } - else { - return new GHOST_EventCursor(system->getMilliSeconds(), - GHOST_kEventCursorMove, - window, - x_screen, - y_screen, - GHOST_TABLET_DATA_NONE); - } - return NULL; + + return new GHOST_EventCursor(system->getMilliSeconds(), + GHOST_kEventCursorMove, + window, + x_screen, + y_screen, + GHOST_TABLET_DATA_NONE); } void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam) @@ -1171,7 +1114,7 @@ void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wPar int delta = GET_WHEEL_DELTA_WPARAM(wParam); if (acc * delta < 0) { - // scroll direction reversed. + /* Scroll direction reversed. */ acc = 0; } acc += delta; @@ -1187,48 +1130,55 @@ void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wPar GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RAWINPUT const &raw) { - bool keyDown = false; - bool is_repeated_modifier = false; + const char vk = raw.data.keyboard.VKey; + bool key_down = false; GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); - GHOST_TKey key = system->hardKey(raw, &keyDown, &is_repeated_modifier); + GHOST_TKey key = system->hardKey(raw, &key_down); GHOST_EventKey *event; + /* NOTE(@campbellbarton): key repeat in WIN32 also applies to modifier-keys. + * Check for this case and filter out modifier-repeat. + * Typically keyboard events are *not* filtered as part of GHOST's event handling. + * As other GHOST back-ends don't have the behavior, it's simplest not to send them through. + * Ideally it would be possible to check the key-map for keys that repeat but this doesn't look + * to be supported. */ + bool is_repeat = false; + bool is_repeated_modifier = false; + if (key_down) { + if (system->m_keycode_last_repeat_key == vk) { + is_repeat = true; + is_repeated_modifier = GHOST_KEY_MODIFIER_CHECK(key); + } + system->m_keycode_last_repeat_key = vk; + } + else { + if (system->m_keycode_last_repeat_key == vk) { + system->m_keycode_last_repeat_key = 0; + } + } + /* We used to check `if (key != GHOST_kKeyUnknown)`, but since the message * values `WM_SYSKEYUP`, `WM_KEYUP` and `WM_CHAR` are ignored, we capture * those events here as well. */ if (!is_repeated_modifier) { - char vk = raw.data.keyboard.VKey; char utf8_char[6] = {0}; - char ascii = 0; - bool is_repeat = false; + BYTE state[256]; + const BOOL has_state = GetKeyboardState((PBYTE)state); + const bool ctrl_pressed = has_state && state[VK_CONTROL] & 0x80; + const bool alt_pressed = has_state && state[VK_MENU] & 0x80; - /* Unlike on Linux, not all keys can send repeat events. E.g. modifier keys don't. */ - if (keyDown) { - if (system->m_keycode_last_repeat_key == vk) { - is_repeat = true; - } - system->m_keycode_last_repeat_key = vk; - } - else { - if (system->m_keycode_last_repeat_key == vk) { - system->m_keycode_last_repeat_key = 0; - } + if (!key_down) { + /* Pass. */ } - - wchar_t utf16[3] = {0}; - BYTE state[256] = {0}; - int r; - GetKeyboardState((PBYTE)state); - bool ctrl_pressed = state[VK_CONTROL] & 0x80; - bool alt_pressed = state[VK_MENU] & 0x80; - /* No text with control key pressed (Alt can be used to insert special characters though!). */ - if (ctrl_pressed && !alt_pressed) { - utf8_char[0] = '\0'; + else if (ctrl_pressed && !alt_pressed) { + /* Pass. */ } - // Don't call ToUnicodeEx on dead keys as it clears the buffer and so won't allow diacritical - // composition. + /* Don't call #ToUnicodeEx on dead keys as it clears the buffer and so won't allow diacritical + * composition. */ else if (MapVirtualKeyW(vk, 2) != 0) { + wchar_t utf16[3] = {0}; + int r; /* TODO: #ToUnicodeEx can respond with up to 4 utf16 chars (only 2 here). * Could be up to 24 utf8 bytes. */ if ((r = ToUnicodeEx( @@ -1243,28 +1193,25 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA } } - if (!keyDown) { - utf8_char[0] = '\0'; - ascii = '\0'; - } - else { - ascii = utf8_char[0] & 0x80 ? '?' : utf8_char[0]; - } - #ifdef WITH_INPUT_IME - if (window->getImeInput()->IsImeKeyEvent(ascii, key)) { - return NULL; + if (key_down && ((utf8_char[0] & 0x80) == 0)) { + const char ascii = utf8_char[0]; + if (window->getImeInput()->IsImeKeyEvent(ascii, key)) { + return NULL; + } } #endif /* WITH_INPUT_IME */ event = new GHOST_EventKey(system->getMilliSeconds(), - keyDown ? GHOST_kEventKeyDown : GHOST_kEventKeyUp, + key_down ? GHOST_kEventKeyDown : GHOST_kEventKeyUp, window, key, is_repeat, utf8_char); - // GHOST_PRINTF("%c\n", ascii); // we already get this info via EventPrinter +#if 0 /* we already get this info via EventPrinter. */ + GHOST_PRINTF("%c\n", ascii); +#endif } else { event = NULL; @@ -1285,9 +1232,7 @@ GHOST_Event *GHOST_SystemWin32::processWindowSizeEvent(GHOST_WindowWin32 *window system->dispatchEvents(); return NULL; } - else { - return sizeEvent; - } + return sizeEvent; } GHOST_Event *GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, @@ -1368,54 +1313,53 @@ bool GHOST_SystemWin32::processNDOF(RAWINPUT const &raw) uint64_t now = getMilliSeconds(); static bool firstEvent = true; - if (firstEvent) { // determine exactly which device is plugged in + if (firstEvent) { /* Determine exactly which device is plugged in. */ RID_DEVICE_INFO info; unsigned infoSize = sizeof(RID_DEVICE_INFO); info.cbSize = infoSize; GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICEINFO, &info, &infoSize); - if (info.dwType == RIM_TYPEHID) + if (info.dwType == RIM_TYPEHID) { m_ndofManager->setDevice(info.hid.dwVendorId, info.hid.dwProductId); - else + } + else { GHOST_PRINT("<!> not a HID device... mouse/kb perhaps?\n"); - + } firstEvent = false; } - // The NDOF manager sends button changes immediately, and *pretends* to - // send motion. Mark as 'sent' so motion will always get dispatched. + /* The NDOF manager sends button changes immediately, and *pretends* to + * send motion. Mark as 'sent' so motion will always get dispatched. */ eventSent = true; BYTE const *data = raw.data.hid.bRawData; BYTE packetType = data[0]; switch (packetType) { - case 1: // translation - { + case 1: { /* Translation. */ const short *axis = (short *)(data + 1); - // massage into blender view coords (same goes for rotation) + /* Massage into blender view coords (same goes for rotation). */ const int t[3] = {axis[0], -axis[2], axis[1]}; m_ndofManager->updateTranslation(t, now); if (raw.data.hid.dwSizeHid == 13) { - // this report also includes rotation + /* This report also includes rotation. */ const int r[3] = {-axis[3], axis[5], -axis[4]}; m_ndofManager->updateRotation(r, now); - // I've never gotten one of these, has anyone else? + /* I've never gotten one of these, has anyone else? */ GHOST_PRINT("ndof: combined T + R\n"); } break; } - case 2: // rotation - { + case 2: { /* Rotation. */ + const short *axis = (short *)(data + 1); const int r[3] = {-axis[0], axis[2], -axis[1]}; m_ndofManager->updateRotation(r, now); break; } - case 3: // buttons - { + case 3: { /* Buttons. */ int button_bits; memcpy(&button_bits, data + 1, sizeof(button_bits)); m_ndofManager->updateButtons(button_bits, now); @@ -1424,7 +1368,7 @@ bool GHOST_SystemWin32::processNDOF(RAWINPUT const &raw) } return eventSent; } -#endif // WITH_INPUT_NDOF +#endif /* WITH_INPUT_NDOF */ void GHOST_SystemWin32::driveTrackpad() { @@ -1487,8 +1431,8 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, if (hwnd) { if (msg == WM_NCCREATE) { - // Tell Windows to automatically handle scaling of non-client areas - // such as the caption bar. EnableNonClientDpiScaling was introduced in Windows 10 + /* Tell Windows to automatically handle scaling of non-client areas + * such as the caption bar. #EnableNonClientDpiScaling was introduced in Windows 10. */ HMODULE m_user32 = ::LoadLibrary("User32.dll"); if (m_user32) { GHOST_WIN32_EnableNonClientDpiScaling fpEnableNonClientDpiScaling = @@ -1503,7 +1447,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, GHOST_WindowWin32 *window = (GHOST_WindowWin32 *)::GetWindowLongPtr(hwnd, GWLP_USERDATA); if (window) { switch (msg) { - // we need to check if new key layout has AltGr + /* We need to check if new key layout has AltGr. */ case WM_INPUTLANGCHANGE: { system->handleKeyboardChange(); #ifdef WITH_INPUT_IME @@ -1512,9 +1456,9 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, #endif break; } - //////////////////////////////////////////////////////////////////////// - // Keyboard events, processed - //////////////////////////////////////////////////////////////////////// + /* ========================== + * Keyboard events, processed + * ========================== */ case WM_INPUT: { RAWINPUT raw; RAWINPUT *raw_ptr = &raw; @@ -1523,7 +1467,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, GetRawInputData((HRAWINPUT)lParam, RID_INPUT, raw_ptr, &rawSize, sizeof(RAWINPUTHEADER)); switch (raw.header.dwType) { - case RIM_TYPEKEYBOARD: + case RIM_TYPEKEYBOARD: { event = processKeyEvent(window, raw); if (!event) { GHOST_PRINT("GHOST_SystemWin32::wndProc: key event "); @@ -1531,20 +1475,22 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, GHOST_PRINT(" key ignored\n"); } break; + } #ifdef WITH_INPUT_NDOF - case RIM_TYPEHID: + case RIM_TYPEHID: { if (system->processNDOF(raw)) { eventHandled = true; } break; + } #endif } break; } #ifdef WITH_INPUT_IME - //////////////////////////////////////////////////////////////////////// - // IME events, processed, read more in GHOST_IME.h - //////////////////////////////////////////////////////////////////////// + /* ================================================= + * IME events, processed, read more in `GHOST_IME.h` + * ================================================= */ case WM_IME_NOTIFY: { /* Update conversion status when IME is changed or input mode is changed. */ if (wParam == IMN_SETOPENSTATUS || wParam == IMN_SETCONVERSIONMODE) { @@ -1592,56 +1538,53 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, break; } #endif /* WITH_INPUT_IME */ - //////////////////////////////////////////////////////////////////////// - // Keyboard events, ignored - //////////////////////////////////////////////////////////////////////// + /* ======================== + * Keyboard events, ignored + * ======================== */ case WM_KEYDOWN: case WM_SYSKEYDOWN: case WM_KEYUP: case WM_SYSKEYUP: - /* These functions were replaced by #WM_INPUT. */ + /* These functions were replaced by #WM_INPUT. */ case WM_CHAR: - /* The WM_CHAR message is posted to the window with the keyboard focus when - * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR - * contains the character code of the key that was pressed. - */ + /* The #WM_CHAR message is posted to the window with the keyboard focus when + * a WM_KEYDOWN message is translated by the #TranslateMessage function. + * WM_CHAR contains the character code of the key that was pressed. */ case WM_DEADCHAR: - /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a - * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR + /* The #WM_DEADCHAR message is posted to the window with the keyboard focus when a + * WM_KEYUP message is translated by the #TranslateMessage function. WM_DEADCHAR * specifies a character code generated by a dead key. A dead key is a key that * generates a character, such as the umlaut (double-dot), that is combined with * another character to form a composite character. For example, the umlaut-O * character (Ö) is generated by typing the dead key for the umlaut character, and - * then typing the O key. - */ + * then typing the O key. */ break; case WM_SYSDEADCHAR: - /* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when - * a WM_SYSKEYDOWN message is translated by the TranslateMessage function. - * WM_SYSDEADCHAR specifies the character code of a system dead key - that is, - * a dead key that is pressed while holding down the alt key. - */ - case WM_SYSCHAR: - /* The WM_SYSCHAR message is sent to the window with the keyboard focus when - * a WM_SYSCHAR message is translated by the TranslateMessage function. + /* The #WM_SYSDEADCHAR message is sent to the window with the keyboard focus when + * a WM_SYSKEYDOWN message is translated by the #TranslateMessage function. + * WM_SYSDEADCHAR specifies the character code of a system dead key - that is, + * a dead key that is pressed while holding down the alt key. */ + case WM_SYSCHAR: { + /* #The WM_SYSCHAR message is sent to the window with the keyboard focus when + * a WM_SYSCHAR message is translated by the #TranslateMessage function. * WM_SYSCHAR specifies the character code of a dead key - that is, * a dead key that is pressed while holding down the alt key. - * To prevent the sound, DefWindowProc must be avoided by return - */ + * To prevent the sound, #DefWindowProc must be avoided by return. */ break; - case WM_SYSCOMMAND: - /* The WM_SYSCOMMAND message is sent to the window when system commands such as + } + case WM_SYSCOMMAND: { + /* The #WM_SYSCOMMAND message is sent to the window when system commands such as * maximize, minimize or close the window are triggered. Also it is sent when ALT - * button is press for menu. To prevent this we must return preventing DefWindowProc. + * button is press for menu. To prevent this we must return preventing #DefWindowProc. * * Note that the four low-order bits of the wParam parameter are used internally by the * OS. To obtain the correct result when testing the value of wParam, an application must - * combine the value 0xFFF0 with the wParam value by using the bit-wise AND operator. - */ + * combine the value 0xFFF0 with the wParam value by using the bit-wise AND operator. */ switch (wParam & 0xFFF0) { - case SC_KEYMENU: + case SC_KEYMENU: { eventHandled = true; break; + } case SC_RESTORE: { ::ShowWindow(hwnd, SW_RESTORE); window->setState(window->getState()); @@ -1672,9 +1615,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } } break; - //////////////////////////////////////////////////////////////////////// - // Wintab events, processed - //////////////////////////////////////////////////////////////////////// + } + /* ======================== + * Wintab events, processed + * ======================== */ case WT_CSRCHANGE: { WINTAB_PRINTF("HWND %p HCTX %p WT_CSRCHANGE\n", window->getHWND(), (void *)lParam); GHOST_Wintab *wt = window->getWintab(); @@ -1726,44 +1670,53 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, eventHandled = true; break; } - case WT_PACKET: + case WT_PACKET: { processWintabEvent(window); eventHandled = true; break; - //////////////////////////////////////////////////////////////////////// - // Wintab events, debug - //////////////////////////////////////////////////////////////////////// - case WT_CTXOPEN: + } + /* ==================== + * Wintab events, debug + * ==================== */ + case WT_CTXOPEN: { WINTAB_PRINTF("HWND %p HCTX %p WT_CTXOPEN\n", window->getHWND(), (void *)wParam); break; - case WT_CTXCLOSE: + } + case WT_CTXCLOSE: { WINTAB_PRINTF("HWND %p HCTX %p WT_CTXCLOSE\n", window->getHWND(), (void *)wParam); break; - case WT_CTXUPDATE: + } + case WT_CTXUPDATE: { WINTAB_PRINTF("HWND %p HCTX %p WT_CTXUPDATE\n", window->getHWND(), (void *)wParam); break; - case WT_CTXOVERLAP: + } + case WT_CTXOVERLAP: { WINTAB_PRINTF("HWND %p HCTX %p WT_CTXOVERLAP", window->getHWND(), (void *)wParam); switch (lParam) { - case CXS_DISABLED: + case CXS_DISABLED: { WINTAB_PRINTF(" CXS_DISABLED\n"); break; - case CXS_OBSCURED: + } + case CXS_OBSCURED: { WINTAB_PRINTF(" CXS_OBSCURED\n"); break; - case CXS_ONTOP: + } + case CXS_ONTOP: { WINTAB_PRINTF(" CXS_ONTOP\n"); break; + } } break; - //////////////////////////////////////////////////////////////////////// - // Pointer events, processed - //////////////////////////////////////////////////////////////////////// + } + /* ========================= + * Pointer events, processed + * ========================= */ case WM_POINTERUPDATE: case WM_POINTERDOWN: - case WM_POINTERUP: + case WM_POINTERUP: { processPointerEvent(msg, window, wParam, lParam, eventHandled); break; + } case WM_POINTERLEAVE: { uint32_t pointerId = GET_POINTERID_WPARAM(wParam); POINTER_INFO pointerInfo; @@ -1778,19 +1731,22 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } break; } - //////////////////////////////////////////////////////////////////////// - // Mouse events, processed - //////////////////////////////////////////////////////////////////////// - case WM_LBUTTONDOWN: + /* ======================= + * Mouse events, processed + * ======================= */ + case WM_LBUTTONDOWN: { event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft); break; - case WM_MBUTTONDOWN: + } + case WM_MBUTTONDOWN: { event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle); break; - case WM_RBUTTONDOWN: + } + case WM_RBUTTONDOWN: { event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight); break; - case WM_XBUTTONDOWN: + } + case WM_XBUTTONDOWN: { if ((short)HIWORD(wParam) == XBUTTON1) { event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton4); } @@ -1798,16 +1754,20 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton5); } break; - case WM_LBUTTONUP: + } + case WM_LBUTTONUP: { event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft); break; - case WM_MBUTTONUP: + } + case WM_MBUTTONUP: { event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle); break; - case WM_RBUTTONUP: + } + case WM_RBUTTONUP: { event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight); break; - case WM_XBUTTONUP: + } + case WM_XBUTTONUP: { if ((short)HIWORD(wParam) == XBUTTON1) { event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4); } @@ -1815,7 +1775,8 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5); } break; - case WM_MOUSEMOVE: + } + case WM_MOUSEMOVE: { if (!window->m_mousePresent) { WINTAB_PRINTF("HWND %p mouse enter\n", window->getHWND()); TRACKMOUSEEVENT tme = {sizeof(tme)}; @@ -1832,6 +1793,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, event = processCursorEvent(window); break; + } case WM_MOUSEWHEEL: { /* The WM_MOUSEWHEEL message is sent to the focus window * when the mouse wheel is rotated. The DefWindowProc @@ -1847,7 +1809,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, #endif break; } - case WM_SETCURSOR: + case WM_SETCURSOR: { /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor * to move within a window and mouse input is not captured. * This means we have to set the cursor shape every time the mouse moves! @@ -1855,16 +1817,17 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, * arrow if it is not in the client area. */ if (LOWORD(lParam) == HTCLIENT) { - // Load the current cursor + /* Load the current cursor. */ window->loadCursor(window->getCursorVisibility(), window->getCursorShape()); - // Bypass call to DefWindowProc + /* Bypass call to #DefWindowProc. */ return 0; } else { - // Outside of client area show standard cursor + /* Outside of client area show standard cursor. */ window->loadCursor(true, GHOST_kStandardCursorDefault); } break; + } case WM_MOUSELEAVE: { WINTAB_PRINTF("HWND %p mouse leave\n", window->getHWND()); window->m_mousePresent = false; @@ -1877,26 +1840,27 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } break; } - //////////////////////////////////////////////////////////////////////// - // Mouse events, ignored - //////////////////////////////////////////////////////////////////////// - case WM_NCMOUSEMOVE: - /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved - * within the non-client area of the window. This message is posted to the window that - * contains the cursor. If a window has captured the mouse, this message is not posted. - */ - case WM_NCHITTEST: + /* ===================== + * Mouse events, ignored + * ===================== */ + case WM_NCMOUSEMOVE: { + /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved + * within the non-client area of the window. This message is posted to the window that + * contains the cursor. If a window has captured the mouse, this message is not posted. + */ + } + case WM_NCHITTEST: { /* The WM_NCHITTEST message is sent to a window when the cursor moves, or * when a mouse button is pressed or released. If the mouse is not captured, * the message is sent to the window beneath the cursor. Otherwise, the message * is sent to the window that has captured the mouse. */ break; - - //////////////////////////////////////////////////////////////////////// - // Window events, processed - //////////////////////////////////////////////////////////////////////// - case WM_CLOSE: + } + /* ======================== + * Window events, processed + * ======================== */ + case WM_CLOSE: { /* The WM_CLOSE message is sent as a signal that a window * or an application should terminate. Restore if minimized. */ if (IsIconic(hwnd)) { @@ -1904,31 +1868,29 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } event = processWindowEvent(GHOST_kEventWindowClose, window); break; - case WM_ACTIVATE: + } + case WM_ACTIVATE: { /* The WM_ACTIVATE message is sent to both the window being activated and the window * being deactivated. If the windows use the same input queue, the message is sent * synchronously, first to the window procedure of the top-level window being * deactivated, then to the window procedure of the top-level window being activated. * If the windows use different input queues, the message is sent asynchronously, * so the window is activated immediately. */ - { - GHOST_ModifierKeys modifiers; - modifiers.clear(); - system->storeModifierKeys(modifiers); - system->m_wheelDeltaAccum = 0; - system->m_keycode_last_repeat_key = 0; - event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : - GHOST_kEventWindowDeactivate, - window); - /* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL - * will not be dispatched to OUR active window if we minimize one of OUR windows. */ - if (LOWORD(wParam) == WA_INACTIVE) - window->lostMouseCapture(); - - lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); - break; + + system->m_wheelDeltaAccum = 0; + system->m_keycode_last_repeat_key = 0; + event = processWindowEvent( + LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window); + /* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL + * will not be dispatched to OUR active window if we minimize one of OUR windows. */ + if (LOWORD(wParam) == WA_INACTIVE) { + window->lostMouseCapture(); } - case WM_ENTERSIZEMOVE: + + lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); + break; + } + case WM_ENTERSIZEMOVE: { /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving * or sizing modal loop. The window enters the moving or sizing modal loop when the user * clicks the window's title bar or sizing border, or when the window passes the @@ -1938,10 +1900,12 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, */ window->m_inLiveResize = 1; break; - case WM_EXITSIZEMOVE: + } + case WM_EXITSIZEMOVE: { window->m_inLiveResize = 0; break; - case WM_PAINT: + } + case WM_PAINT: { /* An application sends the WM_PAINT message when the system or another application * makes a request to paint a portion of an application's window. The message is sent * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage @@ -1956,7 +1920,8 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, eventHandled = true; } break; - case WM_GETMINMAXINFO: + } + case WM_GETMINMAXINFO: { /* The WM_GETMINMAXINFO message is sent to a window when the size or * position of the window is about to change. An application can use * this message to override the window's default maximized size and @@ -1965,10 +1930,12 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, processMinMaxInfo((MINMAXINFO *)lParam); /* Let DefWindowProc handle it. */ break; - case WM_SIZING: + } + case WM_SIZING: { event = processWindowSizeEvent(window); break; - case WM_SIZE: + } + case WM_SIZE: { /* The WM_SIZE message is sent to a window after its size has changed. * The WM_SIZE and WM_MOVE messages are not sent if an application handles the * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient @@ -1977,15 +1944,17 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, */ event = processWindowSizeEvent(window); break; - case WM_CAPTURECHANGED: + } + case WM_CAPTURECHANGED: { window->lostMouseCapture(); break; + } case WM_MOVING: /* The WM_MOVING message is sent to a window that the user is moving. By processing * this message, an application can monitor the size and position of the drag rectangle * and, if needed, change its size or position. */ - case WM_MOVE: + case WM_MOVE: { /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient * to perform any move or size change processing during the WM_WINDOWPOSCHANGED @@ -2001,33 +1970,33 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } break; - case WM_DPICHANGED: + } + case WM_DPICHANGED: { /* The WM_DPICHANGED message is sent when the effective dots per inch (dpi) for a * window has changed. The DPI is the scale factor for a window. There are multiple * events that can cause the DPI to change such as when the window is moved to a monitor - * with a different DPI. - */ - { - // The suggested new size and position of the window. - RECT *const suggestedWindowRect = (RECT *)lParam; + * with a different DPI. */ - // Push DPI change event first - system->pushEvent(processWindowEvent(GHOST_kEventWindowDPIHintChanged, window)); - system->dispatchEvents(); - eventHandled = true; + /* The suggested new size and position of the window. */ + RECT *const suggestedWindowRect = (RECT *)lParam; - // Then move and resize window - SetWindowPos(hwnd, - NULL, - suggestedWindowRect->left, - suggestedWindowRect->top, - suggestedWindowRect->right - suggestedWindowRect->left, - suggestedWindowRect->bottom - suggestedWindowRect->top, - SWP_NOZORDER | SWP_NOACTIVATE); + /* Push DPI change event first. */ + system->pushEvent(processWindowEvent(GHOST_kEventWindowDPIHintChanged, window)); + system->dispatchEvents(); + eventHandled = true; - window->updateDPI(); - } + /* Then move and resize window. */ + SetWindowPos(hwnd, + NULL, + suggestedWindowRect->left, + suggestedWindowRect->top, + suggestedWindowRect->right - suggestedWindowRect->left, + suggestedWindowRect->bottom - suggestedWindowRect->top, + SWP_NOZORDER | SWP_NOACTIVATE); + + window->updateDPI(); break; + } case WM_DISPLAYCHANGE: { GHOST_Wintab *wt = window->getWintab(); if (wt) { @@ -2035,7 +2004,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } break; } - case WM_KILLFOCUS: + case WM_KILLFOCUS: { /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard * focus. We want to prevent this if a window is still active and it loses focus to * nowhere. */ @@ -2043,73 +2012,73 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, ::SetFocus(hwnd); } break; - case WM_SETTINGCHANGE: + } + case WM_SETTINGCHANGE: { /* Microsoft: "Note that some applications send this message with lParam set to NULL" */ if ((lParam != NULL) && (wcscmp(LPCWSTR(lParam), L"ImmersiveColorSet") == 0)) { window->ThemeRefresh(); } break; - //////////////////////////////////////////////////////////////////////// - // Window events, ignored - //////////////////////////////////////////////////////////////////////// + } + /* ====================== + * Window events, ignored + * ====================== */ case WM_WINDOWPOSCHANGED: - /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place - * in the Z order has changed as a result of a call to the SetWindowPos function or - * another window-management function. - * The WM_SIZE and WM_MOVE messages are not sent if an application handles the - * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient - * to perform any move or size change processing during the WM_WINDOWPOSCHANGED - * message without calling DefWindowProc. - */ + /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place + * in the Z order has changed as a result of a call to the SetWindowPos function or + * another window-management function. + * The WM_SIZE and WM_MOVE messages are not sent if an application handles the + * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient + * to perform any move or size change processing during the WM_WINDOWPOSCHANGED + * message without calling DefWindowProc. + */ case WM_ERASEBKGND: - /* An application sends the WM_ERASEBKGND message when the window background must be - * erased (for example, when a window is resized). The message is sent to prepare an - * invalidated portion of a window for painting. - */ + /* An application sends the WM_ERASEBKGND message when the window background must be + * erased (for example, when a window is resized). The message is sent to prepare an + * invalidated portion of a window for painting. */ case WM_NCPAINT: - /* An application sends the WM_NCPAINT message to a window - * when its frame must be painted. */ + /* An application sends the WM_NCPAINT message to a window + * when its frame must be painted. */ case WM_NCACTIVATE: - /* The WM_NCACTIVATE message is sent to a window when its non-client area needs to be - * changed to indicate an active or inactive state. */ + /* The WM_NCACTIVATE message is sent to a window when its non-client area needs to be + * changed to indicate an active or inactive state. */ case WM_DESTROY: - /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the - * window procedure of the window being destroyed after the window is removed from the - * screen. This message is sent first to the window being destroyed and then to the child - * windows (if any) as they are destroyed. During the processing of the message, it can - * be assumed that all child windows still exist. */ - case WM_NCDESTROY: + /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the + * window procedure of the window being destroyed after the window is removed from the + * screen. This message is sent first to the window being destroyed and then to the child + * windows (if any) as they are destroyed. During the processing of the message, it can + * be assumed that all child windows still exist. */ + case WM_NCDESTROY: { /* The WM_NCDESTROY message informs a window that its non-client area is being * destroyed. The DestroyWindow function sends the WM_NCDESTROY message to the window * following the WM_DESTROY message. WM_DESTROY is used to free the allocated memory * object associated with the window. */ break; + } case WM_SHOWWINDOW: - /* The WM_SHOWWINDOW message is sent to a window when the window is - * about to be hidden or shown. */ + /* The WM_SHOWWINDOW message is sent to a window when the window is + * about to be hidden or shown. */ case WM_WINDOWPOSCHANGING: - /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in - * the Z order is about to change as a result of a call to the SetWindowPos function or - * another window-management function. - */ - case WM_SETFOCUS: + /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in + * the Z order is about to change as a result of a call to the SetWindowPos function or + * another window-management function. */ + case WM_SETFOCUS: { /* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */ break; - //////////////////////////////////////////////////////////////////////// - // Other events - //////////////////////////////////////////////////////////////////////// + } + /* ============ + * Other events + * ============ */ case WM_GETTEXT: - /* An application sends a WM_GETTEXT message to copy the text that - * corresponds to a window into a buffer provided by the caller. - */ + /* An application sends a WM_GETTEXT message to copy the text that + * corresponds to a window into a buffer provided by the caller. */ case WM_ACTIVATEAPP: - /* The WM_ACTIVATEAPP message is sent when a window belonging to a - * different application than the active window is about to be activated. - * The message is sent to the application whose window is being activated - * and to the application whose window is being deactivated. - */ - case WM_TIMER: + /* The WM_ACTIVATEAPP message is sent when a window belonging to a + * different application than the active window is about to be activated. + * The message is sent to the application whose window is being activated + * and to the application whose window is being deactivated. */ + case WM_TIMER: { /* The WIN32 docs say: * The WM_TIMER message is posted to the installing thread's message queue * when a timer expires. You can process the message by providing a WM_TIMER @@ -2117,19 +2086,20 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, * call the TimerProc callback function specified in the call to the SetTimer * function used to install the timer. * - * In GHOST, we let DefWindowProc call the timer callback. - */ + * In GHOST, we let DefWindowProc call the timer callback. */ break; - case DM_POINTERHITTEST: + } + case DM_POINTERHITTEST: { /* The DM_POINTERHITTEST message is sent to a window, when pointer input is first * detected, in order to determine the most probable input target for Direct * Manipulation. */ window->onPointerHitTest(wParam); break; + } } } else { - // Event found for a window before the pointer to the class has been set. + /* Event found for a window before the pointer to the class has been set. */ GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n"); /* These are events we typically miss at this point: * WM_GETMINMAXINFO 0x24 @@ -2141,7 +2111,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } } else { - // Events without valid hwnd + /* Events without valid `hwnd`. */ GHOST_PRINT("GHOST_SystemWin32::wndProc: event without window\n"); } @@ -2150,16 +2120,15 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, eventHandled = true; } - if (!eventHandled) + if (!eventHandled) { lResult = ::DefWindowProcW(hwnd, msg, wParam, lParam); + } return lResult; } char *GHOST_SystemWin32::getClipboard(bool selection) const { - char *temp_buff; - if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) { wchar_t *buffer; HANDLE hData = GetClipboardData(CF_UNICODETEXT); @@ -2173,7 +2142,7 @@ char *GHOST_SystemWin32::getClipboard(bool selection) const return NULL; } - temp_buff = alloc_utf_8_from_16(buffer, 0); + char *temp_buff = alloc_utf_8_from_16(buffer, 0); /* Buffer mustn't be accessed after CloseClipboard * it would like accessing free-d memory */ @@ -2182,7 +2151,7 @@ char *GHOST_SystemWin32::getClipboard(bool selection) const return temp_buff; } - else if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL)) { + if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL)) { char *buffer; size_t len = 0; HANDLE hData = GetClipboardData(CF_TEXT); @@ -2197,7 +2166,7 @@ char *GHOST_SystemWin32::getClipboard(bool selection) const } len = strlen(buffer); - temp_buff = (char *)malloc(len + 1); + char *temp_buff = (char *)malloc(len + 1); strncpy(temp_buff, buffer, len); temp_buff[len] = '\0'; @@ -2208,21 +2177,19 @@ char *GHOST_SystemWin32::getClipboard(bool selection) const return temp_buff; } - else { - return NULL; - } + return nullptr; } void GHOST_SystemWin32::putClipboard(const char *buffer, bool selection) const { if (selection || !buffer) { return; - } // for copying the selection, used on X11 + } /* For copying the selection, used on X11. */ if (OpenClipboard(NULL)) { EmptyClipboard(); - // Get length of buffer including the terminating null + /* Get length of buffer including the terminating null. */ size_t len = count_utf_16_from_8(buffer); HGLOBAL clipbuffer = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t) * len); @@ -2279,7 +2246,7 @@ GHOST_TSuccess GHOST_SystemWin32::showMessageBox(const char *title, case IDCONTINUE: break; default: - break; // should never happen + break; /* Should never happen. */ } free((void *)title_16); @@ -2347,14 +2314,15 @@ static bool isStartedFromCommandPrompt() } /* When we're starting from a wrapper we need to compare with parent process ID. */ - if (pid != (start_from_launcher ? ppid : GetCurrentProcessId())) + if (pid != (start_from_launcher ? ppid : GetCurrentProcessId())) { return true; + } } return false; } -int GHOST_SystemWin32::setConsoleWindowState(GHOST_TConsoleWindowState action) +bool GHOST_SystemWin32::setConsoleWindowState(GHOST_TConsoleWindowState action) { HWND wnd = GetConsoleWindow(); @@ -2362,28 +2330,31 @@ int GHOST_SystemWin32::setConsoleWindowState(GHOST_TConsoleWindowState action) case GHOST_kConsoleWindowStateHideForNonConsoleLaunch: { if (!isStartedFromCommandPrompt()) { ShowWindow(wnd, SW_HIDE); - m_consoleStatus = 0; + m_consoleStatus = false; } break; } - case GHOST_kConsoleWindowStateHide: + case GHOST_kConsoleWindowStateHide: { ShowWindow(wnd, SW_HIDE); - m_consoleStatus = 0; + m_consoleStatus = false; break; - case GHOST_kConsoleWindowStateShow: + } + case GHOST_kConsoleWindowStateShow: { ShowWindow(wnd, SW_SHOW); if (!isStartedFromCommandPrompt()) { DeleteMenu(GetSystemMenu(wnd, FALSE), SC_CLOSE, MF_BYCOMMAND); } - m_consoleStatus = 1; + m_consoleStatus = true; break; - case GHOST_kConsoleWindowStateToggle: + } + case GHOST_kConsoleWindowStateToggle: { ShowWindow(wnd, m_consoleStatus ? SW_HIDE : SW_SHOW); m_consoleStatus = !m_consoleStatus; if (m_consoleStatus && !isStartedFromCommandPrompt()) { DeleteMenu(GetSystemMenu(wnd, FALSE), SC_CLOSE, MF_BYCOMMAND); } break; + } } return m_consoleStatus; diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index b40f5e3fd75..f5cd0055b34 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -10,10 +10,10 @@ #ifndef WIN32 # error WIN32 only! -#endif // WIN32 +#endif /* WIN32 */ #define WIN32_LEAN_AND_MEAN -#include <ole2.h> // for drag-n-drop +#include <ole2.h> /* For drag-n-drop. */ #include <windows.h> #include "GHOST_System.h" @@ -105,7 +105,7 @@ class GHOST_SystemWin32 : public GHOST_System { * \param state: The state of the window when opened. * \param type: The type of drawing context installed in this window. * \param glSettings: Misc OpenGL settings. - * \param exclusive: Use to show the window ontop and ignore others (used fullscreen). + * \param exclusive: Use to show the window on top and ignore others (used full-screen). * \param parentWindow: Parent window. * \return The new window (or 0 if creation failed). */ @@ -295,11 +295,10 @@ class GHOST_SystemWin32 : public GHOST_System { /** * Catches raw WIN32 key codes from WM_INPUT in the wndproc. * \param raw: RawInput structure with detailed info about the key event. - * \param keyDown: Pointer flag that specify if a key is down. - * \param vk: Pointer to virtual key. + * \param r_key_down: Set true when the key is pressed, otherwise false. * \return The GHOST key (GHOST_kKeyUnknown if no match). */ - GHOST_TKey hardKey(RAWINPUT const &raw, bool *r_keyDown, bool *r_is_repeated_modifier); + GHOST_TKey hardKey(RAWINPUT const &raw, bool *r_key_down); /** * Creates mouse button event. @@ -387,7 +386,7 @@ class GHOST_SystemWin32 : public GHOST_System { static GHOST_Event *processImeEvent(GHOST_TEventType type, GHOST_WindowWin32 *window, GHOST_TEventImeData *data); -#endif // WITH_INPUT_IME +#endif /* WITH_INPUT_IME */ /** * Handles minimum window size. @@ -417,19 +416,6 @@ class GHOST_SystemWin32 : public GHOST_System { void processTrackpad(); /** - * Returns the local state of the modifier keys (from the message queue). - * \param keys: The state of the keys. - */ - inline void retrieveModifierKeys(GHOST_ModifierKeys &keys) const; - - /** - * Stores the state of the modifier keys locally. - * For internal use only! - * param keys The new state of the modifier keys. - */ - inline void storeModifierKeys(const GHOST_ModifierKeys &keys); - - /** * Check current key layout for AltGr */ inline void handleKeyboardChange(void); @@ -444,10 +430,8 @@ class GHOST_SystemWin32 : public GHOST_System { * \param action: console state * \return current status (1 -visible, 0 - hidden) */ - int setConsoleWindowState(GHOST_TConsoleWindowState action); + bool setConsoleWindowState(GHOST_TConsoleWindowState action); - /** The current state of the modifier keys. */ - GHOST_ModifierKeys m_modifierKeys; /** The virtual-key code (VKey) of the last press event. Used to detect repeat events. */ unsigned short m_keycode_last_repeat_key; /** State variable set at initialization. */ @@ -466,36 +450,26 @@ class GHOST_SystemWin32 : public GHOST_System { HKL m_keylayout; /** Console status. */ - int m_consoleStatus; + bool m_consoleStatus; /** Wheel delta accumulator. */ int m_wheelDeltaAccum; }; -inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys &keys) const -{ - keys = m_modifierKeys; -} - -inline void GHOST_SystemWin32::storeModifierKeys(const GHOST_ModifierKeys &keys) -{ - m_modifierKeys = keys; -} - inline void GHOST_SystemWin32::handleKeyboardChange(void) { - m_keylayout = GetKeyboardLayout(0); // get keylayout for current thread + m_keylayout = GetKeyboardLayout(0); /* Get keylayout for current thread. */ int i; SHORT s; - // save the language identifier. + /* Save the language identifier. */ m_langId = LOWORD(m_keylayout); for (m_hasAltGr = false, i = 32; i < 256; ++i) { s = VkKeyScanEx((char)i, m_keylayout); - // s == -1 means no key that translates passed char code - // high byte contains shift state. bit 2 ctrl pressed, bit 4 alt pressed - // if both are pressed, we have AltGr keycombo on keylayout + /* `s == -1` means no key that translates passed char code high byte contains shift state. + * bit 2 Control pressed, bit 4 `Alt` pressed if both are pressed, + * we have `AltGr` key-combination on key-layout. */ if (s != -1 && (s & 0x600) == 0x600) { m_hasAltGr = true; break; diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 0494e462bfc..08ac0edb7ec 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -33,12 +33,8 @@ #include "GHOST_Debug.h" -#if defined(WITH_GL_EGL) -# include "GHOST_ContextEGL.h" -# include <EGL/eglext.h> -#else -# include "GHOST_ContextGLX.h" -#endif +#include "GHOST_ContextEGL.h" +#include "GHOST_ContextGLX.h" #ifdef WITH_XF86KEYSYM # include <X11/XF86keysym.h> @@ -105,8 +101,7 @@ GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(nullptr), m_sta m_display = XOpenDisplay(nullptr); if (!m_display) { - std::cerr << "Unable to open a display" << std::endl; - abort(); /* was return before, but this would just mean it will crash later */ + throw std::runtime_error("X11: Unable to open a display"); } #ifdef USE_X11_ERROR_HANDLERS @@ -235,10 +230,6 @@ GHOST_SystemX11::~GHOST_SystemX11() clearXInputDevices(); #endif /* WITH_X11_XINPUT */ -#ifdef WITH_GL_EGL - ::eglTerminate(::eglGetDisplay(m_display)); -#endif - if (m_xkb_descr) { XkbFreeKeyboard(m_xkb_descr, XkbAllComponentsMask, true); } @@ -354,7 +345,6 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title, is_dialog, ((glSettings.flags & GHOST_glStereoVisual) != 0), exclusive, - ((glSettings.flags & GHOST_glAlphaBackground) != 0), (glSettings.flags & GHOST_glDebugContext) != 0); if (window) { @@ -375,6 +365,56 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title, return window; } +#ifdef USE_EGL +static GHOST_Context *create_egl_context( + GHOST_SystemX11 *system, Display *display, bool debug_context, int ver_major, int ver_minor) +{ + GHOST_Context *context; + context = new GHOST_ContextEGL(system, + false, + EGLNativeWindowType(nullptr), + EGLNativeDisplayType(display), + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + ver_major, + ver_minor, + GHOST_OPENGL_EGL_CONTEXT_FLAGS | + (debug_context ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0), + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_API); + + if (context->initializeDrawingContext()) { + return context; + } + delete context; + + return nullptr; +} +#endif + +static GHOST_Context *create_glx_context(Display *display, + bool debug_context, + int ver_major, + int ver_minor) +{ + GHOST_Context *context; + context = new GHOST_ContextGLX(false, + (Window) nullptr, + display, + (GLXFBConfig) nullptr, + GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + ver_major, + ver_minor, + GHOST_OPENGL_GLX_CONTEXT_FLAGS | + (debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), + GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); + + if (context->initializeDrawingContext()) { + return context; + } + delete context; + + return nullptr; +} /** * Create a new off-screen context. * Never explicitly delete the context, use #disposeContext() instead. @@ -394,98 +434,33 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSetti const bool debug_context = (glSettings.flags & GHOST_glDebugContext) != 0; -#if defined(WITH_GL_PROFILE_CORE) - { - const char *version_major = (char *)glewGetString(GLEW_VERSION_MAJOR); - if (version_major != nullptr && version_major[0] == '1') { - fprintf(stderr, "Error: GLEW version 2.0 and above is required.\n"); - abort(); - } - } -#endif - - const int profile_mask = -#ifdef WITH_GL_EGL -# if defined(WITH_GL_PROFILE_CORE) - EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT; -# elif defined(WITH_GL_PROFILE_COMPAT) - EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT; -# else -# error // must specify either core or compat at build time -# endif -#else -# if defined(WITH_GL_PROFILE_CORE) - GLX_CONTEXT_CORE_PROFILE_BIT_ARB; -# elif defined(WITH_GL_PROFILE_COMPAT) - GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; -# else -# error // must specify either core or compat at build time -# endif -#endif - GHOST_Context *context; +#ifdef USE_EGL + /* Try to initialize an EGL context. */ for (int minor = 5; minor >= 0; --minor) { -#if defined(WITH_GL_EGL) - context = new GHOST_ContextEGL(this, - false, - EGLNativeWindowType(nullptr), - EGLNativeDisplayType(m_display), - profile_mask, - 4, - minor, - GHOST_OPENGL_EGL_CONTEXT_FLAGS | - (debug_context ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0), - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#else - context = new GHOST_ContextGLX(false, - (Window) nullptr, - m_display, - (GLXFBConfig) nullptr, - profile_mask, - 4, - minor, - GHOST_OPENGL_GLX_CONTEXT_FLAGS | - (debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), - GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); -#endif - - if (context->initializeDrawingContext()) { + context = create_egl_context(this, m_display, debug_context, 4, minor); + if (context != nullptr) { return context; } - delete context; + } + context = create_egl_context(this, m_display, debug_context, 3, 3); + if (context != nullptr) { + return context; } -#if defined(WITH_GL_EGL) - context = new GHOST_ContextEGL(this, - false, - EGLNativeWindowType(nullptr), - EGLNativeDisplayType(m_display), - profile_mask, - 3, - 3, - GHOST_OPENGL_EGL_CONTEXT_FLAGS | - (debug_context ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0), - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#else - context = new GHOST_ContextGLX(false, - (Window) nullptr, - m_display, - (GLXFBConfig) nullptr, - profile_mask, - 3, - 3, - GHOST_OPENGL_GLX_CONTEXT_FLAGS | - (debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), - GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); + /* EGL initialization failed, try to fallback to a GLX context. */ #endif - - if (context->initializeDrawingContext()) { + for (int minor = 5; minor >= 0; --minor) { + context = create_glx_context(m_display, debug_context, 4, minor); + if (context != nullptr) { + return context; + } + } + context = create_glx_context(m_display, debug_context, 3, 3); + if (context != nullptr) { return context; } - delete context; return nullptr; } @@ -1090,7 +1065,8 @@ void GHOST_SystemX11::processEvent(XEvent *xe) case GHOST_kKeyLeftShift: case GHOST_kKeyRightControl: case GHOST_kKeyLeftControl: - case GHOST_kKeyOS: + case GHOST_kKeyLeftOS: + case GHOST_kKeyRightOS: case GHOST_kKey0: case GHOST_kKey1: case GHOST_kKey2: @@ -1625,9 +1601,10 @@ GHOST_TSuccess GHOST_SystemX11::getModifierKeys(GHOST_ModifierKeys &keys) const keys.set(GHOST_kModifierKeyLeftAlt, ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) != 0); keys.set(GHOST_kModifierKeyRightAlt, ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) != 0); /* super (windows) - only one GHOST-kModifierKeyOS, so mapping to either */ - keys.set(GHOST_kModifierKeyOS, - (((m_keyboard_vector[super_l >> 3] >> (super_l & 7)) & 1) || - ((m_keyboard_vector[super_r >> 3] >> (super_r & 7)) & 1)) != 0); + keys.set(GHOST_kModifierKeyLeftOS, + ((m_keyboard_vector[super_l >> 3] >> (super_l & 7)) & 1) != 0); + keys.set(GHOST_kModifierKeyRightOS, + ((m_keyboard_vector[super_r >> 3] >> (super_r & 7)) & 1) != 0); return GHOST_kSuccess; } @@ -1843,8 +1820,8 @@ static GHOST_TKey ghost_key_from_keysym(const KeySym key) GXMAP(type, XK_Control_R, GHOST_kKeyRightControl); GXMAP(type, XK_Alt_L, GHOST_kKeyLeftAlt); GXMAP(type, XK_Alt_R, GHOST_kKeyRightAlt); - GXMAP(type, XK_Super_L, GHOST_kKeyOS); - GXMAP(type, XK_Super_R, GHOST_kKeyOS); + GXMAP(type, XK_Super_L, GHOST_kKeyLeftOS); + GXMAP(type, XK_Super_R, GHOST_kKeyRightOS); GXMAP(type, XK_Insert, GHOST_kKeyInsert); GXMAP(type, XK_Delete, GHOST_kKeyDelete); diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index 7938aa2b646..33376d36a92 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -115,7 +115,7 @@ class GHOST_SystemX11 : public GHOST_System { * \param state: The state of the window when opened. * \param type: The type of drawing context installed in this window. * \param stereoVisual: Create a stereo visual for quad buffered stereo. - * \param exclusive: Use to show the window ontop and ignore others (used full*screen). + * \param exclusive: Use to show the window on top and ignore others (used full-screen). * \param parentWindow: Parent (embedder) window. * \return The new window (or 0 if creation failed). */ @@ -253,7 +253,7 @@ class GHOST_SystemX11 : public GHOST_System { /** * \see GHOST_ISystem */ - int setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) + bool setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) { return 0; } diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp index db4d6c3bb71..da292a90869 100644 --- a/intern/ghost/intern/GHOST_Window.cpp +++ b/intern/ghost/intern/GHOST_Window.cpp @@ -92,6 +92,11 @@ GHOST_TSuccess GHOST_Window::getSwapInterval(int &intervalOut) return m_context->getSwapInterval(intervalOut); } +GHOST_Context *GHOST_Window::getContext() +{ + return m_context; +} + unsigned int GHOST_Window::getDefaultFramebuffer() { return (m_context) ? m_context->getDefaultFramebuffer() : 0; diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 5ff91c05b16..1c0991bba30 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -29,7 +29,7 @@ class GHOST_Window : public GHOST_IWindow { * \param height: The height of the window. * \param state: The state the window is initially opened with. * \param wantStereoVisual: Stereo visual for quad buffered stereo. - * \param exclusive: Use to show the window ontop and ignore others (used full-screen). + * \param exclusive: Use to show the window on top and ignore others (used full-screen). */ GHOST_Window(uint32_t width, uint32_t height, @@ -72,7 +72,7 @@ class GHOST_Window : public GHOST_IWindow { * Returns indication as to whether the window is valid. * \return The validity of the window. */ - virtual bool getValid() const + virtual bool getValid() const override { return m_context != NULL; } @@ -81,15 +81,15 @@ class GHOST_Window : public GHOST_IWindow { * Returns the associated OS object/handle * \return The associated OS object/handle */ - virtual void *getOSWindow() const; + virtual void *getOSWindow() const override; /** * Returns the current cursor shape. * \return The current cursor shape. */ - inline GHOST_TStandardCursor getCursorShape() const; + inline GHOST_TStandardCursor getCursorShape() const override; - inline bool isDialog() const + inline bool isDialog() const override { return false; } @@ -99,7 +99,7 @@ class GHOST_Window : public GHOST_IWindow { * \param cursorShape: The new cursor shape type id. * \return Indication of success. */ - GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape); + GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape) override; /** * Set the shape of the cursor to a custom cursor. @@ -115,15 +115,15 @@ class GHOST_Window : public GHOST_IWindow { int sizey, int hotX, int hotY, - bool canInvertColor); + bool canInvertColor) override; - GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap); + GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap) override; /** * Returns the visibility state of the cursor. * \return The visibility state of the cursor. */ - inline bool getCursorVisibility() const; + inline bool getCursorVisibility() const override; inline GHOST_TGrabCursorMode getCursorGrabMode() const; inline bool getCursorGrabModeIsWarp() const; inline GHOST_TAxisFlag getCursorGrabAxis() const; @@ -136,7 +136,7 @@ class GHOST_Window : public GHOST_IWindow { * \param visible: The new visibility state of the cursor. * \return Indication of success. */ - GHOST_TSuccess setCursorVisibility(bool visible); + GHOST_TSuccess setCursorVisibility(bool visible) override; /** * Sets the cursor grab. @@ -146,28 +146,28 @@ class GHOST_Window : public GHOST_IWindow { GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode mode, GHOST_TAxisFlag wrap_axis, GHOST_Rect *bounds, - int32_t mouse_ungrab_xy[2]); + int32_t mouse_ungrab_xy[2]) override; /** * Gets the cursor grab region, if unset the window is used. * reset when grab is disabled. */ - GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds); + GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) override; void getCursorGrabState(GHOST_TGrabCursorMode &mode, GHOST_TAxisFlag &axis_flag, GHOST_Rect &bounds, - bool &use_software_cursor); + bool &use_software_cursor) override; /** * Return true when a software cursor should be used. */ - bool getCursorGrabUseSoftwareDisplay(); + bool getCursorGrabUseSoftwareDisplay() override; /** * Sets the progress bar value displayed in the window/application icon * \param progress: The progress percentage (0.0 to 1.0). */ - virtual GHOST_TSuccess setProgressBar(float /*progress*/) + virtual GHOST_TSuccess setProgressBar(float /*progress*/) override { return GHOST_kFailure; } @@ -175,7 +175,7 @@ class GHOST_Window : public GHOST_IWindow { /** * Hides the progress bar in the icon */ - virtual GHOST_TSuccess endProgressBar() + virtual GHOST_TSuccess endProgressBar() override { return GHOST_kFailure; } @@ -185,43 +185,43 @@ class GHOST_Window : public GHOST_IWindow { * \param interval: The swap interval to use. * \return A boolean success indicator. */ - GHOST_TSuccess setSwapInterval(int interval); + GHOST_TSuccess setSwapInterval(int interval) override; /** * Gets the current swap interval for #swapBuffers. * \return An integer. */ - GHOST_TSuccess getSwapInterval(int &intervalOut); + GHOST_TSuccess getSwapInterval(int &intervalOut) override; /** * Tells if the ongoing drag'n'drop object can be accepted upon mouse drop */ - void setAcceptDragOperation(bool canAccept); + void setAcceptDragOperation(bool canAccept) override; /** * Returns acceptance of the dropped object * Usually called by the "object dropped" event handling function */ - bool canAcceptDragOperation() const; + bool canAcceptDragOperation() const override; /** * Sets the window "modified" status, indicating unsaved changes * \param isUnsavedChanges: Unsaved changes or not. * \return Indication of success. */ - virtual GHOST_TSuccess setModifiedState(bool isUnsavedChanges); + virtual GHOST_TSuccess setModifiedState(bool isUnsavedChanges) override; /** * Gets the window "modified" status, indicating unsaved changes * \return True if there are unsaved changes */ - virtual bool getModifiedState(); + virtual bool getModifiedState() override; /** * Returns the type of drawing context used in this window. * \return The current type of drawing context. */ - inline GHOST_TDrawingContextType getDrawingContextType(); + inline GHOST_TDrawingContextType getDrawingContextType() override; /** * Tries to install a rendering context in this window. @@ -230,19 +230,19 @@ class GHOST_Window : public GHOST_IWindow { * \param type: The type of rendering context installed. * \return Indication as to whether installation has succeeded. */ - GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type); + GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type) override; /** * Swaps front and back buffers of a window. * \return A boolean success indicator. */ - virtual GHOST_TSuccess swapBuffers(); + virtual GHOST_TSuccess swapBuffers() override; /** * Activates the drawing context of this window. * \return A boolean success indicator. */ - virtual GHOST_TSuccess activateDrawingContext(); + virtual GHOST_TSuccess activateDrawingContext() override; /** * Updates the drawing context of this window. Needed @@ -252,16 +252,22 @@ class GHOST_Window : public GHOST_IWindow { GHOST_TSuccess updateDrawingContext(); /** + * Get the drawing context associated with this window. + *\return Pointer to the context object. + */ + GHOST_Context *getContext(); + + /** * Gets the OpenGL frame-buffer associated with the window's contents. * \return The ID of an OpenGL frame-buffer object. */ - virtual unsigned int getDefaultFramebuffer(); + virtual unsigned int getDefaultFramebuffer() override; /** * Returns the window user data. * \return The window user data. */ - inline GHOST_TUserDataPtr getUserData() const + inline GHOST_TUserDataPtr getUserData() const override { return m_userData; } @@ -270,12 +276,12 @@ class GHOST_Window : public GHOST_IWindow { * Changes the window user data. * \param userData: The window user data. */ - void setUserData(const GHOST_TUserDataPtr userData) + void setUserData(const GHOST_TUserDataPtr userData) override { m_userData = userData; } - float getNativePixelSize(void) + float getNativePixelSize(void) override { if (m_nativePixelSize > 0.0f) return m_nativePixelSize; @@ -286,18 +292,18 @@ class GHOST_Window : public GHOST_IWindow { * Returns the recommended DPI for this window. * \return The recommended DPI for this window. */ - virtual inline uint16_t getDPIHint() + virtual inline uint16_t getDPIHint() override { return 96; } #ifdef WITH_INPUT_IME - virtual void beginIME(int32_t x, int32_t y, int32_t w, int32_t h, bool completed) + virtual void beginIME(int32_t x, int32_t y, int32_t w, int32_t h, bool completed) override { /* do nothing temporarily if not in windows */ } - virtual void endIME() + virtual void endIME() override { /* do nothing temporarily if not in windows */ } diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index e7f5fdaa011..737fd64bdf0 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -719,7 +719,7 @@ void GHOST_WindowCocoa::setNativePixelSize(void) } /** - * \note Fullscreen switch is not actual fullscreen with display capture. + * \note Full-screen switch is not actual fullscreen with display capture. * As this capture removes all OS X window manager features. * * Instead, the menu bar and the dock are hidden, and the window is made border-less and enlarged. diff --git a/intern/ghost/intern/GHOST_WindowManager.h b/intern/ghost/intern/GHOST_WindowManager.h index bf7a0f4ec61..a0a58fa82d8 100644 --- a/intern/ghost/intern/GHOST_WindowManager.h +++ b/intern/ghost/intern/GHOST_WindowManager.h @@ -113,13 +113,13 @@ class GHOST_WindowManager { /** The list of windows managed */ std::vector<GHOST_IWindow *> m_windows; - /** Window in fullscreen state. There can be only one of this which is not in or window list. */ + /** Window in full-screen state. There can be only one of this which is not in or window list. */ GHOST_IWindow *m_fullScreenWindow; /** The active window. */ GHOST_IWindow *m_activeWindow; - /** Window that was active before entering fullscreen state. */ + /** Window that was active before entering full-screen state. */ GHOST_IWindow *m_activeWindowBeforeFullScreen; #ifdef WITH_CXX_GUARDEDALLOC diff --git a/intern/ghost/intern/GHOST_WindowNULL.h b/intern/ghost/intern/GHOST_WindowNULL.h index 01b50251d69..f9c0a593d5f 100644 --- a/intern/ghost/intern/GHOST_WindowNULL.h +++ b/intern/ghost/intern/GHOST_WindowNULL.h @@ -11,32 +11,31 @@ #include <map> -class GHOST_SystemNULL; +class GHOST_SystemHeadless; class GHOST_WindowNULL : public GHOST_Window { public: - GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor) + GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor /*cursorShape*/) override { return GHOST_kSuccess; } - GHOST_WindowNULL(GHOST_SystemNULL *system, - const char *title, - int32_t left, - int32_t top, + GHOST_WindowNULL(const char *title, + int32_t /*left*/, + int32_t /*top*/, uint32_t width, uint32_t height, GHOST_TWindowState state, - const GHOST_IWindow *parentWindow, - GHOST_TDrawingContextType type, + const GHOST_IWindow * /*parentWindow*/, + GHOST_TDrawingContextType /*type*/, const bool stereoVisual) - : GHOST_Window(width, height, state, stereoVisual, false), m_system(system) + : GHOST_Window(width, height, state, stereoVisual, false) { setTitle(title); } protected: - GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType type) + GHOST_TSuccess installDrawingContext(GHOST_TDrawingContextType /*type*/) { return GHOST_kSuccess; } @@ -44,114 +43,111 @@ class GHOST_WindowNULL : public GHOST_Window { { return GHOST_kSuccess; } - GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) + GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode /*mode*/) override { return GHOST_kSuccess; } - GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) + GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor /*shape*/) override { return GHOST_kSuccess; } - GHOST_TSuccess setWindowCustomCursorShape(uint8_t *bitmap, - uint8_t *mask, - int sizex, - int sizey, - int hotX, - int hotY, - bool canInvertColor) + GHOST_TSuccess setWindowCustomCursorShape(uint8_t * /*bitmap*/, + uint8_t * /*mask*/, + int /*sizex*/, + int /*sizey*/, + int /*hotX*/, + int /*hotY*/, + bool /*canInvertColor*/) override { return GHOST_kSuccess; } - bool getValid() const + bool getValid() const override { return true; } - void setTitle(const char *title) + void setTitle(const char * /*title*/) override { /* nothing */ } - std::string getTitle() const + std::string getTitle() const override { return "untitled"; } - void getWindowBounds(GHOST_Rect &bounds) const + void getWindowBounds(GHOST_Rect &bounds) const override { getClientBounds(bounds); } - void getClientBounds(GHOST_Rect &bounds) const + void getClientBounds(GHOST_Rect & /*bounds*/) const override { /* nothing */ } - GHOST_TSuccess setClientWidth(uint32_t width) + GHOST_TSuccess setClientWidth(uint32_t /*width*/) override { return GHOST_kFailure; } - GHOST_TSuccess setClientHeight(uint32_t height) + GHOST_TSuccess setClientHeight(uint32_t /*height*/) override { return GHOST_kFailure; } - GHOST_TSuccess setClientSize(uint32_t width, uint32_t height) + GHOST_TSuccess setClientSize(uint32_t /*width*/, uint32_t /*height*/) override { return GHOST_kFailure; } - void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const + void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const override { outX = inX; outY = inY; } - void clientToScreen(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const + void clientToScreen(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const override { outX = inX; outY = inY; } - GHOST_TSuccess swapBuffers() + GHOST_TSuccess swapBuffers() override { return GHOST_kFailure; } - GHOST_TSuccess activateDrawingContext() + GHOST_TSuccess activateDrawingContext() override { return GHOST_kFailure; } - ~GHOST_WindowNULL() - { /* nothing */ - } - GHOST_TSuccess setWindowCursorVisibility(bool visible) + ~GHOST_WindowNULL() override = default; + + GHOST_TSuccess setWindowCursorVisibility(bool /*visible*/) override { return GHOST_kSuccess; } - GHOST_TSuccess setState(GHOST_TWindowState state) + GHOST_TSuccess setState(GHOST_TWindowState /*state*/) override { return GHOST_kSuccess; } - GHOST_TWindowState getState() const + GHOST_TWindowState getState() const override { return GHOST_kWindowStateNormal; } - GHOST_TSuccess invalidate() + GHOST_TSuccess invalidate() override { return GHOST_kSuccess; } - GHOST_TSuccess setOrder(GHOST_TWindowOrder order) + GHOST_TSuccess setOrder(GHOST_TWindowOrder /*order*/) override { return GHOST_kSuccess; } - GHOST_TSuccess beginFullScreen() const + GHOST_TSuccess beginFullScreen() const override { return GHOST_kSuccess; } - GHOST_TSuccess endFullScreen() const + GHOST_TSuccess endFullScreen() const override { return GHOST_kSuccess; } private: - GHOST_SystemNULL *m_system; - /** * \param type: The type of rendering context create. * \return Indication of success. */ - GHOST_Context *newDrawingContext(GHOST_TDrawingContextType type) + GHOST_Context *newDrawingContext(GHOST_TDrawingContextType /*type*/) override { return nullptr; } diff --git a/intern/ghost/intern/GHOST_WindowSDL.cpp b/intern/ghost/intern/GHOST_WindowSDL.cpp index 09192d989e4..59dc80cf7e6 100644 --- a/intern/ghost/intern/GHOST_WindowSDL.cpp +++ b/intern/ghost/intern/GHOST_WindowSDL.cpp @@ -6,7 +6,6 @@ #include "GHOST_WindowSDL.h" #include "SDL_mouse.h" -#include "glew-mx.h" #include "GHOST_ContextSDL.h" diff --git a/intern/ghost/intern/GHOST_WindowViewCocoa.h b/intern/ghost/intern/GHOST_WindowViewCocoa.h index 58c029620da..29653bd5ea2 100644 --- a/intern/ghost/intern/GHOST_WindowViewCocoa.h +++ b/intern/ghost/intern/GHOST_WindowViewCocoa.h @@ -226,7 +226,7 @@ [super drawRect:rect]; systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, associatedWindow); - /* For some cases like entering fullscreen we need to redraw immediately + /* For some cases like entering full-screen we need to redraw immediately * so our window does not show blank during the animation */ if (associatedWindow->getImmediateDraw()) systemCocoa->dispatchEvents(); diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp index e303bd5b6aa..5f3cb3e3f3a 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.cpp +++ b/intern/ghost/intern/GHOST_WindowWayland.cpp @@ -38,7 +38,7 @@ static constexpr size_t base_dpi = 96; static GHOST_WindowManager *window_manager = nullptr; -struct window_t { +struct GWL_Window { GHOST_WindowWayland *w = nullptr; struct wl_surface *wl_surface = nullptr; /** @@ -47,7 +47,7 @@ struct window_t { * This is an ordered set (whoever adds to this is responsible for keeping members unique). * In practice this is rarely manipulated and is limited by the number of physical displays. */ - std::vector<output_t *> outputs; + std::vector<GWL_Output *> outputs; /** The scale value written to #wl_surface_set_buffer_scale. */ int scale = 0; @@ -87,7 +87,7 @@ struct window_t { /** * Return -1 if `output_a` has a scale smaller than `output_b`, 0 when there equal, otherwise 1. */ -static int output_scale_cmp(const output_t *output_a, const output_t *output_b) +static int output_scale_cmp(const GWL_Output *output_a, const GWL_Output *output_b) { if (output_a->scale < output_b->scale) { return -1; @@ -112,12 +112,12 @@ static int output_scale_cmp(const output_t *output_a, const output_t *output_b) return 0; } -static int outputs_max_scale_or_default(const std::vector<output_t *> &outputs, +static int outputs_max_scale_or_default(const std::vector<GWL_Output *> &outputs, const int32_t scale_default, uint32_t *r_dpi) { - const output_t *output_max = nullptr; - for (const output_t *reg_output : outputs) { + const GWL_Output *output_max = nullptr; + for (const GWL_Output *reg_output : outputs) { if (!output_max || (output_scale_cmp(output_max, reg_output) == -1)) { output_max = reg_output; } @@ -160,7 +160,7 @@ static void xdg_toplevel_handle_configure(void *data, /* TODO: log `states`, not urgent. */ CLOG_INFO(LOG, 2, "configure (size=[%d, %d])", width, height); - window_t *win = static_cast<window_t *>(data); + GWL_Window *win = static_cast<GWL_Window *>(data); win->size_pending[0] = win->scale * width; win->size_pending[1] = win->scale * height; @@ -189,7 +189,7 @@ static void xdg_toplevel_handle_configure(void *data, static void xdg_toplevel_handle_close(void *data, xdg_toplevel * /*xdg_toplevel*/) { CLOG_INFO(LOG, 2, "close"); - static_cast<window_t *>(data)->w->close(); + static_cast<GWL_Window *>(data)->w->close(); } static const xdg_toplevel_listener toplevel_listener = { @@ -218,7 +218,7 @@ static void frame_handle_configure(struct libdecor_frame *frame, { CLOG_INFO(LOG, 2, "configure"); - window_t *win = static_cast<window_t *>(data); + GWL_Window *win = static_cast<GWL_Window *>(data); int size_next[2]; enum libdecor_window_state window_state; @@ -257,7 +257,7 @@ static void frame_handle_close(struct libdecor_frame * /*frame*/, void *data) { CLOG_INFO(LOG, 2, "close"); - static_cast<window_t *>(data)->w->close(); + static_cast<GWL_Window *>(data)->w->close(); } static void frame_handle_commit(struct libdecor_frame * /*frame*/, void *data) @@ -265,8 +265,8 @@ static void frame_handle_commit(struct libdecor_frame * /*frame*/, void *data) CLOG_INFO(LOG, 2, "commit"); /* We have to swap twice to keep any pop-up menus alive. */ - static_cast<window_t *>(data)->w->swapBuffers(); - static_cast<window_t *>(data)->w->swapBuffers(); + static_cast<GWL_Window *>(data)->w->swapBuffers(); + static_cast<GWL_Window *>(data)->w->swapBuffers(); } static struct libdecor_frame_interface libdecor_frame_iface = { @@ -296,7 +296,7 @@ static void xdg_toplevel_decoration_handle_configure( const uint32_t mode) { CLOG_INFO(LOG, 2, "configure (mode=%u)", mode); - static_cast<window_t *>(data)->decoration_mode = (zxdg_toplevel_decoration_v1_mode)mode; + static_cast<GWL_Window *>(data)->decoration_mode = (zxdg_toplevel_decoration_v1_mode)mode; } static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listener = { @@ -322,7 +322,7 @@ static void xdg_surface_handle_configure(void *data, xdg_surface *xdg_surface, const uint32_t serial) { - window_t *win = static_cast<window_t *>(data); + GWL_Window *win = static_cast<GWL_Window *>(data); if (win->xdg_surface != xdg_surface) { CLOG_INFO(LOG, 2, "configure (skipped)"); @@ -369,15 +369,15 @@ static CLG_LogRef LOG_WL_SURFACE = {"ghost.wl.handle.surface"}; static void surface_handle_enter(void *data, struct wl_surface * /*wl_surface*/, - struct wl_output *output) + struct wl_output *wl_output) { - if (!ghost_wl_output_own(output)) { + if (!ghost_wl_output_own(wl_output)) { CLOG_INFO(LOG, 2, "enter (skipped)"); return; } CLOG_INFO(LOG, 2, "enter"); - output_t *reg_output = ghost_wl_output_user_data(output); + GWL_Output *reg_output = ghost_wl_output_user_data(wl_output); GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(data); if (win->outputs_enter(reg_output)) { win->outputs_changed_update_scale(); @@ -386,15 +386,15 @@ static void surface_handle_enter(void *data, static void surface_handle_leave(void *data, struct wl_surface * /*wl_surface*/, - struct wl_output *output) + struct wl_output *wl_output) { - if (!ghost_wl_output_own(output)) { + if (!ghost_wl_output_own(wl_output)) { CLOG_INFO(LOG, 2, "leave (skipped)"); return; } CLOG_INFO(LOG, 2, "leave"); - output_t *reg_output = ghost_wl_output_user_data(output); + GWL_Output *reg_output = ghost_wl_output_user_data(wl_output); GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(data); if (win->outputs_leave(reg_output)) { win->outputs_changed_update_scale(); @@ -435,7 +435,7 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system, const bool exclusive) : GHOST_Window(width, height, state, stereoVisual, exclusive), m_system(system), - w(new window_t) + w(new GWL_Window) { /* Globally store pointer to window manager. */ if (!window_manager) { @@ -877,12 +877,12 @@ int GHOST_WindowWayland::scale() const return w->scale; } -wl_surface *GHOST_WindowWayland::surface() const +wl_surface *GHOST_WindowWayland::wl_surface() const { return w->wl_surface; } -const std::vector<output_t *> &GHOST_WindowWayland::outputs() +const std::vector<GWL_Output *> &GHOST_WindowWayland::outputs() { return w->outputs; } @@ -935,6 +935,9 @@ GHOST_TSuccess GHOST_WindowWayland::notify_size() * Functionality only used for the WAYLAND implementation. * \{ */ +/** + * Return true when the windows scale or DPI changes. + */ bool GHOST_WindowWayland::outputs_changed_update_scale() { uint32_t dpi_next; @@ -943,7 +946,7 @@ bool GHOST_WindowWayland::outputs_changed_update_scale() return false; } - window_t *win = this->w; + GWL_Window *win = this->w; const uint32_t dpi_curr = win->dpi; const int scale_curr = win->scale; bool changed = false; @@ -963,26 +966,32 @@ bool GHOST_WindowWayland::outputs_changed_update_scale() * use a multiplier for the default DPI as workaround. */ win->dpi = dpi_next; changed = true; + + /* As this is a low-level function, we might want adding this event to be optional, + * always add the event unless it causes issues. */ + GHOST_System *system = (GHOST_System *)GHOST_ISystem::getSystem(); + system->pushEvent( + new GHOST_Event(system->getMilliSeconds(), GHOST_kEventWindowDPIHintChanged, this)); } return changed; } -bool GHOST_WindowWayland::outputs_enter(output_t *reg_output) +bool GHOST_WindowWayland::outputs_enter(GWL_Output *output) { - std::vector<output_t *> &outputs = w->outputs; - auto it = std::find(outputs.begin(), outputs.end(), reg_output); + std::vector<GWL_Output *> &outputs = w->outputs; + auto it = std::find(outputs.begin(), outputs.end(), output); if (it != outputs.end()) { return false; } - outputs.push_back(reg_output); + outputs.push_back(output); return true; } -bool GHOST_WindowWayland::outputs_leave(output_t *reg_output) +bool GHOST_WindowWayland::outputs_leave(GWL_Output *output) { - std::vector<output_t *> &outputs = w->outputs; - auto it = std::find(outputs.begin(), outputs.end(), reg_output); + std::vector<GWL_Output *> &outputs = w->outputs; + auto it = std::find(outputs.begin(), outputs.end(), output); if (it == outputs.end()) { return false; } diff --git a/intern/ghost/intern/GHOST_WindowWayland.h b/intern/ghost/intern/GHOST_WindowWayland.h index c754e4cd9e7..9b4c17ecd95 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.h +++ b/intern/ghost/intern/GHOST_WindowWayland.h @@ -14,8 +14,8 @@ class GHOST_SystemWayland; -struct output_t; -struct window_t; +struct GWL_Output; +struct GWL_Window; class GHOST_WindowWayland : public GHOST_Window { public: @@ -97,8 +97,8 @@ class GHOST_WindowWayland : public GHOST_Window { uint16_t dpi() const; int scale() const; - struct wl_surface *surface() const; - const std::vector<output_t *> &outputs(); + struct wl_surface *wl_surface() const; + const std::vector<GWL_Output *> &outputs(); /* WAYLAND window-level functions. */ @@ -109,14 +109,14 @@ class GHOST_WindowWayland : public GHOST_Window { /* WAYLAND utility functions. */ - bool outputs_enter(output_t *reg_output); - bool outputs_leave(output_t *reg_output); + bool outputs_enter(GWL_Output *output); + bool outputs_leave(GWL_Output *output); bool outputs_changed_update_scale(); private: GHOST_SystemWayland *m_system; - struct window_t *w; + struct GWL_Window *w; std::string title; /** diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 2e17454d24f..50ee9385e39 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -26,7 +26,7 @@ #ifndef GET_POINTERID_WPARAM # define GET_POINTERID_WPARAM(wParam) (LOWORD(wParam)) -#endif // GET_POINTERID_WPARAM +#endif /* GET_POINTERID_WPARAM */ const wchar_t *GHOST_WindowWin32::s_windowClassName = L"GHOST_WindowClass"; const int GHOST_WindowWin32::s_maxTitleLength = 128; @@ -93,18 +93,18 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, adjustWindowRectForClosestMonitor(&win_rect, style, extended_style); wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0); - m_hWnd = ::CreateWindowExW(extended_style, // window extended style - s_windowClassName, // pointer to registered class name - title_16, // pointer to window name - style, // window style - win_rect.left, // horizontal position of window - win_rect.top, // vertical position of window - win_rect.right - win_rect.left, // window width - win_rect.bottom - win_rect.top, // window height - m_parentWindowHwnd, // handle to parent or owner window - 0, // handle to menu or child-window identifier - ::GetModuleHandle(0), // handle to application instance - 0); // pointer to window-creation data + m_hWnd = ::CreateWindowExW(extended_style, /* window extended style */ + s_windowClassName, /* pointer to registered class name */ + title_16, /* pointer to window name */ + style, /* window style */ + win_rect.left, /* horizontal position of window */ + win_rect.top, /* vertical position of window */ + win_rect.right - win_rect.left, /* window width */ + win_rect.bottom - win_rect.top, /* window height */ + m_parentWindowHwnd, /* handle to parent or owner window */ + 0, /* handle to menu or child-window identifier */ + ::GetModuleHandle(0), /* handle to application instance */ + 0); /* pointer to window-creation data */ free(title_16); if (m_hWnd == NULL) { @@ -197,7 +197,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, /* Force an initial paint of the window. */ ::UpdateWindow(m_hWnd); - /* Initialize Wintab. */ + /* Initialize WINTAB. */ if (system->getTabletAPI() != GHOST_kTabletWinPointer) { loadWintab(GHOST_kWindowStateMinimized != state); } @@ -221,7 +221,7 @@ void GHOST_WindowWin32::updateDirectManipulation() void GHOST_WindowWin32::onPointerHitTest(WPARAM wParam) { - /* Only DM_POINTERHITTEST can be the first message of input sequence of touchpad input. */ + /* Only #DM_POINTERHITTEST can be the first message of input sequence of touch-pad input. */ if (!m_directManipulationHelper) { return; @@ -280,9 +280,9 @@ GHOST_WindowWin32::~GHOST_WindowWin32() } if (m_dropTarget) { - // Disable DragDrop + /* Disable DragDrop. */ RevokeDragDrop(m_hWnd); - // Release our reference of the DropTarget and it will delete itself eventually. + /* Release our reference of the DropTarget and it will delete itself eventually. */ m_dropTarget->Release(); m_dropTarget = NULL; } @@ -531,7 +531,8 @@ GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state) break; } ::SetWindowLongPtr(m_hWnd, GWL_STYLE, style); - /* SetWindowLongPtr Docs: frame changes not visible until SetWindowPos with SWP_FRAMECHANGED. */ + /* #SetWindowLongPtr Docs: + * Frame changes not visible until #SetWindowPos with #SWP_FRAMECHANGED. */ ::SetWindowPos(m_hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure; } @@ -580,7 +581,6 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty if (type == GHOST_kDrawingContextTypeOpenGL) { GHOST_Context *context; -#if defined(WITH_GL_PROFILE_CORE) /* - AMD and Intel give us exactly this version * - NVIDIA gives at least this version <-- desired behavior * So we ask for 4.5, 4.4 ... 3.3 in descending order @@ -619,40 +619,14 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty } return context; - -#elif defined(WITH_GL_PROFILE_COMPAT) - // ask for 2.1 context, driver gives any GL version >= 2.1 - // (hopefully the latest compatibility profile) - // 2.1 ignores the profile bit & is incompatible with core profile - context = new GHOST_ContextWGL(m_wantStereoVisual, - m_wantAlphaBackground, - m_hWnd, - m_hDC, - 0, // no profile bit - 2, - 1, - (m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0), - GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); - - if (context->initializeDrawingContext()) { - return context; - } - else { - delete context; - } -#else -# error // must specify either core or compat at build time -#endif } else if (type == GHOST_kDrawingContextTypeD3D) { GHOST_Context *context; context = new GHOST_ContextD3D(false, m_hWnd); - if (context->initializeDrawingContext()) { - return context; - } - else { + if (!context->initializeDrawingContext()) { delete context; + context = nullptr; } return context; @@ -705,7 +679,7 @@ void GHOST_WindowWin32::updateMouseCapture(GHOST_MouseCaptureEventWin32 event) HCURSOR GHOST_WindowWin32::getStandardCursor(GHOST_TStandardCursor shape) const { - // Convert GHOST cursor to Windows OEM cursor + /* Convert GHOST cursor to Windows OEM cursor. */ HANDLE cursor = NULL; HMODULE module = ::GetModuleHandle(0); uint32_t flags = LR_SHARED | LR_DEFAULTSIZE; @@ -763,36 +737,36 @@ HCURSOR GHOST_WindowWin32::getStandardCursor(GHOST_TStandardCursor shape) const break; case GHOST_kStandardCursorHelp: cursor = ::LoadImage(NULL, IDC_HELP, IMAGE_CURSOR, cx, cy, flags); - break; // Arrow and question mark + break; /* Arrow and question mark */ case GHOST_kStandardCursorWait: cursor = ::LoadImage(NULL, IDC_WAIT, IMAGE_CURSOR, cx, cy, flags); - break; // Hourglass + break; /* Hourglass */ case GHOST_kStandardCursorText: cursor = ::LoadImage(NULL, IDC_IBEAM, IMAGE_CURSOR, cx, cy, flags); - break; // I-beam + break; /* I-beam */ case GHOST_kStandardCursorCrosshair: cursor = ::LoadImage(module, "cross_cursor", IMAGE_CURSOR, cx, cy, flags); - break; // Standard Cross + break; /* Standard Cross */ case GHOST_kStandardCursorCrosshairA: cursor = ::LoadImage(module, "crossA_cursor", IMAGE_CURSOR, cx, cy, flags); - break; // Crosshair A + break; /* Crosshair A */ case GHOST_kStandardCursorCrosshairB: cursor = ::LoadImage(module, "crossB_cursor", IMAGE_CURSOR, cx, cy, flags); - break; // Diagonal Crosshair B + break; /* Diagonal Crosshair B */ case GHOST_kStandardCursorCrosshairC: cursor = ::LoadImage(module, "crossC_cursor", IMAGE_CURSOR, cx, cy, flags); - break; // Minimal Crosshair C + break; /* Minimal Crosshair C */ case GHOST_kStandardCursorBottomSide: case GHOST_kStandardCursorUpDown: cursor = ::LoadImage(module, "movens_cursor", IMAGE_CURSOR, cx, cy, flags); - break; // Double-pointed arrow pointing north and south + break; /* Double-pointed arrow pointing north and south */ case GHOST_kStandardCursorLeftSide: case GHOST_kStandardCursorLeftRight: cursor = ::LoadImage(module, "moveew_cursor", IMAGE_CURSOR, cx, cy, flags); - break; // Double-pointed arrow pointing west and east + break; /* Double-pointed arrow pointing west and east */ case GHOST_kStandardCursorTopSide: cursor = ::LoadImage(NULL, IDC_UPARROW, IMAGE_CURSOR, cx, cy, flags); - break; // Vertical arrow + break; /* Vertical arrow */ case GHOST_kStandardCursorTopLeftCorner: cursor = ::LoadImage(NULL, IDC_SIZENWSE, IMAGE_CURSOR, cx, cy, flags); break; @@ -814,7 +788,7 @@ HCURSOR GHOST_WindowWin32::getStandardCursor(GHOST_TStandardCursor shape) const case GHOST_kStandardCursorDestroy: case GHOST_kStandardCursorStop: cursor = ::LoadImage(module, "forbidden_cursor", IMAGE_CURSOR, cx, cy, flags); - break; // Slashed circle + break; /* Slashed circle */ case GHOST_kStandardCursorDefault: cursor = NULL; break; @@ -863,8 +837,9 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]); setCursorGrabAccum(0, 0); - if (mode == GHOST_kGrabHide) + if (mode == GHOST_kGrabHide) { setWindowCursorVisibility(false); + } } updateMouseCapture(OperatorGrab); } @@ -874,9 +849,9 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode setWindowCursorVisibility(true); } if (m_cursorGrab != GHOST_kGrabNormal) { - /* use to generate a mouse move event, otherwise the last event + /* Use to generate a mouse move event, otherwise the last event * blender gets can be outside the screen causing menus not to show - * properly unless the user moves the mouse */ + * properly unless the user moves the mouse. */ int32_t pos[2]; m_system->getCursorPosition(pos[0], pos[1]); m_system->setCursorPosition(pos[0], pos[1]); @@ -927,7 +902,7 @@ GHOST_TSuccess GHOST_WindowWin32::getPointerInfo( for (uint32_t i = 0; i < outCount; i++) { POINTER_INFO pointerApiInfo = pointerPenInfo[i].pointerInfo; - // Obtain the basic information from the event + /* Obtain the basic information from the event. */ outPointerInfo[i].pointerId = pointerId; outPointerInfo[i].isPrimary = isPrimary; @@ -1069,8 +1044,9 @@ void GHOST_WindowWin32::ThemeRefresh() &pcbData) == ERROR_SUCCESS) { BOOL DarkMode = !lightMode; - /* 20 == DWMWA_USE_IMMERSIVE_DARK_MODE in Windows 11 SDK. This value was undocumented for - * Windows 10 versions 2004 and later, supported for Windows 11 Build 22000 and later. */ + /* `20 == DWMWA_USE_IMMERSIVE_DARK_MODE` in Windows 11 SDK. + * This value was undocumented for Windows 10 versions 2004 and later, + * supported for Windows 11 Build 22000 and later. */ DwmSetWindowAttribute(this->m_hWnd, 20, &DarkMode, sizeof(DarkMode)); } } @@ -1126,8 +1102,9 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape( int x, y, cols; cols = sizeX / 8; /* Number of whole bytes per row (width of bitmap/mask). */ - if (sizeX % 8) + if (sizeX % 8) { cols++; + } if (m_customCursor) { DestroyCursor(m_customCursor); @@ -1165,16 +1142,18 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape( GHOST_TSuccess GHOST_WindowWin32::setProgressBar(float progress) { /* #SetProgressValue sets state to #TBPF_NORMAL automatically. */ - if (m_Bar && S_OK == m_Bar->SetProgressValue(m_hWnd, 10000 * progress, 10000)) + if (m_Bar && S_OK == m_Bar->SetProgressValue(m_hWnd, 10000 * progress, 10000)) { return GHOST_kSuccess; + } return GHOST_kFailure; } GHOST_TSuccess GHOST_WindowWin32::endProgressBar() { - if (m_Bar && S_OK == m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS)) + if (m_Bar && S_OK == m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS)) { return GHOST_kSuccess; + } return GHOST_kFailure; } diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index 88731597caa..44071f0915e 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -10,7 +10,7 @@ #ifndef WIN32 # error WIN32 only! -#endif // WIN32 +#endif /* WIN32 */ #include "GHOST_TaskbarWin32.h" #include "GHOST_TrackpadWin32.h" @@ -25,7 +25,7 @@ class GHOST_SystemWin32; class GHOST_DropTargetWin32; -// typedefs for user32 functions to allow dynamic loading of Windows 10 DPI scaling functions +/* typedefs for user32 functions to allow dynamic loading of Windows 10 DPI scaling functions. */ typedef UINT(API *GHOST_WIN32_GetDpiForWindow)(HWND); typedef BOOL(API *GHOST_WIN32_AdjustWindowRectExForDpi)( diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 83c608435b0..113f453325d 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -10,9 +10,7 @@ #include <X11/Xmd.h> #include <X11/Xutil.h> #include <X11/cursorfont.h> -#ifdef WITH_X11_ALPHA -# include <X11/extensions/Xrender.h> -#endif + #include "GHOST_Debug.h" #include "GHOST_IconX11.h" #include "GHOST_SystemX11.h" @@ -23,12 +21,8 @@ # include "GHOST_DropTargetX11.h" #endif -#ifdef WITH_GL_EGL -# include "GHOST_ContextEGL.h" -# include <EGL/eglext.h> -#else -# include "GHOST_ContextGLX.h" -#endif +#include "GHOST_ContextEGL.h" +#include "GHOST_ContextGLX.h" /* for XIWarpPointer */ #ifdef WITH_X11_XINPUT @@ -88,9 +82,7 @@ enum { #define _NET_WM_STATE_ADD 1 // #define _NET_WM_STATE_TOGGLE 2 // UNUSED -#ifdef WITH_GL_EGL - -static XVisualInfo *x11_visualinfo_from_egl(Display *display) +static XVisualInfo *get_x11_visualinfo(Display *display) { int num_visuals; XVisualInfo vinfo_template; @@ -98,106 +90,6 @@ static XVisualInfo *x11_visualinfo_from_egl(Display *display) return XGetVisualInfo(display, VisualScreenMask, &vinfo_template, &num_visuals); } -#else - -static XVisualInfo *x11_visualinfo_from_glx(Display *display, - bool stereoVisual, - bool needAlpha, - GLXFBConfig *fbconfig) -{ - int glx_major, glx_minor, glx_version; /* GLX version: major.minor */ - int glx_attribs[64]; - - *fbconfig = nullptr; - - /* Set up the minimum attributes that we require and see if - * X can find us a visual matching those requirements. */ - - if (!glXQueryVersion(display, &glx_major, &glx_minor)) { - fprintf(stderr, - "%s:%d: X11 glXQueryVersion() failed, " - "verify working openGL system!\n", - __FILE__, - __LINE__); - - return nullptr; - } - glx_version = glx_major * 100 + glx_minor; -# ifndef WITH_X11_ALPHA - (void)glx_version; -# endif - -# ifdef WITH_X11_ALPHA - if (needAlpha && glx_version >= 103 && - (glXChooseFBConfig || (glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddressARB( - (const GLubyte *)"glXChooseFBConfig")) != nullptr) && - (glXGetVisualFromFBConfig || - (glXGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)glXGetProcAddressARB( - (const GLubyte *)"glXGetVisualFromFBConfig")) != nullptr)) { - - GHOST_X11_GL_GetAttributes(glx_attribs, 64, stereoVisual, needAlpha, true); - - int nbfbconfig; - GLXFBConfig *fbconfigs = glXChooseFBConfig( - display, DefaultScreen(display), glx_attribs, &nbfbconfig); - - /* Any sample level or even zero, which means oversampling disabled, is good - * but we need a valid visual to continue */ - if (nbfbconfig > 0) { - /* take a frame buffer config that has alpha cap */ - for (int i = 0; i < nbfbconfig; i++) { - XVisualInfo *visual = (XVisualInfo *)glXGetVisualFromFBConfig(display, fbconfigs[i]); - if (!visual) { - continue; - } - /* if we don't need a alpha background, the first config will do, otherwise - * test the alphaMask as it won't necessarily be present */ - if (needAlpha) { - XRenderPictFormat *pict_format = XRenderFindVisualFormat(display, visual->visual); - if (!pict_format) { - continue; - } - if (pict_format->direct.alphaMask <= 0) { - continue; - } - } - - *fbconfig = fbconfigs[i]; - XFree(fbconfigs); - - return visual; - } - - XFree(fbconfigs); - } - } - else -# endif - { - /* legacy, don't use extension */ - GHOST_X11_GL_GetAttributes(glx_attribs, 64, stereoVisual, needAlpha, false); - - XVisualInfo *visual = glXChooseVisual(display, DefaultScreen(display), glx_attribs); - - /* Any sample level or even zero, which means oversampling disabled, is good - * but we need a valid visual to continue */ - if (visual != nullptr) { - return visual; - } - } - - /* All options exhausted, cannot continue */ - fprintf(stderr, - "%s:%d: X11 glXChooseVisual() failed, " - "verify working openGL system!\n", - __FILE__, - __LINE__); - - return nullptr; -} - -#endif // WITH_GL_EGL - GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, Display *display, const char *title, @@ -211,7 +103,6 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, const bool is_dialog, const bool stereoVisual, const bool exclusive, - const bool alphaBackground, const bool is_debug) : GHOST_Window(width, height, state, stereoVisual, exclusive), m_display(display), @@ -235,13 +126,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, m_is_debug_context(is_debug) { if (type == GHOST_kDrawingContextTypeOpenGL) { -#ifdef WITH_GL_EGL - m_visualInfo = x11_visualinfo_from_egl(m_display); - (void)alphaBackground; -#else - m_visualInfo = x11_visualinfo_from_glx( - m_display, stereoVisual, alphaBackground, (GLXFBConfig *)&m_fbconfig); -#endif + m_visualInfo = get_x11_visualinfo(m_display); } else { XVisualInfo tmp = {nullptr}; @@ -332,7 +217,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, * So, m_post_init indicate that we need wait for the MapNotify * event and then set the Window state to the m_post_state. */ - else if ((state != GHOST_kWindowStateNormal) && (state != GHOST_kWindowStateMinimized)) { + else if (!ELEM(state, GHOST_kWindowStateNormal, GHOST_kWindowStateMinimized)) { m_post_init = True; m_post_state = state; } @@ -1293,6 +1178,65 @@ GHOST_WindowX11::~GHOST_WindowX11() } } +#ifdef USE_EGL +static GHOST_Context *create_egl_context(GHOST_SystemX11 *system, + Window window, + Display *display, + bool want_stereo, + bool debug_context, + int ver_major, + int ver_minor) +{ + GHOST_Context *context; + context = new GHOST_ContextEGL(system, + want_stereo, + EGLNativeWindowType(window), + EGLNativeDisplayType(display), + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + ver_major, + ver_minor, + GHOST_OPENGL_EGL_CONTEXT_FLAGS | + (debug_context ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0), + GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, + EGL_OPENGL_API); + + if (context->initializeDrawingContext()) { + return context; + } + delete context; + + return nullptr; +} +#endif + +static GHOST_Context *create_glx_context(Window window, + Display *display, + GLXFBConfig fbconfig, + bool want_stereo, + bool debug_context, + int ver_major, + int ver_minor) +{ + GHOST_Context *context; + context = new GHOST_ContextGLX(want_stereo, + window, + display, + fbconfig, + GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + ver_major, + ver_minor, + GHOST_OPENGL_GLX_CONTEXT_FLAGS | + (debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), + GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); + + if (context->initializeDrawingContext()) { + return context; + } + delete context; + + return nullptr; +} + GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type) { if (type == GHOST_kDrawingContextTypeOpenGL) { @@ -1307,99 +1251,48 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type * - Try 3.3 core profile * - No fall-backs. */ -#if defined(WITH_GL_PROFILE_CORE) - { - const char *version_major = (char *)glewGetString(GLEW_VERSION_MAJOR); - if (version_major != nullptr && version_major[0] == '1') { - fprintf(stderr, "Error: GLEW version 2.0 and above is required.\n"); - abort(); - } - } -#endif - - const int profile_mask = -#ifdef WITH_GL_EGL -# if defined(WITH_GL_PROFILE_CORE) - EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT; -# elif defined(WITH_GL_PROFILE_COMPAT) - EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT; -# else -# error // must specify either core or compat at build time -# endif -#else -# if defined(WITH_GL_PROFILE_CORE) - GLX_CONTEXT_CORE_PROFILE_BIT_ARB; -# elif defined(WITH_GL_PROFILE_COMPAT) - GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; -# else -# error // must specify either core or compat at build time -# endif -#endif - GHOST_Context *context; +#ifdef USE_EGL + /* Try to initialize an EGL context. */ for (int minor = 5; minor >= 0; --minor) { -#ifdef WITH_GL_EGL - context = new GHOST_ContextEGL( - this->m_system, - m_wantStereoVisual, - EGLNativeWindowType(m_window), - EGLNativeDisplayType(m_display), - profile_mask, - 4, - minor, - GHOST_OPENGL_EGL_CONTEXT_FLAGS | - (m_is_debug_context ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0), - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#else - context = new GHOST_ContextGLX(m_wantStereoVisual, - m_window, - m_display, - (GLXFBConfig)m_fbconfig, - profile_mask, - 4, - minor, - GHOST_OPENGL_GLX_CONTEXT_FLAGS | - (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), - GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); -#endif - - if (context->initializeDrawingContext()) { + context = create_egl_context( + this->m_system, m_window, m_display, m_wantStereoVisual, m_is_debug_context, 4, minor); + if (context != nullptr) { return context; } - delete context; } -#ifdef WITH_GL_EGL - context = new GHOST_ContextEGL(this->m_system, - m_wantStereoVisual, - EGLNativeWindowType(m_window), - EGLNativeDisplayType(m_display), - profile_mask, - 3, - 3, - GHOST_OPENGL_EGL_CONTEXT_FLAGS | - (m_is_debug_context ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0), - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#else - context = new GHOST_ContextGLX(m_wantStereoVisual, - m_window, + context = create_egl_context( + this->m_system, m_window, m_display, m_wantStereoVisual, m_is_debug_context, 3, 3); + if (context != nullptr) { + return context; + } + + /* EGL initialization failed, try to fallback to a GLX context. */ +#endif + for (int minor = 5; minor >= 0; --minor) { + context = create_glx_context(m_window, m_display, (GLXFBConfig)m_fbconfig, - profile_mask, - 3, - 3, - GHOST_OPENGL_GLX_CONTEXT_FLAGS | - (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), - GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); -#endif - - if (context->initializeDrawingContext()) { + m_wantStereoVisual, + m_is_debug_context, + 4, + minor); + if (context != nullptr) { + return context; + } + } + context = create_glx_context(m_window, + m_display, + (GLXFBConfig)m_fbconfig, + m_wantStereoVisual, + m_is_debug_context, + 3, + 3); + if (context != nullptr) { return context; } - delete context; /* Ugly, but we get crashes unless a whole bunch of systems are patched. */ fprintf(stderr, "Error! Unsupported graphics card or driver.\n"); @@ -1712,7 +1605,7 @@ uint16_t GHOST_WindowX11::getDPIHint() int success = XrmGetResource(xrdb, "Xft.dpi", "Xft.Dpi", &type, &val); if (success && type) { - if (strcmp(type, "String") == 0) { + if (STREQ(type, "String")) { return atoi((char *)val.addr); } } diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index ac4edd83549..c7a6b5e7357 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -47,7 +47,6 @@ class GHOST_WindowX11 : public GHOST_Window { * \param parentWindow: Parent (embedder) window. * \param type: The type of drawing context installed in this window. * \param stereoVisual: Stereo visual for quad buffered stereo. - * \param alphaBackground: Enable alpha blending of window with display background. */ GHOST_WindowX11(GHOST_SystemX11 *system, Display *display, @@ -62,7 +61,6 @@ class GHOST_WindowX11 : public GHOST_Window { const bool is_dialog = false, const bool stereoVisual = false, const bool exclusive = false, - const bool alphaBackground = false, const bool is_debug = false); bool getValid() const; diff --git a/intern/ghost/intern/GHOST_XrContext.cpp b/intern/ghost/intern/GHOST_XrContext.cpp index 2ac3d9ec2a5..413e2670750 100644 --- a/intern/ghost/intern/GHOST_XrContext.cpp +++ b/intern/ghost/intern/GHOST_XrContext.cpp @@ -436,9 +436,11 @@ void GHOST_XrContext::getExtensionsToEnable( r_ext_names.push_back(gpu_binding); } -#if defined(WITH_GHOST_X11) && defined(WITH_GL_EGL) - assert(openxr_extension_is_available(m_oxr->extensions, XR_MNDX_EGL_ENABLE_EXTENSION_NAME)); - r_ext_names.push_back(XR_MNDX_EGL_ENABLE_EXTENSION_NAME); +#if defined(WITH_GHOST_X11) + if (openxr_extension_is_available(m_oxr->extensions, XR_MNDX_EGL_ENABLE_EXTENSION_NAME)) { + /* Use EGL if that backend is available. */ + r_ext_names.push_back(XR_MNDX_EGL_ENABLE_EXTENSION_NAME); + } #endif for (const std::string_view &ext : try_ext) { diff --git a/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp b/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp index aa230bf8deb..6a7eb25925a 100644 --- a/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp +++ b/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp @@ -8,17 +8,16 @@ #include <list> #include <sstream> -#if defined(WITH_GL_EGL) +#if defined(WITH_GHOST_X11) # include "GHOST_ContextEGL.h" -# if defined(WITH_GHOST_X11) -# include "GHOST_SystemX11.h" -# endif -# if defined(WITH_GHOST_WAYLAND) -# include "GHOST_SystemWayland.h" -# endif -#elif defined(WITH_GHOST_X11) # include "GHOST_ContextGLX.h" -#elif defined(WIN32) +# include "GHOST_SystemX11.h" +#endif +#if defined(WITH_GHOST_WAYLAND) +# include "GHOST_ContextEGL.h" +# include "GHOST_SystemWayland.h" +#endif +#if defined(WIN32) # include "GHOST_ContextD3D.h" # include "GHOST_ContextWGL.h" # include "GHOST_SystemWin32.h" @@ -61,19 +60,30 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding { XrSystemId system_id, std::string *r_requirement_info) const override { -#if defined(WITH_GL_EGL) - GHOST_ContextEGL &ctx_gl = static_cast<GHOST_ContextEGL &>(ghost_ctx); -#elif defined(WITH_GHOST_X11) - GHOST_ContextGLX &ctx_gl = static_cast<GHOST_ContextGLX &>(ghost_ctx); -#else + int gl_major_version, gl_minor_version; +#if defined(WIN32) GHOST_ContextWGL &ctx_gl = static_cast<GHOST_ContextWGL &>(ghost_ctx); + gl_major_version = ctx_gl.m_contextMajorVersion; + gl_minor_version = ctx_gl.m_contextMinorVersion; +#elif defined(WITH_GHOST_X11) || defined(WITH_GHOST_WAYLAND) + if (dynamic_cast<GHOST_ContextEGL *>(&ghost_ctx)) { + GHOST_ContextEGL &ctx_gl = static_cast<GHOST_ContextEGL &>(ghost_ctx); + gl_major_version = ctx_gl.m_contextMajorVersion; + gl_minor_version = ctx_gl.m_contextMinorVersion; + } +# if defined(WITH_GHOST_X11) + else { + GHOST_ContextGLX &ctx_gl = static_cast<GHOST_ContextGLX &>(ghost_ctx); + gl_major_version = ctx_gl.m_contextMajorVersion; + gl_minor_version = ctx_gl.m_contextMinorVersion; + } +# endif #endif static PFN_xrGetOpenGLGraphicsRequirementsKHR s_xrGetOpenGLGraphicsRequirementsKHR_fn = nullptr; // static XrInstance s_instance = XR_NULL_HANDLE; XrGraphicsRequirementsOpenGLKHR gpu_requirements = {XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR}; - const XrVersion gl_version = XR_MAKE_VERSION( - ctx_gl.m_contextMajorVersion, ctx_gl.m_contextMinorVersion, 0); + const XrVersion gl_version = XR_MAKE_VERSION(gl_major_version, gl_minor_version, 0); /* Although it would seem reasonable that the proc address would not change if the instance was * the same, in testing, repeated calls to #xrGetInstanceProcAddress() with the same instance @@ -112,45 +122,67 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding { void initFromGhostContext(GHOST_Context &ghost_ctx) override { -#if defined(WITH_GHOST_X11) -# if defined(WITH_GL_EGL) - GHOST_ContextEGL &ctx_egl = static_cast<GHOST_ContextEGL &>(ghost_ctx); - - if (dynamic_cast<const GHOST_SystemX11 *const>(ctx_egl.m_system)) { - oxr_binding.egl.type = XR_TYPE_GRAPHICS_BINDING_EGL_MNDX; - oxr_binding.egl.getProcAddress = eglGetProcAddress; - oxr_binding.egl.display = ctx_egl.getDisplay(); - oxr_binding.egl.config = ctx_egl.getConfig(); - oxr_binding.egl.context = ctx_egl.getContext(); - } +#if defined(WITH_GHOST_X11) || defined(WITH_GHOST_WAYLAND) + /* WAYLAND/X11 may be dynamically selected at load time but both may also be + * supported at compile time individually. + * Without `is_ctx_egl` & `is_wayland` preprocessor checks become an unmanageable soup. */ + const bool is_ctx_egl = dynamic_cast<GHOST_ContextEGL *>(&ghost_ctx) != nullptr; + if (is_ctx_egl) { + GHOST_ContextEGL &ctx_egl = static_cast<GHOST_ContextEGL &>(ghost_ctx); + const bool is_wayland = ( +# if defined(WITH_GHOST_WAYLAND) + dynamic_cast<const GHOST_SystemWayland *const>(ctx_egl.m_system) != nullptr # else - GHOST_ContextGLX &ctx_glx = static_cast<GHOST_ContextGLX &>(ghost_ctx); - XVisualInfo *visual_info = glXGetVisualFromFBConfig(ctx_glx.m_display, ctx_glx.m_fbconfig); + false +# endif + ); + + if (is_wayland) { +# if defined(WITH_GHOST_WAYLAND) + /* #GHOST_SystemWayland */ + oxr_binding.wl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR; + oxr_binding.wl.display = (struct wl_display *)ctx_egl.m_nativeDisplay; +# else + GHOST_ASSERT(false, "Unexpected State: logical error, unreachable!"); +# endif /* !WITH_GHOST_WAYLAND */ + } + else { /* `!is_wayland` */ +# if defined(WITH_GHOST_X11) + /* #GHOST_SystemX11. */ + oxr_binding.egl.type = XR_TYPE_GRAPHICS_BINDING_EGL_MNDX; + oxr_binding.egl.getProcAddress = eglGetProcAddress; + oxr_binding.egl.display = ctx_egl.getDisplay(); + oxr_binding.egl.config = ctx_egl.getConfig(); + oxr_binding.egl.context = ctx_egl.getContext(); +# else + GHOST_ASSERT(false, "Unexpected State: built with only WAYLAND and no System found!"); +# endif /* !WITH_GHOST_X11 */ + } + } + else { /* `!is_ctx_egl` */ +# if defined(WITH_GHOST_X11) + GHOST_ContextGLX &ctx_glx = static_cast<GHOST_ContextGLX &>(ghost_ctx); + XVisualInfo *visual_info = glXGetVisualFromFBConfig(ctx_glx.m_display, ctx_glx.m_fbconfig); - oxr_binding.glx.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR; - oxr_binding.glx.xDisplay = ctx_glx.m_display; - oxr_binding.glx.glxFBConfig = ctx_glx.m_fbconfig; - oxr_binding.glx.glxDrawable = ctx_glx.m_window; - oxr_binding.glx.glxContext = ctx_glx.m_context; - oxr_binding.glx.visualid = visual_info->visualid; + oxr_binding.glx.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR; + oxr_binding.glx.xDisplay = ctx_glx.m_display; + oxr_binding.glx.glxFBConfig = ctx_glx.m_fbconfig; + oxr_binding.glx.glxDrawable = ctx_glx.m_window; + oxr_binding.glx.glxContext = ctx_glx.m_context; + oxr_binding.glx.visualid = visual_info->visualid; - XFree(visual_info); -# endif + XFree(visual_info); +# else + GHOST_ASSERT(false, "Unexpected State: built without X11 and no EGL context is available!"); +# endif /* !WITH_GHOST_X11 */ + } #elif defined(WIN32) GHOST_ContextWGL &ctx_wgl = static_cast<GHOST_ContextWGL &>(ghost_ctx); oxr_binding.wgl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR; oxr_binding.wgl.hDC = ctx_wgl.m_hDC; oxr_binding.wgl.hGLRC = ctx_wgl.m_hGLRC; -#endif - -#if defined(WITH_GHOST_WAYLAND) - GHOST_ContextEGL &ctx_wl_egl = static_cast<GHOST_ContextEGL &>(ghost_ctx); - if (dynamic_cast<const GHOST_SystemWayland *const>(ctx_wl_egl.m_system)) { - oxr_binding.wl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR; - oxr_binding.wl.display = (struct wl_display *)ctx_wl_egl.m_nativeDisplay; - } -#endif +#endif /* WIN32 */ /* Generate a frame-buffer to use for blitting into the texture. */ glGenFramebuffers(1, &m_fbo); diff --git a/intern/ghost/intern/GHOST_Xr_openxr_includes.h b/intern/ghost/intern/GHOST_Xr_openxr_includes.h index 9706f51c027..1c16f746f7a 100644 --- a/intern/ghost/intern/GHOST_Xr_openxr_includes.h +++ b/intern/ghost/intern/GHOST_Xr_openxr_includes.h @@ -28,13 +28,8 @@ # include <d3d12.h> #endif #ifdef WITH_GHOST_X11 -# ifdef WITH_GL_EGL -/* TODO: Why do we have to create this typedef manually? */ -typedef void (*(*PFNEGLGETPROCADDRESSPROC)(const char *procname))(void); -# include <GL/eglew.h> -# else -# include <GL/glxew.h> -# endif +# include <epoxy/egl.h> +# include <epoxy/glx.h> #endif #include <openxr/openxr.h> diff --git a/intern/ghost/intern/GHOST_utildefines.h b/intern/ghost/intern/GHOST_utildefines.h index f0ae6e12d3e..ff092099c7c 100644 --- a/intern/ghost/intern/GHOST_utildefines.h +++ b/intern/ghost/intern/GHOST_utildefines.h @@ -208,3 +208,32 @@ (void)0 /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name String Macros + * \{ */ + +/* Macro to convert a value to string in the preprocessor: + * - `STRINGIFY_ARG`: gives the argument as a string + * - `STRINGIFY_APPEND`: appends any argument 'b' onto the string argument 'a', + * used by `STRINGIFY` because some preprocessors warn about zero arguments. + * - `STRINGIFY`: gives the argument's value as a string. */ + +#define STRINGIFY_ARG(x) "" #x +#define STRINGIFY_APPEND(a, b) "" a #b +#define STRINGIFY(x) STRINGIFY_APPEND("", x) + +/* generic strcmp macros */ +#if defined(_MSC_VER) +# define strcasecmp _stricmp +# define strncasecmp _strnicmp +#endif + +#define STREQ(a, b) (strcmp(a, b) == 0) +#define STRCASEEQ(a, b) (strcasecmp(a, b) == 0) +#define STREQLEN(a, b, n) (strncmp(a, b, n) == 0) +#define STRCASEEQLEN(a, b, n) (strncasecmp(a, b, n) == 0) + +#define STRPREFIX(a, b) (strncmp((a), (b), strlen(b)) == 0) + +/** \} */ |