Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/ghost/intern')
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp50
-rw-r--r--intern/ghost/intern/GHOST_Context.h4
-rw-r--r--intern/ghost/intern/GHOST_Debug.h18
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerWin32.cpp12
-rw-r--r--intern/ghost/intern/GHOST_DropTargetWin32.cpp24
-rw-r--r--intern/ghost/intern/GHOST_EventButton.h10
-rw-r--r--intern/ghost/intern/GHOST_EventCursor.h6
-rw-r--r--intern/ghost/intern/GHOST_EventKey.h2
-rw-r--r--intern/ghost/intern/GHOST_EventPrinter.h2
-rw-r--r--intern/ghost/intern/GHOST_ISystem.cpp57
-rw-r--r--intern/ghost/intern/GHOST_IXrGraphicsBinding.h5
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.cpp2
-rw-r--r--intern/ghost/intern/GHOST_System.cpp27
-rw-r--r--intern/ghost/intern/GHOST_System.h24
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.h4
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm81
-rw-r--r--intern/ghost/intern/GHOST_SystemNULL.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.cpp24
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp1778
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h111
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp274
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h72
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp57
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h22
-rw-r--r--intern/ghost/intern/GHOST_Window.h5
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.h13
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm11
-rw-r--r--intern/ghost/intern/GHOST_WindowNULL.h9
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.cpp10
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.h7
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp415
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.h124
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp179
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h93
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp22
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.h12
-rw-r--r--intern/ghost/intern/GHOST_XrContext.cpp16
-rw-r--r--intern/ghost/intern/GHOST_XrContext.h1
-rw-r--r--intern/ghost/intern/GHOST_XrGraphicsBinding.cpp77
-rw-r--r--intern/ghost/intern/GHOST_XrSession.cpp45
-rw-r--r--intern/ghost/intern/GHOST_XrSession.h4
-rw-r--r--intern/ghost/intern/GHOST_XrSwapchain.cpp12
-rw-r--r--intern/ghost/intern/GHOST_XrSwapchain.h1
-rw-r--r--intern/ghost/intern/GHOST_Xr_openxr_includes.h2
45 files changed, 3184 insertions, 544 deletions
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index af2a13945d1..843684b6d2e 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -24,6 +24,7 @@
*/
#include <stdlib.h>
+#include <string.h>
#include "GHOST_C-api.h"
#include "GHOST_IEvent.h"
@@ -150,25 +151,6 @@ GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
return system->disposeContext(context);
}
-#ifdef WIN32
-GHOST_ContextHandle GHOST_CreateDirectXContext(GHOST_SystemHandle systemhandle)
-{
- GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
-
- return (GHOST_ContextHandle)system->createOffscreenContext(GHOST_kDrawingContextTypeD3D);
-}
-
-GHOST_TSuccess GHOST_DisposeDirectXContext(GHOST_SystemHandle systemhandle,
- GHOST_ContextHandle contexthandle)
-{
- GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
- GHOST_IContext *context = (GHOST_IContext *)contexthandle;
-
- return system->disposeContext(context);
-}
-
-#endif
-
GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
const char *title,
GHOST_TInt32 left,
@@ -546,17 +528,15 @@ void GHOST_SetTitle(GHOST_WindowHandle windowhandle, const char *title)
char *GHOST_GetTitle(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- STR_String title;
-
- window->getTitle(title);
+ std::string title = window->getTitle();
- char *ctitle = (char *)malloc(title.Length() + 1);
+ char *ctitle = (char *)malloc(title.size() + 1);
if (ctitle == NULL) {
return NULL;
}
- strcpy(ctitle, title.Ptr());
+ strcpy(ctitle, title.c_str());
return ctitle;
}
@@ -697,7 +677,7 @@ GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle)
return context->activateDrawingContext();
}
else {
- GHOST_PRINT("GHOST_ActivateOpenGLContext: Context not valid");
+ GHOST_PRINTF("%s: Context not valid\n", __func__);
return GHOST_kFailure;
}
}
@@ -716,13 +696,6 @@ unsigned int GHOST_GetContextDefaultOpenGLFramebuffer(GHOST_ContextHandle contex
return context->getDefaultFramebuffer();
}
-int GHOST_isUpsideDownContext(GHOST_ContextHandle contexthandle)
-{
- GHOST_IContext *context = (GHOST_IContext *)contexthandle;
-
- return context->isUpsideDown();
-}
-
unsigned int GHOST_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
@@ -743,11 +716,6 @@ void GHOST_SetTabletAPI(GHOST_SystemHandle systemhandle, GHOST_TTabletAPI api)
system->setTabletAPI(api);
}
-const GHOST_TabletData *GHOST_GetTabletData(GHOST_WindowHandle windowhandle)
-{
- return &((GHOST_IWindow *)windowhandle)->GetTabletData();
-}
-
GHOST_TInt32 GHOST_GetWidthRectangle(GHOST_RectangleHandle rectanglehandle)
{
return ((GHOST_Rect *)rectanglehandle)->getWidth();
@@ -991,4 +959,12 @@ void GHOST_XrDrawViewFunc(GHOST_XrContextHandle xr_contexthandle, GHOST_XrDrawVi
GHOST_XR_CAPI_CALL(xr_context->setDrawViewFunc(draw_view_fn), xr_context);
}
+int GHOST_XrSessionNeedsUpsideDownDrawing(const GHOST_XrContextHandle xr_contexthandle)
+{
+ GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
+
+ GHOST_XR_CAPI_CALL_RET(xr_context->needsUpsideDownDrawing(), xr_context);
+ return 0; /* Only reached if exception is thrown. */
+}
+
#endif
diff --git a/intern/ghost/intern/GHOST_Context.h b/intern/ghost/intern/GHOST_Context.h
index 0bd6f63d07e..411a7de5c79 100644
--- a/intern/ghost/intern/GHOST_Context.h
+++ b/intern/ghost/intern/GHOST_Context.h
@@ -120,9 +120,9 @@ class GHOST_Context : public GHOST_IContext {
}
/**
- * Returns if the window is rendered upside down compared to OpenGL.
+ * Returns if the context is rendered upside down compared to OpenGL.
*/
- inline bool isUpsideDown() const
+ virtual inline bool isUpsideDown() const
{
return false;
}
diff --git a/intern/ghost/intern/GHOST_Debug.h b/intern/ghost/intern/GHOST_Debug.h
index 0163197e14a..5b5c2688297 100644
--- a/intern/ghost/intern/GHOST_Debug.h
+++ b/intern/ghost/intern/GHOST_Debug.h
@@ -33,15 +33,11 @@
#endif
#ifdef WITH_GHOST_DEBUG
-# define GHOST_DEBUG // spit ghost events to stdout
-#endif // WITH_GHOST_DEBUG
-
-#ifdef GHOST_DEBUG
# include <iostream>
# include <stdio.h> //for printf()
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
# define GHOST_PRINT(x) \
{ \
std::cout << x; \
@@ -52,10 +48,10 @@
printf(x, __VA_ARGS__); \
} \
(void)0
-#else // GHOST_DEBUG
+#else // WITH_GHOST_DEBUG
# define GHOST_PRINT(x)
# define GHOST_PRINTF(x, ...)
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
#ifdef WITH_ASSERT_ABORT
# include <stdio.h> //for fprintf()
@@ -70,7 +66,7 @@
} \
} \
(void)0
-#elif defined(GHOST_DEBUG)
+#elif defined(WITH_GHOST_DEBUG)
# define GHOST_ASSERT(x, info) \
{ \
if (!(x)) { \
@@ -80,8 +76,8 @@
} \
} \
(void)0
-#else // GHOST_DEBUG
+#else // WITH_GHOST_DEBUG
# define GHOST_ASSERT(x, info) ((void)0)
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
#endif // __GHOST_DEBUG_H__
diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
index aabaffc7732..3557c4cd0c5 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
@@ -80,13 +80,13 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::getDisplaySetting(GHOST_TUns8 display,
GHOST_TSuccess success;
DEVMODE dm;
if (::EnumDisplaySettings(display_device.DeviceName, index, &dm)) {
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n",
dm.dmPelsWidth,
dm.dmPelsHeight,
dm.dmBitsPerPel,
dm.dmDisplayFrequency);
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
setting.xPixels = dm.dmPelsWidth;
setting.yPixels = dm.dmPelsHeight;
setting.bpp = dm.dmBitsPerPel;
@@ -142,16 +142,16 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::setCurrentDisplaySetting(
* dm.dmSize = sizeof(DEVMODE);
* dm.dmDriverExtra = 0;
*/
-#ifdef GHOST_DEBUG
+#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 // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
LONG status = ::ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
switch (status) {
case DISP_CHANGE_SUCCESSFUL:
printf("display change: The settings change was successful.\n");
@@ -182,6 +182,6 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::setCurrentDisplaySetting(
printf("display change: Return value invalid\n");
break;
}
-#endif // 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 9f8ce3b5095..fe11d9a28f2 100644
--- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp
+++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp
@@ -28,10 +28,10 @@
#include "utf_winfunc.h"
#include "utfconv.h"
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
// utility
void printLastError(void);
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
GHOST_DropTargetWin32::GHOST_DropTargetWin32(GHOST_WindowWin32 *window, GHOST_SystemWin32 *system)
: m_window(window), m_system(system)
@@ -209,9 +209,9 @@ void *GHOST_DropTargetWin32::getGhostData(IDataObject *pDataObject)
// return getDropDataAsBitmap(pDataObject);
break;
default:
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
::printf("\nGHOST_kDragnDropTypeUnknown");
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
return NULL;
break;
}
@@ -284,10 +284,10 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject)
// Free memory
::GlobalUnlock(stgmed.hGlobal);
::ReleaseStgMedium(&stgmed);
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
::printf("\n<converted droped unicode string>\n%s\n</droped converted unicode string>\n",
tmp_string);
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
return tmp_string;
}
}
@@ -336,9 +336,9 @@ int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char *&out)
NULL);
if (!size) {
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
::printLastError();
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
return 0;
}
@@ -351,16 +351,16 @@ int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char *&out)
size = ::WideCharToMultiByte(CP_ACP, 0x00000400, in, -1, (LPSTR)out, size, NULL, NULL);
if (!size) {
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
::printLastError();
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
::free(out);
out = NULL;
}
return size;
}
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
void printLastError(void)
{
LPTSTR s;
@@ -378,4 +378,4 @@ void printLastError(void)
LocalFree(s);
}
}
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
diff --git a/intern/ghost/intern/GHOST_EventButton.h b/intern/ghost/intern/GHOST_EventButton.h
index e854bc23e5a..4247ae150a4 100644
--- a/intern/ghost/intern/GHOST_EventButton.h
+++ b/intern/ghost/intern/GHOST_EventButton.h
@@ -37,17 +37,19 @@ class GHOST_EventButton : public GHOST_Event {
* Constructor.
* \param time The time this event was generated.
* \param type The type of this event.
- * \param window: The window of this event.
- * \param button: The state of the buttons were at the time of the event.
+ * \param window The window of this event.
+ * \param button The state of the buttons were at the time of the event.
+ * \param tablet The tablet data associated with this event.
*/
GHOST_EventButton(GHOST_TUns64 time,
GHOST_TEventType type,
GHOST_IWindow *window,
- GHOST_TButtonMask button)
+ GHOST_TButtonMask button,
+ const GHOST_TabletData &tablet)
: GHOST_Event(time, type, window)
{
m_buttonEventData.button = button;
- m_buttonEventData.tablet = window->GetTabletData();
+ m_buttonEventData.tablet = tablet;
m_data = &m_buttonEventData;
}
diff --git a/intern/ghost/intern/GHOST_EventCursor.h b/intern/ghost/intern/GHOST_EventCursor.h
index 41597db216a..8ba657fd9fa 100644
--- a/intern/ghost/intern/GHOST_EventCursor.h
+++ b/intern/ghost/intern/GHOST_EventCursor.h
@@ -38,17 +38,19 @@ class GHOST_EventCursor : public GHOST_Event {
* \param type The type of this event.
* \param x The x-coordinate of the location the cursor was at the time of the event.
* \param y The y-coordinate of the location the cursor was at the time of the event.
+ * \param tablet The tablet data associated with this event.
*/
GHOST_EventCursor(GHOST_TUns64 msec,
GHOST_TEventType type,
GHOST_IWindow *window,
GHOST_TInt32 x,
- GHOST_TInt32 y)
+ GHOST_TInt32 y,
+ const GHOST_TabletData &tablet)
: GHOST_Event(msec, type, window)
{
m_cursorEventData.x = x;
m_cursorEventData.y = y;
- m_cursorEventData.tablet = window->GetTabletData();
+ m_cursorEventData.tablet = tablet;
m_data = &m_cursorEventData;
}
diff --git a/intern/ghost/intern/GHOST_EventKey.h b/intern/ghost/intern/GHOST_EventKey.h
index 24e20b20659..8f59c555914 100644
--- a/intern/ghost/intern/GHOST_EventKey.h
+++ b/intern/ghost/intern/GHOST_EventKey.h
@@ -25,6 +25,8 @@
#ifndef __GHOST_EVENTKEY_H__
#define __GHOST_EVENTKEY_H__
+#include <string.h>
+
#include "GHOST_Event.h"
/**
diff --git a/intern/ghost/intern/GHOST_EventPrinter.h b/intern/ghost/intern/GHOST_EventPrinter.h
index fad9ec3cc69..ead16525ec6 100644
--- a/intern/ghost/intern/GHOST_EventPrinter.h
+++ b/intern/ghost/intern/GHOST_EventPrinter.h
@@ -27,8 +27,6 @@
#include "GHOST_IEventConsumer.h"
-#include "STR_String.h"
-
/**
* An Event consumer that prints all the events to standard out.
* Really useful when debugging.
diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp
index 914f6712676..7c12bfe0306 100644
--- a/intern/ghost/intern/GHOST_ISystem.cpp
+++ b/intern/ghost/intern/GHOST_ISystem.cpp
@@ -27,20 +27,22 @@
#include "GHOST_ISystem.h"
-#ifdef WITH_X11
+#if defined(WITH_HEADLESS)
+# include "GHOST_SystemNULL.h"
+#elif defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND)
+# include "GHOST_SystemWayland.h"
# include "GHOST_SystemX11.h"
-#else
-# ifdef WITH_HEADLESS
-# include "GHOST_SystemNULL.h"
-# elif defined(WITH_GHOST_SDL)
-# include "GHOST_SystemSDL.h"
-# elif defined(WIN32)
-# include "GHOST_SystemWin32.h"
-# else
-# ifdef __APPLE__
-# include "GHOST_SystemCocoa.h"
-# endif
-# endif
+# include <stdexcept>
+#elif defined(WITH_GHOST_X11)
+# include "GHOST_SystemX11.h"
+#elif defined(WITH_GHOST_WAYLAND)
+# include "GHOST_SystemWayland.h"
+#elif defined(WITH_GHOST_SDL)
+# include "GHOST_SystemSDL.h"
+#elif defined(WIN32)
+# include "GHOST_SystemWin32.h"
+#elif defined(__APPLE__)
+# include "GHOST_SystemCocoa.h"
#endif
GHOST_ISystem *GHOST_ISystem::m_system = NULL;
@@ -49,20 +51,29 @@ GHOST_TSuccess GHOST_ISystem::createSystem()
{
GHOST_TSuccess success;
if (!m_system) {
-#ifdef WITH_X11
- m_system = new GHOST_SystemX11();
-#else
-# ifdef WITH_HEADLESS
+#if defined(WITH_HEADLESS)
m_system = new GHOST_SystemNULL();
-# elif defined(WITH_GHOST_SDL)
+#elif defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND)
+ /* Special case, try Wayland, fall back to X11. */
+ try {
+ m_system = new GHOST_SystemWayland();
+ }
+ catch (const std::runtime_error &) {
+ /* fallback to X11. */
+ }
+ if (!m_system) {
+ m_system = new GHOST_SystemX11();
+ }
+#elif defined(WITH_GHOST_X11)
+ m_system = new GHOST_SystemX11();
+#elif defined(WITH_GHOST_WAYLAND)
+ m_system = new GHOST_SystemWayland();
+#elif defined(WITH_GHOST_SDL)
m_system = new GHOST_SystemSDL();
-# elif defined(WIN32)
+#elif defined(WIN32)
m_system = new GHOST_SystemWin32();
-# else
-# ifdef __APPLE__
+#elif defined(__APPLE__)
m_system = new GHOST_SystemCocoa();
-# endif
-# endif
#endif
success = m_system != NULL ? GHOST_kSuccess : GHOST_kFailure;
}
diff --git a/intern/ghost/intern/GHOST_IXrGraphicsBinding.h b/intern/ghost/intern/GHOST_IXrGraphicsBinding.h
index 25281d3d0ba..5794a682023 100644
--- a/intern/ghost/intern/GHOST_IXrGraphicsBinding.h
+++ b/intern/ghost/intern/GHOST_IXrGraphicsBinding.h
@@ -33,7 +33,7 @@ class GHOST_IXrGraphicsBinding {
public:
union {
-#if defined(WITH_X11)
+#if defined(WITH_GHOST_X11)
XrGraphicsBindingOpenGLXlibKHR glx;
#elif defined(WIN32)
XrGraphicsBindingOpenGLWin32KHR wgl;
@@ -61,6 +61,7 @@ class GHOST_IXrGraphicsBinding {
uint32_t image_count) = 0;
virtual void submitToSwapchainImage(XrSwapchainImageBaseHeader *swapchain_image,
const GHOST_XrDrawViewInfo *draw_info) = 0;
+ virtual bool needsUpsideDownDrawing(GHOST_Context &ghost_ctx) const = 0;
protected:
/* Use GHOST_XrGraphicsBindingCreateFromType! */
@@ -68,6 +69,6 @@ class GHOST_IXrGraphicsBinding {
};
std::unique_ptr<GHOST_IXrGraphicsBinding> GHOST_XrGraphicsBindingCreateFromType(
- GHOST_TXrGraphicsBinding type);
+ GHOST_TXrGraphicsBinding type, GHOST_Context *ghost_ctx);
#endif /* __GHOST_IXRGRAPHICSBINDING_H__ */
diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp
index a9fbadab37a..dda78c0ac5b 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManager.cpp
@@ -19,6 +19,8 @@
#include "GHOST_EventKey.h"
#include "GHOST_EventNDOF.h"
#include "GHOST_WindowManager.h"
+
+#include <limits.h>
#include <math.h>
#include <stdio.h> // for error/info reporting
#include <string.h> // for memory functions
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index 97704435f04..b0d2adff4bc 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -23,8 +23,8 @@
#include "GHOST_System.h"
+#include <chrono>
#include <stdio.h> /* just for printf */
-#include <time.h>
#include "GHOST_DisplayManager.h"
#include "GHOST_EventManager.h"
@@ -58,12 +58,9 @@ GHOST_System::~GHOST_System()
GHOST_TUns64 GHOST_System::getMilliSeconds() const
{
- GHOST_TUns64 millis = ::clock();
- if (CLOCKS_PER_SEC != 1000) {
- millis *= 1000;
- millis /= CLOCKS_PER_SEC;
- }
- return millis;
+ return std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
}
GHOST_ITimerTask *GHOST_System::installTimer(GHOST_TUns64 delay,
@@ -122,16 +119,6 @@ GHOST_TSuccess GHOST_System::disposeWindow(GHOST_IWindow *window)
return success;
}
-GHOST_IContext *GHOST_System::createOffscreenContext(GHOST_TDrawingContextType type)
-{
- switch (type) {
- case GHOST_kDrawingContextTypeOpenGL:
- return createOffscreenContext();
- default:
- return NULL;
- }
-}
-
bool GHOST_System::validWindow(GHOST_IWindow *window)
{
return m_windowManager->getWindowFound(window);
@@ -319,12 +306,12 @@ GHOST_TSuccess GHOST_System::init()
m_windowManager = new GHOST_WindowManager();
m_eventManager = new GHOST_EventManager();
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
if (m_eventManager) {
m_eventPrinter = new GHOST_EventPrinter();
m_eventManager->addConsumer(m_eventPrinter);
}
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
if (m_timerManager && m_windowManager && m_eventManager) {
return GHOST_kSuccess;
@@ -377,7 +364,7 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
GHOST_ASSERT(m_displayManager,
"GHOST_System::createFullScreenWindow(): invalid display manager");
// GHOST_PRINT("GHOST_System::createFullScreenWindow(): creating full-screen window\n");
- *window = (GHOST_Window *)createWindow(STR_String(""),
+ *window = (GHOST_Window *)createWindow("",
0,
0,
settings.xPixels,
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index 2eec6ca43b3..c2d712c11cd 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -31,9 +31,9 @@
#include "GHOST_Debug.h"
#include "GHOST_EventManager.h"
#include "GHOST_ModifierKeys.h"
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
# include "GHOST_EventPrinter.h"
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
class GHOST_DisplayManager;
class GHOST_Event;
@@ -119,12 +119,6 @@ class GHOST_System : public GHOST_ISystem {
virtual GHOST_IContext *createOffscreenContext() = 0;
/**
- * Overload to allow requesting a different context type. By default only OpenGL is supported.
- * However by explicitly overloading this a system may add support for others.
- */
- GHOST_IContext *createOffscreenContext(GHOST_TDrawingContextType type);
-
- /**
* Returns whether a window is valid.
* \param window Pointer to the window to be checked.
* \return Indication of validity.
@@ -225,7 +219,7 @@ class GHOST_System : public GHOST_ISystem {
***************************************************************************************/
/**
- * Returns the state of a modifier key (ouside the message queue).
+ * Returns the state of a modifier key (outside the message queue).
* \param mask The modifier key state to retrieve.
* \param isDown The state of a modifier key (true == pressed).
* \return Indication of success.
@@ -233,7 +227,7 @@ class GHOST_System : public GHOST_ISystem {
GHOST_TSuccess getModifierKeyState(GHOST_TModifierKeyMask mask, bool &isDown) const;
/**
- * Returns the state of a mouse button (ouside the message queue).
+ * Returns the state of a mouse button (outside the message queue).
* \param mask The button state to retrieve.
* \param isDown Button state.
* \return Indication of success.
@@ -253,8 +247,8 @@ class GHOST_System : public GHOST_ISystem {
***************************************************************************************/
/**
- * Sets 3D mouse deadzone
- * \param deadzone: Deadzone of the 3D mouse (both for rotation and pan) relative to full range
+ * Sets 3D mouse dead-zone
+ * \param deadzone: Dead-zone of the 3D mouse (both for rotation and pan) relative to full range.
*/
void setNDOFDeadZone(float deadzone);
#endif
@@ -301,7 +295,7 @@ class GHOST_System : public GHOST_ISystem {
virtual GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const = 0;
/**
- * Returns the state of the mouse buttons (ouside the message queue).
+ * Returns the state of the mouse buttons (outside the message queue).
* \param buttons The state of the buttons.
* \return Indication of success.
*/
@@ -396,9 +390,9 @@ class GHOST_System : public GHOST_ISystem {
#endif
/** Prints all the events. */
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
GHOST_EventPrinter *m_eventPrinter;
-#endif // GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
/** Settings of the display before the display went fullscreen. */
GHOST_DisplaySetting m_preFullScreenSetting;
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h
index 1e44c3e31d4..bbd6f1d8995 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.h
+++ b/intern/ghost/intern/GHOST_SystemCocoa.h
@@ -100,7 +100,7 @@ class GHOST_SystemCocoa : public GHOST_System {
* \param parentWindow Parent (embedder) window
* \return The new window (or 0 if creation failed).
*/
- GHOST_IWindow *createWindow(const STR_String &title,
+ GHOST_IWindow *createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -198,7 +198,7 @@ class GHOST_SystemCocoa : public GHOST_System {
GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const;
/**
- * Returns the state of the mouse buttons (ouside the message queue).
+ * Returns the state of the mouse buttons (outside the message queue).
* \param buttons The state of the buttons.
* \return Indication of success.
*/
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index 9becff40995..5592078e20e 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -698,7 +698,7 @@ void GHOST_SystemCocoa::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns3
getMainDisplayDimensions(width, height);
}
-GHOST_IWindow *GHOST_SystemCocoa::createWindow(const STR_String &title,
+GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -817,7 +817,8 @@ GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32
CGAssociateMouseAndMouseCursorPosition(true);
// Force mouse move event (not pushed by Cocoa)
- pushEvent(new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, x, y));
+ pushEvent(new GHOST_EventCursor(
+ getMilliSeconds(), GHOST_kEventCursorMove, window, x, y, window->GetCocoaTabletData()));
m_outsideLoopEventProcessed = true;
return GHOST_kSuccess;
@@ -1062,14 +1063,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
}
switch (eventType) {
case GHOST_kEventWindowClose:
- // check for index of mainwindow as it would quit blender without dialog and discard
- if ([windowsList count] > 1 &&
- window->getCocoaWindow() != [windowsList objectAtIndex:[windowsList count] - 1]) {
- pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window));
- }
- else {
- handleQuitRequest(); // -> quit dialog
- }
+ pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window));
break;
case GHOST_kEventWindowActivate:
m_windowManager->setActiveWindow(window);
@@ -1098,8 +1092,11 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window));
// Mouse up event is trapped by the resizing event loop,
// so send it anyway to the window manager.
- pushEvent(new GHOST_EventButton(
- getMilliSeconds(), GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft));
+ pushEvent(new GHOST_EventButton(getMilliSeconds(),
+ GHOST_kEventButtonUp,
+ window,
+ GHOST_kButtonMaskLeft,
+ GHOST_TABLET_DATA_NONE));
// m_ignoreWindowSizedMessages = true;
}
break;
@@ -1437,7 +1434,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
case NSEventTypeTabletProximity:
/* Reset tablet data when device enters proximity or leaves. */
- ct = GHOST_TABLET_DATA_DEFAULT;
+ ct = GHOST_TABLET_DATA_NONE;
if ([event isEnteringProximity]) {
/* Pointer is entering tablet area proximity. */
switch ([event pointingDeviceType]) {
@@ -1504,38 +1501,52 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
switch ([event type]) {
case NSEventTypeLeftMouseDown:
handleTabletEvent(event); // Update window tablet state to be included in event.
- pushEvent(new GHOST_EventButton(
- [event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft));
+ pushEvent(new GHOST_EventButton([event timestamp] * 1000,
+ GHOST_kEventButtonDown,
+ window,
+ GHOST_kButtonMaskLeft,
+ window -> GetCocoaTabletData()));
break;
case NSEventTypeRightMouseDown:
handleTabletEvent(event); // Update window tablet state to be included in event.
- pushEvent(new GHOST_EventButton(
- [event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight));
+ pushEvent(new GHOST_EventButton([event timestamp] * 1000,
+ GHOST_kEventButtonDown,
+ window,
+ GHOST_kButtonMaskRight,
+ window -> GetCocoaTabletData()));
break;
case NSEventTypeOtherMouseDown:
handleTabletEvent(event); // Handle tablet events combined with mouse events
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
GHOST_kEventButtonDown,
window,
- convertButton([event buttonNumber])));
+ convertButton([event buttonNumber]),
+ window -> GetCocoaTabletData()));
break;
case NSEventTypeLeftMouseUp:
handleTabletEvent(event); // Update window tablet state to be included in event.
- pushEvent(new GHOST_EventButton(
- [event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft));
+ pushEvent(new GHOST_EventButton([event timestamp] * 1000,
+ GHOST_kEventButtonUp,
+ window,
+ GHOST_kButtonMaskLeft,
+ window -> GetCocoaTabletData()));
break;
case NSEventTypeRightMouseUp:
handleTabletEvent(event); // Update window tablet state to be included in event.
- pushEvent(new GHOST_EventButton(
- [event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight));
+ pushEvent(new GHOST_EventButton([event timestamp] * 1000,
+ GHOST_kEventButtonUp,
+ window,
+ GHOST_kButtonMaskRight,
+ window -> GetCocoaTabletData()));
break;
case NSEventTypeOtherMouseUp:
handleTabletEvent(event); // Update window tablet state to be included in event.
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
GHOST_kEventButtonUp,
window,
- convertButton([event buttonNumber])));
+ convertButton([event buttonNumber]),
+ window -> GetCocoaTabletData()));
break;
case NSEventTypeLeftMouseDragged:
@@ -1568,8 +1579,12 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
window->setCursorGrabAccum(x_accum, y_accum);
window->clientToScreenIntern(x_warp + x_accum, y_warp + y_accum, x, y);
- pushEvent(new GHOST_EventCursor(
- [event timestamp] * 1000, GHOST_kEventCursorMove, window, x, y));
+ pushEvent(new GHOST_EventCursor([event timestamp] * 1000,
+ GHOST_kEventCursorMove,
+ window,
+ x,
+ y,
+ window -> GetCocoaTabletData()));
break;
}
case GHOST_kGrabWrap: // Wrap cursor at area/window boundaries
@@ -1614,8 +1629,12 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
// Generate event
GHOST_TInt32 x, y;
window->clientToScreenIntern(x_mouse + x_accum, y_mouse + y_accum, x, y);
- pushEvent(new GHOST_EventCursor(
- [event timestamp] * 1000, GHOST_kEventCursorMove, window, x, y));
+ pushEvent(new GHOST_EventCursor([event timestamp] * 1000,
+ GHOST_kEventCursorMove,
+ window,
+ x,
+ y,
+ window -> GetCocoaTabletData()));
break;
}
default: {
@@ -1624,8 +1643,12 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
GHOST_TInt32 x, y;
window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
- pushEvent(new GHOST_EventCursor(
- [event timestamp] * 1000, GHOST_kEventCursorMove, window, x, y));
+ pushEvent(new GHOST_EventCursor([event timestamp] * 1000,
+ GHOST_kEventCursorMove,
+ window,
+ x,
+ y,
+ window -> GetCocoaTabletData()));
break;
}
}
diff --git a/intern/ghost/intern/GHOST_SystemNULL.h b/intern/ghost/intern/GHOST_SystemNULL.h
index 68a726f2be8..186cb92d1aa 100644
--- a/intern/ghost/intern/GHOST_SystemNULL.h
+++ b/intern/ghost/intern/GHOST_SystemNULL.h
@@ -106,7 +106,7 @@ class GHOST_SystemNULL : public GHOST_System {
return GHOST_kFailure;
}
- GHOST_IWindow *createWindow(const STR_String &title,
+ GHOST_IWindow *createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp
index 5dae0ce504b..b32ec4306e8 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.cpp
+++ b/intern/ghost/intern/GHOST_SystemSDL.cpp
@@ -49,7 +49,7 @@ GHOST_SystemSDL::~GHOST_SystemSDL()
SDL_Quit();
}
-GHOST_IWindow *GHOST_SystemSDL::createWindow(const STR_String &title,
+GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -390,22 +390,31 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
SDL_WarpMouseInWindow(sdl_win, x_new - x_win, y_new - y_win);
}
- g_event = new GHOST_EventCursor(
- getMilliSeconds(), GHOST_kEventCursorMove, window, x_new, y_new);
+ g_event = new GHOST_EventCursor(getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ window,
+ x_new,
+ y_new,
+ GHOST_TABLET_DATA_NONE);
}
else {
g_event = new GHOST_EventCursor(getMilliSeconds(),
GHOST_kEventCursorMove,
window,
x_root + x_accum,
- y_root + y_accum);
+ y_root + y_accum,
+ GHOST_TABLET_DATA_NONE);
}
}
else
#endif
{
- g_event = new GHOST_EventCursor(
- getMilliSeconds(), GHOST_kEventCursorMove, window, x_root, y_root);
+ g_event = new GHOST_EventCursor(getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ window,
+ x_root,
+ y_root,
+ GHOST_TABLET_DATA_NONE);
}
break;
}
@@ -435,7 +444,8 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
else
break;
- g_event = new GHOST_EventButton(getMilliSeconds(), type, window, gbmask);
+ g_event = new GHOST_EventButton(
+ getMilliSeconds(), type, window, gbmask, GHOST_TABLET_DATA_NONE);
break;
}
case SDL_MOUSEWHEEL: {
diff --git a/intern/ghost/intern/GHOST_SystemSDL.h b/intern/ghost/intern/GHOST_SystemSDL.h
index 1994781530b..8feec9de61d 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.h
+++ b/intern/ghost/intern/GHOST_SystemSDL.h
@@ -80,7 +80,7 @@ class GHOST_SystemSDL : public GHOST_System {
private:
GHOST_TSuccess init();
- GHOST_IWindow *createWindow(const STR_String &title,
+ GHOST_IWindow *createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
new file mode 100644
index 00000000000..31110694ea6
--- /dev/null
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -0,0 +1,1778 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup GHOST
+ */
+
+#include "GHOST_SystemWayland.h"
+#include "GHOST_Event.h"
+#include "GHOST_EventButton.h"
+#include "GHOST_EventCursor.h"
+#include "GHOST_EventDragnDrop.h"
+#include "GHOST_EventKey.h"
+#include "GHOST_EventWheel.h"
+#include "GHOST_TimerManager.h"
+#include "GHOST_WindowManager.h"
+
+#include "GHOST_ContextEGL.h"
+
+#include <EGL/egl.h>
+#include <wayland-egl.h>
+
+#include <algorithm>
+#include <atomic>
+#include <stdexcept>
+#include <thread>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <pointer-constraints-client-protocol.h>
+#include <relative-pointer-client-protocol.h>
+#include <wayland-cursor.h>
+#include <xkbcommon/xkbcommon.h>
+
+#include <fcntl.h>
+#include <linux/input-event-codes.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <cstring>
+
+struct output_t {
+ struct wl_output *output;
+ int32_t width, height;
+ int transform;
+ int scale;
+ std::string make;
+ std::string model;
+};
+
+struct buffer_t {
+ void *data;
+ size_t size;
+};
+
+struct cursor_t {
+ bool visible;
+ struct wl_surface *surface = nullptr;
+ struct wl_buffer *buffer;
+ struct wl_cursor_image image;
+ struct buffer_t *file_buffer = nullptr;
+};
+
+struct data_offer_t {
+ std::unordered_set<std::string> types;
+ uint32_t source_actions;
+ uint32_t dnd_action;
+ struct wl_data_offer *id;
+ std::atomic<bool> in_use;
+ struct {
+ int x, y;
+ } dnd;
+};
+
+struct data_source_t {
+ struct wl_data_source *data_source;
+ /** Last device that was active. */
+ uint32_t source_serial;
+ char *buffer_out;
+};
+
+struct key_repeat_payload_t {
+ GHOST_SystemWayland *system;
+ GHOST_IWindow *window;
+ GHOST_TKey key;
+ GHOST_TEventKeyData key_data;
+};
+
+struct input_t {
+ GHOST_SystemWayland *system;
+
+ std::string name;
+ struct wl_seat *seat;
+ struct wl_pointer *pointer = nullptr;
+ struct wl_keyboard *keyboard = nullptr;
+
+ uint32_t pointer_serial;
+ int x, y;
+ GHOST_Buttons buttons;
+ struct cursor_t cursor;
+
+ struct zwp_relative_pointer_v1 *relative_pointer;
+ struct zwp_locked_pointer_v1 *locked_pointer;
+
+ struct xkb_context *xkb_context;
+ struct xkb_state *xkb_state;
+ struct {
+ /* Key repetition in character per second. */
+ int32_t rate;
+ /* Time (milliseconds) after which to start repeating keys. */
+ int32_t delay;
+ /* Timer for key repeats. */
+ GHOST_ITimerTask *timer = nullptr;
+ } key_repeat;
+
+ struct wl_surface *focus_pointer = nullptr;
+ struct wl_surface *focus_keyboard = nullptr;
+
+ struct wl_data_device *data_device = nullptr;
+ struct data_offer_t *data_offer_dnd; /* Drag & Drop. */
+ struct data_offer_t *data_offer_copy_paste; /* Copy & Paste. */
+
+ struct data_source_t *data_source;
+};
+
+struct display_t {
+ GHOST_SystemWayland *system;
+
+ struct wl_display *display;
+ struct wl_compositor *compositor = nullptr;
+ struct xdg_wm_base *xdg_shell = nullptr;
+ struct wl_shm *shm = nullptr;
+ std::vector<output_t *> outputs;
+ std::vector<input_t *> inputs;
+ struct wl_cursor_theme *cursor_theme = nullptr;
+ struct wl_data_device_manager *data_device_manager = nullptr;
+ struct zwp_relative_pointer_manager_v1 *relative_pointer_manager = nullptr;
+ struct zwp_pointer_constraints_v1 *pointer_constraints = nullptr;
+
+ std::vector<struct wl_surface *> os_surfaces;
+ std::vector<struct wl_egl_window *> os_egl_windows;
+};
+
+static void display_destroy(display_t *d)
+{
+ if (d->data_device_manager) {
+ wl_data_device_manager_destroy(d->data_device_manager);
+ }
+
+ for (output_t *output : d->outputs) {
+ wl_output_destroy(output->output);
+ delete output;
+ }
+
+ for (input_t *input : d->inputs) {
+ 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);
+ }
+ delete input->data_source;
+ }
+ if (input->data_offer_copy_paste) {
+ wl_data_offer_destroy(input->data_offer_copy_paste->id);
+ delete input->data_offer_copy_paste;
+ }
+ if (input->data_device) {
+ wl_data_device_release(input->data_device);
+ }
+ if (input->pointer) {
+ if (input->cursor.file_buffer) {
+ munmap(input->cursor.file_buffer->data, input->cursor.file_buffer->size);
+ delete input->cursor.file_buffer;
+ }
+ if (input->cursor.surface) {
+ wl_surface_destroy(input->cursor.surface);
+ }
+ if (input->pointer) {
+ wl_pointer_destroy(input->pointer);
+ }
+ }
+ if (input->keyboard) {
+ if (input->key_repeat.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;
+ }
+ wl_keyboard_destroy(input->keyboard);
+ }
+ if (input->xkb_state) {
+ xkb_state_unref(input->xkb_state);
+ }
+ if (input->xkb_context) {
+ xkb_context_unref(input->xkb_context);
+ }
+ wl_seat_destroy(input->seat);
+ delete input;
+ }
+
+ if (d->cursor_theme) {
+ wl_cursor_theme_destroy(d->cursor_theme);
+ }
+
+ if (d->shm) {
+ wl_shm_destroy(d->shm);
+ }
+
+ if (d->relative_pointer_manager) {
+ zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager);
+ }
+
+ if (d->pointer_constraints) {
+ zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
+ }
+
+ for (wl_egl_window *os_egl_window : d->os_egl_windows) {
+ wl_egl_window_destroy(os_egl_window);
+ }
+
+ for (wl_surface *os_surface : d->os_surfaces) {
+ wl_surface_destroy(os_surface);
+ }
+
+ if (d->compositor) {
+ wl_compositor_destroy(d->compositor);
+ }
+
+ if (d->xdg_shell) {
+ xdg_wm_base_destroy(d->xdg_shell);
+ }
+
+ if (eglGetDisplay) {
+ ::eglTerminate(eglGetDisplay(EGLNativeDisplayType(d->display)));
+ }
+
+ if (d->display) {
+ wl_display_disconnect(d->display);
+ }
+
+ delete d;
+}
+
+static GHOST_TKey xkb_map_gkey(const xkb_keysym_t &sym)
+{
+
+ GHOST_TKey gkey;
+ if (sym >= XKB_KEY_0 && sym <= XKB_KEY_9) {
+ gkey = GHOST_TKey(sym);
+ }
+ else if (sym >= XKB_KEY_KP_0 && sym <= XKB_KEY_KP_9) {
+ gkey = GHOST_TKey(GHOST_kKeyNumpad0 + sym - XKB_KEY_KP_0);
+ }
+ else if (sym >= XKB_KEY_A && sym <= XKB_KEY_Z) {
+ gkey = GHOST_TKey(sym);
+ }
+ else if (sym >= XKB_KEY_a && sym <= XKB_KEY_z) {
+ gkey = GHOST_TKey(sym - XKB_KEY_a + XKB_KEY_A);
+ }
+ else if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F24) {
+ gkey = GHOST_TKey(GHOST_kKeyF1 + sym - XKB_KEY_F1);
+ }
+ else {
+
+#define GXMAP(k, x, y) \
+ case x: \
+ k = y; \
+ break
+
+ switch (sym) {
+ GXMAP(gkey, XKB_KEY_BackSpace, GHOST_kKeyBackSpace);
+ GXMAP(gkey, XKB_KEY_Tab, GHOST_kKeyTab);
+ GXMAP(gkey, XKB_KEY_Linefeed, GHOST_kKeyLinefeed);
+ GXMAP(gkey, XKB_KEY_Clear, GHOST_kKeyClear);
+ GXMAP(gkey, XKB_KEY_Return, GHOST_kKeyEnter);
+
+ GXMAP(gkey, XKB_KEY_Escape, GHOST_kKeyEsc);
+ GXMAP(gkey, XKB_KEY_space, GHOST_kKeySpace);
+ GXMAP(gkey, XKB_KEY_apostrophe, GHOST_kKeyQuote);
+ GXMAP(gkey, XKB_KEY_comma, GHOST_kKeyComma);
+ GXMAP(gkey, XKB_KEY_minus, GHOST_kKeyMinus);
+ GXMAP(gkey, XKB_KEY_plus, GHOST_kKeyPlus);
+ GXMAP(gkey, XKB_KEY_period, GHOST_kKeyPeriod);
+ GXMAP(gkey, XKB_KEY_slash, GHOST_kKeySlash);
+
+ GXMAP(gkey, XKB_KEY_semicolon, GHOST_kKeySemicolon);
+ GXMAP(gkey, XKB_KEY_equal, GHOST_kKeyEqual);
+
+ GXMAP(gkey, XKB_KEY_bracketleft, GHOST_kKeyLeftBracket);
+ GXMAP(gkey, XKB_KEY_bracketright, GHOST_kKeyRightBracket);
+ GXMAP(gkey, XKB_KEY_backslash, GHOST_kKeyBackslash);
+ GXMAP(gkey, XKB_KEY_grave, GHOST_kKeyAccentGrave);
+
+ GXMAP(gkey, XKB_KEY_Shift_L, GHOST_kKeyLeftShift);
+ GXMAP(gkey, XKB_KEY_Shift_R, GHOST_kKeyRightShift);
+ GXMAP(gkey, XKB_KEY_Control_L, GHOST_kKeyLeftControl);
+ 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_Menu, GHOST_kKeyApp);
+
+ GXMAP(gkey, XKB_KEY_Caps_Lock, GHOST_kKeyCapsLock);
+ GXMAP(gkey, XKB_KEY_Num_Lock, GHOST_kKeyNumLock);
+ GXMAP(gkey, XKB_KEY_Scroll_Lock, GHOST_kKeyScrollLock);
+
+ GXMAP(gkey, XKB_KEY_Left, GHOST_kKeyLeftArrow);
+ GXMAP(gkey, XKB_KEY_Right, GHOST_kKeyRightArrow);
+ GXMAP(gkey, XKB_KEY_Up, GHOST_kKeyUpArrow);
+ GXMAP(gkey, XKB_KEY_Down, GHOST_kKeyDownArrow);
+
+ GXMAP(gkey, XKB_KEY_Print, GHOST_kKeyPrintScreen);
+ GXMAP(gkey, XKB_KEY_Pause, GHOST_kKeyPause);
+
+ GXMAP(gkey, XKB_KEY_Insert, GHOST_kKeyInsert);
+ GXMAP(gkey, XKB_KEY_Delete, GHOST_kKeyDelete);
+ GXMAP(gkey, XKB_KEY_Home, GHOST_kKeyHome);
+ GXMAP(gkey, XKB_KEY_End, GHOST_kKeyEnd);
+ GXMAP(gkey, XKB_KEY_Page_Up, GHOST_kKeyUpPage);
+ GXMAP(gkey, XKB_KEY_Page_Down, GHOST_kKeyDownPage);
+
+ GXMAP(gkey, XKB_KEY_KP_Decimal, GHOST_kKeyNumpadPeriod);
+ GXMAP(gkey, XKB_KEY_KP_Enter, GHOST_kKeyNumpadEnter);
+ GXMAP(gkey, XKB_KEY_KP_Add, GHOST_kKeyNumpadPlus);
+ GXMAP(gkey, XKB_KEY_KP_Subtract, GHOST_kKeyNumpadMinus);
+ GXMAP(gkey, XKB_KEY_KP_Multiply, GHOST_kKeyNumpadAsterisk);
+ GXMAP(gkey, XKB_KEY_KP_Divide, GHOST_kKeyNumpadSlash);
+
+ GXMAP(gkey, XKB_KEY_XF86AudioPlay, GHOST_kKeyMediaPlay);
+ GXMAP(gkey, XKB_KEY_XF86AudioStop, GHOST_kKeyMediaStop);
+ GXMAP(gkey, XKB_KEY_XF86AudioPrev, GHOST_kKeyMediaFirst);
+ GXMAP(gkey, XKB_KEY_XF86AudioNext, GHOST_kKeyMediaLast);
+ default:
+ GHOST_PRINT("unhandled key: " << std::hex << std::showbase << sym << std::dec << " ("
+ << sym << ")" << std::endl);
+ gkey = GHOST_kKeyUnknown;
+ }
+#undef GXMAP
+ }
+
+ return gkey;
+}
+
+static const int default_cursor_size = 24;
+
+static const std::unordered_map<GHOST_TStandardCursor, std::string> cursors = {
+ {GHOST_kStandardCursorDefault, "left_ptr"},
+ {GHOST_kStandardCursorRightArrow, "right_ptr"},
+ {GHOST_kStandardCursorLeftArrow, "left_ptr"},
+ {GHOST_kStandardCursorInfo, ""},
+ {GHOST_kStandardCursorDestroy, ""},
+ {GHOST_kStandardCursorHelp, "question_arrow"},
+ {GHOST_kStandardCursorWait, "watch"},
+ {GHOST_kStandardCursorText, "xterm"},
+ {GHOST_kStandardCursorCrosshair, "crosshair"},
+ {GHOST_kStandardCursorCrosshairA, ""},
+ {GHOST_kStandardCursorCrosshairB, ""},
+ {GHOST_kStandardCursorCrosshairC, ""},
+ {GHOST_kStandardCursorPencil, ""},
+ {GHOST_kStandardCursorUpArrow, "sb_up_arrow"},
+ {GHOST_kStandardCursorDownArrow, "sb_down_arrow"},
+ {GHOST_kStandardCursorVerticalSplit, ""},
+ {GHOST_kStandardCursorHorizontalSplit, ""},
+ {GHOST_kStandardCursorEraser, ""},
+ {GHOST_kStandardCursorKnife, ""},
+ {GHOST_kStandardCursorEyedropper, ""},
+ {GHOST_kStandardCursorZoomIn, ""},
+ {GHOST_kStandardCursorZoomOut, ""},
+ {GHOST_kStandardCursorMove, "move"},
+ {GHOST_kStandardCursorNSEWScroll, ""},
+ {GHOST_kStandardCursorNSScroll, ""},
+ {GHOST_kStandardCursorEWScroll, ""},
+ {GHOST_kStandardCursorStop, ""},
+ {GHOST_kStandardCursorUpDown, "sb_v_double_arrow"},
+ {GHOST_kStandardCursorLeftRight, "sb_h_double_arrow"},
+ {GHOST_kStandardCursorTopSide, "top_side"},
+ {GHOST_kStandardCursorBottomSide, "bottom_side"},
+ {GHOST_kStandardCursorLeftSide, "left_side"},
+ {GHOST_kStandardCursorRightSide, "right_side"},
+ {GHOST_kStandardCursorTopLeftCorner, "top_left_corner"},
+ {GHOST_kStandardCursorTopRightCorner, "top_right_corner"},
+ {GHOST_kStandardCursorBottomRightCorner, "bottom_right_corner"},
+ {GHOST_kStandardCursorBottomLeftCorner, "bottom_left_corner"},
+ {GHOST_kStandardCursorCopy, "copy"},
+};
+
+static constexpr const char *mime_text_plain = "text/plain";
+static constexpr const char *mime_text_utf8 = "text/plain;charset=utf-8";
+static constexpr const char *mime_text_uri = "text/uri-list";
+
+static const std::unordered_map<std::string, GHOST_TDragnDropTypes> mime_dnd = {
+ {mime_text_plain, GHOST_kDragnDropTypeString},
+ {mime_text_utf8, GHOST_kDragnDropTypeString},
+ {mime_text_uri, GHOST_kDragnDropTypeFilenames},
+};
+
+static const std::vector<std::string> mime_preference_order = {
+ mime_text_uri,
+ mime_text_utf8,
+ mime_text_plain,
+};
+
+static const std::vector<std::string> mime_send = {
+ "UTF8_STRING",
+ "COMPOUND_TEXT",
+ "TEXT",
+ "STRING",
+ "text/plain;charset=utf-8",
+ "text/plain",
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Interface Callbacks
+ *
+ * These callbacks are registered for Wayland interfaces and called when
+ * an event is received from the compositor.
+ * \{ */
+
+static void relative_pointer_relative_motion(
+ void *data,
+ struct zwp_relative_pointer_v1 * /*zwp_relative_pointer_v1*/,
+ uint32_t /*utime_hi*/,
+ uint32_t /*utime_lo*/,
+ wl_fixed_t dx,
+ wl_fixed_t dy,
+ wl_fixed_t /*dx_unaccel*/,
+ wl_fixed_t /*dy_unaccel*/)
+{
+ input_t *input = static_cast<input_t *>(data);
+
+ input->x += wl_fixed_to_int(dx);
+ input->y += wl_fixed_to_int(dy);
+
+ GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
+ wl_surface_get_user_data(input->focus_pointer));
+
+ input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ win,
+ input->x,
+ input->y,
+ GHOST_TABLET_DATA_NONE));
+}
+
+static const zwp_relative_pointer_v1_listener relative_pointer_listener = {
+ relative_pointer_relative_motion,
+};
+
+static void dnd_events(const input_t *const input, const GHOST_TEventType event)
+{
+ const GHOST_TUns64 time = input->system->getMilliSeconds();
+ GHOST_IWindow *const window = static_cast<GHOST_WindowWayland *>(
+ wl_surface_get_user_data(input->focus_pointer));
+ for (const std::string &type : mime_preference_order) {
+ input->system->pushEvent(new GHOST_EventDragnDrop(time,
+ event,
+ mime_dnd.at(type),
+ window,
+ input->data_offer_dnd->dnd.x,
+ input->data_offer_dnd->dnd.y,
+ nullptr));
+ }
+}
+
+static std::string read_pipe(data_offer_t *data_offer, const std::string mime_receive)
+{
+ int pipefd[2];
+ pipe(pipefd);
+ wl_data_offer_receive(data_offer->id, mime_receive.c_str(), pipefd[1]);
+ close(pipefd[1]);
+
+ std::string data;
+ ssize_t len;
+ char buffer[4096];
+ while ((len = read(pipefd[0], buffer, sizeof(buffer))) > 0) {
+ data.insert(data.end(), buffer, buffer + len);
+ }
+ close(pipefd[0]);
+ data_offer->in_use.store(false);
+
+ return data;
+}
+
+/**
+ * A target accepts an offered mime type.
+ *
+ * Sent when a target accepts pointer_focus or motion events. If
+ * a target does not accept any of the offered types, type is NULL.
+ */
+static void data_source_target(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/,
+ const char * /*mime_type*/)
+{
+ /* pass */
+}
+
+static void data_source_send(void *data,
+ struct wl_data_source * /*wl_data_source*/,
+ const char * /*mime_type*/,
+ int32_t fd)
+{
+ const char *const buffer = static_cast<char *>(data);
+ write(fd, buffer, strlen(buffer) + 1);
+ close(fd);
+}
+
+static void data_source_cancelled(void * /*data*/, struct wl_data_source *wl_data_source)
+{
+ wl_data_source_destroy(wl_data_source);
+}
+
+/**
+ * The drag-and-drop operation physically finished.
+ *
+ * The user performed the drop action. This event does not
+ * indicate acceptance, #wl_data_source.cancelled may still be
+ * emitted afterwards if the drop destination does not accept any mime type.
+ */
+static void data_source_dnd_drop_performed(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/)
+{
+ /* pass */
+}
+
+/**
+ * The drag-and-drop operation concluded.
+ *
+ * The drop destination finished interoperating with this data
+ * source, so the client is now free to destroy this data source
+ * and free all associated data.
+ */
+static void data_source_dnd_finished(void * /*data*/, struct wl_data_source * /*wl_data_source*/)
+{
+ /* pass */
+}
+
+/**
+ * Notify the selected action.
+ *
+ * This event indicates the action selected by the compositor
+ * after matching the source/destination side actions. Only one
+ * action (or none) will be offered here.
+ */
+static void data_source_action(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/,
+ uint32_t /*dnd_action*/)
+{
+ /* pass */
+}
+
+static const struct wl_data_source_listener data_source_listener = {
+ data_source_target,
+ data_source_send,
+ data_source_cancelled,
+ data_source_dnd_drop_performed,
+ data_source_dnd_finished,
+ data_source_action,
+};
+
+static void data_offer_offer(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ const char *mime_type)
+{
+ static_cast<data_offer_t *>(data)->types.insert(mime_type);
+}
+
+static void data_offer_source_actions(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ uint32_t source_actions)
+{
+ static_cast<data_offer_t *>(data)->source_actions = source_actions;
+}
+
+static void data_offer_action(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ uint32_t dnd_action)
+{
+ static_cast<data_offer_t *>(data)->dnd_action = dnd_action;
+}
+
+static const struct wl_data_offer_listener data_offer_listener = {
+ data_offer_offer,
+ data_offer_source_actions,
+ data_offer_action,
+};
+
+static void data_device_data_offer(void * /*data*/,
+ struct wl_data_device * /*wl_data_device*/,
+ struct wl_data_offer *id)
+{
+ data_offer_t *data_offer = new data_offer_t;
+ data_offer->id = id;
+ wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
+}
+
+static void data_device_enter(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ uint32_t serial,
+ struct wl_surface * /*surface*/,
+ wl_fixed_t x,
+ wl_fixed_t y,
+ struct wl_data_offer *id)
+{
+ input_t *input = static_cast<input_t *>(data);
+ 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;
+
+ data_offer->in_use.store(true);
+ data_offer->dnd.x = wl_fixed_to_int(x);
+ data_offer->dnd.y = wl_fixed_to_int(y);
+
+ wl_data_offer_set_actions(id,
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE,
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
+
+ for (const std::string &type : mime_preference_order) {
+ wl_data_offer_accept(id, serial, type.c_str());
+ }
+
+ dnd_events(input, GHOST_kEventDraggingEntered);
+}
+
+static void data_device_leave(void *data, struct wl_data_device * /*wl_data_device*/)
+{
+ input_t *input = static_cast<input_t *>(data);
+
+ dnd_events(input, GHOST_kEventDraggingExited);
+
+ 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;
+ }
+}
+
+static void data_device_motion(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ uint32_t /*time*/,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ input_t *input = static_cast<input_t *>(data);
+ input->data_offer_dnd->dnd.x = wl_fixed_to_int(x);
+ input->data_offer_dnd->dnd.y = wl_fixed_to_int(y);
+ dnd_events(input, GHOST_kEventDraggingUpdated);
+}
+
+static void data_device_drop(void *data, struct wl_data_device * /*wl_data_device*/)
+{
+ input_t *input = static_cast<input_t *>(data);
+ data_offer_t *data_offer = input->data_offer_dnd;
+
+ const std::string mime_receive = *std::find_first_of(mime_preference_order.begin(),
+ mime_preference_order.end(),
+ data_offer->types.begin(),
+ data_offer->types.end());
+
+ auto read_uris = [](input_t *const input,
+ data_offer_t *data_offer,
+ const std::string mime_receive) {
+ const int x = data_offer->dnd.x;
+ const int y = data_offer->dnd.y;
+
+ const std::string data = read_pipe(data_offer, mime_receive);
+
+ wl_data_offer_finish(data_offer->id);
+ wl_data_offer_destroy(data_offer->id);
+
+ delete data_offer;
+ data_offer = nullptr;
+
+ GHOST_SystemWayland *const system = input->system;
+
+ if (mime_receive == mime_text_uri) {
+ static constexpr const char *file_proto = "file://";
+ static constexpr const char *crlf = "\r\n";
+
+ std::vector<std::string> uris;
+
+ size_t pos = 0;
+ while (true) {
+ pos = data.find(file_proto, pos);
+ const size_t start = pos + sizeof(file_proto) - 1;
+ pos = data.find(crlf, pos);
+ const size_t end = pos;
+
+ if (pos == std::string::npos) {
+ break;
+ }
+ uris.push_back(data.substr(start, end - start));
+ }
+
+ GHOST_TStringArray *flist = static_cast<GHOST_TStringArray *>(
+ malloc(sizeof(GHOST_TStringArray)));
+ flist->count = int(uris.size());
+ flist->strings = static_cast<GHOST_TUns8 **>(malloc(uris.size() * sizeof(GHOST_TUns8 *)));
+ for (size_t i = 0; i < uris.size(); i++) {
+ flist->strings[i] = static_cast<GHOST_TUns8 *>(
+ malloc((uris[i].size() + 1) * sizeof(GHOST_TUns8)));
+ memcpy(flist->strings[i], uris[i].data(), uris[i].size() + 1);
+ }
+ GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
+ wl_surface_get_user_data(input->focus_pointer));
+ system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(),
+ GHOST_kEventDraggingDropDone,
+ GHOST_kDragnDropTypeFilenames,
+ win,
+ x,
+ y,
+ flist));
+ }
+ else if (mime_receive == mime_text_plain || mime_receive == mime_text_utf8) {
+ /* TODO: enable use of internal functions 'txt_insert_buf' and
+ * 'text_update_edited' to behave like dropped text was pasted. */
+ }
+ wl_display_roundtrip(system->display());
+ };
+
+ std::thread read_thread(read_uris, input, data_offer, mime_receive);
+ read_thread.detach();
+}
+
+static void data_device_selection(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ struct wl_data_offer *id)
+{
+ input_t *input = static_cast<input_t *>(data);
+ data_offer_t *data_offer = input->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;
+ }
+
+ if (id == nullptr) {
+ return;
+ }
+
+ /* 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;
+
+ std::string mime_receive;
+ for (const std::string &type : {mime_text_utf8, mime_text_plain}) {
+ if (data_offer->types.count(type)) {
+ mime_receive = type;
+ break;
+ }
+ }
+
+ auto read_selection = [](GHOST_SystemWayland *const system,
+ data_offer_t *data_offer,
+ const std::string mime_receive) {
+ const std::string data = read_pipe(data_offer, mime_receive);
+ system->setSelection(data);
+ };
+
+ std::thread read_thread(read_selection, input->system, data_offer, mime_receive);
+ read_thread.detach();
+}
+
+static const struct wl_data_device_listener data_device_listener = {
+ data_device_data_offer,
+ data_device_enter,
+ data_device_leave,
+ data_device_motion,
+ data_device_drop,
+ data_device_selection,
+};
+
+static void cursor_buffer_release(void *data, struct wl_buffer *wl_buffer)
+{
+ cursor_t *cursor = static_cast<cursor_t *>(data);
+
+ wl_buffer_destroy(wl_buffer);
+ cursor->buffer = nullptr;
+}
+
+const struct wl_buffer_listener cursor_buffer_listener = {
+ cursor_buffer_release,
+};
+
+static void pointer_enter(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t serial,
+ struct wl_surface *surface,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y)
+{
+ if (!surface) {
+ return;
+ }
+ input_t *input = static_cast<input_t *>(data);
+ input->pointer_serial = serial;
+ input->x = wl_fixed_to_int(surface_x);
+ input->y = wl_fixed_to_int(surface_y);
+ input->focus_pointer = surface;
+
+ input->system->pushEvent(
+ new GHOST_EventCursor(input->system->getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ static_cast<GHOST_WindowWayland *>(wl_surface_get_user_data(surface)),
+ input->x,
+ input->y,
+ GHOST_TABLET_DATA_NONE));
+}
+
+static void pointer_leave(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t /*serial*/,
+ struct wl_surface *surface)
+{
+ if (surface != nullptr) {
+ static_cast<input_t *>(data)->focus_pointer = nullptr;
+ }
+}
+
+static void pointer_motion(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t /*time*/,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y)
+{
+ input_t *input = static_cast<input_t *>(data);
+
+ GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
+ wl_surface_get_user_data(input->focus_pointer));
+
+ if (!win) {
+ return;
+ }
+
+ input->x = wl_fixed_to_int(surface_x);
+ input->y = wl_fixed_to_int(surface_y);
+
+ input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ win,
+ wl_fixed_to_int(surface_x),
+ wl_fixed_to_int(surface_y),
+ GHOST_TABLET_DATA_NONE));
+}
+
+static void pointer_button(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t serial,
+ uint32_t /*time*/,
+ uint32_t button,
+ uint32_t state)
+{
+ GHOST_TEventType etype = GHOST_kEventUnknown;
+ switch (state) {
+ case WL_POINTER_BUTTON_STATE_RELEASED:
+ etype = GHOST_kEventButtonUp;
+ break;
+ case WL_POINTER_BUTTON_STATE_PRESSED:
+ etype = GHOST_kEventButtonDown;
+ break;
+ }
+
+ GHOST_TButtonMask ebutton = GHOST_kButtonMaskLeft;
+ switch (button) {
+ case BTN_LEFT:
+ ebutton = GHOST_kButtonMaskLeft;
+ break;
+ case BTN_MIDDLE:
+ ebutton = GHOST_kButtonMaskMiddle;
+ break;
+ case BTN_RIGHT:
+ ebutton = GHOST_kButtonMaskRight;
+ break;
+ }
+
+ input_t *input = static_cast<input_t *>(data);
+ GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
+ wl_surface_get_user_data(input->focus_pointer));
+ input->data_source->source_serial = serial;
+ input->buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED);
+ input->system->pushEvent(new GHOST_EventButton(
+ input->system->getMilliSeconds(), etype, win, ebutton, GHOST_TABLET_DATA_NONE));
+}
+
+static void pointer_axis(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ uint32_t /*time*/,
+ uint32_t axis,
+ wl_fixed_t value)
+{
+ if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) {
+ return;
+ }
+ input_t *input = static_cast<input_t *>(data);
+ GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
+ wl_surface_get_user_data(input->focus_pointer));
+ input->system->pushEvent(
+ new GHOST_EventWheel(input->system->getMilliSeconds(), win, std::signbit(value) ? +1 : -1));
+}
+
+static const struct wl_pointer_listener pointer_listener = {
+ pointer_enter,
+ pointer_leave,
+ pointer_motion,
+ pointer_button,
+ pointer_axis,
+};
+
+static void keyboard_keymap(
+ void *data, struct wl_keyboard * /*wl_keyboard*/, uint32_t format, int32_t fd, uint32_t size)
+{
+ input_t *input = static_cast<input_t *>(data);
+
+ if ((!data) || (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)) {
+ close(fd);
+ return;
+ }
+
+ char *map_str = static_cast<char *>(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0));
+ if (map_str == MAP_FAILED) {
+ close(fd);
+ throw std::runtime_error("keymap mmap failed: " + std::string(std::strerror(errno)));
+ }
+
+ struct xkb_keymap *keymap = xkb_keymap_new_from_string(
+ input->xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
+ munmap(map_str, size);
+ close(fd);
+
+ if (!keymap) {
+ return;
+ }
+
+ input->xkb_state = xkb_state_new(keymap);
+
+ xkb_keymap_unref(keymap);
+}
+
+/**
+ * Enter event.
+ *
+ * Notification that this seat's keyboard focus is on a certain
+ * surface.
+ */
+static void keyboard_enter(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t /*serial*/,
+ struct wl_surface *surface,
+ struct wl_array * /*keys*/)
+{
+ if (surface != nullptr) {
+ static_cast<input_t *>(data)->focus_keyboard = surface;
+ }
+}
+
+/**
+ * Leave event.
+ *
+ * Notification that this seat's keyboard focus is no longer on a
+ * certain surface.
+ */
+static void keyboard_leave(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t /*serial*/,
+ struct wl_surface *surface)
+{
+ if (surface != nullptr) {
+ static_cast<input_t *>(data)->focus_keyboard = nullptr;
+ }
+}
+
+/**
+ * A version of #xkb_state_key_get_one_sym which returns the key without any modifiers pressed.
+ * Needed because #GHOST_TKey uses these values as key-codes.
+ */
+static xkb_keysym_t xkb_state_key_get_one_sym_without_modifiers(struct xkb_state *xkb_state,
+ xkb_keycode_t key)
+{
+ /* Use an empty keyboard state to access key symbol without modifiers. */
+ xkb_state_get_keymap(xkb_state);
+ struct xkb_keymap *keymap = xkb_state_get_keymap(xkb_state);
+ struct xkb_state *xkb_state_empty = xkb_state_new(keymap);
+
+ /* Enable number-lock. */
+ {
+ 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) {
+ xkb_state_update_mask(xkb_state_empty, (1 << mod2), 0, (1 << num), 0, 0, 0);
+ }
+ }
+
+ const xkb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state_empty, key);
+ xkb_state_unref(xkb_state_empty);
+ return sym;
+}
+
+static void keyboard_key(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t serial,
+ uint32_t /*time*/,
+ uint32_t key,
+ uint32_t state)
+{
+ input_t *input = static_cast<input_t *>(data);
+
+ GHOST_TEventType etype = GHOST_kEventUnknown;
+ switch (state) {
+ case WL_KEYBOARD_KEY_STATE_RELEASED:
+ etype = GHOST_kEventKeyUp;
+ break;
+ case WL_KEYBOARD_KEY_STATE_PRESSED:
+ etype = GHOST_kEventKeyDown;
+ break;
+ }
+
+ const xkb_keysym_t sym = xkb_state_key_get_one_sym_without_modifiers(input->xkb_state, key + 8);
+
+ if (sym == XKB_KEY_NoSymbol) {
+ return;
+ }
+ const GHOST_TKey gkey = xkb_map_gkey(sym);
+
+ /* Delete previous timer. */
+ if (xkb_keymap_key_repeats(xkb_state_get_keymap(input->xkb_state), key + 8) &&
+ input->key_repeat.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_TEventKeyData key_data;
+
+ if (etype == GHOST_kEventKeyDown) {
+ xkb_state_key_get_utf8(
+ input->xkb_state, key + 8, key_data.utf8_buf, sizeof(GHOST_TEventKeyData::utf8_buf));
+ }
+ else {
+ key_data.utf8_buf[0] = '\0';
+ }
+
+ input->data_source->source_serial = serial;
+
+ GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
+ wl_surface_get_user_data(input->focus_keyboard));
+ input->system->pushEvent(new GHOST_EventKey(
+ input->system->getMilliSeconds(), etype, win, gkey, '\0', key_data.utf8_buf, false));
+
+ /* Start timer for repeating key, if applicable. */
+ if (input->key_repeat.rate > 0 &&
+ xkb_keymap_key_repeats(xkb_state_get_keymap(input->xkb_state), key + 8) &&
+ etype == GHOST_kEventKeyDown) {
+
+ key_repeat_payload_t *payload = new key_repeat_payload_t({
+ .system = input->system,
+ .window = win,
+ .key = gkey,
+ .key_data = key_data,
+ });
+
+ auto cb = [](GHOST_ITimerTask *task, GHOST_TUns64 /*time*/) {
+ struct key_repeat_payload_t *payload = static_cast<key_repeat_payload_t *>(
+ task->getUserData());
+ payload->system->pushEvent(new GHOST_EventKey(payload->system->getMilliSeconds(),
+ GHOST_kEventKeyDown,
+ payload->window,
+ payload->key,
+ '\0',
+ payload->key_data.utf8_buf,
+ true));
+ };
+ input->key_repeat.timer = input->system->installTimer(
+ input->key_repeat.delay, 1000 / input->key_repeat.rate, cb, payload);
+ }
+}
+
+static void keyboard_modifiers(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ uint32_t /*serial*/,
+ uint32_t mods_depressed,
+ uint32_t mods_latched,
+ uint32_t mods_locked,
+ uint32_t group)
+{
+ xkb_state_update_mask(static_cast<input_t *>(data)->xkb_state,
+ mods_depressed,
+ mods_latched,
+ mods_locked,
+ 0,
+ 0,
+ group);
+}
+
+static void keyboard_repeat_info(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ int32_t rate,
+ int32_t delay)
+{
+ input_t *input = static_cast<input_t *>(data);
+
+ input->key_repeat.rate = rate;
+ input->key_repeat.delay = delay;
+}
+
+static const struct wl_keyboard_listener keyboard_listener = {
+ keyboard_keymap,
+ keyboard_enter,
+ keyboard_leave,
+ keyboard_key,
+ keyboard_modifiers,
+ keyboard_repeat_info,
+};
+
+static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
+{
+ input_t *input = static_cast<input_t *>(data);
+ input->pointer = nullptr;
+ input->keyboard = nullptr;
+
+ if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
+ input->pointer = wl_seat_get_pointer(wl_seat);
+ input->cursor.surface = wl_compositor_create_surface(input->system->compositor());
+ input->cursor.visible = true;
+ input->cursor.buffer = nullptr;
+ input->cursor.file_buffer = new buffer_t;
+ wl_pointer_add_listener(input->pointer, &pointer_listener, data);
+ }
+
+ if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
+ input->keyboard = wl_seat_get_keyboard(wl_seat);
+ wl_keyboard_add_listener(input->keyboard, &keyboard_listener, data);
+ }
+}
+
+static void seat_name(void *data, struct wl_seat * /*wl_seat*/, const char *name)
+{
+ static_cast<input_t *>(data)->name = std::string(name);
+}
+
+static const struct wl_seat_listener seat_listener = {
+ seat_capabilities,
+ seat_name,
+};
+
+static void output_geometry(void *data,
+ struct wl_output * /*wl_output*/,
+ int32_t /*x*/,
+ int32_t /*y*/,
+ int32_t /*physical_width*/,
+ int32_t /*physical_height*/,
+ int32_t /*subpixel*/,
+ const char *make,
+ const char *model,
+ int32_t transform)
+{
+ output_t *output = static_cast<output_t *>(data);
+ output->transform = transform;
+ output->make = std::string(make);
+ output->model = std::string(model);
+}
+
+static void output_mode(void *data,
+ struct wl_output * /*wl_output*/,
+ uint32_t /*flags*/,
+ int32_t width,
+ int32_t height,
+ int32_t /*refresh*/)
+{
+ output_t *output = static_cast<output_t *>(data);
+ output->width = width;
+ output->height = height;
+}
+
+/**
+ * Sent all information about output.
+ *
+ * This event is sent after all other properties have been sent
+ * after binding to the output object and after any other property
+ * changes done after that. This allows changes to the output
+ * properties to be seen as atomic, even if they happen via multiple events.
+ */
+static void output_done(void * /*data*/, struct wl_output * /*wl_output*/)
+{
+}
+
+static void output_scale(void *data, struct wl_output * /*wl_output*/, int32_t factor)
+{
+ static_cast<output_t *>(data)->scale = factor;
+}
+
+static const struct wl_output_listener output_listener = {
+ output_geometry,
+ output_mode,
+ output_done,
+ output_scale,
+};
+
+static void shell_ping(void * /*data*/, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
+{
+ xdg_wm_base_pong(xdg_wm_base, serial);
+}
+
+static const struct xdg_wm_base_listener shell_listener = {
+ shell_ping,
+};
+
+static void global_add(void *data,
+ struct wl_registry *wl_registry,
+ uint32_t name,
+ const char *interface,
+ uint32_t /*version*/)
+{
+ struct display_t *display = static_cast<struct display_t *>(data);
+ if (!strcmp(interface, wl_compositor_interface.name)) {
+ display->compositor = static_cast<wl_compositor *>(
+ wl_registry_bind(wl_registry, name, &wl_compositor_interface, 1));
+ }
+ else if (!strcmp(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, wl_output_interface.name)) {
+ output_t *output = new output_t;
+ output->scale = 1;
+ output->output = static_cast<wl_output *>(
+ wl_registry_bind(wl_registry, name, &wl_output_interface, 2));
+ display->outputs.push_back(output);
+ wl_output_add_listener(output->output, &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->xkb_state = nullptr;
+ input->data_offer_dnd = nullptr;
+ input->data_offer_copy_paste = nullptr;
+ input->data_source = new data_source_t;
+ input->data_source->data_source = nullptr;
+ input->data_source->buffer_out = nullptr;
+ input->relative_pointer = nullptr;
+ input->locked_pointer = nullptr;
+ input->seat = static_cast<wl_seat *>(
+ wl_registry_bind(wl_registry, name, &wl_seat_interface, 4));
+ display->inputs.push_back(input);
+ wl_seat_add_listener(input->seat, &seat_listener, input);
+ }
+ else if (!strcmp(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)) {
+ display->data_device_manager = static_cast<wl_data_device_manager *>(
+ wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 1));
+ }
+ else if (!strcmp(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)) {
+ display->pointer_constraints = static_cast<zwp_pointer_constraints_v1 *>(
+ wl_registry_bind(wl_registry, name, &zwp_pointer_constraints_v1_interface, 1));
+ }
+}
+
+/**
+ * Announce removal of global object.
+ *
+ * Notify the client of removed global objects.
+ *
+ * This event notifies the client that the global identified by
+ * name is no longer available. If the client bound to the global
+ * using the bind request, the client should now destroy that object.
+ */
+static void global_remove(void * /*data*/, struct wl_registry * /*wl_registry*/, uint32_t /*name*/)
+{
+}
+
+static const struct wl_registry_listener registry_listener = {
+ global_add,
+ global_remove,
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Ghost Implementation
+ *
+ * Wayland specific implementation of the GHOST_System interface.
+ * \{ */
+
+GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t)
+{
+ d->system = this;
+ /* Connect to the Wayland server. */
+ d->display = wl_display_connect(nullptr);
+ if (!d->display) {
+ display_destroy(d);
+ throw std::runtime_error("Wayland: unable to connect to display!");
+ }
+
+ /* Register interfaces. */
+ struct wl_registry *registry = wl_display_get_registry(d->display);
+ wl_registry_add_listener(registry, &registry_listener, d);
+ /* Call callback for registry listener. */
+ wl_display_roundtrip(d->display);
+ /* Call callbacks for registered listeners. */
+ wl_display_roundtrip(d->display);
+ wl_registry_destroy(registry);
+
+ if (!d->xdg_shell) {
+ display_destroy(d);
+ throw std::runtime_error("Wayland: unable to access xdg_shell!");
+ }
+
+ /* 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->seat);
+ wl_data_device_add_listener(input->data_device, &data_device_listener, input);
+ }
+ }
+
+ const char *theme = std::getenv("XCURSOR_THEME");
+ const char *size = std::getenv("XCURSOR_SIZE");
+ const int sizei = size ? std::stoi(size) : default_cursor_size;
+
+ d->cursor_theme = wl_cursor_theme_load(theme, sizei, d->shm);
+ if (!d->cursor_theme) {
+ display_destroy(d);
+ throw std::runtime_error("Wayland: unable to access cursor themes!");
+ }
+}
+
+GHOST_SystemWayland::~GHOST_SystemWayland()
+{
+ display_destroy(d);
+}
+
+bool GHOST_SystemWayland::processEvents(bool waitForEvent)
+{
+ const bool fired = getTimerManager()->fireTimers(getMilliSeconds());
+
+ if (waitForEvent) {
+ wl_display_dispatch(d->display);
+ }
+ else {
+ wl_display_roundtrip(d->display);
+ }
+
+ return fired || (getEventManager()->getNumEvents() > 0);
+}
+
+int GHOST_SystemWayland::toggleConsole(int /*action*/)
+{
+ return 0;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) const
+{
+ if (!d->inputs.empty()) {
+ static const xkb_state_component mods_all = xkb_state_component(
+ XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED | XKB_STATE_MODS_LOCKED |
+ XKB_STATE_MODS_EFFECTIVE);
+
+ keys.set(GHOST_kModifierKeyLeftShift,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_SHIFT, mods_all) ==
+ 1);
+ keys.set(GHOST_kModifierKeyRightShift,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_SHIFT, mods_all) ==
+ 1);
+ keys.set(GHOST_kModifierKeyLeftAlt,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "LAlt", mods_all) == 1);
+ keys.set(GHOST_kModifierKeyRightAlt,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "RAlt", mods_all) == 1);
+ keys.set(GHOST_kModifierKeyLeftControl,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "LControl", mods_all) == 1);
+ keys.set(GHOST_kModifierKeyRightControl,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "RControl", mods_all) == 1);
+ keys.set(GHOST_kModifierKeyOS,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "Super", mods_all) == 1);
+ keys.set(GHOST_kModifierKeyNumMasks,
+ xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "NumLock", mods_all) == 1);
+
+ return GHOST_kSuccess;
+ }
+ return GHOST_kFailure;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const
+{
+ if (!d->inputs.empty()) {
+ buttons = d->inputs[0]->buttons;
+ return GHOST_kSuccess;
+ }
+ return GHOST_kFailure;
+}
+
+GHOST_TUns8 *GHOST_SystemWayland::getClipboard(bool /*selection*/) const
+{
+ GHOST_TUns8 *clipboard = static_cast<GHOST_TUns8 *>(malloc((selection.size() + 1)));
+ memcpy(clipboard, selection.data(), selection.size() + 1);
+ return clipboard;
+}
+
+void GHOST_SystemWayland::putClipboard(GHOST_TInt8 *buffer, bool /*selection*/) const
+{
+ if (!d->data_device_manager || d->inputs.empty()) {
+ return;
+ }
+
+ data_source_t *data_source = d->inputs[0]->data_source;
+
+ /* Copy buffer. */
+ data_source->buffer_out = static_cast<char *>(malloc(strlen(buffer) + 1));
+ std::strcpy(data_source->buffer_out, buffer);
+
+ 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, data_source->buffer_out);
+
+ for (const std::string &type : mime_send) {
+ wl_data_source_offer(data_source->data_source, type.c_str());
+ }
+
+ if (!d->inputs.empty() && d->inputs[0]->data_device) {
+ wl_data_device_set_selection(
+ d->inputs[0]->data_device, data_source->data_source, data_source->source_serial);
+ }
+}
+
+GHOST_TUns8 GHOST_SystemWayland::getNumDisplays() const
+{
+ return d ? GHOST_TUns8(d->outputs.size()) : 0;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(GHOST_TInt32 &x, GHOST_TInt32 &y) const
+{
+ if (!d->inputs.empty() && (d->inputs[0]->focus_pointer != nullptr)) {
+ x = d->inputs[0]->x;
+ y = d->inputs[0]->y;
+ return GHOST_kSuccess;
+ }
+ else {
+ return GHOST_kFailure;
+ }
+}
+
+GHOST_TSuccess GHOST_SystemWayland::setCursorPosition(GHOST_TInt32 /*x*/, GHOST_TInt32 /*y*/)
+{
+ return GHOST_kFailure;
+}
+
+void GHOST_SystemWayland::getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const
+{
+ if (getNumDisplays() > 0) {
+ /* We assume first output as main. */
+ width = uint32_t(d->outputs[0]->width);
+ height = uint32_t(d->outputs[0]->height);
+ }
+}
+
+void GHOST_SystemWayland::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const
+{
+ getMainDisplayDimensions(width, height);
+}
+
+GHOST_IContext *GHOST_SystemWayland::createOffscreenContext()
+{
+ /* Create new off-screen window. */
+ wl_surface *os_surface = wl_compositor_create_surface(compositor());
+ wl_egl_window *os_egl_window = wl_egl_window_create(os_surface, int(1), int(1));
+
+ d->os_surfaces.push_back(os_surface);
+ d->os_egl_windows.push_back(os_egl_window);
+
+ GHOST_Context *context = new GHOST_ContextEGL(false,
+ EGLNativeWindowType(os_egl_window),
+ EGLNativeDisplayType(d->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()) {
+ return context;
+ }
+ else {
+ delete context;
+ }
+
+ GHOST_PRINT("Cannot create off-screen EGL context" << std::endl);
+
+ return nullptr;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::disposeContext(GHOST_IContext *context)
+{
+ delete context;
+ return GHOST_kSuccess;
+}
+
+GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
+ GHOST_TInt32 left,
+ GHOST_TInt32 top,
+ GHOST_TUns32 width,
+ GHOST_TUns32 height,
+ GHOST_TWindowState state,
+ GHOST_TDrawingContextType type,
+ GHOST_GLSettings glSettings,
+ const bool exclusive,
+ const bool is_dialog,
+ const GHOST_IWindow *parentWindow)
+{
+ GHOST_WindowWayland *window = new GHOST_WindowWayland(
+ this,
+ title,
+ left,
+ top,
+ width,
+ height,
+ state,
+ parentWindow,
+ type,
+ is_dialog,
+ ((glSettings.flags & GHOST_glStereoVisual) != 0),
+ exclusive);
+
+ if (window) {
+ if (window->getValid()) {
+ m_windowManager->addWindow(window);
+ m_windowManager->setActiveWindow(window);
+ pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window));
+ }
+ else {
+ delete window;
+ window = nullptr;
+ }
+ }
+
+ return window;
+}
+
+wl_display *GHOST_SystemWayland::display()
+{
+ return d->display;
+}
+
+wl_compositor *GHOST_SystemWayland::compositor()
+{
+ return d->compositor;
+}
+
+xdg_wm_base *GHOST_SystemWayland::shell()
+{
+ return d->xdg_shell;
+}
+
+void GHOST_SystemWayland::setSelection(const std::string &selection)
+{
+ this->selection = selection;
+}
+
+static void set_cursor_buffer(input_t *input, wl_buffer *buffer)
+{
+ input->cursor.visible = (buffer != nullptr);
+
+ wl_surface_attach(input->cursor.surface, buffer, 0, 0);
+ wl_surface_commit(input->cursor.surface);
+
+ if (input->cursor.visible) {
+ wl_surface_damage(input->cursor.surface,
+ 0,
+ 0,
+ int32_t(input->cursor.image.width),
+ int32_t(input->cursor.image.height));
+ wl_pointer_set_cursor(input->pointer,
+ input->pointer_serial,
+ input->cursor.surface,
+ int32_t(input->cursor.image.hotspot_x),
+ int32_t(input->cursor.image.hotspot_y));
+ }
+}
+
+GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
+{
+ if (d->inputs.empty()) {
+ return GHOST_kFailure;
+ }
+ const std::string cursor_name = cursors.count(shape) ? cursors.at(shape) :
+ cursors.at(GHOST_kStandardCursorDefault);
+
+ wl_cursor *cursor = wl_cursor_theme_get_cursor(d->cursor_theme, cursor_name.c_str());
+
+ if (!cursor) {
+ GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
+ return GHOST_kFailure;
+ }
+
+ struct wl_cursor_image *image = cursor->images[0];
+ struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
+ if (!buffer) {
+ return GHOST_kFailure;
+ }
+ cursor_t *c = &d->inputs[0]->cursor;
+ c->buffer = buffer;
+ c->image = *image;
+
+ set_cursor_buffer(d->inputs[0], buffer);
+
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::hasCursorShape(GHOST_TStandardCursor cursorShape)
+{
+ return GHOST_TSuccess(cursors.count(cursorShape) && !cursors.at(cursorShape).empty());
+}
+
+GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(GHOST_TUns8 *bitmap,
+ GHOST_TUns8 *mask,
+ int sizex,
+ int sizey,
+ int hotX,
+ int hotY,
+ bool /*canInvertColor*/)
+{
+ if (d->inputs.empty()) {
+ return GHOST_kFailure;
+ }
+
+ cursor_t *cursor = &d->inputs[0]->cursor;
+
+ static const int32_t stride = sizex * 4; /* ARGB */
+ cursor->file_buffer->size = size_t(stride * sizey);
+
+ const int fd = memfd_create("blender-cursor-custom", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK);
+ posix_fallocate(fd, 0, int32_t(cursor->file_buffer->size));
+
+ cursor->file_buffer->data = mmap(
+ nullptr, cursor->file_buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ struct wl_shm_pool *pool = wl_shm_create_pool(d->shm, fd, int32_t(cursor->file_buffer->size));
+
+ wl_buffer *buffer = wl_shm_pool_create_buffer(
+ pool, 0, sizex, sizey, stride, WL_SHM_FORMAT_ARGB8888);
+
+ wl_shm_pool_destroy(pool);
+ close(fd);
+
+ wl_buffer_add_listener(buffer, &cursor_buffer_listener, cursor);
+
+ static constexpr uint32_t black = 0xFF000000;
+ static constexpr uint32_t white = 0xFFFFFFFF;
+ static constexpr uint32_t transparent = 0x00000000;
+
+ uint8_t datab = 0, maskb = 0;
+ uint32_t *pixel;
+
+ for (int y = 0; y < sizey; ++y) {
+ pixel = &static_cast<uint32_t *>(cursor->file_buffer->data)[y * sizex];
+ for (int x = 0; x < sizex; ++x) {
+ if ((x % 8) == 0) {
+ datab = *bitmap++;
+ maskb = *mask++;
+
+ /* Reverse bit order. */
+ datab = uint8_t((datab * 0x0202020202ULL & 0x010884422010ULL) % 1023);
+ maskb = uint8_t((maskb * 0x0202020202ULL & 0x010884422010ULL) % 1023);
+ }
+
+ if (maskb & 0x80) {
+ *pixel++ = (datab & 0x80) ? white : black;
+ }
+ else {
+ *pixel++ = (datab & 0x80) ? white : transparent;
+ }
+ datab <<= 1;
+ maskb <<= 1;
+ }
+ }
+
+ cursor->buffer = buffer;
+ cursor->image.width = uint32_t(sizex);
+ cursor->image.height = uint32_t(sizey);
+ cursor->image.hotspot_x = uint32_t(hotX);
+ cursor->image.hotspot_y = uint32_t(hotY);
+
+ set_cursor_buffer(d->inputs[0], buffer);
+
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible)
+{
+ if (d->inputs.empty()) {
+ return GHOST_kFailure;
+ }
+
+ input_t *input = d->inputs[0];
+
+ cursor_t *cursor = &input->cursor;
+ if (visible) {
+ if (!cursor->visible) {
+ set_cursor_buffer(input, cursor->buffer);
+ }
+ }
+ else {
+ if (cursor->visible) {
+ set_cursor_buffer(input, nullptr);
+ }
+ }
+
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mode,
+ wl_surface *surface)
+{
+ if (d->inputs.empty()) {
+ return GHOST_kFailure;
+ }
+
+ input_t *input = d->inputs[0];
+
+ switch (mode) {
+ case GHOST_kGrabDisable:
+ if (input->relative_pointer) {
+ zwp_relative_pointer_v1_destroy(input->relative_pointer);
+ input->relative_pointer = nullptr;
+ }
+ if (input->locked_pointer) {
+ zwp_locked_pointer_v1_destroy(input->locked_pointer);
+ input->locked_pointer = nullptr;
+ }
+ break;
+
+ case GHOST_kGrabNormal:
+ case GHOST_kGrabWrap:
+ input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
+ d->relative_pointer_manager, input->pointer);
+ zwp_relative_pointer_v1_add_listener(
+ input->relative_pointer, &relative_pointer_listener, input);
+ input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
+ d->pointer_constraints,
+ surface,
+ input->pointer,
+ nullptr,
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+ break;
+
+ case GHOST_kGrabHide:
+ setCursorVisibility(false);
+ break;
+ }
+
+ return GHOST_kSuccess;
+}
+
+/** \} */
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
new file mode 100644
index 00000000000..89cd3406b69
--- /dev/null
+++ b/intern/ghost/intern/GHOST_SystemWayland.h
@@ -0,0 +1,111 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup GHOST
+ * Declaration of GHOST_SystemWayland class.
+ */
+
+#ifndef __GHOST_SYSTEMWAYLAND_H__
+#define __GHOST_SYSTEMWAYLAND_H__
+
+#include "../GHOST_Types.h"
+#include "GHOST_System.h"
+#include "GHOST_WindowWayland.h"
+
+#include <wayland-client.h>
+#include <xdg-shell-client-protocol.h>
+
+#include <string>
+
+class GHOST_WindowWayland;
+
+struct display_t;
+
+class GHOST_SystemWayland : public GHOST_System {
+ public:
+ GHOST_SystemWayland();
+
+ ~GHOST_SystemWayland() override;
+
+ bool processEvents(bool waitForEvent) override;
+
+ int toggleConsole(int action) override;
+
+ GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const override;
+
+ GHOST_TSuccess getButtons(GHOST_Buttons &buttons) const override;
+
+ GHOST_TUns8 *getClipboard(bool selection) const override;
+
+ void putClipboard(GHOST_TInt8 *buffer, bool selection) const override;
+
+ GHOST_TUns8 getNumDisplays() const override;
+
+ GHOST_TSuccess getCursorPosition(GHOST_TInt32 &x, GHOST_TInt32 &y) const override;
+
+ GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) override;
+
+ void getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const override;
+
+ void getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const override;
+
+ GHOST_IContext *createOffscreenContext() override;
+
+ GHOST_TSuccess disposeContext(GHOST_IContext *context) override;
+
+ GHOST_IWindow *createWindow(const char *title,
+ GHOST_TInt32 left,
+ GHOST_TInt32 top,
+ GHOST_TUns32 width,
+ GHOST_TUns32 height,
+ GHOST_TWindowState state,
+ GHOST_TDrawingContextType type,
+ GHOST_GLSettings glSettings,
+ const bool exclusive,
+ const bool is_dialog,
+ const GHOST_IWindow *parentWindow) override;
+
+ wl_display *display();
+
+ wl_compositor *compositor();
+
+ xdg_wm_base *shell();
+
+ void setSelection(const std::string &selection);
+
+ GHOST_TSuccess setCursorShape(GHOST_TStandardCursor shape);
+
+ GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape);
+
+ GHOST_TSuccess setCustomCursorShape(GHOST_TUns8 *bitmap,
+ GHOST_TUns8 *mask,
+ int sizex,
+ int sizey,
+ int hotX,
+ int hotY,
+ bool canInvertColor);
+
+ GHOST_TSuccess setCursorVisibility(bool visible);
+
+ GHOST_TSuccess setCursorGrab(const GHOST_TGrabCursorMode mode, wl_surface *surface);
+
+ private:
+ struct display_t *d;
+ std::string selection;
+};
+
+#endif /* __GHOST_SYSTEMWAYLAND_H__ */
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index e31186bd6a5..849aa5a96f5 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -115,12 +115,22 @@
# define WM_DPICHANGED 0x02E0
#endif // WM_DPICHANGED
+// WM_POINTER API messages minimum Windows 7
+#ifndef WM_POINTERENTER
+# define WM_POINTERENTER 0x0249
+#endif // WM_POINTERENTER
+#ifndef WM_POINTERDOWN
+# define WM_POINTERDOWN 0x0246
+#endif // WM_POINTERDOWN
#ifndef WM_POINTERUPDATE
# define WM_POINTERUPDATE 0x0245
#endif // WM_POINTERUPDATE
-
-#define WM_POINTERDOWN 0x0246
-#define WM_POINTERUP 0x0247
+#ifndef WM_POINTERUP
+# define WM_POINTERUP 0x0247
+#endif // WM_POINTERUP
+#ifndef WM_POINTERLEAVE
+# define WM_POINTERLEAVE 0x024A
+#endif // WM_POINTERLEAVE
/* Workaround for some laptop touchpads, some of which seems to
* have driver issues which makes it so window function receives
@@ -184,7 +194,8 @@ typedef enum MONITOR_DPI_TYPE {
typedef HRESULT(API *GHOST_WIN32_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS);
typedef BOOL(API *GHOST_WIN32_EnableNonClientDpiScaling)(HWND);
-GHOST_SystemWin32::GHOST_SystemWin32() : m_hasPerformanceCounter(false), m_freq(0), m_start(0)
+GHOST_SystemWin32::GHOST_SystemWin32()
+ : m_hasPerformanceCounter(false), m_freq(0), m_start(0), m_lfstart(0)
{
m_displayManager = new GHOST_DisplayManagerWin32();
GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n");
@@ -223,22 +234,32 @@ GHOST_SystemWin32::~GHOST_SystemWin32()
toggleConsole(1);
}
+GHOST_TUns64 GHOST_SystemWin32::performanceCounterToMillis(__int64 perf_ticks) const
+{
+ // Calculate the time passed since system initialization.
+ __int64 delta = (perf_ticks - m_start) * 1000;
+
+ GHOST_TUns64 t = (GHOST_TUns64)(delta / m_freq);
+ return t;
+}
+
+GHOST_TUns64 GHOST_SystemWin32::tickCountToMillis(__int64 ticks) const
+{
+ return ticks - m_lfstart;
+}
+
GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const
{
// Hardware does not support high resolution timers. We will use GetTickCount instead then.
if (!m_hasPerformanceCounter) {
- return ::GetTickCount();
+ return tickCountToMillis(::GetTickCount());
}
// Retrieve current count
__int64 count = 0;
::QueryPerformanceCounter((LARGE_INTEGER *)&count);
- // Calculate the time passed since system initialization.
- __int64 delta = 1000 * (count - m_start);
-
- GHOST_TUns64 t = (GHOST_TUns64)(delta / m_freq);
- return t;
+ return performanceCounterToMillis(count);
}
GHOST_TUns8 GHOST_SystemWin32::getNumDisplays() const
@@ -261,7 +282,7 @@ void GHOST_SystemWin32::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns3
height = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
}
-GHOST_IWindow *GHOST_SystemWin32::createWindow(const STR_String &title,
+GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -411,9 +432,9 @@ GHOST_TSuccess GHOST_SystemWin32::disposeContext(GHOST_IContext *context)
* Never explicitly delete the window, use #disposeContext() instead.
* \return The new context (or 0 if creation failed).
*/
-GHOST_IContext *GHOST_SystemWin32::createOffscreenContextD3D()
+GHOST_ContextD3D *GHOST_SystemWin32::createOffscreenContextD3D()
{
- GHOST_Context *context;
+ GHOST_ContextD3D *context;
HWND wnd = CreateWindowA("STATIC",
"Blender XR",
@@ -435,16 +456,11 @@ GHOST_IContext *GHOST_SystemWin32::createOffscreenContextD3D()
return context;
}
-GHOST_IContext *GHOST_SystemWin32::createOffscreenContext(GHOST_TDrawingContextType type)
+GHOST_TSuccess GHOST_SystemWin32::disposeContextD3D(GHOST_ContextD3D *context)
{
- switch (type) {
- case GHOST_kDrawingContextTypeOpenGL:
- return createOffscreenContext();
- case GHOST_kDrawingContextTypeD3D:
- return createOffscreenContextD3D();
- default:
- return NULL;
- }
+ delete context;
+
+ return GHOST_kSuccess;
}
bool GHOST_SystemWin32::processEvents(bool waitForEvent)
@@ -575,6 +591,7 @@ GHOST_TSuccess GHOST_SystemWin32::init()
FreeLibrary(user32);
initRawInput();
+ m_lfstart = ::GetTickCount();
// Determine whether this system has a high frequency performance counter. */
m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER *)&m_freq) == TRUE;
if (m_hasPerformanceCounter) {
@@ -620,8 +637,12 @@ GHOST_TSuccess GHOST_SystemWin32::exit()
return GHOST_System::exit();
}
-GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, int *keyDown, char *vk)
+GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw,
+ bool *r_keyDown,
+ bool *r_is_repeated_modifier)
{
+ bool is_repeated_modifier = false;
+
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
GHOST_TKey key = GHOST_kKeyUnknown;
GHOST_ModifierKeys modifiers;
@@ -630,7 +651,7 @@ GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, int *keyDown, char *v
// 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;
- *keyDown = !(raw.data.keyboard.Flags & RI_KEY_BREAK) && msg != WM_KEYUP && msg != WM_SYSKEYUP;
+ *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,
@@ -642,32 +663,32 @@ GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, int *keyDown, char *v
GHOST_TModifierKeyMask modifier;
switch (key) {
case GHOST_kKeyLeftShift: {
- changed = (modifiers.get(GHOST_kModifierKeyLeftShift) != (bool)*keyDown);
+ changed = (modifiers.get(GHOST_kModifierKeyLeftShift) != *r_keyDown);
modifier = GHOST_kModifierKeyLeftShift;
break;
}
case GHOST_kKeyRightShift: {
- changed = (modifiers.get(GHOST_kModifierKeyRightShift) != (bool)*keyDown);
+ changed = (modifiers.get(GHOST_kModifierKeyRightShift) != *r_keyDown);
modifier = GHOST_kModifierKeyRightShift;
break;
}
case GHOST_kKeyLeftControl: {
- changed = (modifiers.get(GHOST_kModifierKeyLeftControl) != (bool)*keyDown);
+ changed = (modifiers.get(GHOST_kModifierKeyLeftControl) != *r_keyDown);
modifier = GHOST_kModifierKeyLeftControl;
break;
}
case GHOST_kKeyRightControl: {
- changed = (modifiers.get(GHOST_kModifierKeyRightControl) != (bool)*keyDown);
+ changed = (modifiers.get(GHOST_kModifierKeyRightControl) != *r_keyDown);
modifier = GHOST_kModifierKeyRightControl;
break;
}
case GHOST_kKeyLeftAlt: {
- changed = (modifiers.get(GHOST_kModifierKeyLeftAlt) != (bool)*keyDown);
+ changed = (modifiers.get(GHOST_kModifierKeyLeftAlt) != *r_keyDown);
modifier = GHOST_kModifierKeyLeftAlt;
break;
}
case GHOST_kKeyRightAlt: {
- changed = (modifiers.get(GHOST_kModifierKeyRightAlt) != (bool)*keyDown);
+ changed = (modifiers.get(GHOST_kModifierKeyRightAlt) != *r_keyDown);
modifier = GHOST_kModifierKeyRightAlt;
break;
}
@@ -676,17 +697,15 @@ GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, int *keyDown, char *v
}
if (changed) {
- modifiers.set(modifier, (bool)*keyDown);
+ modifiers.set(modifier, *r_keyDown);
system->storeModifierKeys(modifiers);
}
else {
- key = GHOST_kKeyUnknown;
+ is_repeated_modifier = true;
}
}
- if (vk)
- *vk = raw.data.keyboard.VKey;
-
+ *r_is_repeated_modifier = is_repeated_modifier;
return key;
}
@@ -911,73 +930,122 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type,
GHOST_TButtonMask mask)
{
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
- if (window->useTabletAPI(GHOST_kTabletNative)) {
- window->setTabletData(NULL);
+
+ if (type == GHOST_kEventButtonDown) {
+ window->updateMouseCapture(MousePressed);
+ }
+ else if (type == GHOST_kEventButtonUp) {
+ window->updateMouseCapture(MouseReleased);
+ }
+
+ if (window->m_tabletInRange) {
+ if (window->useTabletAPI(GHOST_kTabletNative)) {
+ // Win32 Pointer processing handles input while in-range and in-contact events.
+ return NULL;
+ }
}
- return new GHOST_EventButton(system->getMilliSeconds(), type, window, mask);
+
+ return new GHOST_EventButton(
+ system->getMilliSeconds(), type, window, mask, window->getTabletData());
}
-GHOST_Event *GHOST_SystemWin32::processPointerEvent(GHOST_TEventType type,
- GHOST_WindowWin32 *window,
- WPARAM wParam,
- LPARAM lParam,
- bool &eventHandled)
+void GHOST_SystemWin32::processPointerEvents(
+ UINT type, GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam, bool &eventHandled)
{
- GHOST_PointerInfoWin32 pointerInfo;
+ std::vector<GHOST_PointerInfoWin32> pointerInfo;
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
if (!window->useTabletAPI(GHOST_kTabletNative)) {
- return NULL;
+ return;
}
- if (window->getPointerInfo(&pointerInfo, wParam, lParam) != GHOST_kSuccess) {
- return NULL;
+ if (window->getPointerInfo(pointerInfo, wParam, lParam) != GHOST_kSuccess) {
+ return;
}
- if (!pointerInfo.isPrimary) {
+ if (!pointerInfo[0].isPrimary) {
eventHandled = true;
- return NULL; // For multi-touch displays we ignore these events
+ return; // For multi-touch displays we ignore these events
}
- system->setCursorPosition(pointerInfo.pixelLocation.x, pointerInfo.pixelLocation.y);
-
switch (type) {
- case GHOST_kEventButtonDown:
- /* Update window tablet data to be included in event. */
- window->setTabletData(&pointerInfo.tabletData);
- eventHandled = true;
- return new GHOST_EventButton(
- system->getMilliSeconds(), GHOST_kEventButtonDown, window, pointerInfo.buttonMask);
- case GHOST_kEventButtonUp:
- eventHandled = true;
- return new GHOST_EventButton(
- system->getMilliSeconds(), GHOST_kEventButtonUp, window, pointerInfo.buttonMask);
- case GHOST_kEventCursorMove:
- /* Update window tablet data to be included in event. */
- window->setTabletData(&pointerInfo.tabletData);
- eventHandled = true;
- return new GHOST_EventCursor(system->getMilliSeconds(),
- GHOST_kEventCursorMove,
- window,
- pointerInfo.pixelLocation.x,
- pointerInfo.pixelLocation.y);
+ case WM_POINTERENTER:
+ window->m_tabletInRange = true;
+ system->pushEvent(new GHOST_EventCursor(pointerInfo[0].time,
+ GHOST_kEventCursorMove,
+ window,
+ pointerInfo[0].pixelLocation.x,
+ pointerInfo[0].pixelLocation.y,
+ pointerInfo[0].tabletData));
+ break;
+ 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,
+ window,
+ pointerInfo[0].pixelLocation.x,
+ pointerInfo[0].pixelLocation.y,
+ pointerInfo[0].tabletData));
+ system->pushEvent(new GHOST_EventButton(pointerInfo[0].time,
+ GHOST_kEventButtonDown,
+ window,
+ pointerInfo[0].buttonMask,
+ pointerInfo[0].tabletData));
+ window->updateMouseCapture(MousePressed);
+ break;
+ case WM_POINTERUPDATE:
+ // Coalesced pointer events are reverse chronological order, reorder chronologically.
+ // Only contiguous move events are coalesced.
+ for (GHOST_TUns32 i = pointerInfo.size(); i-- > 0;) {
+ system->pushEvent(new GHOST_EventCursor(pointerInfo[i].time,
+ GHOST_kEventCursorMove,
+ window,
+ pointerInfo[i].pixelLocation.x,
+ pointerInfo[i].pixelLocation.y,
+ pointerInfo[i].tabletData));
+ }
+ break;
+ case WM_POINTERUP:
+ system->pushEvent(new GHOST_EventButton(pointerInfo[0].time,
+ GHOST_kEventButtonUp,
+ window,
+ pointerInfo[0].buttonMask,
+ pointerInfo[0].tabletData));
+ window->updateMouseCapture(MouseReleased);
+ break;
+ case WM_POINTERLEAVE:
+ window->m_tabletInRange = false;
+ system->pushEvent(new GHOST_EventButton(pointerInfo[0].time,
+ GHOST_kEventCursorMove,
+ window,
+ pointerInfo[0].buttonMask,
+ pointerInfo[0].tabletData));
+ break;
default:
- return NULL;
+ break;
}
+
+ eventHandled = true;
+ system->setCursorPosition(pointerInfo[0].pixelLocation.x, pointerInfo[0].pixelLocation.y);
}
-GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type,
- GHOST_WindowWin32 *window)
+GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window)
{
GHOST_TInt32 x_screen, y_screen;
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
- system->getCursorPosition(x_screen, y_screen);
+ if (window->m_tabletInRange) {
+ if (window->useTabletAPI(GHOST_kTabletNative)) {
+ // Tablet input handled in WM_POINTER* events. WM_MOUSEMOVE events in response to tablet
+ // input aren't normally generated when using WM_POINTER events, but manually moving the
+ // system cursor as we do in WM_POINTER handling does.
+ return NULL;
+ }
+ }
- /* TODO: CHECK IF THIS IS A TABLET EVENT */
- bool is_tablet = false;
+ system->getCursorPosition(x_screen, y_screen);
- if (is_tablet == false && window->getCursorGrabModeIsWarp()) {
+ if (window->getCursorGrabModeIsWarp() && !window->m_tabletInRange) {
GHOST_TInt32 x_new = x_screen;
GHOST_TInt32 y_new = y_screen;
GHOST_TInt32 x_accum, y_accum;
@@ -1004,12 +1072,17 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type,
GHOST_kEventCursorMove,
window,
x_screen + x_accum,
- y_screen + y_accum);
+ y_screen + y_accum,
+ window->getTabletData());
}
}
else {
- return new GHOST_EventCursor(
- system->getMilliSeconds(), GHOST_kEventCursorMove, window, x_screen, y_screen);
+ return new GHOST_EventCursor(system->getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ window,
+ x_screen,
+ y_screen,
+ window->getTabletData());
}
return NULL;
}
@@ -1038,16 +1111,17 @@ void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wPar
GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RAWINPUT const &raw)
{
- int keyDown = 0;
- char vk;
+ bool keyDown = false;
+ bool is_repeated_modifier = false;
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
- GHOST_TKey key = system->hardKey(raw, &keyDown, &vk);
+ GHOST_TKey key = system->hardKey(raw, &keyDown, &is_repeated_modifier);
GHOST_EventKey *event;
/* 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;
@@ -1105,6 +1179,10 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
// GHOST_PRINTF("%c\n", ascii); // we already get this info via EventPrinter
}
+ else {
+ event = NULL;
+ }
+
return event;
}
@@ -1390,40 +1468,26 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
////////////////////////////////////////////////////////////////////////
// Pointer events, processed
////////////////////////////////////////////////////////////////////////
+ case WM_POINTERENTER:
case WM_POINTERDOWN:
- event = processPointerEvent(
- GHOST_kEventButtonDown, window, wParam, lParam, eventHandled);
- if (event && eventHandled) {
- window->registerMouseClickEvent(0);
- }
- break;
- case WM_POINTERUP:
- event = processPointerEvent(GHOST_kEventButtonUp, window, wParam, lParam, eventHandled);
- if (event && eventHandled) {
- window->registerMouseClickEvent(1);
- }
- break;
case WM_POINTERUPDATE:
- event = processPointerEvent(
- GHOST_kEventCursorMove, window, wParam, lParam, eventHandled);
+ case WM_POINTERUP:
+ case WM_POINTERLEAVE:
+ processPointerEvents(msg, window, wParam, lParam, eventHandled);
break;
////////////////////////////////////////////////////////////////////////
// Mouse events, processed
////////////////////////////////////////////////////////////////////////
case WM_LBUTTONDOWN:
- window->registerMouseClickEvent(0);
event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft);
break;
case WM_MBUTTONDOWN:
- window->registerMouseClickEvent(0);
event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle);
break;
case WM_RBUTTONDOWN:
- window->registerMouseClickEvent(0);
event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight);
break;
case WM_XBUTTONDOWN:
- window->registerMouseClickEvent(0);
if ((short)HIWORD(wParam) == XBUTTON1) {
event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton4);
}
@@ -1432,19 +1496,15 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
}
break;
case WM_LBUTTONUP:
- window->registerMouseClickEvent(1);
event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft);
break;
case WM_MBUTTONUP:
- window->registerMouseClickEvent(1);
event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle);
break;
case WM_RBUTTONUP:
- window->registerMouseClickEvent(1);
event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight);
break;
case WM_XBUTTONUP:
- window->registerMouseClickEvent(1);
if ((short)HIWORD(wParam) == XBUTTON1) {
event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4);
}
@@ -1453,7 +1513,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
}
break;
case WM_MOUSEMOVE:
- event = processCursorEvent(GHOST_kEventCursorMove, window);
+ event = processCursorEvent(window);
break;
case WM_MOUSEWHEEL: {
/* The WM_MOUSEWHEEL message is sent to the focus window
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index e624cc83427..6b7901c2ade 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -42,6 +42,7 @@ class GHOST_EventWheel;
class GHOST_EventWindow;
class GHOST_EventDragnDrop;
+class GHOST_ContextD3D;
class GHOST_WindowWin32;
/**
@@ -65,6 +66,20 @@ class GHOST_SystemWin32 : public GHOST_System {
***************************************************************************************/
/**
+ * This method converts performance counter measurements into milliseconds since the start of the
+ * system process.
+ * \return The number of milliseconds since the start of the system process.
+ */
+ GHOST_TUns64 performanceCounterToMillis(__int64 perf_ticks) const;
+
+ /**
+ * This method converts system ticks into milliseconds since the start of the
+ * system process.
+ * \return The number of milliseconds since the start of the system process.
+ */
+ GHOST_TUns64 tickCountToMillis(__int64 ticks) const;
+
+ /**
* Returns the system time.
* Returns the number of milliseconds since the start of the system process.
* This overloaded method uses the high frequency timer if available.
@@ -111,7 +126,7 @@ class GHOST_SystemWin32 : public GHOST_System {
* \param parentWindow Parent window
* \return The new window (or 0 if creation failed).
*/
- GHOST_IWindow *createWindow(const STR_String &title,
+ GHOST_IWindow *createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -131,18 +146,28 @@ class GHOST_SystemWin32 : public GHOST_System {
GHOST_IContext *createOffscreenContext();
/**
- * Create a new offscreen context.
- * Never explicitly delete the window, use disposeContext() instead.
+ * Dispose of a context.
+ * \param context Pointer to the context to be disposed.
+ * \return Indication of success.
+ */
+ GHOST_TSuccess disposeContext(GHOST_IContext *context);
+
+ /**
+ * Create a new offscreen DirectX context.
+ * Never explicitly delete the context, use disposeContext() instead.
+ * This is for GHOST internal, Win32 specific use, so it can be called statically.
+ *
* \return The new context (or 0 if creation failed).
*/
- GHOST_IContext *createOffscreenContext(GHOST_TDrawingContextType type);
+ static GHOST_ContextD3D *createOffscreenContextD3D();
/**
- * Dispose of a context.
+ * Dispose of a DirectX context.
+ * This is for GHOST internal, Win32 specific use, so it can be called statically.
* \param context Pointer to the context to be disposed.
* \return Indication of success.
*/
- GHOST_TSuccess disposeContext(GHOST_IContext *context);
+ static GHOST_TSuccess disposeContextD3D(GHOST_ContextD3D *context);
/***************************************************************************************
** Event management functionality
@@ -187,7 +212,7 @@ class GHOST_SystemWin32 : public GHOST_System {
GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const;
/**
- * Returns the state of the mouse buttons (ouside the message queue).
+ * Returns the state of the mouse buttons (outside the message queue).
* \param buttons The state of the buttons.
* \return Indication of success.
*/
@@ -256,13 +281,6 @@ class GHOST_SystemWin32 : public GHOST_System {
GHOST_TSuccess exit();
/**
- * Create a new offscreen DirectX context.
- * Never explicitly delete the window, use disposeContext() instead.
- * \return The new context (or 0 if creation failed).
- */
- GHOST_IContext *createOffscreenContextD3D();
-
- /**
* Converts raw WIN32 key codes from the wndproc to GHOST keys.
* \param vKey The virtual key from hardKey
* \param ScanCode The ScanCode of pressed key (similar to PS/2 Set 1)
@@ -278,7 +296,7 @@ class GHOST_SystemWin32 : public GHOST_System {
* \param vk Pointer to virtual key
* \return The GHOST key (GHOST_kKeyUnknown if no match).
*/
- GHOST_TKey hardKey(RAWINPUT const &raw, int *keyDown, char *vk);
+ GHOST_TKey hardKey(RAWINPUT const &raw, bool *r_keyDown, bool *r_is_repeated_modifier);
/**
* Creates mouse button event.
@@ -292,27 +310,29 @@ class GHOST_SystemWin32 : public GHOST_System {
GHOST_TButtonMask mask);
/**
- * Creates pointer event.
- * \param type The type of event to create.
+ * Creates tablet events from Wintab events.
+ * \param type The type of pointer event
+ * \param window The window receiving the event (the active window).
+ */
+ static GHOST_TSuccess processWintabEvents(GHOST_TEventType type, GHOST_WindowWin32 *window);
+
+ /**
+ * Creates tablet events from pointer events.
+ * \param type The type of pointer event
* \param window The window receiving the event (the active window).
* \param wParam The wParam from the wndproc
* \param lParam The lParam from the wndproc
* \param eventhandled true if the method handled the event
- * \return The event created.
*/
- static GHOST_Event *processPointerEvent(GHOST_TEventType type,
- GHOST_WindowWin32 *window,
- WPARAM wParam,
- LPARAM lParam,
- bool &eventhandled);
+ static void processPointerEvents(
+ UINT type, GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam, bool &eventhandled);
/**
* Creates cursor event.
- * \param type The type of event to create.
* \param window The window receiving the event (the active window).
* \return The event created.
*/
- static GHOST_EventCursor *processCursorEvent(GHOST_TEventType type, GHOST_WindowWin32 *window);
+ static GHOST_EventCursor *processCursorEvent(GHOST_WindowWin32 *window);
/**
* Handles a mouse wheel event.
@@ -422,6 +442,8 @@ class GHOST_SystemWin32 : public GHOST_System {
__int64 m_freq;
/** High frequency timer variable. */
__int64 m_start;
+ /** Low frequency timer variable. */
+ __int64 m_lfstart;
/** AltGr on current keyboard layout. */
bool m_hasAltGr;
/** language identifier. */
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index a9d656a1c36..5c1f34e3a63 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -338,7 +338,7 @@ void GHOST_SystemX11::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32
* \param parentWindow Parent window
* \return The new window (or 0 if creation failed).
*/
-GHOST_IWindow *GHOST_SystemX11::createWindow(const STR_String &title,
+GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -910,8 +910,8 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
for (; win_it != win_end; ++win_it) {
- GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it);
- window->refreshXInputDevices();
+ GHOST_WindowX11 *window_xinput = static_cast<GHOST_WindowX11 *>(*win_it);
+ window_xinput->refreshXInputDevices();
}
}
}
@@ -960,11 +960,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
case MotionNotify: {
XMotionEvent &xme = xe->xmotion;
-#ifdef WITH_X11_XINPUT
bool is_tablet = window->GetTabletData().Active != GHOST_kTabletModeNone;
-#else
- bool is_tablet = false;
-#endif
if (is_tablet == false && window->getCursorGrabModeIsWarp()) {
GHOST_TInt32 x_new = xme.x_root;
@@ -1000,12 +996,17 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
GHOST_kEventCursorMove,
window,
xme.x_root + x_accum,
- xme.y_root + y_accum);
+ xme.y_root + y_accum,
+ window->GetTabletData());
}
}
else {
- g_event = new GHOST_EventCursor(
- getMilliSeconds(), GHOST_kEventCursorMove, window, xme.x_root, xme.y_root);
+ g_event = new GHOST_EventCursor(getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ window,
+ xme.x_root,
+ xme.y_root,
+ window->GetTabletData());
}
break;
}
@@ -1272,7 +1273,8 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
else
break;
- g_event = new GHOST_EventButton(getMilliSeconds(), type, window, gbmask);
+ g_event = new GHOST_EventButton(
+ getMilliSeconds(), type, window, gbmask, window->GetTabletData());
break;
}
@@ -1373,8 +1375,12 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
*/
XCrossingEvent &xce = xe->xcrossing;
if (xce.mode == NotifyNormal) {
- g_event = new GHOST_EventCursor(
- getMilliSeconds(), GHOST_kEventCursorMove, window, xce.x_root, xce.y_root);
+ g_event = new GHOST_EventCursor(getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ window,
+ xce.x_root,
+ xce.y_root,
+ window->GetTabletData());
}
// printf("X: %s window %d\n",
@@ -1563,7 +1569,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
GHOST_TSuccess GHOST_SystemX11::getModifierKeys(GHOST_ModifierKeys &keys) const
{
- /* Analyze the masks retuned from XQueryPointer. */
+ /* Analyze the masks returned from XQueryPointer. */
memset((void *)m_keyboard_vector, 0, sizeof(m_keyboard_vector));
@@ -1875,7 +1881,7 @@ static GHOST_TKey ghost_key_from_keysym(const KeySym key)
# endif
#endif
default:
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
printf("%s: unknown key: %lu / 0x%lx\n", __func__, key, key);
#endif
type = GHOST_kKeyUnknown;
@@ -1899,7 +1905,7 @@ static GHOST_TKey ghost_key_from_keycode(const XkbDescPtr xkb_descr, const KeyCo
switch (id) {
case MAKE_ID('T', 'L', 'D', 'E'):
return GHOST_kKeyAccentGrave;
-#ifdef GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
default:
printf("%s unhandled keycode: %.*s\n", __func__, XkbKeyNameLength, id_str);
break;
@@ -2166,14 +2172,24 @@ GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const
else if (owner == None)
return (NULL);
+ /* Restore events so copy doesn't swallow other event types (keyboard/mouse). */
+ vector<XEvent> restore_events;
+
while (1) {
/* only get an event if xcout() is doing something */
- if (context != XCLIB_XCOUT_NONE)
+ bool restore_this_event = false;
+ if (context != XCLIB_XCOUT_NONE) {
XNextEvent(m_display, &evt);
+ restore_this_event = (evt.type != SelectionNotify);
+ }
/* fetch the selection, or part of it */
getClipboard_xcout(&evt, sseln, target, &sel_buf, &sel_len, &context);
+ if (restore_this_event) {
+ restore_events.push_back(evt);
+ }
+
/* fallback is needed. set XA_STRING to target and restart the loop. */
if (context == XCLIB_XCOUT_FALLBACK) {
context = XCLIB_XCOUT_NONE;
@@ -2202,6 +2218,11 @@ GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const
break;
}
+ while (!restore_events.empty()) {
+ XPutBackEvent(m_display, &restore_events.back());
+ restore_events.pop_back();
+ }
+
if (sel_len) {
/* only print the buffer out, and free it, if it's not
* empty
@@ -2450,7 +2471,7 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title,
string cmd = "xdg-open \"" + string(link) + "\"";
if (system(cmd.c_str()) != 0) {
GHOST_PRINTF("GHOST_SystemX11::showMessageBox: Unable to run system command [%s]",
- cmd);
+ cmd.c_str());
}
}
break;
diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index d0e0506e77b..5888605ec95 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -137,7 +137,7 @@ class GHOST_SystemX11 : public GHOST_System {
* \param parentWindow Parent (embedder) window
* \return The new window (or 0 if creation failed).
*/
- GHOST_IWindow *createWindow(const STR_String &title,
+ GHOST_IWindow *createWindow(const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -182,7 +182,7 @@ class GHOST_SystemX11 : public GHOST_System {
GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const;
/**
- * Returns the state of the mouse buttons (ouside the message queue).
+ * Returns the state of the mouse buttons (outside the message queue).
* \param buttons The state of the buttons.
* \return Indication of success.
*/
@@ -211,7 +211,7 @@ class GHOST_SystemX11 : public GHOST_System {
}
#endif
- /* Helped function for get data from the clipboard. */
+ /** Helped function for get data from the clipboard. */
void getClipboard_xcout(const XEvent *evt,
Atom sel,
Atom target,
@@ -337,7 +337,7 @@ class GHOST_SystemX11 : public GHOST_System {
private:
Display *m_display;
- /* Use for scancode lookups. */
+ /** Use for scan-code look-ups. */
XkbDescRec *m_xkb_descr;
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
@@ -349,20 +349,22 @@ class GHOST_SystemX11 : public GHOST_System {
std::vector<GHOST_TabletX11> m_xtablets;
#endif
- /// The vector of windows that need to be updated.
+ /** The vector of windows that need to be updated. */
std::vector<GHOST_WindowX11 *> m_dirty_windows;
- /// Start time at initialization.
+ /** Start time at initialization. */
GHOST_TUns64 m_start_time;
- /// A vector of keyboard key masks
+ /** A vector of keyboard key masks. */
char m_keyboard_vector[32];
- /* to prevent multiple warp, we store the time of the last warp event
- * and stop accumulating all events generated before that */
+ /**
+ * To prevent multiple warp, we store the time of the last warp event
+ * and stop accumulating all events generated before that.
+ */
Time m_last_warp;
- /* detect autorepeat glitch */
+ /* Detect auto-repeat glitch. */
unsigned int m_last_release_keycode;
Time m_last_release_time;
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index 553a7d89df4..472149148e6 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -27,7 +27,6 @@
#include "GHOST_IWindow.h"
-class STR_String;
class GHOST_Context;
/**
@@ -61,8 +60,8 @@ class GHOST_Window : public GHOST_IWindow {
* \section Interface inherited from GHOST_IWindow left for derived class
* implementation.
* virtual bool getValid() const = 0;
- * virtual void setTitle(const STR_String& title) = 0;
- * virtual void getTitle(STR_String& title) const = 0;
+ * virtual void setTitle(const char * title) = 0;
+ * virtual std::string getTitle() const = 0;
* virtual void getWindowBounds(GHOST_Rect& bounds) const = 0;
* virtual void getClientBounds(GHOST_Rect& bounds) const = 0;
* virtual GHOST_TSuccess setClientWidth(GHOST_TUns32 width) = 0;
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h
index a49949c2c8d..15429eab5db 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowCocoa.h
@@ -30,7 +30,6 @@
#endif // __APPLE__
#include "GHOST_Window.h"
-#include "STR_String.h"
@class CAMetalLayer;
@class CocoaMetalView;
@@ -58,7 +57,7 @@ class GHOST_WindowCocoa : public GHOST_Window {
* \param stereoVisual Stereo visual for quad buffered stereo.
*/
GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 bottom,
GHOST_TUns32 width,
@@ -92,13 +91,12 @@ class GHOST_WindowCocoa : public GHOST_Window {
* Sets the title displayed in the title bar.
* \param title The title to display in the title bar.
*/
- void setTitle(const STR_String &title);
-
+ void setTitle(const char *title);
/**
* Returns the title displayed in the title bar.
* \param title The title displayed in the title bar.
*/
- void getTitle(STR_String &title) const;
+ std::string getTitle() const;
/**
* Returns the window rectangle dimensions.
@@ -222,11 +220,6 @@ class GHOST_WindowCocoa : public GHOST_Window {
bool isDialog() const;
- const GHOST_TabletData &GetTabletData()
- {
- return m_tablet;
- }
-
GHOST_TabletData &GetCocoaTabletData()
{
return m_tablet;
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index c90b49c27a5..05adc41cb8e 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -291,7 +291,7 @@
/* clang-format on */
GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 bottom,
GHOST_TUns32 width,
@@ -395,7 +395,7 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
setTitle(title);
- m_tablet = GHOST_TABLET_DATA_DEFAULT;
+ m_tablet = GHOST_TABLET_DATA_NONE;
CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init];
[windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
@@ -482,7 +482,7 @@ void *GHOST_WindowCocoa::getOSWindow() const
return (void *)m_window;
}
-void GHOST_WindowCocoa::setTitle(const STR_String &title)
+void GHOST_WindowCocoa::setTitle(const char *title)
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setTitle(): window invalid");
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@@ -524,7 +524,7 @@ void GHOST_WindowCocoa::setTitle(const STR_String &title)
[pool drain];
}
-void GHOST_WindowCocoa::getTitle(STR_String &title) const
+std::string GHOST_WindowCocoa::getTitle() const
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getTitle(): window invalid");
@@ -532,11 +532,14 @@ void GHOST_WindowCocoa::getTitle(STR_String &title) const
NSString *windowTitle = [m_window title];
+ std::string title;
if (windowTitle != nil) {
title = [windowTitle UTF8String];
}
[pool drain];
+
+ return title;
}
void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect &bounds) const
diff --git a/intern/ghost/intern/GHOST_WindowNULL.h b/intern/ghost/intern/GHOST_WindowNULL.h
index db40075e6ca..e1aa0cb7f13 100644
--- a/intern/ghost/intern/GHOST_WindowNULL.h
+++ b/intern/ghost/intern/GHOST_WindowNULL.h
@@ -26,7 +26,6 @@
#include <map>
-class STR_String;
class GHOST_SystemNULL;
class GHOST_WindowNULL : public GHOST_Window {
@@ -37,7 +36,7 @@ class GHOST_WindowNULL : public GHOST_Window {
}
GHOST_WindowNULL(GHOST_SystemNULL *system,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -83,12 +82,12 @@ class GHOST_WindowNULL : public GHOST_Window {
{
return true;
}
- void setTitle(const STR_String &title)
+ void setTitle(const char *title)
{ /* nothing */
}
- void getTitle(STR_String &title) const
+ std::string getTitle() const
{
- title = "untitled";
+ return "untitled";
}
void getWindowBounds(GHOST_Rect &bounds) const
{
diff --git a/intern/ghost/intern/GHOST_WindowSDL.cpp b/intern/ghost/intern/GHOST_WindowSDL.cpp
index e8d129f45fe..dcb1ab8c78c 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.cpp
+++ b/intern/ghost/intern/GHOST_WindowSDL.cpp
@@ -27,7 +27,7 @@
#include <assert.h>
GHOST_WindowSDL::GHOST_WindowSDL(GHOST_SystemSDL *system,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -148,14 +148,14 @@ bool GHOST_WindowSDL::getValid() const
return GHOST_Window::getValid() && m_valid_setup;
}
-void GHOST_WindowSDL::setTitle(const STR_String &title)
+void GHOST_WindowSDL::setTitle(const char *title)
{
- SDL_SetWindowTitle(m_sdl_win, title.ReadPtr());
+ SDL_SetWindowTitle(m_sdl_win, title);
}
-void GHOST_WindowSDL::getTitle(STR_String &title) const
+std::string GHOST_WindowSDL::getTitle() const
{
- title = SDL_GetWindowTitle(m_sdl_win);
+ return SDL_GetWindowTitle(m_sdl_win);
}
void GHOST_WindowSDL::getWindowBounds(GHOST_Rect &bounds) const
diff --git a/intern/ghost/intern/GHOST_WindowSDL.h b/intern/ghost/intern/GHOST_WindowSDL.h
index eadd1b7df9d..5039c742c9d 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.h
+++ b/intern/ghost/intern/GHOST_WindowSDL.h
@@ -35,7 +35,6 @@ extern "C" {
# error "SDL 2.0 or newer is needed to build with Ghost"
#endif
-class STR_String;
class GHOST_SystemSDL;
class GHOST_WindowSDL : public GHOST_Window {
@@ -49,7 +48,7 @@ class GHOST_WindowSDL : public GHOST_Window {
public:
GHOST_WindowSDL(GHOST_SystemSDL *system,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -107,9 +106,9 @@ class GHOST_WindowSDL : public GHOST_Window {
GHOST_TSuccess setWindowCursorVisibility(bool visible);
- void setTitle(const STR_String &title);
+ void setTitle(const char *title);
- void getTitle(STR_String &title) const;
+ std::string getTitle() const;
GHOST_TSuccess setClientWidth(GHOST_TUns32 width);
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
new file mode 100644
index 00000000000..ef02db7abc3
--- /dev/null
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -0,0 +1,415 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup GHOST
+ */
+
+#include "GHOST_WindowWayland.h"
+#include "GHOST_SystemWayland.h"
+#include "GHOST_WindowManager.h"
+
+#include "GHOST_Event.h"
+
+#include "GHOST_ContextEGL.h"
+#include "GHOST_ContextNone.h"
+
+#include <wayland-egl.h>
+
+struct window_t {
+ GHOST_WindowWayland *w;
+ wl_surface *surface;
+ struct xdg_surface *xdg_surface;
+ struct xdg_toplevel *xdg_toplevel;
+ wl_egl_window *egl_window;
+ int32_t pending_width, pending_height;
+ bool is_maximised;
+ bool is_fullscreen;
+ bool is_active;
+ bool is_dialog;
+ int32_t width, height;
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Wayland Interface Callbacks
+ *
+ * These callbacks are registered for Wayland interfaces and called when
+ * an event is received from the compositor.
+ * \{ */
+
+static void toplevel_configure(
+ void *data, xdg_toplevel * /*xdg_toplevel*/, int32_t width, int32_t height, wl_array *states)
+{
+ window_t *win = static_cast<window_t *>(data);
+ win->pending_width = width;
+ win->pending_height = height;
+
+ win->is_maximised = false;
+ win->is_fullscreen = false;
+ win->is_active = false;
+
+ /* Note that the macro 'wl_array_for_each' would typically be used to simplify this logic,
+ * however it's not compatible with C++, so perform casts instead.
+ * If this needs to be done more often we could define our own C++ compatible macro. */
+ for (enum xdg_toplevel_state *state = static_cast<xdg_toplevel_state *>(states->data);
+ reinterpret_cast<uint8_t *>(state) < (static_cast<uint8_t *>(states->data) + states->size);
+ state++) {
+ switch (*state) {
+ case XDG_TOPLEVEL_STATE_MAXIMIZED:
+ win->is_maximised = true;
+ break;
+ case XDG_TOPLEVEL_STATE_FULLSCREEN:
+ win->is_fullscreen = true;
+ break;
+ case XDG_TOPLEVEL_STATE_ACTIVATED:
+ win->is_active = true;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void toplevel_close(void *data, xdg_toplevel * /*xdg_toplevel*/)
+{
+ static_cast<window_t *>(data)->w->close();
+}
+
+static const xdg_toplevel_listener toplevel_listener = {
+ toplevel_configure,
+ toplevel_close,
+};
+
+static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t serial)
+{
+ window_t *win = static_cast<window_t *>(data);
+
+ int w, h;
+ wl_egl_window_get_attached_size(win->egl_window, &w, &h);
+ if (win->pending_width != 0 && win->pending_height != 0 && win->pending_width != w &&
+ win->pending_height != h) {
+ win->width = win->pending_width;
+ win->height = win->pending_height;
+ wl_egl_window_resize(win->egl_window, win->pending_width, win->pending_height, 0, 0);
+ win->pending_width = 0;
+ win->pending_height = 0;
+ win->w->notify_size();
+ }
+
+ if (win->is_active) {
+ win->w->activate();
+ }
+ else {
+ win->w->deactivate();
+ }
+
+ xdg_surface_ack_configure(xdg_surface, serial);
+}
+
+static const xdg_surface_listener surface_listener = {
+ surface_configure,
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Ghost Implementation
+ *
+ * Wayland specific implementation of the GHOST_Window interface.
+ * \{ */
+
+GHOST_TSuccess GHOST_WindowWayland::hasCursorShape(GHOST_TStandardCursor cursorShape)
+{
+ return m_system->hasCursorShape(cursorShape);
+}
+
+GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
+ const char *title,
+ GHOST_TInt32 /*left*/,
+ GHOST_TInt32 /*top*/,
+ GHOST_TUns32 width,
+ GHOST_TUns32 height,
+ GHOST_TWindowState state,
+ const GHOST_IWindow *parentWindow,
+ GHOST_TDrawingContextType type,
+ const bool is_dialog,
+ const bool stereoVisual,
+ const bool exclusive)
+ : GHOST_Window(width, height, state, stereoVisual, exclusive),
+ m_system(system),
+ w(new window_t)
+{
+ w->w = this;
+
+ w->width = int32_t(width);
+ w->height = int32_t(height);
+
+ w->is_dialog = is_dialog;
+
+ /* Window surfaces. */
+ w->surface = wl_compositor_create_surface(m_system->compositor());
+ w->egl_window = wl_egl_window_create(w->surface, int(width), int(height));
+
+ w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->shell(), w->surface);
+ w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
+
+ wl_surface_set_user_data(w->surface, this);
+
+ xdg_surface_add_listener(w->xdg_surface, &surface_listener, w);
+ xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w);
+
+ if (parentWindow) {
+ xdg_toplevel_set_parent(
+ w->xdg_toplevel, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_toplevel);
+ }
+
+ /* Call top-level callbacks. */
+ wl_surface_commit(w->surface);
+ wl_display_roundtrip(m_system->display());
+
+ setState(state);
+
+ setTitle(title);
+
+ /* EGL context. */
+ if (setDrawingContextType(type) == GHOST_kFailure) {
+ GHOST_PRINT("Failed to create EGL context" << std::endl);
+ }
+}
+
+GHOST_TSuccess GHOST_WindowWayland::close()
+{
+ return m_system->pushEvent(
+ new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowClose, this));
+}
+
+GHOST_TSuccess GHOST_WindowWayland::activate()
+{
+ if (m_system->getWindowManager()->setActiveWindow(this) == GHOST_kFailure) {
+ return GHOST_kFailure;
+ }
+ return m_system->pushEvent(
+ new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowActivate, this));
+}
+
+GHOST_TSuccess GHOST_WindowWayland::deactivate()
+{
+ m_system->getWindowManager()->setWindowInactive(this);
+ return m_system->pushEvent(
+ new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowDeactivate, this));
+}
+
+GHOST_TSuccess GHOST_WindowWayland::notify_size()
+{
+ return m_system->pushEvent(
+ new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowSize, this));
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
+{
+ return m_system->setCursorGrab(mode, w->surface);
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setWindowCursorShape(GHOST_TStandardCursor shape)
+{
+ const GHOST_TSuccess ok = m_system->setCursorShape(shape);
+ m_cursorShape = (ok == GHOST_kSuccess) ? shape : GHOST_kStandardCursorDefault;
+ return ok;
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
+ GHOST_TUns8 *mask,
+ int sizex,
+ int sizey,
+ int hotX,
+ int hotY,
+ bool canInvertColor)
+{
+ return m_system->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor);
+}
+
+void GHOST_WindowWayland::setTitle(const char *title)
+{
+ xdg_toplevel_set_title(w->xdg_toplevel, title);
+ xdg_toplevel_set_app_id(w->xdg_toplevel, title);
+ this->title = title;
+}
+
+std::string GHOST_WindowWayland::getTitle() const
+{
+ return this->title.empty() ? "untitled" : this->title;
+}
+
+void GHOST_WindowWayland::getWindowBounds(GHOST_Rect &bounds) const
+{
+ getClientBounds(bounds);
+}
+
+void GHOST_WindowWayland::getClientBounds(GHOST_Rect &bounds) const
+{
+ bounds.set(0, 0, w->width, w->height);
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setClientWidth(GHOST_TUns32 width)
+{
+ return setClientSize(width, GHOST_TUns32(w->height));
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setClientHeight(GHOST_TUns32 height)
+{
+ return setClientSize(GHOST_TUns32(w->width), height);
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
+{
+ wl_egl_window_resize(w->egl_window, int(width), int(height), 0, 0);
+ return GHOST_kSuccess;
+}
+
+void GHOST_WindowWayland::screenToClient(GHOST_TInt32 inX,
+ GHOST_TInt32 inY,
+ GHOST_TInt32 &outX,
+ GHOST_TInt32 &outY) const
+{
+ outX = inX;
+ outY = inY;
+}
+
+void GHOST_WindowWayland::clientToScreen(GHOST_TInt32 inX,
+ GHOST_TInt32 inY,
+ GHOST_TInt32 &outX,
+ GHOST_TInt32 &outY) const
+{
+ outX = inX;
+ outY = inY;
+}
+
+GHOST_WindowWayland::~GHOST_WindowWayland()
+{
+ releaseNativeHandles();
+
+ wl_egl_window_destroy(w->egl_window);
+ xdg_toplevel_destroy(w->xdg_toplevel);
+ xdg_surface_destroy(w->xdg_surface);
+ wl_surface_destroy(w->surface);
+
+ delete w;
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setWindowCursorVisibility(bool visible)
+{
+ return m_system->setCursorVisibility(visible);
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setState(GHOST_TWindowState state)
+{
+ switch (state) {
+ case GHOST_kWindowStateNormal:
+ /* Unset states. */
+ switch (getState()) {
+ case GHOST_kWindowStateMaximized:
+ xdg_toplevel_unset_maximized(w->xdg_toplevel);
+ break;
+ case GHOST_kWindowStateFullScreen:
+ xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
+ break;
+ default:
+ break;
+ }
+ break;
+ case GHOST_kWindowStateMaximized:
+ xdg_toplevel_set_maximized(w->xdg_toplevel);
+ break;
+ case GHOST_kWindowStateMinimized:
+ xdg_toplevel_set_minimized(w->xdg_toplevel);
+ break;
+ case GHOST_kWindowStateFullScreen:
+ xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
+ break;
+ case GHOST_kWindowStateEmbedded:
+ return GHOST_kFailure;
+ }
+ return GHOST_kSuccess;
+}
+
+GHOST_TWindowState GHOST_WindowWayland::getState() const
+{
+ if (w->is_fullscreen) {
+ return GHOST_kWindowStateFullScreen;
+ }
+ else if (w->is_maximised) {
+ return GHOST_kWindowStateMaximized;
+ }
+ else {
+ return GHOST_kWindowStateNormal;
+ }
+}
+
+GHOST_TSuccess GHOST_WindowWayland::invalidate()
+{
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_WindowWayland::setOrder(GHOST_TWindowOrder /*order*/)
+{
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_WindowWayland::beginFullScreen() const
+{
+ xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_WindowWayland::endFullScreen() const
+{
+ xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
+ return GHOST_kSuccess;
+}
+
+bool GHOST_WindowWayland::isDialog() const
+{
+ return w->is_dialog;
+}
+
+/**
+ * \param type The type of rendering context create.
+ * \return Indication of success.
+ */
+GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType type)
+{
+ GHOST_Context *context;
+ switch (type) {
+ case GHOST_kDrawingContextTypeNone:
+ context = new GHOST_ContextNone(m_wantStereoVisual);
+ break;
+ case GHOST_kDrawingContextTypeOpenGL:
+ context = new GHOST_ContextEGL(m_wantStereoVisual,
+ EGLNativeWindowType(w->egl_window),
+ EGLNativeDisplayType(m_system->display()),
+ EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
+ 3,
+ 3,
+ GHOST_OPENGL_EGL_CONTEXT_FLAGS,
+ GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
+ EGL_OPENGL_API);
+ break;
+ }
+
+ return (context->initializeDrawingContext() == GHOST_kSuccess) ? context : nullptr;
+}
+
+/** \} */
diff --git a/intern/ghost/intern/GHOST_WindowWayland.h b/intern/ghost/intern/GHOST_WindowWayland.h
new file mode 100644
index 00000000000..23e55fcd6e4
--- /dev/null
+++ b/intern/ghost/intern/GHOST_WindowWayland.h
@@ -0,0 +1,124 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup GHOST
+ *
+ * Declaration of GHOST_WindowWayland class.
+ */
+
+#ifndef __GHOST_WINDOWWAYLAND_H__
+#define __GHOST_WINDOWWAYLAND_H__
+
+#include "GHOST_Window.h"
+
+class GHOST_SystemWayland;
+
+struct window_t;
+
+class GHOST_WindowWayland : public GHOST_Window {
+ public:
+ GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape) override;
+
+ GHOST_WindowWayland(GHOST_SystemWayland *system,
+ const char *title,
+ GHOST_TInt32 left,
+ GHOST_TInt32 top,
+ GHOST_TUns32 width,
+ GHOST_TUns32 height,
+ GHOST_TWindowState state,
+ const GHOST_IWindow *parentWindow,
+ GHOST_TDrawingContextType type,
+ const bool is_dialog,
+ const bool stereoVisual,
+ const bool exclusive);
+
+ ~GHOST_WindowWayland() override;
+
+ GHOST_TSuccess close();
+
+ GHOST_TSuccess activate();
+
+ GHOST_TSuccess deactivate();
+
+ GHOST_TSuccess notify_size();
+
+ protected:
+ GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) override;
+
+ GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) override;
+
+ GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
+ GHOST_TUns8 *mask,
+ int sizex,
+ int sizey,
+ int hotX,
+ int hotY,
+ bool canInvertColor) override;
+
+ void setTitle(const char *title) override;
+
+ std::string getTitle() const override;
+
+ void getWindowBounds(GHOST_Rect &bounds) const override;
+
+ void getClientBounds(GHOST_Rect &bounds) const override;
+
+ GHOST_TSuccess setClientWidth(GHOST_TUns32 width) override;
+
+ GHOST_TSuccess setClientHeight(GHOST_TUns32 height) override;
+
+ GHOST_TSuccess setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) override;
+
+ void screenToClient(GHOST_TInt32 inX,
+ GHOST_TInt32 inY,
+ GHOST_TInt32 &outX,
+ GHOST_TInt32 &outY) const override;
+
+ void clientToScreen(GHOST_TInt32 inX,
+ GHOST_TInt32 inY,
+ GHOST_TInt32 &outX,
+ GHOST_TInt32 &outY) const override;
+
+ GHOST_TSuccess setWindowCursorVisibility(bool visible) override;
+
+ GHOST_TSuccess setState(GHOST_TWindowState state) override;
+
+ GHOST_TWindowState getState() const override;
+
+ GHOST_TSuccess invalidate() override;
+
+ GHOST_TSuccess setOrder(GHOST_TWindowOrder order) override;
+
+ GHOST_TSuccess beginFullScreen() const override;
+
+ GHOST_TSuccess endFullScreen() const override;
+
+ bool isDialog() const override;
+
+ private:
+ GHOST_SystemWayland *m_system;
+ struct window_t *w;
+ std::string title;
+
+ /**
+ * \param type The type of rendering context create.
+ * \return Indication of success.
+ */
+ GHOST_Context *newDrawingContext(GHOST_TDrawingContextType type) override;
+};
+
+#endif // __GHOST_WINDOWWAYLAND_H__
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 6570f27ac5a..55525157753 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -59,7 +59,7 @@ __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
}
GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -72,6 +72,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
bool is_debug,
bool dialog)
: GHOST_Window(width, height, state, wantStereoVisual, false),
+ m_tabletInRange(false),
m_inLiveResize(false),
m_system(system),
m_hDC(0),
@@ -82,15 +83,15 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
m_wantAlphaBackground(alphaBackground),
m_normal_state(GHOST_kWindowStateNormal),
m_user32(NULL),
- m_fpGetPointerInfo(NULL),
- m_fpGetPointerPenInfo(NULL),
- m_fpGetPointerTouchInfo(NULL),
+ m_fpGetPointerInfoHistory(NULL),
+ m_fpGetPointerPenInfoHistory(NULL),
+ m_fpGetPointerTouchInfoHistory(NULL),
m_parentWindowHwnd(parentwindow ? parentwindow->m_hWnd : NULL),
m_debug_context(is_debug)
{
// Initialize tablet variables
memset(&m_wintab, 0, sizeof(m_wintab));
- m_tabletData = GHOST_TABLET_DATA_DEFAULT;
+ m_tabletData = GHOST_TABLET_DATA_NONE;
// Create window
if (state != GHOST_kWindowStateFullScreen) {
@@ -157,7 +158,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
height = rect.bottom - rect.top;
}
- wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
+ wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
m_hWnd = ::CreateWindowW(s_windowClassName, // pointer to registered class name
title_16, // pointer to window name
wintype, // window style
@@ -172,7 +173,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
free(title_16);
}
else {
- wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
+ wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
m_hWnd = ::CreateWindowW(s_windowClassName, // pointer to registered class name
title_16, // pointer to window name
WS_MAXIMIZE, // window style
@@ -288,11 +289,12 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
// Initialize Windows Ink
if (m_user32) {
- m_fpGetPointerInfo = (GHOST_WIN32_GetPointerInfo)::GetProcAddress(m_user32, "GetPointerInfo");
- m_fpGetPointerPenInfo = (GHOST_WIN32_GetPointerPenInfo)::GetProcAddress(m_user32,
- "GetPointerPenInfo");
- m_fpGetPointerTouchInfo = (GHOST_WIN32_GetPointerTouchInfo)::GetProcAddress(
- m_user32, "GetPointerTouchInfo");
+ m_fpGetPointerInfoHistory = (GHOST_WIN32_GetPointerInfoHistory)::GetProcAddress(
+ m_user32, "GetPointerInfoHistory");
+ m_fpGetPointerPenInfoHistory = (GHOST_WIN32_GetPointerPenInfoHistory)::GetProcAddress(
+ m_user32, "GetPointerPenInfoHistory");
+ m_fpGetPointerTouchInfoHistory = (GHOST_WIN32_GetPointerTouchInfoHistory)::GetProcAddress(
+ m_user32, "GetPointerTouchInfoHistory");
}
// Initialize Wintab
@@ -379,9 +381,9 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
if (m_user32) {
FreeLibrary(m_user32);
m_user32 = NULL;
- m_fpGetPointerInfo = NULL;
- m_fpGetPointerPenInfo = NULL;
- m_fpGetPointerTouchInfo = NULL;
+ m_fpGetPointerInfoHistory = NULL;
+ m_fpGetPointerPenInfoHistory = NULL;
+ m_fpGetPointerTouchInfoHistory = NULL;
}
if (m_customCursor) {
@@ -428,19 +430,18 @@ HWND GHOST_WindowWin32::getHWND() const
return m_hWnd;
}
-void GHOST_WindowWin32::setTitle(const STR_String &title)
+void GHOST_WindowWin32::setTitle(const char *title)
{
- wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
+ wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
::SetWindowTextW(m_hWnd, (wchar_t *)title_16);
free(title_16);
}
-void GHOST_WindowWin32::getTitle(STR_String &title) const
+std::string GHOST_WindowWin32::getTitle() const
{
char buf[s_maxTitleLength]; /*CHANGE + never used yet*/
::GetWindowText(m_hWnd, buf, s_maxTitleLength);
- STR_String temp(buf);
- title = buf;
+ return std::string(buf);
}
void GHOST_WindowWin32::getWindowBounds(GHOST_Rect &bounds) const
@@ -785,21 +786,20 @@ bool GHOST_WindowWin32::isDialog() const
return (parent != 0) && (style & WS_POPUPWINDOW);
}
-void GHOST_WindowWin32::registerMouseClickEvent(int press)
+void GHOST_WindowWin32::updateMouseCapture(GHOST_MouseCaptureEventWin32 event)
{
-
- switch (press) {
- case 0:
+ switch (event) {
+ case MousePressed:
m_nPressedButtons++;
break;
- case 1:
+ case MouseReleased:
if (m_nPressedButtons)
m_nPressedButtons--;
break;
- case 2:
+ case OperatorGrab:
m_hasGrabMouse = true;
break;
- case 3:
+ case OperatorUngrab:
m_hasGrabMouse = false;
break;
}
@@ -814,6 +814,11 @@ void GHOST_WindowWin32::registerMouseClickEvent(int press)
}
}
+bool GHOST_WindowWin32::getMousePressed() const
+{
+ return m_nPressedButtons;
+}
+
HCURSOR GHOST_WindowWin32::getStandardCursor(GHOST_TStandardCursor shape) const
{
// Convert GHOST cursor to Windows OEM cursor
@@ -977,7 +982,7 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode
if (mode == GHOST_kGrabHide)
setWindowCursorVisibility(false);
}
- registerMouseClickEvent(2);
+ updateMouseCapture(OperatorGrab);
}
else {
if (m_cursorGrab == GHOST_kGrabHide) {
@@ -997,7 +1002,7 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode
* can be incorrect on exit. */
setCursorGrabAccum(0, 0);
m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */
- registerMouseClickEvent(3);
+ updateMouseCapture(OperatorUngrab);
}
return GHOST_kSuccess;
@@ -1017,78 +1022,82 @@ GHOST_TSuccess GHOST_WindowWin32::hasCursorShape(GHOST_TStandardCursor cursorSha
return (getStandardCursor(cursorShape)) ? GHOST_kSuccess : GHOST_kFailure;
}
-GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(GHOST_PointerInfoWin32 *pointerInfo,
- WPARAM wParam,
- LPARAM lParam)
+GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(
+ std::vector<GHOST_PointerInfoWin32> &outPointerInfo, WPARAM wParam, LPARAM lParam)
{
- ZeroMemory(pointerInfo, sizeof(GHOST_PointerInfoWin32));
-
- // Obtain the basic information from the event
- pointerInfo->pointerId = GET_POINTERID_WPARAM(wParam);
- pointerInfo->isInContact = IS_POINTER_INCONTACT_WPARAM(wParam);
- pointerInfo->isPrimary = IS_POINTER_PRIMARY_WPARAM(wParam);
-
- // Obtain more accurate and predicted information from the Pointer API
- POINTER_INFO pointerApiInfo;
- if (!(m_fpGetPointerInfo && m_fpGetPointerInfo(pointerInfo->pointerId, &pointerApiInfo))) {
+ if (!useTabletAPI(GHOST_kTabletNative)) {
return GHOST_kFailure;
}
- pointerInfo->hasButtonMask = GHOST_kSuccess;
- switch (pointerApiInfo.ButtonChangeType) {
- case POINTER_CHANGE_FIRSTBUTTON_DOWN:
- case POINTER_CHANGE_FIRSTBUTTON_UP:
- pointerInfo->buttonMask = GHOST_kButtonMaskLeft;
- break;
- case POINTER_CHANGE_SECONDBUTTON_DOWN:
- case POINTER_CHANGE_SECONDBUTTON_UP:
- pointerInfo->buttonMask = GHOST_kButtonMaskRight;
- break;
- case POINTER_CHANGE_THIRDBUTTON_DOWN:
- case POINTER_CHANGE_THIRDBUTTON_UP:
- pointerInfo->buttonMask = GHOST_kButtonMaskMiddle;
- break;
- case POINTER_CHANGE_FOURTHBUTTON_DOWN:
- case POINTER_CHANGE_FOURTHBUTTON_UP:
- pointerInfo->buttonMask = GHOST_kButtonMaskButton4;
- break;
- case POINTER_CHANGE_FIFTHBUTTON_DOWN:
- case POINTER_CHANGE_FIFTHBUTTON_UP:
- pointerInfo->buttonMask = GHOST_kButtonMaskButton5;
- break;
- default:
- pointerInfo->hasButtonMask = GHOST_kFailure;
- break;
+ GHOST_TInt32 pointerId = GET_POINTERID_WPARAM(wParam);
+ GHOST_TInt32 isPrimary = IS_POINTER_PRIMARY_WPARAM(wParam);
+ GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem();
+ GHOST_TUns32 outCount;
+
+ if (!(m_fpGetPointerInfoHistory && m_fpGetPointerInfoHistory(pointerId, &outCount, NULL))) {
+ return GHOST_kFailure;
}
- pointerInfo->pixelLocation = pointerApiInfo.ptPixelLocation;
- pointerInfo->tabletData.Active = GHOST_kTabletModeNone;
- pointerInfo->tabletData.Pressure = 1.0f;
- pointerInfo->tabletData.Xtilt = 0.0f;
- pointerInfo->tabletData.Ytilt = 0.0f;
+ auto pointerPenInfo = std::vector<POINTER_PEN_INFO>(outCount);
+ outPointerInfo.resize(outCount);
- if (pointerApiInfo.pointerType != PT_PEN) {
+ if (!(m_fpGetPointerPenInfoHistory &&
+ m_fpGetPointerPenInfoHistory(pointerId, &outCount, pointerPenInfo.data()))) {
return GHOST_kFailure;
}
- POINTER_PEN_INFO pointerPenInfo;
- if (m_fpGetPointerPenInfo && m_fpGetPointerPenInfo(pointerInfo->pointerId, &pointerPenInfo)) {
- pointerInfo->tabletData.Active = GHOST_kTabletModeStylus;
+ for (GHOST_TUns32 i = 0; i < outCount; i++) {
+ POINTER_INFO pointerApiInfo = pointerPenInfo[i].pointerInfo;
+ // Obtain the basic information from the event
+ outPointerInfo[i].pointerId = pointerId;
+ outPointerInfo[i].isPrimary = isPrimary;
+
+ switch (pointerApiInfo.ButtonChangeType) {
+ case POINTER_CHANGE_FIRSTBUTTON_DOWN:
+ case POINTER_CHANGE_FIRSTBUTTON_UP:
+ outPointerInfo[i].buttonMask = GHOST_kButtonMaskLeft;
+ break;
+ case POINTER_CHANGE_SECONDBUTTON_DOWN:
+ case POINTER_CHANGE_SECONDBUTTON_UP:
+ outPointerInfo[i].buttonMask = GHOST_kButtonMaskRight;
+ break;
+ case POINTER_CHANGE_THIRDBUTTON_DOWN:
+ case POINTER_CHANGE_THIRDBUTTON_UP:
+ outPointerInfo[i].buttonMask = GHOST_kButtonMaskMiddle;
+ break;
+ case POINTER_CHANGE_FOURTHBUTTON_DOWN:
+ case POINTER_CHANGE_FOURTHBUTTON_UP:
+ outPointerInfo[i].buttonMask = GHOST_kButtonMaskButton4;
+ break;
+ case POINTER_CHANGE_FIFTHBUTTON_DOWN:
+ case POINTER_CHANGE_FIFTHBUTTON_UP:
+ outPointerInfo[i].buttonMask = GHOST_kButtonMaskButton5;
+ break;
+ default:
+ break;
+ }
+
+ outPointerInfo[i].pixelLocation = pointerApiInfo.ptPixelLocation;
+ outPointerInfo[i].tabletData.Active = GHOST_kTabletModeStylus;
+ outPointerInfo[i].tabletData.Pressure = 1.0f;
+ outPointerInfo[i].tabletData.Xtilt = 0.0f;
+ outPointerInfo[i].tabletData.Ytilt = 0.0f;
+ outPointerInfo[i].time = system->performanceCounterToMillis(pointerApiInfo.PerformanceCount);
- if (pointerPenInfo.penMask & PEN_MASK_PRESSURE) {
- pointerInfo->tabletData.Pressure = pointerPenInfo.pressure / 1024.0f;
+ if (pointerPenInfo[i].penMask & PEN_MASK_PRESSURE) {
+ outPointerInfo[i].tabletData.Pressure = pointerPenInfo[i].pressure / 1024.0f;
}
- if (pointerPenInfo.penFlags & PEN_FLAG_ERASER) {
- pointerInfo->tabletData.Active = GHOST_kTabletModeEraser;
+ if (pointerPenInfo[i].penFlags & PEN_FLAG_ERASER) {
+ outPointerInfo[i].tabletData.Active = GHOST_kTabletModeEraser;
}
- if (pointerPenInfo.penFlags & PEN_MASK_TILT_X) {
- pointerInfo->tabletData.Xtilt = fmin(fabs(pointerPenInfo.tiltX / 90), 1.0f);
+ if (pointerPenInfo[i].penMask & PEN_MASK_TILT_X) {
+ outPointerInfo[i].tabletData.Xtilt = fmin(fabs(pointerPenInfo[i].tiltX / 90.0f), 1.0f);
}
- if (pointerPenInfo.penFlags & PEN_MASK_TILT_Y) {
- pointerInfo->tabletData.Ytilt = fmin(fabs(pointerPenInfo.tiltY / 90), 1.0f);
+ if (pointerPenInfo[i].penMask & PEN_MASK_TILT_Y) {
+ outPointerInfo[i].tabletData.Ytilt = fmin(fabs(pointerPenInfo[i].tiltY / 90.0f), 1.0f);
}
}
@@ -1101,7 +1110,7 @@ void GHOST_WindowWin32::setTabletData(GHOST_TabletData *pTabletData)
m_tabletData = *pTabletData;
}
else {
- m_tabletData = GHOST_TABLET_DATA_DEFAULT;
+ m_tabletData = GHOST_TABLET_DATA_NONE;
}
}
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index ac1ec0ee852..dbed7c5ee5f 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -35,6 +35,8 @@
# include "GHOST_ImeWin32.h"
#endif
+#include <vector>
+
#include <wintab.h>
#define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR)
#define PACKETMODE PK_BUTTONS
@@ -88,6 +90,26 @@ typedef enum tagPOINTER_BUTTON_CHANGE_TYPE {
typedef DWORD POINTER_INPUT_TYPE;
typedef UINT32 POINTER_FLAGS;
+#define POINTER_FLAG_NONE 0x00000000
+#define POINTER_FLAG_NEW 0x00000001
+#define POINTER_FLAG_INRANGE 0x00000002
+#define POINTER_FLAG_INCONTACT 0x00000004
+#define POINTER_FLAG_FIRSTBUTTON 0x00000010
+#define POINTER_FLAG_SECONDBUTTON 0x00000020
+#define POINTER_FLAG_THIRDBUTTON 0x00000040
+#define POINTER_FLAG_FOURTHBUTTON 0x00000080
+#define POINTER_FLAG_FIFTHBUTTON 0x00000100
+#define POINTER_FLAG_PRIMARY 0x00002000
+#define POINTER_FLAG_CONFIDENCE 0x000004000
+#define POINTER_FLAG_CANCELED 0x000008000
+#define POINTER_FLAG_DOWN 0x00010000
+#define POINTER_FLAG_UPDATE 0x00020000
+#define POINTER_FLAG_UP 0x00040000
+#define POINTER_FLAG_WHEEL 0x00080000
+#define POINTER_FLAG_HWHEEL 0x00100000
+#define POINTER_FLAG_CAPTURECHANGED 0x00200000
+#define POINTER_FLAG_HASTRANSFORM 0x00400000
+
typedef struct tagPOINTER_INFO {
POINTER_INPUT_TYPE pointerType;
UINT32 pointerId;
@@ -192,20 +214,33 @@ typedef struct tagPOINTER_TOUCH_INFO {
#define IS_POINTER_CANCELED_WPARAM(wParam) \
IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_CANCELED)
-typedef BOOL(API *GHOST_WIN32_GetPointerInfo)(UINT32 pointerId, POINTER_INFO *pointerInfo);
-typedef BOOL(API *GHOST_WIN32_GetPointerPenInfo)(UINT32 pointerId, POINTER_PEN_INFO *penInfo);
-typedef BOOL(API *GHOST_WIN32_GetPointerTouchInfo)(UINT32 pointerId, POINTER_TOUCH_INFO *penInfo);
+typedef BOOL(WINAPI *GHOST_WIN32_GetPointerInfoHistory)(UINT32 pointerId,
+ UINT32 *entriesCount,
+ POINTER_INFO *pointerInfo);
+typedef BOOL(WINAPI *GHOST_WIN32_GetPointerPenInfoHistory)(UINT32 pointerId,
+ UINT32 *entriesCount,
+ POINTER_PEN_INFO *penInfo);
+typedef BOOL(WINAPI *GHOST_WIN32_GetPointerTouchInfoHistory)(UINT32 pointerId,
+ UINT32 *entriesCount,
+ POINTER_TOUCH_INFO *touchInfo);
struct GHOST_PointerInfoWin32 {
GHOST_TInt32 pointerId;
- GHOST_TInt32 isInContact;
GHOST_TInt32 isPrimary;
- GHOST_TSuccess hasButtonMask;
GHOST_TButtonMask buttonMask;
POINT pixelLocation;
+ GHOST_TUns64 time;
+
GHOST_TabletData tabletData;
};
+typedef enum {
+ MousePressed,
+ MouseReleased,
+ OperatorGrab,
+ OperatorUngrab
+} GHOST_MouseCaptureEventWin32;
+
/**
* GHOST window on M$ Windows OSs.
*/
@@ -226,7 +261,7 @@ class GHOST_WindowWin32 : public GHOST_Window {
* \param parentWindowHwnd
*/
GHOST_WindowWin32(GHOST_SystemWin32 *system,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -261,13 +296,13 @@ class GHOST_WindowWin32 : public GHOST_Window {
* Sets the title displayed in the title bar.
* \param title The title to display in the title bar.
*/
- void setTitle(const STR_String &title);
+ void setTitle(const char *title);
/**
* Returns the title displayed in the title bar.
- * \param title The title displayed in the title bar.
+ * \return The title displayed in the title bar.
*/
- void getTitle(STR_String &title) const;
+ std::string getTitle() const;
/**
* Returns the window rectangle dimensions.
@@ -364,17 +399,14 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_TSuccess endProgressBar();
/**
- * Register a mouse click event (should be called
+ * Register a mouse capture state (should be called
* for any real button press, controls mouse
* capturing).
*
- * \param press
- * 0 - mouse pressed
- * 1 - mouse released
- * 2 - operator grab
- * 3 - operator ungrab
+ * \param event Whether mouse was pressed and released, or an operator grabbed or ungrabbed the
+ * mouse
*/
- void registerMouseClickEvent(int press);
+ void updateMouseCapture(GHOST_MouseCaptureEventWin32 event);
/**
* Inform the window that it has lost mouse capture,
@@ -392,16 +424,24 @@ class GHOST_WindowWin32 : public GHOST_Window {
HCURSOR getStandardCursor(GHOST_TStandardCursor shape) const;
void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const;
- const GHOST_TabletData &GetTabletData()
+ const GHOST_TabletData &getTabletData()
{
return m_tabletData;
}
void setTabletData(GHOST_TabletData *tabletData);
bool useTabletAPI(GHOST_TTabletAPI api) const;
- void getPointerInfo(WPARAM wParam);
- void processWin32PointerEvent(WPARAM wParam);
+ /**
+ * Translate WM_POINTER events into GHOST_PointerInfoWin32 structs.
+ * \param outPointerInfo Storage to return resulting GHOST_PointerInfoWin32 structs
+ * \param wParam WPARAM of the event
+ * \param lParam LPARAM of the event
+ */
+ GHOST_TSuccess getPointerInfo(std::vector<GHOST_PointerInfoWin32> &outPointerInfo,
+ WPARAM wParam,
+ LPARAM lParam);
+
void processWin32TabletActivateEvent(WORD state);
void processWin32TabletInitEvent();
void processWin32TabletEvent(WPARAM wParam, LPARAM lParam);
@@ -419,7 +459,14 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_TUns16 getDPIHint() override;
- GHOST_TSuccess getPointerInfo(GHOST_PointerInfoWin32 *pointerInfo, WPARAM wParam, LPARAM lParam);
+ /**
+ * Get whether there are currently any mouse buttons pressed
+ * \return True if there are any currently pressed mouse buttons
+ */
+ bool getMousePressed() const;
+
+ /** Whether a tablet stylus is being tracked */
+ bool m_tabletInRange;
/** if the window currently resizing */
bool m_inLiveResize;
@@ -527,9 +574,9 @@ class GHOST_WindowWin32 : public GHOST_Window {
/** user32 dll handle*/
HMODULE m_user32;
- GHOST_WIN32_GetPointerInfo m_fpGetPointerInfo;
- GHOST_WIN32_GetPointerPenInfo m_fpGetPointerPenInfo;
- GHOST_WIN32_GetPointerTouchInfo m_fpGetPointerTouchInfo;
+ GHOST_WIN32_GetPointerInfoHistory m_fpGetPointerInfoHistory;
+ GHOST_WIN32_GetPointerPenInfoHistory m_fpGetPointerPenInfoHistory;
+ GHOST_WIN32_GetPointerTouchInfoHistory m_fpGetPointerTouchInfoHistory;
HWND m_parentWindowHwnd;
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index 3bece605d45..691f1790a2d 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -33,7 +33,6 @@
#include "GHOST_IconX11.h"
#include "GHOST_SystemX11.h"
#include "GHOST_WindowX11.h"
-#include "STR_String.h"
#ifdef WITH_XDND
# include "GHOST_DropTargetX11.h"
@@ -61,6 +60,7 @@
#include <unistd.h>
#include <algorithm>
+#include <limits.h>
#include <math.h>
#include <string>
@@ -212,7 +212,7 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
Display *display,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -239,6 +239,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
#ifdef WITH_XDND
m_dropTarget(NULL),
#endif
+ m_tabletData(GHOST_TABLET_DATA_NONE),
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
m_xic(NULL),
#endif
@@ -413,9 +414,9 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
/* XClassHint, title */
{
XClassHint *xclasshint = XAllocClassHint();
- const int len = title.Length() + 1;
+ const int len = strlen(title) + 1;
char *wmclass = (char *)malloc(sizeof(char) * len);
- memcpy(wmclass, title.ReadPtr(), len * sizeof(char));
+ memcpy(wmclass, title, len * sizeof(char));
xclasshint->res_name = wmclass;
xclasshint->res_class = wmclass;
XSetClassHint(m_display, m_window, xclasshint);
@@ -498,8 +499,6 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
#ifdef WITH_X11_XINPUT
refreshXInputDevices();
-
- m_tabletData = GHOST_TABLET_DATA_DEFAULT;
#endif
/* now set up the rendering context. */
@@ -618,7 +617,7 @@ bool GHOST_WindowX11::getValid() const
return GHOST_Window::getValid() && m_valid_setup;
}
-void GHOST_WindowX11::setTitle(const STR_String &title)
+void GHOST_WindowX11::setTitle(const char *title)
{
Atom name = XInternAtom(m_display, "_NET_WM_NAME", 0);
Atom utf8str = XInternAtom(m_display, "UTF8_STRING", 0);
@@ -628,8 +627,8 @@ void GHOST_WindowX11::setTitle(const STR_String &title)
utf8str,
8,
PropModeReplace,
- (const unsigned char *)title.ReadPtr(),
- title.Length());
+ (const unsigned char *)title,
+ strlen(title));
/* This should convert to valid x11 string
* and getTitle would need matching change */
@@ -638,13 +637,14 @@ void GHOST_WindowX11::setTitle(const STR_String &title)
XFlush(m_display);
}
-void GHOST_WindowX11::getTitle(STR_String &title) const
+std::string GHOST_WindowX11::getTitle() const
{
char *name = NULL;
XFetchName(m_display, m_window, &name);
- title = name ? name : "untitled";
+ std::string title = name ? name : "untitled";
XFree(name);
+ return title;
}
void GHOST_WindowX11::getWindowBounds(GHOST_Rect &bounds) const
diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h
index a9914d88340..4232ff40b52 100644
--- a/intern/ghost/intern/GHOST_WindowX11.h
+++ b/intern/ghost/intern/GHOST_WindowX11.h
@@ -37,7 +37,6 @@
#include <map>
-class STR_String;
class GHOST_SystemX11;
#ifdef WITH_XDND
@@ -69,7 +68,7 @@ class GHOST_WindowX11 : public GHOST_Window {
*/
GHOST_WindowX11(GHOST_SystemX11 *system,
Display *display,
- const STR_String &title,
+ const char *title,
GHOST_TInt32 left,
GHOST_TInt32 top,
GHOST_TUns32 width,
@@ -85,9 +84,9 @@ class GHOST_WindowX11 : public GHOST_Window {
bool getValid() const;
- void setTitle(const STR_String &title);
+ void setTitle(const char *title);
- void getTitle(STR_String &title) const;
+ std::string getTitle() const;
void getWindowBounds(GHOST_Rect &bounds) const;
@@ -144,12 +143,11 @@ class GHOST_WindowX11 : public GHOST_Window {
* Return a handle to the x11 window type.
*/
Window getXWindow();
-#ifdef WITH_X11_XINPUT
+
GHOST_TabletData &GetTabletData()
{
return m_tabletData;
}
-#endif // WITH_X11_XINPUT
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
XIC getX11_XIC()
@@ -269,9 +267,7 @@ class GHOST_WindowX11 : public GHOST_Window {
GHOST_DropTargetX11 *m_dropTarget;
#endif
-#ifdef WITH_X11_XINPUT
GHOST_TabletData m_tabletData;
-#endif
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
XIC m_xic;
diff --git a/intern/ghost/intern/GHOST_XrContext.cpp b/intern/ghost/intern/GHOST_XrContext.cpp
index a757aa9a555..3aab420a9b6 100644
--- a/intern/ghost/intern/GHOST_XrContext.cpp
+++ b/intern/ghost/intern/GHOST_XrContext.cpp
@@ -465,7 +465,14 @@ void GHOST_XrContext::startSession(const GHOST_XrSessionBeginInfo *begin_info)
void GHOST_XrContext::endSession()
{
- m_session->requestEnd();
+ if (m_session) {
+ if (m_session->isRunning()) {
+ m_session->requestEnd();
+ }
+ else {
+ m_session = nullptr;
+ }
+ }
}
bool GHOST_XrContext::isSessionRunning() const
@@ -512,6 +519,13 @@ void GHOST_XrContext::setDrawViewFunc(GHOST_XrDrawViewFn draw_view_fn)
m_custom_funcs.draw_view_fn = draw_view_fn;
}
+bool GHOST_XrContext::needsUpsideDownDrawing() const
+{
+ /* Must only be called after the session was started */
+ assert(m_session);
+ return m_session->needsUpsideDownDrawing();
+}
+
/** \} */ /* Public Accessors and Mutators */
/* -------------------------------------------------------------------- */
diff --git a/intern/ghost/intern/GHOST_XrContext.h b/intern/ghost/intern/GHOST_XrContext.h
index af65f262323..7dbd0a0d011 100644
--- a/intern/ghost/intern/GHOST_XrContext.h
+++ b/intern/ghost/intern/GHOST_XrContext.h
@@ -78,6 +78,7 @@ class GHOST_XrContext : public GHOST_IXrContext {
void setGraphicsContextBindFuncs(GHOST_XrGraphicsContextBindFn bind_fn,
GHOST_XrGraphicsContextUnbindFn unbind_fn) override;
void setDrawViewFunc(GHOST_XrDrawViewFn draw_view_fn) override;
+ bool needsUpsideDownDrawing() const override;
void handleSessionStateChange(const XrEventDataSessionStateChanged *lifecycle);
diff --git a/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp b/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp
index ea97b3a50cf..71e6af3fa4f 100644
--- a/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp
+++ b/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp
@@ -22,11 +22,12 @@
#include <list>
#include <sstream>
-#if defined(WITH_X11)
+#if defined(WITH_GHOST_X11)
# include "GHOST_ContextGLX.h"
#elif defined(WIN32)
# include "GHOST_ContextD3D.h"
# include "GHOST_ContextWGL.h"
+# include "GHOST_SystemWin32.h"
#endif
#include "GHOST_C-api.h"
#include "GHOST_Xr_intern.h"
@@ -67,7 +68,7 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding {
XrSystemId system_id,
std::string *r_requirement_info) const override
{
-#if defined(WITH_X11)
+#if defined(WITH_GHOST_X11)
GHOST_ContextGLX *ctx_gl = static_cast<GHOST_ContextGLX *>(ghost_ctx);
#else
GHOST_ContextWGL *ctx_gl = static_cast<GHOST_ContextWGL *>(ghost_ctx);
@@ -106,7 +107,7 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding {
void initFromGhostContext(GHOST_Context *ghost_ctx) override
{
-#if defined(WITH_X11)
+#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);
@@ -180,6 +181,11 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
+ bool needsUpsideDownDrawing(GHOST_Context &ghost_ctx) const override
+ {
+ return ghost_ctx.isUpsideDown();
+ }
+
private:
std::list<std::vector<XrSwapchainImageOpenGLKHR>> m_image_cache;
GLuint m_fbo = 0;
@@ -188,19 +194,27 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding {
#ifdef WIN32
class GHOST_XrGraphicsBindingD3D : public GHOST_IXrGraphicsBinding {
public:
+ GHOST_XrGraphicsBindingD3D(GHOST_Context *ghost_ctx)
+ : GHOST_IXrGraphicsBinding(), m_ghost_wgl_ctx(*static_cast<GHOST_ContextWGL *>(ghost_ctx))
+ {
+ m_ghost_d3d_ctx = GHOST_SystemWin32::createOffscreenContextD3D();
+ }
~GHOST_XrGraphicsBindingD3D()
{
if (m_shared_resource) {
- m_ghost_ctx->disposeSharedOpenGLResource(m_shared_resource);
+ m_ghost_d3d_ctx->disposeSharedOpenGLResource(m_shared_resource);
+ }
+ if (m_ghost_d3d_ctx) {
+ GHOST_SystemWin32::disposeContextD3D(m_ghost_d3d_ctx);
}
}
- bool checkVersionRequirements(GHOST_Context *ghost_ctx,
- XrInstance instance,
- XrSystemId system_id,
- std::string *r_requirement_info) const override
+ bool checkVersionRequirements(
+ GHOST_Context * /*ghost_ctx*/, /* Remember: This is the OpenGL context! */
+ XrInstance instance,
+ XrSystemId system_id,
+ std::string *r_requirement_info) const override
{
- GHOST_ContextD3D *ctx_dx = static_cast<GHOST_ContextD3D *>(ghost_ctx);
static PFN_xrGetD3D11GraphicsRequirementsKHR s_xrGetD3D11GraphicsRequirementsKHR_fn = nullptr;
XrGraphicsRequirementsD3D11KHR gpu_requirements = {XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR};
@@ -222,16 +236,15 @@ class GHOST_XrGraphicsBindingD3D : public GHOST_IXrGraphicsBinding {
*r_requirement_info = std::move(strstream.str());
}
- return ctx_dx->m_device->GetFeatureLevel() >= gpu_requirements.minFeatureLevel;
+ return m_ghost_d3d_ctx->m_device->GetFeatureLevel() >= gpu_requirements.minFeatureLevel;
}
- void initFromGhostContext(GHOST_Context *ghost_ctx) override
+ void initFromGhostContext(
+ GHOST_Context * /*ghost_ctx*/ /* Remember: This is the OpenGL context! */
+ ) override
{
- GHOST_ContextD3D *ctx_d3d = static_cast<GHOST_ContextD3D *>(ghost_ctx);
-
oxr_binding.d3d11.type = XR_TYPE_GRAPHICS_BINDING_D3D11_KHR;
- oxr_binding.d3d11.device = ctx_d3d->m_device;
- m_ghost_ctx = ctx_d3d;
+ oxr_binding.d3d11.device = m_ghost_d3d_ctx->m_device;
}
bool chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
@@ -266,7 +279,7 @@ class GHOST_XrGraphicsBindingD3D : public GHOST_IXrGraphicsBinding {
swapchain_image);
# if 0
- /* Ideally we'd just create a render target view for the OpenXR swapchain image texture and
+ /* Ideally we'd just create a render target view for the OpenXR swap-chain image texture and
* blit from the OpenGL context into it. The NV_DX_interop extension doesn't want to work with
* this though. At least not with Optimus hardware. See:
* https://github.com/mpv-player/mpv/issues/2949#issuecomment-197262807.
@@ -284,35 +297,47 @@ class GHOST_XrGraphicsBindingD3D : public GHOST_IXrGraphicsBinding {
m_ghost_ctx->blitFromOpenGLContext(m_shared_resource, draw_info->width, draw_info->height);
# else
if (!m_shared_resource) {
- m_shared_resource = m_ghost_ctx->createSharedOpenGLResource(draw_info->width,
- draw_info->height);
+ m_shared_resource = m_ghost_d3d_ctx->createSharedOpenGLResource(draw_info->width,
+ draw_info->height);
}
- m_ghost_ctx->blitFromOpenGLContext(m_shared_resource, draw_info->width, draw_info->height);
+ m_ghost_d3d_ctx->blitFromOpenGLContext(m_shared_resource, draw_info->width, draw_info->height);
- m_ghost_ctx->m_device_ctx->OMSetRenderTargets(0, nullptr, nullptr);
- m_ghost_ctx->m_device_ctx->CopyResource(d3d_swapchain_image->texture,
- m_ghost_ctx->getSharedTexture2D(m_shared_resource));
+ m_ghost_d3d_ctx->m_device_ctx->OMSetRenderTargets(0, nullptr, nullptr);
+ m_ghost_d3d_ctx->m_device_ctx->CopyResource(
+ d3d_swapchain_image->texture, m_ghost_d3d_ctx->getSharedTexture2D(m_shared_resource));
# endif
}
+ bool needsUpsideDownDrawing(GHOST_Context &) const
+ {
+ return m_ghost_d3d_ctx->isUpsideDown();
+ }
+
private:
- GHOST_ContextD3D *m_ghost_ctx;
- GHOST_SharedOpenGLResource *m_shared_resource;
+ /** Primary OpenGL context for Blender to use for drawing. */
+ GHOST_ContextWGL &m_ghost_wgl_ctx;
+ /** Secondary DirectX 11 context to share with OpenGL context. */
+ GHOST_ContextD3D *m_ghost_d3d_ctx = nullptr;
+ /** Handle to shared resource object. */
+ GHOST_SharedOpenGLResource *m_shared_resource = nullptr;
+
std::list<std::vector<XrSwapchainImageD3D11KHR>> m_image_cache;
};
#endif // WIN32
std::unique_ptr<GHOST_IXrGraphicsBinding> GHOST_XrGraphicsBindingCreateFromType(
- GHOST_TXrGraphicsBinding type)
+ GHOST_TXrGraphicsBinding type, GHOST_Context *context)
{
switch (type) {
case GHOST_kXrGraphicsOpenGL:
return std::unique_ptr<GHOST_XrGraphicsBindingOpenGL>(new GHOST_XrGraphicsBindingOpenGL());
#ifdef WIN32
case GHOST_kXrGraphicsD3D11:
- return std::unique_ptr<GHOST_XrGraphicsBindingD3D>(new GHOST_XrGraphicsBindingD3D());
+ return std::unique_ptr<GHOST_XrGraphicsBindingD3D>(new GHOST_XrGraphicsBindingD3D(context));
#endif
default:
return nullptr;
}
+
+ (void)context; /* Might be unused. */
}
diff --git a/intern/ghost/intern/GHOST_XrSession.cpp b/intern/ghost/intern/GHOST_XrSession.cpp
index 53d22cbd679..edc4960cf32 100644
--- a/intern/ghost/intern/GHOST_XrSession.cpp
+++ b/intern/ghost/intern/GHOST_XrSession.cpp
@@ -45,7 +45,7 @@ struct OpenXRSessionData {
XrSpace reference_space;
XrSpace view_space;
std::vector<XrView> views;
- std::vector<std::unique_ptr<GHOST_XrSwapchain>> swapchains;
+ std::vector<GHOST_XrSwapchain> swapchains;
};
struct GHOST_XrDrawInfo {
@@ -76,6 +76,9 @@ GHOST_XrSession::~GHOST_XrSession()
if (m_oxr->reference_space != XR_NULL_HANDLE) {
CHECK_XR_ASSERT(xrDestroySpace(m_oxr->reference_space));
}
+ if (m_oxr->view_space != XR_NULL_HANDLE) {
+ CHECK_XR_ASSERT(xrDestroySpace(m_oxr->view_space));
+ }
if (m_oxr->session != XR_NULL_HANDLE) {
CHECK_XR_ASSERT(xrDestroySession(m_oxr->session));
}
@@ -169,7 +172,8 @@ void GHOST_XrSession::start(const GHOST_XrSessionBeginInfo *begin_info)
}
std::string requirement_str;
- m_gpu_binding = GHOST_XrGraphicsBindingCreateFromType(m_context->getGraphicsBindingType());
+ m_gpu_binding = GHOST_XrGraphicsBindingCreateFromType(m_context->getGraphicsBindingType(),
+ m_gpu_ctx);
if (!m_gpu_binding->checkVersionRequirements(
m_gpu_ctx, m_context->getInstance(), m_oxr->system_id, &requirement_str)) {
std::ostringstream strstream;
@@ -199,13 +203,17 @@ void GHOST_XrSession::requestEnd()
xrRequestExitSession(m_oxr->session);
}
-void GHOST_XrSession::end()
+void GHOST_XrSession::beginSession()
{
- assert(m_oxr->session != XR_NULL_HANDLE);
+ XrSessionBeginInfo begin_info = {XR_TYPE_SESSION_BEGIN_INFO};
+ begin_info.primaryViewConfigurationType = m_oxr->view_type;
+ CHECK_XR(xrBeginSession(m_oxr->session, &begin_info), "Failed to cleanly begin the VR session.");
+}
+void GHOST_XrSession::endSession()
+{
+ assert(m_oxr->session != XR_NULL_HANDLE);
CHECK_XR(xrEndSession(m_oxr->session), "Failed to cleanly end the VR session.");
- unbindGraphicsContext();
- m_draw_info = nullptr;
}
GHOST_XrSession::LifeExpectancy GHOST_XrSession::handleStateChangeEvent(
@@ -218,16 +226,11 @@ GHOST_XrSession::LifeExpectancy GHOST_XrSession::handleStateChangeEvent(
switch (lifecycle->state) {
case XR_SESSION_STATE_READY: {
- XrSessionBeginInfo begin_info = {XR_TYPE_SESSION_BEGIN_INFO};
-
- begin_info.primaryViewConfigurationType = m_oxr->view_type;
- CHECK_XR(xrBeginSession(m_oxr->session, &begin_info),
- "Failed to cleanly begin the VR session.");
+ beginSession();
break;
}
case XR_SESSION_STATE_STOPPING:
- /* Runtime will change state to STATE_EXITING, don't destruct session yet. */
- end();
+ endSession();
break;
case XR_SESSION_STATE_EXITING:
case XR_SESSION_STATE_LOSS_PENDING:
@@ -264,8 +267,7 @@ void GHOST_XrSession::prepareDrawing()
"Failed to get count of view configurations.");
for (const XrViewConfigurationView &view_config : view_configs) {
- m_oxr->swapchains.push_back(std::unique_ptr<GHOST_XrSwapchain>(
- new GHOST_XrSwapchain(*m_gpu_binding, m_oxr->session, view_config)));
+ m_oxr->swapchains.emplace_back(*m_gpu_binding, m_oxr->session, view_config);
}
m_oxr->views.resize(view_count, {XR_TYPE_VIEW});
@@ -440,7 +442,7 @@ XrCompositionLayerProjection GHOST_XrSession::drawLayer(
r_proj_layer_views.resize(view_count);
for (uint32_t view_idx = 0; view_idx < view_count; view_idx++) {
- drawView(*m_oxr->swapchains[view_idx],
+ drawView(m_oxr->swapchains[view_idx],
r_proj_layer_views[view_idx],
view_location,
m_oxr->views[view_idx],
@@ -454,6 +456,11 @@ XrCompositionLayerProjection GHOST_XrSession::drawLayer(
return layer;
}
+bool GHOST_XrSession::needsUpsideDownDrawing() const
+{
+ return m_gpu_binding && m_gpu_binding->needsUpsideDownDrawing(*m_gpu_ctx);
+}
+
/** \} */ /* Drawing */
/* -------------------------------------------------------------------- */
@@ -493,16 +500,14 @@ void GHOST_XrSession::bindGraphicsContext()
{
const GHOST_XrCustomFuncs &custom_funcs = m_context->getCustomFuncs();
assert(custom_funcs.gpu_ctx_bind_fn);
- m_gpu_ctx = static_cast<GHOST_Context *>(
- custom_funcs.gpu_ctx_bind_fn(m_context->getGraphicsBindingType()));
+ m_gpu_ctx = static_cast<GHOST_Context *>(custom_funcs.gpu_ctx_bind_fn());
}
void GHOST_XrSession::unbindGraphicsContext()
{
const GHOST_XrCustomFuncs &custom_funcs = m_context->getCustomFuncs();
if (custom_funcs.gpu_ctx_unbind_fn) {
- custom_funcs.gpu_ctx_unbind_fn(m_context->getGraphicsBindingType(),
- (GHOST_ContextHandle)m_gpu_ctx);
+ custom_funcs.gpu_ctx_unbind_fn((GHOST_ContextHandle)m_gpu_ctx);
}
m_gpu_ctx = nullptr;
}
diff --git a/intern/ghost/intern/GHOST_XrSession.h b/intern/ghost/intern/GHOST_XrSession.h
index 9c1ed3756d4..da0128b2851 100644
--- a/intern/ghost/intern/GHOST_XrSession.h
+++ b/intern/ghost/intern/GHOST_XrSession.h
@@ -47,6 +47,7 @@ class GHOST_XrSession {
LifeExpectancy handleStateChangeEvent(const XrEventDataSessionStateChanged *lifecycle);
bool isRunning() const;
+ bool needsUpsideDownDrawing() const;
void unbindGraphicsContext(); /* Public so context can ensure it's unbound as needed. */
@@ -67,7 +68,8 @@ class GHOST_XrSession {
std::unique_ptr<GHOST_XrDrawInfo> m_draw_info;
void initSystem();
- void end();
+ void beginSession();
+ void endSession();
void bindGraphicsContext();
diff --git a/intern/ghost/intern/GHOST_XrSwapchain.cpp b/intern/ghost/intern/GHOST_XrSwapchain.cpp
index 4c91bcc2dc3..f50cfde0687 100644
--- a/intern/ghost/intern/GHOST_XrSwapchain.cpp
+++ b/intern/ghost/intern/GHOST_XrSwapchain.cpp
@@ -92,9 +92,19 @@ GHOST_XrSwapchain::GHOST_XrSwapchain(GHOST_IXrGraphicsBinding &gpu_binding,
m_oxr->swapchain_images = swapchain_images_create(m_oxr->swapchain, gpu_binding);
}
+GHOST_XrSwapchain::GHOST_XrSwapchain(GHOST_XrSwapchain &&other)
+ : m_oxr(std::move(other.m_oxr)),
+ m_image_width(other.m_image_width),
+ m_image_height(other.m_image_height)
+{
+ /* Prevent xrDestroySwapchain call for the moved out item. */
+ other.m_oxr = nullptr;
+}
+
GHOST_XrSwapchain::~GHOST_XrSwapchain()
{
- if (m_oxr->swapchain != XR_NULL_HANDLE) {
+ /* m_oxr may be NULL after move. */
+ if (m_oxr && m_oxr->swapchain != XR_NULL_HANDLE) {
CHECK_XR_ASSERT(xrDestroySwapchain(m_oxr->swapchain));
}
}
diff --git a/intern/ghost/intern/GHOST_XrSwapchain.h b/intern/ghost/intern/GHOST_XrSwapchain.h
index df9cd924dd0..ab0a6736c9c 100644
--- a/intern/ghost/intern/GHOST_XrSwapchain.h
+++ b/intern/ghost/intern/GHOST_XrSwapchain.h
@@ -30,6 +30,7 @@ class GHOST_XrSwapchain {
GHOST_XrSwapchain(GHOST_IXrGraphicsBinding &gpu_binding,
const XrSession &session,
const XrViewConfigurationView &view_config);
+ GHOST_XrSwapchain(GHOST_XrSwapchain &&other);
~GHOST_XrSwapchain();
XrSwapchainImageBaseHeader *acquireDrawableSwapchainImage();
diff --git a/intern/ghost/intern/GHOST_Xr_openxr_includes.h b/intern/ghost/intern/GHOST_Xr_openxr_includes.h
index 925d6037750..9cac43b1549 100644
--- a/intern/ghost/intern/GHOST_Xr_openxr_includes.h
+++ b/intern/ghost/intern/GHOST_Xr_openxr_includes.h
@@ -42,7 +42,7 @@
#ifdef XR_USE_GRAPHICS_API_D3D12
# include <d3d12.h>
#endif
-#ifdef WITH_X11
+#ifdef WITH_GHOST_X11
# include <GL/glxew.h>
#endif