Fix building with shared OIDN libraries
[blender.git] / intern / ghost / intern / GHOST_SystemX11.cpp
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  * Part of this code has been taken from Qt, under LGPL license
19  * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
20  */
21
22 /** \file
23  * \ingroup GHOST
24  */
25
26 #include <X11/Xatom.h>
27 #include <X11/keysym.h>
28 #include <X11/XKBlib.h> /* allow detectable autorepeate */
29 #include <X11/Xutil.h>
30
31 #include "GHOST_SystemX11.h"
32 #include "GHOST_WindowX11.h"
33 #include "GHOST_WindowManager.h"
34 #include "GHOST_TimerManager.h"
35 #include "GHOST_EventCursor.h"
36 #include "GHOST_EventKey.h"
37 #include "GHOST_EventButton.h"
38 #include "GHOST_EventWheel.h"
39 #include "GHOST_DisplayManagerX11.h"
40 #include "GHOST_EventDragnDrop.h"
41 #ifdef WITH_INPUT_NDOF
42 #  include "GHOST_NDOFManagerUnix.h"
43 #endif
44
45 #ifdef WITH_XDND
46 #  include "GHOST_DropTargetX11.h"
47 #endif
48
49 #include "GHOST_Debug.h"
50
51 #if defined(WITH_GL_EGL)
52 #  include "GHOST_ContextEGL.h"
53 #else
54 #  include "GHOST_ContextGLX.h"
55 #endif
56
57 #ifdef WITH_XF86KEYSYM
58 #  include <X11/XF86keysym.h>
59 #endif
60
61 #ifdef WITH_X11_XFIXES
62 #  include <X11/extensions/Xfixes.h>
63 /* Workaround for XWayland grab glitch: T53004. */
64 #  define WITH_XWAYLAND_HACK
65 #endif
66
67 /* for XIWarpPointer */
68 #ifdef WITH_X11_XINPUT
69 #  include <X11/extensions/XInput2.h>
70 #endif
71
72 /* For timing */
73 #include <sys/time.h>
74 #include <unistd.h>
75
76 #include <iostream>
77 #include <vector>
78 #include <stdio.h> /* for fprintf only */
79 #include <cstdlib> /* for exit */
80
81 /* for debugging - so we can breakpoint X11 errors */
82 // #define USE_X11_ERROR_HANDLERS
83
84 #ifdef WITH_X11_XINPUT
85 #  define USE_XINPUT_HOTPLUG
86 #endif
87
88 /* see [#34039] Fix Alt key glitch on Unity desktop */
89 #define USE_UNITY_WORKAROUND
90
91 /* Fix 'shortcut' part of keyboard reading code only ever using first defined keymap
92  * instead of active one. See T47228 and D1746 */
93 #define USE_NON_LATIN_KB_WORKAROUND
94
95 static GHOST_TKey ghost_key_from_keysym(const KeySym key);
96 static GHOST_TKey ghost_key_from_keycode(const XkbDescPtr xkb_descr, const KeyCode keycode);
97 static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym key,
98                                                    const XkbDescPtr xkb_descr,
99                                                    const KeyCode keycode);
100
101 /* these are for copy and select copy */
102 static char *txt_cut_buffer = NULL;
103 static char *txt_select_buffer = NULL;
104
105 #ifdef WITH_XWAYLAND_HACK
106 static bool use_xwayland_hack = false;
107 #endif
108
109 using namespace std;
110
111 GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(NULL), m_start_time(0)
112 {
113   XInitThreads();
114   m_display = XOpenDisplay(NULL);
115
116   if (!m_display) {
117     std::cerr << "Unable to open a display" << std::endl;
118     abort(); /* was return before, but this would just mean it will crash later */
119   }
120
121 #ifdef USE_X11_ERROR_HANDLERS
122   (void)XSetErrorHandler(GHOST_X11_ApplicationErrorHandler);
123   (void)XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler);
124 #endif
125
126 #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
127   /* note -- don't open connection to XIM server here, because the locale
128    * has to be set before opening the connection but setlocale() has not
129    * been called yet.  the connection will be opened after entering
130    * the event loop. */
131   m_xim = NULL;
132 #endif
133
134 #define GHOST_INTERN_ATOM_IF_EXISTS(atom) \
135   { \
136     m_atom.atom = XInternAtom(m_display, #atom, True); \
137   } \
138   (void)0
139 #define GHOST_INTERN_ATOM(atom) \
140   { \
141     m_atom.atom = XInternAtom(m_display, #atom, False); \
142   } \
143   (void)0
144
145   GHOST_INTERN_ATOM_IF_EXISTS(WM_DELETE_WINDOW);
146   GHOST_INTERN_ATOM(WM_PROTOCOLS);
147   GHOST_INTERN_ATOM(WM_TAKE_FOCUS);
148   GHOST_INTERN_ATOM(WM_STATE);
149   GHOST_INTERN_ATOM(WM_CHANGE_STATE);
150   GHOST_INTERN_ATOM(_NET_WM_STATE);
151   GHOST_INTERN_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
152   GHOST_INTERN_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
153
154   GHOST_INTERN_ATOM(_NET_WM_STATE_FULLSCREEN);
155   GHOST_INTERN_ATOM(_MOTIF_WM_HINTS);
156   GHOST_INTERN_ATOM(TARGETS);
157   GHOST_INTERN_ATOM(STRING);
158   GHOST_INTERN_ATOM(COMPOUND_TEXT);
159   GHOST_INTERN_ATOM(TEXT);
160   GHOST_INTERN_ATOM(CLIPBOARD);
161   GHOST_INTERN_ATOM(PRIMARY);
162   GHOST_INTERN_ATOM(XCLIP_OUT);
163   GHOST_INTERN_ATOM(INCR);
164   GHOST_INTERN_ATOM(UTF8_STRING);
165 #ifdef WITH_X11_XINPUT
166   m_atom.TABLET = XInternAtom(m_display, XI_TABLET, False);
167 #endif
168
169 #undef GHOST_INTERN_ATOM_IF_EXISTS
170 #undef GHOST_INTERN_ATOM
171
172   m_last_warp = 0;
173   m_last_release_keycode = 0;
174   m_last_release_time = 0;
175
176   /* compute the initial time */
177   timeval tv;
178   if (gettimeofday(&tv, NULL) == -1) {
179     GHOST_ASSERT(false, "Could not instantiate timer!");
180   }
181
182   /* Taking care not to overflow the tv.tv_sec * 1000 */
183   m_start_time = GHOST_TUns64(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
184
185   /* use detectable autorepeate, mac and windows also do this */
186   int use_xkb;
187   int xkb_opcode, xkb_event, xkb_error;
188   int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
189
190   use_xkb = XkbQueryExtension(
191       m_display, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major, &xkb_minor);
192   if (use_xkb) {
193     XkbSetDetectableAutoRepeat(m_display, true, NULL);
194
195     m_xkb_descr = XkbGetMap(m_display, 0, XkbUseCoreKbd);
196     if (m_xkb_descr) {
197       XkbGetNames(m_display, XkbKeyNamesMask, m_xkb_descr);
198     }
199   }
200
201 #ifdef WITH_XWAYLAND_HACK
202   use_xwayland_hack = getenv("WAYLAND_DISPLAY") != NULL;
203 #endif
204
205 #ifdef WITH_X11_XINPUT
206   /* detect if we have xinput (for reuse) */
207   {
208     memset(&m_xinput_version, 0, sizeof(m_xinput_version));
209     XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
210     if (version && (version != (XExtensionVersion *)NoSuchExtension)) {
211       if (version->present) {
212         m_xinput_version = *version;
213       }
214       XFree(version);
215     }
216   }
217
218 #  ifdef USE_XINPUT_HOTPLUG
219   if (m_xinput_version.present) {
220     XEventClass class_presence;
221     int xi_presence;
222     DevicePresence(m_display, xi_presence, class_presence);
223     XSelectExtensionEvent(
224         m_display, RootWindow(m_display, DefaultScreen(m_display)), &class_presence, 1);
225     (void)xi_presence;
226   }
227 #  endif /* USE_XINPUT_HOTPLUG */
228
229   refreshXInputDevices();
230 #endif /* WITH_X11_XINPUT */
231 }
232
233 GHOST_SystemX11::~GHOST_SystemX11()
234 {
235 #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
236   if (m_xim) {
237     XCloseIM(m_xim);
238   }
239 #endif
240
241 #ifdef WITH_X11_XINPUT
242   /* Close tablet devices. */
243   clearXInputDevices();
244 #endif /* WITH_X11_XINPUT */
245
246   if (m_xkb_descr) {
247     XkbFreeKeyboard(m_xkb_descr, XkbAllComponentsMask, true);
248   }
249
250   XCloseDisplay(m_display);
251 }
252
253 GHOST_TSuccess GHOST_SystemX11::init()
254 {
255   GHOST_TSuccess success = GHOST_System::init();
256
257   if (success) {
258 #ifdef WITH_INPUT_NDOF
259     m_ndofManager = new GHOST_NDOFManagerUnix(*this);
260 #endif
261     m_displayManager = new GHOST_DisplayManagerX11(this);
262
263     if (m_displayManager) {
264       return GHOST_kSuccess;
265     }
266   }
267
268   return GHOST_kFailure;
269 }
270
271 GHOST_TUns64 GHOST_SystemX11::getMilliSeconds() const
272 {
273   timeval tv;
274   if (gettimeofday(&tv, NULL) == -1) {
275     GHOST_ASSERT(false, "Could not compute time!");
276   }
277
278   /* Taking care not to overflow the tv.tv_sec * 1000 */
279   return GHOST_TUns64(tv.tv_sec) * 1000 + tv.tv_usec / 1000 - m_start_time;
280 }
281
282 GHOST_TUns8 GHOST_SystemX11::getNumDisplays() const
283 {
284   return GHOST_TUns8(1);
285 }
286
287 /**
288  * Returns the dimensions of the main display on this system.
289  * \return The dimension of the main display.
290  */
291 void GHOST_SystemX11::getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const
292 {
293   if (m_display) {
294     /* note, for this to work as documented,
295      * we would need to use Xinerama check r54370 for code that did this,
296      * we've since removed since its not worth the extra dep - campbell */
297     getAllDisplayDimensions(width, height);
298   }
299 }
300
301 /**
302  * Returns the dimensions of the main display on this system.
303  * \return The dimension of the main display.
304  */
305 void GHOST_SystemX11::getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const
306 {
307   if (m_display) {
308     width = DisplayWidth(m_display, DefaultScreen(m_display));
309     height = DisplayHeight(m_display, DefaultScreen(m_display));
310   }
311 }
312
313 /**
314  * Create a new window.
315  * The new window is added to the list of windows managed.
316  * Never explicitly delete the window, use disposeWindow() instead.
317  * \param   title   The name of the window
318  * (displayed in the title bar of the window if the OS supports it).
319  * \param   left    The coordinate of the left edge of the window.
320  * \param   top     The coordinate of the top edge of the window.
321  * \param   width   The width the window.
322  * \param   height  The height the window.
323  * \param   state   The state of the window when opened.
324  * \param   type    The type of drawing context installed in this window.
325  * \param glSettings: Misc OpenGL settings.
326  * \param exclusive: Use to show the window ontop and ignore others (used fullscreen).
327  * \param   parentWindow    Parent (embedder) window
328  * \return  The new window (or 0 if creation failed).
329  */
330 GHOST_IWindow *GHOST_SystemX11::createWindow(const STR_String &title,
331                                              GHOST_TInt32 left,
332                                              GHOST_TInt32 top,
333                                              GHOST_TUns32 width,
334                                              GHOST_TUns32 height,
335                                              GHOST_TWindowState state,
336                                              GHOST_TDrawingContextType type,
337                                              GHOST_GLSettings glSettings,
338                                              const bool exclusive,
339                                              const GHOST_TEmbedderWindowID parentWindow)
340 {
341   GHOST_WindowX11 *window = NULL;
342
343   if (!m_display)
344     return 0;
345
346   window = new GHOST_WindowX11(this,
347                                m_display,
348                                title,
349                                left,
350                                top,
351                                width,
352                                height,
353                                state,
354                                parentWindow,
355                                type,
356                                ((glSettings.flags & GHOST_glStereoVisual) != 0),
357                                exclusive,
358                                ((glSettings.flags & GHOST_glAlphaBackground) != 0),
359                                (glSettings.flags & GHOST_glDebugContext) != 0);
360
361   if (window) {
362     /* Both are now handle in GHOST_WindowX11.cpp
363      * Focus and Delete atoms. */
364
365     if (window->getValid()) {
366       /* Store the pointer to the window */
367       m_windowManager->addWindow(window);
368       m_windowManager->setActiveWindow(window);
369       pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window));
370     }
371     else {
372       delete window;
373       window = NULL;
374     }
375   }
376   return window;
377 }
378
379 /**
380  * Create a new offscreen context.
381  * Never explicitly delete the context, use disposeContext() instead.
382  * \return  The new context (or 0 if creation failed).
383  */
384 GHOST_IContext *GHOST_SystemX11::createOffscreenContext()
385 {
386   // During development:
387   //   try 4.x compatibility profile
388   //   try 3.3 compatibility profile
389   //   fall back to 3.0 if needed
390   //
391   // Final Blender 2.8:
392   //   try 4.x core profile
393   //   try 3.3 core profile
394   //   no fallbacks
395
396 #if defined(WITH_GL_PROFILE_CORE)
397   {
398     const char *version_major = (char *)glewGetString(GLEW_VERSION_MAJOR);
399     if (version_major != NULL && version_major[0] == '1') {
400       fprintf(stderr, "Error: GLEW version 2.0 and above is required.\n");
401       abort();
402     }
403   }
404 #endif
405
406   const int profile_mask =
407 #if defined(WITH_GL_PROFILE_CORE)
408       GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
409 #elif defined(WITH_GL_PROFILE_COMPAT)
410       GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
411 #else
412 #  error  // must specify either core or compat at build time
413 #endif
414
415   GHOST_Context *context;
416
417   for (int minor = 5; minor >= 0; --minor) {
418     context = new GHOST_ContextGLX(false,
419                                    (Window)NULL,
420                                    m_display,
421                                    (GLXFBConfig)NULL,
422                                    profile_mask,
423                                    4,
424                                    minor,
425                                    GHOST_OPENGL_GLX_CONTEXT_FLAGS |
426                                        (false ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
427                                    GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
428
429     if (context->initializeDrawingContext())
430       return context;
431     else
432       delete context;
433   }
434
435   context = new GHOST_ContextGLX(false,
436                                  (Window)NULL,
437                                  m_display,
438                                  (GLXFBConfig)NULL,
439                                  profile_mask,
440                                  3,
441                                  3,
442                                  GHOST_OPENGL_GLX_CONTEXT_FLAGS |
443                                      (false ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
444                                  GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
445
446   if (context->initializeDrawingContext())
447     return context;
448   else
449     delete context;
450
451   return NULL;
452 }
453
454 /**
455  * Dispose of a context.
456  * \param   context Pointer to the context to be disposed.
457  * \return  Indication of success.
458  */
459 GHOST_TSuccess GHOST_SystemX11::disposeContext(GHOST_IContext *context)
460 {
461   delete context;
462
463   return GHOST_kSuccess;
464 }
465
466 #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
467 static void destroyIMCallback(XIM /*xim*/, XPointer ptr, XPointer /*data*/)
468 {
469   GHOST_PRINT("XIM server died\n");
470
471   if (ptr)
472     *(XIM *)ptr = NULL;
473 }
474
475 bool GHOST_SystemX11::openX11_IM()
476 {
477   if (!m_display)
478     return false;
479
480   /* set locale modifiers such as "@im=ibus" specified by XMODIFIERS */
481   XSetLocaleModifiers("");
482
483   m_xim = XOpenIM(m_display, NULL, (char *)GHOST_X11_RES_NAME, (char *)GHOST_X11_RES_CLASS);
484   if (!m_xim)
485     return false;
486
487   XIMCallback destroy;
488   destroy.callback = (XIMProc)destroyIMCallback;
489   destroy.client_data = (XPointer)&m_xim;
490   XSetIMValues(m_xim, XNDestroyCallback, &destroy, NULL);
491   return true;
492 }
493 #endif
494
495 GHOST_WindowX11 *GHOST_SystemX11::findGhostWindow(Window xwind) const
496 {
497
498   if (xwind == 0)
499     return NULL;
500
501   /* It is not entirely safe to do this as the backptr may point
502    * to a window that has recently been removed.
503    * We should always check the window manager's list of windows
504    * and only process events on these windows. */
505
506   vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
507
508   vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
509   vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
510
511   for (; win_it != win_end; ++win_it) {
512     GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it);
513     if (window->getXWindow() == xwind) {
514       return window;
515     }
516   }
517   return NULL;
518 }
519
520 static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep)
521 {
522   int fd = ConnectionNumber(display);
523   fd_set fds;
524
525   FD_ZERO(&fds);
526   FD_SET(fd, &fds);
527
528   if (maxSleep == -1) {
529     select(fd + 1, &fds, NULL, NULL, NULL);
530   }
531   else {
532     timeval tv;
533
534     tv.tv_sec = maxSleep / 1000;
535     tv.tv_usec = (maxSleep - tv.tv_sec * 1000) * 1000;
536
537     select(fd + 1, &fds, NULL, NULL, &tv);
538   }
539 }
540
541 /* This function borrowed from Qt's X11 support
542  * qclipboard_x11.cpp
543  *  */
544 struct init_timestamp_data {
545   Time timestamp;
546 };
547
548 static Bool init_timestamp_scanner(Display *, XEvent *event, XPointer arg)
549 {
550   init_timestamp_data *data = reinterpret_cast<init_timestamp_data *>(arg);
551   switch (event->type) {
552     case ButtonPress:
553     case ButtonRelease:
554       data->timestamp = event->xbutton.time;
555       break;
556     case MotionNotify:
557       data->timestamp = event->xmotion.time;
558       break;
559     case KeyPress:
560     case KeyRelease:
561       data->timestamp = event->xkey.time;
562       break;
563     case PropertyNotify:
564       data->timestamp = event->xproperty.time;
565       break;
566     case EnterNotify:
567     case LeaveNotify:
568       data->timestamp = event->xcrossing.time;
569       break;
570     case SelectionClear:
571       data->timestamp = event->xselectionclear.time;
572       break;
573     default:
574       break;
575   }
576
577   return false;
578 }
579
580 Time GHOST_SystemX11::lastEventTime(Time default_time)
581 {
582   init_timestamp_data data;
583   data.timestamp = default_time;
584   XEvent ev;
585   XCheckIfEvent(m_display, &ev, &init_timestamp_scanner, (XPointer)&data);
586
587   return data.timestamp;
588 }
589
590 bool GHOST_SystemX11::processEvents(bool waitForEvent)
591 {
592   /* Get all the current events -- translate them into
593    * ghost events and call base class pushEvent() method. */
594
595   bool anyProcessed = false;
596
597   do {
598     GHOST_TimerManager *timerMgr = getTimerManager();
599
600     if (waitForEvent && m_dirty_windows.empty() && !XPending(m_display)) {
601       GHOST_TUns64 next = timerMgr->nextFireTime();
602
603       if (next == GHOST_kFireTimeNever) {
604         SleepTillEvent(m_display, -1);
605       }
606       else {
607         GHOST_TInt64 maxSleep = next - getMilliSeconds();
608
609         if (maxSleep >= 0)
610           SleepTillEvent(m_display, next - getMilliSeconds());
611       }
612     }
613
614     if (timerMgr->fireTimers(getMilliSeconds())) {
615       anyProcessed = true;
616     }
617
618     while (XPending(m_display)) {
619       XEvent xevent;
620       XNextEvent(m_display, &xevent);
621
622 #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
623       /* open connection to XIM server and create input context (XIC)
624        * when receiving the first FocusIn or KeyPress event after startup,
625        * or recover XIM and XIC when the XIM server has been restarted */
626       if (xevent.type == FocusIn || xevent.type == KeyPress) {
627         if (!m_xim && openX11_IM()) {
628           GHOST_PRINT("Connected to XIM server\n");
629         }
630
631         if (m_xim) {
632           GHOST_WindowX11 *window = findGhostWindow(xevent.xany.window);
633           if (window && !window->getX11_XIC() && window->createX11_XIC()) {
634             GHOST_PRINT("XIM input context created\n");
635             if (xevent.type == KeyPress)
636               /* we can assume the window has input focus
637                * here, because key events are received only
638                * when the window is focused. */
639               XSetICFocus(window->getX11_XIC());
640           }
641         }
642       }
643
644       /* dispatch event to XIM server */
645       if ((XFilterEvent(&xevent, (Window)NULL) == True)) {
646         /* do nothing now, the event is consumed by XIM. */
647         continue;
648       }
649 #endif
650       /* when using autorepeat, some keypress events can actually come *after* the
651        * last keyrelease. The next code takes care of that */
652       if (xevent.type == KeyRelease) {
653         m_last_release_keycode = xevent.xkey.keycode;
654         m_last_release_time = xevent.xkey.time;
655       }
656       else if (xevent.type == KeyPress) {
657         if ((xevent.xkey.keycode == m_last_release_keycode) &&
658             ((xevent.xkey.time <= m_last_release_time)))
659           continue;
660       }
661
662       processEvent(&xevent);
663       anyProcessed = true;
664
665 #ifdef USE_UNITY_WORKAROUND
666       /* note: processEvent() can't include this code because
667        * KeymapNotify event have no valid window information. */
668
669       /* the X server generates KeymapNotify event immediately after
670        * every EnterNotify and FocusIn event.  we handle this event
671        * to correct modifier states. */
672       if (xevent.type == FocusIn) {
673         /* use previous event's window, because KeymapNotify event
674          * has no window information. */
675         GHOST_WindowX11 *window = findGhostWindow(xevent.xany.window);
676         if (window && XPending(m_display) >= 2) {
677           XNextEvent(m_display, &xevent);
678
679           if (xevent.type == KeymapNotify) {
680             XEvent xev_next;
681
682             /* check if KeyPress or KeyRelease event was generated
683              * in order to confirm the window is active. */
684             XPeekEvent(m_display, &xev_next);
685
686             if (xev_next.type == KeyPress || xev_next.type == KeyRelease) {
687               /* XK_Hyper_L/R currently unused */
688               const static KeySym modifiers[8] = {
689                   XK_Shift_L,
690                   XK_Shift_R,
691                   XK_Control_L,
692                   XK_Control_R,
693                   XK_Alt_L,
694                   XK_Alt_R,
695                   XK_Super_L,
696                   XK_Super_R,
697               };
698
699               for (int i = 0; i < (sizeof(modifiers) / sizeof(*modifiers)); i++) {
700                 KeyCode kc = XKeysymToKeycode(m_display, modifiers[i]);
701                 if (((xevent.xkeymap.key_vector[kc >> 3] >> (kc & 7)) & 1) != 0) {
702                   pushEvent(new GHOST_EventKey(getMilliSeconds(),
703                                                GHOST_kEventKeyDown,
704                                                window,
705                                                ghost_key_from_keysym(modifiers[i]),
706                                                '\0',
707                                                NULL));
708                 }
709               }
710             }
711           }
712         }
713       }
714 #endif /* USE_UNITY_WORKAROUND */
715     }
716
717     if (generateWindowExposeEvents()) {
718       anyProcessed = true;
719     }
720
721 #ifdef WITH_INPUT_NDOF
722     if (static_cast<GHOST_NDOFManagerUnix *>(m_ndofManager)->processEvents()) {
723       anyProcessed = true;
724     }
725 #endif
726
727   } while (waitForEvent && !anyProcessed);
728
729   return anyProcessed;
730 }
731
732 #ifdef WITH_X11_XINPUT
733 static bool checkTabletProximity(Display *display, XDevice *device)
734 {
735   /* we could have true/false/not-found return value, but for now false is OK */
736
737   /* see: state.c from xinput, to get more data out of the device */
738   XDeviceState *state;
739
740   if (device == NULL) {
741     return false;
742   }
743
744   /* needed since unplugging will abort() without this */
745   GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store);
746
747   state = XQueryDeviceState(display, device);
748
749   GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store);
750
751   if (state) {
752     XInputClass *cls = state->data;
753     // printf("%d class%s :\n", state->num_classes,
754     //       (state->num_classes > 1) ? "es" : "");
755     for (int loop = 0; loop < state->num_classes; loop++) {
756       switch (cls->c_class) {
757         case ValuatorClass:
758           XValuatorState *val_state = (XValuatorState *)cls;
759           // printf("ValuatorClass Mode=%s Proximity=%s\n",
760           //        val_state->mode & 1 ? "Absolute" : "Relative",
761           //        val_state->mode & 2 ? "Out" : "In");
762
763           if ((val_state->mode & 2) == 0) {
764             XFreeDeviceState(state);
765             return true;
766           }
767           break;
768       }
769       cls = (XInputClass *)((char *)cls + cls->length);
770     }
771     XFreeDeviceState(state);
772   }
773   return false;
774 }
775 #endif /* WITH_X11_XINPUT */
776
777 void GHOST_SystemX11::processEvent(XEvent *xe)
778 {
779   GHOST_WindowX11 *window = findGhostWindow(xe->xany.window);
780   GHOST_Event *g_event = NULL;
781
782 #ifdef USE_XINPUT_HOTPLUG
783   /* Hot-Plug support */
784   if (m_xinput_version.present) {
785     XEventClass class_presence;
786     int xi_presence;
787
788     DevicePresence(m_display, xi_presence, class_presence);
789     (void)class_presence;
790
791     if (xe->type == xi_presence) {
792       XDevicePresenceNotifyEvent *notify_event = (XDevicePresenceNotifyEvent *)xe;
793       if ((notify_event->devchange == DeviceEnabled) ||
794           (notify_event->devchange == DeviceDisabled) ||
795           (notify_event->devchange == DeviceAdded) || (notify_event->devchange == DeviceRemoved)) {
796         refreshXInputDevices();
797
798         /* update all window events */
799         {
800           vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
801           vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
802           vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
803
804           for (; win_it != win_end; ++win_it) {
805             GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it);
806             window->refreshXInputDevices();
807           }
808         }
809       }
810     }
811   }
812 #endif /* USE_XINPUT_HOTPLUG */
813
814   if (!window) {
815     return;
816   }
817
818 #ifdef WITH_X11_XINPUT
819   /* Proximity-Out Events are not reliable, if the tablet is active - check on each event
820    * this adds a little overhead but only while the tablet is in use.
821    * in the future we could have a ghost call window->CheckTabletProximity()
822    * but for now enough parts of the code are checking 'Active'
823    * - campbell */
824   if (window->GetTabletData()->Active != GHOST_kTabletModeNone) {
825     bool any_proximity = false;
826
827     for (GHOST_TabletX11 &xtablet : m_xtablets) {
828       if (checkTabletProximity(xe->xany.display, xtablet.Device)) {
829         any_proximity = true;
830       }
831     }
832
833     if (!any_proximity) {
834       // printf("proximity disable\n");
835       window->GetTabletData()->Active = GHOST_kTabletModeNone;
836     }
837   }
838 #endif /* WITH_X11_XINPUT */
839   switch (xe->type) {
840     case Expose: {
841       XExposeEvent &xee = xe->xexpose;
842
843       if (xee.count == 0) {
844         /* Only generate a single expose event
845          * per read of the event queue. */
846
847         g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window);
848       }
849       break;
850     }
851
852     case MotionNotify: {
853       XMotionEvent &xme = xe->xmotion;
854
855 #ifdef WITH_X11_XINPUT
856       bool is_tablet = window->GetTabletData()->Active != GHOST_kTabletModeNone;
857 #else
858       bool is_tablet = false;
859 #endif
860
861       if (is_tablet == false && window->getCursorGrabModeIsWarp()) {
862         GHOST_TInt32 x_new = xme.x_root;
863         GHOST_TInt32 y_new = xme.y_root;
864         GHOST_TInt32 x_accum, y_accum;
865         GHOST_Rect bounds;
866
867         /* fallback to window bounds */
868         if (window->getCursorGrabBounds(bounds) == GHOST_kFailure)
869           window->getClientBounds(bounds);
870
871         /* Could also clamp to screen bounds wrap with a window outside the view will fail atm.
872          * Use offset of 8 in case the window is at screen bounds. */
873         bounds.wrapPoint(x_new, y_new, 8, window->getCursorGrabAxis());
874
875         window->getCursorGrabAccum(x_accum, y_accum);
876
877         if (x_new != xme.x_root || y_new != xme.y_root) {
878           if (xme.time > m_last_warp) {
879             /* when wrapping we don't need to add an event because the
880              * setCursorPosition call will cause a new event after */
881             setCursorPosition(x_new, y_new); /* wrap */
882             window->setCursorGrabAccum(x_accum + (xme.x_root - x_new),
883                                        y_accum + (xme.y_root - y_new));
884             m_last_warp = lastEventTime(xme.time);
885           }
886           else {
887             setCursorPosition(x_new, y_new); /* wrap but don't accumulate */
888           }
889         }
890         else {
891           g_event = new GHOST_EventCursor(getMilliSeconds(),
892                                           GHOST_kEventCursorMove,
893                                           window,
894                                           xme.x_root + x_accum,
895                                           xme.y_root + y_accum);
896         }
897       }
898       else {
899         g_event = new GHOST_EventCursor(
900             getMilliSeconds(), GHOST_kEventCursorMove, window, xme.x_root, xme.y_root);
901       }
902       break;
903     }
904
905     case KeyPress:
906     case KeyRelease: {
907       XKeyEvent *xke = &(xe->xkey);
908       KeySym key_sym;
909       char ascii;
910 #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
911       /* utf8_array[] is initial buffer used for Xutf8LookupString().
912        * if the length of the utf8 string exceeds this array, allocate
913        * another memory area and call Xutf8LookupString() again.
914        * the last 5 bytes are used to avoid segfault that might happen
915        * at the end of this buffer when the constructor of GHOST_EventKey
916        * reads 6 bytes regardless of the effective data length. */
917       char utf8_array[16 * 6 + 5]; /* 16 utf8 characters */
918       char *utf8_buf = utf8_array;
919       int len = 1; /* at least one null character will be stored */
920 #else
921       char *utf8_buf = NULL;
922 #endif
923
924       GHOST_TEventType type = (xke->type == KeyPress) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp;
925
926       GHOST_TKey gkey;
927
928 #ifdef USE_NON_LATIN_KB_WORKAROUND
929       /* XXX Code below is kinda awfully convoluted... Issues are:
930        *
931        *     - In keyboards like latin ones, numbers need a 'Shift' to be accessed but key_sym
932        *       is unmodified (or anyone swapping the keys with xmodmap).
933        *
934        *     - XLookupKeysym seems to always use first defined keymap (see T47228), which generates
935        *       keycodes unusable by ghost_key_from_keysym for non-latin-compatible keymaps.
936        *
937        * To address this, we:
938        *
939        *     - Try to get a 'number' key_sym using XLookupKeysym (with virtual shift modifier),
940        *       in a very restrictive set of cases.
941        *     - Fallback to XLookupString to get a key_sym from active user-defined keymap.
942        *
943        * Note that:
944        *     - This effectively 'lock' main number keys to always output number events
945        *       (except when using alt-gr).
946        *     - This enforces users to use an ascii-compatible keymap with Blender -
947        *       but at least it gives predictable and consistent results.
948        *
949        * Also, note that nothing in XLib sources [1] makes it obvious why those two functions give
950        * different key_sym results...
951        *
952        * [1] http://cgit.freedesktop.org/xorg/lib/libX11/tree/src/KeyBind.c
953        */
954       KeySym key_sym_str;
955       /* Mode_switch 'modifier' is AltGr - when this one or Shift are enabled,
956        * we do not want to apply that 'forced number' hack. */
957       const unsigned int mode_switch_mask = XkbKeysymToModifiers(xke->display, XK_Mode_switch);
958       const unsigned int number_hack_forbidden_kmods_mask = mode_switch_mask | ShiftMask;
959       if ((xke->keycode >= 10 && xke->keycode < 20) &&
960           ((xke->state & number_hack_forbidden_kmods_mask) == 0)) {
961         key_sym = XLookupKeysym(xke, ShiftMask);
962         if (!((key_sym >= XK_0) && (key_sym <= XK_9))) {
963           key_sym = XLookupKeysym(xke, 0);
964         }
965       }
966       else {
967         key_sym = XLookupKeysym(xke, 0);
968       }
969
970       if (!XLookupString(xke, &ascii, 1, &key_sym_str, NULL)) {
971         ascii = '\0';
972       }
973
974       /* Only allow a limited set of keys from XLookupKeysym,
975        * all others we take from XLookupString, unless it gives unknown key... */
976       gkey = ghost_key_from_keysym_or_keycode(key_sym, m_xkb_descr, xke->keycode);
977       switch (gkey) {
978         case GHOST_kKeyRightAlt:
979         case GHOST_kKeyLeftAlt:
980         case GHOST_kKeyRightShift:
981         case GHOST_kKeyLeftShift:
982         case GHOST_kKeyRightControl:
983         case GHOST_kKeyLeftControl:
984         case GHOST_kKeyOS:
985         case GHOST_kKey0:
986         case GHOST_kKey1:
987         case GHOST_kKey2:
988         case GHOST_kKey3:
989         case GHOST_kKey4:
990         case GHOST_kKey5:
991         case GHOST_kKey6:
992         case GHOST_kKey7:
993         case GHOST_kKey8:
994         case GHOST_kKey9:
995         case GHOST_kKeyNumpad0:
996         case GHOST_kKeyNumpad1:
997         case GHOST_kKeyNumpad2:
998         case GHOST_kKeyNumpad3:
999         case GHOST_kKeyNumpad4:
1000         case GHOST_kKeyNumpad5:
1001         case GHOST_kKeyNumpad6:
1002         case GHOST_kKeyNumpad7:
1003         case GHOST_kKeyNumpad8:
1004         case GHOST_kKeyNumpad9:
1005         case GHOST_kKeyNumpadPeriod:
1006         case GHOST_kKeyNumpadEnter:
1007         case GHOST_kKeyNumpadPlus:
1008         case GHOST_kKeyNumpadMinus:
1009         case GHOST_kKeyNumpadAsterisk:
1010         case GHOST_kKeyNumpadSlash:
1011           break;
1012         default: {
1013           GHOST_TKey gkey_str = ghost_key_from_keysym(key_sym_str);
1014           if (gkey_str != GHOST_kKeyUnknown) {
1015             gkey = gkey_str;
1016           }
1017         }
1018       }
1019 #else
1020       /* In keyboards like latin ones,
1021        * numbers needs a 'Shift' to be accessed but key_sym
1022        * is unmodified (or anyone swapping the keys with xmodmap).
1023        *
1024        * Here we look at the 'Shifted' version of the key.
1025        * If it is a number, then we take it instead of the normal key.
1026        *
1027        * The modified key is sent in the 'ascii's variable anyway.
1028        */
1029       if ((xke->keycode >= 10 && xke->keycode < 20) &&
1030           ((key_sym = XLookupKeysym(xke, ShiftMask)) >= XK_0) && (key_sym <= XK_9)) {
1031         /* pass (keep shift'ed key_sym) */
1032       }
1033       else {
1034         /* regular case */
1035         key_sym = XLookupKeysym(xke, 0);
1036       }
1037
1038       gkey = ghost_key_from_keysym_or_keycode(key_sym, m_xkb_descr, xke->keycode);
1039
1040       if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
1041         ascii = '\0';
1042       }
1043 #endif
1044
1045 #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
1046       /* getting unicode on key-up events gives XLookupNone status */
1047       XIC xic = window->getX11_XIC();
1048       if (xic && xke->type == KeyPress) {
1049         Status status;
1050
1051         /* use utf8 because its not locale depentant, from xorg docs */
1052         if (!(len = Xutf8LookupString(
1053                   xic, xke, utf8_buf, sizeof(utf8_array) - 5, &key_sym, &status))) {
1054           utf8_buf[0] = '\0';
1055         }
1056
1057         if (status == XBufferOverflow) {
1058           utf8_buf = (char *)malloc(len + 5);
1059           len = Xutf8LookupString(xic, xke, utf8_buf, len, &key_sym, &status);
1060         }
1061
1062         if ((status == XLookupChars || status == XLookupBoth)) {
1063           if ((unsigned char)utf8_buf[0] >= 32) { /* not an ascii control character */
1064             /* do nothing for now, this is valid utf8 */
1065           }
1066           else {
1067             utf8_buf[0] = '\0';
1068           }
1069         }
1070         else if (status == XLookupKeySym) {
1071           /* this key doesn't have a text representation, it is a command
1072            * key of some sort */
1073         }
1074         else {
1075           printf("Bad keycode lookup. Keysym 0x%x Status: %s\n",
1076                  (unsigned int)key_sym,
1077                  (status == XLookupNone ?
1078                       "XLookupNone" :
1079                       status == XLookupKeySym ? "XLookupKeySym" : "Unknown status"));
1080
1081           printf("'%.*s' %p %p\n", len, utf8_buf, xic, m_xim);
1082         }
1083       }
1084       else {
1085         utf8_buf[0] = '\0';
1086       }
1087 #endif
1088
1089       g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, ascii, utf8_buf);
1090
1091 #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
1092       /* when using IM for some languages such as Japanese,
1093        * one event inserts multiple utf8 characters */
1094       if (xic && xke->type == KeyPress) {
1095         unsigned char c;
1096         int i = 0;
1097         while (1) {
1098           /* search character boundary */
1099           if ((unsigned char)utf8_buf[i++] > 0x7f) {
1100             for (; i < len; ++i) {
1101               c = utf8_buf[i];
1102               if (c < 0x80 || c > 0xbf)
1103                 break;
1104             }
1105           }
1106
1107           if (i >= len)
1108             break;
1109
1110           /* enqueue previous character */
1111           pushEvent(g_event);
1112
1113           g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, '\0', &utf8_buf[i]);
1114         }
1115       }
1116
1117       if (utf8_buf != utf8_array)
1118         free(utf8_buf);
1119 #endif
1120
1121       break;
1122     }
1123
1124     case ButtonPress:
1125     case ButtonRelease: {
1126       XButtonEvent &xbe = xe->xbutton;
1127       GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
1128       GHOST_TEventType type = (xbe.type == ButtonPress) ? GHOST_kEventButtonDown :
1129                                                           GHOST_kEventButtonUp;
1130
1131       /* process wheel mouse events and break, only pass on press events */
1132       if (xbe.button == Button4) {
1133         if (xbe.type == ButtonPress)
1134           g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1);
1135         break;
1136       }
1137       else if (xbe.button == Button5) {
1138         if (xbe.type == ButtonPress)
1139           g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1);
1140         break;
1141       }
1142
1143       /* process rest of normal mouse buttons */
1144       if (xbe.button == Button1)
1145         gbmask = GHOST_kButtonMaskLeft;
1146       else if (xbe.button == Button2)
1147         gbmask = GHOST_kButtonMaskMiddle;
1148       else if (xbe.button == Button3)
1149         gbmask = GHOST_kButtonMaskRight;
1150       /* It seems events 6 and 7 are for horizontal scrolling.
1151        * you can re-order button mapping like this... (swaps 6,7 with 8,9)
1152        *   xmodmap -e "pointer = 1 2 3 4 5 8 9 6 7"
1153        */
1154       else if (xbe.button == 6)
1155         gbmask = GHOST_kButtonMaskButton6;
1156       else if (xbe.button == 7)
1157         gbmask = GHOST_kButtonMaskButton7;
1158       else if (xbe.button == 8)
1159         gbmask = GHOST_kButtonMaskButton4;
1160       else if (xbe.button == 9)
1161         gbmask = GHOST_kButtonMaskButton5;
1162       else
1163         break;
1164
1165       g_event = new GHOST_EventButton(getMilliSeconds(), type, window, gbmask);
1166       break;
1167     }
1168
1169     /* change of size, border, layer etc. */
1170     case ConfigureNotify: {
1171       /* XConfigureEvent & xce = xe->xconfigure; */
1172
1173       g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window);
1174       break;
1175     }
1176
1177     case FocusIn:
1178     case FocusOut: {
1179       XFocusChangeEvent &xfe = xe->xfocus;
1180
1181       /* TODO: make sure this is the correct place for activate/deactivate */
1182       // printf("X: focus %s for window %d\n",
1183       //        xfe.type == FocusIn ? "in" : "out", (int) xfe.window);
1184
1185       /* May have to look at the type of event and filter some out. */
1186
1187       GHOST_TEventType gtype = (xfe.type == FocusIn) ? GHOST_kEventWindowActivate :
1188                                                        GHOST_kEventWindowDeactivate;
1189
1190 #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
1191       XIC xic = window->getX11_XIC();
1192       if (xic) {
1193         if (xe->type == FocusIn)
1194           XSetICFocus(xic);
1195         else
1196           XUnsetICFocus(xic);
1197       }
1198 #endif
1199
1200       g_event = new GHOST_Event(getMilliSeconds(), gtype, window);
1201       break;
1202     }
1203     case ClientMessage: {
1204       XClientMessageEvent &xcme = xe->xclient;
1205
1206       if (((Atom)xcme.data.l[0]) == m_atom.WM_DELETE_WINDOW) {
1207         g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window);
1208       }
1209       else if (((Atom)xcme.data.l[0]) == m_atom.WM_TAKE_FOCUS) {
1210         XWindowAttributes attr;
1211         Window fwin;
1212         int revert_to;
1213
1214         /* as ICCCM say, we need reply this event
1215          * with a SetInputFocus, the data[1] have
1216          * the valid timestamp (send by the wm).
1217          *
1218          * Some WM send this event before the
1219          * window is really mapped (for example
1220          * change from virtual desktop), so we need
1221          * to be sure that our windows is mapped
1222          * or this call fail and close blender.
1223          */
1224         if (XGetWindowAttributes(m_display, xcme.window, &attr) == True) {
1225           if (XGetInputFocus(m_display, &fwin, &revert_to) == True) {
1226             if (attr.map_state == IsViewable) {
1227               if (fwin != xcme.window)
1228                 XSetInputFocus(m_display, xcme.window, RevertToParent, xcme.data.l[1]);
1229             }
1230           }
1231         }
1232       }
1233       else {
1234 #ifdef WITH_XDND
1235         /* try to handle drag event
1236          * (if there's no such events, GHOST_HandleClientMessage will return zero) */
1237         if (window->getDropTarget()->GHOST_HandleClientMessage(xe) == false) {
1238           /* Unknown client message, ignore */
1239         }
1240 #else
1241         /* Unknown client message, ignore */
1242 #endif
1243       }
1244
1245       break;
1246     }
1247
1248     case DestroyNotify:
1249       ::exit(-1);
1250     /* We're not interested in the following things.(yet...) */
1251     case NoExpose:
1252     case GraphicsExpose:
1253       break;
1254
1255     case EnterNotify:
1256     case LeaveNotify: {
1257       /* XCrossingEvents pointer leave enter window.
1258        * also do cursor move here, MotionNotify only
1259        * happens when motion starts & ends inside window.
1260        * we only do moves when the crossing mode is 'normal'
1261        * (really crossing between windows) since some windowmanagers
1262        * also send grab/ungrab crossings for mousewheel events.
1263        */
1264       XCrossingEvent &xce = xe->xcrossing;
1265       if (xce.mode == NotifyNormal) {
1266         g_event = new GHOST_EventCursor(
1267             getMilliSeconds(), GHOST_kEventCursorMove, window, xce.x_root, xce.y_root);
1268       }
1269
1270       // printf("X: %s window %d\n",
1271       //        xce.type == EnterNotify ? "entering" : "leaving", (int) xce.window);
1272
1273       if (xce.type == EnterNotify)
1274         m_windowManager->setActiveWindow(window);
1275       else
1276         m_windowManager->setWindowInactive(window);
1277
1278       break;
1279     }
1280     case MapNotify:
1281       /*
1282        * From ICCCM:
1283        * [ Clients can select for StructureNotify on their
1284        *   top-level windows to track transition between
1285        *   Normal and Iconic states. Receipt of a MapNotify
1286        *   event will indicate a transition to the Normal
1287        *   state, and receipt of an UnmapNotify event will
1288        *   indicate a transition to the Iconic state. ]
1289        */
1290       if (window->m_post_init == True) {
1291         /*
1292          * Now we are sure that the window is
1293          * mapped, so only need change the state.
1294          */
1295         window->setState(window->m_post_state);
1296         window->m_post_init = False;
1297       }
1298       break;
1299     case UnmapNotify:
1300       break;
1301     case MappingNotify:
1302     case ReparentNotify:
1303       break;
1304     case SelectionRequest: {
1305       XEvent nxe;
1306       Atom target, utf8_string, string, compound_text, c_string;
1307       XSelectionRequestEvent *xse = &xe->xselectionrequest;
1308
1309       target = XInternAtom(m_display, "TARGETS", False);
1310       utf8_string = XInternAtom(m_display, "UTF8_STRING", False);
1311       string = XInternAtom(m_display, "STRING", False);
1312       compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False);
1313       c_string = XInternAtom(m_display, "C_STRING", False);
1314
1315       /* support obsolete clients */
1316       if (xse->property == None) {
1317         xse->property = xse->target;
1318       }
1319
1320       nxe.xselection.type = SelectionNotify;
1321       nxe.xselection.requestor = xse->requestor;
1322       nxe.xselection.property = xse->property;
1323       nxe.xselection.display = xse->display;
1324       nxe.xselection.selection = xse->selection;
1325       nxe.xselection.target = xse->target;
1326       nxe.xselection.time = xse->time;
1327
1328       /* Check to see if the requestor is asking for String */
1329       if (xse->target == utf8_string || xse->target == string || xse->target == compound_text ||
1330           xse->target == c_string) {
1331         if (xse->selection == XInternAtom(m_display, "PRIMARY", False)) {
1332           XChangeProperty(m_display,
1333                           xse->requestor,
1334                           xse->property,
1335                           xse->target,
1336                           8,
1337                           PropModeReplace,
1338                           (unsigned char *)txt_select_buffer,
1339                           strlen(txt_select_buffer));
1340         }
1341         else if (xse->selection == XInternAtom(m_display, "CLIPBOARD", False)) {
1342           XChangeProperty(m_display,
1343                           xse->requestor,
1344                           xse->property,
1345                           xse->target,
1346                           8,
1347                           PropModeReplace,
1348                           (unsigned char *)txt_cut_buffer,
1349                           strlen(txt_cut_buffer));
1350         }
1351       }
1352       else if (xse->target == target) {
1353         Atom alist[5];
1354         alist[0] = target;
1355         alist[1] = utf8_string;
1356         alist[2] = string;
1357         alist[3] = compound_text;
1358         alist[4] = c_string;
1359         XChangeProperty(m_display,
1360                         xse->requestor,
1361                         xse->property,
1362                         xse->target,
1363                         32,
1364                         PropModeReplace,
1365                         (unsigned char *)alist,
1366                         5);
1367         XFlush(m_display);
1368       }
1369       else {
1370         /* Change property to None because we do not support anything but STRING */
1371         nxe.xselection.property = None;
1372       }
1373
1374       /* Send the event to the client 0 0 == False, SelectionNotify */
1375       XSendEvent(m_display, xse->requestor, 0, 0, &nxe);
1376       XFlush(m_display);
1377       break;
1378     }
1379
1380     default: {
1381 #ifdef WITH_X11_XINPUT
1382       for (GHOST_TabletX11 &xtablet : m_xtablets) {
1383         if (xe->type == xtablet.MotionEvent || xe->type == xtablet.PressEvent) {
1384           XDeviceMotionEvent *data = (XDeviceMotionEvent *)xe;
1385           if (data->deviceid != xtablet.ID) {
1386             continue;
1387           }
1388
1389           const unsigned char axis_first = data->first_axis;
1390           const unsigned char axes_end = axis_first + data->axes_count; /* after the last */
1391           int axis_value;
1392
1393           /* stroke might begin without leading ProxyIn event,
1394            * this happens when window is opened when stylus is already hovering
1395            * around tablet surface */
1396           window->GetTabletData()->Active = xtablet.mode;
1397
1398           /* Note: This event might be generated with incomplete dataset
1399            * (don't exactly know why, looks like in some cases, if the value does not change,
1400            * it is not included in subsequent XDeviceMotionEvent events).
1401            * So we have to check which values this event actually contains!
1402            */
1403
1404 #  define AXIS_VALUE_GET(axis, val) \
1405     ((axis_first <= axis && axes_end > axis) && \
1406      ((void)(val = data->axis_data[axis - axis_first]), true))
1407
1408           if (AXIS_VALUE_GET(2, axis_value)) {
1409             window->GetTabletData()->Pressure = axis_value / ((float)xtablet.PressureLevels);
1410           }
1411
1412           /* the (short) cast and the & 0xffff is bizarre and unexplained anywhere,
1413            * but I got garbage data without it. Found it in the xidump.c source --matt
1414            *
1415            * The '& 0xffff' just truncates the value to its two lowest bytes, this probably means
1416            * some drivers do not properly set the whole int value? Since we convert to float
1417            * afterward, I don't think we need to cast to short here, but do not have a device to
1418            * check this. --mont29
1419            */
1420           if (AXIS_VALUE_GET(3, axis_value)) {
1421             window->GetTabletData()->Xtilt = (short)(axis_value & 0xffff) /
1422                                              ((float)xtablet.XtiltLevels);
1423           }
1424           if (AXIS_VALUE_GET(4, axis_value)) {
1425             window->GetTabletData()->Ytilt = (short)(axis_value & 0xffff) /
1426                                              ((float)xtablet.YtiltLevels);
1427           }
1428
1429 #  undef AXIS_VALUE_GET
1430         }
1431         else if (xe->type == xtablet.ProxInEvent) {
1432           XProximityNotifyEvent *data = (XProximityNotifyEvent *)xe;
1433           if (data->deviceid != xtablet.ID) {
1434             continue;
1435           }
1436
1437           window->GetTabletData()->Active = xtablet.mode;
1438         }
1439         else if (xe->type == xtablet.ProxOutEvent) {
1440           window->GetTabletData()->Active = GHOST_kTabletModeNone;
1441         }
1442       }
1443 #endif  // WITH_X11_XINPUT
1444       break;
1445     }
1446   }
1447
1448   if (g_event) {
1449     pushEvent(g_event);
1450   }
1451 }
1452
1453 GHOST_TSuccess GHOST_SystemX11::getModifierKeys(GHOST_ModifierKeys &keys) const
1454 {
1455
1456   /* analyse the masks retuned from XQueryPointer. */
1457
1458   memset((void *)m_keyboard_vector, 0, sizeof(m_keyboard_vector));
1459
1460   XQueryKeymap(m_display, (char *)m_keyboard_vector);
1461
1462   /* now translate key symbols into keycodes and
1463    * test with vector. */
1464
1465   const static KeyCode shift_l = XKeysymToKeycode(m_display, XK_Shift_L);
1466   const static KeyCode shift_r = XKeysymToKeycode(m_display, XK_Shift_R);
1467   const static KeyCode control_l = XKeysymToKeycode(m_display, XK_Control_L);
1468   const static KeyCode control_r = XKeysymToKeycode(m_display, XK_Control_R);
1469   const static KeyCode alt_l = XKeysymToKeycode(m_display, XK_Alt_L);
1470   const static KeyCode alt_r = XKeysymToKeycode(m_display, XK_Alt_R);
1471   const static KeyCode super_l = XKeysymToKeycode(m_display, XK_Super_L);
1472   const static KeyCode super_r = XKeysymToKeycode(m_display, XK_Super_R);
1473
1474   /* shift */
1475   keys.set(GHOST_kModifierKeyLeftShift,
1476            ((m_keyboard_vector[shift_l >> 3] >> (shift_l & 7)) & 1) != 0);
1477   keys.set(GHOST_kModifierKeyRightShift,
1478            ((m_keyboard_vector[shift_r >> 3] >> (shift_r & 7)) & 1) != 0);
1479   /* control */
1480   keys.set(GHOST_kModifierKeyLeftControl,
1481            ((m_keyboard_vector[control_l >> 3] >> (control_l & 7)) & 1) != 0);
1482   keys.set(GHOST_kModifierKeyRightControl,
1483            ((m_keyboard_vector[control_r >> 3] >> (control_r & 7)) & 1) != 0);
1484   /* alt */
1485   keys.set(GHOST_kModifierKeyLeftAlt, ((m_keyboard_vector[alt_l >> 3] >> (alt_l & 7)) & 1) != 0);
1486   keys.set(GHOST_kModifierKeyRightAlt, ((m_keyboard_vector[alt_r >> 3] >> (alt_r & 7)) & 1) != 0);
1487   /* super (windows) - only one GHOST-kModifierKeyOS, so mapping to either */
1488   keys.set(GHOST_kModifierKeyOS,
1489            (((m_keyboard_vector[super_l >> 3] >> (super_l & 7)) & 1) ||
1490             ((m_keyboard_vector[super_r >> 3] >> (super_r & 7)) & 1)) != 0);
1491
1492   return GHOST_kSuccess;
1493 }
1494
1495 GHOST_TSuccess GHOST_SystemX11::getButtons(GHOST_Buttons &buttons) const
1496 {
1497   Window root_return, child_return;
1498   int rx, ry, wx, wy;
1499   unsigned int mask_return;
1500
1501   if (XQueryPointer(m_display,
1502                     RootWindow(m_display, DefaultScreen(m_display)),
1503                     &root_return,
1504                     &child_return,
1505                     &rx,
1506                     &ry,
1507                     &wx,
1508                     &wy,
1509                     &mask_return) == True) {
1510     buttons.set(GHOST_kButtonMaskLeft, (mask_return & Button1Mask) != 0);
1511     buttons.set(GHOST_kButtonMaskMiddle, (mask_return & Button2Mask) != 0);
1512     buttons.set(GHOST_kButtonMaskRight, (mask_return & Button3Mask) != 0);
1513   }
1514   else {
1515     return GHOST_kFailure;
1516   }
1517
1518   return GHOST_kSuccess;
1519 }
1520
1521 static GHOST_TSuccess getCursorPosition_impl(Display *display,
1522                                              GHOST_TInt32 &x,
1523                                              GHOST_TInt32 &y,
1524                                              Window *child_return)
1525 {
1526   int rx, ry, wx, wy;
1527   unsigned int mask_return;
1528   Window root_return;
1529
1530   if (XQueryPointer(display,
1531                     RootWindow(display, DefaultScreen(display)),
1532                     &root_return,
1533                     child_return,
1534                     &rx,
1535                     &ry,
1536                     &wx,
1537                     &wy,
1538                     &mask_return) == False) {
1539     return GHOST_kFailure;
1540   }
1541   else {
1542     x = rx;
1543     y = ry;
1544   }
1545   return GHOST_kSuccess;
1546 }
1547
1548 GHOST_TSuccess GHOST_SystemX11::getCursorPosition(GHOST_TInt32 &x, GHOST_TInt32 &y) const
1549 {
1550   Window child_return;
1551   return getCursorPosition_impl(m_display, x, y, &child_return);
1552 }
1553
1554 GHOST_TSuccess GHOST_SystemX11::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y)
1555 {
1556
1557   /* This is a brute force move in screen coordinates
1558    * XWarpPointer does relative moves so first determine the
1559    * current pointer position. */
1560
1561   int cx, cy;
1562
1563 #ifdef WITH_XWAYLAND_HACK
1564   Window child_return = None;
1565   if (getCursorPosition_impl(m_display, cx, cy, &child_return) == GHOST_kFailure) {
1566     return GHOST_kFailure;
1567   }
1568 #else
1569   if (getCursorPosition(cx, cy) == GHOST_kFailure) {
1570     return GHOST_kFailure;
1571   }
1572 #endif
1573
1574   int relx = x - cx;
1575   int rely = y - cy;
1576
1577 #ifdef WITH_XWAYLAND_HACK
1578   if (use_xwayland_hack) {
1579     if (child_return != None) {
1580       XFixesHideCursor(m_display, child_return);
1581     }
1582   }
1583 #endif
1584
1585 #if defined(WITH_X11_XINPUT) && defined(USE_X11_XINPUT_WARP)
1586   if ((m_xinput_version.present) && (m_xinput_version.major_version >= 2)) {
1587     /* Needed to account for XInput "Coordinate Transformation Matrix", see T48901 */
1588     int device_id;
1589     if (XIGetClientPointer(m_display, None, &device_id) != False) {
1590       XIWarpPointer(m_display, device_id, None, None, 0, 0, 0, 0, relx, rely);
1591     }
1592   }
1593   else
1594 #endif
1595   {
1596     XWarpPointer(m_display, None, None, 0, 0, 0, 0, relx, rely);
1597   }
1598
1599 #ifdef WITH_XWAYLAND_HACK
1600   if (use_xwayland_hack) {
1601     if (child_return != None) {
1602       XFixesShowCursor(m_display, child_return);
1603     }
1604   }
1605 #endif
1606
1607   XSync(m_display, 0); /* Sync to process all requests */
1608
1609   return GHOST_kSuccess;
1610 }
1611
1612 void GHOST_SystemX11::addDirtyWindow(GHOST_WindowX11 *bad_wind)
1613 {
1614   GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
1615
1616   m_dirty_windows.push_back(bad_wind);
1617 }
1618
1619 bool GHOST_SystemX11::generateWindowExposeEvents()
1620 {
1621   vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
1622   vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
1623   bool anyProcessed = false;
1624
1625   for (; w_start != w_end; ++w_start) {
1626     GHOST_Event *g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, *w_start);
1627
1628     (*w_start)->validate();
1629
1630     if (g_event) {
1631       pushEvent(g_event);
1632       anyProcessed = true;
1633     }
1634   }
1635
1636   m_dirty_windows.clear();
1637   return anyProcessed;
1638 }
1639
1640 static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym keysym,
1641                                                    XkbDescPtr xkb_descr,
1642                                                    const KeyCode keycode)
1643 {
1644   GHOST_TKey type = ghost_key_from_keysym(keysym);
1645   if (type == GHOST_kKeyUnknown) {
1646     if (xkb_descr) {
1647       type = ghost_key_from_keycode(xkb_descr, keycode);
1648     }
1649   }
1650   return type;
1651 }
1652
1653 #define GXMAP(k, x, y) \
1654   case x: \
1655     k = y; \
1656     break
1657
1658 static GHOST_TKey ghost_key_from_keysym(const KeySym key)
1659 {
1660   GHOST_TKey type;
1661
1662   if ((key >= XK_A) && (key <= XK_Z)) {
1663     type = GHOST_TKey(key - XK_A + int(GHOST_kKeyA));
1664   }
1665   else if ((key >= XK_a) && (key <= XK_z)) {
1666     type = GHOST_TKey(key - XK_a + int(GHOST_kKeyA));
1667   }
1668   else if ((key >= XK_0) && (key <= XK_9)) {
1669     type = GHOST_TKey(key - XK_0 + int(GHOST_kKey0));
1670   }
1671   else if ((key >= XK_F1) && (key <= XK_F24)) {
1672     type = GHOST_TKey(key - XK_F1 + int(GHOST_kKeyF1));
1673   }
1674   else {
1675     switch (key) {
1676       GXMAP(type, XK_BackSpace, GHOST_kKeyBackSpace);
1677       GXMAP(type, XK_Tab, GHOST_kKeyTab);
1678       GXMAP(type, XK_ISO_Left_Tab, GHOST_kKeyTab);
1679       GXMAP(type, XK_Return, GHOST_kKeyEnter);
1680       GXMAP(type, XK_Escape, GHOST_kKeyEsc);
1681       GXMAP(type, XK_space, GHOST_kKeySpace);
1682
1683       GXMAP(type, XK_Linefeed, GHOST_kKeyLinefeed);
1684       GXMAP(type, XK_semicolon, GHOST_kKeySemicolon);
1685       GXMAP(type, XK_period, GHOST_kKeyPeriod);
1686       GXMAP(type, XK_comma, GHOST_kKeyComma);
1687       GXMAP(type, XK_quoteright, GHOST_kKeyQuote);
1688       GXMAP(type, XK_quoteleft, GHOST_kKeyAccentGrave);
1689       GXMAP(type, XK_minus, GHOST_kKeyMinus);
1690       GXMAP(type, XK_plus, GHOST_kKeyPlus);
1691       GXMAP(type, XK_slash, GHOST_kKeySlash);
1692       GXMAP(type, XK_backslash, GHOST_kKeyBackslash);
1693       GXMAP(type, XK_equal, GHOST_kKeyEqual);
1694       GXMAP(type, XK_bracketleft, GHOST_kKeyLeftBracket);
1695       GXMAP(type, XK_bracketright, GHOST_kKeyRightBracket);
1696       GXMAP(type, XK_Pause, GHOST_kKeyPause);
1697
1698       GXMAP(type, XK_Shift_L, GHOST_kKeyLeftShift);
1699       GXMAP(type, XK_Shift_R, GHOST_kKeyRightShift);
1700       GXMAP(type, XK_Control_L, GHOST_kKeyLeftControl);
1701       GXMAP(type, XK_Control_R, GHOST_kKeyRightControl);
1702       GXMAP(type, XK_Alt_L, GHOST_kKeyLeftAlt);
1703       GXMAP(type, XK_Alt_R, GHOST_kKeyRightAlt);
1704       GXMAP(type, XK_Super_L, GHOST_kKeyOS);
1705       GXMAP(type, XK_Super_R, GHOST_kKeyOS);
1706
1707       GXMAP(type, XK_Insert, GHOST_kKeyInsert);
1708       GXMAP(type, XK_Delete, GHOST_kKeyDelete);
1709       GXMAP(type, XK_Home, GHOST_kKeyHome);
1710       GXMAP(type, XK_End, GHOST_kKeyEnd);
1711       GXMAP(type, XK_Page_Up, GHOST_kKeyUpPage);
1712       GXMAP(type, XK_Page_Down, GHOST_kKeyDownPage);
1713
1714       GXMAP(type, XK_Left, GHOST_kKeyLeftArrow);
1715       GXMAP(type, XK_Right, GHOST_kKeyRightArrow);
1716       GXMAP(type, XK_Up, GHOST_kKeyUpArrow);
1717       GXMAP(type, XK_Down, GHOST_kKeyDownArrow);
1718
1719       GXMAP(type, XK_Caps_Lock, GHOST_kKeyCapsLock);
1720       GXMAP(type, XK_Scroll_Lock, GHOST_kKeyScrollLock);
1721       GXMAP(type, XK_Num_Lock, GHOST_kKeyNumLock);
1722
1723       /* keypad events */
1724
1725       GXMAP(type, XK_KP_0, GHOST_kKeyNumpad0);
1726       GXMAP(type, XK_KP_1, GHOST_kKeyNumpad1);
1727       GXMAP(type, XK_KP_2, GHOST_kKeyNumpad2);
1728       GXMAP(type, XK_KP_3, GHOST_kKeyNumpad3);
1729       GXMAP(type, XK_KP_4, GHOST_kKeyNumpad4);
1730       GXMAP(type, XK_KP_5, GHOST_kKeyNumpad5);
1731       GXMAP(type, XK_KP_6, GHOST_kKeyNumpad6);
1732       GXMAP(type, XK_KP_7, GHOST_kKeyNumpad7);
1733       GXMAP(type, XK_KP_8, GHOST_kKeyNumpad8);
1734       GXMAP(type, XK_KP_9, GHOST_kKeyNumpad9);
1735       GXMAP(type, XK_KP_Decimal, GHOST_kKeyNumpadPeriod);
1736
1737       GXMAP(type, XK_KP_Insert, GHOST_kKeyNumpad0);
1738       GXMAP(type, XK_KP_End, GHOST_kKeyNumpad1);
1739       GXMAP(type, XK_KP_Down, GHOST_kKeyNumpad2);
1740       GXMAP(type, XK_KP_Page_Down, GHOST_kKeyNumpad3);
1741       GXMAP(type, XK_KP_Left, GHOST_kKeyNumpad4);
1742       GXMAP(type, XK_KP_Begin, GHOST_kKeyNumpad5);
1743       GXMAP(type, XK_KP_Right, GHOST_kKeyNumpad6);
1744       GXMAP(type, XK_KP_Home, GHOST_kKeyNumpad7);
1745       GXMAP(type, XK_KP_Up, GHOST_kKeyNumpad8);
1746       GXMAP(type, XK_KP_Page_Up, GHOST_kKeyNumpad9);
1747       GXMAP(type, XK_KP_Delete, GHOST_kKeyNumpadPeriod);
1748
1749       GXMAP(type, XK_KP_Enter, GHOST_kKeyNumpadEnter);
1750       GXMAP(type, XK_KP_Add, GHOST_kKeyNumpadPlus);
1751       GXMAP(type, XK_KP_Subtract, GHOST_kKeyNumpadMinus);
1752       GXMAP(type, XK_KP_Multiply, GHOST_kKeyNumpadAsterisk);
1753       GXMAP(type, XK_KP_Divide, GHOST_kKeyNumpadSlash);
1754
1755       /* Media keys in some keyboards and laptops with XFree86/Xorg */
1756 #ifdef WITH_XF86KEYSYM
1757       GXMAP(type, XF86XK_AudioPlay, GHOST_kKeyMediaPlay);
1758       GXMAP(type, XF86XK_AudioStop, GHOST_kKeyMediaStop);
1759       GXMAP(type, XF86XK_AudioPrev, GHOST_kKeyMediaFirst);
1760       GXMAP(type, XF86XK_AudioRewind, GHOST_kKeyMediaFirst);
1761       GXMAP(type, XF86XK_AudioNext, GHOST_kKeyMediaLast);
1762 #  ifdef XF86XK_AudioForward /* Debian lenny's XF86keysym.h has no XF86XK_AudioForward define */
1763       GXMAP(type, XF86XK_AudioForward, GHOST_kKeyMediaLast);
1764 #  endif
1765 #endif
1766       default:
1767 #ifdef GHOST_DEBUG
1768         printf("%s: unknown key: %lu / 0x%lx\n", __func__, key, key);
1769 #endif
1770         type = GHOST_kKeyUnknown;
1771         break;
1772     }
1773   }
1774
1775   return type;
1776 }
1777
1778 #undef GXMAP
1779
1780 #define MAKE_ID(a, b, c, d) ((int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a))
1781
1782 static GHOST_TKey ghost_key_from_keycode(const XkbDescPtr xkb_descr, const KeyCode keycode)
1783 {
1784   GHOST_ASSERT(XkbKeyNameLength == 4, "Name length is invalid!");
1785   if (keycode >= xkb_descr->min_key_code && keycode <= xkb_descr->max_key_code) {
1786     const char *id_str = xkb_descr->names->keys[keycode].name;
1787     const uint32_t id = MAKE_ID(id_str[0], id_str[1], id_str[2], id_str[3]);
1788     switch (id) {
1789       case MAKE_ID('T', 'L', 'D', 'E'):
1790         return GHOST_kKeyAccentGrave;
1791 #ifdef GHOST_DEBUG
1792       default:
1793         printf("%s unhandled keycode: %.*s\n", __func__, XkbKeyNameLength, id_str);
1794         break;
1795 #endif
1796     }
1797   }
1798   else if (keycode != 0) {
1799     GHOST_ASSERT(false, "KeyCode out of range!");
1800   }
1801   return GHOST_kKeyUnknown;
1802 }
1803
1804 #undef MAKE_ID
1805
1806 /* from xclip.c xcout() v0.11 */
1807
1808 #define XCLIB_XCOUT_NONE 0          /* no context */
1809 #define XCLIB_XCOUT_SENTCONVSEL 1   /* sent a request */
1810 #define XCLIB_XCOUT_INCR 2          /* in an incr loop */
1811 #define XCLIB_XCOUT_FALLBACK 3      /* STRING failed, need fallback to UTF8 */
1812 #define XCLIB_XCOUT_FALLBACK_UTF8 4 /* UTF8 failed, move to compouned */
1813 #define XCLIB_XCOUT_FALLBACK_COMP 5 /* compouned failed, move to text. */
1814 #define XCLIB_XCOUT_FALLBACK_TEXT 6
1815
1816 /* Retrieves the contents of a selections. */
1817 void GHOST_SystemX11::getClipboard_xcout(const XEvent *evt,
1818                                          Atom sel,
1819                                          Atom target,
1820                                          unsigned char **txt,
1821                                          unsigned long *len,
1822                                          unsigned int *context) const
1823 {
1824   Atom pty_type;
1825   int pty_format;
1826   unsigned char *buffer;
1827   unsigned long pty_size, pty_items;
1828   unsigned char *ltxt = *txt;
1829
1830   vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
1831   vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
1832   GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it);
1833   Window win = window->getXWindow();
1834
1835   switch (*context) {
1836     /* There is no context, do an XConvertSelection() */
1837     case XCLIB_XCOUT_NONE:
1838       /* Initialise return length to 0 */
1839       if (*len > 0) {
1840         free(*txt);
1841         *len = 0;
1842       }
1843
1844       /* Send a selection request */
1845       XConvertSelection(m_display, sel, target, m_atom.XCLIP_OUT, win, CurrentTime);
1846       *context = XCLIB_XCOUT_SENTCONVSEL;
1847       return;
1848
1849     case XCLIB_XCOUT_SENTCONVSEL:
1850       if (evt->type != SelectionNotify)
1851         return;
1852
1853       if (target == m_atom.UTF8_STRING && evt->xselection.property == None) {
1854         *context = XCLIB_XCOUT_FALLBACK_UTF8;
1855         return;
1856       }
1857       else if (target == m_atom.COMPOUND_TEXT && evt->xselection.property == None) {
1858         *context = XCLIB_XCOUT_FALLBACK_COMP;
1859         return;
1860       }
1861       else if (target == m_atom.TEXT && evt->xselection.property == None) {
1862         *context = XCLIB_XCOUT_FALLBACK_TEXT;
1863         return;
1864       }
1865
1866       /* find the size and format of the data in property */
1867       XGetWindowProperty(m_display,
1868                          win,
1869                          m_atom.XCLIP_OUT,
1870                          0,
1871                          0,
1872                          False,
1873                          AnyPropertyType,
1874                          &pty_type,
1875                          &pty_format,
1876                          &pty_items,
1877                          &pty_size,
1878                          &buffer);
1879       XFree(buffer);
1880
1881       if (pty_type == m_atom.INCR) {
1882         /* start INCR mechanism by deleting property */
1883         XDeleteProperty(m_display, win, m_atom.XCLIP_OUT);
1884         XFlush(m_display);
1885         *context = XCLIB_XCOUT_INCR;
1886         return;
1887       }
1888
1889       /* if it's not incr, and not format == 8, then there's
1890        * nothing in the selection (that xclip understands, anyway) */
1891
1892       if (pty_format != 8) {
1893         *context = XCLIB_XCOUT_NONE;
1894         return;
1895       }
1896
1897       // not using INCR mechanism, just read the property
1898       XGetWindowProperty(m_display,
1899                          win,
1900                          m_atom.XCLIP_OUT,
1901                          0,
1902                          (long)pty_size,
1903                          False,
1904                          AnyPropertyType,
1905                          &pty_type,
1906                          &pty_format,
1907                          &pty_items,
1908                          &pty_size,
1909                          &buffer);
1910
1911       /* finished with property, delete it */
1912       XDeleteProperty(m_display, win, m_atom.XCLIP_OUT);
1913
1914       /* copy the buffer to the pointer for returned data */
1915       ltxt = (unsigned char *)malloc(pty_items);
1916       memcpy(ltxt, buffer, pty_items);
1917
1918       /* set the length of the returned data */
1919       *len = pty_items;
1920       *txt = ltxt;
1921
1922       /* free the buffer */
1923       XFree(buffer);
1924
1925       *context = XCLIB_XCOUT_NONE;
1926
1927       /* complete contents of selection fetched, return 1 */
1928       return;
1929
1930     case XCLIB_XCOUT_INCR:
1931       /* To use the INCR method, we basically delete the
1932        * property with the selection in it, wait for an
1933        * event indicating that the property has been created,
1934        * then read it, delete it, etc. */
1935
1936       /* make sure that the event is relevant */
1937       if (evt->type != PropertyNotify)
1938         return;
1939
1940       /* skip unless the property has a new value */
1941       if (evt->xproperty.state != PropertyNewValue)
1942         return;
1943
1944       /* check size and format of the property */
1945       XGetWindowProperty(m_display,
1946                          win,
1947                          m_atom.XCLIP_OUT,
1948                          0,
1949                          0,
1950                          False,
1951                          AnyPropertyType,
1952                          &pty_type,
1953                          &pty_format,
1954                          &pty_items,
1955                          &pty_size,
1956                          &buffer);
1957
1958       if (pty_format != 8) {
1959         /* property does not contain text, delete it
1960          * to tell the other X client that we have read
1961          * it and to send the next property */
1962         XFree(buffer);
1963         XDeleteProperty(m_display, win, m_atom.XCLIP_OUT);
1964         return;
1965       }
1966
1967       if (pty_size == 0) {
1968         /* no more data, exit from loop */
1969         XFree(buffer);
1970         XDeleteProperty(m_display, win, m_atom.XCLIP_OUT);
1971         *context = XCLIB_XCOUT_NONE;
1972
1973         /* this means that an INCR transfer is now
1974          * complete, return 1 */
1975         return;
1976       }
1977
1978       XFree(buffer);
1979
1980       /* if we have come this far, the property contains
1981        * text, we know the size. */
1982       XGetWindowProperty(m_display,
1983                          win,
1984                          m_atom.XCLIP_OUT,
1985                          0,
1986                          (long)pty_size,
1987                          False,
1988                          AnyPropertyType,
1989                          &pty_type,
1990                          &pty_format,
1991                          &pty_items,
1992                          &pty_size,
1993                          &buffer);
1994
1995       /* allocate memory to accommodate data in *txt */
1996       if (*len == 0) {
1997         *len = pty_items;
1998         ltxt = (unsigned char *)malloc(*len);
1999       }
2000       else {
2001         *len += pty_items;
2002         ltxt = (unsigned char *)realloc(ltxt, *len);
2003       }
2004
2005       /* add data to ltxt */
2006       memcpy(&ltxt[*len - pty_items], buffer, pty_items);
2007
2008       *txt = ltxt;
2009       XFree(buffer);
2010
2011       /* delete property to get the next item */
2012       XDeleteProperty(m_display, win, m_atom.XCLIP_OUT);
2013       XFlush(m_display);
2014       return;
2015   }
2016   return;
2017 }
2018
2019 GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const
2020 {
2021   Atom sseln;
2022   Atom target = m_atom.UTF8_STRING;
2023   Window owner;
2024
2025   /* from xclip.c doOut() v0.11 */
2026   unsigned char *sel_buf;
2027   unsigned long sel_len = 0;
2028   XEvent evt;
2029   unsigned int context = XCLIB_XCOUT_NONE;
2030
2031   if (selection == True)
2032     sseln = m_atom.PRIMARY;
2033   else
2034     sseln = m_atom.CLIPBOARD;
2035
2036   vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
2037   vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
2038   GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it);
2039   Window win = window->getXWindow();
2040
2041   /* check if we are the owner. */
2042   owner = XGetSelectionOwner(m_display, sseln);
2043   if (owner == win) {
2044     if (sseln == m_atom.CLIPBOARD) {
2045       sel_buf = (unsigned char *)malloc(strlen(txt_cut_buffer) + 1);
2046       strcpy((char *)sel_buf, txt_cut_buffer);
2047       return sel_buf;
2048     }
2049     else {
2050       sel_buf = (unsigned char *)malloc(strlen(txt_select_buffer) + 1);
2051       strcpy((char *)sel_buf, txt_select_buffer);
2052       return sel_buf;
2053     }
2054   }
2055   else if (owner == None)
2056     return (NULL);
2057
2058   while (1) {
2059     /* only get an event if xcout() is doing something */
2060     if (context != XCLIB_XCOUT_NONE)
2061       XNextEvent(m_display, &evt);
2062
2063     /* fetch the selection, or part of it */
2064     getClipboard_xcout(&evt, sseln, target, &sel_buf, &sel_len, &context);
2065
2066     /* fallback is needed. set XA_STRING to target and restart the loop. */
2067     if (context == XCLIB_XCOUT_FALLBACK) {
2068       context = XCLIB_XCOUT_NONE;
2069       target = m_atom.STRING;
2070       continue;
2071     }
2072     else if (context == XCLIB_XCOUT_FALLBACK_UTF8) {
2073       /* utf8 fail, move to compouned text. */
2074       context = XCLIB_XCOUT_NONE;
2075       target = m_atom.COMPOUND_TEXT;
2076       continue;
2077     }
2078     else if (context == XCLIB_XCOUT_FALLBACK_COMP) {
2079       /* compouned text fail, move to text. */
2080       context = XCLIB_XCOUT_NONE;
2081       target = m_atom.TEXT;
2082       continue;
2083     }
2084     else if (context == XCLIB_XCOUT_FALLBACK_TEXT) {
2085       /* text fail, nothing else to try, break. */
2086       context = XCLIB_XCOUT_NONE;
2087     }
2088
2089     /* only continue if xcout() is doing something */
2090     if (context == XCLIB_XCOUT_NONE)
2091       break;
2092   }
2093
2094   if (sel_len) {
2095     /* only print the buffer out, and free it, if it's not
2096      * empty
2097      */
2098     unsigned char *tmp_data = (unsigned char *)malloc(sel_len + 1);
2099     memcpy((char *)tmp_data, (char *)sel_buf, sel_len);
2100     tmp_data[sel_len] = '\0';
2101
2102     if (sseln == m_atom.STRING)
2103       XFree(sel_buf);
2104     else
2105       free(sel_buf);
2106
2107     return tmp_data;
2108   }
2109   return (NULL);
2110 }
2111
2112 void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const
2113 {
2114   Window m_window, owner;
2115
2116   vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
2117   vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
2118   GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it);
2119   m_window = window->getXWindow();
2120
2121   if (buffer) {
2122     if (selection == False) {
2123       XSetSelectionOwner(m_display, m_atom.CLIPBOARD, m_window, CurrentTime);
2124       owner = XGetSelectionOwner(m_display, m_atom.CLIPBOARD);
2125       if (txt_cut_buffer)
2126         free((void *)txt_cut_buffer);
2127
2128       txt_cut_buffer = (char *)malloc(strlen(buffer) + 1);
2129       strcpy(txt_cut_buffer, buffer);
2130     }
2131     else {
2132       XSetSelectionOwner(m_display, m_atom.PRIMARY, m_window, CurrentTime);
2133       owner = XGetSelectionOwner(m_display, m_atom.PRIMARY);
2134       if (txt_select_buffer)
2135         free((void *)txt_select_buffer);
2136
2137       txt_select_buffer = (char *)malloc(strlen(buffer) + 1);
2138       strcpy(txt_select_buffer, buffer);
2139     }
2140
2141     if (owner != m_window)
2142       fprintf(stderr, "failed to own primary\n");
2143   }
2144 }
2145
2146 #ifdef WITH_XDND
2147 GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType,
2148                                                   GHOST_TDragnDropTypes draggedObjectType,
2149                                                   GHOST_IWindow *window,
2150                                                   int mouseX,
2151                                                   int mouseY,
2152                                                   void *data)
2153 {
2154   GHOST_SystemX11 *system = ((GHOST_SystemX11 *)getSystem());
2155   return system->pushEvent(new GHOST_EventDragnDrop(
2156       system->getMilliSeconds(), eventType, draggedObjectType, window, mouseX, mouseY, data));
2157 }
2158 #endif
2159 /**
2160  * These callbacks can be used for debugging, so we can breakpoint on an X11 error.
2161  *
2162  * Dummy function to get around IO Handler exiting if device invalid
2163  * Basically it will not crash blender now if you have a X device that
2164  * is configured but not plugged in.
2165  */
2166 int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *event)
2167 {
2168   char error_code_str[512];
2169
2170   XGetErrorText(display, event->error_code, error_code_str, sizeof(error_code_str));
2171
2172   fprintf(stderr,
2173           "Received X11 Error:\n"
2174           "\terror code:   %d\n"
2175           "\trequest code: %d\n"
2176           "\tminor code:   %d\n"
2177           "\terror text:   %s\n",
2178           event->error_code,
2179           event->request_code,
2180           event->minor_code,
2181           error_code_str);
2182
2183   /* No exit! - but keep lint happy */
2184   return 0;
2185 }
2186
2187 int GHOST_X11_ApplicationIOErrorHandler(Display * /*display*/)
2188 {
2189   fprintf(stderr, "Ignoring Xlib error: error IO\n");
2190
2191   /* No exit! - but keep lint happy */
2192   return 0;
2193 }
2194
2195 #ifdef WITH_X11_XINPUT
2196
2197 static bool is_filler_char(char c)
2198 {
2199   return isspace(c) || c == '_' || c == '-' || c == ';' || c == ':';
2200 }
2201
2202 /* These C functions are copied from Wine 3.12's wintab.c */
2203 static bool match_token(const char *haystack, const char *needle)
2204 {
2205   const char *h, *n;
2206   for (h = haystack; *h;) {
2207     while (*h && is_filler_char(*h))
2208       h++;
2209     if (!*h)
2210       break;
2211
2212     for (n = needle; *n && *h && tolower(*h) == tolower(*n); n++)
2213       h++;
2214     if (!*n && (is_filler_char(*h) || !*h))
2215       return true;
2216
2217     while (*h && !is_filler_char(*h))
2218       h++;
2219   }
2220   return false;
2221 }
2222
2223 /* Determining if an X device is a Tablet style device is an imperfect science.
2224  * We rely on common conventions around device names as well as the type reported
2225  * by Wacom tablets.  This code will likely need to be expanded for alternate tablet types
2226  *
2227  * Wintab refers to any device that interacts with the tablet as a cursor,
2228  * (stylus, eraser, tablet mouse, airbrush, etc)
2229  * this is not to be confused with wacom x11 configuration "cursor" device.
2230  * Wacoms x11 config "cursor" refers to its device slot (which we mirror with
2231  * our gSysCursors) for puck like devices (tablet mice essentially).
2232  */
2233 static GHOST_TTabletMode tablet_mode_from_name(const char *name, const char *type)
2234 {
2235   int i;
2236   static const char *tablet_stylus_whitelist[] = {"stylus", "wizardpen", "acecad", "pen", NULL};
2237
2238   static const char *type_blacklist[] = {"pad", "cursor", "touch", NULL};
2239
2240   /* Skip some known unsupported types. */
2241   for (i = 0; type_blacklist[i] != NULL; i++) {
2242     if (type && (strcasecmp(type, type_blacklist[i]) == 0)) {
2243       return GHOST_kTabletModeNone;
2244     }
2245   }
2246
2247   /* First check device type to avoid cases where name is "Pen and Eraser" and type is "ERASER" */
2248   for (i = 0; tablet_stylus_whitelist[i] != NULL; i++) {
2249     if (type && match_token(type, tablet_stylus_whitelist[i])) {
2250       return GHOST_kTabletModeStylus;
2251     }
2252   }
2253   if (type && match_token(type, "eraser")) {
2254     return GHOST_kTabletModeEraser;
2255   }
2256   for (i = 0; tablet_stylus_whitelist[i] != NULL; i++) {
2257     if (name && match_token(name, tablet_stylus_whitelist[i])) {
2258       return GHOST_kTabletModeStylus;
2259     }
2260   }
2261   if (name && match_token(name, "eraser")) {
2262     return GHOST_kTabletModeEraser;
2263   }
2264
2265   return GHOST_kTabletModeNone;
2266 }
2267
2268 /* End code copied from Wine. */
2269
2270 void GHOST_SystemX11::refreshXInputDevices()
2271 {
2272   if (m_xinput_version.present) {
2273     /* Close tablet devices. */
2274     clearXInputDevices();
2275
2276     /* Install our error handler to override Xlib's termination behavior */
2277     GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store);
2278
2279     {
2280       int device_count;
2281       XDeviceInfo *device_info = XListInputDevices(m_display, &device_count);
2282
2283       for (int i = 0; i < device_count; ++i) {
2284         char *device_type = device_info[i].type ? XGetAtomName(m_display, device_info[i].type) :
2285                                                   NULL;
2286         GHOST_TTabletMode tablet_mode = tablet_mode_from_name(device_info[i].name, device_type);
2287
2288         // printf("Tablet type:'%s', name:'%s', index:%d\n", device_type, device_info[i].name, i);
2289
2290         if (device_type) {
2291           XFree((void *)device_type);
2292         }
2293
2294         if (!(tablet_mode == GHOST_kTabletModeStylus || tablet_mode == GHOST_kTabletModeEraser)) {
2295           continue;
2296         }
2297
2298         GHOST_TabletX11 xtablet = {tablet_mode};
2299         xtablet.ID = device_info[i].id;
2300         xtablet.Device = XOpenDevice(m_display, xtablet.ID);
2301
2302         if (xtablet.Device != NULL) {
2303           /* Find how many pressure levels tablet has */
2304           XAnyClassPtr ici = device_info[i].inputclassinfo;
2305
2306           for (int j = 0; j < xtablet.Device->num_classes; ++j) {
2307             if (ici->c_class == ValuatorClass) {
2308               XValuatorInfo *xvi = (XValuatorInfo *)ici;
2309               xtablet.PressureLevels = xvi->axes[2].max_value;
2310
2311               if (xvi->num_axes > 3) {
2312                 /* this is assuming that the tablet has the same tilt resolution in both
2313                  * positive and negative directions. It would be rather weird if it didn't.. */
2314                 xtablet.XtiltLevels = xvi->axes[3].max_value;
2315                 xtablet.YtiltLevels = xvi->axes[4].max_value;
2316               }
2317               else {
2318                 xtablet.XtiltLevels = 0;
2319                 xtablet.YtiltLevels = 0;
2320               }
2321
2322               break;
2323             }
2324
2325             ici = (XAnyClassPtr)(((char *)ici) + ici->length);
2326           }
2327
2328           m_xtablets.push_back(xtablet);
2329         }
2330       }
2331
2332       XFreeDeviceList(device_info);
2333     }
2334
2335     GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store);
2336   }
2337 }
2338
2339 void GHOST_SystemX11::clearXInputDevices()
2340 {
2341   for (GHOST_TabletX11 &xtablet : m_xtablets) {
2342     if (xtablet.Device)
2343       XCloseDevice(m_display, xtablet.Device);
2344   }
2345
2346   m_xtablets.clear();
2347 }
2348
2349 #endif /* WITH_X11_XINPUT */