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