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